def create_contract(ext, msg): #print('CREATING WITH GAS', msg.gas) sender = decode_hex(msg.sender) if len(msg.sender) == 40 else msg.sender if ext.tx_origin != msg.sender: ext._block.increment_nonce(msg.sender) nonce = utils.encode_int(ext._block.get_nonce(msg.sender) - 1) msg.to = mk_contract_address(sender, nonce) b = ext.get_balance(msg.to) if b > 0: ext.set_balance(msg.to, b) ext._block.set_nonce(msg.to, 0) ext._block.set_code(msg.to, b'') ext._block.reset_storage(msg.to) msg.is_create = True # assert not ext.get_code(msg.to) code = msg.data.extract_all() msg.data = vm.CallData([], 0, 0) res, gas, dat = _apply_msg(ext, msg, code) assert utils.is_numeric(gas) if res: if not len(dat): return 1, gas, msg.to gcost = len(dat) * opcodes.GCONTRACTBYTE if gas >= gcost: gas -= gcost else: dat = [] #print('CONTRACT CREATION OOG', 'have', gas, 'want', gcost) log_msg.debug('CONTRACT CREATION OOG', have=gas, want=gcost) ext._block.set_code(msg.to, b''.join(map(ascii_chr, dat))) return 1, gas, msg.to else: return 0, gas, b''
def format_message(self, msg, kwargs, highlight, level): if getattr(self, 'log_json', False): message = dict() message['event'] = '{}.{}'.format( self.name, msg.lower().replace(' ', '_')) message['level'] = logging.getLevelName(level) try: message.update(kwargs) try: msg = json.dumps(message, cls=_LogJSONEncoder) except TypeError: # Invalid value. With our custom encoder this can only happen with non-string message = _stringify_dict_keys(message) msg = json.dumps(message, cls=_LogJSONEncoder) except UnicodeDecodeError: message.update({ k: v if is_numeric(v) or isinstance(v, (float, complex)) else repr(v) for k, v in kwargs.items() }) msg = json.dumps(message, cls=_LogJSONEncoder) else: msg = "{}{} {}{}".format( bcolors.WARNING if highlight else "", msg, " ".join("{}={!s}".format(k, v) for k, v in kwargs.items()), bcolors.ENDC if highlight else "" ) return msg
def to_snapshot(self, root_only=False, no_prevblocks=False): snapshot = {} if root_only: # Smaller snapshot format that only includes the state root # (requires original DB to re-initialize) snapshot["state_root"] = '0x' + encode_hex(self.trie.root_hash) else: # "Full" snapshot snapshot["alloc"] = self.to_dict() # Save non-state-root variables for k, default in STATE_DEFAULTS.items(): default = copy.copy(default) v = getattr(self, k) if is_numeric(default): snapshot[k] = str(v) elif isinstance(default, (str, bytes)): snapshot[k] = '0x' + encode_hex(v) elif k == 'prev_headers' and not no_prevblocks: snapshot[k] = [ prev_header_to_dict(h) for h in v[:self.config['PREV_HEADER_DEPTH']] ] elif k == 'recent_uncles' and not no_prevblocks: snapshot[k] = { str(n): ['0x' + encode_hex(h) for h in headers] for n, headers in v.items() } return snapshot
def get_block(self, block_id=None): """Return the block identified by `block_id`. This method also sets :attr:`default_block` to the value of `block_id` which will be returned if, at later calls, `block_id` is not provided. Subdispatchers using this function have to ensure sure that a chainmanager is registered via :attr:`required_services`. :param block_id: either the block number as integer or 'pending', 'earliest' or 'latest', or `None` for the default block :returns: the requested block :raises: :exc:`KeyError` if the block does not exist """ assert 'chain' in self.app.services chain = self.app.services.chain.chain if block_id is None: block_id = self.default_block else: self.default_block = block_id if block_id == 'pending': return self.app.services.chain.chain.head_candidate if block_id == 'latest': return chain.head if block_id == 'earliest': block_id = 0 if is_numeric(block_id): # by number hash_ = chain.index.get_block_by_number(block_id) else: # by hash assert is_string(block_id) hash_ = block_id return chain.get(hash_)
def decint(n): if is_numeric(n) and n < 2**256 and n > -2**255: return n elif is_numeric(n): raise Exception("Number out of range: %r" % n) elif is_string(n) and len(n) == 40: return big_endian_to_int(decode_hex(n)) elif is_string(n) and len(n) <= 32: return big_endian_to_int(n) elif is_string(n) and len(n) > 32: raise Exception("String too long: %r" % n) elif n is True: return 1 elif n is False or n is None: return 0 else: raise Exception("Cannot encode integer: %r" % n)
def from_snapshot(cls, snapshot_data, env, executing_on_head=False): state = State(env=env) if "alloc" in snapshot_data: for addr, data in snapshot_data["alloc"].items(): if len(addr) == 40: addr = decode_hex(addr) assert len(addr) == 20 if 'wei' in data: state.set_balance(addr, parse_as_int(data['wei'])) if 'balance' in data: state.set_balance(addr, parse_as_int(data['balance'])) if 'code' in data: state.set_code(addr, parse_as_bin(data['code'])) if 'nonce' in data: state.set_nonce(addr, parse_as_int(data['nonce'])) if 'storage' in data: for k, v in data['storage'].items(): state.set_storage_data( addr, big_endian_to_int(parse_as_bin(k)), big_endian_to_int(parse_as_bin(v))) elif "state_root" in snapshot_data: state.trie.root_hash = parse_as_bin(snapshot_data["state_root"]) else: raise Exception( "Must specify either alloc or state root parameter") for k, default in STATE_DEFAULTS.items(): default = copy.copy(default) v = snapshot_data[k] if k in snapshot_data else None if is_numeric(default): setattr(state, k, parse_as_int(v) if k in snapshot_data else default) elif is_string(default): setattr(state, k, parse_as_bin(v) if k in snapshot_data else default) elif k == 'prev_headers': if k in snapshot_data: headers = [dict_to_prev_header(h) for h in v] else: headers = default setattr(state, k, headers) elif k == 'recent_uncles': if k in snapshot_data: uncles = {} for height, _uncles in v.items(): uncles[int(height)] = [] for uncle in _uncles: uncles[int(height)].append(parse_as_bin(uncle)) else: uncles = default setattr(state, k, uncles) if executing_on_head: state.executing_on_head = True state.commit() state.changed = {} return state
def normalize_number(value): if is_numeric(value): return value elif is_string(value): if value.startswith(b'0x'): return int(value, 16) else: return big_endian_to_int(value) else: raise ValueError("Unknown numeric encoding: {0}".format(value))
def encode_number(value, length=None): """Encode interger quantity `data`.""" if not is_numeric(value): raise ValueError("Unsupported type: {0}".format(type(value))) hex_value = encode_data(int_to_big_endian(value), length) if length: return hex_value else: return add_0x(strip_0x(hex_value).lstrip(b'0') or b'0')
def _apply_msg(ext, msg, code): if log_msg.is_active('trace'): log_msg.debug("MSG APPLY", sender=encode_hex(msg.sender), to=encode_hex(msg.to), gas=msg.gas, value=msg.value, data=encode_hex(msg.data.extract_all())) if log_state.is_active('trace'): log_state.trace('MSG PRE STATE SENDER', account=msg.sender, bal=ext.get_balance(msg.sender), state=ext.log_storage(msg.sender)) log_state.trace('MSG PRE STATE RECIPIENT', account=msg.to, bal=ext.get_balance(msg.to), state=ext.log_storage(msg.to)) # Transfer value, instaquit if not enough snapshot = ext._block.snapshot() o = ext._block.transfer_value(msg.sender, msg.to, msg.value) if not o: log_msg.debug('MSG TRANSFER FAILED', have=ext.get_balance(msg.to), want=msg.value) return 1, msg.gas, [] # Main loop if msg.code_address in specials.specials: res, gas, dat = specials.specials[msg.code_address](ext, msg) else: res, gas, dat = vm.vm_execute(ext, msg, code) gas = int(gas) assert utils.is_numeric(gas) if log_msg.is_active('trace'): log_msg.debug('MSG APPLIED', result=o, gas_remained=gas, sender=msg.sender, to=msg.to, data=dat) if log_state.is_active('trace'): log_state.trace('MSG PRE STATE SENDER', account=msg.sender, bal=ext.get_balance(msg.sender), state=ext.log_storage(msg.sender)) log_state.trace('MSG PRE STATE RECIPIENT', account=msg.to, bal=ext.get_balance(msg.to), state=ext.log_storage(msg.to)) if res == 0: log_msg.debug('REVERTING') ext._block.revert(snapshot) return res, gas, dat
def mine(block_number, difficulty, mining_hash, start_nonce=0, rounds=1000): assert utils.is_numeric(start_nonce) cache = get_cache(block_number) nonce = start_nonce target = utils.zpad(utils.int_to_big_endian(2**256 // (difficulty or 1) - 1), 32) for i in range(1, rounds + 1): bin_nonce = utils.zpad(utils.int_to_big_endian((nonce + i) & TT64M1), 8) o = hashimoto_light(block_number, cache, mining_hash, bin_nonce) if o[b"result"] <= target: log.debug("nonce found") assert len(bin_nonce) == 8 assert len(o[b"mix digest"]) == 32 return bin_nonce, o[b"mix digest"] return None, None
def create_contract(ext, msg): log_msg.debug("CONTRACT CREATION") # print('CREATING WITH GAS', msg.gas) sender = decode_hex(msg.sender) if len(msg.sender) == 40 else msg.sender code = msg.data.extract_all() if ext._block.number >= ext._block.config["METROPOLIS_FORK_BLKNUM"]: msg.to = mk_metropolis_contract_address(msg.sender, code) if ext.get_code(msg.to): if ext.get_nonce(msg.to) >= 2 ** 40: ext.set_nonce(msg.to, (ext.get_nonce(msg.to) + 1) % 2 ** 160) msg.to = normalize_address((ext.get_nonce(msg.to) - 1) % 2 ** 160) else: ext.set_nonce(msg.to, (big_endian_to_int(msg.to) + 2) % 2 ** 160) msg.to = normalize_address((ext.get_nonce(msg.to) - 1) % 2 ** 160) else: if ext.tx_origin != msg.sender: ext._block.increment_nonce(msg.sender) nonce = utils.encode_int(ext._block.get_nonce(msg.sender) - 1) msg.to = mk_contract_address(sender, nonce) b = ext.get_balance(msg.to) if b > 0: ext.set_balance(msg.to, b) ext._block.set_nonce(msg.to, 0) ext._block.set_code(msg.to, b"") ext._block.reset_storage(msg.to) msg.is_create = True # assert not ext.get_code(msg.to) msg.data = vm.CallData([], 0, 0) snapshot = ext._block.snapshot() res, gas, dat = _apply_msg(ext, msg, code) assert utils.is_numeric(gas) if res: if not len(dat): return 1, gas, msg.to gcost = len(dat) * opcodes.GCONTRACTBYTE if gas >= gcost: gas -= gcost else: dat = [] log_msg.debug("CONTRACT CREATION OOG", have=gas, want=gcost, block_number=ext._block.number) if ext._block.number >= ext._block.config["HOMESTEAD_FORK_BLKNUM"]: ext._block.revert(snapshot) return 0, 0, b"" ext._block.set_code(msg.to, b"".join(map(ascii_chr, dat))) return 1, gas, msg.to else: return 0, gas, b""
def decint(n, signed=False): # pylint: disable=invalid-name,too-many-branches """ Decode an unsigned/signed integer. """ if isinstance(n, str): n = utils.to_string(n) if n is True: return 1 if n is False: return 0 if n is None: return 0 if is_numeric(n): if signed: if not -TT255 <= n <= TT255 - 1: raise EncodingError('Number out of range: %r' % n) else: if not 0 <= n <= TT256 - 1: raise EncodingError('Number out of range: %r' % n) return n if is_string(n): if len(n) > 32: raise EncodingError('String too long: %r' % n) if len(n) == 40: int_bigendian = decode_hex(n) else: int_bigendian = n # pylint: disable=redefined-variable-type result = big_endian_to_int(int_bigendian) if signed: if result >= TT255: result -= TT256 if not -TT255 <= result <= TT255 - 1: raise EncodingError('Number out of range: %r' % n) else: if not 0 <= result <= TT256 - 1: raise EncodingError('Number out of range: %r' % n) return result raise EncodingError('Cannot decode integer: %r' % n)
def create_contract(ext, msg): log_msg.debug('CONTRACT CREATION') #print('CREATING WITH GAS', msg.gas) sender = decode_hex(msg.sender) if len(msg.sender) == 40 else msg.sender code = msg.data.extract_all() if ext._block.number >= ext._block.config['METROPOLIS_FORK_BLKNUM']: msg.to = mk_metropolis_contract_address(msg.sender, code) if ext.get_code(msg.to): if ext.get_nonce(msg.to) >= 2 ** 40: ext.set_nonce(msg.to, (ext.get_nonce(msg.to) + 1) % 2 ** 160) msg.to = normalize_address((ext.get_nonce(msg.to) - 1) % 2 ** 160) else: ext.set_nonce(msg.to, (big_endian_to_int(msg.to) + 2) % 2 ** 160) msg.to = normalize_address((ext.get_nonce(msg.to) - 1) % 2 ** 160) else: if ext.tx_origin != msg.sender: ext._block.increment_nonce(msg.sender) nonce = utils.encode_int(ext._block.get_nonce(msg.sender) - 1) msg.to = mk_contract_address(sender, nonce) b = ext.get_balance(msg.to) if b > 0: ext.set_balance(msg.to, b) ext._block.set_nonce(msg.to, 0) ext._block.set_code(msg.to, b'') ext._block.reset_storage(msg.to) msg.is_create = True # assert not ext.get_code(msg.to) msg.data = vm.CallData([], 0, 0) snapshot = ext._block.snapshot() res, gas, dat = _apply_msg(ext, msg, code) assert utils.is_numeric(gas) if res: if not len(dat): return 1, gas, msg.to gcost = len(dat) * opcodes.GCONTRACTBYTE if gas >= gcost: gas -= gcost else: dat = [] log_msg.debug('CONTRACT CREATION OOG', have=gas, want=gcost, block_number=ext._block.number) if ext._block.number >= ext._block.config['HOMESTEAD_FORK_BLKNUM']: ext._block.revert(snapshot) return 0, 0, b'' ext._block.set_code(msg.to, b''.join(map(ascii_chr, dat))) return 1, gas, msg.to else: return 0, gas, b''
def __init__(self, chain, blocks=None, addresses=None, topics=None, pending=False, latest=False): self.chain = chain if blocks is not None: self.blocks = blocks else: self.blocks = [] self.addresses = addresses self.topics = topics if self.topics: for topic in self.topics: assert topic is None or is_numeric(topic) self.pending = pending self.latest = latest self.blocks_done = set() self._logs = {} self._new_logs = {}
def decode_filter(filter_dict, block): """Decodes a filter as expected by eth_newFilter or eth_getLogs to a :class:`Filter`.""" if not isinstance(filter_dict, dict): raise Exception('Filter must be an object') address = filter_dict.get('address', None) if utils.is_string(address): addresses = [decode_hex(strip_0x(address))] elif isinstance(address, Iterable): addresses = [decode_hex(strip_0x(addr)) for addr in address] elif address is None: addresses = None else: raise Exception('Parameter must be address or list of addresses') if 'topics' in filter_dict: topics = [] for topic in filter_dict['topics']: if topic is not None: topics.append(utils.big_endian_to_int(decode_hex(strip_0x(topic)))) else: topics.append(None) else: topics = None from_block = filter_dict.get('fromBlock') or 'latest' to_block = filter_dict.get('toBlock') or 'latest' if from_block not in ('earliest', 'latest', 'pending'): from_block = decode_number(from_block) if to_block not in ('earliest', 'latest', 'pending'): to_block = decode_number(to_block) # check order block_id_dict = { 'earliest': 0, 'latest': block.number, 'pending': block.number+1 } range_ = [b if utils.is_numeric(b) else block_id_dict[b] for b in (from_block, to_block)] if range_[0] > range_[1]: raise Exception('fromBlock must be newer or equal to toBlock') return {"from_block": from_block, "to_block": to_block, "addresses": addresses, "topics": topics}
def decint(n, signed=False): if isinstance(n, str): n = utils.to_string(n) if is_numeric(n): min_, max_ = (-TT255, TT255 - 1) if signed else (0, TT256 - 1) if n > max_ or n < min_: raise EncodingError("Number out of range: %r" % n) return n elif is_string(n): if len(n) == 40: n = decode_hex(n) if len(n) > 32: raise EncodingError("String too long: %r" % n) i = big_endian_to_int(n) return (i - TT256) if signed and i >= TT255 else i elif n is True: return 1 elif n is False or n is None: return 0 else: raise EncodingError("Cannot encode integer: %r" % n)
def encode_single(typ, arg): # pylint: disable=too-many-return-statements,too-many-branches,too-many-statements,too-many-locals """ Encode `arg` as `typ`. `arg` will be encoded in a best effort manner, were necessary the function will try to correctly define the underlying binary representation (ie. decoding a hex-encoded address/hash). Args: typ (Tuple[(str, int, list)]): A 3-tuple defining the `arg` type. The first element defines the type name. The second element defines the type length in bits. The third element defines if it's an array type. Together the first and second defines the elementary type, the third element must be present but is ignored. Valid type names are: - uint - int - bool - ufixed - fixed - string - bytes - hash - address arg (object): The object to be encoded, it must be a python object compatible with the `typ`. Raises: ValueError: when an invalid `typ` is supplied. ValueOutOfBounds: when `arg` cannot be encoded as `typ` because of the binary contraints. Note: This function don't work with array types, for that use the `enc` function. """ base, sub, _ = typ if base == 'uint': sub = int(sub) if not (0 < sub <= 256 and sub % 8 == 0): raise ValueError( 'invalid unsigned integer bit length {}'.format(sub)) try: i = decint(arg, signed=False) except EncodingError: # arg is larger than 2**256 raise ValueOutOfBounds(repr(arg)) if not 0 <= i < 2 ** sub: raise ValueOutOfBounds(repr(arg)) value_encoded = int_to_big_endian(i) return zpad(value_encoded, 32) if base == 'int': sub = int(sub) bits = sub - 1 if not (0 < sub <= 256 and sub % 8 == 0): raise ValueError('invalid integer bit length {}'.format(sub)) try: i = decint(arg, signed=True) except EncodingError: # arg is larger than 2**255 raise ValueOutOfBounds(repr(arg)) if not -2 ** bits <= i < 2 ** bits: raise ValueOutOfBounds(repr(arg)) value = i % 2 ** 256 # convert negative to "equivalent" positive value_encoded = int_to_big_endian(value) return zpad(value_encoded, 32) if base == 'bool': if arg is True: value_encoded = int_to_big_endian(1) elif arg is False: value_encoded = int_to_big_endian(0) else: raise ValueError('%r is not bool' % arg) return zpad(value_encoded, 32) if base == 'ufixed': sub = str(sub) # pylint: disable=redefined-variable-type high_str, low_str = sub.split('x') high = int(high_str) low = int(low_str) if not (0 < high + low <= 256 and high % 8 == 0 and low % 8 == 0): raise ValueError('invalid unsigned fixed length {}'.format(sub)) if not 0 <= arg < 2 ** high: raise ValueOutOfBounds(repr(arg)) float_point = arg * 2 ** low fixed_point = int(float_point) return zpad(int_to_big_endian(fixed_point), 32) if base == 'fixed': sub = str(sub) # pylint: disable=redefined-variable-type high_str, low_str = sub.split('x') high = int(high_str) low = int(low_str) bits = high - 1 if not (0 < high + low <= 256 and high % 8 == 0 and low % 8 == 0): raise ValueError('invalid unsigned fixed length {}'.format(sub)) if not -2 ** bits <= arg < 2 ** bits: raise ValueOutOfBounds(repr(arg)) float_point = arg * 2 ** low fixed_point = int(float_point) value = fixed_point % 2 ** 256 return zpad(int_to_big_endian(value), 32) # Decimals if base == 'decimal': val_to_encode = int(arg * 10**int(sub)) return zpad(encode_int(val_to_encode % 2**256), 32) if base == 'string': if isinstance(arg, utils.unicode): arg = arg.encode('utf8') else: try: arg.decode('utf8') except UnicodeDecodeError: raise ValueError('string must be utf8 encoded') if len(sub): # fixed length if not 0 <= len(arg) <= int(sub): raise ValueError('invalid string length {}'.format(sub)) if not 0 <= int(sub) <= 32: raise ValueError('invalid string length {}'.format(sub)) return rzpad(arg, 32) if not 0 <= len(arg) < TT256: raise Exception('Integer invalid or out of range: %r' % arg) length_encoded = zpad(int_to_big_endian(len(arg)), 32) value_encoded = rzpad(arg, utils.ceil32(len(arg))) return length_encoded + value_encoded if base == 'bytes': if not is_string(arg): if isinstance(arg, str): arg = bytes(arg, 'utf8') else: raise EncodingError('Expecting string: %r' % arg) arg = utils.to_string(arg) # py2: force unicode into str if len(sub): # fixed length if not 0 <= len(arg) <= int(sub): raise ValueError('string must be utf8 encoded') if not 0 <= int(sub) <= 32: raise ValueError('string must be utf8 encoded') return rzpad(arg, 32) if not 0 <= len(arg) < TT256: raise Exception('Integer invalid or out of range: %r' % arg) length_encoded = zpad(int_to_big_endian(len(arg)), 32) value_encoded = rzpad(arg, utils.ceil32(len(arg))) return length_encoded + value_encoded if base == 'hash': if not (int(sub) and int(sub) <= 32): raise EncodingError('too long: %r' % arg) if is_numeric(arg): return zpad(encode_int(arg), 32) if len(arg) == int(sub): return zpad(arg, 32) if len(arg) == int(sub) * 2: return zpad(decode_hex(arg), 32) raise EncodingError('Could not parse hash: %r' % arg) if base == 'address': assert sub == '' if is_numeric(arg): return zpad(encode_int(arg), 32) if len(arg) == 20: return zpad(arg, 32) if len(arg) == 40: return zpad(decode_hex(arg), 32) if len(arg) == 42 and arg[:2] == '0x': return zpad(decode_hex(arg[2:]), 32) raise EncodingError('Could not parse address: %r' % arg) raise EncodingError('Unhandled type: %r %r' % (base, sub))
def snapshot_form(val): if is_numeric(val): return str(val) elif is_string(val): return '0x' + encode_hex(val)
def apply_transaction(block, tx): validate_transaction(block, tx) log_tx.debug('TX NEW', tx_dict=tx.log_dict()) # start transacting ################# block.increment_nonce(tx.sender) # print block.get_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_used(tx) 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=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
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
def getStorageAt(self, address, index, block_id=None): block = self.json_rpc_server.get_block(block_id) i = block.get_storage_data(address, index) assert is_numeric(i) return int_to_big_endian(i)
def quantity_encoder(i): """Encode interger quantity `data`.""" assert is_numeric(i) data = int_to_big_endian(i) return '0x' + (encode_hex(data).lstrip('0') or '0')
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