def mk_transaction_spv_proof(block, tx): trie.proof.push(trie.RECORDING) processblock.apply_transaction(block, tx) o = trie.proof.get_nodelist() trie.proof.pop() o2 = list(map(rlp.decode, list(set(map(rlp.encode, o))))) return o2
def test_call(block, sender, to, data='', gasprice=0, value=0): state_root_before = block.state_root assert block.has_parent() # rebuild block state before finalization parent = block.get_parent() test_block = block.init_from_parent(parent, block.coinbase, timestamp=block.timestamp) for _tx in block.get_transactions(): success, output = processblock.apply_transaction(test_block, _tx) assert success # apply transaction startgas = block.gas_limit - block.gas_used gasprice = 0 nonce = test_block.get_nonce(sender) tx = Transaction(nonce, gasprice, startgas, to, value, data) tx.sender = sender try: success, output = processblock.apply_transaction(test_block, tx) except processblock.InvalidTransaction as e: success = False assert block.state_root == state_root_before if success: return output else: log.debug('test_call failed', error=e) return None
def call(this, to, value=0, data='', sender=None, startgas=25000, gasprice=10*denoms.szabo): sender = address20(sender or this.coinbase) to = address20(to) block = this.head_candidate state_root_before = block.state_root assert block.has_parent() # rebuild block state before finalization parent = block.get_parent() test_block = block.init_from_parent(parent, block.coinbase, timestamp=block.timestamp) for tx in block.get_transactions(): success, output = processblock.apply_transaction(test_block, tx) assert success # apply transaction nonce = test_block.get_nonce(sender) tx = Transaction(nonce, gasprice, startgas, to, value, data) tx.sender = sender try: success, output = processblock.apply_transaction(test_block, tx) except processblock.InvalidTransaction as e: success = False assert block.state_root == state_root_before if success: return output else: return False
def call(this, to, value=0, data='', sender=None, startgas=25000, gasprice=60 * denoms.shannon): sender = normalize_address(sender or this.coinbase) to = normalize_address(to, allow_blank=True) block = this.head_candidate state_root_before = block.state_root assert block.has_parent() # rebuild block state before finalization parent = block.get_parent() test_block = block.init_from_parent(parent, block.coinbase, timestamp=block.timestamp) for tx in block.get_transactions(): success, output = processblock.apply_transaction(test_block, tx) assert success # apply transaction nonce = test_block.get_nonce(sender) tx = Transaction(nonce, gasprice, startgas, to, value, data) tx.sender = sender try: success, output = processblock.apply_transaction(test_block, tx) except InvalidTransaction: success = False assert block.state_root == state_root_before if success: return output else: return False
def call(self, data, block_id=None): block = self.json_rpc_server.get_block(block_id) state_root_before = block.state_root # rebuild block state before finalization if block.has_parent(): parent = block.get_parent() test_block = block.init_from_parent(parent, block.coinbase, timestamp=block.timestamp) for tx in block.get_transactions(): success, output = processblock.apply_transaction(test_block, tx) assert success else: original = block.snapshot() original['journal'] = deepcopy(original['journal']) # do not alter original journal test_block = ethereum.blocks.genesis(block.db) test_block.revert(original) # validate transaction if not isinstance(data, dict): raise BadRequestError('Transaction must be an object') to = address_decoder(data['to']) try: startgas = quantity_decoder(data['gas']) except KeyError: startgas = block.gas_limit - block.gas_used try: gasprice = quantity_decoder(data['gasPrice']) except KeyError: gasprice = 0 try: value = quantity_decoder(data['value']) except KeyError: value = 0 try: data_ = data_decoder(data['data']) except KeyError: data_ = b'' try: sender = address_decoder(data['from']) except KeyError: sender = '\x00' * 20 # apply transaction nonce = test_block.get_nonce(sender) tx = Transaction(nonce, gasprice, startgas, to, value, data_) tx.sender = sender try: success, output = processblock.apply_transaction(test_block, tx) except processblock.InvalidTransaction as e: success = False assert block.state_root == state_root_before if success: return output else: return False
def verify_transaction_spv_proof(block, tx, proof): trie.proof.push(trie.VERIFYING, proof) try: processblock.apply_transaction(block, tx) trie.proof.pop() return True except Exception as e: print(e) trie.proof.pop() return False
def call(self, data, block_id=None): block = self.json_rpc_server.get_block(block_id) state_root_before = block.state_root # rebuild block state before finalization if block.has_parent(): parent = block.get_parent() test_block = block.init_from_parent(parent, block.coinbase, timestamp=block.timestamp) for tx in block.get_transactions(): success, output = processblock.apply_transaction(test_block, tx) assert success else: original = block.snapshot() original['journal'] = deepcopy(original['journal']) # do not alter original journal test_block = ethereum.blocks.genesis(block.db) test_block.revert(original) # validate transaction if not isinstance(data, dict): raise BadRequestError('Transaction must be an object') to = address_decoder(data['to']) try: startgas = quantity_decoder(data['gas']) except KeyError: startgas = block.gas_limit - block.gas_used try: gasprice = quantity_decoder(data['gasPrice']) except KeyError: gasprice = 0 try: value = quantity_decoder(data['value']) except KeyError: value = 0 try: data_ = data_decoder(data['data']) except KeyError: data_ = b'' try: sender = address_decoder(data['from']) except KeyError: sender = '\x00' * 20 # apply transaction nonce = test_block.get_nonce(sender) tx = Transaction(nonce, gasprice, startgas, to, value, data_) tx.sender = sender try: success, output = processblock.apply_transaction(test_block, tx) except processblock.InvalidTransaction: success = False assert block.state_root == state_root_before if success: return output else: return False
def _get_trace(self, txhash): try: # index test_blk, tx, i = self._get_block_before_tx(txhash) except (KeyError, TypeError): raise Exception('Unknown Transaction %s' % txhash) # collect debug output FIXME set loglevel trace??? recorder = LogRecorder() # apply tx (thread? we don't want logs from other invocations) self.app.services.chain.add_transaction_lock.acquire() processblock.apply_transaction(test_blk, tx) # FIXME deactivate tx context switch or lock self.app.services.chain.add_transaction_lock.release() return dict(tx=txhash, trace=recorder.pop_records())
def _get_trace(self, txhash): try: # index test_blk, tx, i = self._get_block_before_tx(txhash) except (KeyError, TypeError): raise Exception('Unknown Transaction %s' % txhash) # collect debug output FIXME set loglevel trace??? recorder = LogRecorder() # apply tx (thread? we don't want logs from other invocations) self.app.services.chain.add_transaction_lock.acquire() processblock.apply_transaction( test_blk, tx) # FIXME deactivate tx context switch or lock self.app.services.chain.add_transaction_lock.release() return dict(tx=txhash, trace=recorder.pop_records())
def deliver(self, enc_num, to): # nonce = number of transactions already sent by that account head = self.app.services.chain.chain.head nonce = head.get_nonce(self.my_addr) # Took from buterin example: # https://blog.ethereum.org/2014/04/10/pyethereum-and-serpent-programming-guide/ gasprice = 10**12 # Took from buterin example: # https://blog.ethereum.org/2014/04/10/pyethereum-and-serpent-programming-guide/ startgas = 10000 value = 0 # It's just a message, don't need to send any value (TODO: confirm that info) # data is a json formatted message but has to be 'binary' unix_now = int(round(time())) payload = {} payload['when'] = unix_now payload['number'] = enc_num payload['publish_on'] = unix_now + 86400 # in 24 hours payload['published_at'] = 'http://www.example.com/foo' data = json.dumps(payload) deliver_tx = Transaction(nonce, gasprice, startgas, to, value, data) signed_deliver_tx = deliver_tx.sign(self.privkey_hex) success, output = apply_transaction(head, signed_deliver_tx)
def call(self, data, block_id=None): block = self.json_rpc_server.get_block(block_id) # rebuild block state before finalization parent = block.get_parent() test_block = block.init_from_parent(parent, block.coinbase, timestamp=block.timestamp) for tx in block.get_transactions(): success, output = processblock.apply_transaction(test_block, tx) assert success # validate transaction if not isinstance(data, dict): raise BadRequestError('Transaction must be an object') to = address_decoder(data['to']) try: startgas = quantity_decoder(data['gas']) except KeyError: startgas = block.gas_limit - block.gas_used try: gasprice = quantity_decoder(data['gasPrice']) except KeyError: gasprice = 0 try: value = quantity_decoder(data['value']) except KeyError: value = 0 try: data_ = data_decoder(data['data']) except KeyError: data_ = b'' try: sender = address_decoder(data['from']) except KeyError: sender = '\x00' * 20 # initialize transaction nonce = block.get_nonce(sender) tx = Transaction(nonce, gasprice, startgas, to, value, data_) tx.sender = sender # apply transaction try: success, output = processblock.apply_transaction(test_block, tx) except processblock.InvalidTransaction: success = False if success: return output else: return False
def test_transaction(db): k, v, k2, v2 = accounts() blk = mkquickgenesis({v: {"balance": utils.denoms.ether * 1}}, db=db) store_block(blk) blk = mine_next_block(blk) tx = get_transaction() assert tx not in blk.get_transactions() success, res = processblock.apply_transaction(blk, tx) assert tx in blk.get_transactions() assert blk.get_balance(v) == utils.denoms.finney * 990 assert blk.get_balance(v2) == utils.denoms.finney * 10
def send_raw_transaction(self, raw_transaction): from ethereum import ( processblock, tester, ) from ethereum.transactions import Transaction rlp_transaction = rlp.decode(raw_transaction, Transaction) # Manipulate `tester.state` directly success, _ = processblock.apply_transaction(self.evm.block, rlp_transaction) if not success: raise tester.TransactionFailed self.evm.last_tx = rlp_transaction return rlp_transaction.hash
def evm(self, code, sender=DEFAULT_KEY, endowment=0, gas=None): sendnonce = self.block.get_nonce(privtoaddr(sender)) transaction = transactions.contract(sendnonce, gas_price, gas_limit, endowment, code) transaction.sign(sender) if gas is not None: transaction.startgas = gas (success, output) = processblock.apply_transaction(self.block, transaction) if not success: raise ContractCreationFailed() return output
def call(_from, to, data, **kw): # pyethereum does not have direct support for non-mutating calls. # The implemenation just copies the state and discards it after. # Here we apply real transaction, but with gas price 0. # We assume the transaction does not modify the state, but nonce # will be bumped no matter what. _from = _from[2:].decode('hex') data = data[2:].decode('hex') nonce = self.state.block.get_nonce(_from) value = kw.get('value', 0) tx = Transaction(nonce, 0, 100000, to, value, data) assert _from == tester.a1 tx.sign(tester.k1) block = kw['block'] assert block == 'pending' success, output = apply_transaction(self.state.block, tx) assert success return '0x' + output.encode('hex')
def add_transaction(self, transaction): """Add a transaction to the :attr:`head_candidate` block. If the transaction is invalid, the block will not be changed. :returns: `True` is the transaction was successfully added or `False` if the transaction was invalid """ assert self.head_candidate is not None head_candidate = self.head_candidate log.debug('add tx', num_txs=self.num_transactions(), tx=transaction, on=head_candidate) if self.head_candidate.includes_transaction(transaction.hash): log.debug('known tx') return old_state_root = head_candidate.state_root # revert finalization head_candidate.state_root = self.pre_finalize_state_root try: success, output = processblock.apply_transaction( head_candidate, transaction) except InvalidTransaction as e: # if unsuccessful the prerequisites were not fullfilled # and the tx is invalid, state must not have changed log.debug('invalid tx', error=e) head_candidate.state_root = old_state_root # reset return False log.debug('valid tx') # we might have a new head_candidate (due to ctx switches in pyethapp) if self.head_candidate != head_candidate: log.debug('head_candidate changed during validation, trying again') return self.add_transaction(transaction) self.pre_finalize_state_root = head_candidate.state_root head_candidate.finalize() log.debug('tx applied', result=output) assert old_state_root != head_candidate.state_root return True
def add_transaction(self, transaction): """Add a transaction to the :attr:`head_candidate` block. If the transaction is invalid, the block will not be changed. :returns: `True` is the transaction was successfully added or `False` if the transaction was invalid """ assert self.head_candidate is not None if self.head_candidate.number < 40000: return head_candidate = self.head_candidate log.debug('add tx', num_txs=self.num_transactions(), tx=transaction, on=head_candidate) if self.head_candidate.includes_transaction(transaction.hash): log.debug('known tx') return old_state_root = head_candidate.state_root # revert finalization head_candidate.state_root = self.pre_finalize_state_root try: success, output = processblock.apply_transaction(head_candidate, transaction) except processblock.InvalidTransaction as e: # if unsuccessful the prerequisites were not fullfilled # and the tx is invalid, state must not have changed log.debug('invalid tx', error=e) head_candidate.state_root = old_state_root # reset return False log.debug('valid tx') # we might have a new head_candidate (due to ctx switches in pyethapp) if self.head_candidate != head_candidate: log.debug('head_candidate changed during validation, trying again') self.add_transaction(transaction) return self.pre_finalize_state_root = head_candidate.state_root head_candidate.finalize() log.debug('tx applied', result=output) assert old_state_root != head_candidate.state_root return True
def eth_sendRawTransaction(raw_tx): global evm global transaction_contract_addresses print('eth_sendRawTransaction') # Get a transaction object from the raw hash. tx = rlp.decode(decode_hex(strip_0x(raw_tx)), transactions.Transaction) print("") print("Raw Transaction Details:") print(" ") print(" From: " + "0x" + encode_hex(tx.sender)) print(" To: " + "0x" + encode_hex(tx.to)) print(" Gas: " + int_to_hex(tx.startgas)) print(" GasPrice: " + int_to_hex(tx.gasprice)) print(" Value: " + int_to_hex(tx.value)) print(" Data: " + "0x" + encode_hex(tx.data)) print("") (s, r) = processblock.apply_transaction(evm.block, tx) if not s: raise Exception("Transaction failed") if isContract(tx): contract_address = r else: contract_address = None tx_hash = "0x" + encode_hex(tx.hash) if contract_address != None: transaction_contract_addresses[tx_hash] = contract_address mine(evm) return tx_hash
def eth_sendRawTransaction(raw_tx): global evm global transaction_contract_addresses print 'eth_sendRawTransaction' # Get a transaction object from the raw hash. tx = rlp.decode(strip_0x(raw_tx).decode("hex"), transactions.Transaction) print "" print "Raw Transaction Details:" print " " print " From: " + "0x" + tx.sender.encode("hex") print " To: " + "0x" + tx.to.encode("hex") print " Gas: " + int_to_hex(tx.startgas) print " GasPrice: " + int_to_hex(tx.gasprice) print " Value: " + int_to_hex(tx.value) print " Data: " + "0x" + tx.data.encode("hex") print "" (s, r) = processblock.apply_transaction(evm.block, tx) if not s: raise Exception("Transaction failed") if isContract(tx): contract_address = r else: contract_address = None tx_hash = "0x" + tx.hash.encode("hex") if contract_address != None: transaction_contract_addresses[tx_hash] = contract_address evm.mine() return tx_hash
def run_state_test(params, mode): pre = params['pre'] exek = params['transaction'] env = params['env'] assert set(env.keys()) == set([ 'currentGasLimit', 'currentTimestamp', 'previousHash', 'currentCoinbase', 'currentDifficulty', 'currentNumber' ]) assert len(env['currentCoinbase']) == 40 # setup env header = blocks.BlockHeader( prevhash=decode_hex(env['previousHash']), number=parse_int_or_hex(env['currentNumber']), coinbase=decode_hex(env['currentCoinbase']), difficulty=parse_int_or_hex(env['currentDifficulty']), gas_limit=parse_int_or_hex(env['currentGasLimit']), timestamp=parse_int_or_hex(env['currentTimestamp'])) blk = blocks.Block(header, env=db_env) # setup state for address, h in list(pre.items()): assert len(address) == 40 address = decode_hex(address) assert set(h.keys()) == set(['code', 'nonce', 'balance', 'storage']) blk.set_nonce(address, parse_int_or_hex(h['nonce'])) blk.set_balance(address, parse_int_or_hex(h['balance'])) blk.set_code(address, decode_hex(h['code'][2:])) for k, v in h['storage'].items(): blk.set_storage_data(address, utils.big_endian_to_int(decode_hex(k[2:])), utils.big_endian_to_int(decode_hex(v[2:]))) for address, h in list(pre.items()): address = decode_hex(address) assert blk.get_nonce(address) == parse_int_or_hex(h['nonce']) assert blk.get_balance(address) == parse_int_or_hex(h['balance']) assert blk.get_code(address) == decode_hex(h['code'][2:]) for k, v in h['storage'].items(): assert blk.get_storage_data( address, utils.big_endian_to_int(decode_hex( k[2:]))) == utils.big_endian_to_int(decode_hex(v[2:])) # execute transactions orig_apply_msg = pb.apply_msg def apply_msg_wrapper(ext, msg): def blkhash(n): if n >= blk.number or n < blk.number - 256: return b'' else: return utils.sha3(to_string(n)) ext.block_hash = blkhash return orig_apply_msg(ext, msg) pb.apply_msg = apply_msg_wrapper try: tx = transactions.Transaction( nonce=parse_int_or_hex(exek['nonce'] or b"0"), gasprice=parse_int_or_hex(exek['gasPrice'] or b"0"), startgas=parse_int_or_hex(exek['gasLimit'] or b"0"), to=decode_hex(exek['to'][2:] if exek['to'][:2] == b'0x' else exek['to']), value=parse_int_or_hex(exek['value'] or b"0"), data=decode_hex(remove_0x_head(exek['data']))) except InvalidTransaction: tx = None success, output = False, b'' time_pre = time.time() time_post = time_pre else: if 'secretKey' in exek: tx.sign(exek['secretKey']) elif all(key in exek for key in ['v', 'r', 's']): tx.v = decode_hex(remove_0x_head(exek['v'])) tx.r = decode_hex(remove_0x_head(exek['r'])) tx.s = decode_hex(remove_0x_head(exek['s'])) else: assert False time_pre = time.time() try: success, output = pb.apply_transaction(blk, tx) blk.commit_state() except pb.InvalidTransaction: success, output = False, b'' blk.commit_state() pass time_post = time.time() if tx.to == b'': output = blk.get_code(output) pb.apply_msg = orig_apply_msg params2 = copy.deepcopy(params) if success: params2['logs'] = [log.to_dict() for log in blk.get_receipt(0).logs] params2['out'] = b'0x' + encode_hex(output) params2['post'] = copy.deepcopy(blk.to_dict(True)['state']) params2['postStateRoot'] = encode_hex(blk.state.root_hash) assert 'post' in params # we always have a post state in the tests if mode == FILL: return params2 elif mode == VERIFY: params1 = copy.deepcopy(params) shouldbe, reallyis = params1.get('post', None), params2.get('post', None) compare_post_states(shouldbe, reallyis) for k in [ 'pre', 'exec', 'env', 'callcreates', 'out', 'gas', 'logs', 'postStateRoot' ]: shouldbe = params1.get(k, None) reallyis = params2.get(k, None) if shouldbe != reallyis: raise Exception("Mismatch: " + k + ':\n shouldbe %r\n reallyis %r' % (shouldbe, reallyis)) elif mode == TIME: return time_post - time_pre
def _send(self, sender, to, value, evmdata='', funid=None, abi=None, # pylint: disable=too-many-arguments profiling=0): # pylint: disable=too-many-locals if funid is not None or abi is not None: raise Exception( 'Send with funid+abi is deprecated. Please use the abi_contract mechanism' ) start_time = time.time() gas_used = self.block.gas_used sendnonce = self.block.get_nonce(privtoaddr(sender)) transaction = transactions.Transaction(sendnonce, gas_price, gas_limit, to, value, evmdata) self.last_tx = transaction transaction.sign(sender) recorder = None if profiling > 1: recorder = LogRecorder( disable_other_handlers=True, log_config=TRACE_LVL_MAP[3], ) try: (success, output) = processblock.apply_transaction(self.block, transaction) if not success: raise TransactionFailed() out = { 'output': output, } if profiling > 0: zero_bytes_count = transaction.data.count(ascii_chr(0)) non_zero_bytes_count = len(transaction.data) - zero_bytes_count zero_bytes_cost = opcodes.GTXDATAZERO * zero_bytes_count nonzero_bytes_cost = opcodes.GTXDATANONZERO * non_zero_bytes_count base_gas_cost = opcodes.GTXCOST intrinsic_gas_used = base_gas_cost + zero_bytes_cost + nonzero_bytes_cost out['time'] = time.time() - start_time out['gas'] = self.block.gas_used - gas_used - intrinsic_gas_used if profiling > 1: trace = recorder.pop_records() vm_operations = [ event['op'] for event in trace if event['event'] == 'vm' ] opdict = {} for operation in vm_operations: opdict[operation] = opdict.get(operation, 0) + 1 out['ops'] = opdict return out finally: # ensure LogRecorder has been disabled if recorder: recorder.pop_records()
def _send( self, sender, to, value, evmdata='', funid=None, abi=None, # pylint: disable=too-many-arguments profiling=0): # pylint: disable=too-many-locals if funid is not None or abi is not None: raise Exception( 'Send with funid+abi is deprecated. Please use the abi_contract mechanism' ) start_time = time.time() gas_used = self.block.gas_used sendnonce = self.block.get_nonce(privtoaddr(sender)) transaction = transactions.Transaction(sendnonce, gas_price, gas_limit, to, value, evmdata) self.last_tx = transaction transaction.sign(sender) recorder = None if profiling > 1: recorder = LogRecorder( disable_other_handlers=True, log_config=TRACE_LVL_MAP[3], ) try: (success, output) = processblock.apply_transaction(self.block, transaction) if not success: raise TransactionFailed() out = { 'output': output, } if profiling > 0: zero_bytes_count = transaction.data.count(ascii_chr(0)) non_zero_bytes_count = len(transaction.data) - zero_bytes_count zero_bytes_cost = opcodes.GTXDATAZERO * zero_bytes_count nonzero_bytes_cost = opcodes.GTXDATANONZERO * non_zero_bytes_count base_gas_cost = opcodes.GTXCOST intrinsic_gas_used = base_gas_cost + zero_bytes_cost + nonzero_bytes_cost out['time'] = time.time() - start_time out['gas'] = self.block.gas_used - gas_used - intrinsic_gas_used if profiling > 1: trace = recorder.pop_records() vm_operations = [ event['op'] for event in trace if event['event'] == 'vm' ] opdict = {} for operation in vm_operations: opdict[operation] = opdict.get(operation, 0) + 1 out['ops'] = opdict return out finally: # ensure LogRecorder has been disabled if recorder: recorder.pop_records()
def run_state_test(params, mode): pre = params['pre'] exek = params['transaction'] env = params['env'] assert set(env.keys()) == set(['currentGasLimit', 'currentTimestamp', 'previousHash', 'currentCoinbase', 'currentDifficulty', 'currentNumber']) assert len(env['currentCoinbase']) == 40 # setup env header = blocks.BlockHeader( prevhash=decode_hex(env['previousHash']), number=parse_int_or_hex(env['currentNumber']), coinbase=decode_hex(env['currentCoinbase']), difficulty=parse_int_or_hex(env['currentDifficulty']), timestamp=parse_int_or_hex(env['currentTimestamp']), # work around https://github.com/ethereum/pyethereum/issues/390 [1]: gas_limit=min(2 ** 63 - 1, parse_int_or_hex(env['currentGasLimit']))) blk = blocks.Block(header, env=db_env) # work around https://github.com/ethereum/pyethereum/issues/390 [2]: blk.gas_limit = parse_int_or_hex(env['currentGasLimit']) # setup state for address, h in list(pre.items()): assert len(address) == 40 address = decode_hex(address) assert set(h.keys()) == set(['code', 'nonce', 'balance', 'storage']) blk.set_nonce(address, parse_int_or_hex(h['nonce'])) blk.set_balance(address, parse_int_or_hex(h['balance'])) blk.set_code(address, decode_hex(h['code'][2:])) for k, v in h['storage'].items(): blk.set_storage_data(address, utils.big_endian_to_int(decode_hex(k[2:])), utils.big_endian_to_int(decode_hex(v[2:]))) for address, h in list(pre.items()): address = decode_hex(address) assert blk.get_nonce(address) == parse_int_or_hex(h['nonce']) assert blk.get_balance(address) == parse_int_or_hex(h['balance']) assert blk.get_code(address) == decode_hex(h['code'][2:]) for k, v in h['storage'].items(): assert blk.get_storage_data(address, utils.big_endian_to_int( decode_hex(k[2:]))) == utils.big_endian_to_int(decode_hex(v[2:])) # execute transactions orig_apply_msg = pb.apply_msg def apply_msg_wrapper(ext, msg): def blkhash(n): if n >= blk.number or n < blk.number - 256: return b'' else: return utils.sha3(to_string(n)) ext.block_hash = blkhash return orig_apply_msg(ext, msg) pb.apply_msg = apply_msg_wrapper try: tx = transactions.Transaction( nonce=parse_int_or_hex(exek['nonce'] or b"0"), gasprice=parse_int_or_hex(exek['gasPrice'] or b"0"), startgas=parse_int_or_hex(exek['gasLimit'] or b"0"), to=normalize_address(exek['to'], allow_blank=True), value=parse_int_or_hex(exek['value'] or b"0"), data=decode_hex(remove_0x_head(exek['data']))) except InvalidTransaction: tx = None success, output = False, b'' time_pre = time.time() time_post = time_pre else: if 'secretKey' in exek: tx.sign(exek['secretKey']) elif all(key in exek for key in ['v', 'r', 's']): tx.v = decode_hex(remove_0x_head(exek['v'])) tx.r = decode_hex(remove_0x_head(exek['r'])) tx.s = decode_hex(remove_0x_head(exek['s'])) else: assert False time_pre = time.time() try: print('trying') success, output = pb.apply_transaction(blk, tx) blk.commit_state() print('success', blk.get_receipts()[-1].gas_used) except InvalidTransaction: success, output = False, b'' blk.commit_state() pass time_post = time.time() if tx.to == b'': output = blk.get_code(output) pb.apply_msg = orig_apply_msg params2 = copy.deepcopy(params) if success: params2['logs'] = [log.to_dict() for log in blk.get_receipt(0).logs] params2['out'] = b'0x' + encode_hex(output) params2['post'] = copy.deepcopy(blk.to_dict(True)['state']) params2['postStateRoot'] = encode_hex(blk.state.root_hash) if mode == FILL: return params2 elif mode == VERIFY: params1 = copy.deepcopy(params) shouldbe, reallyis = params1.get('post', None), params2.get('post', None) compare_post_states(shouldbe, reallyis) for k in ['pre', 'exec', 'env', 'callcreates', 'out', 'gas', 'logs', 'postStateRoot']: _shouldbe = params1.get(k, None) _reallyis = params2.get(k, None) if _shouldbe != _reallyis: print(('Mismatch {key}: shouldbe {shouldbe_key} != reallyis {reallyis_key}.\n' 'post: {shouldbe_post} != {reallyis_post}').format( shouldbe_key=_shouldbe, reallyis_key=_reallyis, shouldbe_post=shouldbe, reallyis_post=reallyis, key=k)) raise Exception("Mismatch: " + k + ':\n shouldbe %r\n reallyis %r' % (_shouldbe, _reallyis)) elif mode == TIME: return time_post - time_pre
def __init__(self, header, transaction_list=[], uncles=[], db=None, parent=None, making=False): if db is None: raise TypeError("No database object given") self.db = db self.header = header self.uncles = uncles self.uncles = uncles self.suicides = [] self.logs = [] self.log_listeners = [] self.refunds = 0 self.ether_delta = 0 # Journaling cache for state tree updates self.caches = { 'balance': {}, 'nonce': {}, 'code': {}, 'storage': {}, 'all': {} } self.journal = [] if self.number > 0: self.ancestor_hashes = [self.prevhash] else: self.ancestor_hashes = [None] * 256 # do some consistency checks on parent if given if parent: if hasattr(parent, 'db') and self.db != parent.db: raise ValueError("Parent lives in different database") if self.prevhash != parent.header.hash: raise ValueError("Block's prevhash and parent's hash do not match") if self.number != parent.header.number + 1: raise ValueError("Block's number is not the successor of its parent number") if not check_gaslimit(parent, self.gas_limit): raise ValueError("Block's gaslimit is inconsistent with its parent's gaslimit") if self.difficulty != calc_difficulty(parent, self.timestamp): raise ValueError("Block's difficulty is inconsistent with its parent's difficulty") for uncle in uncles: assert isinstance(uncle, BlockHeader) original_values = { 'gas_used': header.gas_used, 'timestamp': header.timestamp, 'difficulty': header.difficulty, 'uncles_hash': header.uncles_hash, 'bloom': header.bloom, } self.transactions = Trie(db, trie.BLANK_ROOT) self.receipts = Trie(db, trie.BLANK_ROOT) # replay transactions if state is unknown state_unknown = (header.prevhash != GENESIS_PREVHASH and header.state_root != trie.BLANK_ROOT and (len(header.state_root) != 32 or b'validated:' + self.hash not in db) and not making) if state_unknown: assert transaction_list is not None if not parent: parent = self.get_parent_header() self.state = SecureTrie(Trie(db, parent.state_root)) self.transaction_count = 0 self.gas_used = 0 # replay for tx in transaction_list: success, output = processblock.apply_transaction(self, tx) self.finalize() else: # trust the state root in the header self.state = SecureTrie(Trie(self.db, header._state_root)) self.transaction_count = 0 if transaction_list: for tx in transaction_list: self.add_transaction_to_list(tx) if self.transactions.root_hash != header.tx_list_root: raise ValueError("Transaction list root hash does not match") # receipts trie populated by add_transaction_to_list is incorrect # (it doesn't know intermediate states), so reset it self.receipts = Trie(self.db, header.receipts_root) if self.number < 40000: assert len(self.transactions) == 0 # checks ############################## def must(what, f, symb, a, b): if not f(a, b): if dump_block_on_failed_verification: sys.stderr.write('%r' % self.to_dict()) raise VerificationFailed(what, a, symb, b) def must_equal(what, a, b): return must(what, lambda x, y: x == y, "==", a, b) def must_ge(what, a, b): return must(what, lambda x, y: x >= y, ">=", a, b) def must_le(what, a, b): return must(what, lambda x, y: x <= y, "<=", a, b) if parent: must_equal('prev_hash', self.prevhash, parent.hash) must_ge('gas_limit', self.gas_limit, parent.gas_limit * (GASLIMIT_ADJMAX_FACTOR - 1) // GASLIMIT_ADJMAX_FACTOR) must_le('gas_limit', self.gas_limit, parent.gas_limit * (GASLIMIT_ADJMAX_FACTOR + 1) // GASLIMIT_ADJMAX_FACTOR) must_equal('gas_used', original_values['gas_used'], self.gas_used) must_equal('timestamp', self.timestamp, original_values['timestamp']) must_equal('difficulty', self.difficulty, original_values['difficulty']) must_equal('uncles_hash', utils.sha3(rlp.encode(uncles)), original_values['uncles_hash']) assert header.block is None must_equal('state_root', self.state.root_hash, header.state_root) must_equal('tx_list_root', self.transactions.root_hash, header.tx_list_root) must_equal('receipts_root', self.receipts.root_hash, header.receipts_root) must_equal('bloom', self.bloom, original_values['bloom']) # from now on, trie roots refer to block instead of header header.block = self # Basic consistency verifications if not self.check_fields(): raise ValueError("Block is invalid") if len(self.header.extra_data) > 1024: raise ValueError("Extra data cannot exceed 1024 bytes") if self.header.coinbase == '': raise ValueError("Coinbase cannot be empty address") if not self.state.root_hash_valid(): raise ValueError("State Merkle root of block %r not found in " "database" % self) if (not self.is_genesis() and self.nonce and not self.header.check_pow()): raise ValueError("PoW check failed") self.db.put(b'validated:' + self.hash, '1')
def send(tx): success, _ = apply_transaction(self.state.block, tx) assert success # What happens in real RPC eth_send? return '0x' + tx.hash.encode('hex')
def run_state_test(params, mode): pre = params['pre'] exek = params['transaction'] env = params['env'] assert set(env.keys()) == set(['currentGasLimit', 'currentTimestamp', 'previousHash', 'currentCoinbase', 'currentDifficulty', 'currentNumber']) assert len(env['currentCoinbase']) == 40 # setup env header = blocks.BlockHeader( prevhash=decode_hex(env['previousHash']), number=parse_int_or_hex(env['currentNumber']), coinbase=decode_hex(env['currentCoinbase']), difficulty=parse_int_or_hex(env['currentDifficulty']), timestamp=parse_int_or_hex(env['currentTimestamp']), # work around https://github.com/ethereum/pyethereum/issues/390 [1]: gas_limit=min(db_env.config['MAX_GAS_LIMIT'], parse_int_or_hex(env['currentGasLimit']))) blk = blocks.Block(header, env=db_env) # work around https://github.com/ethereum/pyethereum/issues/390 [2]: blk.gas_limit = parse_int_or_hex(env['currentGasLimit']) # setup state for address, h in list(pre.items()): assert len(address) == 40 address = decode_hex(address) assert set(h.keys()) == set(['code', 'nonce', 'balance', 'storage']) blk.set_nonce(address, parse_int_or_hex(h['nonce'])) blk.set_balance(address, parse_int_or_hex(h['balance'])) blk.set_code(address, decode_hex(h['code'][2:])) for k, v in h['storage'].items(): blk.set_storage_data(address, utils.big_endian_to_int(decode_hex(k[2:])), utils.big_endian_to_int(decode_hex(v[2:]))) for address, h in list(pre.items()): address = decode_hex(address) assert blk.get_nonce(address) == parse_int_or_hex(h['nonce']) assert blk.get_balance(address) == parse_int_or_hex(h['balance']) assert blk.get_code(address) == decode_hex(h['code'][2:]) for k, v in h['storage'].items(): assert blk.get_storage_data(address, utils.big_endian_to_int( decode_hex(k[2:]))) == utils.big_endian_to_int(decode_hex(v[2:])) # execute transactions orig_apply_msg = pb.apply_msg def apply_msg_wrapper(ext, msg): def blkhash(n): if n >= blk.number or n < blk.number - 256: return b'' else: return utils.sha3(to_string(n)) ext.block_hash = blkhash return orig_apply_msg(ext, msg) pb.apply_msg = apply_msg_wrapper try: tx = transactions.Transaction( nonce=parse_int_or_hex(exek['nonce'] or b"0"), gasprice=parse_int_or_hex(exek['gasPrice'] or b"0"), startgas=parse_int_or_hex(exek['gasLimit'] or b"0"), to=normalize_address(exek['to'], allow_blank=True), value=parse_int_or_hex(exek['value'] or b"0"), data=decode_hex(remove_0x_head(exek['data']))) except InvalidTransaction: tx = None success, output = False, b'' time_pre = time.time() time_post = time_pre else: if 'secretKey' in exek: tx.sign(exek['secretKey']) elif all(key in exek for key in ['v', 'r', 's']): tx.v = decode_hex(remove_0x_head(exek['v'])) tx.r = decode_hex(remove_0x_head(exek['r'])) tx.s = decode_hex(remove_0x_head(exek['s'])) else: assert False time_pre = time.time() try: print('trying') success, output = pb.apply_transaction(blk, tx) blk.commit_state() print('success', blk.get_receipts()[-1].gas_used) except InvalidTransaction: success, output = False, b'' blk.commit_state() pass time_post = time.time() if tx.to == b'': output = blk.get_code(output) pb.apply_msg = orig_apply_msg params2 = copy.deepcopy(params) if success: params2['logs'] = [log.to_dict() for log in blk.get_receipt(0).logs] params2['out'] = b'0x' + encode_hex(output) params2['post'] = copy.deepcopy(blk.to_dict(True)['state']) params2['postStateRoot'] = encode_hex(blk.state.root_hash) if mode == FILL: return params2 elif mode == VERIFY: params1 = copy.deepcopy(params) shouldbe, reallyis = params1.get('post', None), params2.get('post', None) compare_post_states(shouldbe, reallyis) for k in ['pre', 'exec', 'env', 'callcreates', 'out', 'gas', 'logs', 'postStateRoot']: _shouldbe = params1.get(k, None) _reallyis = params2.get(k, None) if str_to_bytes(k) == b'out' and _shouldbe[:1] in ('#', b'#'): _reallyis = str_to_bytes('#%s' % ((len(_reallyis) - 2) // 2)) if _shouldbe != _reallyis: print(('Mismatch {key}: shouldbe {shouldbe_key} != reallyis {reallyis_key}.\n' 'post: {shouldbe_post} != {reallyis_post}').format( shouldbe_key=_shouldbe, reallyis_key=_reallyis, shouldbe_post=shouldbe, reallyis_post=reallyis, key=k)) raise Exception("Mismatch: " + k + ':\n shouldbe %r\n reallyis %r' % (_shouldbe, _reallyis)) elif mode == TIME: return time_post - time_pre