## Nobicoin Virtual Machine `vm.py` We write our codes for this section in this file. ``` class VM: def __init__(self, storage, transaction): self.storage = storage self.tx = transaction def transaction_type(self): # detect the transaction type( contract call, asset transfer, contract deployment) pass def parse(self, code): # Parse the contract code and return it in a format that's easy to execute. pass def execute(self, parsed_code): # Execute the parsed code. pass def get_storage(self, address): # Get the storage for the given address. return self.storage.get(address, {}) def set_storage(self, address, key, value): # Set a value in the storage for the given address. if address not in self.storage: self.storage[address] = {} self.storage[address][key] = value def run(self, code): parsed_code = self.parse(code) self.execute(parsed_code) if __name__=="__main__": # write testing purpose thing in here pass ``` **trace and dependencies:** > 1. depend to the kv file storage > 2. it get used when a miner wants to create new block during the each transaction proccessing **contract language design**: ``` file extention .nob ``` `variable_types: uint, string, address, mapping` ``` pragma we.are.nob var uint x = value1; var string y = value2; var address z = value3; var mapping l (address , uint); constructor(inputs){ uint x = value1; string y = value2; address z = value3; } func function_name(uint v1, address v2){ if (v1 > 10){ z = v2 } else{ z = nobi.sender } } ``` **tasks**: > 1. in this file first we check we need to fire the vm or not. conditions: > a. the destination address is zero address (nobi00000) > b. the destination address has code storage > 2. if it was just simple coin transfer we rturning true and current state root and let the codes continue the proccsess > 3. if the destination was zero address (nobi000) thats means we have new contract to deploy. so we push the contract on the code storage space of the account and run constructor and imply the result on the storage of the account . > 4. if it was contract call we should first load the destination code and sotrage and get the call data and the code and start the interprate the contract code and apply the result on the destination contract storage. > 5. we should also design the data read api in this file for reading the storage of the contracts > 6. we should impelement the state root approach to commit the state root in each new block and for doing this after each function the vm run it should return the new state root > 7. we should implement the interpretur for our language **fungible token contract in Nobi Language (erc20 like)** ``` pragma we.are.nob var string token_name; var uint max_supply; var mapping balance (address , balance); constructor(string name, uint supply, addree reciver){ token_name = name; max_supply = supply; balance[reciver] = max_supply; } func transfer (uint amount, address reciver){ internal_var sender_balance = balance [nobi.sender] internal_var reciver_balance= balance [reciver] if (sender_balance >= amount){ balance[nobi.sender] = sender_balance - amount; balance [reciver] = reciver_balance + amount; } else { reject; } } ``` **Instrutions** ``` <!-- GET instruction: read data in key and set it in var --> GET {var_name} {key} <!-- SET instruction: write data in var in key storage space --> SET {key} {var_name} <!-- Var instruction: define a variable and set initial value --> VAR {var_name} {if exist? initial_value : default value} INC {var_name} ADD {var_name1} {var_name2} {dst_var_name} SUB {var_name1} {var_name2} {dst_var_name} MOL {var_name1} {var_name2} {dst_var_name} DIV {var_name1} {var_name2} {dst_var_name} GT {var_name1} {var_name2} {dst_var_name} LT {var_name1} {var_name2} {dst_var_name} GTE {var_name1} {var_name2} {dst_var_name} LTE {var_name1} {var_name2} {dst_var_name} EQ {var_name1} {var_name2} {dst_var_name} NEQ {var_name1} {var_name2} {dst_var_name} JIF {condition_var_name} {dst_line / Lable} {else_line, els_lable} CONCAT {var_name_1} {var_name_2} {dst_var_name} HALT <!-- MSG_SENDER instruction: the initial value is set to the transaction sender --> MSG_SENDER FUNCTION_SELECTOR INPUTS_0 INPUTS_1 INPUTS_2 ... INPUTS_7 ``` **Fungible token Contract with nobi assembly** ``` VAR is_constractor 0 VAR constractor_signature 1001 VAR is_transfer 0 VAR transfer_signature 1002 VAR suffix = "_balance" EQ FUNCTION_SELECTOR constractor_signature is_contractor EQ FUNCTION_SELECTOR transfer_signature is_transfer JIF is_contractor Constructor JIF is_transfer Transfer ###Constructor: VAR total_suplly 10000 // VAR token_name "noooobtoken" VAR key CONCAT MSG_SENDER suffix key Set key total_suplly HALT ###Transfer: // INPUTS_0 Amount // INPUTS_1 Receiver VAR key CONCAT MSG_SENDER suffix key VAR balance GET balance key VAR is_not_enough_balance 0 LT balance, INPUTS_0 is_not_enough_balance JIF is_not_enough_balance Halt_the_program VAR remaining_balance SUB balance INPUTS_0 remaining_balance SET key remaining_balance VAR receiver_key CONCAT INPUTS_1 suffix receiver_key VAR receiver_balance GET receiver_balance receiver_key VAR new_receiver_balance ADD receiver_balance INPUTS_0 new_receiver_balance SET receiver_key new_receiver_balance HALT Halt_the_program: HALT