def test_call_checks_signature(vm, v, r, s): transaction = UserAccountTransaction(**merge(DEFAULT_TX_PARAMS, { "v": v, "r": r, "s": s })) message_params = { "gas": transaction.gas, "to": transaction.to, "sender": ENTRY_POINT, "value": 0, "code": ACCOUNT_CODE, "is_create": False, "access_list": transaction.prefix_list, } message = ShardingMessage( **assoc(message_params, "data", transaction.data)) transaction_context = ShardingTransactionContext( origin=ENTRY_POINT, sig_hash=transaction.sig_hash, transaction_gas_limit=transaction.gas, ) computation = vm.state.get_computation(message, transaction_context) computation = computation.apply_message() assert computation.is_error # error is due to bad signature, so with tx should pass with original one message = ShardingMessage( **assoc(message_params, "data", SIGNED_DEFAULT_TRANSACTION.data)) computation = vm.state.get_computation(message, transaction_context) computation = computation.apply_message() assert computation.is_success
def prepare_child_message(self, gas, to, value, data, code, **kwargs): kwargs.setdefault('sender', self.msg.storage_address) child_message = ShardingMessage(gas=gas, to=to, value=value, data=data, code=code, depth=self.msg.depth + 1, access_list=self.msg.access_list, **kwargs) return child_message
def run_pre_computation(self, transaction): state_db_cm = functools.partial(self.state_db, access_list=transaction.prefix_list) # Validate the transaction transaction.validate() self.validate_transaction(transaction) with state_db_cm() as state_db: # Setup VM Message message_gas = transaction.gas - transaction.intrinsic_gas if transaction.code: data = b'' code = transaction.code is_create = True else: data = transaction.data code = state_db.get_code(transaction.to) is_create = False self.logger.info( ("TRANSACTION: to: %s | gas: %s | " "data-hash: %s | code-hash: %s | salt: %s"), encode_hex(transaction.to), transaction.gas, encode_hex(keccak(transaction.data)), encode_hex(keccak(transaction.code)), encode_hex(transaction.salt), ) return ShardingMessage( gas=message_gas, to=transaction.to, sender=ENTRY_POINT, value=0, data=data, code=code, is_create=is_create, access_list=transaction.prefix_list, )
def execute_transaction(self, transaction): # state_db ontext manager that restricts access as specified in the transacion state_db_cm = functools.partial(self.state_db, access_list=transaction.prefix_list) # # 1) Pre Computation # # Validate the transaction transaction.validate() self.validate_transaction(transaction) with state_db_cm() as state_db: # Setup VM Message message_gas = transaction.gas - transaction.intrinsic_gas if transaction.code: contract_address = generate_CREATE2_contract_address( transaction.salt, transaction.code, ) data = b'' code = transaction.code is_create = True else: contract_address = None data = transaction.data code = state_db.get_code(transaction.to) is_create = False self.logger.info( ("TRANSACTION: to: %s | gas: %s | " "data-hash: %s | code-hash: %s | salt: %s"), encode_hex(transaction.to), transaction.gas, encode_hex(keccak(transaction.data)), encode_hex(keccak(transaction.code)), encode_hex(transaction.salt), ) message = ShardingMessage( gas=message_gas, to=transaction.to, sender=ENTRY_POINT, value=0, data=data, code=code, is_create=is_create, access_list=transaction.prefix_list, ) transaction_context = self.get_transaction_context_class()( origin=transaction.to, sig_hash=transaction.sig_hash, transaction_gas_limit=transaction.gas, ) # # 2) Apply the message to the VM. # if message.is_create: with state_db_cm(read_only=True) as state_db: is_collision = state_db.account_has_code(contract_address) # Check if contract address provided by transaction is correct if contract_address != transaction.to: computation = self.get_computation(message, transaction_context) computation._error = IncorrectContractCreationAddress( "Contract address calculated: {0} but {1} is provided". format( encode_hex(contract_address), encode_hex(transaction.to), )) self.logger.debug( "Contract address calculated: %s but %s is provided", encode_hex(contract_address), encode_hex(transaction.to), ) elif is_collision: # The address of the newly created contract has collided # with an existing contract address. computation = self.get_computation(message, transaction_context) computation._error = ContractCreationCollision( "Address collision while creating contract: {0}".format( encode_hex(contract_address), )) self.logger.debug( "Address collision while creating contract: %s", encode_hex(contract_address), ) else: computation = self.get_computation( message, transaction_context, ).apply_create_message() else: computation = self.get_computation( message, transaction_context).apply_message() # # 2) Post Computation # # Self Destruct Refunds num_deletions = len(computation.get_accounts_for_deletion()) if num_deletions: computation.refund_gas(REFUND_SELFDESTRUCT * num_deletions) # Gas Refunds transaction_fee, gas_refund_amount = computation.compute_transaction_fee_and_refund( ) if gas_refund_amount: self.logger.debug( 'TRANSACTION REFUND: %s -> %s', gas_refund_amount, encode_hex(message.to), ) with state_db_cm() as state_db: state_db.delta_balance(message.to, gas_refund_amount) # Miner Fees self.logger.debug( 'TRANSACTION FEE: %s', transaction_fee, ) # Process Self Destructs with state_db_cm() as state_db: for account, beneficiary in computation.get_accounts_for_deletion( ): # TODO: need to figure out how we prevent multiple selfdestructs from # the same account and if this is the right place to put this. self.logger.debug('DELETING ACCOUNT: %s', encode_hex(account)) # TODO: this balance setting is likely superflous and can be # removed since `delete_account` does this. state_db.set_balance(account, 0) state_db.delete_account(account) return computation