def coerce_addr_to_hex(x): if is_numeric(x): return encode_hex(zpad(big_endian_int.serialize(x), 20)) elif len(x) == 40 or len(x) == 0: return x else: return encode_hex(zpad(x, 20)[-20:])
def get_connected_apps(): a_config = dict(p2p=dict(listen_host='127.0.0.1', listen_port=3005), node=dict(privkey_hex=encode_hex(crypto.sha3(b'a')))) b_config = copy.deepcopy(a_config) b_config['p2p']['listen_port'] = 3006 b_config['node']['privkey_hex'] = encode_hex(crypto.sha3(b'b')) a_app = BaseApp(a_config) peermanager.PeerManager.register_with_app(a_app) a_app.start() b_app = BaseApp(b_config) peermanager.PeerManager.register_with_app(b_app) b_app.start() a_peermgr = a_app.services.peermanager b_peermgr = b_app.services.peermanager # connect host = b_config['p2p']['listen_host'] port = b_config['p2p']['listen_port'] pubkey = crypto.privtopub(decode_hex(b_config['node']['privkey_hex'])) a_peermgr.connect((host, port), remote_pubkey=pubkey) return a_app, b_app
def to_dict(self): return { "bloom": encode_hex(bloom.b64(bloom.bloom_from_list(self.bloomables()))), "address": encode_hex(self.address), "data": b"0x" + encode_hex(self.data), "topics": [encode_hex(utils.int32.serialize(t)) for t in self.topics], }
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 create_app(node_num, config, services, app_class): num_nodes = config['num_nodes'] base_port = config['base_port'] seed = config['seed'] min_peers = config['min_peers'] max_peers = config['max_peers'] assert_config(node_num, num_nodes, min_peers, max_peers) config = copy.deepcopy(config) config['node_num'] = node_num # create this node priv_key config['node']['privkey_hex'] = encode_hex(mk_privkey( '{}:udp:{}'.format(seed, node_num).encode('utf-8'))) # set ports based on node config['discovery']['listen_port'] = base_port + node_num config['p2p']['listen_port'] = base_port + node_num config['p2p']['min_peers'] = min(10, min_peers) config['p2p']['max_peers'] = max_peers config['client_version_string'] = ('NODE{}'.format(node_num)).encode('utf-8') app = app_class(config) log.info('create_app', config=app.config) # register services for service in services: assert issubclass(service, BaseService) if service.name not in app.config['deactivated_services']: assert service.name not in app.services service.register_with_app(app) assert hasattr(app.services, service.name) return app
def test_app_restart(): host, port = '127.0.0.1', 3020 a_config = dict(p2p=dict(listen_host=host, listen_port=port), node=dict(privkey_hex=encode_hex(crypto.sha3(b'a')))) a_app = BaseApp(a_config) peermanager.PeerManager.register_with_app(a_app) # Restart app 10-times: there should be no exception for i in range(10): a_app.start() assert a_app.services.peermanager.server.started try_tcp_connect((host, port)) assert a_app.services.peermanager.num_peers() == 0 a_app.stop() assert a_app.services.peermanager.is_stopped # Start the app 10-times: there should be no exception like 'Bind error' for i in range(10): a_app.start() assert a_app.services.peermanager.server.started try_tcp_connect((host, port)) a_app.stop() assert a_app.services.peermanager.is_stopped
class MockPeerManager(peermanager.PeerManager): privkey = crypto.sha3(b'a') pubkey = crypto.privtopub(privkey) wired_services = services config = { 'client_version_string': b'mock', 'p2p': { 'listen_port': 3006 }, 'node': { 'privkey_hex': encode_hex(privkey), 'id': encode_hex(pubkey), } } def __init__(self): pass
def checksum_encode(addr): # Takes a 20-byte binary address as input addr = normalize_address(addr) o = '' v = big_endian_to_int(sha3(addr)) for i, c in enumerate(encode_hex(addr)): if c in '0123456789': o += c else: o += c.upper() if (v & (2**(255 - 4 * i))) else c.lower() return '0x' + o
def recv_pong(self, remote, echoed): "tcp addresses are only updated upon receipt of Pong packet" assert remote != self.this_node pingid = self._mkpingid(echoed, remote) log.debug('recv pong', remote=remote, pingid=encode_hex(pingid)[:8], local=self.this_node) # update address (clumsy fixme) if hasattr(remote, 'address'): # not available in tests nnodes = self.routing.neighbours(remote) if nnodes and nnodes[0] == remote: nnodes[0].address = remote.address # updated tcp address # update rest self.update(remote, pingid)
def _apply_msg(ext, msg, code): trace_msg = log_msg.is_active("trace") if trace_msg: log_msg.debug( "MSG APPLY", sender=encode_hex(msg.sender), to=encode_hex(msg.to), gas=msg.gas, value=msg.value, codelen=len(code), data=encode_hex(msg.data.extract_all()) if msg.data.size < 2500 else ("data<%d>" % msg.data.size), pre_storage=ext.log_storage(msg.to), static=msg.static, depth=msg.depth, gas_token_id=msg.gas_token_id, transfer_token_id=msg.transfer_token_id, ) # early exit if msg.sender is disallowed if transfer_failure_by_posw_balance_check(ext, msg): log_msg.warn("SENDER NOT ALLOWED", sender=encode_hex(msg.sender)) return 0, 0, [] # transfer value, quit if not enough snapshot = ext.snapshot() if msg.transfers_value: if not ext.transfer_value(msg.sender, msg.to, msg.transfer_token_id, msg.value): log_msg.debug( "MSG TRANSFER FAILED", have=ext.get_balance(msg.sender, token_id=msg.transfer_token_id), want=msg.value, ) # TODO: Why return success if the transfer failed? return 1, msg.gas, [] # Main loop if msg.code_address in ext.specials: res, gas, dat = ext.specials[msg.code_address](ext, msg) else: res, gas, dat = vm.vm_execute(ext, msg, code) if trace_msg: log_msg.debug( "MSG APPLIED", gas_remained=gas, sender=encode_hex(msg.sender), to=encode_hex(msg.to), data=dat if len(dat) < 2500 else ("data<%d>" % len(dat)), post_storage=ext.log_storage(msg.to), ) if res == 0: log_msg.debug("REVERTING") ext.revert(snapshot) return res, gas, dat
def get_app(port, seed): config = dict( discovery=dict(), node=dict(privkey_hex=encode_hex(crypto.sha3(seed))), p2p=dict(listen_port=port), ) config_discovery = config['discovery'] config_discovery['listen_host'] = '127.0.0.1' config_discovery['listen_port'] = port config_discovery['bootstrap_nodes'] = [] # create app app = BaseApp(config) discovery.NodeDiscovery.register_with_app(app) return app
def __init__(self, host, port, seed): self.address = discovery.Address(host, port) config = dict( discovery=dict(), node=dict(privkey_hex=encode_hex(crypto.sha3(seed))), p2p=dict(listen_port=port), ) config_discovery = config['discovery'] config_discovery['listen_host'] = host config_discovery['listen_port'] = port app = AppMock() app.config = config self.protocol = discovery.DiscoveryProtocol(app=app, transport=self)
def ping(self, node, replacement=None): """ successful pings should lead to an update if bucket is not full elif least recently seen, does not respond in time """ assert isinstance(node, Node) assert node != self.this_node log.debug('pinging', remote=node, local=self.this_node) echoed = self.wire.send_ping(node) pingid = self._mkpingid(echoed, node) assert pingid timeout = time.time() + k_request_timeout log.debug('set wait for pong from', remote=node, local=self.this_node, pingid=encode_hex(pingid)[:4]) self._expected_pongs[pingid] = (timeout, node, replacement)
def connect_go(): a_config = dict(p2p=dict(listen_host='127.0.0.1', listen_port=3010), node=dict(privkey_hex=encode_hex(crypto.sha3(b'a')))) a_app = BaseApp(a_config) peermanager.PeerManager.register_with_app(a_app) a_app.start() a_peermgr = a_app.services.peermanager # connect pubkey = decode_hex( "6ed2fecb28ff17dec8647f08aa4368b57790000e0e9b33a7b91f32c41b6ca9ba21600e9a8c44248ce63a71544388c6745fa291f88f8b81e109ba3da11f7b41b9" ) a_peermgr.connect(('127.0.0.1', 30303), remote_pubkey=pubkey) gevent.sleep(50) a_app.stop()
def _apply_msg(ext, msg, code): trace_msg = log_msg.is_active("trace") if trace_msg: log_msg.debug( "MSG APPLY", sender=encode_hex(msg.sender), to=encode_hex(msg.to), gas=msg.gas, value=msg.value, codelen=len(code), data=encode_hex(msg.data.extract_all()) if msg.data.size < 2500 else ("data<%d>" % msg.data.size), pre_storage=ext.log_storage(msg.to), static=msg.static, depth=msg.depth, ) # transfer value, quit if not enough snapshot = ext.snapshot() if msg.transfers_value: if msg.is_cross_shard: if not ext.deduct_value(msg.sender, msg.value): return 1, msg.gas, [] ext.add_cross_shard_transaction_deposit( quarkchain.core.CrossShardTransactionDeposit( tx_hash=msg.tx_hash, from_address=quarkchain.core.Address( msg.sender, msg.from_full_shard_key), to_address=quarkchain.core.Address(msg.to, msg.to_full_shard_key), value=msg.value, gas_price=ext.tx_gasprice, )) elif not ext.transfer_value(msg.sender, msg.to, msg.value): log_msg.debug("MSG TRANSFER FAILED", have=ext.get_balance(msg.to), want=msg.value) return 1, msg.gas, [] if msg.is_cross_shard: # Cross shard contract call is not supported return 1, msg.gas, [] # Main loop if msg.code_address in ext.specials: res, gas, dat = ext.specials[msg.code_address](ext, msg) else: res, gas, dat = vm.vm_execute(ext, msg, code) if trace_msg: log_msg.debug( "MSG APPLIED", gas_remained=gas, sender=encode_hex(msg.sender), to=encode_hex(msg.to), data=dat if len(dat) < 2500 else ("data<%d>" % len(dat)), post_storage=ext.log_storage(msg.to), ) if res == 0: log_msg.debug("REVERTING") ext.revert(snapshot) return res, gas, dat
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 create_contract(ext, msg, contract_recipient=b"", salt=None): log_msg.debug("CONTRACT CREATION") if msg.transfer_token_id != ext.default_chain_token: # TODODLL calling smart contract with non QKC transfer_token_id is not supported return 0, msg.gas, b"" code = msg.data.extract_all() if ext.tx_origin != msg.sender: ext.increment_nonce(msg.sender) if contract_recipient != b"": # apply xshard deposit, where contract address has already been specified msg.to = contract_recipient elif salt is not None: # create2 msg.to = mk_contract_address2(msg.sender, salt, utils.sha3(code)) else: nonce = utils.encode_int(ext.get_nonce(msg.sender) - 1) msg.to = mk_contract_address(msg.sender, nonce, msg.to_full_shard_key) if ext.get_nonce(msg.to) or len(ext.get_code(msg.to)): log_msg.debug("CREATING CONTRACT ON TOP OF EXISTING CONTRACT") return 0, 0, b"" if ext.account_exists(msg.to): ext.set_nonce(msg.to, 0) ext.set_code(msg.to, b"") ext.reset_storage(msg.to) msg.is_create = True # assert not ext.get_code(msg.to) msg.data = vm.CallData([], 0, 0) snapshot = ext.snapshot() ext.set_nonce(msg.to, 1) ext.reset_storage(msg.to) res, gas, dat = _apply_msg(ext, msg, code) log_msg.debug( "CONTRACT CREATION FINISHED", res=res, gas=gas, dat=dat if len(dat) < 2500 else ("data<%d>" % len(dat)), ) if res: if not len(dat): # ext.set_code(msg.to, b'') return 1, gas, msg.to gcost = len(dat) * opcodes.GCONTRACTBYTE if gas >= gcost and (len(dat) <= 24576): gas -= gcost else: log_msg.debug( "CONTRACT CREATION FAILED", have=gas, want=gcost, block_number=ext.block_number, ) ext.revert(snapshot) return 0, 0, b"" ext.set_code(msg.to, bytearray_to_bytestr(dat)) log_msg.debug("SETTING CODE", addr=encode_hex(msg.to), lendat=len(dat)) return 1, gas, msg.to else: ext.revert(snapshot) return 0, gas, dat
def _apply_msg(ext, msg, code): trace_msg = log_msg.is_active("trace") if trace_msg: log_msg.debug( "MSG APPLY", sender=encode_hex(msg.sender), to=encode_hex(msg.to), gas=msg.gas, value=msg.value, codelen=len(code), data=encode_hex(msg.data.extract_all()) if msg.data.size < 2500 else ("data<%d>" % msg.data.size), pre_storage=ext.log_storage(msg.to), static=msg.static, depth=msg.depth, gas_token_id=msg.gas_token_id, transfer_token_id=msg.transfer_token_id, ) # early exit if msg.sender is disallowed if transfer_failure_by_posw_balance_check(ext, msg): log_msg.warn("SENDER NOT ALLOWED", sender=encode_hex(msg.sender)) return 0, 0, [] # transfer value, quit if not enough snapshot = ext.snapshot() if msg.transfers_value: if not ext.transfer_value(msg.sender, msg.to, msg.transfer_token_id, msg.value): log_msg.debug( "MSG TRANSFER FAILED", have=ext.get_balance(msg.sender, token_id=msg.transfer_token_id), want=msg.value, ) return 0, 0, [] # Main loop special_proc, enable_ts = ext.specials.get(msg.code_address, (None, 0)) if special_proc and ext.block_timestamp > enable_ts: res, gas, dat = special_proc(ext, msg) else: res, gas, dat = vm.vm_execute(ext, msg, code) if trace_msg: log_msg.debug( "MSG APPLIED", gas_remained=gas, sender=encode_hex(msg.sender), to=encode_hex(msg.to), data=dat if len(dat) < 2500 else ("data<%d>" % len(dat)), post_storage=ext.log_storage(msg.to), ) if (res == 1 and code != b"" and msg.transfer_token_id != ext.default_chain_token and not msg.token_id_queried and msg.value != 0): res = 0 if res == 0: log_msg.debug("REVERTING") ext.revert(snapshot) return res, gas, dat
o = 0 for a in arr: o = (o << 8) + a return o def int_to_32bytearray(i): o = [0] * 32 for x in range(32): o[31 - x] = i & 0xFF i >>= 8 return o assert ( encode_hex(sha3(b"")) == "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" ) @Memoize def privtoaddr(k): k = normalize_key(k) x, y = privtopub(k) return sha3(encode_int32(x) + encode_int32(y))[12:] def checksum_encode(addr): # Takes a 20-byte binary address as input addr = normalize_address(addr) o = "" v = big_endian_to_int(sha3(addr))
def phx(x): return encode_hex(x)[:8]
def int_to_hex(x): o = encode_hex(encode_int(x)) return '0x' + (o[1:] if (len(o) > 0 and o[0] == b'0') else o)
def decode_addr(v): """decodes an address from serialization""" if len(v) not in [0, 20]: raise Exception("Serialized addresses must be empty or 20 bytes long!") return encode_hex(v)
def devp2p_app(env, network): seed = 0 gevent.get_hub().SYSTEM_ERROR = BaseException # get bootstrap node (node0) enode bootstrap_node_privkey = sha3("{}:udp:{}:{}".format( seed, env.cluster_config.P2P.BOOTSTRAP_HOST, env.cluster_config.P2P.BOOTSTRAP_PORT, ).encode("utf-8")) bootstrap_node_pubkey = privtopub_raw(bootstrap_node_privkey) enode = host_port_pubkey_to_uri( env.cluster_config.P2P.BOOTSTRAP_HOST, env.cluster_config.P2P.BOOTSTRAP_PORT, bootstrap_node_pubkey, ) services = [NodeDiscovery, peermanager.PeerManager, Devp2pService] # prepare config base_config = dict() for s in services: update_config_with_defaults(base_config, s.default_config) base_config["discovery"]["bootstrap_nodes"] = [ enode ] + parse_additional_bootstraps( env.cluster_config.P2P.ADDITIONAL_BOOTSTRAPS) base_config["seed"] = seed base_config["base_port"] = env.cluster_config.P2P.DISCOVERY_PORT base_config["min_peers"] = env.cluster_config.P2P.MIN_PEERS base_config["max_peers"] = env.cluster_config.P2P.MAX_PEERS min_peers = base_config["min_peers"] max_peers = base_config["max_peers"] assert min_peers <= max_peers config = copy.deepcopy(base_config) node_num = 0 config["node_num"] = env.cluster_config.P2P.DISCOVERY_PORT # create this node priv_key config["node"]["privkey_hex"] = encode_hex( sha3("{}:udp:{}:{}".format( seed, network.ip, env.cluster_config.P2P.DISCOVERY_PORT).encode("utf-8"))) # set ports based on node config["discovery"]["listen_port"] = env.cluster_config.P2P.DISCOVERY_PORT config["p2p"]["listen_port"] = env.cluster_config.P2P.DISCOVERY_PORT config["p2p"]["min_peers"] = min_peers config["p2p"]["max_peers"] = max_peers ip = network.ip config["client_version_string"] = "{}:{}".format( ip, network.port).encode("utf-8") app = Devp2pApp(config, network) Logger.info("create_app config={}".format(app.config)) # register services for service in services: assert issubclass(service, BaseService) if service.name not in app.config["deactivated_services"]: assert service.name not in app.services service.register_with_app(app) assert hasattr(app.services, service.name) serve_app(app)
def bytearray_to_int(arr): o = 0 for a in arr: o = (o << 8) + a return o def int_to_32bytearray(i): o = [0] * 32 for x in range(32): o[31 - x] = i & 0xff i >>= 8 return o assert encode_hex( sha3(b'')) == 'c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470' @Memoize def privtoaddr(k): k = normalize_key(k) x, y = privtopub(k) return sha3(encode_int32(x) + encode_int32(y))[12:] def checksum_encode(addr): # Takes a 20-byte binary address as input addr = normalize_address(addr) o = '' v = big_endian_to_int(sha3(addr)) for i, c in enumerate(encode_hex(addr)): if c in '0123456789':
def create_contract(ext, msg): log_msg.debug("CONTRACT CREATION") if msg.is_cross_shard: return 0, msg.gas, b"" code = msg.data.extract_all() if ext.tx_origin != msg.sender: ext.increment_nonce(msg.sender) if ext.post_constantinople_hardfork() and msg.sender == null_address: msg.to = mk_contract_address(msg.sender, msg.to_full_shard_key, 0) # msg.to = sha3(msg.sender + code)[12:] else: nonce = utils.encode_int(ext.get_nonce(msg.sender) - 1) msg.to = mk_contract_address(msg.sender, msg.to_full_shard_key, nonce) if ext.post_metropolis_hardfork() and (ext.get_nonce(msg.to) or len(ext.get_code(msg.to))): log_msg.debug("CREATING CONTRACT ON TOP OF EXISTING CONTRACT") return 0, 0, b"" b = ext.get_balance(msg.to) if b > 0: ext.set_balance(msg.to, b) ext.set_nonce(msg.to, 0) ext.set_code(msg.to, b"") # ext.reset_storage(msg.to) msg.is_create = True # assert not ext.get_code(msg.to) msg.data = vm.CallData([], 0, 0) snapshot = ext.snapshot() ext.set_nonce(msg.to, 1 if ext.post_spurious_dragon_hardfork() else 0) res, gas, dat = _apply_msg(ext, msg, code) log_msg.debug( "CONTRACT CREATION FINISHED", res=res, gas=gas, dat=dat if len(dat) < 2500 else ("data<%d>" % len(dat)), ) if res: if not len(dat): # ext.set_code(msg.to, b'') return 1, gas, msg.to gcost = len(dat) * opcodes.GCONTRACTBYTE if gas >= gcost and (len(dat) <= 24576 or not ext.post_spurious_dragon_hardfork()): gas -= gcost else: dat = [] log_msg.debug( "CONTRACT CREATION FAILED", have=gas, want=gcost, block_number=ext.block_number, ) if ext.post_homestead_hardfork(): ext.revert(snapshot) return 0, 0, b"" ext.set_code(msg.to, bytearray_to_bytestr(dat)) log_msg.debug("SETTING CODE", addr=encode_hex(msg.to), lendat=len(dat)) return 1, gas, msg.to else: ext.revert(snapshot) return 0, gas, dat
def dump_state(trie): res = '' for k, v in list(trie.to_dict().items()): res += '%r:%r\n' % (encode_hex(k), encode_hex(v)) return res
def __repr__(self): return "<Log(address=%r, topics=%r, data=%r)>" % ( encode_hex(self.address), self.topics, self.data, )
def main(): parser = argparse.ArgumentParser() parser.add_argument("--bootstrap_host", default="0.0.0.0", type=str) parser.add_argument("--bootstrap_port", default=29000, type=int) # p2p port for this node parser.add_argument("--node_port", default=29000, type=int) parser.add_argument("--node_num", default=0, type=int) parser.add_argument("--min_peers", default=2, type=int) parser.add_argument("--max_peers", default=10, type=int) seed = 0 args = parser.parse_args() gevent.get_hub().SYSTEM_ERROR = BaseException # get bootstrap node (node0) enode bootstrap_node_privkey = sha3("{}:udp:{}".format(0, 0).encode("utf-8")) bootstrap_node_pubkey = privtopub_raw(bootstrap_node_privkey) enode = host_port_pubkey_to_uri(args.bootstrap_host, args.bootstrap_port, bootstrap_node_pubkey) services = [NodeDiscovery, peermanager.PeerManager, ExampleService] # prepare config base_config = dict() for s in services: update_config_with_defaults(base_config, s.default_config) base_config["discovery"]["bootstrap_nodes"] = [enode] base_config["seed"] = seed base_config["base_port"] = args.node_port base_config["min_peers"] = args.min_peers base_config["max_peers"] = args.max_peers log.info("run:", base_config=base_config) min_peers = base_config["min_peers"] max_peers = base_config["max_peers"] assert min_peers <= max_peers config = copy.deepcopy(base_config) config["node_num"] = args.node_num # create this node priv_key config["node"]["privkey_hex"] = encode_hex( sha3("{}:udp:{}".format(seed, args.node_num).encode("utf-8"))) # set ports based on node config["discovery"]["listen_port"] = args.node_port config["p2p"]["listen_port"] = args.node_port config["p2p"]["min_peers"] = min(10, min_peers) config["p2p"]["max_peers"] = max_peers config["client_version_string"] = "NODE{}".format( args.node_num).encode('utf-8') app = ExampleApp(config) log.info("create_app", config=app.config) # register services for service in services: assert issubclass(service, BaseService) if service.name not in app.config["deactivated_services"]: assert service.name not in app.services service.register_with_app(app) assert hasattr(app.services, service.name) app_helper.serve_until_stopped([app])
def host_port_pubkey_to_uri(host, port, pubkey): assert len(pubkey) == 512 // 8 uri = '{}{}@{}:{}'.format(node_uri_scheme, bytes_to_str(encode_hex(pubkey)), str(host), port) return str_to_bytes(uri)
def int_to_hex(x): o = encode_hex(encode_int(x)) return "0x" + (o[1:] if (len(o) > 0 and o[0] == b"0") else o)