def run_computation(self, transaction, message): """Apply the message to the VM.""" transaction_context = self.get_transaction_context_class()( gas_price=transaction.gas_price, origin=transaction.sender, ) if message.is_create: is_collision = self.read_only_state_db.account_has_code_or_nonce( message.storage_address) if is_collision: # The address of the newly created contract has *somehow* 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(message.storage_address), )) self.logger.debug( "Address collision while creating contract: %s", encode_hex(message.storage_address), ) else: computation = self.get_computation( message, transaction_context, ).apply_create_message() else: computation = self.get_computation( message, transaction_context).apply_message() return computation
def build_computation(self, message, transaction): """Apply the message to the VM.""" transaction_context = self.get_transaction_context(transaction) if message.is_create: is_collision = self.vm_state.account_db.account_has_code_or_nonce( message.storage_address) if is_collision: # The address of the newly created contract has *somehow* collided # with an existing contract address. computation = self.vm_state.get_computation( message, transaction_context) computation._error = ContractCreationCollision( "Address collision while creating contract: {0}".format( encode_hex(message.storage_address), )) self.vm_state.logger.debug( "Address collision while creating contract: %s", encode_hex(message.storage_address), ) else: computation = self.vm_state.get_computation( message, transaction_context, ).apply_create_message() else: computation = self.vm_state.get_computation( message, transaction_context).apply_message() return computation
def run_computation(self, transaction, message): """Apply the message to the VM.""" state_db_cm = functools.partial(self.state_db, access_list=transaction.prefix_list) if transaction.code: contract_address = generate_CREATE2_contract_address( transaction.salt, transaction.code, ) else: contract_address = None transaction_context = self.get_transaction_context_class()( origin=transaction.to, sig_hash=transaction.sig_hash, transaction_gas_limit=transaction.gas, ) 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() return computation
def _execute_frontier_transaction(vm_state, transaction): # Reusable for other forks # # 1) Pre Computation # # Validate the transaction transaction.validate() vm_state.validate_transaction(transaction) gas_fee = transaction.gas * transaction.gas_price with vm_state.state_db() as state_db: # Buy Gas state_db.delta_balance(transaction.sender, -1 * gas_fee) # Increment Nonce state_db.increment_nonce(transaction.sender) # Setup VM Message message_gas = transaction.gas - transaction.intrinsic_gas if transaction.to == constants.CREATE_CONTRACT_ADDRESS: contract_address = generate_contract_address( transaction.sender, state_db.get_nonce(transaction.sender) - 1, ) data = b'' code = transaction.data else: contract_address = None data = transaction.data code = state_db.get_code(transaction.to) vm_state.logger.info( ("TRANSACTION: sender: %s | to: %s | value: %s | gas: %s | " "gas-price: %s | s: %s | r: %s | v: %s | data-hash: %s"), encode_hex(transaction.sender), encode_hex(transaction.to), transaction.value, transaction.gas, transaction.gas_price, transaction.s, transaction.r, transaction.v, encode_hex(keccak(transaction.data)), ) message = Message( gas=message_gas, to=transaction.to, sender=transaction.sender, value=transaction.value, data=data, code=code, create_address=contract_address, ) transaction_context = vm_state.get_transaction_context_class()( gas_price=transaction.gas_price, origin=transaction.sender, ) # # 2) Apply the message to the VM. # if message.is_create: with vm_state.state_db(read_only=True) as state_db: is_collision = state_db.account_has_code_or_nonce(contract_address) if is_collision: # The address of the newly created contract has *somehow* collided # with an existing contract address. computation = vm_state.get_computation(message, transaction_context) computation._error = ContractCreationCollision( "Address collision while creating contract: {0}".format( encode_hex(contract_address), )) vm_state.logger.debug( "Address collision while creating contract: %s", encode_hex(contract_address), ) else: computation = vm_state.get_computation( message, transaction_context, ).apply_create_message() else: computation = vm_state.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.gas_meter.refund_gas(REFUND_SELFDESTRUCT * num_deletions) # Gas Refunds gas_remaining = computation.get_gas_remaining() gas_refunded = computation.get_gas_refund() gas_used = transaction.gas - gas_remaining gas_refund = min(gas_refunded, gas_used // 2) gas_refund_amount = (gas_refund + gas_remaining) * transaction.gas_price if gas_refund_amount: vm_state.logger.debug( 'TRANSACTION REFUND: %s -> %s', gas_refund_amount, encode_hex(message.sender), ) with vm_state.state_db() as state_db: state_db.delta_balance(message.sender, gas_refund_amount) # Miner Fees transaction_fee = (transaction.gas - gas_remaining - gas_refund) * transaction.gas_price vm_state.logger.debug( 'TRANSACTION FEE: %s -> %s', transaction_fee, encode_hex(vm_state.coinbase), ) with vm_state.state_db() as state_db: state_db.delta_balance(vm_state.coinbase, transaction_fee) # Process Self Destructs with vm_state.state_db() 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. vm_state.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
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