def __call__(self, computation): computation.consume_gas(self.gas_cost, reason=self.mnemonic) value, start_position, size = computation.stack_pop( num_items=3, type_hint=constants.UINT256, ) computation.extend_memory(start_position, size) insufficient_funds = computation.state.account_db.get_balance( computation.msg.storage_address ) < value stack_too_deep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT if insufficient_funds or stack_too_deep: computation.stack_push(0) return call_data = computation.memory_read(start_position, size) create_msg_gas = self.max_child_gas_modifier( computation.get_gas_remaining() ) computation.consume_gas(create_msg_gas, reason="CREATE") creation_nonce = computation.state.account_db.get_nonce(computation.msg.storage_address) computation.state.account_db.increment_nonce(computation.msg.storage_address) contract_address = generate_contract_address( computation.msg.storage_address, creation_nonce, ) is_collision = computation.state.account_db.account_has_code_or_nonce(contract_address) if is_collision: self.logger.debug( "Address collision while creating contract: %s", encode_hex(contract_address), ) computation.stack_push(0) return child_msg = computation.prepare_child_message( gas=create_msg_gas, to=constants.CREATE_CONTRACT_ADDRESS, value=value, data=b'', code=call_data, create_address=contract_address, ) child_computation = computation.apply_child_computation(child_msg) if child_computation.is_error: computation.stack_push(0) else: computation.stack_push(contract_address) computation.return_gas(child_computation.get_gas_remaining())
def __call__(self, computation): computation.gas_meter.consume_gas(self.gas_cost, reason=self.mnemonic) value, start_position, size = computation.stack.pop( num_items=3, type_hint=constants.UINT256, ) computation.extend_memory(start_position, size) with computation.vm.state_db(read_only=True) as state_db: insufficient_funds = state_db.get_balance( computation.msg.storage_address) < value stack_too_deep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT if insufficient_funds or stack_too_deep: computation.stack.push(0) return call_data = computation.memory.read(start_position, size) create_msg_gas = self.max_child_gas_modifier( computation.gas_meter.gas_remaining) computation.gas_meter.consume_gas(create_msg_gas, reason="CREATE") with computation.vm.state_db(read_only=True) as state_db: creation_nonce = state_db.get_nonce( computation.msg.storage_address) contract_address = generate_contract_address( computation.msg.storage_address, creation_nonce) child_msg = computation.prepare_child_message( gas=create_msg_gas, to=constants.CREATE_CONTRACT_ADDRESS, value=value, data=b'', code=call_data, create_address=contract_address, ) if child_msg.is_create: child_computation = computation.vm.apply_create_message(child_msg) else: child_computation = computation.vm.apply_message(child_msg) computation.children.append(child_computation) if child_computation.error: computation.stack.push(0) else: computation.gas_meter.return_gas( child_computation.gas_meter.gas_remaining) computation.stack.push(contract_address)
def run_pre_computation(self, transaction): # Validate the transaction transaction.validate() self.validate_transaction(transaction) gas_fee = transaction.gas * transaction.gas_price with self.mutable_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) self.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)), ) return Message( gas=message_gas, to=transaction.to, sender=transaction.sender, value=transaction.value, data=data, code=code, create_address=contract_address, )
def build_evm_message(self, transaction): transaction_context = self.get_transaction_context(transaction) gas_fee = transaction.gas * transaction_context.gas_price # Buy Gas self.vm_state.account_db.delta_balance(transaction.sender, -1 * gas_fee) # Increment Nonce self.vm_state.account_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, self.vm_state.account_db.get_nonce(transaction.sender) - 1, ) data = b'' code = transaction.data else: contract_address = None data = transaction.data code = self.vm_state.account_db.get_code(transaction.to) self.vm_state.logger.debug( ("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, ) return message
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_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 _apply_frontier_transaction(evm, transaction): # # 1) Pre Computation # # Validate the transaction try: transaction.validate() except ValidationError as err: raise InvalidTransaction(str(err)) evm.validate_transaction(transaction) gas_cost = transaction.gas * transaction.gas_price sender_balance = evm.state_db.get_balance(transaction.sender) # Buy Gas evm.state_db.set_balance(transaction.sender, sender_balance - gas_cost) # Increment Nonce evm.state_db.increment_nonce(transaction.sender) # Setup VM Message message_gas = transaction.gas - transaction.intrensic_gas if transaction.to == constants.CREATE_CONTRACT_ADDRESS: contract_address = generate_contract_address( transaction.sender, evm.state_db.get_nonce(transaction.sender) - 1, ) data = b'' code = transaction.data else: contract_address = None data = transaction.data code = evm.state_db.get_code(transaction.to) if evm.logger: evm.logger.info( ("TRANSACTION: sender: %s | to: %s | value: %s | gas: %s | " "gas-price: %s | s: %s | r: %s | v: %s | data: %s"), encode_hex(transaction.sender), encode_hex(transaction.to), transaction.value, transaction.gas, transaction.gas_price, transaction.s, transaction.r, transaction.v, encode_hex(transaction.data), ) message = Message( gas=message_gas, gas_price=transaction.gas_price, to=transaction.to, sender=transaction.sender, value=transaction.value, data=data, code=code, create_address=contract_address, ) # # 2) Apply the message to the EVM. # if message.is_create: computation = evm.apply_create_message(message) else: computation = evm.apply_message(message) # # 2) Post Computation # if computation.error: # Miner Fees transaction_fee = transaction.gas * transaction.gas_price if evm.logger: evm.logger.debug('TRANSACTION FEE: %s', transaction_fee) coinbase_balance = evm.state_db.get_balance(evm.block.header.coinbase) evm.state_db.set_balance( evm.block.header.coinbase, coinbase_balance + transaction_fee, ) else: # Suicide Refunds num_deletions = len(computation.get_accounts_for_deletion()) if num_deletions: computation.gas_meter.refund_gas(constants.REFUND_SUICIDE * 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: if evm.logger: evm.logger.debug( 'TRANSACTION REFUND: %s -> %s', gas_refund_amount, encode_hex(message.sender), ) sender_balance = evm.state_db.get_balance(message.sender) evm.state_db.set_balance(message.sender, sender_balance + gas_refund_amount) # Miner Fees transaction_fee = (transaction.gas - gas_remaining - gas_refund) * transaction.gas_price if evm.logger: evm.logger.debug( 'TRANSACTION FEE: %s -> %s', transaction_fee, encode_hex(evm.block.header.coinbase), ) coinbase_balance = evm.state_db.get_balance(evm.block.header.coinbase) evm.state_db.set_balance( evm.block.header.coinbase, coinbase_balance + transaction_fee, ) # Suicides for account, beneficiary in computation.get_accounts_for_deletion(): # TODO: need to figure out how we prevent multiple suicides from # the same account and if this is the right place to put this. if evm.logger is not None: evm.logger.debug('DELETING ACCOUNT: %s', encode_hex(account)) evm.state_db.set_balance(account, 0) evm.state_db.delete_account(account) return computation
def __call__(self, computation): computation.gas_meter.consume_gas(self.gas_cost, reason=self.mnemonic) value, start_position, size = computation.stack.pop( num_items=3, type_hint=constants.UINT256, ) computation.extend_memory(start_position, size) with computation.vm_state.state_db(read_only=True) as state_db: insufficient_funds = state_db.get_balance( computation.msg.storage_address) < value stack_too_deep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT if insufficient_funds or stack_too_deep: computation.stack.push(0) return call_data = computation.memory.read(start_position, size) create_msg_gas = self.max_child_gas_modifier( computation.gas_meter.gas_remaining ) computation.gas_meter.consume_gas(create_msg_gas, reason="CREATE") with computation.vm_state.state_db() as state_db: creation_nonce = state_db.get_nonce(computation.msg.storage_address) state_db.increment_nonce(computation.msg.storage_address) contract_address = generate_contract_address( computation.msg.storage_address, creation_nonce, ) is_collision = state_db.account_has_code_or_nonce(contract_address) if is_collision: computation.vm_state.logger.debug( "Address collision while creating contract: %s", encode_hex(contract_address), ) computation.stack.push(0) return child_msg = computation.prepare_child_message( gas=create_msg_gas, to=constants.CREATE_CONTRACT_ADDRESS, value=value, data=b'', code=call_data, create_address=contract_address, ) child_computation = computation.apply_child_computation(child_msg) if child_computation.is_error: computation.stack.push(0) else: computation.stack.push(contract_address) computation.gas_meter.return_gas(child_computation.gas_meter.gas_remaining)