def vm_trace(ext, msg, compustate, opcode, pushcache, tracer=log_vm_op): """ This diverges from normal logging, as we use the logging namespace only to decide which features get logged in 'eth.vm.op' i.e. tracing can not be activated by activating a sub like 'eth.vm.op.stack' """ op, in_args, out_args, fee = opcodes.opcodes[opcode] trace_data = {} trace_data["stack"] = list(map(to_string, list(compustate.prev_stack))) if compustate.prev_prev_op in ( "MLOAD", "MSTORE", "MSTORE8", "SHA3", "CALL", "CALLCODE", "CREATE", "CALLDATACOPY", "CODECOPY", "EXTCODECOPY", ): if len(compustate.prev_memory) < 4096: trace_data["memory"] = "".join( [encode_hex(ascii_chr(x)) for x in compustate.prev_memory] ) else: trace_data["sha3memory"] = encode_hex( utils.sha3(b"".join([ascii_chr(x) for x in compustate.prev_memory])) ) if compustate.prev_prev_op in ("SSTORE",) or compustate.steps == 0: trace_data["storage"] = ext.log_storage(msg.to) trace_data["gas"] = to_string(compustate.prev_gas) trace_data["gas_cost"] = to_string(compustate.prev_gas - compustate.gas) trace_data["fee"] = fee trace_data["inst"] = opcode trace_data["pc"] = to_string(compustate.prev_pc) if compustate.steps == 0: trace_data["depth"] = msg.depth trace_data["address"] = msg.to trace_data["steps"] = compustate.steps trace_data["depth"] = msg.depth if op[:4] == "PUSH": print(repr(pushcache)) trace_data["pushvalue"] = pushcache[compustate.prev_pc] tracer.trace("vm", op=op, **trace_data) compustate.steps += 1 compustate.prev_prev_op = op
def intrinsic_gas_used(self): num_zero_bytes = str_to_bytes(self.data).count(ascii_chr(0)) num_non_zero_bytes = len(self.data) - num_zero_bytes return (opcodes.GTXCOST + (opcodes.CREATE[3] if not self.to else 0) + opcodes.GTXDATAZERO * num_zero_bytes + opcodes.GTXDATANONZERO * num_non_zero_bytes + (opcodes.GTXXSHARDCOST if self.is_cross_shard else 0))
def ecies_encrypt(cls, data, raw_pubkey, shared_mac_data=''): """ ECIES Encrypt, where P = recipient public key is: 1) generate r = random value 2) generate shared-secret = kdf( ecdhAgree(r, P) ) 3) generate R = rG [same op as generating a public key] 4) send 0x04 || R || AsymmetricEncrypt(shared-secret, plaintext) || tag currently used by go: ECIES_AES128_SHA256 = &ECIESParams{ Hash: sha256.New, hashAlgo: crypto.SHA256, Cipher: aes.NewCipher, BlockSize: aes.BlockSize, KeyLen: 16, } """ # 1) generate r = random value ephem = ECCx() # 2) generate shared-secret = kdf( ecdhAgree(r, P) ) key_material = ephem.raw_get_ecdh_key(pubkey_x=raw_pubkey[:32], pubkey_y=raw_pubkey[32:]) assert len(key_material) == 32 key = eciesKDF(key_material, 32) assert len(key) == 32 key_enc, key_mac = key[:16], key[16:] key_mac = sha256(key_mac).digest() assert len(key_mac) == 32 # 3) generate R = rG [same op as generating a public key] ephem_pubkey = ephem.raw_pubkey # encrypt iv = pyelliptic.Cipher.gen_IV(cls.ecies_ciphername) assert len(iv) == 16 ctx = pyelliptic.Cipher(key_enc, iv, 1, cls.ecies_ciphername) ciphertext = ctx.ciphering(data) assert len(ciphertext) == len(data) # 4) send 0x04 || R || AsymmetricEncrypt(shared-secret, plaintext) || tag msg = ascii_chr(0x04) + ephem_pubkey + iv + ciphertext # the MAC of a message (called the tag) as per SEC 1, 3.5. tag = hmac_sha256(key_mac, msg[1 + 64:] + str_to_bytes(shared_mac_data)) assert len(tag) == 32 msg += tag assert len(msg) == 1 + 64 + 16 + 32 + len(data) == 113 + len(data) assert len(msg) - cls.ecies_encrypt_overhead_length == len(data) return msg
def create_auth_message(self, remote_pubkey, ephemeral_privkey=None, nonce=None): """ 1. initiator generates ecdhe-random and nonce and creates auth 2. initiator connects to remote and sends auth New: E(remote-pubk, S(ephemeral-privk, ecdh-shared-secret ^ nonce) || H(ephemeral-pubk) || pubk || nonce || 0x0 ) Known: E(remote-pubk, S(ephemeral-privk, token ^ nonce) || H(ephemeral-pubk) || pubk || nonce || 0x1) """ assert self.is_initiator if not self.ecc.is_valid_key(remote_pubkey): raise InvalidKeyError('invalid remote pubkey') self.remote_pubkey = remote_pubkey ecdh_shared_secret = self.ecc.get_ecdh_key(remote_pubkey) token = ecdh_shared_secret flag = 0x0 self.initiator_nonce = nonce or sha3( ienc(random.randint(0, 2**256 - 1))) assert len(self.initiator_nonce) == 32 token_xor_nonce = sxor(token, self.initiator_nonce) assert len(token_xor_nonce) == 32 ephemeral_pubkey = self.ephemeral_ecc.raw_pubkey assert len(ephemeral_pubkey) == 512 / 8 if not self.ecc.is_valid_key(ephemeral_pubkey): raise InvalidKeyError('invalid ephemeral pubkey') # S(ephemeral-privk, ecdh-shared-secret ^ nonce) S = self.ephemeral_ecc.sign(token_xor_nonce) assert len(S) == 65 # S || H(ephemeral-pubk) || pubk || nonce || 0x0 auth_message = S + sha3(ephemeral_pubkey) + self.ecc.raw_pubkey + \ self.initiator_nonce + ascii_chr(flag) assert len(auth_message) == 65 + 32 + 64 + 32 + 1 == 194 return auth_message
def ecrecover_to_pub(rawhash, v, r, s): if coincurve and hasattr(coincurve, "PublicKey"): try: pk = coincurve.PublicKey.from_signature_and_message( zpad(bytearray_to_bytestr(int_to_32bytearray(r)), 32) + zpad(bytearray_to_bytestr(int_to_32bytearray(s)), 32) + ascii_chr(v - 27), rawhash, hasher=None, ) pub = pk.format(compressed=False)[1:] except BaseException: pub = b"\x00" * 64 else: result = ecdsa_raw_recover(rawhash, (v, r, s)) if result: x, y = result pub = encode_int32(x) + encode_int32(y) else: raise ValueError('Invalid VRS') assert len(pub) == 64 return pub
def vm_execute(ext, msg, code): # precompute trace flag # if we trace vm, we're in slow mode anyway trace_vm = log_vm_op.is_active("trace") # Initialize stack, memory, program counter, etc compustate = Compustate(gas=msg.gas) stk = compustate.stack mem = compustate.memory # Compute jumpdest_mask, pushcache = preprocess_code(code) codelen = len(code) # For tracing purposes op = None _prevop = None steps = 0 while compustate.pc < codelen: opcode = safe_ord(code[compustate.pc]) # Invalid operation if opcode not in opcodes.opcodes: return vm_exception("INVALID OP", opcode=opcode) op, in_args, out_args, fee = opcodes.opcodes[opcode] # Apply operation if trace_vm: compustate.reset_prev() compustate.gas -= fee compustate.pc += 1 # Tracing if trace_vm: """ This diverges from normal logging, as we use the logging namespace only to decide which features get logged in 'eth.vm.op' i.e. tracing can not be activated by activating a sub like 'eth.vm.op.stack' """ trace_data = {} trace_data["stack"] = list(map(to_string, list(compustate.stack))) if _prevop in ( "MLOAD", "MSTORE", "MSTORE8", "SHA3", "CALL", "CALLCODE", "CREATE", "CALLDATACOPY", "CODECOPY", "EXTCODECOPY", ): if len(compustate.memory) < 4096: trace_data["memory"] = "".join( [encode_hex(ascii_chr(x)) for x in compustate.memory] ) else: trace_data["sha3memory"] = encode_hex( utils.sha3(b"".join([ascii_chr(x) for x in compustate.memory])) ) if _prevop in ("SSTORE",) or steps == 0: trace_data["storage"] = ext.log_storage(msg.to) trace_data["gas"] = to_string(compustate.gas + fee) trace_data["inst"] = opcode trace_data["pc"] = to_string(compustate.pc - 1) if steps == 0: trace_data["depth"] = msg.depth trace_data["address"] = msg.to trace_data["steps"] = steps trace_data["depth"] = msg.depth if op[:4] == "PUSH": trace_data["pushvalue"] = pushcache[compustate.pc - 1] log_vm_op.trace("vm", op=op, **trace_data) steps += 1 _prevop = op # out of gas error if compustate.gas < 0: return vm_exception("OUT OF GAS") # empty stack error if in_args > len(compustate.stack): return vm_exception( "INSUFFICIENT STACK", op=op, needed=to_string(in_args), available=to_string(len(compustate.stack)), ) # overfull stack error if len(compustate.stack) - in_args + out_args > 1024: return vm_exception( "STACK SIZE LIMIT EXCEEDED", op=op, pre_height=to_string(len(compustate.stack)), ) # Valid operations # Pushes first because they are very frequent if 0x60 <= opcode <= 0x7F: stk.append(pushcache[compustate.pc - 1]) # Move 1 byte forward for 0x60, up to 32 bytes for 0x7f compustate.pc += opcode - 0x5F # Arithmetic elif opcode < 0x10: if op == "STOP": return peaceful_exit("STOP", compustate.gas, []) elif op == "ADD": stk.append((stk.pop() + stk.pop()) & TT256M1) elif op == "SUB": stk.append((stk.pop() - stk.pop()) & TT256M1) elif op == "MUL": stk.append((stk.pop() * stk.pop()) & TT256M1) elif op == "DIV": s0, s1 = stk.pop(), stk.pop() stk.append(0 if s1 == 0 else s0 // s1) elif op == "MOD": s0, s1 = stk.pop(), stk.pop() stk.append(0 if s1 == 0 else s0 % s1) elif op == "SDIV": s0, s1 = utils.to_signed(stk.pop()), utils.to_signed(stk.pop()) stk.append( 0 if s1 == 0 else (abs(s0) // abs(s1) * (-1 if s0 * s1 < 0 else 1)) & TT256M1 ) elif op == "SMOD": s0, s1 = utils.to_signed(stk.pop()), utils.to_signed(stk.pop()) stk.append( 0 if s1 == 0 else (abs(s0) % abs(s1) * (-1 if s0 < 0 else 1)) & TT256M1 ) elif op == "ADDMOD": s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() stk.append((s0 + s1) % s2 if s2 else 0) elif op == "MULMOD": s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() stk.append((s0 * s1) % s2 if s2 else 0) elif op == "EXP": base, exponent = stk.pop(), stk.pop() # fee for exponent is dependent on its bytes # calc n bytes to represent exponent nbytes = len(utils.encode_int(exponent)) expfee = nbytes * opcodes.GEXPONENTBYTE if compustate.gas < expfee: compustate.gas = 0 return vm_exception("OOG EXPONENT") compustate.gas -= expfee stk.append(pow(base, exponent, TT256)) elif op == "SIGNEXTEND": s0, s1 = stk.pop(), stk.pop() if s0 <= 31: testbit = s0 * 8 + 7 if s1 & (1 << testbit): stk.append(s1 | (TT256 - (1 << testbit))) else: stk.append(s1 & ((1 << testbit) - 1)) else: stk.append(s1) # Comparisons elif opcode < 0x20: if op == "LT": stk.append(1 if stk.pop() < stk.pop() else 0) elif op == "GT": stk.append(1 if stk.pop() > stk.pop() else 0) elif op == "SLT": s0, s1 = utils.to_signed(stk.pop()), utils.to_signed(stk.pop()) stk.append(1 if s0 < s1 else 0) elif op == "SGT": s0, s1 = utils.to_signed(stk.pop()), utils.to_signed(stk.pop()) stk.append(1 if s0 > s1 else 0) elif op == "EQ": stk.append(1 if stk.pop() == stk.pop() else 0) elif op == "ISZERO": stk.append(0 if stk.pop() else 1) elif op == "AND": stk.append(stk.pop() & stk.pop()) elif op == "OR": stk.append(stk.pop() | stk.pop()) elif op == "XOR": stk.append(stk.pop() ^ stk.pop()) elif op == "NOT": stk.append(TT256M1 - stk.pop()) elif op == "BYTE": s0, s1 = stk.pop(), stk.pop() if s0 >= 32: stk.append(0) else: stk.append((s1 // 256 ** (31 - s0)) % 256) elif op == "SHL": s0, s1 = stk.pop(), stk.pop() stk.append(0 if s0 >= 256 else (s1 << s0) & TT256M1) elif op == "SHR": s0, s1 = stk.pop(), stk.pop() stk.append(0 if s0 >= 256 else s1 >> s0) elif op == "SAR": s0, s1 = stk.pop(), utils.to_signed(stk.pop()) if s0 >= 256: ret = 0 if s1 >= 0 else TT256M1 else: ret = (s1 >> s0) & TT256M1 stk.append(ret) # SHA3 and environment info elif opcode < 0x40: if op == "SHA3": s0, s1 = stk.pop(), stk.pop() compustate.gas -= opcodes.GSHA3WORD * (utils.ceil32(s1) // 32) if compustate.gas < 0: return vm_exception("OOG PAYING FOR SHA3") if not mem_extend(mem, compustate, op, s0, s1): return vm_exception("OOG EXTENDING MEMORY") data = bytearray_to_bytestr(mem[s0 : s0 + s1]) stk.append(utils.big_endian_to_int(utils.sha3(data))) elif op == "ADDRESS": stk.append(utils.coerce_to_int(msg.to)) elif op == "BALANCE": addr = utils.coerce_addr_to_hex(stk.pop() % 2 ** 160) stk.append(ext.get_balance(addr)) elif op == "ORIGIN": stk.append(utils.coerce_to_int(ext.tx_origin)) elif op == "CALLER": stk.append(utils.coerce_to_int(msg.sender)) elif op == "CALLVALUE": stk.append(msg.value) elif op == "CALLDATALOAD": stk.append(msg.data.extract32(stk.pop())) elif op == "CALLDATASIZE": stk.append(msg.data.size) elif op == "CALLDATACOPY": mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, size): return vm_exception("OOG EXTENDING MEMORY") if not data_copy(compustate, size): return vm_exception("OOG COPY DATA") msg.data.extract_copy(mem, mstart, dstart, size) elif op == "CODESIZE": stk.append(codelen) elif op == "CODECOPY": mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, size): return vm_exception("OOG EXTENDING MEMORY") if not data_copy(compustate, size): return vm_exception("OOG COPY DATA") for i in range(size): if dstart + i < codelen: mem[mstart + i] = safe_ord(code[dstart + i]) else: mem[mstart + i] = 0 elif op == "RETURNDATACOPY": mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, size): return vm_exception("OOG EXTENDING MEMORY") if not data_copy(compustate, size): return vm_exception("OOG COPY DATA") if dstart + size > len(compustate.last_returned): return vm_exception("RETURNDATACOPY out of range") mem[mstart : mstart + size] = compustate.last_returned[ dstart : dstart + size ] elif op == "RETURNDATASIZE": stk.append(len(compustate.last_returned)) elif op == "GASPRICE": stk.append(ext.tx_gasprice) elif op == "EXTCODESIZE": addr = utils.coerce_addr_to_hex(stk.pop() % 2 ** 160) stk.append(len(ext.get_code(addr) or b"")) elif op == "EXTCODECOPY": addr = utils.coerce_addr_to_hex(stk.pop() % 2 ** 160) start, s2, size = stk.pop(), stk.pop(), stk.pop() extcode = ext.get_code(addr) or b"" assert utils.is_string(extcode) if not mem_extend(mem, compustate, op, start, size): return vm_exception("OOG EXTENDING MEMORY") if not data_copy(compustate, size): return vm_exception("OOG COPY DATA") for i in range(size): if s2 + i < len(extcode): mem[start + i] = safe_ord(extcode[s2 + i]) else: mem[start + i] = 0 elif op == "EXTCODEHASH": addr = utils.coerce_addr_to_hex(stk.pop() % 2 ** 160) if not ext.account_exists(addr): stk.append(0) else: extcode = ext.get_code(addr) or b"" assert utils.is_string(extcode) stk.append(utils.big_endian_to_int(utils.sha3(extcode))) # Block info elif opcode < 0x50: if op == "BLOCKHASH": stk.append(utils.big_endian_to_int(ext.block_hash(stk.pop()))) elif op == "COINBASE": stk.append(utils.big_endian_to_int(ext.block_coinbase)) elif op == "TIMESTAMP": stk.append(ext.block_timestamp) elif op == "NUMBER": stk.append(ext.block_number) elif op == "DIFFICULTY": stk.append(ext.block_difficulty) elif op == "GASLIMIT": stk.append(ext.block_gas_limit) # VM state manipulations elif opcode < 0x60: if op == "POP": stk.pop() elif op == "MLOAD": s0 = stk.pop() if not mem_extend(mem, compustate, op, s0, 32): return vm_exception("OOG EXTENDING MEMORY") stk.append(utils.bytes_to_int(mem[s0 : s0 + 32])) elif op == "MSTORE": s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, 32): return vm_exception("OOG EXTENDING MEMORY") mem[s0 : s0 + 32] = utils.encode_int32(s1) elif op == "MSTORE8": s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, 1): return vm_exception("OOG EXTENDING MEMORY") mem[s0] = s1 % 256 elif op == "SLOAD": stk.append(ext.get_storage_data(msg.to, stk.pop())) elif op == "SSTORE": s0, s1 = stk.pop(), stk.pop() if msg.static: return vm_exception("Cannot SSTORE inside a static context") if ext.get_storage_data(msg.to, s0): gascost = opcodes.GSTORAGEMOD if s1 else opcodes.GSTORAGEKILL refund = 0 if s1 else opcodes.GSTORAGEREFUND else: gascost = opcodes.GSTORAGEADD if s1 else opcodes.GSTORAGEMOD refund = 0 if compustate.gas < gascost: return vm_exception("OUT OF GAS") compustate.gas -= gascost # adds neg gascost as a refund if below zero ext.add_refund(refund) ext.set_storage_data(msg.to, s0, s1) elif op == "JUMP": compustate.pc = stk.pop() if compustate.pc >= codelen or not ( (1 << compustate.pc) & jumpdest_mask ): return vm_exception("BAD JUMPDEST") elif op == "JUMPI": s0, s1 = stk.pop(), stk.pop() if s1: compustate.pc = s0 if compustate.pc >= codelen or not ( (1 << compustate.pc) & jumpdest_mask ): return vm_exception("BAD JUMPDEST") elif op == "PC": stk.append(compustate.pc - 1) elif op == "MSIZE": stk.append(len(mem)) elif op == "GAS": stk.append(compustate.gas) # AFTER subtracting cost 1 # DUPn (eg. DUP1: a b c -> a b c c, DUP3: a b c -> a b c a) elif op[:3] == "DUP": # 0x7f - opcode is a negative number, -1 for 0x80 ... -16 for 0x8f stk.append(stk[0x7F - opcode]) # SWAPn (eg. SWAP1: a b c d -> a b d c, SWAP3: a b c d -> d b c a) elif op[:4] == "SWAP": # 0x8e - opcode is a negative number, -2 for 0x90 ... -17 for 0x9f temp = stk[0x8E - opcode] stk[0x8E - opcode] = stk[-1] stk[-1] = temp # Logs (aka "events") elif op[:3] == "LOG": """ 0xa0 ... 0xa4, 32/64/96/128/160 + len(data) gas a. Opcodes LOG0...LOG4 are added, takes 2-6 stack arguments MEMSTART MEMSZ (TOPIC1) (TOPIC2) (TOPIC3) (TOPIC4) b. Logs are kept track of during tx execution exactly the same way as suicides (except as an ordered list, not a set). Each log is in the form [address, [topic1, ... ], data] where: * address is what the ADDRESS opcode would output * data is mem[MEMSTART: MEMSTART + MEMSZ] * topics are as provided by the opcode c. The ordered list of logs in the transaction are expressed as [log0, log1, ..., logN]. """ depth = int(op[3:]) mstart, msz = stk.pop(), stk.pop() topics = [stk.pop() for x in range(depth)] compustate.gas -= msz * opcodes.GLOGBYTE if msg.static: return vm_exception("Cannot LOG inside a static context") if not mem_extend(mem, compustate, op, mstart, msz): return vm_exception("OOG EXTENDING MEMORY") data = bytearray_to_bytestr(mem[mstart : mstart + msz]) ext.log(msg.to, topics, data) log_log.trace( "LOG", to=msg.to, topics=topics, data=list(map(utils.safe_ord, data)) ) # Create a new contract elif op in ("CREATE", "CREATE2"): salt = None if op == "CREATE": value, mstart, msz = stk.pop(), stk.pop(), stk.pop() else: # CREATE2 value, mstart, msz, salt = stk.pop(), stk.pop(), stk.pop(), stk.pop() salt = salt.to_bytes(32, byteorder="big") compustate.gas -= opcodes.GSHA3WORD * ceil(msz / 32) if not mem_extend(mem, compustate, op, mstart, msz): return vm_exception("OOG EXTENDING MEMORY") if msg.static: return vm_exception("Cannot CREATE inside a static context") if ext.get_balance(msg.to) >= value and msg.depth < MAX_DEPTH: cd = CallData(mem, mstart, msz) ingas = compustate.gas ingas = all_but_1n(ingas, opcodes.CALL_CHILD_LIMIT_DENOM) create_msg = Message( msg.to, b"", value, ingas, cd, msg.depth + 1, # Used for calculating contract address to_full_shard_key=msg.to_full_shard_key, transfer_token_id=msg.transfer_token_id, gas_token_id=msg.gas_token_id, ) o, gas, data = ext.create(create_msg, salt) if o: stk.append(utils.coerce_to_int(data)) compustate.last_returned = bytearray(b"") else: stk.append(0) compustate.last_returned = bytearray(data) compustate.gas = compustate.gas - ingas + gas else: stk.append(0) compustate.last_returned = bytearray(b"") # Calls elif op in ("CALL", "CALLCODE", "DELEGATECALL", "STATICCALL"): # Pull arguments from the stack if op in ("CALL", "CALLCODE"): gas, to, value, meminstart, meminsz, memoutstart, memoutsz = ( stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), ) else: gas, to, meminstart, meminsz, memoutstart, memoutsz = ( stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), ) value = 0 # Static context prohibition if msg.static and value > 0 and op == "CALL": return vm_exception( "Cannot make a non-zero-value call inside a static context" ) # Expand memory if not mem_extend( mem, compustate, op, meminstart, meminsz ) or not mem_extend(mem, compustate, op, memoutstart, memoutsz): return vm_exception("OOG EXTENDING MEMORY") to = utils.int_to_addr(to) # Extra gas costs based on various factors extra_gas = 0 # Creating a new account if op == "CALL" and not ext.account_exists(to) and (value > 0): extra_gas += opcodes.GCALLNEWACCOUNT # Value transfer if value > 0: extra_gas += opcodes.GCALLVALUETRANSFER # Compute child gas limit if compustate.gas < extra_gas: return vm_exception("OUT OF GAS", needed=extra_gas) gas = min( gas, all_but_1n(compustate.gas - extra_gas, opcodes.CALL_CHILD_LIMIT_DENOM), ) submsg_gas = gas + opcodes.GSTIPEND * (value > 0) # Verify that there is sufficient balance and depth if ext.get_balance(msg.to) < value or msg.depth >= MAX_DEPTH: compustate.gas -= gas + extra_gas - submsg_gas stk.append(0) compustate.last_returned = bytearray(b"") else: # Subtract gas from parent compustate.gas -= gas + extra_gas assert compustate.gas >= 0 cd = CallData(mem, meminstart, meminsz) # Generate the message if op == "CALL": call_msg = Message( msg.to, to, value, submsg_gas, cd, msg.depth + 1, # Used for calculating contract address to_full_shard_key=msg.to_full_shard_key, code_address=to, static=msg.static, transfer_token_id=msg.transfer_token_id, gas_token_id=msg.gas_token_id, ) elif op == "DELEGATECALL": call_msg = Message( msg.sender, msg.to, msg.value, submsg_gas, cd, msg.depth + 1, # Used for calculating contract address to_full_shard_key=msg.to_full_shard_key, code_address=to, transfers_value=False, static=msg.static, transfer_token_id=msg.transfer_token_id, gas_token_id=msg.gas_token_id, ) elif op == "STATICCALL": call_msg = Message( msg.to, to, value, submsg_gas, cd, msg.depth + 1, # Used for calculating contract address to_full_shard_key=msg.to_full_shard_key, code_address=to, static=True, transfer_token_id=msg.transfer_token_id, gas_token_id=msg.gas_token_id, ) elif op == "CALLCODE": call_msg = Message( msg.to, msg.to, value, submsg_gas, cd, msg.depth + 1, # Used for calculating contract address to_full_shard_key=msg.to_full_shard_key, code_address=to, static=msg.static, transfer_token_id=msg.transfer_token_id, gas_token_id=msg.gas_token_id, ) else: raise Exception("Lolwut") # Get result if call_msg.to == PROC_CURRENT_MNT_ID: msg.token_id_queried = True result, gas, data = ext.msg(call_msg) if result == 0: stk.append(0) else: stk.append(1) # Set output memory for i in range(min(len(data), memoutsz)): mem[memoutstart + i] = data[i] compustate.gas += gas compustate.last_returned = bytearray(data) # Return opcode elif op == "RETURN": s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, s1): return vm_exception("OOG EXTENDING MEMORY") return peaceful_exit("RETURN", compustate.gas, mem[s0 : s0 + s1]) # Revert opcode (Metropolis) elif op == "REVERT": s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, s1): return vm_exception("OOG EXTENDING MEMORY") return revert(compustate.gas, mem[s0 : s0 + s1]) # SUICIDE opcode (also called SELFDESTRUCT) elif op == "SUICIDE": if msg.static: return vm_exception("Cannot SUICIDE inside a static context") to = utils.encode_int(stk.pop()) to = ((b"\x00" * (32 - len(to))) + to)[12:] xfer = ext.get_balance(msg.to) extra_gas = ( (not ext.account_exists(to)) * (xfer > 0) * opcodes.GCALLNEWACCOUNT ) if not eat_gas(compustate, extra_gas): return vm_exception("OUT OF GAS") ext.set_balance(to, ext.get_balance(to) + xfer) ext.set_balance(msg.to, 0) ext.add_suicide(msg.to) log_msg.debug( "SUICIDING", addr=utils.checksum_encode(msg.to), to=utils.checksum_encode(to), xferring=xfer, ) return peaceful_exit("SUICIDED", compustate.gas, []) if trace_vm: compustate.reset_prev() return peaceful_exit("CODE OUT OF RANGE", compustate.gas, [])
def int_to_addr(x): o = [b''] * 20 for i in range(20): o[19 - i] = ascii_chr(x & 0xff) x >>= 8 return b''.join(o)
def int_to_addr(x): o = [b""] * 20 for i in range(20): o[19 - i] = ascii_chr(x & 0xFF) x >>= 8 return b"".join(o)
def sxor(s1, s2): "string xor" assert len(s1) == len(s2) return b''.join( ascii_chr(safe_ord(a) ^ safe_ord(b)) for a, b in zip(s1, s2))