def __init__(self, nonce, gasprice, startgas, to, value, data, v=0, r=0, s=0): if len(to) in (40, 48): to = decode_hex(to) if len(to) == 24: to = utils.check_and_strip_checksum(to) assert len(to) == 20 or len(to) == 0 super(Transaction, self).__init__(nonce, gasprice, startgas, to, value, data, v, r, s) self.logs = [] if self.gasprice >= TT256 or self.startgas >= TT256 or \ self.value >= TT256 or self.nonce >= TT256: raise InvalidTransaction("Values way too high!") if self.startgas < intrinsic_gas_used(self): raise InvalidTransaction("Startgas too low") log.debug('deserialized tx', tx=encode_hex(self.hash)[:8])
def apply_transaction(block, tx, cb=None, validate=True): eth_call = False def dummy_cb(*args, **kwargs): pass if cb is None: cb = dummy_cb eth_call = True if validate: validate_transaction(block, tx) log_tx.debug('TX NEW', tx_dict=tx.log_dict()) # start transacting ################# block.increment_nonce(tx.sender) intrinsic_gas = intrinsic_gas_used(tx) 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)) # buy startgas if validate: 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 = CapVMExt(block, tx, cb) if tx.to and tx.to != CREATE_CONTRACT_ADDRESS: result, gas_remained, data = ext._msg(message) log_tx.debug('_res_', result=result, gas_remained=gas_remained, data=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=data) assert gas_remained >= 0 log_tx.debug("TX APPLIED", result=result, gas_remained=gas_remained, data=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=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