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