def store_back_address(self, opcodes: OpcodeList): """ INPUT: | EoS | New Back address OUTPUT: | EoS | """ self.load_back_address_addr(opcodes) opcodes.add('MSTORE')
def load_atom_value(self, opcodes: OpcodeList, atom_address: int): """ INPUT: | EoS | OUTPUT: | EoS | Value of Atom on provided address | """ self.load_atom_address(opcodes, atom_address) opcodes.add('MLOAD')
def load_cur_atom_counter(self, opcodes: OpcodeList): """ INPUT: | EoS | OUTPUT: | EoS | Value of Current Atom counter """ self.load_cur_atom_counter_addr(opcodes) opcodes.add('MLOAD')
def load_back_address(self, opcodes: OpcodeList): """ INPUT: | EoS | OUTPUT: | EoS | Current Back address """ self.load_back_address_addr(opcodes) opcodes.add('MLOAD')
def store_new_gap(self, opcodes: OpcodeList): """ INPUT: | EoS | New gap OUTPUT: | EoS | """ opcodes.add('PUSH', dec_to_hex(0, 2 * self.__address_length)) opcodes.add('MSTORE')
def load_prev_gap(self, opcodes: OpcodeList): """ INPUT: | EoS | OUTPUT: | EoS | Address of previout frame's start """ self.load_cur_gap(opcodes) opcodes.add('MLOAD')
def store_atom_value(self, opcodes: OpcodeList, atom_address: int): """ INPUT: | EoS | New value of Atom OUTPUT: | EoS | """ self.load_atom_address(opcodes, atom_address) opcodes.add('MSTORE')
def load_cur_gap(self, opcodes: OpcodeList): """ INPUT: | EoS | OUTPUT: | EoS | Gap of current frame | """ opcodes.add('PUSH', dec_to_hex(0, 2 * self.__address_length)) opcodes.add('MLOAD')
def calc_new_frame_gap(self, opcodes: OpcodeList): """ INPUT: | EoS | OUTPUT: | EoS | Gap of new frame """ self.load_cur_gap(opcodes) self.calc_cur_frame_size(opcodes) opcodes.add('ADD')
def load_back_address_addr(self, opcodes: OpcodeList): """ INPUT: | EoS | OUTPUT: | EoS | Address of Current Back address """ self.load_cur_gap(opcodes) opcodes.add('PUSH', dec_to_hex(0x40, 2 * self.__address_length)) opcodes.add('ADD')
def __plus(self, body: AstNode, ctx: Context, opcodes: OpcodeList): """ INPUT (2): | EoS | Value 1 | Value 2 OUTPUT (1): | EoS | Sum of values """ assert len(body.child_nodes) == 3 opcodes.add('ADD')
def __and(self, body: AstNode, ctx: Context, opcodes: OpcodeList): """ INPUT (2): | EoS | v1 (bool) | v2 (bool) OUTPUT (1): | EoS | v1 AND v2 (bool) """ assert len(body.child_nodes) == 3 opcodes.add('AND')
def __greater(self, body: AstNode, ctx: Context, opcodes: OpcodeList): """ INPUT (2): | EoS | Value 1 | Value 2 OUTPUT (1): | EoS | Is Value 1 greater than Value 2 """ assert len(body.child_nodes) == 3 opcodes.add('LT')
def load_cur_atom_counter_addr(self, opcodes: OpcodeList): """ INPUT: | EoS | OUTPUT: | EoS | Address of Current Atom counter """ self.load_cur_gap(opcodes) opcodes.add('PUSH', dec_to_hex(0x20, 2 * self.__address_length)) opcodes.add('ADD')
def __times(self, body: AstNode, ctx: Context, opcodes: OpcodeList): """ INPUT (2): | EoS | Value 1 | Value 2 OUTPUT (1): | EoS | Value 1 * Value 2 """ assert len(body.child_nodes) == 3 opcodes.add('MUL')
def __equal(self, body: AstNode, ctx: Context, opcodes: OpcodeList): """ INPUT (2): | EoS | Value 1 | Value 2 OUTPUT (1): | EoS | Does value 1 equals value 2 (bool) """ assert len(body.child_nodes) == 3 opcodes.add('EQ')
def __greatereq(self, body: AstNode, ctx: Context, opcodes: OpcodeList): """ INPUT (2): | EoS | Value 1 | Value 2 OUTPUT (1): | EoS | Does Value 1 less or equals Value (bool) """ assert len(body.child_nodes) == 3 opcodes.add('GT') opcodes.add('ISZERO')
def __break(self, body: AstNode, ctx: Context, opcodes: OpcodeList): """ INPUT: | EoS | OUTPUT: | EoS | """ assert len(body.child_nodes) == 1 opcodes.add('PUSH', dec_to_hex(0, 2 * self.__address_length)) opcodes.add('JUMP', dec_to_hex(self.__current_while_id, 2 * self.__address_length)) pass
def __not(self, body: AstNode, ctx: Context, opcodes: OpcodeList): """ INPUT (1): | EoS | value (bool) OUTPUT (1): | EoS | !value (bool) """ assert len(body.child_nodes) == 2 opcodes.add('PUSH', dec_to_hex(0, 2 * self.address_length)) opcodes.add('EQ')
def load_atom_address(self, opcodes: OpcodeList, atom_address: int): """ INPUT: | EoS | OUTPUT: | EoS | Address of Atom on provided address """ self.load_cur_gap(opcodes) opcodes.add('PUSH', dec_to_hex(atom_address, 2 * self.__address_length)) opcodes.add('ADD')
def __divide(self, body: AstNode, ctx: Context, opcodes: OpcodeList): """ INPUT (2): | EoS | Value 1 | Value 2 OUTPUT (1): | EoS | Value 1 // Value 2 """ assert len(body.child_nodes) == 3 opcodes.add('SWAP1') opcodes.add('DIV')
def add_frame(self, opcodes: OpcodeList): """ INPUT: | EoS | Arg1 | ... | ArgN | Back Address | OUTPUT: | EoS | Arg1 | ... | ArgN | """ self.load_cur_gap(opcodes) self.calc_new_frame_gap(opcodes) opcodes.add('MSTORE') self.calc_new_frame_gap(opcodes) self.store_new_gap(opcodes) # Back address gone self.store_back_address(opcodes)
def calc_cur_frame_size(self, opcodes: OpcodeList): """ INPUT: | EoS | OUTPUT: | EoS | Size of current frame """ opcodes.add( 'PUSH', dec_to_hex(self.__frame_service_atoms * 0x20, 2 * self.__address_length)) self.load_cur_atom_counter(opcodes) opcodes.add('PUSH', dec_to_hex(32, 2 * self.__address_length)) opcodes.add('MUL') opcodes.add('ADD')
def __init__(self, ast: AST, address_length=32, frame_service_atoms=3): self.__address_length = address_length self.__frame_service_atoms = frame_service_atoms assert 32 >= address_length >= 1 assert frame_service_atoms >= 2 self.__opcodes: OpcodeList = OpcodeList(address_length) self.__ast = ast # Init Virtual stack and function Singletons VirtualStackHelper(address_length, frame_service_atoms).init_stack(self.__opcodes) SpecialForms(address_length) BuiltIns(self.__address_length) Declared(address_length, frame_service_atoms)
def __nonequal(self, body: AstNode, ctx: Context, opcodes: OpcodeList): """ INPUT (2): | EoS | Value 1 | Value 2 OUTPUT (1): | EoS | Does Value 1 differs from Value 2 (bool) """ assert len(body.child_nodes) == 3 opcodes.add('EQ') opcodes.add('PUSH', dec_to_hex(0, 2 * self.address_length)) opcodes.add('EQ')
def __read(self, body: AstNode, ctx: Context, opcodes: OpcodeList): """ INPUT (0): | EoS | OUTPUT (1): | EoS | Value from input """ assert len(body.child_nodes) == 2 opcodes.add('PUSH', dec_to_hex(0x20, 2 * self.address_length)) opcodes.add('MUL') opcodes.add('CALLDATALOAD')
def call(self, call_body: AstNode, ctx: Context, opcodes: OpcodeList): assert call_body.type == AstNodeType.List assert call_body.child_nodes[ 0].type == AstNodeType.Literal or call_body.child_nodes[ 0].type == AstNodeType.Atom # Prepare back address, part 1 opcodes.add('PUSH') back_address = len(opcodes.list) - 1 # Jump into the function opcodes.add( 'PUSH', dec_to_hex(self.__funcs[call_body.child_nodes[0].value], 2 * self.address_length)) opcodes.add('JUMP') # Prepare back address, part 2 opcodes.add('JUMPDEST') opcodes.list[back_address].extra_value = dec_to_hex( opcodes.list[-1].id, 2 * self.address_length)
def declare_function(self, call_body: AstNode, ctx: Context, opcodes: OpcodeList): assert call_body.type == AstNodeType.List assert call_body.child_nodes[0].type == AstNodeType.Literal or call_body.child_nodes[0].type == AstNodeType.Atom assert call_body.child_nodes[0].value == 'func' """ INPUT: | EoS | Arg1 | ... | ArgN | Back address OUTPUT: | EoS | """ # Set entry point opcodes.add('JUMPDEST') Declared().add(call_body.child_nodes[1].value, opcodes.list[-1].id) # Make new stack frame # Back address gone VirtualStackHelper().add_frame(opcodes) # Set atom counter, part 1 opcodes.add('PUSH') func_atom_counter = len(opcodes.list) - 1 VirtualStackHelper().load_cur_atom_counter_addr(opcodes) opcodes.add('MSTORE') # Declare arguments in context # Args gone for arg_name in reversed(call_body.child_nodes[2].child_nodes): assert arg_name.type == AstNodeType.Atom address, is_new = ctx.get_atom_addr(arg_name.value) VirtualStackHelper().store_atom_value(opcodes, address) # Generate body self.process_call(call_body.child_nodes[3], ctx, opcodes) # Set atom counter, part 2 opcodes.list[func_atom_counter].extra_value = \ dec_to_hex(ctx.id_counter - self.__frame_service_atoms, 2 * self.__address_length) # Remove frame and leave function VirtualStackHelper().load_back_address(opcodes) VirtualStackHelper().remove_frame(opcodes) opcodes.add('JUMP')
def init_stack(self, opcodes: OpcodeList): """ NO SIDE EFFECTS """ # Set ZERO FRAME (prog frame) gap = 0x40 opcodes.add('PUSH', dec_to_hex(0x40, 2 * self.__address_length)) opcodes.add('PUSH', dec_to_hex(0, 2 * self.__address_length)) opcodes.add('MSTORE') # Init zero frame # Set start of previous frame and back address as 0x00 opcodes.add('PUSH', dec_to_hex(0x0, 2 * self.__address_length)) opcodes.add('DUP1') opcodes.add('PUSH', dec_to_hex(0x40, 2 * self.__address_length)) opcodes.add('MSTORE') opcodes.add('PUSH', dec_to_hex(0x40 + 0x40, 2 * self.__address_length)) opcodes.add('MSTORE') # Set counter of atoms as 0x00 opcodes.add('PUSH', dec_to_hex(0x0, 2 * self.__address_length)) opcodes.add('PUSH', dec_to_hex(0x40 + 0x20, 2 * self.__address_length)) opcodes.add('MSTORE')
def __return(self, body: AstNode, ctx: Context, opcodes: OpcodeList): """ INPUT (1): | EoS | Some value OUTPUT (0): | EoS | """ assert len(body.child_nodes) == 2 if ctx.is_prog: opcodes.add('PUSH', dec_to_hex(0, 2 * self.address_length)) opcodes.add('MSTORE') opcodes.add('PUSH', dec_to_hex(32, 2 * self.address_length)) opcodes.add('PUSH', dec_to_hex(0, 2 * self.address_length)) opcodes.add('RETURN') else: VirtualStackHelper().load_back_address(opcodes) VirtualStackHelper().remove_frame(opcodes) opcodes.add('JUMP')