def validate_transaction(state, tx): # (1) The transaction signature is valid; if not tx.sender: # sender is set and validated on Transaction initialization raise UnsignedTransaction(tx) assert config_fork_specific_validation( state.config, state.block_number, tx) # (2) the transaction nonce is valid (equivalent to the # sender account's current nonce); req_nonce = 0 if tx.sender == null_address else state.get_nonce(tx.sender) if req_nonce != tx.nonce: raise InvalidNonce(rp(tx, 'nonce', tx.nonce, req_nonce)) # (3) the gas limit is no smaller than the intrinsic gas, # g0, used by the transaction; if tx.startgas < tx.intrinsic_gas_used: raise InsufficientStartGas( rp(tx, 'startgas', tx.startgas, tx.intrinsic_gas_used)) # (4) the sender account balance contains at least the # cost, v0, required in up-front payment. total_cost = tx.value + tx.gasprice * tx.startgas if state.get_balance(tx.sender) < total_cost: raise InsufficientBalance( rp(tx, 'balance', state.get_balance(tx.sender), total_cost)) # check block gas limit if state.gas_used + tx.startgas > state.gas_limit: raise BlockGasLimitReached( rp(tx, 'gaslimit', state.gas_used + tx.startgas, state.gas_limit)) # EIP86-specific restrictions if tx.sender == null_address and (tx.value != 0 or tx.gasprice != 0): raise InvalidTransaction( "EIP86 transactions must have 0 value and gasprice") return True
def validate_transaction(block, tx): def rp(what, actual, target): return '%r: %r actual:%r target:%r' % (tx, what, actual, target) # (1) The transaction signature is valid; if not tx.sender: # sender is set and validated on Transaction initialization if block.number >= config.default_config["METROPOLIS_FORK_BLKNUM"]: tx._sender = normalize_address(config.default_config["METROPOLIS_ENTRY_POINT"]) else: raise UnsignedTransaction(tx) if block.number >= config.default_config["HOMESTEAD_FORK_BLKNUM"]: tx.check_low_s() # (2) the transaction nonce is valid (equivalent to the # sender account's current nonce); acctnonce = block.get_nonce(tx.sender) if acctnonce != tx.nonce: raise InvalidNonce(rp('nonce', tx.nonce, acctnonce)) # (3) the gas limit is no smaller than the intrinsic gas, # g0, used by the transaction; if tx.startgas < tx.intrinsic_gas_used: raise InsufficientStartGas(rp('startgas', tx.startgas, tx.intrinsic_gas_used)) # (4) the sender account balance contains at least the # cost, v0, required in up-front payment. total_cost = tx.value + tx.gasprice * tx.startgas if block.get_balance(tx.sender) < total_cost: raise InsufficientBalance(rp('balance', block.get_balance(tx.sender), total_cost)) # check block gas limit if block.gas_used + tx.startgas > block.gas_limit: raise BlockGasLimitReached(rp('gaslimit', block.gas_used + tx.startgas, block.gas_limit)) return True
def apply_transaction(state, tx): ExTime, vmtime, CreationTime = 0, 0, 0 state.logs = [] state.suicides = [] state.refunds = 0 validate_transaction(state, tx) intrinsic_gas = tx.intrinsic_gas_used if state.is_HOMESTEAD(): assert tx.s * 2 < transactions.secpk1n if not tx.to or tx.to == CREATE_CONTRACT_ADDRESS: intrinsic_gas += opcodes.CREATE[3] if tx.startgas < intrinsic_gas: raise InsufficientStartGas( rp(tx, 'startgas', tx.startgas, intrinsic_gas)) log_tx.debug('TX NEW', txdict=tx.to_dict()) # start transacting ################# if tx.sender != null_address: state.increment_nonce(tx.sender) # buy startgas assert state.get_balance(tx.sender) >= tx.startgas * tx.gasprice state.delta_balance(tx.sender, -tx.startgas * tx.gasprice) message_data = vm.CallData([safe_ord(x) for x in tx.data], 0, len(tx.data)) message = vm.Message(tx.sender, tx.to, tx.value, tx.startgas - intrinsic_gas, message_data, code_address=tx.to) # MESSAGE ext = VMExt(state, tx) if tx.to != b'': result, gas_remained, data, ExTime, vmtime = apply_msg(ext, message) # print "Tx", "Ex. Time: ", (t2-t1)* 1000000, "Gas used: ", tx.startgas - gas_remained else: # CREATE result, gas_remained, data, ExTime, vmtime = create_contract( ext, message) # print "Create", "Ex. Time: ", (t4-t3) * 1000000, "Gas used: ", tx.startgas - gas_remained assert gas_remained >= 0 log_tx.debug("TX APPLIED", result=result, gas_remained=gas_remained, data=data) gas_used = tx.startgas - gas_remained # Transaction failed if not result: log_tx.debug('TX FAILED', reason='out of gas', startgas=tx.startgas, gas_remained=gas_remained) state.delta_balance(tx.sender, tx.gasprice * gas_remained) state.delta_balance(state.block_coinbase, tx.gasprice * gas_used) output = b'' success = 0 # Transaction success else: log_tx.debug('TX SUCCESS', data=data) state.refunds += len(set(state.suicides)) * opcodes.GSUICIDEREFUND if state.refunds > 0: log_tx.debug('Refunding', gas_refunded=min(state.refunds, gas_used // 2)) gas_remained += min(state.refunds, gas_used // 2) gas_used -= min(state.refunds, gas_used // 2) state.refunds = 0 # sell remaining gas state.delta_balance(tx.sender, tx.gasprice * gas_remained) state.delta_balance(state.block_coinbase, tx.gasprice * gas_used) if tx.to: output = bytearray_to_bytestr(data) else: output = data success = 1 state.gas_used += gas_used # Clear suicides suicides = state.suicides state.suicides = [] for s in suicides: state.set_balance(s, 0) state.del_account(s) # Pre-Metropolis: commit state after every tx if not state.is_METROPOLIS() and not SKIP_MEDSTATES: state.commit() # Construct a receipt r = mk_receipt(state, success, state.logs) _logs = list(state.logs) state.logs = [] state.add_receipt(r) state.set_param('bloom', state.bloom | r.bloom) state.set_param('txindex', state.txindex + 1) return success, output.encode("hex"), ExTime, gas_used, vmtime
def apply_transaction(block, tx): validate_transaction(block, tx) # print(block.get_nonce(tx.sender), '@@@') def rp(what, actual, target): return '%r: %r actual:%r target:%r' % (tx, what, actual, target) intrinsic_gas = tx.intrinsic_gas_used if block.number >= block.config['HOMESTEAD_FORK_BLKNUM']: assert tx.s * 2 < transactions.secpk1n if not tx.to or tx.to == CREATE_CONTRACT_ADDRESS: intrinsic_gas += opcodes.CREATE[3] if tx.startgas < intrinsic_gas: raise InsufficientStartGas(rp('startgas', tx.startgas, intrinsic_gas)) log_tx.debug('TX NEW', tx_dict=tx.log_dict()) # start transacting ################# block.increment_nonce(tx.sender) # buy startgas assert block.get_balance(tx.sender) >= tx.startgas * tx.gasprice block.delta_balance(tx.sender, -tx.startgas * tx.gasprice) message_gas = tx.startgas - intrinsic_gas message_data = vm.CallData([safe_ord(x) for x in tx.data], 0, len(tx.data)) message = vm.Message(tx.sender, tx.to, tx.value, message_gas, message_data, code_address=tx.to) # MESSAGE ext = VMExt(block, tx) if tx.to and tx.to != CREATE_CONTRACT_ADDRESS: result, gas_remained, data = apply_msg(ext, message) log_tx.debug('_res_', result=result, gas_remained=gas_remained, data=lazy_safe_encode(data)) else: # CREATE result, gas_remained, data = create_contract(ext, message) assert utils.is_numeric(gas_remained) log_tx.debug('_create_', result=result, gas_remained=gas_remained, data=lazy_safe_encode(data)) assert gas_remained >= 0 log_tx.debug("TX APPLIED", result=result, gas_remained=gas_remained, data=lazy_safe_encode(data)) if not result: # 0 = OOG failure in both cases log_tx.debug('TX FAILED', reason='out of gas', startgas=tx.startgas, gas_remained=gas_remained) block.gas_used += tx.startgas block.delta_balance(block.coinbase, tx.gasprice * tx.startgas) output = b'' success = 0 else: log_tx.debug('TX SUCCESS', data=lazy_safe_encode(data)) gas_used = tx.startgas - gas_remained block.refunds += len(set(block.suicides)) * opcodes.GSUICIDEREFUND if block.refunds > 0: log_tx.debug('Refunding', gas_refunded=min(block.refunds, gas_used // 2)) gas_remained += min(block.refunds, gas_used // 2) gas_used -= min(block.refunds, gas_used // 2) block.refunds = 0 # sell remaining gas block.delta_balance(tx.sender, tx.gasprice * gas_remained) block.delta_balance(block.coinbase, tx.gasprice * gas_used) block.gas_used += gas_used if tx.to: output = b''.join(map(ascii_chr, data)) else: output = data success = 1 block.commit_state() suicides = block.suicides block.suicides = [] for s in suicides: block.ether_delta -= block.get_balance(s) block.set_balance(s, 0) block.del_account(s) block.add_transaction_to_list(tx) block.logs = [] return success, output