def test(): t.gas_price = 0 s = t.state() c = s.abi_contract('randao.se') votes = [] ids = [] xor = 0 for i in range(5): r = random.randrange(2**256) xor ^= r votes.append(utils.zpad(utils.encode_int(r), 32)) f = c.getFee() for i in range(5): ids.append(c.submitHash(utils.sha3(votes[i]), value=f)) while c.getPhase() == 0: s.mine(10) for i in range(5): c.submitValue(ids[i], votes[i]) while c.getPhase() == 1: s.mine(10) c.claimResults() assert c.getNextResultPos() == 1 assert c.getResult(0) == utils.zpad( utils.encode_int(xor), 32), (c.getResult(0), utils.zpad(utils.encode_int(xor), 32))
def test(): t.gas_price = 0 s = t.state() c = s.abi_contract("randao.se") votes = [] ids = [] xor = 0 for i in range(5): r = random.randrange(2 ** 256) xor ^= r votes.append(utils.zpad(utils.encode_int(r), 32)) f = c.getFee() for i in range(5): ids.append(c.submitHash(utils.sha3(votes[i]), value=f)) while c.getPhase() == 0: s.mine(10) for i in range(5): c.submitValue(ids[i], votes[i]) while c.getPhase() == 1: s.mine(10) c.claimResults() assert c.getNextResultPos() == 1 assert c.getResult(0) == utils.zpad(utils.encode_int(xor), 32), ( c.getResult(0), utils.zpad(utils.encode_int(xor), 32), )
def to_dict(self): odict = self.storage_trie.to_dict() for k, v in self.storage_cache.items(): odict[utils.encode_int(k)] = rlp.encode(utils.encode_int(v)) return {'balance': str(self.balance), 'nonce': str(self.nonce), 'code': '0x' + encode_hex(self.code), 'storage': {'0x' + encode_hex(key.lstrip(b'\x00') or b'\x00'): '0x' + encode_hex(rlp.decode(val)) for key, val in odict.items()}}
def mk_independent_transaction_spv_proof(block, index): block = blocks.Block.init_from_header(block.db, block.list_header()) tx = transactions.Transaction.create(block.get_transaction(index)) block.get_receipt(index) if index > 0: pre_med, pre_gas, _, _ = block.get_receipt(index - 1) else: pre_med, pre_gas = block.get_parent().state_root, 0 block.state_root = pre_med block.gas_used = pre_gas nodes = mk_transaction_spv_proof(block, tx) nodes.extend( block.transactions.produce_spv_proof( rlp.encode(utils.encode_int(index)))) if index > 0: nodes.extend( block.transactions.produce_spv_proof( rlp.encode(utils.encode_int(index - 1)))) nodes = list(map(rlp.decode, list(set(map(rlp.encode, nodes))))) print(nodes) return rlp.encode([ utils.encode_int(64), block.get_parent().list_header(), block.list_header(), utils.encode_int(index), nodes ])
def listen(cls, log_, address=None, callback=None): if not len(log_.topics) or log_.topics[0] != cls.event_id(): return if address and address != log_.address: return # o = dict(address=log_.address) o = dict() for i, t in enumerate(log_.topics[1:]): name = cls.args[i]['name'] if cls.arg_types()[i] in ('string', 'bytes'): assert t < 2**256, "error with {}, user bytes32".format( cls.args[i]) d = encode_int(t) else: assert t < 2**256 d = zpad(encode_int(t), 32) data = abi.decode_abi([cls.arg_types()[i]], d)[0] o[name] = data o['event_type'] = cls.__name__ unindexed_types = [a['type'] for a in cls.args if not a['indexed']] o['args'] = abi.decode_abi(unindexed_types, log_.data) if callback: callback(o) else: print(o)
def sign_block(block, key, randao_parent, vchash, skips): block.header.extra_data = \ randao_parent + \ utils.zpad(utils.encode_int(skips), 32) + \ vchash for val in utils.ecsign(block.header.signing_hash, key): block.header.extra_data += utils.zpad(utils.encode_int(val), 32) return block
def _encode_function(self, signature, param_values): prefix = utils.big_endian_to_int(utils.sha3(signature)[:4]) if signature.find('(') == -1: raise RuntimeError('Invalid function signature. Missing "(" and/or ")"...') if signature.find(')') - signature.find('(') == 1: return utils.encode_int(prefix) types = signature[signature.find('(') + 1: signature.find(')')].split(',') encoded_params = encode_abi(types, param_values) return utils.zpad(utils.encode_int(prefix), 4) + encoded_params
def _encode_function(self, signature, param_values): prefix = utils.big_endian_to_int(utils.sha3(signature)[:4]) if signature.find('(') == -1: raise RuntimeError('Invalid function signature. Missing "(" and/or ")"...') if signature.find(')') - signature.find('(') == 1: return utils.encode_int(prefix) types = signature[signature.find('(') + 1: signature.find(')')].split(',') encoded_params = encode_abi(types, param_values) return utils.zpad(utils.encode_int(prefix), 4) + encoded_params
def hash_array(arr): o = b'' for x in arr: if isinstance(x, int): x = utils.zpad(utils.encode_int(x), 32) o += x return utils.big_endian_to_int(utils.sha3(o))
def hash_array(arr): o = '' for x in arr: if isinstance(x, (int, long)): x = utils.zpad(utils.encode_int(x), 32) o += x return utils.big_endian_to_int(utils.sha3(o))
def listen(self, log, noprint=False): if not len(log.topics) or log.topics[0] not in self.event_data: return types = self.event_data[log.topics[0]]['types'] name = self.event_data[log.topics[0]]['name'] names = self.event_data[log.topics[0]]['names'] indexed = self.event_data[log.topics[0]]['indexed'] indexed_types = [types[i] for i in range(len(types)) if indexed[i]] unindexed_types = [ types[i] for i in range(len(types)) if not indexed[i] ] # print('listen', log.data.encode('hex'), log.topics) deserialized_args = decode_abi(unindexed_types, log.data) o = {} c1, c2 = 0, 0 for i in range(len(names)): if indexed[i]: topic_bytes = utils.zpad(utils.encode_int(log.topics[c1 + 1]), 32) o[names[i]] = decode_single(process_type(indexed_types[c1]), topic_bytes) c1 += 1 else: o[names[i]] = deserialized_args[c2] c2 += 1 o["_event_type"] = utils.to_string(name) if not noprint: print(o) return o
def listen(self, log, noprint=False): if not len(log.topics) or log.topics[0] not in self.event_data: return types = self.event_data[log.topics[0]]['types'] name = self.event_data[log.topics[0]]['name'] names = self.event_data[log.topics[0]]['names'] indexed = self.event_data[log.topics[0]]['indexed'] indexed_types = [types[i] for i in range(len(types)) if indexed[i]] unindexed_types = [types[i] for i in range(len(types)) if not indexed[i]] # print('listen', log.data.encode('hex'), log.topics) deserialized_args = decode_abi(unindexed_types, log.data) o = {} c1, c2 = 0, 0 for i in range(len(names)): if indexed[i]: topic_bytes = utils.zpad(utils.encode_int(log.topics[c1 + 1]), 32) o[names[i]] = decode_single(process_type(indexed_types[c1]), topic_bytes) c1 += 1 else: o[names[i]] = deserialized_args[c2] c2 += 1 o["_event_type"] = utils.to_string(name) if not noprint: print(o) return o
def mk_wrapper(code): lencodepush = b'\x60' + utils.encode_int(len(code)) # length of code returner = lencodepush + b'\x60\x0c\x60\x00' # start from 12 in code, 0 in memory returner += b'\x39' # CODECOPY returner += lencodepush + b'\x60\x00' + b'\xf3' # return code assert len(returner) == 12 return returner + code
def commit_refcount_changes(self, epoch): # Save death row nodes timeout_epoch = epoch + self.ttl try: death_row_nodes = rlp.decode(self.db.get('deathrow:'+str(timeout_epoch))) except: death_row_nodes = [] for nodekey in self.death_row: refcount, val = rlp.decode(self.db.get(b'r:'+nodekey)) if refcount == ZERO_ENCODED: new_refcount = utils.encode_int(DEATH_ROW_OFFSET + timeout_epoch) self.db.put(b'r:'+nodekey, rlp.encode([new_refcount, val])) if len(self.death_row) > 0: sys.stderr.write('%d nodes marked for pruning during block %d\n' % (len(self.death_row), timeout_epoch)) death_row_nodes.extend(self.death_row) self.death_row = [] self.db.put('deathrow:'+str(timeout_epoch), rlp.encode(death_row_nodes)) # Save journal try: journal = rlp.decode(self.db.get('journal:'+str(epoch))) except: journal = [] journal.extend(self.journal) self.journal = [] self.db.put('journal:'+str(epoch), rlp.encode(journal))
def create_contract(ext, msg): #print('CREATING WITH GAS', msg.gas) sender = decode_hex(msg.sender) if len(msg.sender) == 40 else msg.sender if ext.tx_origin != msg.sender: ext._block.increment_nonce(msg.sender) nonce = utils.encode_int(ext._block.get_nonce(msg.sender) - 1) msg.to = mk_contract_address(sender, nonce) b = ext.get_balance(msg.to) if b > 0: ext.set_balance(msg.to, b) ext._block.set_nonce(msg.to, 0) ext._block.set_code(msg.to, b'') ext._block.reset_storage(msg.to) msg.is_create = True # assert not ext.get_code(msg.to) code = msg.data.extract_all() msg.data = vm.CallData([], 0, 0) res, gas, dat = _apply_msg(ext, msg, code) assert utils.is_numeric(gas) if res: if not len(dat): return 1, gas, msg.to gcost = len(dat) * opcodes.GCONTRACTBYTE if gas >= gcost: gas -= gcost else: dat = [] #print('CONTRACT CREATION OOG', 'have', gas, 'want', gcost) log_msg.debug('CONTRACT CREATION OOG', have=gas, want=gcost) ext._block.set_code(msg.to, b''.join(map(ascii_chr, dat))) return 1, gas, msg.to else: return 0, gas, b''
def create_contract(ext, msg): #print('CREATING WITH GAS', msg.gas) sender = decode_hex(msg.sender) if len(msg.sender) == 40 else msg.sender if ext.tx_origin != msg.sender: ext._block.increment_nonce(msg.sender) nonce = utils.encode_int(ext._block.get_nonce(msg.sender) - 1) msg.to = mk_contract_address(sender, nonce) b = ext.get_balance(msg.to) if b > 0: ext.set_balance(msg.to, b) ext._block.set_nonce(msg.to, 0) ext._block.set_code(msg.to, b'') ext._block.reset_storage(msg.to) msg.is_create = True # assert not ext.get_code(msg.to) code = msg.data.extract_all() msg.data = vm.CallData([], 0, 0) res, gas, dat = _apply_msg(ext, msg, code) assert utils.is_numeric(gas) if res: if not len(dat): return 1, gas, msg.to gcost = len(dat) * opcodes.GCONTRACTBYTE if gas >= gcost: gas -= gcost else: dat = [] #print('CONTRACT CREATION OOG', 'have', gas, 'want', gcost) log_msg.debug('CONTRACT CREATION OOG', have=gas, want=gcost) ext._block.set_code(msg.to, b''.join(map(ascii_chr, dat))) return 1, gas, msg.to else: return 0, gas, b''
def _safe_call(self): log.debug('create native contract instance called') assert len(self._msg.sender) == 20 assert len(self._msg.data.extract_all()) >= 4 # get native contract nc_address = registry.native_contract_address_prefix + self._msg.data.extract_all()[:4] if nc_address not in registry: return 0, self._msg.gas, b'' native_contract = registry[nc_address].im_self # get new contract address if self._ext.tx_origin != self._msg.sender: self._ext._block.increment_nonce(self._msg.sender) nonce = utils.encode_int(self._ext._block.get_nonce(self._msg.sender) - 1) self._msg.to = registry.mk_instance_address(native_contract, self._msg.sender, nonce) assert not self._ext.get_balance(self._msg.to) # must be none existant # value was initially added to this contract's address, we need to transfer success = self._ext._block.transfer_value(self.address, self._msg.to, self._msg.value) assert success assert not self._ext.get_balance(self.address) # call new instance with additional data self._msg.is_create = True self._msg.data = vm.CallData(self._msg.data.data[4:], 0, 0) res, gas, dat = registry[self._msg.to](self._ext, self._msg) assert gas >= 0 log.debug('created native contract instance', template=nc_address.encode('hex'), instance=self._msg.to.encode('hex')) return res, gas, memoryview(self._msg.to).tolist()
def encode_function_call(self, function_name, args): if function_name not in self.function_data: raise ValueError('Unkown function {}'.format(function_name)) description = self.function_data[function_name] function_selector = zpad(encode_int(description['prefix']), 4) arguments = encode_abi(description['encode_types'], args) return function_selector + arguments
def sha3num(*args): o = '' for arg in args: if isinstance(arg, (int, long)): o += utils.zpad(utils.encode_int(arg), 32) else: o += arg return utils.sha3(o)
def eth_getStorageAt(self, address, position): ''' gets account storage data at position ''' account = self.reader._get_account(address) return _encode_hex( utils.zpad(utils.encode_int(account.get_storage_data(position)), 32))
def sha3num(*args): o = '' for arg in args: if isinstance(arg, (int, long)): o += utils.zpad(utils.encode_int(arg), 32) else: o += arg return utils.sha3(o)
def mk_independent_transaction_spv_proof(block, index): block = blocks.Block.init_from_header(block.db, block.list_header()) tx = transactions.Transaction.create(block.get_transaction(index)) block.get_receipt(index) if index > 0: pre_med, pre_gas, _, _ = block.get_receipt(index - 1) else: pre_med, pre_gas = block.get_parent().state_root, 0 block.state_root = pre_med block.gas_used = pre_gas nodes = mk_transaction_spv_proof(block, tx) nodes.extend(block.transactions.produce_spv_proof(rlp.encode(utils.encode_int(index)))) if index > 0: nodes.extend(block.transactions.produce_spv_proof(rlp.encode(utils.encode_int(index - 1)))) nodes = list(map(rlp.decode, list(set(map(rlp.encode, nodes))))) print(nodes) return rlp.encode([utils.encode_int(64), block.get_parent().list_header(), block.list_header(), utils.encode_int(index), nodes])
def create_wrapper(msg): sender = decode_hex(msg.sender) if \ len(msg.sender) == 40 else msg.sender nonce = utils.encode_int(ext._block.get_nonce(msg.sender)) addr = utils.sha3(rlp.encode([sender, nonce]))[12:] hexdata = encode_hex(msg.data.extract_all()) apply_message_calls.append(dict(gasLimit=to_string(msg.gas), value=to_string(msg.value), destination=b'', data=b'0x' + hexdata)) return 1, msg.gas, addr
def get_multisend_gas(payments): o = 26002 # 21000 + 2 (CALLER) + 5000 (SELFDESTRUCT) for address, wei in payments.items(): encoded_wei = utils.encode_int(wei) or b'\x00' # 20 bytes in txdata for address = 1360 # bytes in txdata for wei = 68 * n # gas for pushes and pops = 3 * 7 + 2 = 23 # CALL = 9700 + 25000 (possible if new account) o += 1360 + 68 * len(encoded_wei) + 23 + 34700 return o
def zpadhex(data, digit=64): if type(data) == int: d = str(data) h = '0' * (64 - len(d)) + d elif type(data) == str: d = data.encode().hex() h = '0' * (64 - len(d)) + d else: h = zpad(encode_int(data), digit).hex() return h
def mk_multisend_code(payments): # expects a dictionary, {address: wei} kode = b'' for address, wei in payments.items(): kode += b'\x60\x00\x60\x00\x60\x00\x60\x00' # 0 0 0 0 encoded_wei = utils.encode_int(wei) or b'\x00' kode += utils.ascii_chr(0x5f + len(encoded_wei)) + encoded_wei # value kode += b'\x73' + utils.normalize_address(address) # to kode += b'\x60\x00\xf1\x50' # 0 CALL POP kode += b'\x33\xff' # CALLER SELFDESTRUCT return kode
def create_wrapper(msg): sender = decode_hex(msg.sender) if \ len(msg.sender) == 40 else msg.sender nonce = utils.encode_int(ext._block.get_nonce(msg.sender)) addr = utils.sha3(rlp.encode([sender, nonce]))[12:] hexdata = encode_hex(msg.data.extract_all()) apply_message_calls.append(dict(gasLimit=to_string(msg.gas), value=to_string(msg.value), destination=b'', data=b'0x' + hexdata)) return 1, msg.gas, addr
def eth_getStorageAt(self, address, position): """Get account storage data at position. :param address: :param position: :return: """ account = self.reader._get_account(address) return _encode_hex( utils.zpad(utils.encode_int(account.get_storage_data(position)), 32))
def rlp_cost(nonce): if nonce == 0: return 1036 elif nonce <= 127: return 906 else: hex = utils.encode_hex(utils.encode_int(nonce)) num_bytes = len(hex) / 2 cost = 1058 + num_bytes * 60 if nonce >= 256**8: cost -= 50 return cost
def listen(cls, log, address=None, callback=None): if not len(log.topics) or log.topics[0] != cls.event_id(): return if address and address != log.address: return o = {} for i, t in enumerate(log.topics[1:]): name = cls.args[i]['name'] if cls.arg_types()[i] in ('string', 'bytes'): d = encode_int(t) else: d = zpad(encode_int(t), 32) data = abi.decode_abi([cls.arg_types()[i]], d)[0] o[name] = data o['event_type'] = cls.__name__ unindexed_types = [a['type'] for a in cls.args if not a['indexed']] o['args'] = abi.decode_abi(unindexed_types, log.data) if callback: callback(o) else: print(o)
def listen(cls, log, address=None, callback=None): if not len(log.topics) or log.topics[0] != cls.event_id(): return if address and address != log.address: return o = {} for i, t in enumerate(log.topics[1:]): name = cls.args[i]['name'] if cls.arg_types()[i] in ('string', 'bytes'): d = encode_int(t) else: d = zpad(encode_int(t), 32) data = abi.decode_abi([cls.arg_types()[i]], d)[0] o[name] = data o['event_type'] = cls.__name__ unindexed_types = [a['type'] for a in cls.args if not a['indexed']] o['args'] = abi.decode_abi(unindexed_types, log.data) if callback: callback(o) else: print(o)
def dec_refcount(self, k): # raise Exception("WHY AM I CHANGING A REFCOUNT?!:?") node_object = rlp.decode(self.db.get(b'r:'+k)) refcount = utils.decode_int(node_object[0]) if self.logging: sys.stderr.write('decreasing %s to: %d\n' % (utils.encode_hex(k), refcount - 1)) assert refcount > 0 self.journal.append([node_object[0], k]) new_refcount = utils.encode_int(refcount - 1) self.db.put(b'r:'+k, rlp.encode([new_refcount, node_object[1]])) if new_refcount == ZERO_ENCODED: self.death_row.append(k)
def decode_event(self, log_topics, log_data): """ Return a dictionary representation the log. Note: This function won't work with anonymous events. Args: log_topics (List[bin]): The log's indexed arguments. log_data (bin): The encoded non-indexed arguments. """ # topics[0]: keccak(EVENT_NAME+"("+EVENT_ARGS.map(canonical_type_of).join(",")+")") # If the event is declared as anonymous the topics[0] is not generated; if not len(log_topics) or log_topics[0] not in self.event_data: raise ValueError('Unknown log type') event_id_ = log_topics[0] event = self.event_data[event_id_] # data: abi_serialise(EVENT_NON_INDEXED_ARGS) # EVENT_NON_INDEXED_ARGS is the series of EVENT_ARGS that are not # indexed, abi_serialise is the ABI serialisation function used for # returning a series of typed values from a function. unindexed_types = [ type_ for type_, indexed in zip(event['types'], event['indexed']) if not indexed ] unindexed_args = decode_abi(unindexed_types, log_data) # topics[n]: EVENT_INDEXED_ARGS[n - 1] # EVENT_INDEXED_ARGS is the series of EVENT_ARGS that are indexed indexed_count = 1 # skip topics[0] result = {} for name, type_, indexed in zip( event['names'], event['types'], event['indexed']): if indexed: topic_bytes = utils.zpad( utils.encode_int(log_topics[indexed_count]), 32, ) indexed_count += 1 value = decode_single(process_type(type_), topic_bytes) else: value = unindexed_args.pop(0) result[name] = value result['_event_type'] = utils.to_string(event['name']) return result
def create_contract(ext, msg): log_msg.debug('CONTRACT CREATION') #print('CREATING WITH GAS', msg.gas) sender = decode_hex(msg.sender) if len(msg.sender) == 40 else msg.sender code = msg.data.extract_all() if ext._block.number >= ext._block.config['METROPOLIS_FORK_BLKNUM']: msg.to = mk_metropolis_contract_address(msg.sender, code) if ext.get_code(msg.to): if ext.get_nonce(msg.to) >= 2 ** 40: ext.set_nonce(msg.to, (ext.get_nonce(msg.to) + 1) % 2 ** 160) msg.to = normalize_address((ext.get_nonce(msg.to) - 1) % 2 ** 160) else: ext.set_nonce(msg.to, (big_endian_to_int(msg.to) + 2) % 2 ** 160) msg.to = normalize_address((ext.get_nonce(msg.to) - 1) % 2 ** 160) else: if ext.tx_origin != msg.sender: ext._block.increment_nonce(msg.sender) nonce = utils.encode_int(ext._block.get_nonce(msg.sender) - 1) msg.to = mk_contract_address(sender, nonce) b = ext.get_balance(msg.to) if b > 0: ext.set_balance(msg.to, b) ext._block.set_nonce(msg.to, 0) ext._block.set_code(msg.to, b'') ext._block.reset_storage(msg.to) msg.is_create = True # assert not ext.get_code(msg.to) msg.data = vm.CallData([], 0, 0) snapshot = ext._block.snapshot() res, gas, dat = _apply_msg(ext, msg, code) assert utils.is_numeric(gas) if res: if not len(dat): return 1, gas, msg.to gcost = len(dat) * opcodes.GCONTRACTBYTE if gas >= gcost: gas -= gcost else: dat = [] log_msg.debug('CONTRACT CREATION OOG', have=gas, want=gcost, block_number=ext._block.number) if ext._block.number >= ext._block.config['HOMESTEAD_FORK_BLKNUM']: ext._block.revert(snapshot) return 0, 0, b'' ext._block.set_code(msg.to, b''.join(map(ascii_chr, dat))) return 1, gas, msg.to else: return 0, gas, b''
def create_contract(ext, msg): log_msg.debug("CONTRACT CREATION") # print('CREATING WITH GAS', msg.gas) sender = decode_hex(msg.sender) if len(msg.sender) == 40 else msg.sender code = msg.data.extract_all() if ext._block.number >= ext._block.config["METROPOLIS_FORK_BLKNUM"]: msg.to = mk_metropolis_contract_address(msg.sender, code) if ext.get_code(msg.to): if ext.get_nonce(msg.to) >= 2 ** 40: ext.set_nonce(msg.to, (ext.get_nonce(msg.to) + 1) % 2 ** 160) msg.to = normalize_address((ext.get_nonce(msg.to) - 1) % 2 ** 160) else: ext.set_nonce(msg.to, (big_endian_to_int(msg.to) + 2) % 2 ** 160) msg.to = normalize_address((ext.get_nonce(msg.to) - 1) % 2 ** 160) else: if ext.tx_origin != msg.sender: ext._block.increment_nonce(msg.sender) nonce = utils.encode_int(ext._block.get_nonce(msg.sender) - 1) msg.to = mk_contract_address(sender, nonce) b = ext.get_balance(msg.to) if b > 0: ext.set_balance(msg.to, b) ext._block.set_nonce(msg.to, 0) ext._block.set_code(msg.to, b"") ext._block.reset_storage(msg.to) msg.is_create = True # assert not ext.get_code(msg.to) msg.data = vm.CallData([], 0, 0) snapshot = ext._block.snapshot() res, gas, dat = _apply_msg(ext, msg, code) assert utils.is_numeric(gas) if res: if not len(dat): return 1, gas, msg.to gcost = len(dat) * opcodes.GCONTRACTBYTE if gas >= gcost: gas -= gcost else: dat = [] log_msg.debug("CONTRACT CREATION OOG", have=gas, want=gcost, block_number=ext._block.number) if ext._block.number >= ext._block.config["HOMESTEAD_FORK_BLKNUM"]: ext._block.revert(snapshot) return 0, 0, b"" ext._block.set_code(msg.to, b"".join(map(ascii_chr, dat))) return 1, gas, msg.to else: return 0, gas, b""
def decode_contract_call(contract_abi, call_data): call_data_bin = decode_hex(call_data) method_signature = call_data_bin[:4] for description in contract_abi: if description.get('type') != 'function': continue method_name = normalize_abi_method_name(description['name']) arg_types = [item['type'] for item in description['inputs']] method_id = get_abi_method_id(method_name, arg_types) if zpad(encode_int(method_id), 4) == method_signature: try: args = decode_abi(arg_types, call_data_bin[4:]) except AssertionError: # Invalid args continue return method_name, args
def make_match(self, buyer, seller): if buyer.epoch < self.current_block + self.SEALED_WINDOW: print(self.name, 'making sealed offer', buyer.id, seller.id) # TODO: check hash for adding sealed offer, ie hash preferences? # TODO: rework this, see reveal hash_arr = [buyer.epoch, buyer.id, seller.id] shasum = utils.sha3(''.join(map(lambda x: utils.zpad(utils.encode_int(x), 32), hash_arr))) # shasum = utils.sha3(hash_arr) # TODO check epoch against SEALED_WINDOW offer_id = self.market.add_sealed_offer(buyer.id, shasum) print(self.name, 'shasum', utils.decode_int(shasum)) # TODO, combine preferences # TODO rework this, can probably just have buyer and seller instead of id's only offer = Offer(offer_id, buyer.epoch, buyer.id, seller.id, shasum, buyer.preferences) self.sealed_offers.append(offer)
def new_ticket(self, price): ticket_id = self.market.add() # self.market.add_preference(ticket, 'head', 10) # self.market.add_preference(ticket, 'tail', 20) self.market.add_preference(ticket_id, 'price', price) self.market.activate(ticket_id) info = self.market.get_info(ticket_id) # Rebuild Preferences preferences = self.market.get_preferences(ticket_id) keys = [utils.encode_int(x) for x in preferences[::2]] preferences = dict(zip(keys, preferences[1::2])) del preferences[''] self.ticket = Ticket(ticket_id, info[0], info[1], preferences) print(self.name, 'created new ticket', ticket_id, price)
def inc_refcount(self, k, v): # raise Exception("WHY AM I CHANGING A REFCOUNT?!:?") try: node_object = rlp.decode(self.db.get(b'r:'+k)) refcount = utils.decode_int(node_object[0]) self.journal.append([node_object[0], k]) if refcount >= DEATH_ROW_OFFSET: refcount = 0 new_refcount = utils.encode_int(refcount + 1) self.db.put(b'r:'+k, rlp.encode([new_refcount, v])) if self.logging: sys.stderr.write('increasing %s %r to: %d\n' % (utils.encode_hex(k), v, refcount + 1)) except: self.db.put(b'r:'+k, rlp.encode([ONE_ENCODED, v])) self.journal.append([ZERO_ENCODED, k]) if self.logging: sys.stderr.write('increasing %s %r to: %d\n' % (utils.encode_hex(k), v, 1))
def OP_CREATE(): value, mstart, msz = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, msgtop.compustate, '', mstart, msz): return drop(OUT_OF_GAS) if block.get_balance(msgtop.to) >= value: sender = decode_hex(msgtop.to) if len(msgtop.to) == 40 else msgtop.to block.increment_nonce(msgtop.to) data = [0] * ((msz >> 5) + 1) copy32(mem, data, mstart, 0, msz) create_msg = Message(msgtop.to, '', value, gaz() - 100, data, msz) msgtop.compustate.gas -= gaz() - 100 nonce = utils.encode_int(block.get_nonce(msgtop.to) - 1) create_msg.to = encode_hex(utils.sha3(rlp.encode([sender, nonce]))[12:]) special[0] = 'create' special[1] = create_msg special[2] = ''.join([ascii_chr(x) for x in extract_bytes(data, 0, msz)]) else: stk.append(0)
def make_match(self, buyer, seller): if buyer.epoch < self.current_block + self.SEALED_WINDOW: print(self.name, 'making sealed offer', buyer.id, seller.id) # TODO: check hash for adding sealed offer, ie hash preferences? # TODO: rework this, see reveal hash_arr = [buyer.epoch, buyer.id, seller.id] shasum = utils.sha3(''.join( map(lambda x: utils.zpad(utils.encode_int(x), 32), hash_arr))) # shasum = utils.sha3(hash_arr) # TODO check epoch against SEALED_WINDOW offer_id = self.market.add_sealed_offer(buyer.id, shasum) print(self.name, 'shasum', utils.decode_int(shasum)) # TODO, combine preferences # TODO rework this, can probably just have buyer and seller instead of id's only offer = Offer(offer_id, buyer.epoch, buyer.id, seller.id, shasum, buyer.preferences) self.sealed_offers.append(offer)
def chain_difficulty(self): """Get the summarized difficulty. If the summarized difficulty is not stored in the database, it will be calculated recursively and put in the database. """ if self.is_genesis(): return self.difficulty elif b'difficulty:' + encode_hex(self.hash) in self.db: encoded = self.db.get(b'difficulty:' + encode_hex(self.hash)) return utils.decode_int(encoded) else: o = self.difficulty + self.get_parent().chain_difficulty() # o += sum([uncle.difficulty for uncle in self.uncles]) self.state.db.put(b'difficulty:' + encode_hex(self.hash), utils.encode_int(o)) return o return rlp.decode(rlp.encode(l)) == l
def listener(self, msg): ''' Dynamically call Methods based on first param Currently only announce exists Also calls process on new block number, based on delta event ''' event = msg['event'] # if event != 'LOG' and event != 'vm': # print(event) if event == 'LOG' and msg['to'] == self.market.address: msg_type = utils.encode_int(msg['topics'][0]).rstrip('\x00') msg_data = msg['topics'][1:] if hasattr(self, msg_type): getattr(self, msg_type)(msg_data) elif event == 'delta': if self.current_block < self.state.block.number: self.current_block = self.state.block.number self.process()
def listener(self, msg): ''' Dynamically call Methods based on first param Currently only announce exists Also calls process on new block number, based on delta event ''' event = msg['event'] # if event != 'LOG' and event != 'vm': # print(event) if event == 'LOG' and msg['to'] == self.market.address: msg_type = utils.encode_int(msg['topics'][0]).rstrip('\x00') msg_data = msg['topics'][1:] if hasattr(self, msg_type): getattr(self, msg_type)(msg_data) elif event == 'delta': if self.current_block < self.state.block.number: self.current_block = self.state.block.number self.process()
def announce(self, data): ''' A new ticket has arrived ''' ticket_id = data[0] info = self.market.get_info(ticket_id) # Rebuild Preferences preferences = self.market.get_preferences(ticket_id) keys = [utils.encode_int(x) for x in preferences[::2]] preferences = dict(zip(keys, preferences[1::2])) del preferences[''] ticket = Ticket(ticket_id, info[0], info[1], preferences) # Our match maker assumes there is a price if ticket.preferences['price'] < 0: ticket.preferences['price'] = abs(ticket.preferences['price']) self.sellers.append(ticket) else: self.buyers.append(ticket) self.process()
def encode_function_call(self, function_name, args): """ Return the encoded function call. Args: function_name (str): One of the existing functions described in the contract interface. args (List[object]): The function arguments that wll be encoded and used in the contract execution in the vm. Return: bin: The encoded function name and arguments so that it can be used with the evm to execute a funcion call, the binary string follows the Ethereum Contract ABI. """ if function_name not in self.function_data: raise ValueError('Unkown function {}'.format(function_name)) description = self.function_data[function_name] function_selector = zpad(encode_int(description['prefix']), 4) arguments = encode_abi(description['encode_types'], args) return function_selector + arguments
def encode(self, name, args): fdata = self.function_data[name] o = zpad(encode_int(fdata['prefix']), 4) + \ encode_abi(fdata['encode_types'], args) return o
def OP_SUICIDE(): to = utils.encode_int(stk.pop()) to = encode_hex((('\x00' * (32 - len(to))) + to)[12:]) block.transfer_value(msgtop.to, to, block.get_balance(msgtop.to)) block.suicides.append(msgtop.to) drop([])
def hash_value(x): if isinstance(x, (int, long)): x = utils.zpad(utils.encode_int(x), 32) return utils.big_endian_to_int(utils.sha3(x))
def abi_encode_args(method, args): "encode args for method: method_id|data" assert issubclass(method.im_class, NativeABIContract), method.im_class m_abi = method.im_class._get_method_abi(method) return zpad(encode_int(m_abi['id']), 4) + abi.encode_abi(m_abi['arg_types'], args)
else: from functools import lru_cache log = get_logger('eth.block') log_state = get_logger('eth.msg.state') Log = processblock.Log # Genesis block difficulty GENESIS_DIFFICULTY = 2**34 # Genesis block gas limit GENESIS_GAS_LIMIT = 3141592 # Genesis block prevhash, coinbase, nonce GENESIS_PREVHASH = b'\x00' * 32 GENESIS_COINBASE = b'\x00' * 20 GENESIS_NONCE = utils.zpad(utils.encode_int(42), 8) GENESIS_MIXHASH = b'\x00' * 32 # Minimum gas limit MIN_GAS_LIMIT = 125000 # Gas limit adjustment algo: # block.gas_limit = block.parent.gas_limit * 1023/1024 + # (block.gas_used * 6 / 5) / 1024 GASLIMIT_EMA_FACTOR = 1024 GASLIMIT_ADJMAX_FACTOR = 1024 BLKLIM_FACTOR_NOM = 3 BLKLIM_FACTOR_DEN = 2 # Block reward BLOCK_REWARD = 5000 * utils.denoms.finney # GHOST constants UNCLE_DEPTH_PENALTY_FACTOR = 8 NEPHEW_REWARD = BLOCK_REWARD / 32
def encode_single(typ, arg): base, sub, _ = typ # Unsigned integers: uint<sz> if base == 'uint': sub = int(sub) i = decint(arg) if not 0 <= i < 2**sub: raise ValueOutOfBounds(repr(arg)) return zpad(encode_int(i), 32) # bool: int<sz> elif base == 'bool': assert isinstance(arg, bool) return zpad(encode_int(int(arg)), 32) # Signed integers: int<sz> elif base == 'int': sub = int(sub) i = decint(arg) if not -2**(sub - 1) <= i < 2**sub: raise ValueOutOfBounds(repr(arg)) return zpad(encode_int(i % 2**sub), 32) # Unsigned reals: ureal<high>x<low> elif base == 'ureal': high, low = [int(x) for x in sub.split('x')] if not 0 <= arg < 2**high: raise ValueOutOfBounds(repr(arg)) return zpad(encode_int(arg * 2**low), 32) # Signed reals: real<high>x<low> elif base == 'real': high, low = [int(x) for x in sub.split('x')] if not -2**(high - 1) <= arg < 2**(high - 1): raise ValueOutOfBounds(repr(arg)) return zpad(encode_int((arg % 2**high) * 2**low), 32) # Strings elif base == 'string' or base == 'bytes': if not is_string(arg): raise EncodingError("Expecting string: %r" % arg) # Fixed length: string<sz> if len(sub): assert int(sub) <= 32 assert len(arg) <= int(sub) return arg + b'\x00' * (32 - len(arg)) # Variable length: string else: return zpad(encode_int(len(arg)), 32) + \ arg + \ b'\x00' * (utils.ceil32(len(arg)) - len(arg)) # Hashes: hash<sz> elif base == 'hash': if not (int(sub) and int(sub) <= 32): raise EncodingError("too long: %r" % arg) if isnumeric(arg): return zpad(encode_int(arg), 32) elif len(arg) == len(sub): return zpad(arg, 32) elif len(arg) == len(sub) * 2: return zpad(decode_hex(arg), 32) else: raise EncodingError("Could not parse hash: %r" % arg) # Addresses: address (== hash160) elif base == 'address': assert sub == '' if isnumeric(arg): return zpad(encode_int(arg), 32) elif len(arg) == 20: return zpad(arg, 32) elif len(arg) == 40: return zpad(decode_hex(arg), 32) else: raise EncodingError("Could not parse address: %r" % arg) raise EncodingError("Unhandled type: %r %r" % (base, sub))
def encoded_abi_signature(self): return ethereum_utils.zpad(ethereum_utils.encode_int(self.abi_signature), 4)
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') compustate = Compustate(gas=msg.gas) stk = compustate.stack mem = compustate.memory if code in code_cache: processed_code = code_cache[code] else: processed_code = preprocess_code(code) code_cache[code] = processed_code codelen = len(processed_code) s = time.time() op = None steps = 0 _prevop = None # for trace only while 1: # print('op: ', op, time.time() - s) # s = time.time() # stack size limit error if compustate.pc >= codelen: return peaceful_exit('CODE OUT OF RANGE', compustate.gas, []) op, in_args, out_args, fee, opcode, pushval = \ processed_code[compustate.pc] # out of gas error if fee > compustate.gas: 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))) 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))) # Apply operation compustate.gas -= fee compustate.pc += 1 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) < 1024: trace_data['memory'] = \ b''.join([encode_hex(ascii_chr(x)) for x in compustate.memory]) else: trace_data['sha3memory'] = \ encode_hex(utils.sha3(''.join([ascii_chr(x) for x in compustate.memory]))) if _prevop in ('SSTORE', 'SLOAD') 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['op'] = op trace_data['steps'] = steps if op[:4] == 'PUSH': trace_data['pushvalue'] = pushval log_vm_op.trace('vm', **trace_data) steps += 1 _prevop = op # Invalid operation if op == 'INVALID': return vm_exception('INVALID OP', opcode=opcode) # Valid operations if 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) 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 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 = b''.join(map(ascii_chr, 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(len(processed_code)) elif op == 'CODECOPY': start, s1, size = stk.pop(), stk.pop(), stk.pop() 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 s1 + i < len(processed_code): mem[start + i] = processed_code[s1 + i][4] else: mem[start + i] = 0 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] = utils.safe_ord(extcode[s2 + i]) else: mem[start + i] = 0 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) 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') data = b''.join(map(ascii_chr, mem[s0: s0 + 32])) stk.append(utils.big_endian_to_int(data)) elif op == 'MSTORE': s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, 32): return vm_exception('OOG EXTENDING MEMORY') v = s1 for i in range(31, -1, -1): mem[s0 + i] = v % 256 v //= 256 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 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 ext.add_refund(refund) # adds neg gascost as a refund if below zero ext.set_storage_data(msg.to, s0, s1) elif op == 'JUMP': compustate.pc = stk.pop() opnew = processed_code[compustate.pc][0] if \ compustate.pc < len(processed_code) else 'STOP' if opnew != 'JUMPDEST': return vm_exception('BAD JUMPDEST') elif op == 'JUMPI': s0, s1 = stk.pop(), stk.pop() if s1: compustate.pc = s0 opnew = processed_code[compustate.pc][0] if \ compustate.pc < len(processed_code) else 'STOP' if opnew != 'JUMPDEST': 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 elif op[:4] == 'PUSH': pushnum = int(op[4:]) compustate.pc += pushnum stk.append(pushval) elif op[:3] == 'DUP': depth = int(op[3:]) stk.append(stk[-depth]) elif op[:4] == 'SWAP': depth = int(op[4:]) temp = stk[-depth - 1] stk[-depth - 1] = stk[-1] stk[-1] = temp 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 not mem_extend(mem, compustate, op, mstart, msz): return vm_exception('OOG EXTENDING MEMORY') data = b''.join(map(ascii_chr, 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))) # print('LOG', msg.to, topics, list(map(ord, data))) elif op == 'CREATE': value, mstart, msz = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, msz): return vm_exception('OOG EXTENDING MEMORY') if ext.get_balance(msg.to) >= value and msg.depth < 1024: cd = CallData(mem, mstart, msz) create_msg = Message(msg.to, b'', value, compustate.gas, cd, msg.depth + 1) o, gas, addr = ext.create(create_msg) if o: stk.append(utils.coerce_to_int(addr)) compustate.gas = gas else: stk.append(0) compustate.gas = 0 else: stk.append(0) elif op == 'CALL': gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() 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.encode_int(to) to = ((b'\x00' * (32 - len(to))) + to)[12:] extra_gas = (not ext.account_exists(to)) * opcodes.GCALLNEWACCOUNT + \ (value > 0) * opcodes.GCALLVALUETRANSFER submsg_gas = gas + opcodes.GSTIPEND * (value > 0) if compustate.gas < gas + extra_gas: return vm_exception('OUT OF GAS', needed=gas+extra_gas) if ext.get_balance(msg.to) >= value and msg.depth < 1024: compustate.gas -= (gas + extra_gas) cd = CallData(mem, meminstart, meminsz) call_msg = Message(msg.to, to, value, submsg_gas, cd, msg.depth + 1, code_address=to) result, gas, data = ext.msg(call_msg) if result == 0: stk.append(0) else: stk.append(1) compustate.gas += gas for i in range(min(len(data), memoutsz)): mem[memoutstart + i] = data[i] else: compustate.gas -= (gas + extra_gas - submsg_gas) stk.append(0) elif op == 'CALLCODE' or op == 'DELEGATECALL': if op == '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 if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ not mem_extend(mem, compustate, op, memoutstart, memoutsz): return vm_exception('OOG EXTENDING MEMORY') extra_gas = (value > 0) * opcodes.GCALLVALUETRANSFER submsg_gas = gas + opcodes.GSTIPEND * (value > 0) if compustate.gas < gas + extra_gas: return vm_exception('OUT OF GAS', needed=gas+extra_gas) if ext.get_balance(msg.to) >= value and msg.depth < 1024: compustate.gas -= (gas + extra_gas) to = utils.encode_int(to) to = ((b'\x00' * (32 - len(to))) + to)[12:] cd = CallData(mem, meminstart, meminsz) if ext.post_homestead_hardfork() and op == 'DELEGATECALL': call_msg = Message(msg.sender, msg.to, msg.value, submsg_gas, cd, msg.depth + 1, code_address=to, transfers_value=False) elif op == 'DELEGATECALL': return vm_exception('OPCODE INACTIVE') else: call_msg = Message(msg.to, msg.to, value, submsg_gas, cd, msg.depth + 1, code_address=to) result, gas, data = ext.msg(call_msg) if result == 0: stk.append(0) else: stk.append(1) compustate.gas += gas for i in range(min(len(data), memoutsz)): mem[memoutstart + i] = data[i] else: compustate.gas -= (gas + extra_gas - submsg_gas) stk.append(0) 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]) elif op == 'SUICIDE': to = utils.encode_int(stk.pop()) to = ((b'\x00' * (32 - len(to))) + to)[12:] xfer = ext.get_balance(msg.to) ext.set_balance(to, ext.get_balance(to) + xfer) ext.set_balance(msg.to, 0) ext.add_suicide(msg.to) # print('suiciding %s %s %d' % (msg.to, to, xfer)) return 1, compustate.gas, []
import rlp import ethereum.utils as utils import sys from db import BaseDB DEATH_ROW_OFFSET = 2**62 ZERO_ENCODED = utils.encode_int(0) ONE_ENCODED = utils.encode_int(1) class RefcountDB(BaseDB): def __init__(self, db): self.db = db self.journal = [] self.death_row = [] try: self.kv = self.db.kv except: self.kv = None self.ttl = 500 self.logging = False # Increase the reference count associated with a key def inc_refcount(self, k, v): # raise Exception("WHY AM I CHANGING A REFCOUNT?!:?") try: node_object = rlp.decode(self.db.get(b'r:'+k)) refcount = utils.decode_int(node_object[0]) self.journal.append([node_object[0], k]) if refcount >= DEATH_ROW_OFFSET: