From 5f22fceab7d6f91ee62b09ce2a8a17b0b16d6d1f Mon Sep 17 00:00:00 2001 From: Yogesh Srihari Date: Tue, 22 Aug 2017 14:33:08 -0700 Subject: [PATCH] Code formating style to pep8 standards. --- ethereum/__init__.py | 10 +- ethereum/abi.py | 29 +- ethereum/block.py | 9 +- ethereum/bloom.py | 3 +- ethereum/child_dao_list.py | 6 +- ethereum/common.py | 52 +- ethereum/compress.py | 6 +- ethereum/config.py | 32 +- ethereum/consensus_strategy.py | 7 +- ethereum/db.py | 4 +- ethereum/experimental/fastvm.py | 819 ++++++++++---------- ethereum/experimental/pruning_trie.py | 18 +- ethereum/experimental/refcount_db.py | 86 ++- ethereum/experimental/spv.py | 11 +- ethereum/fast_rlp.py | 6 + ethereum/fastvm.py | 945 ++++++++++++----------- ethereum/full_casper/casper_utils.py | 141 +++- ethereum/genesis_helpers.py | 33 +- ethereum/hybrid_casper/consensus.py | 10 +- ethereum/messages.py | 82 +- ethereum/meta.py | 14 +- ethereum/new_state.py | 127 +-- ethereum/opcodes.py | 25 +- ethereum/pow/chain.py | 144 ++-- ethereum/pow/consensus.py | 40 +- ethereum/pow/ethash.py | 7 +- ethereum/pow/ethash_utils.py | 26 +- ethereum/pow/ethpow.py | 18 +- ethereum/slogging.py | 17 +- ethereum/snapshot.py | 10 +- ethereum/specials.py | 36 +- ethereum/state.py | 149 ++-- ethereum/tests/test_abi.py | 63 +- ethereum/tests/test_blocks.py | 81 +- ethereum/tests/test_bloom.py | 4 +- ethereum/tests/test_chain.py | 37 +- ethereum/tests/test_contracts.py | 88 ++- ethereum/tests/test_difficulty.py | 35 +- ethereum/tests/test_genesis.py | 12 +- ethereum/tests/test_opcodes.py | 6 +- ethereum/tests/test_state.py | 20 +- ethereum/tests/test_tester.py | 19 +- ethereum/tests/test_transactions.py | 17 +- ethereum/tests/test_trie.py | 1 + ethereum/tests/test_trie_next_prev.py | 5 +- ethereum/todo_tests/test_logging.py | 30 +- ethereum/todo_tests/test_pos.py | 82 +- ethereum/todo_tests/test_pruning_trie.py | 23 +- ethereum/todo_tests/test_solidity.py | 42 +- ethereum/todo_tests/test_vm.py | 2 +- ethereum/todo_tests/test_vm_failing.py | 1 + ethereum/todo_tests/tst_frontier.py | 24 +- ethereum/tools/_solidity.py | 102 ++- ethereum/tools/keys.py | 14 +- ethereum/tools/new_statetest_utils.py | 34 +- ethereum/tools/tester.py | 96 ++- ethereum/tools/testutils.py | 16 +- ethereum/transaction_queue.py | 4 +- ethereum/transactions.py | 30 +- ethereum/trie.py | 54 +- ethereum/utils.py | 49 +- ethereum/vm.py | 79 +- setup.py | 9 +- tools/fixture_to_example.py | 3 +- tools/keystorer.py | 10 +- tools/mk_ecadd_tests.py | 51 +- tools/mk_ecmul_tests.py | 58 +- tools/mk_ecpairing_tests.py | 109 ++- tools/mk_modexp_tests.py | 33 +- tools/random_vm_test_generator.py | 80 +- tools/vm_test_generator.py | 5 +- 71 files changed, 2710 insertions(+), 1640 deletions(-) diff --git a/ethereum/__init__.py b/ethereum/__init__.py index 05232c694..1b6cfbb5b 100644 --- a/ethereum/__init__.py +++ b/ethereum/__init__.py @@ -2,7 +2,7 @@ # ############# version ################## try: from pkg_resources import get_distribution, DistributionNotFound -except: +except BaseException: DistributionNotFound = Exception import os.path import subprocess @@ -11,7 +11,8 @@ from . import slogging # noqa -GIT_DESCRIBE_RE = re.compile('^(?Pv\d+\.\d+\.\d+)-(?P\d+-g[a-fA-F0-9]+(?:-dirty)?)$') +GIT_DESCRIBE_RE = re.compile( + '^(?Pv\d+\.\d+\.\d+)-(?P\d+-g[a-fA-F0-9]+(?:-dirty)?)$') __version__ = None @@ -33,8 +34,9 @@ stderr=subprocess.STDOUT) match = GIT_DESCRIBE_RE.match(rev) if match: - __version__ = "{}+git-{}".format(match.group("version"), match.group("git")) - except: # FIXME! + __version__ = "{}+git-{}".format( + match.group("version"), match.group("git")) + except BaseException: # FIXME! pass if not __version__: diff --git a/ethereum/abi.py b/ethereum/abi.py index f3eda3841..ea465a494 100644 --- a/ethereum/abi.py +++ b/ethereum/abi.py @@ -5,7 +5,8 @@ import re import warnings -import yaml # use yaml instead of json to get non unicode (works with ascii only data) +# use yaml instead of json to get non unicode (works with ascii only data) +import yaml from rlp.utils import decode_hex from ethereum.utils import encode_hex @@ -230,7 +231,8 @@ def encode_single(typ, arg): # pylint: disable=too-many-return-statements,too-m sub = int(sub) if not (0 < sub <= 256 and sub % 8 == 0): - raise ValueError('invalid unsigned integer bit length {}'.format(sub)) + raise ValueError( + 'invalid unsigned integer bit length {}'.format(sub)) try: i = decint(arg, signed=False) @@ -478,18 +480,23 @@ def __init__(self, contract_interface): elif entry_type == 'fallback': if self.fallback_data is not None: - raise ValueError('Only one fallback function is supported.') + raise ValueError( + 'Only one fallback function is supported.') self.fallback_data = {'payable': description['payable']} else: raise ValueError('Unknown type {}'.format(description['type'])) def encode(self, function_name, args): - warnings.warn('encode is deprecated, please use encode_function_call', DeprecationWarning) + warnings.warn( + 'encode is deprecated, please use encode_function_call', + DeprecationWarning) return self.encode_function_call(function_name, args) def decode(self, function_name, data): - warnings.warn('decode is deprecated, please use decode_function_result', DeprecationWarning) + warnings.warn( + 'decode is deprecated, please use decode_function_result', + DeprecationWarning) return self.decode_function_result(function_name, data) def encode_function_call(self, function_name, args): @@ -534,7 +541,8 @@ def decode_function_result(self, function_name, data): def encode_constructor_arguments(self, args): """ Return the encoded constructor call. """ if self.constructor_data is None: - raise ValueError("The contract interface didn't have a constructor") + raise ValueError( + "The contract interface didn't have a constructor") return encode_abi(self.constructor_data['encode_types'], args) @@ -575,7 +583,8 @@ def decode_event(self, log_topics, log_data): indexed_count = 1 # skip topics[0] result = {} - for name, type_, indexed in zip(event['names'], event['types'], event['indexed']): + for name, type_, indexed in zip( + event['names'], event['types'], event['indexed']): if indexed: topic_bytes = utils.zpad( utils.encode_int(log_topics[indexed_count]), @@ -617,7 +626,8 @@ def process_type(typ): # Crazy reg expression to separate out base type component (eg. uint), # size (eg. 256, 128x128, none), array component (eg. [], [45], none) regexp = '([a-z]*)([0-9]*x?[0-9]*)((\[[0-9]*\])*)' - base, sub, arr, _ = re.match(regexp, utils.to_string_for_regexp(typ)).groups() + base, sub, arr, _ = re.match( + regexp, utils.to_string_for_regexp(typ)).groups() arrlist = re.findall('\[[0-9]*\]', arr) assert len(''.join(arrlist)) == len(arr), \ "Unknown characters found in array declaration" @@ -816,7 +826,8 @@ def dec(typ, arg): # Dynamic-sized strings are encoded as + if base in ('string', 'bytes') and not sub: L = big_endian_to_int(arg[:32]) - assert len(arg[32:]) == ceil32(L), "Wrong data size for string/bytes object: expected %d actual %d" % (ceil32(L), len(arg[32:])) + assert len(arg[32:]) == ceil32( + L), "Wrong data size for string/bytes object: expected %d actual %d" % (ceil32(L), len(arg[32:])) return arg[32:][:L] # Dynamic-sized arrays elif sz is None: diff --git a/ethereum/block.py b/ethereum/block.py index 41a582bcf..1d21b4814 100644 --- a/ethereum/block.py +++ b/ethereum/block.py @@ -100,11 +100,13 @@ def hex_hash(self): @property def mining_hash(self): - return utils.sha3(rlp.encode(self, BlockHeader.exclude(['mixhash', 'nonce']))) + return utils.sha3(rlp.encode( + self, BlockHeader.exclude(['mixhash', 'nonce']))) @property def signing_hash(self): - return utils.sha3(rlp.encode(self, BlockHeader.exclude(['extra_data']))) + return utils.sha3(rlp.encode( + self, BlockHeader.exclude(['extra_data']))) def to_dict(self): """Serialize the header to a readable dictionary.""" @@ -188,7 +190,8 @@ def transaction_count(self): class FakeHeader(): - def __init__(self, hash='\x00' * 32, number=0, timestamp=0, difficulty=1, gas_limit=3141592, gas_used=0, uncles_hash=BLANK_UNCLES_HASH): + def __init__(self, hash='\x00' * 32, number=0, timestamp=0, difficulty=1, + gas_limit=3141592, gas_used=0, uncles_hash=BLANK_UNCLES_HASH): self.hash = hash self.number = number self.timestamp = timestamp diff --git a/ethereum/bloom.py b/ethereum/bloom.py index c5ca796ce..069b55fe3 100644 --- a/ethereum/bloom.py +++ b/ethereum/bloom.py @@ -35,7 +35,8 @@ def bloom_insert(bloom, val): def bloom_bits(val): h = utils.sha3(val) - return [bits_in_number(1 << ((safe_ord(h[i + 1]) + (safe_ord(h[i]) << 8)) & 2047)) for i in range(0, BUCKETS_PER_VAL * 2, 2)] + return [bits_in_number(1 << ((safe_ord(h[i + 1]) + (safe_ord(h[i]) << 8)) & 2047)) + for i in range(0, BUCKETS_PER_VAL * 2, 2)] def bits_in_number(val): diff --git a/ethereum/child_dao_list.py b/ethereum/child_dao_list.py index 42219e716..a006c9aa9 100644 --- a/ethereum/child_dao_list.py +++ b/ethereum/child_dao_list.py @@ -7,6 +7,8 @@ # DAO extrabalance L.append('0x807640a13483f8ac783c557fcdf27be11ea4ac7a') # child DAOs (created by DAO creator) -L.extend(['0x' + encode_hex(mk_contract_address(source, i)) for i in range(1, 58)]) +L.extend(['0x' + encode_hex(mk_contract_address(source, i)) + for i in range(1, 58)]) # child extrabalances -L.extend(['0x' + encode_hex(mk_contract_address(mk_contract_address(source, i), 0)) for i in range(1, 58)]) +L.extend(['0x' + encode_hex(mk_contract_address(mk_contract_address(source, i), 0)) + for i in range(1, 58)]) diff --git a/ethereum/common.py b/ethereum/common.py index 8b8ea05ef..53ebbb60a 100644 --- a/ethereum/common.py +++ b/ethereum/common.py @@ -10,12 +10,17 @@ from ethereum.messages import apply_transaction log = get_logger('eth.block') + # Gas limit adjustment algo def calc_gaslimit(parent, config=default_config): decay = parent.gas_limit // config['GASLIMIT_EMA_FACTOR'] new_contribution = ((parent.gas_used * config['BLKLIM_FACTOR_NOM']) // config['BLKLIM_FACTOR_DEN'] // config['GASLIMIT_EMA_FACTOR']) - gl = max(parent.gas_limit - decay + new_contribution, config['MIN_GAS_LIMIT']) + gl = max( + parent.gas_limit - + decay + + new_contribution, + config['MIN_GAS_LIMIT']) if gl < config['GENESIS_GAS_LIMIT']: gl2 = parent.gas_limit + decay gl = min(config['GENESIS_GAS_LIMIT'], gl2) @@ -30,6 +35,7 @@ def check_gaslimit(parent, gas_limit, config=default_config): b = bool(gas_limit >= config['MIN_GAS_LIMIT']) return a and b + # Difficulty adjustment algo def calc_difficulty(parent, timestamp, config=default_config): # Special case for test chains @@ -43,23 +49,29 @@ def calc_difficulty(parent, timestamp, config=default_config): sign = max(1 - ((timestamp - parent.timestamp) // config['HOMESTEAD_DIFF_ADJUSTMENT_CUTOFF']), -99) else: - sign = 1 if timestamp - parent.timestamp < config['DIFF_ADJUSTMENT_CUTOFF'] else -1 + sign = 1 if timestamp - \ + parent.timestamp < config['DIFF_ADJUSTMENT_CUTOFF'] else -1 # If we enter a special mode where the genesis difficulty starts off below # the minimal difficulty, we allow low-difficulty blocks (this will never # happen in the official protocol) - o = int(max(parent.difficulty + offset * sign, min(parent.difficulty, config['MIN_DIFF']))) + o = int(max(parent.difficulty + offset * sign, + min(parent.difficulty, config['MIN_DIFF']))) period_count = (parent.number + 1) // config['EXPDIFF_PERIOD'] if period_count >= config['EXPDIFF_FREE_PERIODS']: - o = max(o + 2**(period_count - config['EXPDIFF_FREE_PERIODS']), config['MIN_DIFF']) + o = max(o + 2**(period_count - + config['EXPDIFF_FREE_PERIODS']), config['MIN_DIFF']) return o + # Given a parent state, initialize a block with the given arguments -def mk_block_from_prevstate(chain, state=None, timestamp=None, coinbase=b'\x35'*20, extra_data='moo ha ha says the laughing cow.'): +def mk_block_from_prevstate(chain, state=None, timestamp=None, + coinbase=b'\x35' * 20, extra_data='moo ha ha says the laughing cow.'): state = state or chain.state blk = Block(BlockHeader()) now = timestamp or chain.time() blk.header.number = state.block_number + 1 - blk.header.difficulty = calc_difficulty(state.prev_headers[0], now, chain.config) + blk.header.difficulty = calc_difficulty( + state.prev_headers[0], now, chain.config) blk.header.gas_limit = calc_gaslimit(state.prev_headers[0], chain.config) blk.header.timestamp = max(now, state.prev_headers[0].timestamp + 1) blk.header.prevhash = state.prev_headers[0].hash @@ -69,6 +81,7 @@ def mk_block_from_prevstate(chain, state=None, timestamp=None, coinbase=b'\x35'* blk.transactions = [] return blk + # Validate a block header def validate_header(state, header): parent = state.prev_headers[0] @@ -77,10 +90,13 @@ def validate_header(state, header): raise ValueError("Block's prevhash and parent's hash do not match: block prevhash %s parent hash %s" % (encode_hex(header.prevhash), encode_hex(parent.hash))) if header.number != parent.number + 1: - raise ValueError("Block's number is not the successor of its parent number") + raise ValueError( + "Block's number is not the successor of its parent number") if not check_gaslimit(parent, header.gas_limit, config=state.config): - raise ValueError("Block's gaslimit is inconsistent with its parent's gaslimit") - if header.difficulty != calc_difficulty(parent, header.timestamp, config=state.config): + raise ValueError( + "Block's gaslimit is inconsistent with its parent's gaslimit") + if header.difficulty != calc_difficulty( + parent, header.timestamp, config=state.config): raise ValueError("Block's difficulty is inconsistent with its parent's difficulty: parent %d expected %d actual %d. Time diff %d" % (parent.difficulty, calc_difficulty(parent, header.timestamp, config=state.config), header.difficulty, header.timestamp - parent.timestamp)) if header.gas_used > header.gas_limit: @@ -95,17 +111,20 @@ def validate_header(state, header): raise ValueError("Timestamp waaaaaaaaaaayy too large") if header.gas_limit >= 2**63: raise ValueError("Header gas limit too high") - if 0 <= header.number - state.config["DAO_FORK_BLKNUM"] < 10 and header.extra_data != state.config["DAO_FORK_BLKEXTRA"]: + if 0 <= header.number - \ + state.config["DAO_FORK_BLKNUM"] < 10 and header.extra_data != state.config["DAO_FORK_BLKEXTRA"]: raise ValueError("Missing extra data for block near DAO fork") return True + # Add transactions def add_transactions(state, block, txqueue, min_gasprice=0): if not txqueue: return pre_txs = len(block.transactions) - log.info('Adding transactions, %d in txqueue, %d dunkles' % (len(txqueue.txs), pre_txs)) - while 1: + log.info('Adding transactions, %d in txqueue, %d dunkles' % + (len(txqueue.txs), pre_txs)) + while True: tx = txqueue.pop_transaction(max_gas=state.gas_limit - state.gas_used, min_gasprice=min_gasprice) if tx is None: @@ -118,6 +137,7 @@ def add_transactions(state, block, txqueue, min_gasprice=0): pass log.info('Added %d transactions' % (len(block.transactions) - pre_txs)) + # Validate that the transaction list root is correct def validate_transaction_tree(state, block): if block.header.tx_list_root != mk_transaction_sha(block.transactions): @@ -126,6 +146,7 @@ def validate_transaction_tree(state, block): len(block.transactions))) return True + # Set state root, receipt root, etc def set_execution_results(state, block): block.header.receipts_root = mk_receipt_sha(state.receipts) @@ -136,6 +157,7 @@ def set_execution_results(state, block): block.header.bloom = state.bloom log.info('Block pre-sealed, %d gas used' % state.gas_used) + # Verify state root, receipt root, etc def verify_execution_results(state, block): if block.header.bloom != state.bloom: @@ -148,12 +170,13 @@ def verify_execution_results(state, block): if block.header.receipts_root != mk_receipt_sha(state.receipts): raise ValueError("Receipt root mismatch: header %s computed %s, gas used header %d computed %d, %d receipts" % (encode_hex(block.header.receipts_root), encode_hex(mk_receipt_sha(state.receipts)), - block.header.gas_used, state.gas_used, len(state.receipts))) + block.header.gas_used, state.gas_used, len(state.receipts))) if block.header.gas_used != state.gas_used: raise ValueError("Gas used mismatch: header %d computed %d" % (block.header.gas_used, state.gas_used)) return True + # Make the root of a receipt tree def mk_receipt_sha(receipts): t = trie.Trie(EphemDB()) @@ -161,13 +184,16 @@ def mk_receipt_sha(receipts): t.update(rlp.encode(i), rlp.encode(receipt)) return t.root_hash + # Make the root of a transaction tree mk_transaction_sha = mk_receipt_sha + # State changes after block finalized def post_finalize(state, block): state.add_block_header(block.header) + # Update block variables into the state def update_block_env_variables(state, block): state.timestamp = block.header.timestamp diff --git a/ethereum/compress.py b/ethereum/compress.py index 0f250ca43..479e0feac 100644 --- a/ethereum/compress.py +++ b/ethereum/compress.py @@ -1,7 +1,8 @@ from rlp.utils import decode_hex, ascii_chr from ethereum.utils import safe_ord, int_to_bytes -NULLSHA3 = decode_hex('c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470') +NULLSHA3 = decode_hex( + 'c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470') def compress(data): @@ -15,7 +16,8 @@ def compress(data): i += 31 elif data[i:i + 2] == b'\x00\x00': p = 2 - while p < 255 and i + p < len(data) and int_to_bytes(data[i + p]) == b'\x00': + while p < 255 and i + \ + p < len(data) and int_to_bytes(data[i + p]) == b'\x00': p += 1 o += b'\xfe' + ascii_chr(p) i += p - 1 diff --git a/ethereum/config.py b/ethereum/config.py index 188638c4d..f2c5aa512 100644 --- a/ethereum/config.py +++ b/ethereum/config.py @@ -64,28 +64,31 @@ METROPOLIS_GETTER_CODE=decode_hex('6000355460205260206020f3'), METROPOLIS_DIFF_ADJUSTMENT_CUTOFF=9, # Constantinople fork - CONSTANTINOPLE_FORK_BLKNUM = 2**100, + CONSTANTINOPLE_FORK_BLKNUM=2**100, # DAO fork DAO_FORK_BLKNUM=1920000, - DAO_FORK_BLKHASH=decode_hex('4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb'), + DAO_FORK_BLKHASH=decode_hex( + '4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb'), DAO_FORK_BLKEXTRA=decode_hex('64616f2d686172642d666f726b'), CHILD_DAO_LIST=list(map(utils.normalize_address, child_dao_list)), - DAO_WITHDRAWER=utils.normalize_address('0xbf4ed7b27f1d666546e30d74d50d173d20bca754'), + DAO_WITHDRAWER=utils.normalize_address( + '0xbf4ed7b27f1d666546e30d74d50d173d20bca754'), # Anti-DoS fork - ANTI_DOS_FORK_BLKNUM = 2463000, - SPURIOUS_DRAGON_FORK_BLKNUM = 2675000, - CONTRACT_CODE_SIZE_LIMIT = 0x6000, + ANTI_DOS_FORK_BLKNUM=2463000, + SPURIOUS_DRAGON_FORK_BLKNUM=2675000, + CONTRACT_CODE_SIZE_LIMIT=0x6000, # Default consensus strategy: ethash, poa, casper, pbft - CONSENSUS_STRATEGY = 'ethash', + CONSENSUS_STRATEGY='ethash', # Serenity fork - SERENITY_FORK_BLKNUM = 2**99, - PREV_HEADER_DEPTH = 256, - SYSTEM_ENTRY_POINT = utils.int_to_addr(2**160 - 2), - SERENITY_HEADER_VERIFIER = utils.int_to_addr(255), - SERENITY_HEADER_POST_FINALIZER = utils.int_to_addr(254), - SERENITY_GETTER_CODE = decode_hex('60ff331436604014161560155760203560003555005b6000355460205260206020f3'), + SERENITY_FORK_BLKNUM=2**99, + PREV_HEADER_DEPTH=256, + SYSTEM_ENTRY_POINT=utils.int_to_addr(2**160 - 2), + SERENITY_HEADER_VERIFIER=utils.int_to_addr(255), + SERENITY_HEADER_POST_FINALIZER=utils.int_to_addr(254), + SERENITY_GETTER_CODE=decode_hex( + '60ff331436604014161560155760203560003555005b6000355460205260206020f3'), # Custom specials - CUSTOM_SPECIALS = {}, + CUSTOM_SPECIALS={}, ) assert default_config['NEPHEW_REWARD'] == \ default_config['BLOCK_REWARD'] // 32 @@ -99,6 +102,7 @@ def __init__(self, db=None, config=None, global_config=None): self.config = config or dict(default_config) self.global_config = global_config or dict() + config_frontier = copy.copy(default_config) config_frontier["HOMESTEAD_FORK_BLKNUM"] = 2**99 config_frontier["ANTI_DOS_FORK_BLKNUM"] = 2**99 diff --git a/ethereum/consensus_strategy.py b/ethereum/consensus_strategy.py index 19a01890f..afab139da 100644 --- a/ethereum/consensus_strategy.py +++ b/ethereum/consensus_strategy.py @@ -5,8 +5,10 @@ def __init__(self, **kwargs): for k, v in kwargs.items(): setattr(self, k, v) + def get_consensus_strategy(config): - if config['CONSENSUS_STRATEGY'] in ('pow', 'ethpow', 'ethash', 'ethereum1'): + if config['CONSENSUS_STRATEGY'] in ( + 'pow', 'ethpow', 'ethash', 'ethereum1'): from ethereum.pow.consensus import check_pow, validate_uncles, \ initialize, finalize, get_uncle_candidates return ConsensusStrategy( @@ -27,5 +29,4 @@ def get_consensus_strategy(config): get_uncles=get_uncle_candidates, ) else: - raise Exception("Please set a consensus strategy! (pow, casper)") - + raise Exception("Please set a consensus strategy! (pow, casper)") diff --git a/ethereum/db.py b/ethereum/db.py index 50626bbfe..d64c630d0 100644 --- a/ethereum/db.py +++ b/ethereum/db.py @@ -123,16 +123,19 @@ def __eq__(self, other): def __hash__(self): return utils.big_endian_to_int(str_to_bytes(self.__repr__())) + @lru_cache(128) def add1(b): v = utils.big_endian_to_int(b) return utils.zpad(utils.encode_int(v + 1), 4) + @lru_cache(128) def sub1(b): v = utils.big_endian_to_int(b) return utils.zpad(utils.encode_int(v - 1), 4) + class RefcountDB(BaseDB): def __init__(self, db): @@ -181,4 +184,3 @@ def __eq__(self, other): def __hash__(self): return utils.big_endian_to_int(str_to_bytes(self.__repr__())) - diff --git a/ethereum/experimental/fastvm.py b/ethereum/experimental/fastvm.py index 49f6e13ea..0b63c051c 100644 --- a/ethereum/experimental/fastvm.py +++ b/ethereum/experimental/fastvm.py @@ -33,7 +33,7 @@ TT255 = 2 ** 255 for op in opcodes.opcodes: - globals()["op_"+opcodes.opcodes[op][0]] = op + globals()["op_" + opcodes.opcodes[op][0]] = op INVALID = -1 @@ -92,6 +92,7 @@ def __init__(self, **kwargs): for kw in kwargs: setattr(self, kw, kwargs[kw]) + end_breakpoints = [ 'JUMP', 'JUMPI', 'CALL', 'CALLCODE', 'CREATE', 'SUICIDE', 'STOP', 'RETURN', 'SUICIDE', 'INVALID', 'GAS', 'PC' ] @@ -129,7 +130,12 @@ def preprocess_code(code): opcode = -1 cc_gas_consumption += fee cc_min_req_stack = max(cc_min_req_stack, -cc_stack_change + in_args) - cc_max_req_stack = min(cc_max_req_stack, 1024 - cc_stack_change + in_args - out_args) + cc_max_req_stack = min( + cc_max_req_stack, + 1024 - + cc_stack_change + + in_args - + out_args) cc_stack_change = cc_stack_change - in_args + out_args cur_chunk.append(opcode + (pushval << 8)) if op in end_breakpoints or i >= len(code) or \ @@ -207,412 +213,429 @@ def vm_execute(ext, msg, code): steps = 0 _prevop = None # for trace only - while 1: - # print('op: ', op, time.time() - s) - # s = time.time() - # stack size limit error - if compustate.pc not in processed_code: - return vm_exception('INVALID START POINT') - - _data = processed_code[compustate.pc] - gas, min_stack, max_stack, compustate.pc = _data[:4] - ops = _data[4:] - - # out of gas error - if gas > compustate.gas: - return vm_exception('OUT OF GAS') - - # insufficient stack error - if not (min_stack <= len(compustate.stack) <= max_stack): - return vm_exception('INCOMPATIBLE STACK LENGTH', min_stack=min_stack, - have=len(compustate.stack), max_stack=max_stack) - - # Apply operation - compustate.gas -= gas - - for op in ops: - - if trace_vm: - """ - This diverges from normal logging, as we use the logging namespace - only to decide which features get logged in 'eth.vm.op' - i.e. tracing can not be activated by activating a sub - like 'eth.vm.op.stack' - """ - trace_data = {} - trace_data['stack'] = list(map(to_string, list(compustate.stack))) - if _prevop in (op_MLOAD, op_MSTORE, op_MSTORE8, op_SHA3, op_CALL, - op_CALLCODE, op_CREATE, op_CALLDATACOPY, op_CODECOPY, - op_EXTCODECOPY): - if len(compustate.memory) < 1024: - trace_data['memory'] = \ - b''.join([encode_hex(ascii_chr(x)) for x - in compustate.memory]) - else: - trace_data['sha3memory'] = \ - encode_hex(utils.sha3(''.join([ascii_chr(x) for - x in compustate.memory]))) - if _prevop in (op_SSTORE, op_SLOAD) or steps == 0: - trace_data['storage'] = ext.log_storage(msg.to) - # trace_data['gas'] = to_string(compustate.gas + fee) - trace_data['inst'] = op - trace_data['pc'] = to_string(compustate.pc - 1) - if steps == 0: - trace_data['depth'] = msg.depth - trace_data['address'] = msg.to - trace_data['op'] = op - trace_data['steps'] = steps - # if op[:4] == 'PUSH': - # trace_data['pushvalue'] = pushval - log_vm_op.trace('vm', **trace_data) - steps += 1 - _prevop = op - - # Invalid operation - if op == INVALID: - return vm_exception('INVALID OP', opcode=op) - - # Valid operations - if op < 0x10: - if op == op_STOP: - return peaceful_exit('STOP', compustate.gas, []) - elif op == op_ADD: - stk.append((stk.pop() + stk.pop()) & TT256M1) - elif op == op_SUB: - stk.append((stk.pop() - stk.pop()) & TT256M1) - elif op == op_MUL: - stk.append((stk.pop() * stk.pop()) & TT256M1) - elif op == op_DIV: - s0, s1 = stk.pop(), stk.pop() - stk.append(0 if s1 == 0 else s0 // s1) - elif op == op_MOD: - s0, s1 = stk.pop(), stk.pop() - stk.append(0 if s1 == 0 else s0 % s1) - elif op == op_SDIV: - s0, s1 = utils.to_signed(stk.pop()), utils.to_signed(stk.pop()) - stk.append(0 if s1 == 0 else (abs(s0) // abs(s1) * - (-1 if s0 * s1 < 0 else 1)) & TT256M1) - elif op == op_SMOD: - s0, s1 = utils.to_signed(stk.pop()), utils.to_signed(stk.pop()) - stk.append(0 if s1 == 0 else (abs(s0) % abs(s1) * - (-1 if s0 < 0 else 1)) & TT256M1) - elif op == op_ADDMOD: - s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() - stk.append((s0 + s1) % s2 if s2 else 0) - elif op == op_MULMOD: - s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() - stk.append((s0 * s1) % s2 if s2 else 0) - elif op == op_EXP: - base, exponent = stk.pop(), stk.pop() - # fee for exponent is dependent on its bytes - # calc n bytes to represent exponent - nbytes = len(utils.encode_int(exponent)) - expfee = nbytes * opcodes.GEXPONENTBYTE - if compustate.gas < expfee: - compustate.gas = 0 - return vm_exception('OOG EXPONENT') - compustate.gas -= expfee - stk.append(pow(base, exponent, TT256)) - elif op == op_SIGNEXTEND: - s0, s1 = stk.pop(), stk.pop() - if s0 <= 31: - testbit = s0 * 8 + 7 - if s1 & (1 << testbit): - stk.append(s1 | (TT256 - (1 << testbit))) + while True: + # print('op: ', op, time.time() - s) + # s = time.time() + # stack size limit error + if compustate.pc not in processed_code: + return vm_exception('INVALID START POINT') + + _data = processed_code[compustate.pc] + gas, min_stack, max_stack, compustate.pc = _data[:4] + ops = _data[4:] + + # out of gas error + if gas > compustate.gas: + return vm_exception('OUT OF GAS') + + # insufficient stack error + if not (min_stack <= len(compustate.stack) <= max_stack): + return vm_exception('INCOMPATIBLE STACK LENGTH', min_stack=min_stack, + have=len(compustate.stack), max_stack=max_stack) + + # Apply operation + compustate.gas -= gas + + for op in ops: + + if trace_vm: + """ + This diverges from normal logging, as we use the logging namespace + only to decide which features get logged in 'eth.vm.op' + i.e. tracing can not be activated by activating a sub + like 'eth.vm.op.stack' + """ + trace_data = {} + trace_data['stack'] = list( + map(to_string, list(compustate.stack))) + if _prevop in (op_MLOAD, op_MSTORE, op_MSTORE8, op_SHA3, op_CALL, + op_CALLCODE, op_CREATE, op_CALLDATACOPY, op_CODECOPY, + op_EXTCODECOPY): + if len(compustate.memory) < 1024: + trace_data['memory'] = \ + b''.join([encode_hex(ascii_chr(x)) for x + in compustate.memory]) else: - stk.append(s1 & ((1 << testbit) - 1)) - else: - stk.append(s1) - elif op < 0x20: - if op == op_LT: - stk.append(1 if stk.pop() < stk.pop() else 0) - elif op == op_GT: - stk.append(1 if stk.pop() > stk.pop() else 0) - elif op == op_SLT: - s0, s1 = utils.to_signed(stk.pop()), utils.to_signed(stk.pop()) - stk.append(1 if s0 < s1 else 0) - elif op == op_SGT: - s0, s1 = utils.to_signed(stk.pop()), utils.to_signed(stk.pop()) - stk.append(1 if s0 > s1 else 0) - elif op == op_EQ: - stk.append(1 if stk.pop() == stk.pop() else 0) - elif op == op_ISZERO: - stk.append(0 if stk.pop() else 1) - elif op == op_AND: - stk.append(stk.pop() & stk.pop()) - elif op == op_OR: - stk.append(stk.pop() | stk.pop()) - elif op == op_XOR: - stk.append(stk.pop() ^ stk.pop()) - elif op == op_NOT: - stk.append(TT256M1 - stk.pop()) - elif op == op_BYTE: - s0, s1 = stk.pop(), stk.pop() - if s0 >= 32: - stk.append(0) - else: - stk.append((s1 // 256 ** (31 - s0)) % 256) - elif op < 0x40: - if op == op_SHA3: - s0, s1 = stk.pop(), stk.pop() - compustate.gas -= opcodes.GSHA3WORD * (utils.ceil32(s1) // 32) - if compustate.gas < 0: - return vm_exception('OOG PAYING FOR SHA3') - if not mem_extend(mem, compustate, op, s0, s1): - return vm_exception('OOG EXTENDING MEMORY') - data = b''.join(map(ascii_chr, mem[s0: s0 + s1])) - stk.append(utils.big_endian_to_int(utils.sha3(data))) - elif op == op_ADDRESS: - stk.append(utils.coerce_to_int(msg.to)) - elif op == op_BALANCE: - addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) - stk.append(ext.get_balance(addr)) - elif op == op_ORIGIN: - stk.append(utils.coerce_to_int(ext.tx_origin)) - elif op == op_CALLER: - stk.append(utils.coerce_to_int(msg.sender)) - elif op == op_CALLVALUE: - stk.append(msg.value) - elif op == op_CALLDATALOAD: - stk.append(msg.data.extract32(stk.pop())) - elif op == op_CALLDATASIZE: - stk.append(msg.data.size) - elif op == op_CALLDATACOPY: - mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, mstart, size): - return vm_exception('OOG EXTENDING MEMORY') - if not data_copy(compustate, size): - return vm_exception('OOG COPY DATA') - msg.data.extract_copy(mem, mstart, dstart, size) - elif op == op_CODESIZE: - stk.append(len(code)) - elif op == op_CODECOPY: - start, s1, size = stk.pop(), stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, start, size): - return vm_exception('OOG EXTENDING MEMORY') - if not data_copy(compustate, size): - return vm_exception('OOG COPY DATA') - for i in range(size): - if s1 + i < len(code): - mem[start + i] = utils.safe_ord(code[s1 + i]) + trace_data['sha3memory'] = \ + encode_hex(utils.sha3(''.join([ascii_chr(x) for + x in compustate.memory]))) + if _prevop in (op_SSTORE, op_SLOAD) or steps == 0: + trace_data['storage'] = ext.log_storage(msg.to) + # trace_data['gas'] = to_string(compustate.gas + fee) + trace_data['inst'] = op + trace_data['pc'] = to_string(compustate.pc - 1) + if steps == 0: + trace_data['depth'] = msg.depth + trace_data['address'] = msg.to + trace_data['op'] = op + trace_data['steps'] = steps + # if op[:4] == 'PUSH': + # trace_data['pushvalue'] = pushval + log_vm_op.trace('vm', **trace_data) + steps += 1 + _prevop = op + + # Invalid operation + if op == INVALID: + return vm_exception('INVALID OP', opcode=op) + + # Valid operations + if op < 0x10: + if op == op_STOP: + return peaceful_exit('STOP', compustate.gas, []) + elif op == op_ADD: + stk.append((stk.pop() + stk.pop()) & TT256M1) + elif op == op_SUB: + stk.append((stk.pop() - stk.pop()) & TT256M1) + elif op == op_MUL: + stk.append((stk.pop() * stk.pop()) & TT256M1) + elif op == op_DIV: + s0, s1 = stk.pop(), stk.pop() + stk.append(0 if s1 == 0 else s0 // s1) + elif op == op_MOD: + s0, s1 = stk.pop(), stk.pop() + stk.append(0 if s1 == 0 else s0 % s1) + elif op == op_SDIV: + s0, s1 = utils.to_signed( + stk.pop()), utils.to_signed( + stk.pop()) + stk.append(0 if s1 == 0 else (abs(s0) // abs(s1) * + (-1 if s0 * s1 < 0 else 1)) & TT256M1) + elif op == op_SMOD: + s0, s1 = utils.to_signed( + stk.pop()), utils.to_signed( + stk.pop()) + stk.append(0 if s1 == 0 else (abs(s0) % abs(s1) * + (-1 if s0 < 0 else 1)) & TT256M1) + elif op == op_ADDMOD: + s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() + stk.append((s0 + s1) % s2 if s2 else 0) + elif op == op_MULMOD: + s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() + stk.append((s0 * s1) % s2 if s2 else 0) + elif op == op_EXP: + base, exponent = stk.pop(), stk.pop() + # fee for exponent is dependent on its bytes + # calc n bytes to represent exponent + nbytes = len(utils.encode_int(exponent)) + expfee = nbytes * opcodes.GEXPONENTBYTE + if compustate.gas < expfee: + compustate.gas = 0 + return vm_exception('OOG EXPONENT') + compustate.gas -= expfee + stk.append(pow(base, exponent, TT256)) + elif op == op_SIGNEXTEND: + s0, s1 = stk.pop(), stk.pop() + if s0 <= 31: + testbit = s0 * 8 + 7 + if s1 & (1 << testbit): + stk.append(s1 | (TT256 - (1 << testbit))) + else: + stk.append(s1 & ((1 << testbit) - 1)) else: - mem[start + i] = 0 - elif op == op_GASPRICE: - stk.append(ext.tx_gasprice) - elif op == op_EXTCODESIZE: - addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) - stk.append(len(ext.get_code(addr) or b'')) - elif op == op_EXTCODECOPY: - addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) - start, s2, size = stk.pop(), stk.pop(), stk.pop() - extcode = ext.get_code(addr) or b'' - assert utils.is_string(extcode) - if not mem_extend(mem, compustate, op, start, size): - return vm_exception('OOG EXTENDING MEMORY') - if not data_copy(compustate, size): - return vm_exception('OOG COPY DATA') - for i in range(size): - if s2 + i < len(extcode): - mem[start + i] = utils.safe_ord(extcode[s2 + i]) + stk.append(s1) + elif op < 0x20: + if op == op_LT: + stk.append(1 if stk.pop() < stk.pop() else 0) + elif op == op_GT: + stk.append(1 if stk.pop() > stk.pop() else 0) + elif op == op_SLT: + s0, s1 = utils.to_signed( + stk.pop()), utils.to_signed( + stk.pop()) + stk.append(1 if s0 < s1 else 0) + elif op == op_SGT: + s0, s1 = utils.to_signed( + stk.pop()), utils.to_signed( + stk.pop()) + stk.append(1 if s0 > s1 else 0) + elif op == op_EQ: + stk.append(1 if stk.pop() == stk.pop() else 0) + elif op == op_ISZERO: + stk.append(0 if stk.pop() else 1) + elif op == op_AND: + stk.append(stk.pop() & stk.pop()) + elif op == op_OR: + stk.append(stk.pop() | stk.pop()) + elif op == op_XOR: + stk.append(stk.pop() ^ stk.pop()) + elif op == op_NOT: + stk.append(TT256M1 - stk.pop()) + elif op == op_BYTE: + s0, s1 = stk.pop(), stk.pop() + if s0 >= 32: + stk.append(0) else: - mem[start + i] = 0 - elif op < 0x50: - if op == op_BLOCKHASH: - stk.append(utils.big_endian_to_int(ext.block_hash(stk.pop()))) - elif op == op_COINBASE: - stk.append(utils.big_endian_to_int(ext.block_coinbase)) - elif op == op_TIMESTAMP: - stk.append(ext.block_timestamp) - elif op == op_NUMBER: - stk.append(ext.block_number) - elif op == op_DIFFICULTY: - stk.append(ext.block_difficulty) - elif op == op_GASLIMIT: - stk.append(ext.block_gas_limit) - elif op < 0x60: - if op == op_POP: - stk.pop() - elif op == op_MLOAD: - s0 = stk.pop() - if not mem_extend(mem, compustate, op, s0, 32): - return vm_exception('OOG EXTENDING MEMORY') - data = 0 - for c in mem[s0: s0 + 32]: - data = (data << 8) + c - stk.append(data) - elif op == op_MSTORE: - s0, s1 = stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, s0, 32): - return vm_exception('OOG EXTENDING MEMORY') - v = s1 - for i in range(31, -1, -1): - mem[s0 + i] = v % 256 - v //= 256 - elif op == op_MSTORE8: - s0, s1 = stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, s0, 1): - return vm_exception('OOG EXTENDING MEMORY') - mem[s0] = s1 % 256 - elif op == op_SLOAD: - stk.append(ext.get_storage_data(msg.to, stk.pop())) - elif op == op_SSTORE: - s0, s1 = stk.pop(), stk.pop() - if ext.get_storage_data(msg.to, s0): - gascost = opcodes.GSTORAGEMOD if s1 else opcodes.GSTORAGEKILL - refund = 0 if s1 else opcodes.GSTORAGEREFUND - else: - gascost = opcodes.GSTORAGEADD if s1 else opcodes.GSTORAGEMOD - refund = 0 - if compustate.gas < gascost: - return vm_exception('OUT OF GAS') - compustate.gas -= gascost - ext.add_refund(refund) # adds neg gascost as a refund if below zero - ext.set_storage_data(msg.to, s0, s1) - elif op == op_JUMP: - compustate.pc = stk.pop() - opnew = processed_code[compustate.pc][4] if \ - compustate.pc in processed_code else op_STOP - if opnew != op_JUMPDEST: - return vm_exception('BAD JUMPDEST') - elif op == op_JUMPI: - s0, s1 = stk.pop(), stk.pop() - if s1: - compustate.pc = s0 + stk.append((s1 // 256 ** (31 - s0)) % 256) + elif op < 0x40: + if op == op_SHA3: + s0, s1 = stk.pop(), stk.pop() + compustate.gas -= opcodes.GSHA3WORD * \ + (utils.ceil32(s1) // 32) + if compustate.gas < 0: + return vm_exception('OOG PAYING FOR SHA3') + if not mem_extend(mem, compustate, op, s0, s1): + return vm_exception('OOG EXTENDING MEMORY') + data = b''.join(map(ascii_chr, mem[s0: s0 + s1])) + stk.append(utils.big_endian_to_int(utils.sha3(data))) + elif op == op_ADDRESS: + stk.append(utils.coerce_to_int(msg.to)) + elif op == op_BALANCE: + addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) + stk.append(ext.get_balance(addr)) + elif op == op_ORIGIN: + stk.append(utils.coerce_to_int(ext.tx_origin)) + elif op == op_CALLER: + stk.append(utils.coerce_to_int(msg.sender)) + elif op == op_CALLVALUE: + stk.append(msg.value) + elif op == op_CALLDATALOAD: + stk.append(msg.data.extract32(stk.pop())) + elif op == op_CALLDATASIZE: + stk.append(msg.data.size) + elif op == op_CALLDATACOPY: + mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() + if not mem_extend(mem, compustate, op, mstart, size): + return vm_exception('OOG EXTENDING MEMORY') + if not data_copy(compustate, size): + return vm_exception('OOG COPY DATA') + msg.data.extract_copy(mem, mstart, dstart, size) + elif op == op_CODESIZE: + stk.append(len(code)) + elif op == op_CODECOPY: + start, s1, size = stk.pop(), stk.pop(), stk.pop() + if not mem_extend(mem, compustate, op, start, size): + return vm_exception('OOG EXTENDING MEMORY') + if not data_copy(compustate, size): + return vm_exception('OOG COPY DATA') + for i in range(size): + if s1 + i < len(code): + mem[start + i] = utils.safe_ord(code[s1 + i]) + else: + mem[start + i] = 0 + elif op == op_GASPRICE: + stk.append(ext.tx_gasprice) + elif op == op_EXTCODESIZE: + addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) + stk.append(len(ext.get_code(addr) or b'')) + elif op == op_EXTCODECOPY: + addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) + start, s2, size = stk.pop(), stk.pop(), stk.pop() + extcode = ext.get_code(addr) or b'' + assert utils.is_string(extcode) + if not mem_extend(mem, compustate, op, start, size): + return vm_exception('OOG EXTENDING MEMORY') + if not data_copy(compustate, size): + return vm_exception('OOG COPY DATA') + for i in range(size): + if s2 + i < len(extcode): + mem[start + i] = utils.safe_ord(extcode[s2 + i]) + else: + mem[start + i] = 0 + elif op < 0x50: + if op == op_BLOCKHASH: + stk.append( + utils.big_endian_to_int( + ext.block_hash( + stk.pop()))) + elif op == op_COINBASE: + stk.append(utils.big_endian_to_int(ext.block_coinbase)) + elif op == op_TIMESTAMP: + stk.append(ext.block_timestamp) + elif op == op_NUMBER: + stk.append(ext.block_number) + elif op == op_DIFFICULTY: + stk.append(ext.block_difficulty) + elif op == op_GASLIMIT: + stk.append(ext.block_gas_limit) + elif op < 0x60: + if op == op_POP: + stk.pop() + elif op == op_MLOAD: + s0 = stk.pop() + if not mem_extend(mem, compustate, op, s0, 32): + return vm_exception('OOG EXTENDING MEMORY') + data = 0 + for c in mem[s0: s0 + 32]: + data = (data << 8) + c + stk.append(data) + elif op == op_MSTORE: + s0, s1 = stk.pop(), stk.pop() + if not mem_extend(mem, compustate, op, s0, 32): + return vm_exception('OOG EXTENDING MEMORY') + v = s1 + for i in range(31, -1, -1): + mem[s0 + i] = v % 256 + v //= 256 + elif op == op_MSTORE8: + s0, s1 = stk.pop(), stk.pop() + if not mem_extend(mem, compustate, op, s0, 1): + return vm_exception('OOG EXTENDING MEMORY') + mem[s0] = s1 % 256 + elif op == op_SLOAD: + stk.append(ext.get_storage_data(msg.to, stk.pop())) + elif op == op_SSTORE: + s0, s1 = stk.pop(), stk.pop() + if ext.get_storage_data(msg.to, s0): + gascost = opcodes.GSTORAGEMOD if s1 else opcodes.GSTORAGEKILL + refund = 0 if s1 else opcodes.GSTORAGEREFUND + else: + gascost = opcodes.GSTORAGEADD if s1 else opcodes.GSTORAGEMOD + refund = 0 + if compustate.gas < gascost: + return vm_exception('OUT OF GAS') + compustate.gas -= gascost + # adds neg gascost as a refund if below zero + ext.add_refund(refund) + ext.set_storage_data(msg.to, s0, s1) + elif op == op_JUMP: + compustate.pc = stk.pop() opnew = processed_code[compustate.pc][4] if \ compustate.pc in processed_code else op_STOP if opnew != op_JUMPDEST: return vm_exception('BAD JUMPDEST') - elif op == op_PC: - stk.append(compustate.pc - 1) - elif op == op_MSIZE: - stk.append(len(mem)) - elif op == op_GAS: - stk.append(compustate.gas) # AFTER subtracting cost 1 - elif op_PUSH1 <= (op & 255) <= op_PUSH32: - # Hide push value in high-order bytes of op - stk.append(op >> 8) - elif op_DUP1 <= op <= op_DUP16: - depth = op - op_DUP1 + 1 - stk.append(stk[-depth]) - elif op_SWAP1 <= op <= op_SWAP16: - depth = op - op_SWAP1 + 1 - temp = stk[-depth - 1] - stk[-depth - 1] = stk[-1] - stk[-1] = temp - - elif op_LOG0 <= op <= op_LOG4: - """ - 0xa0 ... 0xa4, 32/64/96/128/160 + len(data) gas - a. Opcodes LOG0...LOG4 are added, takes 2-6 stack arguments - MEMSTART MEMSZ (TOPIC1) (TOPIC2) (TOPIC3) (TOPIC4) - b. Logs are kept track of during tx execution exactly the same way as suicides - (except as an ordered list, not a set). - Each log is in the form [address, [topic1, ... ], data] where: - * address is what the ADDRESS opcode would output - * data is mem[MEMSTART: MEMSTART + MEMSZ] - * topics are as provided by the opcode - c. The ordered list of logs in the transaction are expressed as [log0, log1, ..., logN]. - """ - depth = op - op_LOG0 - mstart, msz = stk.pop(), stk.pop() - topics = [stk.pop() for x in range(depth)] - compustate.gas -= msz * opcodes.GLOGBYTE - if not mem_extend(mem, compustate, op, mstart, msz): - return vm_exception('OOG EXTENDING MEMORY') - data = b''.join(map(ascii_chr, mem[mstart: mstart + msz])) - ext.log(msg.to, topics, data) - log_log.trace('LOG', to=msg.to, topics=topics, data=list(map(utils.safe_ord, data))) - # print('LOG', msg.to, topics, list(map(ord, data))) - - elif op == op_CREATE: - value, mstart, msz = stk.pop(), stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, mstart, msz): - return vm_exception('OOG EXTENDING MEMORY') - if ext.get_balance(msg.to) >= value and msg.depth < 1024: - cd = CallData(mem, mstart, msz) - create_msg = Message(msg.to, b'', value, compustate.gas, cd, msg.depth + 1) - o, gas, addr = ext.create(create_msg) - if o: - stk.append(utils.coerce_to_int(addr)) - compustate.gas = gas + elif op == op_JUMPI: + s0, s1 = stk.pop(), stk.pop() + if s1: + compustate.pc = s0 + opnew = processed_code[compustate.pc][4] if \ + compustate.pc in processed_code else op_STOP + if opnew != op_JUMPDEST: + return vm_exception('BAD JUMPDEST') + elif op == op_PC: + stk.append(compustate.pc - 1) + elif op == op_MSIZE: + stk.append(len(mem)) + elif op == op_GAS: + stk.append(compustate.gas) # AFTER subtracting cost 1 + elif op_PUSH1 <= (op & 255) <= op_PUSH32: + # Hide push value in high-order bytes of op + stk.append(op >> 8) + elif op_DUP1 <= op <= op_DUP16: + depth = op - op_DUP1 + 1 + stk.append(stk[-depth]) + elif op_SWAP1 <= op <= op_SWAP16: + depth = op - op_SWAP1 + 1 + temp = stk[-depth - 1] + stk[-depth - 1] = stk[-1] + stk[-1] = temp + + elif op_LOG0 <= op <= op_LOG4: + """ + 0xa0 ... 0xa4, 32/64/96/128/160 + len(data) gas + a. Opcodes LOG0...LOG4 are added, takes 2-6 stack arguments + MEMSTART MEMSZ (TOPIC1) (TOPIC2) (TOPIC3) (TOPIC4) + b. Logs are kept track of during tx execution exactly the same way as suicides + (except as an ordered list, not a set). + Each log is in the form [address, [topic1, ... ], data] where: + * address is what the ADDRESS opcode would output + * data is mem[MEMSTART: MEMSTART + MEMSZ] + * topics are as provided by the opcode + c. The ordered list of logs in the transaction are expressed as [log0, log1, ..., logN]. + """ + depth = op - op_LOG0 + mstart, msz = stk.pop(), stk.pop() + topics = [stk.pop() for x in range(depth)] + compustate.gas -= msz * opcodes.GLOGBYTE + if not mem_extend(mem, compustate, op, mstart, msz): + return vm_exception('OOG EXTENDING MEMORY') + data = b''.join(map(ascii_chr, mem[mstart: mstart + msz])) + ext.log(msg.to, topics, data) + log_log.trace('LOG', to=msg.to, topics=topics, + data=list(map(utils.safe_ord, data))) + # print('LOG', msg.to, topics, list(map(ord, data))) + + elif op == op_CREATE: + value, mstart, msz = stk.pop(), stk.pop(), stk.pop() + if not mem_extend(mem, compustate, op, mstart, msz): + return vm_exception('OOG EXTENDING MEMORY') + if ext.get_balance(msg.to) >= value and msg.depth < 1024: + cd = CallData(mem, mstart, msz) + create_msg = Message( + msg.to, b'', value, compustate.gas, cd, msg.depth + 1) + o, gas, addr = ext.create(create_msg) + if o: + stk.append(utils.coerce_to_int(addr)) + compustate.gas = gas + else: + stk.append(0) + compustate.gas = 0 else: stk.append(0) - compustate.gas = 0 - else: - stk.append(0) - elif op == op_CALL: - gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ - stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ - not mem_extend(mem, compustate, op, memoutstart, memoutsz): - return vm_exception('OOG EXTENDING MEMORY') - to = utils.encode_int(to) - to = ((b'\x00' * (32 - len(to))) + to)[12:] - extra_gas = (not ext.account_exists(to)) * opcodes.GCALLNEWACCOUNT + \ - (value > 0) * opcodes.GCALLVALUETRANSFER - submsg_gas = gas + opcodes.GSTIPEND * (value > 0) - if compustate.gas < gas + extra_gas: - return vm_exception('OUT OF GAS', needed=gas+extra_gas) - if ext.get_balance(msg.to) >= value and msg.depth < 1024: - compustate.gas -= (gas + extra_gas) - cd = CallData(mem, meminstart, meminsz) - call_msg = Message(msg.to, to, value, submsg_gas, cd, - msg.depth + 1, code_address=to) - result, gas, data = ext.msg(call_msg) - if result == 0: - stk.append(0) - else: - stk.append(1) - compustate.gas += gas - for i in range(min(len(data), memoutsz)): - mem[memoutstart + i] = data[i] - else: - compustate.gas -= (gas + extra_gas - submsg_gas) - stk.append(0) - elif op == op_CALLCODE: - gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ - stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ - not mem_extend(mem, compustate, op, memoutstart, memoutsz): - return vm_exception('OOG EXTENDING MEMORY') - extra_gas = (value > 0) * opcodes.GCALLVALUETRANSFER - submsg_gas = gas + opcodes.GSTIPEND * (value > 0) - if compustate.gas < gas + extra_gas: - return vm_exception('OUT OF GAS', needed=gas+extra_gas) - if ext.get_balance(msg.to) >= value and msg.depth < 1024: - compustate.gas -= (gas + extra_gas) + elif op == op_CALL: + gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ + stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() + if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ + not mem_extend(mem, compustate, op, memoutstart, memoutsz): + return vm_exception('OOG EXTENDING MEMORY') to = utils.encode_int(to) to = ((b'\x00' * (32 - len(to))) + to)[12:] - cd = CallData(mem, meminstart, meminsz) - call_msg = Message(msg.to, msg.to, value, submsg_gas, cd, - msg.depth + 1, code_address=to) - result, gas, data = ext.msg(call_msg) - if result == 0: + extra_gas = (not ext.account_exists(to)) * opcodes.GCALLNEWACCOUNT + \ + (value > 0) * opcodes.GCALLVALUETRANSFER + submsg_gas = gas + opcodes.GSTIPEND * (value > 0) + if compustate.gas < gas + extra_gas: + return vm_exception('OUT OF GAS', needed=gas + extra_gas) + if ext.get_balance(msg.to) >= value and msg.depth < 1024: + compustate.gas -= (gas + extra_gas) + cd = CallData(mem, meminstart, meminsz) + call_msg = Message(msg.to, to, value, submsg_gas, cd, + msg.depth + 1, code_address=to) + result, gas, data = ext.msg(call_msg) + if result == 0: + stk.append(0) + else: + stk.append(1) + compustate.gas += gas + for i in range(min(len(data), memoutsz)): + mem[memoutstart + i] = data[i] + else: + compustate.gas -= (gas + extra_gas - submsg_gas) stk.append(0) + elif op == op_CALLCODE: + gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ + stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() + if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ + not mem_extend(mem, compustate, op, memoutstart, memoutsz): + return vm_exception('OOG EXTENDING MEMORY') + extra_gas = (value > 0) * opcodes.GCALLVALUETRANSFER + submsg_gas = gas + opcodes.GSTIPEND * (value > 0) + if compustate.gas < gas + extra_gas: + return vm_exception('OUT OF GAS', needed=gas + extra_gas) + if ext.get_balance(msg.to) >= value and msg.depth < 1024: + compustate.gas -= (gas + extra_gas) + to = utils.encode_int(to) + to = ((b'\x00' * (32 - len(to))) + to)[12:] + cd = CallData(mem, meminstart, meminsz) + call_msg = Message(msg.to, msg.to, value, submsg_gas, cd, + msg.depth + 1, code_address=to) + result, gas, data = ext.msg(call_msg) + if result == 0: + stk.append(0) + else: + stk.append(1) + compustate.gas += gas + for i in range(min(len(data), memoutsz)): + mem[memoutstart + i] = data[i] else: - stk.append(1) - compustate.gas += gas - for i in range(min(len(data), memoutsz)): - mem[memoutstart + i] = data[i] - else: - compustate.gas -= (gas + extra_gas - submsg_gas) - stk.append(0) - elif op == op_RETURN: - s0, s1 = stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, s0, s1): - return vm_exception('OOG EXTENDING MEMORY') - return peaceful_exit('RETURN', compustate.gas, mem[s0: s0 + s1]) - elif op == op_SUICIDE: - to = utils.encode_int(stk.pop()) - to = ((b'\x00' * (32 - len(to))) + to)[12:] - xfer = ext.get_balance(msg.to) - ext.set_balance(to, ext.get_balance(to) + xfer) - ext.set_balance(msg.to, 0) - ext.add_suicide(msg.to) - # print('suiciding %s %s %d' % (msg.to, to, xfer)) - return 1, compustate.gas, [] - - # this is slow! - # for a in stk: - # assert is_numeric(a), (op, stk) - # assert a >= 0 and a < 2**256, (a, op, stk) + compustate.gas -= (gas + extra_gas - submsg_gas) + stk.append(0) + elif op == op_RETURN: + s0, s1 = stk.pop(), stk.pop() + if not mem_extend(mem, compustate, op, s0, s1): + return vm_exception('OOG EXTENDING MEMORY') + return peaceful_exit( + 'RETURN', compustate.gas, mem[s0: s0 + s1]) + elif op == op_SUICIDE: + to = utils.encode_int(stk.pop()) + to = ((b'\x00' * (32 - len(to))) + to)[12:] + xfer = ext.get_balance(msg.to) + ext.set_balance(to, ext.get_balance(to) + xfer) + ext.set_balance(msg.to, 0) + ext.add_suicide(msg.to) + # print('suiciding %s %s %d' % (msg.to, to, xfer)) + return 1, compustate.gas, [] + + # this is slow! + # for a in stk: + # assert is_numeric(a), (op, stk) + # assert a >= 0 and a < 2**256, (a, op, stk) diff --git a/ethereum/experimental/pruning_trie.py b/ethereum/experimental/pruning_trie.py index b2d4ba8d7..c4c358eb9 100644 --- a/ethereum/experimental/pruning_trie.py +++ b/ethereum/experimental/pruning_trie.py @@ -98,6 +98,7 @@ def add_exempt(self, node): def get_mode(self): return self.mode[-1] + proof = ProofConstructor() @@ -188,6 +189,7 @@ def is_key_value_type(node_type): return node_type in [NODE_TYPE_LEAF, NODE_TYPE_EXTENSION] + BLANK_NODE = b'' BLANK_ROOT = utils.sha3rlp(b'') DEATH_ROW_OFFSET = 2**62 @@ -533,7 +535,9 @@ def _getany(self, node, reverse=False, path=[]): if reverse: scan_range.reverse() for i in scan_range: - o = self._getany(self._decode_to_node(node[i]), path=path + [i]) + o = self._getany( + self._decode_to_node( + node[i]), path=path + [i]) if o: return [i] + o return None @@ -865,7 +869,11 @@ def _to_dict(self, node): sub_dict = self._to_dict(self._decode_to_node(node[i])) for sub_key, sub_value in sub_dict.items(): - full_key = (str_to_bytes(str(i)) + b'+' + sub_key).strip(b'+') + full_key = ( + str_to_bytes( + str(i)) + + b'+' + + sub_key).strip(b'+') res[full_key] = sub_value if node[16]: @@ -922,7 +930,11 @@ def _iter_branch(self, node): for i in range(16): sub_tree = self._iter_branch(self._decode_to_node(node[i])) for sub_key, sub_value in sub_tree: - full_key = (str_to_bytes(str(i)) + b'+' + sub_key).strip(b'+') + full_key = ( + str_to_bytes( + str(i)) + + b'+' + + sub_key).strip(b'+') yield (full_key, sub_value) if node[16]: yield (to_string(NIBBLE_TERMINATOR), node[-1]) diff --git a/ethereum/experimental/refcount_db.py b/ethereum/experimental/refcount_db.py index ff801f519..d96529118 100644 --- a/ethereum/experimental/refcount_db.py +++ b/ethereum/experimental/refcount_db.py @@ -16,7 +16,7 @@ def __init__(self, db): self.death_row = [] try: self.kv = self.db.kv - except: + except BaseException: self.kv = None self.ttl = 500 self.logging = False @@ -25,34 +25,40 @@ def __init__(self, db): def inc_refcount(self, k, v): # raise Exception("WHY AM I CHANGING A REFCOUNT?!:?") try: - node_object = rlp.decode(self.db.get(b'r:'+k)) + node_object = rlp.decode(self.db.get(b'r:' + k)) refcount = utils.decode_int(node_object[0]) self.journal.append([node_object[0], k]) if refcount >= DEATH_ROW_OFFSET: refcount = 0 new_refcount = utils.encode_int(refcount + 1) - self.db.put(b'r:'+k, rlp.encode([new_refcount, v])) + self.db.put(b'r:' + k, rlp.encode([new_refcount, v])) if self.logging: - sys.stderr.write('increasing %s %r to: %d\n' % (utils.encode_hex(k), v, refcount + 1)) - except: - self.db.put(b'r:'+k, rlp.encode([ONE_ENCODED, v])) + sys.stderr.write( + 'increasing %s %r to: %d\n' % + (utils.encode_hex(k), v, refcount + 1)) + except BaseException: + self.db.put(b'r:' + k, rlp.encode([ONE_ENCODED, v])) self.journal.append([ZERO_ENCODED, k]) if self.logging: - sys.stderr.write('increasing %s %r to: %d\n' % (utils.encode_hex(k), v, 1)) + sys.stderr.write( + 'increasing %s %r to: %d\n' % + (utils.encode_hex(k), v, 1)) put = inc_refcount # Decrease the reference count associated with a key def dec_refcount(self, k): # raise Exception("WHY AM I CHANGING A REFCOUNT?!:?") - node_object = rlp.decode(self.db.get(b'r:'+k)) + node_object = rlp.decode(self.db.get(b'r:' + k)) refcount = utils.decode_int(node_object[0]) if self.logging: - sys.stderr.write('decreasing %s to: %d\n' % (utils.encode_hex(k), refcount - 1)) + sys.stderr.write( + 'decreasing %s to: %d\n' % + (utils.encode_hex(k), refcount - 1)) assert refcount > 0 self.journal.append([node_object[0], k]) new_refcount = utils.encode_int(refcount - 1) - self.db.put(b'r:'+k, rlp.encode([new_refcount, node_object[1]])) + self.db.put(b'r:' + k, rlp.encode([new_refcount, node_object[1]])) if new_refcount == ZERO_ENCODED: self.death_row.append(k) @@ -60,44 +66,44 @@ def dec_refcount(self, k): def get_refcount(self, k): try: - o = utils.decode_int(self.db.get(b'r:'+k))[0] + o = utils.decode_int(self.db.get(b'r:' + k))[0] if o >= DEATH_ROW_OFFSET: return 0 return o - except: + except BaseException: return 0 # Get the value associated with a key def get(self, k): - return rlp.decode(self.db.get(b'r:'+k))[1] + return rlp.decode(self.db.get(b'r:' + k))[1] # Kill nodes that are eligible to be killed, and remove the associated # deathrow record. Also delete old journals. def cleanup(self, epoch): try: - death_row_node = self.db.get('deathrow:'+str(epoch)) - except: + death_row_node = self.db.get('deathrow:' + str(epoch)) + except BaseException: death_row_node = rlp.encode([]) death_row_nodes = rlp.decode(death_row_node) pruned = 0 for nodekey in death_row_nodes: try: - refcount, val = rlp.decode(self.db.get(b'r:'+nodekey)) + refcount, val = rlp.decode(self.db.get(b'r:' + nodekey)) if utils.decode_int(refcount) == DEATH_ROW_OFFSET + epoch: - self.db.delete(b'r:'+nodekey) + self.db.delete(b'r:' + nodekey) pruned += 1 - except: + except BaseException: pass sys.stderr.write('%d nodes successfully pruned\n' % pruned) # Delete the deathrow after processing it try: - self.db.delete('deathrow:'+str(epoch)) - except: + self.db.delete('deathrow:' + str(epoch)) + except BaseException: pass # Delete journals that are too old try: - self.db.delete('journal:'+str(epoch - self.ttl)) - except: + self.db.delete('journal:' + str(epoch - self.ttl)) + except BaseException: pass # Commit changes to the journal and death row to the database @@ -105,50 +111,54 @@ def commit_refcount_changes(self, epoch): # Save death row nodes timeout_epoch = epoch + self.ttl try: - death_row_nodes = rlp.decode(self.db.get('deathrow:'+str(timeout_epoch))) - except: + death_row_nodes = rlp.decode( + self.db.get( + 'deathrow:' + + str(timeout_epoch))) + except BaseException: death_row_nodes = [] for nodekey in self.death_row: - refcount, val = rlp.decode(self.db.get(b'r:'+nodekey)) + refcount, val = rlp.decode(self.db.get(b'r:' + nodekey)) if refcount == ZERO_ENCODED: - new_refcount = utils.encode_int(DEATH_ROW_OFFSET + timeout_epoch) - self.db.put(b'r:'+nodekey, rlp.encode([new_refcount, val])) + new_refcount = utils.encode_int( + DEATH_ROW_OFFSET + timeout_epoch) + self.db.put(b'r:' + nodekey, rlp.encode([new_refcount, val])) if len(self.death_row) > 0: sys.stderr.write('%d nodes marked for pruning during block %d\n' % (len(self.death_row), timeout_epoch)) death_row_nodes.extend(self.death_row) self.death_row = [] - self.db.put('deathrow:'+str(timeout_epoch), + self.db.put('deathrow:' + str(timeout_epoch), rlp.encode(death_row_nodes)) # Save journal try: - journal = rlp.decode(self.db.get('journal:'+str(epoch))) - except: + journal = rlp.decode(self.db.get('journal:' + str(epoch))) + except BaseException: journal = [] journal.extend(self.journal) self.journal = [] - self.db.put('journal:'+str(epoch), rlp.encode(journal)) + self.db.put('journal:' + str(epoch), rlp.encode(journal)) # Revert changes made during an epoch def revert_refcount_changes(self, epoch): timeout_epoch = epoch + self.ttl # Delete death row additions try: - self.db.delete('deathrow:'+str(timeout_epoch)) - except: + self.db.delete('deathrow:' + str(timeout_epoch)) + except BaseException: pass # Revert journal changes try: - journal = rlp.decode(self.db.get('journal:'+str(epoch))) + journal = rlp.decode(self.db.get('journal:' + str(epoch))) for new_refcount, hashkey in journal[::-1]: - node_object = rlp.decode(self.db.get(b'r:'+hashkey)) - self.db.put(b'r:'+hashkey, + node_object = rlp.decode(self.db.get(b'r:' + hashkey)) + self.db.put(b'r:' + hashkey, rlp.encode([new_refcount, node_object[1]])) - except: + except BaseException: pass def _has_key(self, key): - return b'r:'+key in self.db + return b'r:' + key in self.db def __contains__(self, key): return self._has_key(key) diff --git a/ethereum/experimental/spv.py b/ethereum/experimental/spv.py index 6ee479bc5..5a2322017 100644 --- a/ethereum/experimental/spv.py +++ b/ethereum/experimental/spv.py @@ -38,9 +38,16 @@ def mk_independent_transaction_spv_proof(block, index): block.state_root = pre_med block.gas_used = pre_gas nodes = mk_transaction_spv_proof(block, tx) - nodes.extend(block.transactions.produce_spv_proof(rlp.encode(utils.encode_int(index)))) + nodes.extend( + block.transactions.produce_spv_proof( + rlp.encode( + utils.encode_int(index)))) if index > 0: - nodes.extend(block.transactions.produce_spv_proof(rlp.encode(utils.encode_int(index - 1)))) + nodes.extend( + block.transactions.produce_spv_proof( + rlp.encode( + utils.encode_int( + index - 1)))) nodes = list(map(rlp.decode, list(set(map(rlp.encode, nodes))))) print(nodes) return rlp.encode([utils.encode_int(64), block.get_parent().list_header(), diff --git a/ethereum/fast_rlp.py b/ethereum/fast_rlp.py index 34eba30b9..e9caa5da8 100644 --- a/ethereum/fast_rlp.py +++ b/ethereum/fast_rlp.py @@ -29,6 +29,7 @@ def length_prefix(length, offset): length_string = int_to_big_endian(length) return chr(offset + 56 - 1 + len(length_string)) + length_string + def _decode_optimized(rlp): o = [] pos = 0 @@ -41,6 +42,7 @@ def _decode_optimized(rlp): pos = _l + _p return o + def consume_length_prefix(rlp, start): """Read a length prefix from an RLP string. @@ -67,6 +69,7 @@ def consume_length_prefix(rlp, start): l = big_endian_to_int(rlp[start + 1:start + 1 + ll]) return (list, l, start + 1 + ll) + def optimized_decode_single(x, pos): z = safe_ord(x[pos]) if z < 128: @@ -77,6 +80,7 @@ def optimized_decode_single(x, pos): ll = big_endian_to_int(x[pos + 1: pos + z - 182]) return x[pos + z - 182: pos + z - 182 + ll], z - 182 + ll + def optimized_decode_list(rlp): o, pos = [], 0 _typ, _len, pos = consume_length_prefix(rlp, pos) @@ -86,6 +90,7 @@ def optimized_decode_list(rlp): o.append(x) return o + # if sys.version_info.major == 2: encode_optimized = _encode_optimized @@ -123,5 +128,6 @@ def run(): r = run() assert r == r2 + if __name__ == '__main__': main() diff --git a/ethereum/fastvm.py b/ethereum/fastvm.py index b08060d88..183166f4b 100644 --- a/ethereum/fastvm.py +++ b/ethereum/fastvm.py @@ -29,7 +29,7 @@ MAX_DEPTH = 1024 -JUMPDEST = 0x5b # Hardcoded, change if needed +JUMPDEST = 0x5b # Hardcoded, change if needed class CallData(object): @@ -63,12 +63,13 @@ def extract_copy(self, mem, memstart, datastart, size): class Message(object): def __init__(self, sender, to, value=0, gas=1000000, data='', depth=0, - code_address=None, is_create=False, transfers_value=True, static=False): + code_address=None, is_create=False, transfers_value=True, static=False): self.sender = sender self.to = to self.value = value self.gas = gas - self.data = CallData(list(map(utils.safe_ord, data))) if isinstance(data, (str, bytes)) else data + self.data = CallData(list(map(utils.safe_ord, data))) if isinstance( + data, (str, bytes)) else data self.depth = depth self.logs = [] self.code_address = to if code_address is None else code_address @@ -91,11 +92,14 @@ def __init__(self, **kwargs): for kw in kwargs: setattr(self, kw, kwargs[kw]) + break_list = ('JUMP', 'GAS', 'JUMPI', 'CALL', 'CREATE', 'CALLCODE', 'DELEGATECALL', 'STATICCALL', - 'SUICIDE', 'RETURN', 'REVERT', 'STOP', 'INVALID') + 'SUICIDE', 'RETURN', 'REVERT', 'STOP', 'INVALID') # Preprocesses code, and determines which locations are in the middle # of pushdata and thus invalid + + def preprocess_code(code): assert isinstance(code, bytes) lencode = len(code) @@ -125,7 +129,8 @@ def preprocess_code(code): maxstack = max(stack, maxstack) gascost += o[3] if o[0] in break_list: - outdict[cur_start] = (ops, minstack, 1024 - maxstack, gascost, i + 1) + outdict[cur_start] = ( + ops, minstack, 1024 - maxstack, gascost, i + 1) cur_start = i + 1 ops = [] minstack, maxstack, stack, gascost = 0, 0, 0, 0 @@ -185,10 +190,12 @@ def peaceful_exit(cause, gas, data, **kargs): log_vm_exit.trace('EXIT', cause=cause, **kargs) return 1, gas, data + def revert(gas, data, **kargs): log_vm_exit.trace('REVERT', **kargs) return 0, gas, data + code_cache = {} @@ -215,464 +222,506 @@ def vm_execute(ext, msg, code): _prevop = None # for trace only while compustate.pc in processed_code: - ops, minstack, maxstack, totgas, nextpos = processed_code[compustate.pc] - - if len(compustate.stack) < minstack: - return vm_exception('INSUFFICIENT STACK') - if len(compustate.stack) > maxstack: - return vm_exception('STACK SIZE LIMIT EXCEEDED') - if totgas > compustate.gas: - return vm_exception('OUT OF GAS %d %d' % (totgas, compustate.gas)) - jumped = False - - compustate.gas -= totgas - compustate.pc = nextpos - - - # Invalid operation; can only come at the end of a chunk - if ops[-1][0] == 'INVALID': - return vm_exception('INVALID OP', opcode=ops[-1][1]) - - for op, opcode, pushval in ops: - - if trace_vm: - """ - This diverges from normal logging, as we use the logging namespace - only to decide which features get logged in 'eth.vm.op' - i.e. tracing can not be activated by activating a sub - like 'eth.vm.op.stack' - """ - trace_data = {} - trace_data['stack'] = list(map(to_string, list(compustate.stack))) - if _prevop in ('MLOAD', 'MSTORE', 'MSTORE8', 'SHA3', 'CALL', - 'CALLCODE', 'CREATE', 'CALLDATACOPY', 'CODECOPY', - 'EXTCODECOPY'): - if len(compustate.memory) < 1024: - trace_data['memory'] = \ - ''.join([encode_hex(ascii_chr(x)) for x - in compustate.memory]) - else: - trace_data['sha3memory'] = \ - encode_hex(utils.sha3(b''.join([ascii_chr(x) for - x in compustate.memory]))) - if _prevop in ('SSTORE',) or steps == 0: - trace_data['storage'] = ext.log_storage(msg.to) - trace_data['gas'] = to_string(compustate.gas + totgas) - trace_data['inst'] = opcode - trace_data['pc'] = to_string(compustate.pc - 1) - if steps == 0: + ops, minstack, maxstack, totgas, nextpos = processed_code[compustate.pc] + + if len(compustate.stack) < minstack: + return vm_exception('INSUFFICIENT STACK') + if len(compustate.stack) > maxstack: + return vm_exception('STACK SIZE LIMIT EXCEEDED') + if totgas > compustate.gas: + return vm_exception('OUT OF GAS %d %d' % (totgas, compustate.gas)) + jumped = False + + compustate.gas -= totgas + compustate.pc = nextpos + + # Invalid operation; can only come at the end of a chunk + if ops[-1][0] == 'INVALID': + return vm_exception('INVALID OP', opcode=ops[-1][1]) + + for op, opcode, pushval in ops: + + if trace_vm: + """ + This diverges from normal logging, as we use the logging namespace + only to decide which features get logged in 'eth.vm.op' + i.e. tracing can not be activated by activating a sub + like 'eth.vm.op.stack' + """ + trace_data = {} + trace_data['stack'] = list( + map(to_string, list(compustate.stack))) + if _prevop in ('MLOAD', 'MSTORE', 'MSTORE8', 'SHA3', 'CALL', + 'CALLCODE', 'CREATE', 'CALLDATACOPY', 'CODECOPY', + 'EXTCODECOPY'): + if len(compustate.memory) < 1024: + trace_data['memory'] = \ + ''.join([encode_hex(ascii_chr(x)) for x + in compustate.memory]) + else: + trace_data['sha3memory'] = \ + encode_hex(utils.sha3(b''.join([ascii_chr(x) for + x in compustate.memory]))) + if _prevop in ('SSTORE',) or steps == 0: + trace_data['storage'] = ext.log_storage(msg.to) + trace_data['gas'] = to_string(compustate.gas + totgas) + trace_data['inst'] = opcode + trace_data['pc'] = to_string(compustate.pc - 1) + if steps == 0: + trace_data['depth'] = msg.depth + trace_data['address'] = msg.to + trace_data['steps'] = steps trace_data['depth'] = msg.depth - trace_data['address'] = msg.to - trace_data['steps'] = steps - trace_data['depth'] = msg.depth - if op[:4] == 'PUSH': - trace_data['pushvalue'] = pushval - log_vm_op.trace('vm', op=op, **trace_data) - steps += 1 - _prevop = op - - # Valid operations - # Pushes first because they are very frequent - if 0x60 <= opcode <= 0x7f: - # compustate.pc += opcode - 0x5f # Move 1 byte forward for 0x60, up to 32 bytes for 0x7f - stk.append(pushval) - elif opcode < 0x10: - if op == 'STOP': - return peaceful_exit('STOP', compustate.gas, []) - elif op == 'ADD': - stk.append((stk.pop() + stk.pop()) & TT256M1) - elif op == 'SUB': - stk.append((stk.pop() - stk.pop()) & TT256M1) - elif op == 'MUL': - stk.append((stk.pop() * stk.pop()) & TT256M1) - elif op == 'DIV': - s0, s1 = stk.pop(), stk.pop() - stk.append(0 if s1 == 0 else s0 // s1) - elif op == 'MOD': - s0, s1 = stk.pop(), stk.pop() - stk.append(0 if s1 == 0 else s0 % s1) - elif op == 'SDIV': - s0, s1 = utils.to_signed(stk.pop()), utils.to_signed(stk.pop()) - stk.append(0 if s1 == 0 else (abs(s0) // abs(s1) * - (-1 if s0 * s1 < 0 else 1)) & TT256M1) - elif op == 'SMOD': - s0, s1 = utils.to_signed(stk.pop()), utils.to_signed(stk.pop()) - stk.append(0 if s1 == 0 else (abs(s0) % abs(s1) * - (-1 if s0 < 0 else 1)) & TT256M1) - elif op == 'ADDMOD': - s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() - stk.append((s0 + s1) % s2 if s2 else 0) - elif op == 'MULMOD': - s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() - stk.append((s0 * s1) % s2 if s2 else 0) - elif op == 'EXP': - base, exponent = stk.pop(), stk.pop() - # fee for exponent is dependent on its bytes - # calc n bytes to represent exponent - nbytes = len(utils.encode_int(exponent)) - expfee = nbytes * opcodes.GEXPONENTBYTE - if ext.post_clearing_hardfork(): - expfee += opcodes.EXP_SUPPLEMENTAL_GAS * nbytes - if compustate.gas < expfee: - compustate.gas = 0 - return vm_exception('OOG EXPONENT') - compustate.gas -= expfee - stk.append(pow(base, exponent, TT256)) - elif op == 'SIGNEXTEND': - s0, s1 = stk.pop(), stk.pop() - if s0 <= 31: - testbit = s0 * 8 + 7 - if s1 & (1 << testbit): - stk.append(s1 | (TT256 - (1 << testbit))) + if op[:4] == 'PUSH': + trace_data['pushvalue'] = pushval + log_vm_op.trace('vm', op=op, **trace_data) + steps += 1 + _prevop = op + + # Valid operations + # Pushes first because they are very frequent + if 0x60 <= opcode <= 0x7f: + # compustate.pc += opcode - 0x5f # Move 1 byte forward for + # 0x60, up to 32 bytes for 0x7f + stk.append(pushval) + elif opcode < 0x10: + if op == 'STOP': + return peaceful_exit('STOP', compustate.gas, []) + elif op == 'ADD': + stk.append((stk.pop() + stk.pop()) & TT256M1) + elif op == 'SUB': + stk.append((stk.pop() - stk.pop()) & TT256M1) + elif op == 'MUL': + stk.append((stk.pop() * stk.pop()) & TT256M1) + elif op == 'DIV': + s0, s1 = stk.pop(), stk.pop() + stk.append(0 if s1 == 0 else s0 // s1) + elif op == 'MOD': + s0, s1 = stk.pop(), stk.pop() + stk.append(0 if s1 == 0 else s0 % s1) + elif op == 'SDIV': + s0, s1 = utils.to_signed( + stk.pop()), utils.to_signed( + stk.pop()) + stk.append(0 if s1 == 0 else (abs(s0) // abs(s1) * + (-1 if s0 * s1 < 0 else 1)) & TT256M1) + elif op == 'SMOD': + s0, s1 = utils.to_signed( + stk.pop()), utils.to_signed( + stk.pop()) + stk.append(0 if s1 == 0 else (abs(s0) % abs(s1) * + (-1 if s0 < 0 else 1)) & TT256M1) + elif op == 'ADDMOD': + s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() + stk.append((s0 + s1) % s2 if s2 else 0) + elif op == 'MULMOD': + s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() + stk.append((s0 * s1) % s2 if s2 else 0) + elif op == 'EXP': + base, exponent = stk.pop(), stk.pop() + # fee for exponent is dependent on its bytes + # calc n bytes to represent exponent + nbytes = len(utils.encode_int(exponent)) + expfee = nbytes * opcodes.GEXPONENTBYTE + if ext.post_clearing_hardfork(): + expfee += opcodes.EXP_SUPPLEMENTAL_GAS * nbytes + if compustate.gas < expfee: + compustate.gas = 0 + return vm_exception('OOG EXPONENT') + compustate.gas -= expfee + stk.append(pow(base, exponent, TT256)) + elif op == 'SIGNEXTEND': + s0, s1 = stk.pop(), stk.pop() + if s0 <= 31: + testbit = s0 * 8 + 7 + if s1 & (1 << testbit): + stk.append(s1 | (TT256 - (1 << testbit))) + else: + stk.append(s1 & ((1 << testbit) - 1)) + else: + stk.append(s1) + elif opcode < 0x20: + if op == 'LT': + stk.append(1 if stk.pop() < stk.pop() else 0) + elif op == 'GT': + stk.append(1 if stk.pop() > stk.pop() else 0) + elif op == 'SLT': + s0, s1 = utils.to_signed( + stk.pop()), utils.to_signed( + stk.pop()) + stk.append(1 if s0 < s1 else 0) + elif op == 'SGT': + s0, s1 = utils.to_signed( + stk.pop()), utils.to_signed( + stk.pop()) + stk.append(1 if s0 > s1 else 0) + elif op == 'EQ': + stk.append(1 if stk.pop() == stk.pop() else 0) + elif op == 'ISZERO': + stk.append(0 if stk.pop() else 1) + elif op == 'AND': + stk.append(stk.pop() & stk.pop()) + elif op == 'OR': + stk.append(stk.pop() | stk.pop()) + elif op == 'XOR': + stk.append(stk.pop() ^ stk.pop()) + elif op == 'NOT': + stk.append(TT256M1 - stk.pop()) + elif op == 'BYTE': + s0, s1 = stk.pop(), stk.pop() + if s0 >= 32: + stk.append(0) + else: + stk.append((s1 // 256 ** (31 - s0)) % 256) + elif opcode < 0x40: + if op == 'SHA3': + s0, s1 = stk.pop(), stk.pop() + compustate.gas -= opcodes.GSHA3WORD * \ + (utils.ceil32(s1) // 32) + if compustate.gas < 0: + return vm_exception('OOG PAYING FOR SHA3') + if not mem_extend(mem, compustate, op, s0, s1): + return vm_exception('OOG EXTENDING MEMORY') + data = bytearray_to_bytestr(mem[s0: s0 + s1]) + stk.append(utils.big_endian_to_int(utils.sha3(data))) + elif op == 'ADDRESS': + stk.append(utils.coerce_to_int(msg.to)) + elif op == 'BALANCE': + if ext.post_anti_dos_hardfork(): + if not eat_gas(compustate, + opcodes.BALANCE_SUPPLEMENTAL_GAS): + return vm_exception("OUT OF GAS") + addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) + stk.append(ext.get_balance(addr)) + elif op == 'ORIGIN': + stk.append(utils.coerce_to_int(ext.tx_origin)) + elif op == 'CALLER': + stk.append(utils.coerce_to_int(msg.sender)) + elif op == 'CALLVALUE': + stk.append(msg.value) + elif op == 'CALLDATALOAD': + stk.append(msg.data.extract32(stk.pop())) + elif op == 'CALLDATASIZE': + stk.append(msg.data.size) + elif op == 'CALLDATACOPY': + mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() + if not mem_extend(mem, compustate, op, mstart, size): + return vm_exception('OOG EXTENDING MEMORY') + if not data_copy(compustate, size): + return vm_exception('OOG COPY DATA') + msg.data.extract_copy(mem, mstart, dstart, size) + elif op == 'CODESIZE': + stk.append(len(code)) + elif op == 'CODECOPY': + mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() + if not mem_extend(mem, compustate, op, mstart, size): + return vm_exception('OOG EXTENDING MEMORY') + if not data_copy(compustate, size): + return vm_exception('OOG COPY DATA') + for i in range(size): + if dstart + i < len(code): + mem[mstart + i] = utils.safe_ord(code[dstart + i]) + else: + mem[mstart + i] = 0 + elif op == 'RETURNDATACOPY': + mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() + if not mem_extend(mem, compustate, op, mstart, size): + return vm_exception('OOG EXTENDING MEMORY') + if not data_copy(compustate, size): + return vm_exception('OOG COPY DATA') + if dstart + size > len(compustate.last_returned): + return vm_exception('RETURNDATACOPY out of range') + mem[mstart: mstart + size] = compustate.last_returned + elif op == 'RETURNDATASIZE': + stk.append(len(compustate.last_returned)) + elif op == 'GASPRICE': + stk.append(ext.tx_gasprice) + elif op == 'EXTCODESIZE': + if ext.post_anti_dos_hardfork(): + if not eat_gas(compustate, + opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS): + return vm_exception("OUT OF GAS") + addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) + stk.append(len(ext.get_code(addr) or b'')) + elif op == 'EXTCODECOPY': + if ext.post_anti_dos_hardfork(): + if not eat_gas(compustate, + opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS): + return vm_exception("OUT OF GAS") + addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) + start, s2, size = stk.pop(), stk.pop(), stk.pop() + extcode = ext.get_code(addr) or b'' + assert utils.is_string(extcode) + if not mem_extend(mem, compustate, op, start, size): + return vm_exception('OOG EXTENDING MEMORY') + if not data_copy(compustate, size): + return vm_exception('OOG COPY DATA') + for i in range(size): + if s2 + i < len(extcode): + mem[start + i] = utils.safe_ord(extcode[s2 + i]) + else: + mem[start + i] = 0 + elif opcode < 0x50: + if op == 'BLOCKHASH': + if ext.post_metropolis_hardfork() and False: + bh_addr = ext.blockhash_store + stk.append(ext.get_storage_data(bh_addr, stk.pop())) + else: + stk.append( + utils.big_endian_to_int( + ext.block_hash( + stk.pop()))) + elif op == 'COINBASE': + stk.append(utils.big_endian_to_int(ext.block_coinbase)) + elif op == 'TIMESTAMP': + stk.append(ext.block_timestamp) + elif op == 'NUMBER': + stk.append(ext.block_number) + elif op == 'DIFFICULTY': + stk.append(ext.block_difficulty) + elif op == 'GASLIMIT': + stk.append(ext.block_gas_limit) + elif opcode < 0x60: + if op == 'POP': + stk.pop() + elif op == 'MLOAD': + s0 = stk.pop() + if not mem_extend(mem, compustate, op, s0, 32): + return vm_exception('OOG EXTENDING MEMORY') + stk.append(utils.bytes_to_int(mem[s0: s0 + 32])) + elif op == 'MSTORE': + s0, s1 = stk.pop(), stk.pop() + if not mem_extend(mem, compustate, op, s0, 32): + return vm_exception('OOG EXTENDING MEMORY') + mem[s0: s0 + 32] = utils.encode_int32(s1) + elif op == 'MSTORE8': + s0, s1 = stk.pop(), stk.pop() + if not mem_extend(mem, compustate, op, s0, 1): + return vm_exception('OOG EXTENDING MEMORY') + mem[s0] = s1 % 256 + elif op == 'SLOAD': + if ext.post_anti_dos_hardfork(): + if not eat_gas(compustate, + opcodes.SLOAD_SUPPLEMENTAL_GAS): + return vm_exception("OUT OF GAS") + stk.append(ext.get_storage_data(msg.to, stk.pop())) + elif op == 'SSTORE': + s0, s1 = stk.pop(), stk.pop() + if msg.static: + return vm_exception( + 'Cannot SSTORE inside a static context') + if ext.get_storage_data(msg.to, s0): + gascost = opcodes.GSTORAGEMOD if s1 else opcodes.GSTORAGEKILL + refund = 0 if s1 else opcodes.GSTORAGEREFUND + else: + gascost = opcodes.GSTORAGEADD if s1 else opcodes.GSTORAGEMOD + refund = 0 + if compustate.gas < gascost: + return vm_exception('OUT OF GAS') + compustate.gas -= gascost + # adds neg gascost as a refund if below zero + ext.add_refund(refund) + ext.set_storage_data(msg.to, s0, s1) + elif op == 'JUMP': + compustate.pc = stk.pop() + opnew = code[compustate.pc] if compustate.pc < codelen else 0 + jumped = True + if opnew != JUMPDEST: + return vm_exception('BAD JUMPDEST') + elif op == 'JUMPI': + s0, s1 = stk.pop(), stk.pop() + if s1: + compustate.pc = s0 + opnew = code[compustate.pc] if compustate.pc < codelen else 0 + jumped = True + if opnew != JUMPDEST: + return vm_exception('BAD JUMPDEST') + elif op == 'PC': + stk.append(compustate.pc - 1) + elif op == 'MSIZE': + stk.append(len(mem)) + elif op == 'GAS': + stk.append(compustate.gas) # AFTER subtracting cost 1 + elif op[:3] == 'DUP': + # 0x7f - opcode is a negative number, -1 for 0x80 ... -16 for + # 0x8f + stk.append(stk[0x7f - opcode]) + elif op[:4] == 'SWAP': + # 0x8e - opcode is a negative number, -2 for 0x90 ... -17 for + # 0x9f + temp = stk[0x8e - opcode] + stk[0x8e - opcode] = stk[-1] + stk[-1] = temp + + elif op[:3] == 'LOG': + """ + 0xa0 ... 0xa4, 32/64/96/128/160 + len(data) gas + a. Opcodes LOG0...LOG4 are added, takes 2-6 stack arguments + MEMSTART MEMSZ (TOPIC1) (TOPIC2) (TOPIC3) (TOPIC4) + b. Logs are kept track of during tx execution exactly the same way as suicides + (except as an ordered list, not a set). + Each log is in the form [address, [topic1, ... ], data] where: + * address is what the ADDRESS opcode would output + * data is mem[MEMSTART: MEMSTART + MEMSZ] + * topics are as provided by the opcode + c. The ordered list of logs in the transaction are expressed as [log0, log1, ..., logN]. + """ + depth = int(op[3:]) + mstart, msz = stk.pop(), stk.pop() + topics = [stk.pop() for x in range(depth)] + compustate.gas -= msz * opcodes.GLOGBYTE + if msg.static: + return vm_exception('Cannot LOG inside a static context') + if not mem_extend(mem, compustate, op, mstart, msz): + return vm_exception('OOG EXTENDING MEMORY') + data = bytearray_to_bytestr(mem[mstart: mstart + msz]) + ext.log(msg.to, topics, data) + log_log.trace('LOG', to=msg.to, topics=topics, + data=list(map(utils.safe_ord, data))) + # print('LOG', msg.to, topics, list(map(ord, data))) + + elif op == 'CREATE': + value, mstart, msz = stk.pop(), stk.pop(), stk.pop() + if not mem_extend(mem, compustate, op, mstart, msz): + return vm_exception('OOG EXTENDING MEMORY') + if msg.static: + return vm_exception( + 'Cannot CREATE inside a static context') + if ext.get_balance(msg.to) >= value and msg.depth < MAX_DEPTH: + cd = CallData(mem, mstart, msz) + ingas = compustate.gas + if ext.post_anti_dos_hardfork(): + ingas = all_but_1n( + ingas, opcodes.CALL_CHILD_LIMIT_DENOM) + create_msg = Message( + msg.to, b'', value, ingas, cd, msg.depth + 1) + o, gas, addr = ext.create(create_msg) + if o: + stk.append(utils.coerce_to_int(addr)) else: - stk.append(s1 & ((1 << testbit) - 1)) + stk.append(0) + compustate.gas = compustate.gas - ingas + gas else: - stk.append(s1) - elif opcode < 0x20: - if op == 'LT': - stk.append(1 if stk.pop() < stk.pop() else 0) - elif op == 'GT': - stk.append(1 if stk.pop() > stk.pop() else 0) - elif op == 'SLT': - s0, s1 = utils.to_signed(stk.pop()), utils.to_signed(stk.pop()) - stk.append(1 if s0 < s1 else 0) - elif op == 'SGT': - s0, s1 = utils.to_signed(stk.pop()), utils.to_signed(stk.pop()) - stk.append(1 if s0 > s1 else 0) - elif op == 'EQ': - stk.append(1 if stk.pop() == stk.pop() else 0) - elif op == 'ISZERO': - stk.append(0 if stk.pop() else 1) - elif op == 'AND': - stk.append(stk.pop() & stk.pop()) - elif op == 'OR': - stk.append(stk.pop() | stk.pop()) - elif op == 'XOR': - stk.append(stk.pop() ^ stk.pop()) - elif op == 'NOT': - stk.append(TT256M1 - stk.pop()) - elif op == 'BYTE': - s0, s1 = stk.pop(), stk.pop() - if s0 >= 32: stk.append(0) + elif op in ('CALL', 'CALLCODE', 'DELEGATECALL', 'STATICCALL'): + # Pull arguments from the stack + if op in ('CALL', 'CALLCODE'): + gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ + stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() else: - stk.append((s1 // 256 ** (31 - s0)) % 256) - elif opcode < 0x40: - if op == 'SHA3': - s0, s1 = stk.pop(), stk.pop() - compustate.gas -= opcodes.GSHA3WORD * (utils.ceil32(s1) // 32) - if compustate.gas < 0: - return vm_exception('OOG PAYING FOR SHA3') - if not mem_extend(mem, compustate, op, s0, s1): + gas, to, meminstart, meminsz, memoutstart, memoutsz = \ + stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() + value = 0 + # Static context prohibition + if msg.static and value > 0: + return vm_exception( + 'Cannot make a non-zero-value call inside a static context') + # Expand memory + if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ + not mem_extend(mem, compustate, op, memoutstart, memoutsz): return vm_exception('OOG EXTENDING MEMORY') - data = bytearray_to_bytestr(mem[s0: s0 + s1]) - stk.append(utils.big_endian_to_int(utils.sha3(data))) - elif op == 'ADDRESS': - stk.append(utils.coerce_to_int(msg.to)) - elif op == 'BALANCE': + to = utils.int_to_addr(to) + # Extra gas costs based on hard fork-dependent factors + extra_gas = (not ext.account_exists(to)) * (op == 'CALL') * (value > 0 or not ext.post_clearing_hardfork()) * opcodes.GCALLNEWACCOUNT + \ + (value > 0) * opcodes.GCALLVALUETRANSFER + \ + ext.post_anti_dos_hardfork() * opcodes.CALL_SUPPLEMENTAL_GAS + # Compute child gas limit if ext.post_anti_dos_hardfork(): - if not eat_gas(compustate, opcodes.BALANCE_SUPPLEMENTAL_GAS): - return vm_exception("OUT OF GAS") - addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) - stk.append(ext.get_balance(addr)) - elif op == 'ORIGIN': - stk.append(utils.coerce_to_int(ext.tx_origin)) - elif op == 'CALLER': - stk.append(utils.coerce_to_int(msg.sender)) - elif op == 'CALLVALUE': - stk.append(msg.value) - elif op == 'CALLDATALOAD': - stk.append(msg.data.extract32(stk.pop())) - elif op == 'CALLDATASIZE': - stk.append(msg.data.size) - elif op == 'CALLDATACOPY': - mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, mstart, size): - return vm_exception('OOG EXTENDING MEMORY') - if not data_copy(compustate, size): - return vm_exception('OOG COPY DATA') - msg.data.extract_copy(mem, mstart, dstart, size) - elif op == 'CODESIZE': - stk.append(len(code)) - elif op == 'CODECOPY': - mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, mstart, size): - return vm_exception('OOG EXTENDING MEMORY') - if not data_copy(compustate, size): - return vm_exception('OOG COPY DATA') - for i in range(size): - if dstart + i < len(code): - mem[mstart + i] = utils.safe_ord(code[dstart + i]) + if compustate.gas < extra_gas: + return vm_exception('OUT OF GAS', needed=extra_gas) + gas = min( + gas, + all_but_1n( + compustate.gas - + extra_gas, + opcodes.CALL_CHILD_LIMIT_DENOM)) + else: + if compustate.gas < gas + extra_gas: + return vm_exception( + 'OUT OF GAS', needed=gas + extra_gas) + submsg_gas = gas + opcodes.GSTIPEND * (value > 0) + # Verify that there is sufficient balance and depth + if ext.get_balance(msg.to) < value or msg.depth >= MAX_DEPTH: + compustate.gas -= (gas + extra_gas - submsg_gas) + stk.append(0) + else: + # Subtract gas from parent + compustate.gas -= (gas + extra_gas) + assert compustate.gas >= 0 + cd = CallData(mem, meminstart, meminsz) + # Generate the message + if op == 'CALL': + call_msg = Message(msg.to, to, value, submsg_gas, cd, + msg.depth + 1, code_address=to, static=msg.static) + elif ext.post_homestead_hardfork() and op == 'DELEGATECALL': + call_msg = Message(msg.sender, msg.to, msg.value, submsg_gas, cd, + msg.depth + 1, code_address=to, transfers_value=False, static=msg.static) + elif op == 'DELEGATECALL': + return vm_exception('OPCODE INACTIVE') + elif op == 'CALLCODE': + call_msg = Message(msg.to, msg.to, value, submsg_gas, cd, + msg.depth + 1, code_address=to, static=msg.static) + elif op == 'STATICCALL': + call_msg = Message(msg.to, to, value, submsg_gas, cd, + msg.depth + 1, code_address=to, static=True) else: - mem[mstart + i] = 0 - elif op == 'RETURNDATACOPY': - mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, mstart, size): - return vm_exception('OOG EXTENDING MEMORY') - if not data_copy(compustate, size): - return vm_exception('OOG COPY DATA') - if dstart + size > len(compustate.last_returned): - return vm_exception('RETURNDATACOPY out of range') - mem[mstart: mstart + size] = compustate.last_returned - elif op == 'RETURNDATASIZE': - stk.append(len(compustate.last_returned)) - elif op == 'GASPRICE': - stk.append(ext.tx_gasprice) - elif op == 'EXTCODESIZE': - if ext.post_anti_dos_hardfork(): - if not eat_gas(compustate, opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS): - return vm_exception("OUT OF GAS") - addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) - stk.append(len(ext.get_code(addr) or b'')) - elif op == 'EXTCODECOPY': - if ext.post_anti_dos_hardfork(): - if not eat_gas(compustate, opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS): - return vm_exception("OUT OF GAS") - addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) - start, s2, size = stk.pop(), stk.pop(), stk.pop() - extcode = ext.get_code(addr) or b'' - assert utils.is_string(extcode) - if not mem_extend(mem, compustate, op, start, size): - return vm_exception('OOG EXTENDING MEMORY') - if not data_copy(compustate, size): - return vm_exception('OOG COPY DATA') - for i in range(size): - if s2 + i < len(extcode): - mem[start + i] = utils.safe_ord(extcode[s2 + i]) + raise Exception("Lolwut") + # Get result + result, gas, data = ext.msg(call_msg) + if result == 0: + stk.append(0) else: - mem[start + i] = 0 - elif opcode < 0x50: - if op == 'BLOCKHASH': - if ext.post_metropolis_hardfork() and False: - bh_addr = ext.blockhash_store - stk.append(ext.get_storage_data(bh_addr, stk.pop())) - else: - stk.append(utils.big_endian_to_int(ext.block_hash(stk.pop()))) - elif op == 'COINBASE': - stk.append(utils.big_endian_to_int(ext.block_coinbase)) - elif op == 'TIMESTAMP': - stk.append(ext.block_timestamp) - elif op == 'NUMBER': - stk.append(ext.block_number) - elif op == 'DIFFICULTY': - stk.append(ext.block_difficulty) - elif op == 'GASLIMIT': - stk.append(ext.block_gas_limit) - elif opcode < 0x60: - if op == 'POP': - stk.pop() - elif op == 'MLOAD': - s0 = stk.pop() - if not mem_extend(mem, compustate, op, s0, 32): - return vm_exception('OOG EXTENDING MEMORY') - stk.append(utils.bytes_to_int(mem[s0: s0 + 32])) - elif op == 'MSTORE': + stk.append(1) + # Set output memory + for i in range(min(len(data), memoutsz)): + mem[memoutstart + i] = data[i] + compustate.gas += gas + compustate.last_returned = bytearray(data) + elif op == 'RETURN': s0, s1 = stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, s0, 32): + if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') - mem[s0: s0 + 32] = utils.encode_int32(s1) - elif op == 'MSTORE8': + return peaceful_exit( + 'RETURN', compustate.gas, mem[s0: s0 + s1]) + elif op == 'REVERT': + if not ext.post_metropolis_hardfork(): + return vm_exception('Opcode not yet enabled') s0, s1 = stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, s0, 1): + if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') - mem[s0] = s1 % 256 - elif op == 'SLOAD': - if ext.post_anti_dos_hardfork(): - if not eat_gas(compustate, opcodes.SLOAD_SUPPLEMENTAL_GAS): - return vm_exception("OUT OF GAS") - stk.append(ext.get_storage_data(msg.to, stk.pop())) - elif op == 'SSTORE': - s0, s1 = stk.pop(), stk.pop() + return revert(compustate.gas, mem[s0: s0 + s1]) + elif op == 'SUICIDE': if msg.static: - return vm_exception('Cannot SSTORE inside a static context') - if ext.get_storage_data(msg.to, s0): - gascost = opcodes.GSTORAGEMOD if s1 else opcodes.GSTORAGEKILL - refund = 0 if s1 else opcodes.GSTORAGEREFUND - else: - gascost = opcodes.GSTORAGEADD if s1 else opcodes.GSTORAGEMOD - refund = 0 - if compustate.gas < gascost: - return vm_exception('OUT OF GAS') - compustate.gas -= gascost - ext.add_refund(refund) # adds neg gascost as a refund if below zero - ext.set_storage_data(msg.to, s0, s1) - elif op == 'JUMP': - compustate.pc = stk.pop() - opnew = code[compustate.pc] if compustate.pc < codelen else 0 - jumped = True - if opnew != JUMPDEST: - return vm_exception('BAD JUMPDEST') - elif op == 'JUMPI': - s0, s1 = stk.pop(), stk.pop() - if s1: - compustate.pc = s0 - opnew = code[compustate.pc] if compustate.pc < codelen else 0 - jumped = True - if opnew != JUMPDEST: - return vm_exception('BAD JUMPDEST') - elif op == 'PC': - stk.append(compustate.pc - 1) - elif op == 'MSIZE': - stk.append(len(mem)) - elif op == 'GAS': - stk.append(compustate.gas) # AFTER subtracting cost 1 - elif op[:3] == 'DUP': - stk.append(stk[0x7f - opcode]) # 0x7f - opcode is a negative number, -1 for 0x80 ... -16 for 0x8f - elif op[:4] == 'SWAP': - temp = stk[0x8e - opcode] # 0x8e - opcode is a negative number, -2 for 0x90 ... -17 for 0x9f - stk[0x8e - opcode] = stk[-1] - stk[-1] = temp - - elif op[:3] == 'LOG': - """ - 0xa0 ... 0xa4, 32/64/96/128/160 + len(data) gas - a. Opcodes LOG0...LOG4 are added, takes 2-6 stack arguments - MEMSTART MEMSZ (TOPIC1) (TOPIC2) (TOPIC3) (TOPIC4) - b. Logs are kept track of during tx execution exactly the same way as suicides - (except as an ordered list, not a set). - Each log is in the form [address, [topic1, ... ], data] where: - * address is what the ADDRESS opcode would output - * data is mem[MEMSTART: MEMSTART + MEMSZ] - * topics are as provided by the opcode - c. The ordered list of logs in the transaction are expressed as [log0, log1, ..., logN]. - """ - depth = int(op[3:]) - mstart, msz = stk.pop(), stk.pop() - topics = [stk.pop() for x in range(depth)] - compustate.gas -= msz * opcodes.GLOGBYTE - if msg.static: - return vm_exception('Cannot LOG inside a static context') - if not mem_extend(mem, compustate, op, mstart, msz): - return vm_exception('OOG EXTENDING MEMORY') - data = bytearray_to_bytestr(mem[mstart: mstart + msz]) - ext.log(msg.to, topics, data) - log_log.trace('LOG', to=msg.to, topics=topics, data=list(map(utils.safe_ord, data))) - # print('LOG', msg.to, topics, list(map(ord, data))) - - elif op == 'CREATE': - value, mstart, msz = stk.pop(), stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, mstart, msz): - return vm_exception('OOG EXTENDING MEMORY') - if msg.static: - return vm_exception('Cannot CREATE inside a static context') - if ext.get_balance(msg.to) >= value and msg.depth < MAX_DEPTH: - cd = CallData(mem, mstart, msz) - ingas = compustate.gas + return vm_exception( + 'Cannot SUICIDE inside a static context') + to = utils.encode_int(stk.pop()) + to = ((b'\x00' * (32 - len(to))) + to)[12:] + xfer = ext.get_balance(msg.to) if ext.post_anti_dos_hardfork(): - ingas = all_but_1n(ingas, opcodes.CALL_CHILD_LIMIT_DENOM) - create_msg = Message(msg.to, b'', value, ingas, cd, msg.depth + 1) - o, gas, addr = ext.create(create_msg) - if o: - stk.append(utils.coerce_to_int(addr)) - else: - stk.append(0) - compustate.gas = compustate.gas - ingas + gas - else: - stk.append(0) - elif op in ('CALL', 'CALLCODE', 'DELEGATECALL', 'STATICCALL'): - # Pull arguments from the stack - if op in ('CALL', 'CALLCODE'): - gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ - stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() - else: - gas, to, meminstart, meminsz, memoutstart, memoutsz = \ - stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() - value = 0 - # Static context prohibition - if msg.static and value > 0: - return vm_exception('Cannot make a non-zero-value call inside a static context') - # Expand memory - if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ - not mem_extend(mem, compustate, op, memoutstart, memoutsz): - return vm_exception('OOG EXTENDING MEMORY') - to = utils.int_to_addr(to) - # Extra gas costs based on hard fork-dependent factors - extra_gas = (not ext.account_exists(to)) * (op == 'CALL') * (value > 0 or not ext.post_clearing_hardfork()) * opcodes.GCALLNEWACCOUNT + \ - (value > 0) * opcodes.GCALLVALUETRANSFER + \ - ext.post_anti_dos_hardfork() * opcodes.CALL_SUPPLEMENTAL_GAS - # Compute child gas limit - if ext.post_anti_dos_hardfork(): - if compustate.gas < extra_gas: - return vm_exception('OUT OF GAS', needed=extra_gas) - gas = min(gas, all_but_1n(compustate.gas - extra_gas, opcodes.CALL_CHILD_LIMIT_DENOM)) - else: - if compustate.gas < gas + extra_gas: - return vm_exception('OUT OF GAS', needed=gas+extra_gas) - submsg_gas = gas + opcodes.GSTIPEND * (value > 0) - # Verify that there is sufficient balance and depth - if ext.get_balance(msg.to) < value or msg.depth >= MAX_DEPTH: - compustate.gas -= (gas + extra_gas - submsg_gas) - stk.append(0) - else: - # Subtract gas from parent - compustate.gas -= (gas + extra_gas) - assert compustate.gas >= 0 - cd = CallData(mem, meminstart, meminsz) - # Generate the message - if op == 'CALL': - call_msg = Message(msg.to, to, value, submsg_gas, cd, - msg.depth + 1, code_address=to, static=msg.static) - elif ext.post_homestead_hardfork() and op == 'DELEGATECALL': - call_msg = Message(msg.sender, msg.to, msg.value, submsg_gas, cd, - msg.depth + 1, code_address=to, transfers_value=False, static=msg.static) - elif op == 'DELEGATECALL': - return vm_exception('OPCODE INACTIVE') - elif op == 'CALLCODE': - call_msg = Message(msg.to, msg.to, value, submsg_gas, cd, - msg.depth + 1, code_address=to, static=msg.static) - elif op == 'STATICCALL': - call_msg = Message(msg.to, to, value, submsg_gas, cd, - msg.depth + 1, code_address=to, static=True) - else: - raise Exception("Lolwut") - # Get result - result, gas, data = ext.msg(call_msg) - if result == 0: - stk.append(0) - else: - stk.append(1) - # Set output memory - for i in range(min(len(data), memoutsz)): - mem[memoutstart + i] = data[i] - compustate.gas += gas - compustate.last_returned = bytearray(data) - elif op == 'RETURN': - s0, s1 = stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, s0, s1): - return vm_exception('OOG EXTENDING MEMORY') - return peaceful_exit('RETURN', compustate.gas, mem[s0: s0 + s1]) - elif op == 'REVERT': - if not ext.post_metropolis_hardfork(): - return vm_exception('Opcode not yet enabled') - s0, s1 = stk.pop(), stk.pop() - if not mem_extend(mem, compustate, op, s0, s1): - return vm_exception('OOG EXTENDING MEMORY') - return revert(compustate.gas, mem[s0: s0 + s1]) - elif op == 'SUICIDE': - if msg.static: - return vm_exception('Cannot SUICIDE inside a static context') - to = utils.encode_int(stk.pop()) - to = ((b'\x00' * (32 - len(to))) + to)[12:] - xfer = ext.get_balance(msg.to) - if ext.post_anti_dos_hardfork(): - extra_gas = opcodes.SUICIDE_SUPPLEMENTAL_GAS + \ - (not ext.account_exists(to)) * (xfer > 0 or not ext.post_clearing_hardfork()) * opcodes.GCALLNEWACCOUNT - if not eat_gas(compustate, extra_gas): - return vm_exception("OUT OF GAS") - ext.set_balance(to, ext.get_balance(to) + xfer) - ext.set_balance(msg.to, 0) - ext.add_suicide(msg.to) - log_msg.debug('SUICIDING', addr=utils.checksum_encode(msg.to), to=utils.checksum_encode(to), xferring=xfer) - return 1, compustate.gas, [] - - # assert utils.is_numeric(compustate.gas) - # this is slow! - # for a in stk: - # assert is_numeric(a), (op, stk) - # assert a >= 0 and a < 2**256, (a, op, stk) - #if not jumped: - # assert compustate.pc == nextpos - # compustate.pc = nextpos + extra_gas = opcodes.SUICIDE_SUPPLEMENTAL_GAS + \ + (not ext.account_exists( + to)) * (xfer > 0 or not ext.post_clearing_hardfork()) * opcodes.GCALLNEWACCOUNT + if not eat_gas(compustate, extra_gas): + return vm_exception("OUT OF GAS") + ext.set_balance(to, ext.get_balance(to) + xfer) + ext.set_balance(msg.to, 0) + ext.add_suicide(msg.to) + log_msg.debug( + 'SUICIDING', + addr=utils.checksum_encode( + msg.to), + to=utils.checksum_encode(to), + xferring=xfer) + return 1, compustate.gas, [] + + # assert utils.is_numeric(compustate.gas) + # this is slow! + # for a in stk: + # assert is_numeric(a), (op, stk) + # assert a >= 0 and a < 2**256, (a, op, stk) + # if not jumped: + # assert compustate.pc == nextpos + # compustate.pc = nextpos if compustate.pc >= codelen: return peaceful_exit('CODE OUT OF RANGE', compustate.gas, []) return vm_exception('INVALID JUMP') diff --git a/ethereum/full_casper/casper_utils.py b/ethereum/full_casper/casper_utils.py index 12dcee643..dfed85fb2 100644 --- a/ethereum/full_casper/casper_utils.py +++ b/ethereum/full_casper/casper_utils.py @@ -28,44 +28,55 @@ def get_contract_code(init_code): s = State(env=Env(config=casper_config)) s.gas_limit = 10**9 apply_transaction(s, Transaction(0, 0, 10**8, '', 0, init_code)) - addr = utils.mk_metropolis_contract_address(casper_config['METROPOLIS_ENTRY_POINT'], init_code) + addr = utils.mk_metropolis_contract_address( + casper_config['METROPOLIS_ENTRY_POINT'], init_code) o = s.get_code(addr) assert o return o + _casper_code = None _rlp_decoder_code = None _hash_without_ed_code = None _finalizer_code = None + def get_casper_code(): global _casper_code if not _casper_code: import serpent - _casper_code = get_contract_code(serpent.compile(open(casper_path).read())) + _casper_code = get_contract_code( + serpent.compile(open(casper_path).read())) return _casper_code + def get_rlp_decoder_code(): global _rlp_decoder_code if not _rlp_decoder_code: import serpent - _rlp_decoder_code = get_contract_code(serpent.compile(open(rlp_decoder_path).read())) + _rlp_decoder_code = get_contract_code( + serpent.compile(open(rlp_decoder_path).read())) return _rlp_decoder_code + def get_hash_without_ed_code(): global _hash_without_ed_code if not _hash_without_ed_code: import serpent - _hash_without_ed_code = get_contract_code(serpent.compile(open(hash_without_ed_path).read())) + _hash_without_ed_code = get_contract_code( + serpent.compile(open(hash_without_ed_path).read())) return _hash_without_ed_code + def get_finalizer_code(): global _finalizer_code if not _finalizer_code: import serpent - _finalizer_code = get_contract_code(serpent.compile(open(finalizer_path).read())) + _finalizer_code = get_contract_code( + serpent.compile(open(finalizer_path).read())) return _finalizer_code + # The Casper-specific config declaration casper_config = copy.deepcopy(default_config) casper_config['HOMESTEAD_FORK_BLKNUM'] = 0 @@ -82,11 +93,14 @@ def get_finalizer_code(): _casper_ct = None + def get_casper_ct(): import serpent global _casper_ct if not _casper_ct: - _casper_ct = abi.ContractTranslator(serpent.mk_full_signature(open(casper_path).read())) + _casper_ct = abi.ContractTranslator( + serpent.mk_full_signature( + open(casper_path).read())) return _casper_ct @@ -94,9 +108,10 @@ def get_casper_ct(): # when signing their block RANDAO_SAVE_INTERVAL = 100 + class RandaoManager(): - def __init__(self, seed, rounds=10**4+1): + def __init__(self, seed, rounds=10**4 + 1): self.medstate = [] for i in range(rounds): if not i % RANDAO_SAVE_INTERVAL: @@ -113,12 +128,14 @@ def get_parent(self, val): origval = val for i in range(RANDAO_SAVE_INTERVAL): if val in self.medstate: - o = self.get(self.medstate.index(val) * RANDAO_SAVE_INTERVAL - i - 1) + o = self.get(self.medstate.index(val) * + RANDAO_SAVE_INTERVAL - i - 1) assert utils.sha3(o) == origval return o val = utils.sha3(val) raise Exception("Randao parent not found") + # Create the validation code for a given address def generate_validation_code(addr): import serpent @@ -129,10 +146,11 @@ def generate_validation_code(addr): if a != mustbe: ~invalid() return(1) - """ % ('0x'+utils.normalize_address(addr).encode('hex')) + """ % ('0x' + utils.normalize_address(addr).encode('hex')) return get_contract_code(serpent.compile(code)) -# Call the casper contract statically, + +# Call the casper contract statically, # eg. x = call_casper(state, 'getValidationCode', [2, 5]) def call_casper(state, fun, args=[], gas=1000000, value=0): ct = get_casper_ct() @@ -146,6 +164,7 @@ def call_casper(state, fun, args=[], gas=1000000, value=0): else: return None + # Get the number of skips needed to make a block on the current # parent def get_skips_and_block_making_time(state, vchash, max_lookup=100): @@ -157,16 +176,19 @@ def get_skips_and_block_making_time(state, vchash, max_lookup=100): skips += 1 return None, None + # Check a particular count of skips def check_skips(chain, vchash, skips): vchash2 = call_casper(chain.state, 'getValidator', [skips]) return vchash2 and vchash2 == vchash + # Get timestamp given a particular number of skips def get_timestamp(chain, skips): # Add three because the context the function will be called in will be one # block height later - return call_casper(chain.state, 'getMinTimestamp', [skips]) + 3 + return call_casper(chain.state, 'getMinTimestamp', [skips]) + 3 + # Add a signature to a block def sign_block(block, key, randao_parent, vchash, skips): @@ -178,20 +200,34 @@ def sign_block(block, key, randao_parent, vchash, skips): block.header.extra_data += utils.zpad(utils.encode_int(val), 32) return block + # Sign a withdrawal request def make_withdrawal_signature(key): h = sha3(b'withdrawwithdrawwithdrawwithdraw') v, r, s = ecsign(h, key) return encode_int32(v) + encode_int32(r) + encode_int32(s) -def casper_contract_bootstrap(state, timestamp=0, epoch_length=100, number=0, gas_limit=4712388, nonce=0): + +def casper_contract_bootstrap( + state, timestamp=0, epoch_length=100, number=0, gas_limit=4712388, nonce=0): ct = get_casper_ct() # Set genesis time, and initialize epoch number - t = Transaction(nonce, 0, 10**8, casper_config['CASPER_ADDR'], 0, ct.encode('initialize', [timestamp, epoch_length, number, gas_limit])) + t = Transaction(nonce, + 0, + 10**8, + casper_config['CASPER_ADDR'], + 0, + ct.encode('initialize', + [timestamp, + epoch_length, + number, + gas_limit])) success, output = apply_transaction(state, t) assert success -def validator_inject(state, vcode, deposit_size, randao_commitment, address, nonce=0, ct=None): + +def validator_inject(state, vcode, deposit_size, + randao_commitment, address, nonce=0, ct=None): if not ct: ct = get_casper_ct() state.set_balance(utils.int_to_addr(1), deposit_size) @@ -201,6 +237,7 @@ def validator_inject(state, vcode, deposit_size, randao_commitment, address, non success, output = apply_transaction(state, t) assert success + def casper_state_initialize(state): config = state.config @@ -209,10 +246,19 @@ def casper_state_initialize(state): if state.is_SERENITY(at_fork_height=True): state.set_code(config['CASPER_ADDR'], get_casper_code()) state.set_code(config['RLP_DECODER_ADDR'], get_rlp_decoder_code()) - state.set_code(config['HASH_WITHOUT_BLOOM_ADDR'], get_hash_without_ed_code()) - state.set_code(config['SERENITY_HEADER_POST_FINALIZER'], get_finalizer_code()) - state.set_code(config['METROPOLIS_STATEROOT_STORE'], config['SERENITY_GETTER_CODE']) - state.set_code(config['METROPOLIS_BLOCKHASH_STORE'], config['SERENITY_GETTER_CODE']) + state.set_code( + config['HASH_WITHOUT_BLOOM_ADDR'], + get_hash_without_ed_code()) + state.set_code( + config['SERENITY_HEADER_POST_FINALIZER'], + get_finalizer_code()) + state.set_code( + config['METROPOLIS_STATEROOT_STORE'], + config['SERENITY_GETTER_CODE']) + state.set_code( + config['METROPOLIS_BLOCKHASH_STORE'], + config['SERENITY_GETTER_CODE']) + # Create a casper genesis from given parameters # Validators: (vcode, deposit_size, randao_commitment) @@ -229,17 +275,29 @@ def make_casper_genesis(validators, alloc, timestamp=0, epoch_length=100): ct = get_casper_ct() initialize(state) - casper_contract_bootstrap(state, timestamp=header.timestamp, gas_limit=header.gas_limit) + casper_contract_bootstrap( + state, + timestamp=header.timestamp, + gas_limit=header.gas_limit) # Add validators - for i, (vcode, deposit_size, randao_commitment, address) in enumerate(validators): - validator_inject(state, vcode, deposit_size, randao_commitment, address, i, ct) + for i, (vcode, deposit_size, randao_commitment, + address) in enumerate(validators): + validator_inject( + state, + vcode, + deposit_size, + randao_commitment, + address, + i, + ct) # Start the first epoch casper_start_epoch(state) assert call_casper(state, 'getEpoch', []) == 0 - assert call_casper(state, 'getTotalDeposits', []) == sum([d for a,d,r,a in validators]) + assert call_casper(state, 'getTotalDeposits', []) == sum( + [d for a, d, r, a in validators]) state.set_storage_data(utils.normalize_address(state.config['METROPOLIS_BLOCKHASH_STORE']), state.block_number % state.config['METROPOLIS_WRAPAROUND'], header.hash) @@ -250,30 +308,52 @@ def make_casper_genesis(validators, alloc, timestamp=0, epoch_length=100): def casper_start_epoch(state): ct = get_casper_ct() - t = Transaction(0, 0, 10**8, casper_config['CASPER_ADDR'], 0, ct.encode('newEpoch', [0])) + t = Transaction( + 0, + 0, + 10**8, + casper_config['CASPER_ADDR'], + 0, + ct.encode( + 'newEpoch', + [0])) t._sender = casper_config['CASPER_ADDR'] apply_transaction(state, t) def get_dunkle_candidates(chain, state, scan_limit=10): blknumber = call_casper(state, 'getBlockNumber') - anc = chain.get_block(chain.get_blockhash_by_number(blknumber - scan_limit)) + anc = chain.get_block( + chain.get_blockhash_by_number( + blknumber - scan_limit)) if anc: descendants = chain.get_descendants(anc) else: - descendants = chain.get_descendants(chain.get_block(chain.db.get('GENESIS_HASH'))) - potential_uncles = [x for x in descendants if x not in chain and isinstance(x, Block)] - uncles = [x.header for x in potential_uncles if not call_casper(chain.state, 'isDunkleIncluded', [x.header.hash])] + descendants = chain.get_descendants( + chain.get_block(chain.db.get('GENESIS_HASH'))) + potential_uncles = [ + x for x in descendants if x not in chain and isinstance( + x, Block)] + uncles = [x.header for x in potential_uncles if not call_casper( + chain.state, 'isDunkleIncluded', [x.header.hash])] dunkle_txs = [] ct = get_casper_ct() start_nonce = state.get_nonce(state.config['METROPOLIS_ENTRY_POINT']) for i, u in enumerate(uncles[:4]): txdata = ct.encode('includeDunkle', [rlp.encode(u)]) - dunkle_txs.append(Transaction(start_nonce + i, 0, 650000, chain.config['CASPER_ADDR'], 0, txdata)) + dunkle_txs.append( + Transaction( + start_nonce + i, + 0, + 650000, + chain.config['CASPER_ADDR'], + 0, + txdata)) return dunkle_txs -def casper_setup_block(chain, state=None, timestamp=None, coinbase=b'\x35'*20, extra_data='moo ha ha says the laughing cow.'): +def casper_setup_block(chain, state=None, timestamp=None, + coinbase=b'\x35' * 20, extra_data='moo ha ha says the laughing cow.'): state = state or chain.state blk = Block(BlockHeader()) now = timestamp or chain.time() @@ -298,6 +378,7 @@ def casper_setup_block(chain, state=None, timestamp=None, coinbase=b'\x35'*20, e (blk.header.number, utils.encode_hex(blk.header.prevhash), len(blk.transactions))) return blk + def casper_validate_header(state, header): output = apply_const_message(state, sender=state.config['SYSTEM_ENTRY_POINT'], @@ -308,9 +389,9 @@ def casper_validate_header(state, header): elif output: raise ValueError(output) + def casper_post_finalize_block(state, block): apply_message(state, sender=state.config['SYSTEM_ENTRY_POINT'], to=state.config['SERENITY_HEADER_POST_FINALIZER'], data=rlp.encode(block.header)) - diff --git a/ethereum/genesis_helpers.py b/ethereum/genesis_helpers.py index 6249aec57..e3350a5ab 100644 --- a/ethereum/genesis_helpers.py +++ b/ethereum/genesis_helpers.py @@ -8,20 +8,26 @@ import rlp import json + def block_from_genesis_declaration(genesis_data, env): h = BlockHeader(nonce=parse_as_bin(genesis_data["nonce"]), difficulty=parse_as_int(genesis_data["difficulty"]), - mixhash=parse_as_bin(genesis_data.get("mixhash", genesis_data.get("mixHash", "0"*64))), - coinbase=parse_as_bin(genesis_data["coinbase"]), - bloom=parse_as_int(genesis_data.get("bloom", "0")), - timestamp=parse_as_int(genesis_data["timestamp"]), - prevhash=parse_as_bin(genesis_data["parentHash"]), - extra_data=parse_as_bin(genesis_data["extraData"]), - gas_used=parse_as_int(genesis_data.get("gasUsed", "0")), - gas_limit=parse_as_int(genesis_data["gasLimit"])) + mixhash=parse_as_bin( + genesis_data.get( + "mixhash", genesis_data.get( + "mixHash", "0" * 64))), + coinbase=parse_as_bin(genesis_data["coinbase"]), + bloom=parse_as_int(genesis_data.get("bloom", "0")), + timestamp=parse_as_int(genesis_data["timestamp"]), + prevhash=parse_as_bin(genesis_data["parentHash"]), + extra_data=parse_as_bin(genesis_data["extraData"]), + gas_used=parse_as_int(genesis_data.get("gasUsed", "0")), + gas_limit=parse_as_int(genesis_data["gasLimit"])) return Block(h, [], []) -def state_from_genesis_declaration(genesis_data, env, block=None, allow_empties=False, executing_on_head=False): + +def state_from_genesis_declaration( + genesis_data, env, block=None, allow_empties=False, executing_on_head=False): if block: assert isinstance(block, Block) else: @@ -41,7 +47,10 @@ def state_from_genesis_declaration(genesis_data, env, block=None, allow_empties= 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))) + state.set_storage_data( + addr, big_endian_to_int( + parse_as_bin(k)), big_endian_to_int( + parse_as_bin(v))) get_consensus_strategy(state.config).initialize(state, block) if executing_on_head: state.executing_on_head = True @@ -52,7 +61,7 @@ def state_from_genesis_declaration(genesis_data, env, block=None, allow_empties= rdb.delete(delete) block.header.state_root = state.trie.root_hash state.changed = {} - state.prev_headers=[block.header] + state.prev_headers = [block.header] return state @@ -113,7 +122,7 @@ def mk_basic_state(alloc, header=None, env=None, executing_on_head=False): header = { "number": 0, "gas_limit": env.config['BLOCK_GAS_LIMIT'], "gas_used": 0, "timestamp": 1467446877, "difficulty": 1, - "uncles_hash": '0x'+encode_hex(BLANK_UNCLES_HASH) + "uncles_hash": '0x' + encode_hex(BLANK_UNCLES_HASH) } h = BlockHeader(number=parse_as_int(header['number']), timestamp=parse_as_int(header['timestamp']), diff --git a/ethereum/hybrid_casper/consensus.py b/ethereum/hybrid_casper/consensus.py index ef9875a14..29903d608 100644 --- a/ethereum/hybrid_casper/consensus.py +++ b/ethereum/hybrid_casper/consensus.py @@ -1,5 +1,6 @@ from ethereum import utils + # Update block variables into the state def update_block_env_variables(state, block): state.timestamp = block.header.timestamp @@ -9,6 +10,7 @@ def update_block_env_variables(state, block): state.block_coinbase = block.header.coinbase state.block_difficulty = block.header.difficulty + # Block initialization state transition def initialize(state, block=None): config = state.config @@ -18,16 +20,18 @@ def initialize(state, block=None): state.bloom = 0 state.receipts = [] - if block != None: + if block is not None: update_block_env_variables(state, block) if state.is_DAO(at_fork_height=True): for acct in state.config['CHILD_DAO_LIST']: - state.transfer_value(acct, state.config['DAO_WITHDRAWER'], state.get_balance(acct)) + state.transfer_value( + acct, + state.config['DAO_WITHDRAWER'], + state.get_balance(acct)) if state.is_METROPOLIS(at_fork_height=True): state.set_code(utils.normalize_address( config["METROPOLIS_STATEROOT_STORE"]), config["METROPOLIS_GETTER_CODE"]) state.set_code(utils.normalize_address( config["METROPOLIS_BLOCKHASH_STORE"]), config["METROPOLIS_GETTER_CODE"]) - diff --git a/ethereum/messages.py b/ethereum/messages.py index ce04fd0e5..f65b0d19a 100644 --- a/ethereum/messages.py +++ b/ethereum/messages.py @@ -42,9 +42,11 @@ # DEV OPTIONS SKIP_MEDSTATES = False + def rp(tx, what, actual, target): return '%r: %r actual:%r target:%r' % (tx, what, actual, target) + class Log(rlp.Serializable): # TODO: original version used zpad (here replaced by int32.serialize); had @@ -88,7 +90,8 @@ class Receipt(rlp.Serializable): ] def __init__(self, state_root, gas_used, logs, bloom=None): - # does not call super.__init__ as bloom should not be an attribute but a property + # does not call super.__init__ as bloom should not be an attribute but + # a property self.state_root = state_root self.gas_used = gas_used self.logs = logs @@ -102,12 +105,14 @@ def bloom(self): bloomables = [x.bloomables() for x in self.logs] return bloom.bloom_from_list(utils.flatten(bloomables)) + def mk_receipt(state, success, logs): if state.is_METROPOLIS(): return Receipt(ascii_chr(success), state.gas_used, logs) else: return Receipt(state.trie.root_hash, state.gas_used, logs) + def config_fork_specific_validation(config, blknum, tx): # (1) The transaction signature is valid; _ = tx.sender @@ -126,13 +131,15 @@ def config_fork_specific_validation(config, blknum, tx): raise InvalidTransaction("Wrong network ID") return True + 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) + 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); @@ -143,22 +150,26 @@ def validate_transaction(state, tx): # (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)) + 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)) + 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)) + 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") + raise InvalidTransaction( + "EIP86 transactions must have 0 value and gasprice") return True @@ -185,7 +196,8 @@ def apply_transaction(state, tx): 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)) + raise InsufficientStartGas( + rp(tx, 'startgas', tx.startgas, intrinsic_gas)) log_tx.debug('TX NEW', txdict=tx.to_dict()) @@ -198,7 +210,14 @@ def apply_transaction(state, tx): 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 = vm.Message( + tx.sender, + tx.to, + tx.value, + tx.startgas - + intrinsic_gas, + message_data, + code_address=tx.to) # MESSAGE ext = VMExt(state, tx) @@ -229,7 +248,11 @@ def apply_transaction(state, tx): 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)) + 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 @@ -249,7 +272,7 @@ def apply_transaction(state, tx): 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() @@ -265,13 +288,11 @@ def apply_transaction(state, tx): return success, output - - # VM interface class VMExt(): def __init__(self, state, tx): - self.specials = {k:v for k, v in default_specials.items()} + self.specials = {k: v for k, v in default_specials.items()} for k, v in state.config['CUSTOM_SPECIALS']: self.specials[k] = v self._state = state @@ -298,7 +319,8 @@ def __init__(self, state, tx): self.log = lambda addr, topics, data: \ state.add_log(Log(addr, topics, data)) self.create = lambda msg: create_contract(self, msg) - self.msg = lambda msg: _apply_msg(self, msg, self.get_code(msg.code_address)) + self.msg = lambda msg: _apply_msg( + self, msg, self.get_code(msg.code_address)) self.account_exists = state.account_exists self.post_homestead_hardfork = lambda: state.is_HOMESTEAD() self.post_metropolis_hardfork = lambda: state.is_METROPOLIS() @@ -314,6 +336,7 @@ def __init__(self, state, tx): self.tx_origin = tx.sender if tx else '\x00' * 20 self.tx_gasprice = tx.gasprice if tx else 0 + def apply_msg(ext, msg): return _apply_msg(ext, msg, ext.get_code(msg.code_address)) @@ -323,9 +346,12 @@ def _apply_msg(ext, msg, code): if trace_msg: 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 msg.data.size < 2500 else ("data<%d>" % msg.data.size), - pre_storage=ext.log_storage(msg.to), - static=msg.static, depth=msg.depth) + data=encode_hex( + msg.data.extract_all()) if msg.data.size < 2500 else ( + "data<%d>" % + msg.data.size), + pre_storage=ext.log_storage(msg.to), + static=msg.static, depth=msg.depth) # Transfer value, instaquit if not enough snapshot = ext.snapshot() @@ -341,7 +367,6 @@ def _apply_msg(ext, msg, code): else: res, gas, dat = vm.vm_execute(ext, msg, code) - if trace_msg: log_msg.debug('MSG APPLIED', gas_remained=gas, sender=encode_hex(msg.sender), to=encode_hex(msg.to), @@ -370,10 +395,10 @@ def create_contract(ext, msg): nonce = utils.encode_int(ext.get_nonce(msg.sender) - 1) msg.to = utils.mk_contract_address(msg.sender, nonce) - if ext.post_constantinople_hardfork() and (ext.get_nonce(msg.to) or len(ext.get_code(msg.to))): + if ext.post_constantinople_hardfork() and ( + ext.get_nonce(msg.to) or len(ext.get_code(msg.to))): log_msg.debug('CREATING CONTRACT ON TOP OF EXISTING CONTRACT') return 0, 0, b'' - b = ext.get_balance(msg.to) if b > 0: @@ -390,18 +415,29 @@ def create_contract(ext, msg): ext.set_nonce(msg.to, 1 if ext.post_spurious_dragon_hardfork() else 0) res, gas, dat = _apply_msg(ext, msg, code) - log_msg.debug('CONTRACT CREATION FINISHED', res=res, gas=gas, dat=dat if len(dat) < 2500 else ("data<%d>" % len(dat))) + log_msg.debug( + 'CONTRACT CREATION FINISHED', + res=res, + gas=gas, + dat=dat if len(dat) < 2500 else ( + "data<%d>" % + len(dat))) if res: if not len(dat): # ext.set_code(msg.to, b'') return 1, gas, msg.to gcost = len(dat) * opcodes.GCONTRACTBYTE - if gas >= gcost and (len(dat) <= 24576 or not ext.post_spurious_dragon_hardfork()): + if gas >= gcost and ( + len(dat) <= 24576 or not ext.post_spurious_dragon_hardfork()): gas -= gcost else: dat = [] - log_msg.debug('CONTRACT CREATION FAILED', have=gas, want=gcost, block_number=ext.block_number) + log_msg.debug( + 'CONTRACT CREATION FAILED', + have=gas, + want=gcost, + block_number=ext.block_number) if ext.post_homestead_hardfork(): ext.revert(snapshot) return 0, 0, b'' diff --git a/ethereum/meta.py b/ethereum/meta.py index 14373eea5..8d8b26d12 100644 --- a/ethereum/meta.py +++ b/ethereum/meta.py @@ -10,6 +10,7 @@ from ethereum.utils import sha3, encode_hex import rlp + # Applies the block-level state transition function def apply_block(state, block): # Pre-processing and verification @@ -42,18 +43,25 @@ def apply_block(state, block): def make_head_candidate(chain, txqueue=None, parent=None, timestamp=None, - coinbase=b'\x35'*20, + coinbase=b'\x35' * 20, extra_data='moo ha ha says the laughing cow.', min_gasprice=0): log.debug('Creating head candidate') if parent is None: - temp_state = State.from_snapshot(chain.state.to_snapshot(root_only=True), chain.env) + temp_state = State.from_snapshot( + chain.state.to_snapshot( + root_only=True), chain.env) else: temp_state = chain.mk_poststate_of_blockhash(parent.hash) cs = get_consensus_strategy(chain.env.config) # Initialize a block with the given parent and variables - blk = mk_block_from_prevstate(chain, temp_state, timestamp, coinbase, extra_data) + blk = mk_block_from_prevstate( + chain, + temp_state, + timestamp, + coinbase, + extra_data) # Find and set the uncles blk.uncles = cs.get_uncles(chain, temp_state) blk.header.uncles_hash = sha3(rlp.encode(blk.uncles)) diff --git a/ethereum/new_state.py b/ethereum/new_state.py index 688e59301..2773cd42a 100644 --- a/ethereum/new_state.py +++ b/ethereum/new_state.py @@ -23,6 +23,7 @@ BLANK_HASH = utils.sha3(b'') BLANK_ROOT = utils.sha3rlp(b'') + def snapshot_form(val): if is_numeric(val): return str(val) @@ -47,6 +48,7 @@ def snapshot_form(val): "refunds": 0, } + class Account(rlp.Serializable): fields = [ @@ -93,7 +95,8 @@ def code(self, value): def get_storage_data(self, key): if key not in self.storage_cache: v = self.storage_trie.get(utils.encode_int32(key)) - self.storage_cache[key] = utils.big_endian_to_int(rlp.decode(v) if v else b'') + self.storage_cache[key] = utils.big_endian_to_int( + rlp.decode(v) if v else b'') return self.storage_cache[key] def set_storage_data(self, key, value): @@ -119,12 +122,14 @@ def to_dict(self): odict = self.storage_trie.to_dict() for k, v in self.storage_cache.items(): odict[utils.encode_int(k)] = rlp.encode(utils.encode_int(v)) - return {'balance': str(self.balance), 'nonce': str(self.nonce), 'code': '0x'+encode_hex(self.code), - 'storage': {'0x'+encode_hex(key.lstrip(b'\x00') or b'\x00'): - '0x'+encode_hex(rlp.decode(val)) for key, val in odict.items()} } + return {'balance': str(self.balance), 'nonce': str(self.nonce), 'code': '0x' + encode_hex(self.code), + 'storage': {'0x' + encode_hex(key.lstrip(b'\x00') or b'\x00'): + '0x' + encode_hex(rlp.decode(val)) for key, val in odict.items()}} #from ethereum.state import State -#class Statu(): +# class Statu(): + + class State(): def __init__(self, root=b'', env=Env(), **kwargs): @@ -161,20 +166,24 @@ def get_and_cache_account(self, address): if rlpdata != trie.BLANK_NODE: o = rlp.decode(rlpdata, Account, env=self.env) else: - o = Account.blank_account(self.env, self.config['ACCOUNT_INITIAL_NONCE']) + o = Account.blank_account( + self.env, self.config['ACCOUNT_INITIAL_NONCE']) self.cache[address] = o o._mutable = True o._cached_rlp = None return o def get_balance(self, address): - return self.get_and_cache_account(utils.normalize_address(address)).balance + return self.get_and_cache_account( + utils.normalize_address(address)).balance def get_code(self, address): - return self.get_and_cache_account(utils.normalize_address(address)).code + return self.get_and_cache_account( + utils.normalize_address(address)).code def get_nonce(self, address): - return self.get_and_cache_account(utils.normalize_address(address)).nonce + return self.get_and_cache_account( + utils.normalize_address(address)).nonce def set_and_journal(self, acct, param, val): # self.journal.append((acct, param, getattr(acct, param))) @@ -211,9 +220,10 @@ def increment_nonce(self, address): newnonce = acct.nonce + 1 self.set_and_journal(acct, 'nonce', newnonce) self.set_and_journal(acct, 'touched', True) - + def get_storage_data(self, address, key): - return self.get_and_cache_account(utils.normalize_address(address)).get_storage_data(key) + return self.get_and_cache_account( + utils.normalize_address(address)).get_storage_data(key) def set_storage_data(self, address, key, value): acct = self.get_and_cache_account(utils.normalize_address(address)) @@ -242,7 +252,8 @@ def add_refund(self, value): self.journal.append(lambda: setattr(self.refunds, preval)) def snapshot(self): - return (self.trie.root_hash, len(self.journal), {k: copy.copy(getattr(self, k)) for k in STATE_DEFAULTS}) + return (self.trie.root_hash, len(self.journal), { + k: copy.copy(getattr(self, k)) for k in STATE_DEFAULTS}) def revert(self, snapshot): h, L, auxvars = snapshot @@ -262,32 +273,45 @@ def set_param(self, k, v): setattr(self, k, v) def is_SERENITY(self, at_fork_height=False): - if at_fork_height: return self.block_number == self.config['SERENITY_FORK_BLKNUM'] - else: return self.block_number >= self.config['SERENITY_FORK_BLKNUM'] + if at_fork_height: + return self.block_number == self.config['SERENITY_FORK_BLKNUM'] + else: + return self.block_number >= self.config['SERENITY_FORK_BLKNUM'] def is_HOMESTEAD(self, at_fork_height=False): - if at_fork_height: return self.block_number == self.config['HOMESTEAD_FORK_BLKNUM'] - else: return self.block_number >= self.config['HOMESTEAD_FORK_BLKNUM'] + if at_fork_height: + return self.block_number == self.config['HOMESTEAD_FORK_BLKNUM'] + else: + return self.block_number >= self.config['HOMESTEAD_FORK_BLKNUM'] def is_METROPOLIS(self, at_fork_height=False): - if at_fork_height: return self.block_number == self.config['METROPOLIS_FORK_BLKNUM'] - else: return self.block_number >= self.config['METROPOLIS_FORK_BLKNUM'] + if at_fork_height: + return self.block_number == self.config['METROPOLIS_FORK_BLKNUM'] + else: + return self.block_number >= self.config['METROPOLIS_FORK_BLKNUM'] def is_ANTI_DOS(self, at_fork_height=False): - if at_fork_height: return self.block_number == self.config['ANTI_DOS_FORK_BLKNUM'] - else: return self.block_number >= self.config['ANTI_DOS_FORK_BLKNUM'] + if at_fork_height: + return self.block_number == self.config['ANTI_DOS_FORK_BLKNUM'] + else: + return self.block_number >= self.config['ANTI_DOS_FORK_BLKNUM'] def is_SPURIOUS_DRAGON(self, at_fork_height=False): - if at_fork_height: return self.block_number == self.config['SPURIOUS_DRAGON_FORK_BLKNUM'] - else: return self.block_number >= self.config['SPURIOUS_DRAGON_FORK_BLKNUM'] + if at_fork_height: + return self.block_number == self.config['SPURIOUS_DRAGON_FORK_BLKNUM'] + else: + return self.block_number >= self.config['SPURIOUS_DRAGON_FORK_BLKNUM'] def is_DAO(self, at_fork_height=False): - if at_fork_height: return self.block_number == self.config['DAO_FORK_BLKNUM'] - else: return self.block_number >= self.config['DAO_FORK_BLKNUM'] + if at_fork_height: + return self.block_number == self.config['DAO_FORK_BLKNUM'] + else: + return self.block_number >= self.config['DAO_FORK_BLKNUM'] def account_exists(self, address): if self.is_SPURIOUS_DRAGON(): - o = not self.get_and_cache_account(utils.normalize_address(address)).is_blank() + o = not self.get_and_cache_account( + utils.normalize_address(address)).is_blank() else: a = self.get_and_cache_account(address) if a.touched: @@ -305,13 +329,15 @@ def transfer_value(self, from_addr, to_addr, value): return False def account_to_dict(self, address): - return self.get_and_cache_account(utils.normalize_address(address)).to_dict() + return self.get_and_cache_account( + utils.normalize_address(address)).to_dict() def commit(self, allow_empties=False): for addr, acct in self.cache.items(): if acct.touched: acct.commit() - if acct.exists or allow_empties or (not self.is_SPURIOUS_DRAGON() and not acct.deleted): + if acct.exists or allow_empties or ( + not self.is_SPURIOUS_DRAGON() and not acct.deleted): # print('upd', encode_hex(addr)) self.trie.update(addr, rlp.encode(acct)) else: @@ -323,14 +349,19 @@ def commit(self, allow_empties=False): def to_dict(self): for addr in self.trie.to_dict().keys(): self.get_and_cache_account(addr) - return {encode_hex(addr): acct.to_dict() for addr, acct in self.cache.items()} + return {encode_hex(addr): acct.to_dict() + for addr, acct in self.cache.items()} def del_account(self, address): self.set_balance(address, 0) self.set_nonce(address, 0) self.set_code(address, b'') self.reset_storage(address) - self.set_and_journal(self.get_and_cache_account(utils.normalize_address(address)), 'deleted', True) + self.set_and_journal( + self.get_and_cache_account( + utils.normalize_address(address)), + 'deleted', + True) def reset_storage(self, address): acct = self.get_and_cache_account(address) @@ -338,7 +369,11 @@ def reset_storage(self, address): acct.storage_cache = {} self.journal.append(lambda: setattr(acct, 'storage_cache', pre_cache)) pre_root = acct.storage_trie.root_hash - self.journal.append(lambda: setattr(acct.storage_trie, 'root_hash', pre_root)) + self.journal.append( + lambda: setattr( + acct.storage_trie, + 'root_hash', + pre_root)) acct.storage_trie.root_hash = BLANK_ROOT # Creates a snapshot from a state @@ -347,7 +382,7 @@ def to_snapshot(self, root_only=False, no_prevblocks=False): 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) + snapshot["state_root"] = '0x' + encode_hex(self.trie.root_hash) else: # "Full" snapshot snapshot["alloc"] = self.to_dict() @@ -358,17 +393,19 @@ def to_snapshot(self, root_only=False, no_prevblocks=False): if is_numeric(default): snapshot[k] = str(v) elif isinstance(default, (str, bytes)): - snapshot[k] = '0x'+encode_hex(v) + 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']]] + 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()} + snapshot[k] = {str(n): ['0x' + encode_hex(h) + for h in headers] for n, headers in v.items()} return snapshot # Creates a state from a snapshot @classmethod def from_snapshot(cls, snapshot_data, env): - state = State(env = env) + state = State(env=env) if "alloc" in snapshot_data: for addr, data in snapshot_data["alloc"].items(): if len(addr) == 40: @@ -384,18 +421,22 @@ def from_snapshot(cls, snapshot_data, env): 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, parse_as_bin(k), parse_as_bin(v)) + state.set_storage_data( + addr, parse_as_bin(k), 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") + 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) + 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) + 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] @@ -415,7 +456,6 @@ def from_snapshot(cls, snapshot_data, env): state.commit() return state - def ephemeral_clone(self): snapshot = self.to_snapshot(root_only=True, no_prevblocks=True) env2 = Env(OverlayDB(self.env.db), self.env.config) @@ -433,18 +473,19 @@ def ephemeral_clone(self): def prev_header_to_dict(h): return { - "hash": '0x'+encode_hex(h.hash), + "hash": '0x' + encode_hex(h.hash), "number": str(h.number), "timestamp": str(h.timestamp), "difficulty": str(h.difficulty), "gas_used": str(h.gas_used), "gas_limit": str(h.gas_limit), - "uncles_hash": '0x'+encode_hex(h.uncles_hash) + "uncles_hash": '0x' + encode_hex(h.uncles_hash) } BLANK_UNCLES_HASH = sha3(rlp.encode([])) + def dict_to_prev_header(h): return FakeHeader(hash=parse_as_bin(h['hash']), number=parse_as_int(h['number']), @@ -452,4 +493,4 @@ def dict_to_prev_header(h): difficulty=parse_as_int(h['difficulty']), gas_used=parse_as_int(h.get('gas_used', '0')), gas_limit=parse_as_int(h['gas_limit']), - uncles_hash=parse_as_bin(h.get('uncles_hash', '0x'+encode_hex(BLANK_UNCLES_HASH)))) + uncles_hash=parse_as_bin(h.get('uncles_hash', '0x' + encode_hex(BLANK_UNCLES_HASH)))) diff --git a/ethereum/opcodes.py b/ethereum/opcodes.py index ada04652a..2911581be 100644 --- a/ethereum/opcodes.py +++ b/ethereum/opcodes.py @@ -26,7 +26,7 @@ 0x1a: ['BYTE', 2, 1, 3], 0x20: ['SHA3', 2, 1, 30], 0x30: ['ADDRESS', 0, 1, 2], - 0x31: ['BALANCE', 1, 1, 20], # now 400 + 0x31: ['BALANCE', 1, 1, 20], # now 400 0x32: ['ORIGIN', 0, 1, 2], 0x33: ['CALLER', 0, 1, 2], 0x34: ['CALLVALUE', 0, 1, 2], @@ -36,8 +36,8 @@ 0x38: ['CODESIZE', 0, 1, 2], 0x39: ['CODECOPY', 3, 0, 3], 0x3a: ['GASPRICE', 0, 1, 2], - 0x3b: ['EXTCODESIZE', 1, 1, 20], # now 700 - 0x3c: ['EXTCODECOPY', 4, 0, 20], # now 700 + 0x3b: ['EXTCODESIZE', 1, 1, 20], # now 700 + 0x3c: ['EXTCODECOPY', 4, 0, 20], # now 700 0x40: ['BLOCKHASH', 1, 1, 20], 0x41: ['COINBASE', 0, 1, 2], 0x42: ['TIMESTAMP', 0, 1, 2], @@ -48,8 +48,9 @@ 0x51: ['MLOAD', 1, 1, 3], 0x52: ['MSTORE', 2, 0, 3], 0x53: ['MSTORE8', 2, 0, 3], - 0x54: ['SLOAD', 1, 1, 50], # 200 now - 0x55: ['SSTORE', 2, 0, 0], # actual cost 5000-20000 depending on circumstance + 0x54: ['SLOAD', 1, 1, 50], # 200 now + # actual cost 5000-20000 depending on circumstance + 0x55: ['SSTORE', 2, 0, 0], 0x56: ['JUMP', 1, 0, 8], 0x57: ['JUMPI', 2, 0, 10], 0x58: ['PC', 0, 1, 2], @@ -61,18 +62,18 @@ 0xa2: ['LOG2', 4, 0, 1125], 0xa3: ['LOG3', 5, 0, 1500], 0xa4: ['LOG4', 6, 0, 1875], - #0xe1: ['SLOADBYTES', 3, 0, 50], # to be discontinued - #0xe2: ['SSTOREBYTES', 3, 0, 0], # to be discontinued - #0xe3: ['SSIZE', 1, 1, 50], # to be discontinued + # 0xe1: ['SLOADBYTES', 3, 0, 50], # to be discontinued + # 0xe2: ['SSTOREBYTES', 3, 0, 0], # to be discontinued + # 0xe3: ['SSIZE', 1, 1, 50], # to be discontinued 0xf0: ['CREATE', 3, 1, 32000], - 0xf1: ['CALL', 7, 1, 40], # 700 now - 0xf2: ['CALLCODE', 7, 1, 40], # 700 now + 0xf1: ['CALL', 7, 1, 40], # 700 now + 0xf2: ['CALLCODE', 7, 1, 40], # 700 now 0xf3: ['RETURN', 2, 0, 0], - 0xf4: ['DELEGATECALL', 6, 1, 40], # 700 now + 0xf4: ['DELEGATECALL', 6, 1, 40], # 700 now 0xf5: ['CALLBLACKBOX', 7, 1, 40], 0xfa: ['STATICCALL', 6, 1, 40], 0xfd: ['REVERT', 2, 0, 0], - 0xff: ['SUICIDE', 1, 0, 0], # 5000 now + 0xff: ['SUICIDE', 1, 0, 0], # 5000 now } for i in range(1, 33): diff --git a/ethereum/pow/chain.py b/ethereum/pow/chain.py index 6afb2eb3a..71f5711b0 100644 --- a/ethereum/pow/chain.py +++ b/ethereum/pow/chain.py @@ -17,27 +17,28 @@ from ethereum.block import Block, BlockHeader, BLANK_UNCLES_HASH from ethereum.pow.consensus import initialize from ethereum.genesis_helpers import mk_basic_state, state_from_genesis_declaration, \ - initialize_genesis_keys + initialize_genesis_keys from ethereum.db import RefcountDB log = get_logger('eth.chain') -config_string = ':info' #,eth.chain:debug' +config_string = ':info' # ,eth.chain:debug' #config_string = ':info,eth.vm.log:trace,eth.vm.op:trace,eth.vm.stack:trace,eth.vm.exit:trace,eth.pb.msg:trace,eth.pb.tx:debug' configure_logging(config_string=config_string) class Chain(object): - def __init__(self, genesis=None, env=None, \ + def __init__(self, genesis=None, env=None, new_head_cb=None, reset_genesis=False, localtime=None, max_history=1000, **kwargs): self.env = env or Env() # Initialize the state if 'head_hash' in self.db: # new head tag - self.state = self.mk_poststate_of_blockhash(self.db.get('head_hash')) + self.state = self.mk_poststate_of_blockhash( + self.db.get('head_hash')) self.state.executing_on_head = True - print('Initializing chain from saved head, #%d (%s)' % \ - (self.state.prev_headers[0].number, encode_hex(self.state.prev_headers[0].hash))) + print('Initializing chain from saved head, #%d (%s)' % + (self.state.prev_headers[0].number, encode_hex(self.state.prev_headers[0].hash))) elif genesis is None: raise Exception("Need genesis decl!") elif isinstance(genesis, State): @@ -52,10 +53,11 @@ def __init__(self, genesis=None, env=None, \ reset_genesis = True print('Initializing chain from provided genesis declaration') elif "prev_headers" in genesis: - self.state = State.from_snapshot(genesis, self.env, executing_on_head=True) + self.state = State.from_snapshot( + genesis, self.env, executing_on_head=True) reset_genesis = True - print('Initializing chain from provided state snapshot, %d (%s)' % \ - (self.state.block_number, encode_hex(self.state.prev_headers[0].hash[:8]))) + print('Initializing chain from provided state snapshot, %d (%s)' % + (self.state.block_number, encode_hex(self.state.prev_headers[0].hash[:8]))) elif isinstance(genesis, dict): print('Initializing chain from new state based on alloc') self.state = mk_basic_state(genesis, { @@ -106,7 +108,8 @@ def mk_poststate_of_blockhash(self, blockhash): block_rlp = self.db.get(blockhash) if block_rlp == 'GENESIS': - return State.from_snapshot(json.loads(self.db.get('GENESIS_STATE')), self.env) + return State.from_snapshot(json.loads( + self.db.get('GENESIS_STATE')), self.env) block = rlp.decode(block_rlp, Block) state = State(env=self.env) @@ -126,7 +129,7 @@ def mk_poststate_of_blockhash(self, blockhash): state.recent_uncles[state.block_number - i].append(u.hash) try: b = rlp.decode(state.db.get(b.header.prevhash), Block) - except: + except BaseException: break if i < header_depth: if state.db.get(b.header.prevhash) == 'GENESIS': @@ -134,8 +137,10 @@ def mk_poststate_of_blockhash(self, blockhash): for h in jsondata["prev_headers"][:header_depth - i]: state.prev_headers.append(dict_to_prev_header(h)) for blknum, uncles in jsondata["recent_uncles"].items(): - if int(blknum) >= state.block_number - int(state.config['MAX_UNCLE_DEPTH']): - state.recent_uncles[blknum] = [parse_as_bin(u) for u in uncles] + if int(blknum) >= state.block_number - \ + int(state.config['MAX_UNCLE_DEPTH']): + state.recent_uncles[blknum] = [ + parse_as_bin(u) for u in uncles] else: raise Exception("Dangling prevhash") assert len(state.journal) == 0, state.journal @@ -153,7 +158,8 @@ def get_block(self, blockhash): block_rlp = self.db.get(blockhash) if block_rlp == 'GENESIS': if not hasattr(self, 'genesis'): - self.genesis = rlp.decode(self.db.get('GENESIS_RLP'), sedes=Block) + self.genesis = rlp.decode( + self.db.get('GENESIS_RLP'), sedes=Block) return self.genesis else: return rlp.decode(block_rlp, Block) @@ -166,19 +172,21 @@ def get_block(self, blockhash): def add_child(self, child): try: existing = self.db.get(b'child:' + child.header.prevhash) - except: + except BaseException: existing = b'' existing_hashes = [] for i in range(0, len(existing), 32): - existing_hashes.append(existing[i: i+32]) + existing_hashes.append(existing[i: i + 32]) if child.header.hash not in existing_hashes: - self.db.put(b'child:' + child.header.prevhash, existing + child.header.hash) + self.db.put( + b'child:' + child.header.prevhash, + existing + child.header.hash) # Gets the hash of the block with the given block number def get_blockhash_by_number(self, number): try: return self.db.get(b'block:%d' % number) - except: + except BaseException: return None # Gets the block with the given block number @@ -193,7 +201,7 @@ def get_child_hashes(self, blockhash): for i in range(0, len(data), 32): o.append(data[i:i + 32]) return o - except: + except BaseException: return [] # Get the children of a block @@ -216,7 +224,7 @@ def get_score(self, block): key = b'score:' + block.header.prevhash block = self.get_parent(block) score = int(self.db.get(key)) - for h,d in fills: + for h, d in fills: key = b'score:' + h score = score + d + random.randrange(d // 10**6 + 1) self.db.put(key, str(score)) @@ -229,7 +237,8 @@ def get_score(self, block): def process_time_queue(self, new_time=None): self.localtime = time.time() if new_time is None else new_time i = 0 - while i < len(self.time_queue) and self.time_queue[i].timestamp <= new_time: + while i < len( + self.time_queue) and self.time_queue[i].timestamp <= new_time: log.info('Adding scheduled block') pre_len = len(self.time_queue) self.add_block(self.time_queue.pop(i)) @@ -242,7 +251,8 @@ def add_block(self, block): # Are we receiving the block too early? if block.header.timestamp > now: i = 0 - while i < len(self.time_queue) and block.timestamp > self.time_queue[i].timestamp: + while i < len( + self.time_queue) and block.timestamp > self.time_queue[i].timestamp: i += 1 self.time_queue.insert(i, block) log.info('Block received too early (%d vs %d). Delaying for %d seconds' % @@ -250,7 +260,8 @@ def add_block(self, block): return False # Is the block being added to the head? if block.header.prevhash == self.head_hash: - log.info('Adding to head', head=encode_hex(block.header.prevhash[:4])) + log.info('Adding to head', + head=encode_hex(block.header.prevhash[:4])) self.state.deletes = [] self.state.changed = {} try: @@ -260,14 +271,18 @@ def add_block(self, block): (block.number, encode_hex(block.header.hash[:4]), encode_hex(block.header.prevhash[:4]), e)) return False self.db.put(b'block:%d' % block.header.number, block.header.hash) - block_score = self.get_score(block) # side effect: put 'score:' cache in db + # side effect: put 'score:' cache in db + block_score = self.get_score(block) self.head_hash = block.header.hash for i, tx in enumerate(block.transactions): - self.db.put(b'txindex:' + tx.hash, rlp.encode([block.number, i])) - assert self.get_blockhash_by_number(block.header.number) == block.header.hash + self.db.put(b'txindex:' + + tx.hash, rlp.encode([block.number, i])) + assert self.get_blockhash_by_number( + block.header.number) == block.header.hash deletes = self.state.deletes changed = self.state.changed - # Or is the block being added to a chain that is not currently the head? + # Or is the block being added to a chain that is not currently the + # head? elif block.header.prevhash in self.env.db: log.info('Receiving block %d (%s) not on head (%s), adding to secondary post state %s' % (block.number, encode_hex(block.header.hash[:4]), @@ -290,10 +305,12 @@ def add_block(self, block): while b.header.number >= int(self.db.get('GENESIS_NUMBER')): new_chain[b.header.number] = b key = b'block:%d' % b.header.number - orig_at_height = self.db.get(key) if key in self.db else None + orig_at_height = self.db.get( + key) if key in self.db else None if orig_at_height == b.header.hash: break - if b.prevhash not in self.db or self.db.get(b.prevhash) == 'GENESIS': + if b.prevhash not in self.db or self.db.get( + b.prevhash) == 'GENESIS': break b = self.get_parent(b) replace_from = b.header.number @@ -302,15 +319,20 @@ def add_block(self, block): # Get a list of all accounts that have been edited along the old and # new chains changed_accts = {} - # Read: for i in range(common ancestor block number...new block number) + # Read: for i in range(common ancestor block number...new block + # number) for i in itertools.count(replace_from): log.info('Rewriting height %d' % i) key = b'block:%d' % i # Delete data for old blocks - orig_at_height = self.db.get(key) if key in self.db else None + orig_at_height = self.db.get( + key) if key in self.db else None if orig_at_height: orig_block_at_height = self.get_block(orig_at_height) - log.info('%s no longer in main chain' % encode_hex(orig_block_at_height.header.hash)) + log.info( + '%s no longer in main chain' % + encode_hex( + orig_block_at_height.header.hash)) # Delete from block index self.db.delete(key) # Delete from txindex @@ -318,24 +340,30 @@ def add_block(self, block): if b'txindex:' + tx.hash in self.db: self.db.delete(b'txindex:' + tx.hash) # Add to changed list - acct_list = self.db.get(b'changed:'+orig_block_at_height.hash) + acct_list = self.db.get( + b'changed:' + orig_block_at_height.hash) for j in range(0, len(acct_list), 20): - changed_accts[acct_list[j: j+20]] = True + changed_accts[acct_list[j: j + 20]] = True # Add data for new blocks if i in new_chain: new_block_at_height = new_chain[i] - log.info('%s now in main chain' % encode_hex(new_block_at_height.header.hash)) + log.info( + '%s now in main chain' % + encode_hex( + new_block_at_height.header.hash)) # Add to block index self.db.put(key, new_block_at_height.header.hash) # Add to txindex - for j, tx in enumerate(new_block_at_height.transactions): + for j, tx in enumerate( + new_block_at_height.transactions): self.db.put(b'txindex:' + tx.hash, rlp.encode([new_block_at_height.number, j])) # Add to changed list if i < b.number: - acct_list = self.db.get(b'changed:'+new_block_at_height.hash) + acct_list = self.db.get( + b'changed:' + new_block_at_height.hash) for j in range(0, len(acct_list), 20): - changed_accts[acct_list[j: j+20]] = True + changed_accts[acct_list[j: j + 20]] = True if i not in new_chain and not orig_at_height: break # Add changed list from new head to changed list @@ -345,10 +373,10 @@ def add_block(self, block): for addr in changed_accts.keys(): data = temp_state.trie.get(addr) if data: - self.state.db.put(b'address:'+addr, data) + self.state.db.put(b'address:' + addr, data) else: try: - self.state.db.delete(b'address:'+addr) + self.state.db.delete(b'address:' + addr) except KeyError: pass self.head_hash = block.header.hash @@ -365,29 +393,35 @@ def add_block(self, block): self.add_child(block) self.db.put('head_hash', self.head_hash) self.db.put(block.hash, rlp.encode(block)) - self.db.put(b'changed:'+block.hash, b''.join([k.encode() if isinstance(k, str) else k for k in list(changed.keys())])) + self.db.put(b'changed:' + block.hash, + b''.join([k.encode() if isinstance(k, + str) else k for k in list(changed.keys())])) print('Saved %d address change logs' % len(changed.keys())) - self.db.put(b'deletes:'+block.hash, b''.join(deletes)) - log.debug('Saved %d trie node deletes for block %d (%s)' % (len(deletes), block.number, utils.encode_hex(block.hash))) + self.db.put(b'deletes:' + block.hash, b''.join(deletes)) + log.debug('Saved %d trie node deletes for block %d (%s)' % + (len(deletes), block.number, utils.encode_hex(block.hash))) # Delete old junk data - old_block_hash = self.get_blockhash_by_number(block.number - self.max_history) + old_block_hash = self.get_blockhash_by_number( + block.number - self.max_history) if old_block_hash: try: - deletes = self.db.get(b'deletes:'+old_block_hash) - log.debug('Deleting up to %d trie nodes' % (len(deletes) // 32)) + deletes = self.db.get(b'deletes:' + old_block_hash) + log.debug( + 'Deleting up to %d trie nodes' % + (len(deletes) // 32)) rdb = RefcountDB(self.db) for i in range(0, len(deletes), 32): - rdb.delete(deletes[i: i+32]) - self.db.delete(b'deletes:'+old_block_hash) - self.db.delete(b'changed:'+old_block_hash) + rdb.delete(deletes[i: i + 32]) + self.db.delete(b'deletes:' + old_block_hash) + self.db.delete(b'changed:' + old_block_hash) except KeyError as e: print(e) pass self.db.commit() - assert (b'deletes:'+block.hash) in self.db - log.info('Added block %d (%s) with %d txs and %d gas' % \ - (block.header.number, encode_hex(block.header.hash)[:8], - len(block.transactions), block.header.gas_used)) + assert (b'deletes:' + block.hash) in self.db + log.info('Added block %d (%s) with %d txs and %d gas' % + (block.header.number, encode_hex(block.header.hash)[:8], + len(block.transactions), block.header.gas_used)) # Call optional callback if self.new_head_cb and block.header.number != 0: self.new_head_cb(block) @@ -403,7 +437,7 @@ def __contains__(self, blk): if isinstance(blk, (str, bytes)): try: blk = rlp.decode(self.db.get(blk), Block) - except: + except BaseException: return False try: o = self.get_block(self.get_blockhash_by_number(blk.number)).hash @@ -441,7 +475,7 @@ def get_tx_position(self, tx): def get_transaction(self, tx): print('Deprecated. Use get_tx_position') blknum, index = self.get_tx_position(tx) - blk = self.get_block_by_number(blknum) + blk = self.get_block_by_number(blknum) return blk.transactions[index], blk, index # Get descendants of a block diff --git a/ethereum/pow/consensus.py b/ethereum/pow/consensus.py index 7a826ee85..300d4eb45 100644 --- a/ethereum/pow/consensus.py +++ b/ethereum/pow/consensus.py @@ -4,6 +4,7 @@ from ethereum.exceptions import VerificationFailed import rlp + # Block initialization state transition def initialize(state, block=None): config = state.config @@ -13,18 +14,22 @@ def initialize(state, block=None): state.bloom = 0 state.receipts = [] - if block != None: + if block is not None: update_block_env_variables(state, block) if state.is_DAO(at_fork_height=True): for acct in state.config['CHILD_DAO_LIST']: - state.transfer_value(acct, state.config['DAO_WITHDRAWER'], state.get_balance(acct)) + state.transfer_value( + acct, + state.config['DAO_WITHDRAWER'], + state.get_balance(acct)) # if state.is_METROPOLIS(at_fork_height=True): # state.set_code(utils.normalize_address( # config["METROPOLIS_STATEROOT_STORE"]), config["METROPOLIS_GETTER_CODE"]) # state.set_code(utils.normalize_address( - # config["METROPOLIS_BLOCKHASH_STORE"]), config["METROPOLIS_GETTER_CODE"]) + # config["METROPOLIS_BLOCKHASH_STORE"]), config["METROPOLIS_GETTER_CODE"]) + # Check that proof of work is valid def check_pow(state, header): @@ -32,6 +37,7 @@ def check_pow(state, header): header.nonce, header.difficulty) return True + # Get uncle blocks to add to a block on the given state def get_uncle_candidates(chain, state): uncles = [] @@ -39,9 +45,11 @@ def get_uncle_candidates(chain, state): for h, _uncles in state.recent_uncles.items(): for u in _uncles: ineligible[u] = True - for i in range(0, min(state.config['MAX_UNCLE_DEPTH'], len((state.prev_headers)))): + for i in range( + 0, min(state.config['MAX_UNCLE_DEPTH'], len((state.prev_headers)))): ineligible[state.prev_headers[i].hash] = True - for i in range(1, min(state.config['MAX_UNCLE_DEPTH'], len(state.prev_headers))): + for i in range( + 1, min(state.config['MAX_UNCLE_DEPTH'], len(state.prev_headers))): child_hashes = chain.get_child_hashes(state.prev_headers[i].hash) for c in child_hashes: if c not in ineligible and len(uncles) < 2: @@ -50,6 +58,7 @@ def get_uncle_candidates(chain, state): break return uncles + # Validate that a block has valid uncles def validate_uncles(state, block): """Validate the uncles of this block.""" @@ -66,19 +75,22 @@ def validate_uncles(state, block): # Check uncle validity MAX_UNCLE_DEPTH = state.config['MAX_UNCLE_DEPTH'] - ancestor_chain = [block.header] + [a for a in state.prev_headers[:MAX_UNCLE_DEPTH + 1] if a] + ancestor_chain = [block.header] + \ + [a for a in state.prev_headers[:MAX_UNCLE_DEPTH + 1] if a] # Uncles of this block cannot be direct ancestors and cannot also # be uncles included 1-6 blocks ago ineligible = [b.hash for b in ancestor_chain] for blknum, uncles in state.recent_uncles.items(): - if state.block_number > int(blknum) >= state.block_number - MAX_UNCLE_DEPTH: + if state.block_number > int( + blknum) >= state.block_number - MAX_UNCLE_DEPTH: ineligible.extend([u for u in uncles]) eligible_ancestor_hashes = [x.hash for x in ancestor_chain[2:]] for uncle in block.uncles: if uncle.prevhash not in eligible_ancestor_hashes: raise VerificationFailed("Uncle does not have a valid ancestor") parent = [x for x in ancestor_chain if x.hash == uncle.prevhash][0] - if uncle.difficulty != calc_difficulty(parent, uncle.timestamp, config=state.config): + if uncle.difficulty != calc_difficulty( + parent, uncle.timestamp, config=state.config): raise VerificationFailed("Difficulty mismatch") if uncle.number != parent.number + 1: raise VerificationFailed("Number mismatch") @@ -93,10 +105,12 @@ def validate_uncles(state, block): ineligible.append(uncle.hash) return True + # Block finalization state transition def finalize(state, block): """Apply rewards and commit.""" - delta = int(state.config['BLOCK_REWARD'] + state.config['NEPHEW_REWARD'] * len(block.uncles)) + delta = int(state.config['BLOCK_REWARD'] + + state.config['NEPHEW_REWARD'] * len(block.uncles)) state.delta_balance(state.block_coinbase, delta) br = state.config['BLOCK_REWARD'] @@ -106,7 +120,7 @@ def finalize(state, block): r = int(br * (udpf + uncle.number - state.block_number) // udpf) state.delta_balance(uncle.coinbase, r) - if state.block_number - state.config['MAX_UNCLE_DEPTH'] in state.recent_uncles: - del state.recent_uncles[state.block_number - state.config['MAX_UNCLE_DEPTH']] - - + if state.block_number - \ + state.config['MAX_UNCLE_DEPTH'] in state.recent_uncles: + del state.recent_uncles[state.block_number - + state.config['MAX_UNCLE_DEPTH']] diff --git a/ethereum/pow/ethash.py b/ethereum/pow/ethash.py index afbdfbb4d..d22eaee57 100644 --- a/ethereum/pow/ethash.py +++ b/ethereum/pow/ethash.py @@ -53,7 +53,9 @@ def calc_dataset(full_size, cache): percent = (full_size // HASH_BYTES) // 100 for i in range(full_size // HASH_BYTES): if i % percent == 0: - sys.stderr.write("Completed %d items, %d percent\n" % (i, i // percent)) + sys.stderr.write( + "Completed %d items, %d percent\n" % + (i, i // percent)) o.append(calc_dataset_item(cache, i)) return o @@ -94,7 +96,8 @@ def hashimoto_full(dataset, header, nonce): def mine(full_size, dataset, header, difficulty): from random import randint nonce = randint(0, 2**64) - while decode_int(hashimoto_full(full_size, dataset, header, nonce)) < difficulty: + while decode_int(hashimoto_full( + full_size, dataset, header, nonce)) < difficulty: nonce += 1 nonce %= 2**64 return nonce diff --git a/ethereum/pow/ethash_utils.py b/ethereum/pow/ethash_utils.py index f113dc977..f8f6c0fa5 100644 --- a/ethereum/pow/ethash_utils.py +++ b/ethereum/pow/ethash_utils.py @@ -1,11 +1,15 @@ try: from Crypto.Hash import keccak - sha3_256 = lambda x: keccak.new(digest_bits=256, data=x).digest() - sha3_512 = lambda x: keccak.new(digest_bits=512, data=x) -except: + + def sha3_256(x): return keccak.new(digest_bits=256, data=x).digest() + + def sha3_512(x): return keccak.new(digest_bits=512, data=x) +except BaseException: import sha3 as _sha3 - sha3_256 = lambda x: _sha3.sha3_256(x).digest() - sha3_512 = lambda x: _sha3.sha3_512(x).digest() + + def sha3_256(x): return _sha3.sha3_256(x).digest() + + def sha3_512(x): return _sha3.sha3_512(x).digest() from rlp.utils import decode_hex from ethereum.utils import encode_hex import sys @@ -49,7 +53,8 @@ def serialize_hash(h): def deserialize_hash(h): - return [decode_int(h[i:i+WORD_BYTES]) for i in range(0, len(h), WORD_BYTES)] + return [decode_int(h[i:i + WORD_BYTES]) + for i in range(0, len(h), WORD_BYTES)] def hash_words(h, sz, x): @@ -82,13 +87,15 @@ def xor(a, b): def serialize_cache(ds): return b''.join([serialize_hash(h) for h in ds]) + serialize_dataset = serialize_cache def deserialize_cache(ds): - return [deserialize_hash(ds[i:i+HASH_BYTES]) + return [deserialize_hash(ds[i:i + HASH_BYTES]) for i in range(0, len(ds), HASH_BYTES)] + deserialize_dataset = deserialize_cache @@ -103,7 +110,7 @@ def __len__(self): def __getitem__(self, i): if i >= self.len: raise Exception("listwrap access out of range") - return deserialize_hash(self.data[i*HASH_BYTES:(i+1)*HASH_BYTES]) + return deserialize_hash(self.data[i * HASH_BYTES:(i + 1) * HASH_BYTES]) def __iter__(self): for i in range(self.len): @@ -129,7 +136,8 @@ def get_cache_size(block_number): def get_full_size(block_number): - sz = DATASET_BYTES_INIT + DATASET_BYTES_GROWTH * (block_number // EPOCH_LENGTH) + sz = DATASET_BYTES_INIT + DATASET_BYTES_GROWTH * \ + (block_number // EPOCH_LENGTH) sz -= MIX_BYTES while not isprime(sz // MIX_BYTES): sz -= 2 * MIX_BYTES diff --git a/ethereum/pow/ethpow.py b/ethereum/pow/ethpow.py index f1eaa7915..d496909ef 100644 --- a/ethereum/pow/ethpow.py +++ b/ethereum/pow/ethpow.py @@ -29,7 +29,8 @@ elif ETHASH_LIB == 'pyethash': mkcache = pyethash.mkcache_bytes EPOCH_LENGTH = 30000 - hashimoto_light = lambda s, c, h, n: \ + + def hashimoto_light(s, c, h, n): return \ pyethash.hashimoto_light(s, c, h, utils.big_endian_to_int(n)) else: raise Exception("invalid ethash library set") @@ -52,7 +53,8 @@ def get_cache(block_number): c = mkcache(block_number) cache_by_seed[seed] = c if len(cache_by_seed) > cache_by_seed.max_items: - cache_by_seed.pop(cache_by_seed.keys()[0]) # remove last recently accessed + # remove last recently accessed + cache_by_seed.pop(cache_by_seed.keys()[0]) return c @@ -74,7 +76,8 @@ def check_pow(block_number, header_hash, mixhash, nonce, difficulty): mining_output = hashimoto_light(block_number, cache, header_hash, nonce) if mining_output[b'mix digest'] != mixhash: return False - return utils.big_endian_to_int(mining_output[b'result']) <= 2**256 // (difficulty or 1) + return utils.big_endian_to_int( + mining_output[b'result']) <= 2**256 // (difficulty or 1) class Miner(): @@ -114,9 +117,12 @@ 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) + 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) + 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") @@ -124,5 +130,3 @@ def mine(block_number, difficulty, mining_hash, start_nonce=0, rounds=1000): assert len(o[b"mix digest"]) == 32 return bin_nonce, o[b"mix digest"] return None, None - - diff --git a/ethereum/slogging.py b/ethereum/slogging.py index b1d346946..18c22c9ca 100644 --- a/ethereum/slogging.py +++ b/ethereum/slogging.py @@ -150,10 +150,13 @@ def _proxy(self, method_name, *args, **kwargs): trace = lambda self, *args, **kwargs: self._proxy('trace', *args, **kwargs) debug = lambda self, *args, **kwargs: self._proxy('debug', *args, **kwargs) info = lambda self, *args, **kwargs: self._proxy('info', *args, **kwargs) - warn = warning = lambda self, *args, **kwargs: self._proxy('warning', *args, **kwargs) + warn = warning = lambda self, * \ + args, **kwargs: self._proxy('warning', *args, **kwargs) error = lambda self, *args, **kwargs: self._proxy('error', *args, **kwargs) - exception = lambda self, *args, **kwargs: self._proxy('exception', *args, **kwargs) - fatal = critical = lambda self, *args, **kwargs: self._proxy('critical', *args, **kwargs) + exception = lambda self, * \ + args, **kwargs: self._proxy('exception', *args, **kwargs) + fatal = critical = lambda self, * \ + args, **kwargs: self._proxy('critical', *args, **kwargs) class _LogJSONEncoder(JSONEncoder): @@ -177,7 +180,8 @@ def is_active(self, level_name='trace'): 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['event'] = '{}.{}'.format( + self.name, msg.lower().replace(' ', '_')) message['level'] = logging.getLevelName(level) try: message.update(kwargs) @@ -250,6 +254,7 @@ def getLogger(self, name): logging.setLoggerClass(SLogger) return super(SManager, self).getLogger(name) + rootLogger = RootLogger(DEFAULT_LOGLEVEL) SLogger.root = rootLogger SLogger.manager = SManager(SLogger.root) @@ -301,7 +306,8 @@ def configure(config_string=None, log_json=False, log_file=None): handler.setFormatter(formatter) rootLogger.addHandler(handler) if log_file: - if not any(isinstance(hndlr, FileHandler) for hndlr in rootLogger.handlers): + if not any(isinstance(hndlr, FileHandler) + for hndlr in rootLogger.handlers): handler = FileHandler(log_file) formatter = Formatter("{} {}".format(FILE_PREFIX, log_format)) handler.setFormatter(formatter) @@ -323,6 +329,7 @@ def configure(config_string=None, log_json=False, log_file=None): logger.setLevel(level.upper()) logger.propagate = True + configure_logging = configure diff --git a/ethereum/snapshot.py b/ethereum/snapshot.py index ff4e34dea..6bec25f46 100644 --- a/ethereum/snapshot.py +++ b/ethereum/snapshot.py @@ -45,10 +45,10 @@ def get_ancestor_list(self, n): def create_snapshot(chain, recent=1024): - assert recent > chain.env.config['MAX_UNCLE_DEPTH']+2 + assert recent > chain.env.config['MAX_UNCLE_DEPTH'] + 2 head_block = chain.head - base_block = chain.get_block_by_number(max(head_block.number-recent, 0)) + base_block = chain.get_block_by_number(max(head_block.number - recent, 0)) return { 'base': snapshot_form(rlp.encode(base_block.header)), 'chainDifficulty': snapshot_form(chain.get_score(base_block)), @@ -103,7 +103,7 @@ def load_snapshot(chain, snapshot): # first block is child of base block first_block_rlp = scan_bin(snapshot['blocks'][0]) first_header_data = rlp.decode(first_block_rlp)[0] - head_block_rlp = scan_bin(snapshot['blocks'][limit-1]) + head_block_rlp = scan_bin(snapshot['blocks'][limit - 1]) head_header_data = rlp.decode(head_block_rlp)[0] trie = load_state(chain.env, snapshot['alloc']) @@ -115,8 +115,10 @@ def load_snapshot(chain, snapshot): print "Start loading recent blocks from snapshot" vbh = common.validate_header vus = consensus.validate_uncles + def _vbh(state, header): return True + def _vus(state, block): return True common.validate_header = _vbh @@ -132,7 +134,7 @@ def _vus(state, block): for block_rlp in snapshot['blocks'][1:]: block_rlp = scan_bin(block_rlp) block = rlp.decode(block_rlp, Block) - if count == chain.state.config['MAX_UNCLE_DEPTH']+2: + if count == chain.state.config['MAX_UNCLE_DEPTH'] + 2: consensus.validate_uncles = vus if not chain.add_block(block): print "Failed to load block #%d (%s), abort." % (block.number, encode_hex(block.hash)[:8]) diff --git a/ethereum/specials.py b/ethereum/specials.py index d79df85d8..087898ef6 100644 --- a/ethereum/specials.py +++ b/ethereum/specials.py @@ -72,10 +72,15 @@ def proc_identity(ext, msg): msg.data.extract_copy(o, 0, 0, len(o)) return 1, msg.gas - gas_cost, o + def mult_complexity(x): - if x <= 64: return x ** 2 - elif x <= 1024: return x ** 2 // 4 + 96 * x - 3072 - else: return x ** 2 // 16 + 480 * x - 199680 + if x <= 64: + return x ** 2 + elif x <= 1024: + return x ** 2 // 4 + 96 * x - 3072 + else: + return x ** 2 // 16 + 480 * x - 199680 + def proc_modexp(ext, msg): if not ext.post_metropolis_hardfork(): @@ -84,13 +89,15 @@ def proc_modexp(ext, msg): baselen = msg.data.extract32(0) explen = msg.data.extract32(32) modlen = msg.data.extract32(64) - first_exp_bytes = msg.data.extract32(96 + baselen) >> (8 * max(32 - explen, 0)) + first_exp_bytes = msg.data.extract32( + 96 + baselen) >> (8 * max(32 - explen, 0)) bitlength = -1 while first_exp_bytes: bitlength += 1 first_exp_bytes >>= 1 adjusted_explen = max(bitlength, 0) + 8 * max(explen - 32, 0) - gas_cost = (mult_complexity(max(modlen, baselen)) * max(adjusted_explen, 1)) // opcodes.GMODEXPQUADDIVISOR + gas_cost = (mult_complexity(max(modlen, baselen)) * + max(adjusted_explen, 1)) // opcodes.GMODEXPQUADDIVISOR print(baselen, explen, modlen, 'expected gas cost', gas_cost) if msg.gas < gas_cost: return 0, 0, [] @@ -106,8 +113,15 @@ def proc_modexp(ext, msg): msg.data.extract_copy(mod, 0, 96 + baselen + explen, modlen) if utils.big_endian_to_int(mod) == 0: return 1, msg.gas - gas_cost, [0] * modlen - o = pow(utils.big_endian_to_int(base), utils.big_endian_to_int(exp), utils.big_endian_to_int(mod)) - return 1, msg.gas - gas_cost, [safe_ord(x) for x in utils.zpad(utils.int_to_big_endian(o), modlen)] + o = pow( + utils.big_endian_to_int(base), + utils.big_endian_to_int(exp), + utils.big_endian_to_int(mod)) + return 1, msg.gas - \ + gas_cost, [ + safe_ord(x) for x in utils.zpad( + utils.int_to_big_endian(o), modlen)] + def validate_point(x, y): import py_ecc.optimized_bn128 as bn128 @@ -122,6 +136,7 @@ def validate_point(x, y): p1 = (FQ(1), FQ(1), FQ(0)) return p1 + def proc_ecadd(ext, msg): if not ext.post_metropolis_hardfork(): return 1, msg.gas, [] @@ -139,7 +154,10 @@ def proc_ecadd(ext, msg): if p1 is False or p2 is False: return 0, 0, [] o = bn128.normalize(bn128.add(p1, p2)) - return 1, msg.gas - opcodes.GECADD, [safe_ord(x) for x in (encode_int32(o[0].n) + encode_int32(o[1].n))] + return 1, msg.gas - \ + opcodes.GECADD, [safe_ord(x) for x in ( + encode_int32(o[0].n) + encode_int32(o[1].n))] + def proc_ecmul(ext, msg): if not ext.post_metropolis_hardfork(): @@ -159,6 +177,7 @@ def proc_ecmul(ext, msg): return (1, msg.gas - opcodes.GECMUL, [safe_ord(c) for c in (encode_int32(o[0].n) + encode_int32(o[1].n))]) + def proc_ecpairing(ext, msg): if not ext.post_metropolis_hardfork(): return 1, msg.gas, [] @@ -200,6 +219,7 @@ def proc_ecpairing(ext, msg): result = bn128.final_exponentiate(exponent) == bn128.FQ12.one() return 1, msg.gas - gascost, [0] * 31 + [1 if result else 0] + specials = { decode_hex(k): v for k, v in { diff --git a/ethereum/state.py b/ethereum/state.py index eeb1c12cd..fc11c4397 100644 --- a/ethereum/state.py +++ b/ethereum/state.py @@ -25,6 +25,7 @@ THREE = b'\x00' * 19 + b'\x03' + def snapshot_form(val): if is_numeric(val): return str(val) @@ -49,6 +50,7 @@ def snapshot_form(val): "refunds": 0, } + class Account(rlp.Serializable): fields = [ @@ -95,7 +97,8 @@ def code(self, value): def get_storage_data(self, key): if key not in self.storage_cache: v = self.storage_trie.get(utils.encode_int32(key)) - self.storage_cache[key] = utils.big_endian_to_int(rlp.decode(v) if v else b'') + self.storage_cache[key] = utils.big_endian_to_int( + rlp.decode(v) if v else b'') return self.storage_cache[key] def set_storage_data(self, key, value): @@ -114,18 +117,20 @@ def is_blank(self): @property def exists(self): if self.is_blank(): - return self.touched or (self.existent_at_start and not self.deleted) + return self.touched or ( + self.existent_at_start and not self.deleted) return True def to_dict(self): odict = self.storage_trie.to_dict() for k, v in self.storage_cache.items(): odict[utils.encode_int(k)] = rlp.encode(utils.encode_int(v)) - return {'balance': str(self.balance), 'nonce': str(self.nonce), 'code': '0x'+encode_hex(self.code), - 'storage': {'0x'+encode_hex(key.lstrip(b'\x00') or b'\x00'): - '0x'+encode_hex(rlp.decode(val)) for key, val in odict.items()} } + return {'balance': str(self.balance), 'nonce': str(self.nonce), 'code': '0x' + encode_hex(self.code), + 'storage': {'0x' + encode_hex(key.lstrip(b'\x00') or b'\x00'): + '0x' + encode_hex(rlp.decode(val)) for key, val in odict.items()}} -#from ethereum.state import State + +# from ethereum.state import State class State(): def __init__(self, root=b'', env=Env(), executing_on_head=False, **kwargs): @@ -163,7 +168,7 @@ def get_and_cache_account(self, address): return self.cache[address] if self.executing_on_head and False: try: - rlpdata = self.db.get(b'address:'+address) + rlpdata = self.db.get(b'address:' + address) except KeyError: rlpdata = b'' else: @@ -171,20 +176,24 @@ def get_and_cache_account(self, address): if rlpdata != trie.BLANK_NODE: o = rlp.decode(rlpdata, Account, env=self.env, address=address) else: - o = Account.blank_account(self.env, address, self.config['ACCOUNT_INITIAL_NONCE']) + o = Account.blank_account( + self.env, address, self.config['ACCOUNT_INITIAL_NONCE']) self.cache[address] = o o._mutable = True o._cached_rlp = None return o def get_balance(self, address): - return self.get_and_cache_account(utils.normalize_address(address)).balance + return self.get_and_cache_account( + utils.normalize_address(address)).balance def get_code(self, address): - return self.get_and_cache_account(utils.normalize_address(address)).code + return self.get_and_cache_account( + utils.normalize_address(address)).code def get_nonce(self, address): - return self.get_and_cache_account(utils.normalize_address(address)).nonce + return self.get_and_cache_account( + utils.normalize_address(address)).nonce def set_and_journal(self, acct, param, val): # self.journal.append((acct, param, getattr(acct, param))) @@ -221,9 +230,10 @@ def increment_nonce(self, address): newnonce = acct.nonce + 1 self.set_and_journal(acct, 'nonce', newnonce) self.set_and_journal(acct, 'touched', True) - + def get_storage_data(self, address, key): - return self.get_and_cache_account(utils.normalize_address(address)).get_storage_data(key) + return self.get_and_cache_account( + utils.normalize_address(address)).get_storage_data(key) def set_storage_data(self, address, key, value): acct = self.get_and_cache_account(utils.normalize_address(address)) @@ -252,11 +262,13 @@ def add_refund(self, value): self.journal.append(lambda: setattr(self.refunds, preval)) def snapshot(self): - return (self.trie.root_hash, len(self.journal), {k: copy.copy(getattr(self, k)) for k in STATE_DEFAULTS}) + return (self.trie.root_hash, len(self.journal), { + k: copy.copy(getattr(self, k)) for k in STATE_DEFAULTS}) def revert(self, snapshot): h, L, auxvars = snapshot - three_touched = self.cache[THREE].touched if THREE in self.cache else False # Compatibility with weird geth+parity bug + # Compatibility with weird geth+parity bug + three_touched = self.cache[THREE].touched if THREE in self.cache else False while len(self.journal) > L: try: lastitem = self.journal.pop() @@ -269,7 +281,7 @@ def revert(self, snapshot): self.cache = {} for k in STATE_DEFAULTS: setattr(self, k, copy.copy(auxvars[k])) - if three_touched and 2675000 < self.block_number < 2675200 : # Compatibility with weird geth+parity bug + if three_touched and 2675000 < self.block_number < 2675200: # Compatibility with weird geth+parity bug self.delta_balance(THREE, 0) def set_param(self, k, v): @@ -278,36 +290,51 @@ def set_param(self, k, v): setattr(self, k, v) def is_SERENITY(self, at_fork_height=False): - if at_fork_height: return self.block_number == self.config['SERENITY_FORK_BLKNUM'] - else: return self.block_number >= self.config['SERENITY_FORK_BLKNUM'] + if at_fork_height: + return self.block_number == self.config['SERENITY_FORK_BLKNUM'] + else: + return self.block_number >= self.config['SERENITY_FORK_BLKNUM'] def is_HOMESTEAD(self, at_fork_height=False): - if at_fork_height: return self.block_number == self.config['HOMESTEAD_FORK_BLKNUM'] - else: return self.block_number >= self.config['HOMESTEAD_FORK_BLKNUM'] + if at_fork_height: + return self.block_number == self.config['HOMESTEAD_FORK_BLKNUM'] + else: + return self.block_number >= self.config['HOMESTEAD_FORK_BLKNUM'] def is_METROPOLIS(self, at_fork_height=False): - if at_fork_height: return self.block_number == self.config['METROPOLIS_FORK_BLKNUM'] - else: return self.block_number >= self.config['METROPOLIS_FORK_BLKNUM'] + if at_fork_height: + return self.block_number == self.config['METROPOLIS_FORK_BLKNUM'] + else: + return self.block_number >= self.config['METROPOLIS_FORK_BLKNUM'] def is_CONSTANTINOPLE(self, at_fork_height=False): - if at_fork_height: return self.block_number == self.config['CONSTANTINOPLE_FORK_BLKNUM'] - else: return self.block_number >= self.config['CONSTANTINOPLE_FORK_BLKNUM'] + if at_fork_height: + return self.block_number == self.config['CONSTANTINOPLE_FORK_BLKNUM'] + else: + return self.block_number >= self.config['CONSTANTINOPLE_FORK_BLKNUM'] def is_ANTI_DOS(self, at_fork_height=False): - if at_fork_height: return self.block_number == self.config['ANTI_DOS_FORK_BLKNUM'] - else: return self.block_number >= self.config['ANTI_DOS_FORK_BLKNUM'] + if at_fork_height: + return self.block_number == self.config['ANTI_DOS_FORK_BLKNUM'] + else: + return self.block_number >= self.config['ANTI_DOS_FORK_BLKNUM'] def is_SPURIOUS_DRAGON(self, at_fork_height=False): - if at_fork_height: return self.block_number == self.config['SPURIOUS_DRAGON_FORK_BLKNUM'] - else: return self.block_number >= self.config['SPURIOUS_DRAGON_FORK_BLKNUM'] + if at_fork_height: + return self.block_number == self.config['SPURIOUS_DRAGON_FORK_BLKNUM'] + else: + return self.block_number >= self.config['SPURIOUS_DRAGON_FORK_BLKNUM'] def is_DAO(self, at_fork_height=False): - if at_fork_height: return self.block_number == self.config['DAO_FORK_BLKNUM'] - else: return self.block_number >= self.config['DAO_FORK_BLKNUM'] + if at_fork_height: + return self.block_number == self.config['DAO_FORK_BLKNUM'] + else: + return self.block_number >= self.config['DAO_FORK_BLKNUM'] def account_exists(self, address): if self.is_SPURIOUS_DRAGON(): - o = not self.get_and_cache_account(utils.normalize_address(address)).is_blank() + o = not self.get_and_cache_account( + utils.normalize_address(address)).is_blank() else: a = self.get_and_cache_account(address) if a.deleted and not a.touched: @@ -327,7 +354,8 @@ def transfer_value(self, from_addr, to_addr, value): return False def account_to_dict(self, address): - return self.get_and_cache_account(utils.normalize_address(address)).to_dict() + return self.get_and_cache_account( + utils.normalize_address(address)).to_dict() def commit(self, allow_empties=False): for addr, acct in self.cache.items(): @@ -338,11 +366,11 @@ def commit(self, allow_empties=False): if self.account_exists(addr) or allow_empties: self.trie.update(addr, rlp.encode(acct)) if self.executing_on_head: - self.db.put(b'address:'+addr, rlp.encode(acct)) + self.db.put(b'address:' + addr, rlp.encode(acct)) else: self.trie.delete(addr) if self.executing_on_head: - self.db.delete(b'address:'+addr) + self.db.delete(b'address:' + addr) self.deletes.extend(self.trie.deletes) self.trie.deletes = [] self.cache = {} @@ -351,15 +379,24 @@ def commit(self, allow_empties=False): def to_dict(self): for addr in self.trie.to_dict().keys(): self.get_and_cache_account(addr) - return {encode_hex(addr): acct.to_dict() for addr, acct in self.cache.items()} + return {encode_hex(addr): acct.to_dict() + for addr, acct in self.cache.items()} def del_account(self, address): self.set_balance(address, 0) self.set_nonce(address, 0) self.set_code(address, b'') self.reset_storage(address) - self.set_and_journal(self.get_and_cache_account(utils.normalize_address(address)), 'deleted', True) - self.set_and_journal(self.get_and_cache_account(utils.normalize_address(address)), 'touched', False) + self.set_and_journal( + self.get_and_cache_account( + utils.normalize_address(address)), + 'deleted', + True) + self.set_and_journal( + self.get_and_cache_account( + utils.normalize_address(address)), + 'touched', + False) # self.set_and_journal(self.get_and_cache_account(utils.normalize_address(address)), 'existent_at_start', False) def reset_storage(self, address): @@ -368,7 +405,11 @@ def reset_storage(self, address): acct.storage_cache = {} self.journal.append(lambda: setattr(acct, 'storage_cache', pre_cache)) pre_root = acct.storage_trie.root_hash - self.journal.append(lambda: setattr(acct.storage_trie, 'root_hash', pre_root)) + self.journal.append( + lambda: setattr( + acct.storage_trie, + 'root_hash', + pre_root)) acct.storage_trie.root_hash = BLANK_ROOT # Creates a snapshot from a state @@ -377,7 +418,7 @@ def to_snapshot(self, root_only=False, no_prevblocks=False): 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) + snapshot["state_root"] = '0x' + encode_hex(self.trie.root_hash) else: # "Full" snapshot snapshot["alloc"] = self.to_dict() @@ -388,17 +429,19 @@ def to_snapshot(self, root_only=False, no_prevblocks=False): if is_numeric(default): snapshot[k] = str(v) elif isinstance(default, (str, bytes)): - snapshot[k] = '0x'+encode_hex(v) + 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']]] + 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()} + snapshot[k] = {str(n): ['0x' + encode_hex(h) + for h in headers] for n, headers in v.items()} return snapshot # Creates a state from a snapshot @classmethod def from_snapshot(cls, snapshot_data, env, executing_on_head=False): - state = State(env = env) + state = State(env=env) if "alloc" in snapshot_data: for addr, data in snapshot_data["alloc"].items(): if len(addr) == 40: @@ -414,18 +457,22 @@ def from_snapshot(cls, snapshot_data, env, executing_on_head=False): 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, parse_as_bin(k), parse_as_bin(v)) + state.set_storage_data( + addr, parse_as_bin(k), 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") + 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) + 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) + 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] @@ -448,7 +495,6 @@ def from_snapshot(cls, snapshot_data, env, executing_on_head=False): state.changed = {} return state - def ephemeral_clone(self): snapshot = self.to_snapshot(root_only=True, no_prevblocks=True) env2 = Env(OverlayDB(self.env.db), self.env.config) @@ -466,18 +512,19 @@ def ephemeral_clone(self): def prev_header_to_dict(h): return { - "hash": '0x'+encode_hex(h.hash), + "hash": '0x' + encode_hex(h.hash), "number": str(h.number), "timestamp": str(h.timestamp), "difficulty": str(h.difficulty), "gas_used": str(h.gas_used), "gas_limit": str(h.gas_limit), - "uncles_hash": '0x'+encode_hex(h.uncles_hash) + "uncles_hash": '0x' + encode_hex(h.uncles_hash) } BLANK_UNCLES_HASH = sha3(rlp.encode([])) + def dict_to_prev_header(h): return FakeHeader(hash=parse_as_bin(h['hash']), number=parse_as_int(h['number']), @@ -485,4 +532,4 @@ def dict_to_prev_header(h): difficulty=parse_as_int(h['difficulty']), gas_used=parse_as_int(h.get('gas_used', '0')), gas_limit=parse_as_int(h['gas_limit']), - uncles_hash=parse_as_bin(h.get('uncles_hash', '0x'+encode_hex(BLANK_UNCLES_HASH)))) + uncles_hash=parse_as_bin(h.get('uncles_hash', '0x' + encode_hex(BLANK_UNCLES_HASH)))) diff --git a/ethereum/tests/test_abi.py b/ethereum/tests/test_abi.py index 570f328e6..dbb78ddd6 100644 --- a/ethereum/tests/test_abi.py +++ b/ethereum/tests/test_abi.py @@ -20,9 +20,12 @@ def test_abi_encode_signed_int(): assert abi.decode_abi(['int8'], abi.encode_abi(['int8'], [1]))[0] == 1 assert abi.decode_abi(['int8'], abi.encode_abi(['int8'], [-1]))[0] == -1 + def test_abi_encode_single_int(): - assert abi.encode_single(['int', '256', []], -2**255) == (b'\x80'+b'\x00'*31) - assert abi.encode_single(['int', '256', []], (b'\x80'+b'\x00'*31)) == (b'\x80'+b'\x00'*31) + assert abi.encode_single(['int', '256', []], -2 ** + 255) == (b'\x80' + b'\x00' * 31) + assert abi.encode_single( + ['int', '256', []], (b'\x80' + b'\x00' * 31)) == (b'\x80' + b'\x00' * 31) assert abi.encode_single(['int', '8', []], -128)[-1:] == b'\x80' with pytest.raises(abi.ValueOutOfBounds): @@ -32,40 +35,67 @@ def test_abi_encode_single_int(): with pytest.raises(abi.ValueOutOfBounds): assert abi.encode_single(['int', '8', []], 128) + def test_abi_encode_single_ufixed(): - assert abi.encode_single(['ufixed', '128x128', []], 0) == (b'\x00'*32) - assert abi.encode_single(['ufixed', '128x128', []], 1.125) == (b'\x00'*15 + b'\x01\x20' + b'\x00'*15) - assert abi.encode_single(['ufixed', '128x128', []], 2**127-1) == (b'\x7f' + b'\xff'*15 + b'\x00'*16) + assert abi.encode_single(['ufixed', '128x128', []], 0) == (b'\x00' * 32) + assert abi.encode_single(['ufixed', '128x128', []], 1.125) == ( + b'\x00' * 15 + b'\x01\x20' + b'\x00' * 15) + assert abi.encode_single(['ufixed', '128x128', []], 2 ** + 127 - 1) == (b'\x7f' + b'\xff' * 15 + b'\x00' * 16) + def test_abi_encode_single_fixed(): - assert abi.encode_single(['fixed', '128x128', []], 1.125) == (b'\x00'*15 + b'\x01\x20' + b'\x00'*15) - assert abi.encode_single(['fixed', '128x128', []], -1.125) == (b'\xff'*15 + b'\xfe' + b'\xe0' + b'\x00'*15) + assert abi.encode_single(['fixed', '128x128', []], 1.125) == ( + b'\x00' * 15 + b'\x01\x20' + b'\x00' * 15) + assert abi.encode_single(['fixed', '128x128', []], - + 1.125) == (b'\xff' * + 15 + + b'\xfe' + + b'\xe0' + + b'\x00' * + 15) + def test_abi_encode_single_hash(): - assert abi.encode_single(['hash', '8', []], b'\x00'*8) == b'\x00'*32 - assert abi.encode_single(['hash', '8', []], '00'*8) == b'\x00'*32 + assert abi.encode_single(['hash', '8', []], b'\x00' * 8) == b'\x00' * 32 + assert abi.encode_single(['hash', '8', []], '00' * 8) == b'\x00' * 32 + def test_abi_decode_single_hash(): typ = ['hash', '8', []] - assert b'\x01'*8 == abi.decode_single(typ, abi.encode_single(typ, b'\x01'*8)) + assert b'\x01' * \ + 8 == abi.decode_single(typ, abi.encode_single(typ, b'\x01' * 8)) + def test_abi_decode_single_bytes(): typ = ['bytes', '8', []] - assert (b'\x01\x02' + b'\x00'*6) == abi.decode_single(typ, abi.encode_single(typ, b'\x01\x02')) + assert ( + b'\x01\x02' + + b'\x00' * + 6) == abi.decode_single( + typ, + abi.encode_single( + typ, + b'\x01\x02')) typ = ['bytes', '', []] - assert b'\x01\x02' == abi.decode_single(typ, abi.encode_single(typ, b'\x01\x02')) + assert b'\x01\x02' == abi.decode_single( + typ, abi.encode_single(typ, b'\x01\x02')) + def test_abi_encode_single_prefixed_address(): - prefixed_address = '0x' + '0'*40 - assert abi.encode_single(['address', '', []], prefixed_address) == b'\x00' * 32 + prefixed_address = '0x' + '0' * 40 + assert abi.encode_single( + ['address', '', []], prefixed_address) == b'\x00' * 32 + def test_abi_decode_single_fixed(): fixed_data = abi.encode_single(['fixed', '128x128', []], 1) assert abi.decode_single(['fixed', '128x128', []], fixed_data) == 1 - fixed_data = abi.encode_single(['fixed', '128x128', []], 2**127-1) - assert abi.decode_single(['fixed', '128x128', []], fixed_data) == (2**127-1)*1.0 + fixed_data = abi.encode_single(['fixed', '128x128', []], 2**127 - 1) + assert abi.decode_single(['fixed', '128x128', []], + fixed_data) == (2**127 - 1) * 1.0 fixed_data = abi.encode_single(['fixed', '128x128', []], -1) assert abi.decode_single(['fixed', '128x128', []], fixed_data) == -1 @@ -73,6 +103,7 @@ def test_abi_decode_single_fixed(): fixed_data = abi.encode_single(['fixed', '128x128', []], -2**127) assert abi.decode_single(['fixed', '128x128', []], fixed_data) == -2**127 + # Will be parametrized fron json fixtures def test_state(filename, testname, testdata): print(testdata) diff --git a/ethereum/tests/test_blocks.py b/ethereum/tests/test_blocks.py index 271f3c971..94cc26675 100644 --- a/ethereum/tests/test_blocks.py +++ b/ethereum/tests/test_blocks.py @@ -84,10 +84,13 @@ def run_block_test(params, config_overrides=None): # print(c.state.to_dict()) # print(params["pre"]) assert c.state.env == env - assert c.state.prev_headers[0].state_root == safe_decode(params["genesisBlockHeader"]["stateRoot"]), (encode_hex(c.state.prev_headers[0].state_root), params["genesisBlockHeader"]["stateRoot"]) - assert c.state.trie.root_hash == safe_decode(params["genesisBlockHeader"]["stateRoot"]) - assert c.state.prev_headers[0].hash == safe_decode(params["genesisBlockHeader"]["hash"]) - + assert c.state.prev_headers[0].state_root == safe_decode( + params["genesisBlockHeader"]["stateRoot"]), (encode_hex( + c.state.prev_headers[0].state_root), params["genesisBlockHeader"]["stateRoot"]) + assert c.state.trie.root_hash == safe_decode( + params["genesisBlockHeader"]["stateRoot"]) + assert c.state.prev_headers[0].hash == safe_decode( + params["genesisBlockHeader"]["hash"]) for blk in params["blocks"]: if 'blockHeader' not in blk: @@ -96,7 +99,7 @@ def run_block_test(params, config_overrides=None): rlpdata = safe_decode(blk["rlp"][2:]) success = c.add_block(rlp.decode(rlpdata, Block)) except (ValueError, TypeError, AttributeError, VerificationFailed, - DecodingError, DeserializationError, InvalidTransaction, + DecodingError, DeserializationError, InvalidTransaction, InvalidNonce, KeyError) as e: success = False assert not success @@ -105,28 +108,29 @@ def run_block_test(params, config_overrides=None): assert c.add_block(rlp.decode(rlpdata, Block)) env.config = old_config + def get_config_overrides(network): # Home DAO Tang Spur Byz Const if network == 'Frontier': values = 2**99, 2**99, 2**99, 2**99, 2**99, 2**99 elif network == 'Homestead': - values = 0 , 2**99, 2**99, 2**99, 2**99, 2**99 + values = 0, 2**99, 2**99, 2**99, 2**99, 2**99 elif network == 'EIP150': - values = 0 , 2**99, 0 , 2**99, 2**99, 2**99 + values = 0, 2**99, 0, 2**99, 2**99, 2**99 elif network == 'EIP158': - values = 0 , 2**99, 0 , 0 , 2**99, 2**99 + values = 0, 2**99, 0, 0, 2**99, 2**99 elif network == 'Byzantium': - values = 0 , 2**99, 0 , 0 , 0 , 2**99 + values = 0, 2**99, 0, 0, 0, 2**99 elif network == 'Constantinople': - values = 0 , 2**99, 0 , 0 , 0 , 0 + values = 0, 2**99, 0, 0, 0, 0 elif network == 'FrontierToHomesteadAt5': - values = 5 , 2**99, 2**99, 2**99, 2**99, 2**99 + values = 5, 2**99, 2**99, 2**99, 2**99, 2**99 elif network == 'HomesteadToEIP150At5': - values = 0 , 2**99, 5 , 2**99, 2**99, 2**99 + values = 0, 2**99, 5, 2**99, 2**99, 2**99 elif network == 'HomesteadToDaoAt5': - values = 0 , 5 , 2**99, 2**99, 2**99, 2**99 + values = 0, 5, 2**99, 2**99, 2**99, 2**99 elif network == 'EIP158ToByzantiumAt5': - values = 0 , 2**99, 0 , 0 , 5 , 2**99 + values = 0, 2**99, 0, 0, 5, 2**99 return { 'HOMESTEAD_FORK_BLKNUM': values[0], 'DAO_FORK_BLKNUM': values[1], @@ -145,22 +149,33 @@ def test_block(filename, testname, testdata): ('bcWalletTest.json', u'walletReorganizeOwners'), ('bl10251623GO.json', u'randomBlockTest'), ('bl201507071825GO.json', u'randomBlockTest'), - ('call_OOG_additionalGasCosts2.json', 'call_OOG_additionalGasCosts2_d0g0v0_EIP158'), + ('call_OOG_additionalGasCosts2.json', + 'call_OOG_additionalGasCosts2_d0g0v0_EIP158'), ('MLOAD_Bounds.json', 'MLOAD_Bounds_d0g0v0_EIP158'), - ('RevertDepthCreateAddressCollision.json', 'RevertDepthCreateAddressCollision_d0g0v0_EIP158'), - ('RevertDepthCreateAddressCollision.json', 'RevertDepthCreateAddressCollision_d0g0v1_EIP158'), - ('RevertDepthCreateAddressCollision.json', 'RevertDepthCreateAddressCollision_d0g1v0_EIP158'), - ('RevertDepthCreateAddressCollision.json', 'RevertDepthCreateAddressCollision_d0g1v1_EIP158'), - ('RevertDepthCreateAddressCollision.json', 'RevertDepthCreateAddressCollision_d1g0v0_EIP158'), - ('RevertDepthCreateAddressCollision.json', 'RevertDepthCreateAddressCollision_d1g0v1_EIP158'), - ('RevertDepthCreateAddressCollision.json', 'RevertDepthCreateAddressCollision_d1g1v0_EIP158'), - ('RevertDepthCreateAddressCollision.json', 'RevertDepthCreateAddressCollision_d1g1v1_EIP158'), + ('RevertDepthCreateAddressCollision.json', + 'RevertDepthCreateAddressCollision_d0g0v0_EIP158'), + ('RevertDepthCreateAddressCollision.json', + 'RevertDepthCreateAddressCollision_d0g0v1_EIP158'), + ('RevertDepthCreateAddressCollision.json', + 'RevertDepthCreateAddressCollision_d0g1v0_EIP158'), + ('RevertDepthCreateAddressCollision.json', + 'RevertDepthCreateAddressCollision_d0g1v1_EIP158'), + ('RevertDepthCreateAddressCollision.json', + 'RevertDepthCreateAddressCollision_d1g0v0_EIP158'), + ('RevertDepthCreateAddressCollision.json', + 'RevertDepthCreateAddressCollision_d1g0v1_EIP158'), + ('RevertDepthCreateAddressCollision.json', + 'RevertDepthCreateAddressCollision_d1g1v0_EIP158'), + ('RevertDepthCreateAddressCollision.json', + 'RevertDepthCreateAddressCollision_d1g1v1_EIP158'), ('bcTheDaoTest.json', 'DaoTransactions_UncleExtradata'), ('bcTheDaoTest.json', 'DaoTransactions'), ('failed_tx_xcf416c53_d0g0v0.json', 'failed_tx_xcf416c53_d0g0v0_EIP158'), - ('createJS_ExampleContract_d0g0v0.json', 'createJS_ExampleContract_d0g0v0_EIP158'), + ('createJS_ExampleContract_d0g0v0.json', + 'createJS_ExampleContract_d0g0v0_EIP158'), } + def exclude(filename, testname, _): if 'MemoryStressTest' in filename or 'QuadraticComplexityTest' in filename: return True @@ -175,7 +190,8 @@ def pytest_generate_tests(metafunc): testutils.generate_test_params( 'BlockchainTests', metafunc, - skip_func=lambda filename, testname, _: (filename.split('/')[-1], testname) in skips, + skip_func=lambda filename, testname, _: ( + filename.split('/')[-1], testname) in skips, exclude_func=exclude, ) @@ -187,14 +203,21 @@ def main(): for filename, tests in list(fixtures.items()): for testname, testdata in list(tests.items()): if testname == sys.argv[2]: - print("Testing specified test: %s %s" % (filename, testname)) - run_block_test(testdata, get_config_overrides(testdata["network"])) + print( + "Testing specified test: %s %s" % + (filename, testname)) + run_block_test( + testdata, get_config_overrides( + testdata["network"])) else: for filename, tests in list(fixtures.items()): for testname, testdata in list(tests.items()): - if (filename.split('/')[-1], testname) not in skips and not exclude(filename, testname, None): + if (filename.split( + '/')[-1], testname) not in skips and not exclude(filename, testname, None): print("Testing : %s %s" % (filename, testname)) - run_block_test(testdata, get_config_overrides(testdata["network"])) + run_block_test( + testdata, get_config_overrides( + testdata["network"])) if __name__ == '__main__': diff --git a/ethereum/tests/test_bloom.py b/ethereum/tests/test_bloom.py index 668481b94..5734f64af 100644 --- a/ethereum/tests/test_bloom.py +++ b/ethereum/tests/test_bloom.py @@ -23,7 +23,8 @@ def vm_tests_fixtures(): # FIXME: assert that repo is uptodate # cd fixtures; git pull origin develop; cd ..; git commit fixtures filenames = os.listdir(os.path.join(testutils.fixture_path, 'VMTests')) - files = [os.path.join(testutils.fixture_path, 'VMTests', f) for f in filenames] + files = [os.path.join(testutils.fixture_path, 'VMTests', f) + for f in filenames] vm_fixtures = {} try: for f, fn in zip(files, filenames): @@ -39,6 +40,7 @@ def vm_tests_fixtures(): def gen_func(testdata): return lambda: do_test_bloom(testdata) + for filename, tests in list(vm_tests_fixtures().items()): for testname, testdata in list(tests.items()): if 'logs' not in testdata or 'log' not in testname.lower(): diff --git a/ethereum/tests/test_chain.py b/ethereum/tests/test_chain.py index c51297b1f..da248ef93 100644 --- a/ethereum/tests/test_chain.py +++ b/ethereum/tests/test_chain.py @@ -27,6 +27,8 @@ @pytest.fixture(scope='function') def db(): return EphemDB() + + alt_db = db @@ -39,7 +41,8 @@ def accounts(): return k, v, k2, v2 -def mine_on_chain(chain, parent=None, transactions=[], coinbase=None, timestamp=None): +def mine_on_chain(chain, parent=None, transactions=[], + coinbase=None, timestamp=None): """Mine the next block on a chain. The newly mined block will be considered to be the head of the chain, @@ -55,7 +58,7 @@ def mine_on_chain(chain, parent=None, transactions=[], coinbase=None, timestamp= txqueue.add_transaction(t) parent_timestamp = parent.timestamp if parent else chain.state.timestamp hc, _ = meta.make_head_candidate(chain, txqueue, parent, - timestamp or parent_timestamp + 1, coinbase or b'\x00'*20) + timestamp or parent_timestamp + 1, coinbase or b'\x00' * 20) assert hc.difficulty == 1 m = ethpow.Miner(hc) rounds = 100 @@ -125,10 +128,14 @@ def test_mine_block(db): blk3 = mine_next_block(chain, coinbase=v) blk4 = mine_next_block(chain, coinbase=v) blk5 = mine_next_block(chain, coinbase=v) - assert chain.state.get_balance(v) == chain.env.config['BLOCK_REWARD'] + chain.mk_poststate_of_blockhash(blk4.hash).get_balance(v) - assert chain.state.get_balance(v) == chain.env.config['BLOCK_REWARD'] * 2 + chain.mk_poststate_of_blockhash(blk3.hash).get_balance(v) - assert chain.state.get_balance(v) == chain.env.config['BLOCK_REWARD'] * 3 + chain.mk_poststate_of_blockhash(blk2.hash).get_balance(v) - assert chain.state.get_balance(v) == chain.env.config['BLOCK_REWARD'] * 4 + chain.mk_poststate_of_blockhash(genesis_hash).get_balance(v) + assert chain.state.get_balance( + v) == chain.env.config['BLOCK_REWARD'] + chain.mk_poststate_of_blockhash(blk4.hash).get_balance(v) + assert chain.state.get_balance( + v) == chain.env.config['BLOCK_REWARD'] * 2 + chain.mk_poststate_of_blockhash(blk3.hash).get_balance(v) + assert chain.state.get_balance( + v) == chain.env.config['BLOCK_REWARD'] * 3 + chain.mk_poststate_of_blockhash(blk2.hash).get_balance(v) + assert chain.state.get_balance( + v) == chain.env.config['BLOCK_REWARD'] * 4 + chain.mk_poststate_of_blockhash(genesis_hash).get_balance(v) assert blk2.prevhash == genesis_hash @@ -209,9 +216,9 @@ def test_invalid_transaction(db): def test_prevhash(db): chain = Chain({}, difficulty=1) L1 = mine_on_chain(chain) - assert chain.state.get_block_hash(0) != b'\x00'*32 - assert chain.state.get_block_hash(1) != b'\x00'*32 - assert chain.state.get_block_hash(2) == b'\x00'*32 + assert chain.state.get_block_hash(0) != b'\x00' * 32 + assert chain.state.get_block_hash(1) != b'\x00' * 32 + assert chain.state.get_block_hash(2) == b'\x00' * 32 def test_genesis_chain(db): @@ -329,19 +336,23 @@ def test_reward_uncles(db): uncle_coinbase = decode_hex('2' * 40) # Mine the uncle uncle = mine_on_chain(chain, blk0, coinbase=uncle_coinbase) - assert chain.state.get_balance(uncle_coinbase) == 1 * chain.env.config['BLOCK_REWARD'] + assert chain.state.get_balance( + uncle_coinbase) == 1 * chain.env.config['BLOCK_REWARD'] # Mine the first block in the "intended main chain" blk1 = mine_on_chain(chain, blk0, coinbase=local_coinbase) # next block should reward uncles blk2 = mine_on_chain(chain, blk1, coinbase=local_coinbase) - # print [x.hash for x in chain.get_chain()], [blk0.hash, uncle.hash, blk1.hash, blk2.hash] + # print [x.hash for x in chain.get_chain()], [blk0.hash, uncle.hash, + # blk1.hash, blk2.hash] assert blk1.hash in chain assert uncle.header.hash in [u.hash for u in blk2.uncles] assert chain.head == blk2 assert chain.get_chain() == [blk0, blk1, blk2] assert chain.state.get_balance(local_coinbase) == \ - 2 * chain.env.config['BLOCK_REWARD'] + chain.env.config['NEPHEW_REWARD'] - assert chain.state.get_balance(uncle_coinbase) == chain.env.config['BLOCK_REWARD'] * 7 // 8 + 2 * chain.env.config['BLOCK_REWARD'] + \ + chain.env.config['NEPHEW_REWARD'] + assert chain.state.get_balance( + uncle_coinbase) == chain.env.config['BLOCK_REWARD'] * 7 // 8 # TODO ########################################## diff --git a/ethereum/tests/test_contracts.py b/ethereum/tests/test_contracts.py index dcc39d857..1e6f4713a 100644 --- a/ethereum/tests/test_contracts.py +++ b/ethereum/tests/test_contracts.py @@ -105,6 +105,7 @@ def test_with(): # Test Serpent's import mechanism + mul2_code = """ def double(v): log(v) @@ -161,6 +162,7 @@ def test_inset(): # Inset at the end instead + inset_inner_code2 = """ def g(n): return(n + 10) @@ -190,7 +192,7 @@ def test_inset2(): # Test a simple namecoin implementation -namecoin_code =""" +namecoin_code = """ def main(k, v): if !self.storage[k]: self.storage[k] = v @@ -214,6 +216,7 @@ def test_namecoin(): # Test a simple currency implementation + currency_code = """ data balances[2^160] @@ -250,6 +253,7 @@ def test_currency(): # Test a data feed + data_feed_code = """ data creator data values[] @@ -288,6 +292,7 @@ def test_data_feeds(): # Test an example hedging contract, using the data feed. This tests # contracts calling other contracts + hedge_code = """ extern datafeed: [set:ii, get:i] @@ -467,6 +472,7 @@ def test_reverter(): # Test stateless contracts + add1_code = """ def main(x): self.storage[1] += x @@ -510,6 +516,7 @@ def test_array(): x = c.contract(array_code, language='serpent') assert x.main() == [1] + array_code2 = """ def main(): a = array(1) @@ -524,6 +531,7 @@ def test_array2(): x = c.contract(array_code2, language='serpent') assert x.main() == [1] + array_code3 = """ def main(): a = array(3) @@ -643,8 +651,8 @@ def test_storage_objects(): assert 0 == x.query_items(0, 2) assert 9 == x.query_items(1, 2) assert [555, 556, 656, 559, 1659, - 557, 0, 0, 0, 558, - 657, 0, 0, 0, 658] == x.query_person() + 557, 0, 0, 0, 558, + 657, 0, 0, 0, 658] == x.query_person() assert [361, 441] == x.testping(19, 21) @@ -710,8 +718,9 @@ def test_infinite_storage_objects(): assert 0 == x.query_items(0, 2) assert 9 == x.query_items(1, 2) assert [555, 556, 656, 559, 1659, - 557, 0, 0, 0, 558, - 657, 0, 0, 0, 658] == x.query_person() + 557, 0, 0, 0, 558, + 657, 0, 0, 0, 658] == x.query_person() + fail1 = """ data person(head, arms[2](elbow, fingers[5]), legs[2]) @@ -824,6 +833,7 @@ def test_returnarray_code(): x = c.contract(working_returnarray_code, language='serpent') assert x.main() == [1, 2, 3] + crowdfund_code = """ data campaigns[2^80](recipient, goal, deadline, contrib_total, contrib_count, contribs[2^50](sender, value)) @@ -909,6 +919,7 @@ def test_crowdfund(): assert mida1 + 1 == c.head_state.get_balance(tester.a1) assert mida3 + 59049 == c.head_state.get_balance(tester.a3) + saveload_code = """ data store[1000] @@ -927,12 +938,18 @@ def test_saveload(): c = tester.Chain() x = c.contract(saveload_code, language='serpent') o = x.kall() - assert o[0] == 0x73697220626f62616c6f7420746f207468652072657363756520212131213121, bitcoin.encode(o[0], 16) - assert o[1] == 0x2131213100000000000000000000000000000000000000000000000000000000, bitcoin.encode(o[1], 16) - assert o[2] == 0x73697220626f62616c6f7420746f207468652072657363756520212131213121, bitcoin.encode(o[2], 16) - assert o[3] == 0x2131213100000000000000000000000000000000000000000000000000000000, bitcoin.encode(o[3], 16) - assert o[4] == 0x73697220626f62616c6f7420746f207468652072657363756520212131213121, bitcoin.encode(o[4], 16) - assert o[5] == 0x2100000000000000000000000000000000000000000000000000000000000000, bitcoin.encode(o[5], 16) + assert o[0] == 0x73697220626f62616c6f7420746f207468652072657363756520212131213121, bitcoin.encode( + o[0], 16) + assert o[1] == 0x2131213100000000000000000000000000000000000000000000000000000000, bitcoin.encode( + o[1], 16) + assert o[2] == 0x73697220626f62616c6f7420746f207468652072657363756520212131213121, bitcoin.encode( + o[2], 16) + assert o[3] == 0x2131213100000000000000000000000000000000000000000000000000000000, bitcoin.encode( + o[3], 16) + assert o[4] == 0x73697220626f62616c6f7420746f207468652072657363756520212131213121, bitcoin.encode( + o[4], 16) + assert o[5] == 0x2100000000000000000000000000000000000000000000000000000000000000, bitcoin.encode( + o[5], 16) saveload_code2 = """ @@ -949,8 +966,10 @@ def test_saveload2(): c = tester.Chain() x = c.contract(saveload_code2, language='serpent') c.tx(tester.k0, x.address, 0) - assert bitcoin.encode(c.head_state.get_storage_data(x.address, 0), 256) == b'01ab' + b'\x00' * 28 - assert bitcoin.encode(c.head_state.get_storage_data(x.address, 1), 256) == b'01ab' + b'\x00' * 28 + assert bitcoin.encode(c.head_state.get_storage_data( + x.address, 0), 256) == b'01ab' + b'\x00' * 28 + assert bitcoin.encode(c.head_state.get_storage_data( + x.address, 1), 256) == b'01ab' + b'\x00' * 28 sdiv_code = """ @@ -986,6 +1005,7 @@ def test_argcall(): assert 375 == x.argcall([5, 7, 3]) assert 376 == x.argkall([6, 7, 3]) + more_complex_argcall_code = """ def argcall(args:arr): args[0] *= 2 @@ -1047,6 +1067,7 @@ def test_sort(): assert x.sort([9, 3, 5]) == [3, 5, 9] assert x.sort([80, 234, 112, 112, 29]) == [29, 80, 112, 112, 234] + filename9 = "mul2_qwertyuioplkjhgfdsabarbar.se" sort_tester_code = """ @@ -1069,6 +1090,7 @@ def test_indirect_sort(): os.remove(filename9) assert x.test([80, 234, 112, 112, 29]) == [29, 80, 112, 112, 234] + multiarg_code = """ def kall(a:arr, b, c:arr, d:str, e): x = a[0] + 10 * b + 100 * c[0] + 1000 * a[1] + 10000 * c[1] + 100000 * e @@ -1082,6 +1104,7 @@ def test_multiarg_code(): o = x.kall([1, 2, 3], 4, [5, 6, 7], b"doge", 8) assert o == [862541, safe_ord('d') + safe_ord('o') + safe_ord('g'), 4] + peano_code = """ macro padd($x, psuc($y)): psuc(padd($x, $y)) @@ -1197,7 +1220,12 @@ def test_ecrecover(): assert bitcoin.ecdsa_raw_verify(msghash, (V, R, S), pub) - addr = utils.big_endian_to_int(utils.sha3(bitcoin.encode_pubkey(pub, 'bin')[1:])[12:]) + addr = utils.big_endian_to_int( + utils.sha3( + bitcoin.encode_pubkey( + pub, 'bin')[ + 1:])[ + 12:]) assert utils.big_endian_to_int(utils.privtoaddr(priv)) == addr result = x.test_ecrecover(utils.big_endian_to_int(msghash), V, R, S) @@ -1259,6 +1287,7 @@ def test_sha3(): 0xdfded4ed5ac76ba7379cfe7b3b0f53e768dca8d45a34854e649cfc3c18cbd9cd - 2 ** 256 ] + types_in_functions_code = """ type fixedp: [a, b] @@ -1371,7 +1400,8 @@ def test_mcopy(): c = tester.Chain() x = c.contract(mcopy_code, language='serpent') assert x.mcopy_test(b"123", 5, 6, 259) == \ - b'\x00'*31+b'\x05'+b'\x00'*31+b'\x06'+b'\x00'*30+b'\x01\x03'+b'123' + b'\x00' * 31 + b'\x05' + b'\x00' * 31 + \ + b'\x06' + b'\x00' * 30 + b'\x01\x03' + b'123' mcopy_code_2 = """ @@ -1391,7 +1421,8 @@ def test_mcopy2(): c = tester.Chain() contract = c.contract(mcopy_code_2, language='serpent') assert contract.mcopy_test() == \ - b''.join([utils.zpad(utils.int_to_big_endian(x), 32) for x in [99, 111, 119]]) + b''.join([utils.zpad(utils.int_to_big_endian(x), 32) + for x in [99, 111, 119]]) array_saveload_code = """ @@ -1512,7 +1543,8 @@ def test_abi_logging(): c = tester.Chain() x = c.contract(abi_logging_code, language='serpent') o = [] - c.head_state.log_listeners.append(lambda f: o.append(x.translator.listen(f))) + c.head_state.log_listeners.append( + lambda f: o.append(x.translator.listen(f))) x.test_rabbit(3) assert o == [{"_event_type": b"rabbit", "x": 3}] o.pop() @@ -1521,11 +1553,11 @@ def test_abi_logging(): o.pop() x.test_moose(7, b"nine", 11, [13, 15, 17]) assert o == [{"_event_type": b"moose", "a": 7, "b": b"nine", - "c": 11, "d": [13, 15, 17]}] + "c": 11, "d": [13, 15, 17]}] o.pop() x.test_chicken(tester.a0) assert o == [{"_event_type": b"chicken", - "m": "0x"+utils.encode_hex(tester.a0)}] + "m": "0x" + utils.encode_hex(tester.a0)}] o.pop() @@ -1573,6 +1605,7 @@ def test_abi_address_output(): assert x.get_address(123) == '0x1212121212121212121212121212121212121212' assert x.get_address(125) == '0x5656565656565656565656565656565656565656' + filename5 = 'abi_output_tester_1264876521746198724124' abi_address_caller_code = """ @@ -1613,7 +1646,8 @@ def test_string_logging(): c = tester.Chain() x = c.contract(string_logging_code, language='serpent') o = [] - c.head_state.log_listeners.append(lambda f: o.append(x.translator.listen(f))) + c.head_state.log_listeners.append( + lambda f: o.append(x.translator.listen(f))) x.moo() assert o == [{ "_event_type": b"foo", @@ -1648,6 +1682,7 @@ def test_params_contract(): assert x.garble() == 4 assert x.marble() == b'horse' + prefix_types_in_functions_code = """ type fixedp: fp_ @@ -1683,30 +1718,30 @@ def test_delegatecall(): x1 = c.contract(""" data v event Happy() - + def foo(): log(type=Happy) self.v += 1 return(self.v) """, language='serpent') - + x2 = c.contract(""" extern c1: [foo:[]:int256] data v data callee event Happeh() - + def set_callee(addr:address): self.callee = addr - + def bar(): log(type=Happeh) self.callee.foo(call=delegate) - + def baz(): return(self.v) """, language='serpent') - + x2.set_callee(x1.address) assert x2.baz() == 0 x2.bar() @@ -1716,7 +1751,6 @@ def baz(): assert x2.baz() == 3 - # test_evm = None # test_sixten = None # test_with = None diff --git a/ethereum/tests/test_difficulty.py b/ethereum/tests/test_difficulty.py index e9727bd69..213792e6d 100644 --- a/ethereum/tests/test_difficulty.py +++ b/ethereum/tests/test_difficulty.py @@ -18,12 +18,21 @@ def test_difficulty(filename, testname, testdata): - parent_timestamp=int(testdata["parentTimestamp"], 10 if testdata["parentTimestamp"].isdigit() else 16) - parent_difficulty=int(testdata["parentDifficulty"], 10 if testdata["parentDifficulty"].isdigit() else 16) - parent_blk_number=int(testdata["currentBlockNumber"], 10 if testdata["currentBlockNumber"].isdigit() else 16)-1 - cur_blk_timestamp=int(testdata["currentTimestamp"], 10 if testdata["currentTimestamp"].isdigit() else 16) - reference_dif = int(testdata["currentDifficulty"], 10 if testdata["currentDifficulty"].isdigit() else 16) - + parent_timestamp = int( + testdata["parentTimestamp"], + 10 if testdata["parentTimestamp"].isdigit() else 16) + parent_difficulty = int( + testdata["parentDifficulty"], + 10 if testdata["parentDifficulty"].isdigit() else 16) + parent_blk_number = int( + testdata["currentBlockNumber"], + 10 if testdata["currentBlockNumber"].isdigit() else 16) - 1 + cur_blk_timestamp = int( + testdata["currentTimestamp"], + 10 if testdata["currentTimestamp"].isdigit() else 16) + reference_dif = int( + testdata["currentDifficulty"], + 10 if testdata["currentDifficulty"].isdigit() else 16) env = config.Env() if 'Homestead' in filename: @@ -42,11 +51,13 @@ def test_difficulty(filename, testname, testdata): difficulty=parent_difficulty, number=parent_blk_number)) - calculated_dif = calc_difficulty(parent, cur_blk_timestamp, config=env.config) + calculated_dif = calc_difficulty( + parent, cur_blk_timestamp, config=env.config) print(calculated_dif) print(reference_dif) - assert calculated_dif == reference_dif, (parent.header.difficulty, reference_dif, calculated_dif, parent.header.number, cur_blk_timestamp - parent_timestamp) + assert calculated_dif == reference_dif, (parent.header.difficulty, reference_dif, + calculated_dif, parent.header.number, cur_blk_timestamp - parent_timestamp) def not_a_difficulty_test(filename, testname, testdata): @@ -59,11 +70,15 @@ def not_a_difficulty_test(filename, testname, testdata): def pytest_generate_tests(metafunc): - testutils.generate_test_params('BasicTests', metafunc, exclude_func=not_a_difficulty_test) + testutils.generate_test_params( + 'BasicTests', + metafunc, + exclude_func=not_a_difficulty_test) def main(): - import pdb; pdb.set_trace() + import pdb + pdb.set_trace() if len(sys.argv) == 1: # read fixture from stdin fixtures = {'stdin': json.load(sys.stdin)} diff --git a/ethereum/tests/test_genesis.py b/ethereum/tests/test_genesis.py index 6e401661c..9d656f1b0 100644 --- a/ethereum/tests/test_genesis.py +++ b/ethereum/tests/test_genesis.py @@ -19,7 +19,10 @@ def genesis_fixture(): Read genesis block from fixtures. """ genesis_fixture = None - fn = os.path.join(testutils.fixture_path, 'BasicTests', 'genesishashestest.json') + fn = os.path.join( + testutils.fixture_path, + 'BasicTests', + 'genesishashestest.json') with open(fn, 'r') as f: genesis_fixture = json.load(f) assert genesis_fixture is not None, "Could not read genesishashtest.json from fixtures. Make sure you did 'git submodule init'!" @@ -32,7 +35,9 @@ def genesis_fixture(): @pytest.mark.xfail # code not in sync with genesis fixtures def test_genesis_state_root(genesis_fixture): genesis = blocks_genesis(new_env()) - assert encode_hex(genesis.state_root) == utils.to_string(genesis_fixture['genesis_state_root']) + assert encode_hex( + genesis.state_root) == utils.to_string( + genesis_fixture['genesis_state_root']) def test_genesis_initial_alloc(genesis_fixture): @@ -45,7 +50,8 @@ def test_genesis_initial_alloc(genesis_fixture): @pytest.mark.xfail # code not in sync with genesis fixtures def test_genesis_hash(genesis_fixture): genesis = blocks_genesis(new_env()) - assert genesis.hex_hash() == utils.to_string(genesis_fixture['genesis_hash']) + assert genesis.hex_hash() == utils.to_string( + genesis_fixture['genesis_hash']) if __name__ == '__main__': diff --git a/ethereum/tests/test_opcodes.py b/ethereum/tests/test_opcodes.py index 51e72c29c..b54f28b66 100644 --- a/ethereum/tests/test_opcodes.py +++ b/ethereum/tests/test_opcodes.py @@ -9,8 +9,10 @@ def test_eip150_opcode_gascost(): """Ensure gas prices specified in https://github.com/ethereum/eips/issues/150 """ - assert opcode_gas['EXTCODESIZE'] + opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS == 700 - assert opcode_gas['EXTCODECOPY'] + opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS == 700 + assert opcode_gas['EXTCODESIZE'] + \ + opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS == 700 + assert opcode_gas['EXTCODECOPY'] + \ + opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS == 700 assert opcode_gas['BALANCE'] + opcodes.BALANCE_SUPPLEMENTAL_GAS == 400 assert opcode_gas['SLOAD'] + opcodes.SLOAD_SUPPLEMENTAL_GAS == 200 diff --git a/ethereum/tests/test_state.py b/ethereum/tests/test_state.py index 5c8ceeed3..f46117e8f 100644 --- a/ethereum/tests/test_state.py +++ b/ethereum/tests/test_state.py @@ -28,13 +28,17 @@ def pytest_generate_tests(metafunc): place_to_check, metafunc, exclude_func=lambda filename, _, __: ( - 'stQuadraticComplexityTest' in filename or # Takes too long - 'stMemoryStressTest' in filename or # We run out of memory - 'MLOAD_Bounds.json' in filename or # We run out of memory - 'failed_tx_xcf416c53' in filename or # we know how to pass: force address 3 to get deleted. TODO confer with c++ best path foward. - 'RevertDepthCreateAddressCollision.json' in filename or # we know how to pass: delete contract's code. Looks like c++ issue. - 'pairingTest.json' in filename or # definitely a c++ issue - 'createJS_ExampleContract' in filename # definitely a c++ issue + 'stQuadraticComplexityTest' in filename or # Takes too long + 'stMemoryStressTest' in filename or # We run out of memory + 'MLOAD_Bounds.json' in filename or # We run out of memory + # we know how to pass: force address 3 to get deleted. TODO confer + # with c++ best path foward. + 'failed_tx_xcf416c53' in filename or + # we know how to pass: delete contract's code. Looks like c++ + # issue. + 'RevertDepthCreateAddressCollision.json' in filename or + 'pairingTest.json' in filename or # definitely a c++ issue + 'createJS_ExampleContract' in filename # definitely a c++ issue ) ) @@ -48,7 +52,7 @@ def main(): # load fixtures from specified file or dir try: fixtures = testutils.get_tests_from_file_or_dir(sys.argv[1]) - except: + except BaseException: fixtures = {'stdin': json.loads(sys.argv[1])} for filename, tests in list(fixtures.items()): for testname, testdata in list(tests.items()): diff --git a/ethereum/tests/test_tester.py b/ethereum/tests/test_tester.py index 253590cc9..0b84e7eec 100644 --- a/ethereum/tests/test_tester.py +++ b/ethereum/tests/test_tester.py @@ -6,16 +6,17 @@ from ethereum.tools.tester import Chain, ABIContract from ethereum.tools._solidity import ( - get_solidity, - compile_file, - solidity_get_contract_data, - ) + get_solidity, + compile_file, + solidity_get_contract_data, +) SOLIDITY_AVAILABLE = get_solidity() is not None CONTRACTS_DIR = path.join(path.dirname(__file__), 'contracts') -@pytest.mark.skipif(not SOLIDITY_AVAILABLE, reason='solc compiler not available') +@pytest.mark.skipif(not SOLIDITY_AVAILABLE, + reason='solc compiler not available') def test_abicontract_interface(): """ Test for issue #370. """ tester_state = Chain() @@ -24,10 +25,10 @@ def test_abicontract_interface(): contract_name = 'Simple' simple_compiled = compile_file(contract_path) simple_data = solidity_get_contract_data( - simple_compiled, - contract_path, - contract_name, - ) + simple_compiled, + contract_path, + contract_name, + ) simple_address = tester_state.contract(simple_data['bin']) # ABIContract class must accept json_abi diff --git a/ethereum/tests/test_transactions.py b/ethereum/tests/test_transactions.py index 10a810db7..90ea57895 100644 --- a/ethereum/tests/test_transactions.py +++ b/ethereum/tests/test_transactions.py @@ -25,7 +25,7 @@ def test_transaction(filename, testname, testdata): o = {} tx = rlp.decode(rlpdata, transactions.Transaction) blknum = int(testdata["blocknumber"]) - #if blknum >= config.default_config["HOMESTEAD_FORK_BLKNUM"]: + # if blknum >= config.default_config["HOMESTEAD_FORK_BLKNUM"]: # tx.check_low_s_homestead() assert config_fork_specific_validation(konfig, blknum, tx) assert tx.startgas >= tx.intrinsic_gas_used @@ -50,9 +50,20 @@ def test_transaction(filename, testname, testdata): # print(tx.to_dict(), testdata) assert tx is None else: - assert set(o['transaction'].keys()) == set(testdata.get("transaction", dict()).keys()) + assert set( + o['transaction'].keys()) == set( + testdata.get( + "transaction", + dict()).keys()) o.get("transaction", None) == testdata.get("transaction", None) - assert str_to_bytes(encode_hex(o.get("sender", ''))) == str_to_bytes(testdata.get("sender", '')) + assert str_to_bytes( + encode_hex( + o.get( + "sender", + ''))) == str_to_bytes( + testdata.get( + "sender", + '')) def pytest_generate_tests(metafunc): diff --git a/ethereum/tests/test_trie.py b/ethereum/tests/test_trie.py index 8ab7369b7..7e5e29347 100644 --- a/ethereum/tests/test_trie.py +++ b/ethereum/tests/test_trie.py @@ -18,6 +18,7 @@ def check_testdata(data_keys, expected_keys): assert set(data_keys) == set(expected_keys), \ "test data changed, please adjust tests" + fixture_path = os.path.join(os.path.dirname(__file__), '..', '..', 'fixtures') diff --git a/ethereum/tests/test_trie_next_prev.py b/ethereum/tests/test_trie_next_prev.py index cce66cfd9..bc41a5b7d 100644 --- a/ethereum/tests/test_trie_next_prev.py +++ b/ethereum/tests/test_trie_next_prev.py @@ -18,7 +18,10 @@ def check_testdata(data_keys, expected_keys): def load_tests(): try: - fn = os.path.join(testutils.fixture_path, 'TrieTests', 'trietestnextprev.json') + fn = os.path.join( + testutils.fixture_path, + 'TrieTests', + 'trietestnextprev.json') fixture = json.load(open(fn, 'r')) except IOError: raise IOError("Could not read trietests.json from fixtures", diff --git a/ethereum/todo_tests/test_logging.py b/ethereum/todo_tests/test_logging.py index dd7bb8629..f0eff3db9 100644 --- a/ethereum/todo_tests/test_logging.py +++ b/ethereum/todo_tests/test_logging.py @@ -19,7 +19,8 @@ def teardown_function(function): slogging.configure(**function.snapshot) -@pytest.mark.parametrize('level_name', ['critical', 'error', 'warning', 'info', 'debug', 'trace']) +@pytest.mark.parametrize( + 'level_name', ['critical', 'error', 'warning', 'info', 'debug', 'trace']) def test_basic(caplog, level_name): slogging.configure(":trace") log = slogging.get_logger() @@ -49,7 +50,11 @@ def test_jsonconfig(caplog): slogging.configure(log_json=True) log = slogging.get_logger('prefix') log.warn('abc', a=1) - assert json.loads(caplog.records[0].msg) == dict(event='prefix.abc', a=1, level='WARNING') + assert json.loads( + caplog.records[0].msg) == dict( + event='prefix.abc', + a=1, + level='WARNING') def test_configuration(): @@ -74,7 +79,9 @@ def div(a, b): _ = a // b log.error('heres the stack', stack_info=True) except Exception as e: - log.error('an Exception trace should preceed this msg', exc_info=True) + log.error( + 'an Exception trace should preceed this msg', + exc_info=True) div(1, 0) assert 'an Exception trace' in caplog.text assert 'Traceback' in caplog.text @@ -98,7 +105,8 @@ def log_cb(event_dict): r = called.pop() assert r == dict(event='test listener', abc='thislistener') - log.trace('trace is usually filtered', abc='thislistener') # this handler for function log_cb does not work + # this handler for function log_cb does not work + log.trace('trace is usually filtered', abc='thislistener') assert "trace is usually filtered" not in caplog.text # deactivate listener @@ -148,13 +156,17 @@ def test_get_configuration(): slogging.configure(config_string=config_string, log_json=log_json) config = slogging.get_configuration() assert config['log_json'] == log_json - assert set(config['config_string'].split(',')) == set(config_string.split(',')) + assert set( + config['config_string'].split(',')) == set( + config_string.split(',')) log_json = True slogging.configure(config_string=config_string, log_json=log_json) config = slogging.get_configuration() assert config['log_json'] == log_json - assert set(config['config_string'].split(',')) == set(config_string.split(',')) + assert set( + config['config_string'].split(',')) == set( + config_string.split(',')) # set config differntly slogging.configure(config_string=':TRACE', log_json=False) @@ -164,7 +176,9 @@ def test_get_configuration(): slogging.configure(**config) config = slogging.get_configuration() assert config['log_json'] == log_json - assert set(config['config_string'].split(',')) == set(config_string.split(',')) + assert set( + config['config_string'].split(',')) == set( + config_string.split(',')) def test_recorder(caplog): @@ -216,7 +230,7 @@ def run_vm(raise_error=False): recorder = slogging.LogRecorder() try: run_vm(raise_error=True) - except: + except BaseException: log = slogging.get_logger('eth.vm') for x in recorder.pop_records(): log.info(x.pop('event'), **x) diff --git a/ethereum/todo_tests/test_pos.py b/ethereum/todo_tests/test_pos.py index f34358b5b..b854bcac1 100644 --- a/ethereum/todo_tests/test_pos.py +++ b/ethereum/todo_tests/test_pos.py @@ -34,7 +34,8 @@ deposit_sizes = [i * 500 + 500 for i in range(NUM_PARTICIPANTS)] vcodes = [generate_validation_code(a) for a in addrs] vchashes = [utils.sha3(c) for c in vcodes] -assert len(privkeys) == len(addrs) == len(randaos) == len(deposit_sizes) == len(vcodes) == len(vchashes) == NUM_PARTICIPANTS +assert len(privkeys) == len(addrs) == len(randaos) == len( + deposit_sizes) == len(vcodes) == len(vchashes) == NUM_PARTICIPANTS # Creating casper contract translator ct = get_casper_ct() @@ -47,22 +48,30 @@ epoch_length=100) print('Genesis constructed successfully') chains = [Chain(s.to_snapshot(), env=s.env) for i in range(NUM_PARTICIPANTS)] -withdrawal_time_1 = call_casper(chains[0].state, 'getLockDuration', [vchashes[0]]) +withdrawal_time_1 = call_casper( + chains[0].state, 'getLockDuration', [ + vchashes[0]]) # List of validator IDs that created each block vids = [] + # Create and sign a block def make_block(chain, key, randao, vchash, skips): - h, _ = make_head_candidate(chain, TransactionQueue(), timestamp=get_timestamp(chain, skips)) - return sign_block(h, key, randao.get_parent(call_casper(chain.state, 'getRandao', [vchash])), vchash, skips) + h, _ = make_head_candidate( + chain, TransactionQueue(), timestamp=get_timestamp( + chain, skips)) + return sign_block(h, key, randao.get_parent(call_casper( + chain.state, 'getRandao', [vchash])), vchash, skips) + next_validator = call_casper(s, 'getValidator', [0]) print('Next validator:', next_validator.encode('hex')) next_validator_id = vchashes.index(next_validator) print('Next validator index:', next_validator_id) -skip_count, timestamp = get_skips_and_block_making_time(chains[0].state, next_validator) +skip_count, timestamp = get_skips_and_block_making_time( + chains[0].state, next_validator) assert skip_count == 0 b = make_block(chains[0], privkeys[next_validator_id], randaos[next_validator_id], vchashes[next_validator_id], skip_count) @@ -78,7 +87,8 @@ def make_block(chain, key, randao, vchash, skips): # Make another block next_validator = call_casper(chains[0].state, 'getValidator', [0]) next_validator_id = vchashes.index(next_validator) -skip_count, timestamp = get_skips_and_block_making_time(chains[0].state, next_validator) +skip_count, timestamp = get_skips_and_block_making_time( + chains[0].state, next_validator) assert skip_count == 0 b2 = make_block(chains[0], privkeys[next_validator_id], randaos[next_validator_id], vchashes[next_validator_id], skip_count) @@ -88,18 +98,35 @@ def make_block(chain, key, randao, vchash, skips): # Make a dunkle and include it in a transaction next_validator = call_casper(chains[1].state, 'getValidator', [1]) next_validator_id = vchashes.index(next_validator) -skip_count, timestamp = get_skips_and_block_making_time(chains[1].state, next_validator) +skip_count, timestamp = get_skips_and_block_making_time( + chains[1].state, next_validator) assert skip_count == 1 b3 = make_block(chains[1], privkeys[next_validator_id], randaos[next_validator_id], vchashes[next_validator_id], skip_count) print('Dunkle produced') -t = Transaction(0, 0, 10**6, casper_config['CASPER_ADDR'], 0, ct.encode('includeDunkle', [rlp.encode(b3.header)])).sign(privkeys[0]) +t = Transaction(0, + 0, + 10**6, + casper_config['CASPER_ADDR'], + 0, + ct.encode('includeDunkle', + [rlp.encode(b3.header)])).sign(privkeys[0]) apply_transaction(chains[0].state, t) -assert call_casper(chains[0].state, 'isDunkleIncluded', [utils.sha3(rlp.encode(b3.header))]) +assert call_casper( + chains[0].state, 'isDunkleIncluded', [ + utils.sha3( + rlp.encode( + b3.header))]) print('Dunkle added successfully') # Try (and fail) to add the dunkle again x = chains[0].state.gas_used -t = Transaction(1, 0, 10**6, casper_config['CASPER_ADDR'], 0, ct.encode('includeDunkle', [rlp.encode(b3.header)])).sign(privkeys[0]) +t = Transaction(1, + 0, + 10**6, + casper_config['CASPER_ADDR'], + 0, + ct.encode('includeDunkle', + [rlp.encode(b3.header)])).sign(privkeys[0]) apply_transaction(chains[0].state, t) x2 = chains[0].state.gas_used assert x2 - x == t.startgas, (x2 - x, t.startgas) @@ -129,7 +156,15 @@ def make_block(chain, key, randao, vchash, skips): # Remove a validator sigdata = make_withdrawal_signature(privkeys[0]) txdata = ct.encode('startWithdrawal', [vchashes[0], sigdata]) -t3 = Transaction(chains[0].state.get_nonce(addrs[0]), 0, 1000000, casper_config['CASPER_ADDR'], 0, txdata).sign(privkeys[0]) +t3 = Transaction( + chains[0].state.get_nonce( + addrs[0]), + 0, + 1000000, + casper_config['CASPER_ADDR'], + 0, + txdata).sign( + privkeys[0]) apply_transaction(chains[0].state, t3) assert call_casper(chains[0].state, 'getEndEpoch', [vchashes[0]]) == 4 chains[0].state.commit() @@ -143,7 +178,8 @@ def make_block(chain, key, randao, vchash, skips): assert b.header.number == i assert chains[0].add_block(b) vids.append(next_validator_id) -print('Created 200 blocks after the deposit, created by validators:', vids[-200:]) +print('Created 200 blocks after the deposit, created by validators:', + vids[-200:]) assert len(vchashes) - 1 in vids assert 0 in vids for i in range(400, 400 + withdrawal_time_1 + 1): @@ -153,19 +189,31 @@ def make_block(chain, key, randao, vchash, skips): vchashes[next_validator_id], 0) assert chains[0].add_block(b) vids.append(next_validator_id) -print('Created %d blocks after the withdrawal, created by validators:' % (withdrawal_time_1 + 1), vids[-200:]) +print('Created %d blocks after the withdrawal, created by validators:' % + (withdrawal_time_1 + 1), vids[-200:]) assert len(vchashes) - 1 in vids assert 0 not in vids[-200:] pre_bal = chains[0].state.get_balance(addrs[0]) txdata = ct.encode('withdraw', [vchashes[0]]) -t4 = Transaction(chains[0].state.get_nonce(addrs[0]), 0, 1000000, casper_config['CASPER_ADDR'], 0, txdata).sign(privkeys[0]) +t4 = Transaction( + chains[0].state.get_nonce( + addrs[0]), + 0, + 1000000, + casper_config['CASPER_ADDR'], + 0, + txdata).sign( + privkeys[0]) apply_transaction(chains[0].state, t4) post_bal = chains[0].state.get_balance(addrs[0]) print('Wei withdrawn:', post_bal - pre_bal) blocks_by_v0_in_stage1 = len([x for x in vids[:200] if x == 0]) -expected_revenue_in_stage1 = blocks_by_v0_in_stage1 * max(sum(deposit_sizes[:-1]), 1000000) * 10**18 * BLOCK_MAKING_PPB / 10**9 +expected_revenue_in_stage1 = blocks_by_v0_in_stage1 * \ + max(sum(deposit_sizes[:-1]), 1000000) * 10**18 * BLOCK_MAKING_PPB / 10**9 blocks_by_v0_in_stage2 = len([x for x in vids[200:400] if x == 0]) -expected_revenue_in_stage2 = blocks_by_v0_in_stage2 * max(sum(deposit_sizes), 1000000) * 10**18 * BLOCK_MAKING_PPB / 10**9 +expected_revenue_in_stage2 = blocks_by_v0_in_stage2 * \ + max(sum(deposit_sizes), 1000000) * 10**18 * BLOCK_MAKING_PPB / 10**9 -assert post_bal - pre_bal == deposit_sizes[0] * 10**18 + expected_revenue_in_stage1 + expected_revenue_in_stage2 +assert post_bal - pre_bal == deposit_sizes[0] * 10**18 + \ + expected_revenue_in_stage1 + expected_revenue_in_stage2 print('PoS test fully passed') diff --git a/ethereum/todo_tests/test_pruning_trie.py b/ethereum/todo_tests/test_pruning_trie.py index c4babcc8e..307e0945d 100644 --- a/ethereum/todo_tests/test_pruning_trie.py +++ b/ethereum/todo_tests/test_pruning_trie.py @@ -22,7 +22,8 @@ def check_db_tightness(trees, db): for k, v in db.kv.items(): if rlp.decode(rlp.decode(v)[1]) not in all_nodes: print(utils.encode_hex(k[2:]), rlp.decode(rlp.decode(v)[1])) - raise Exception("unpruned key leak: %d %d" % (len(db.kv), len(all_nodes))) + raise Exception("unpruned key leak: %d %d" % + (len(db.kv), len(all_nodes))) def test_basic_pruning(): @@ -146,7 +147,8 @@ def test_two_trees(): db.commit_refcount_changes(NODES + i) db.cleanup(NODES + i) check_db_tightness([t1, t2], db) - assert t2.to_dict() == {to_string(i): to_string(i) for i in range(NODES // 2)} + assert t2.to_dict() == {to_string(i): to_string(i) + for i in range(NODES // 2)} for i in range(NODES // 2): t2.delete(to_string(i)) db.commit_refcount_changes(NODES * 2 + i) @@ -169,7 +171,8 @@ def test_two_trees_with_clear(): db.cleanup(i) t1.clear_all() db.cleanup(NODES) - assert t2.to_dict() == {to_string(i): to_string(i) for i in range(NODES // 2)} + assert t2.to_dict() == {to_string(i): to_string(i) + for i in range(NODES // 2)} for i in range(NODES // 2): t2.delete(to_string(i)) db.commit_refcount_changes(NODES + i) @@ -343,7 +346,8 @@ def test_deep_inner_branch_deletion(): def test_block_18315_changes(): pre = {} toadd = [ - ['0x0000000000000000000000000000000000000000000000000000000000000000', '0xf9e88bc2b3203e764fe67b4d0f4171b7756117c8'], + ['0x0000000000000000000000000000000000000000000000000000000000000000', + '0xf9e88bc2b3203e764fe67b4d0f4171b7756117c8'], ['0x0000000000000000000000000000000000000000000000000000000000000001', '0x'], ['0x0000000000000000000000000000000000000000000000000000000000000002', '0x'], ] @@ -396,8 +400,11 @@ def load_tests(): except IOError: raise IOError("Could not read trietests.json from fixtures", "Make sure you did 'git submodule init'") - expected_keys = set(['jeff', 'emptyValues', 'branchingTests', 'insert-middle-leaf']) - assert set(fixture.keys()) == expected_keys, ("test data changed!", list(fixture.keys())) + expected_keys = set( + ['jeff', 'emptyValues', 'branchingTests', 'insert-middle-leaf']) + assert set( + fixture.keys()) == expected_keys, ("test data changed!", list( + fixture.keys())) return fixture_to_bytes(fixture) @@ -435,7 +442,8 @@ def _dec(x): db.commit_refcount_changes(1) db.cleanup(1) assert len(db.kv) == 0 - assert pairs['root'] == b'0x' + utils.encode_hex(t.root_hash), (i, list(permut) + deletes) + assert pairs['root'] == b'0x' + \ + utils.encode_hex(t.root_hash), (i, list(permut) + deletes) def test_emptyValues(): @@ -446,7 +454,6 @@ def test_jeff(): run_test('jeff') - # test_basic_pruning = None # test_delayed_pruning = None # test_clear = None diff --git a/ethereum/todo_tests/test_solidity.py b/ethereum/todo_tests/test_solidity.py index 80d9e041e..0f2038e11 100644 --- a/ethereum/todo_tests/test_solidity.py +++ b/ethereum/todo_tests/test_solidity.py @@ -18,7 +18,8 @@ def bytecode_is_generated(cinfo, cname): return 'code' in cinfo[cname] and len(cinfo[cname]['code']) > 10 -@pytest.mark.skipif(not SOLIDITY_AVAILABLE, reason='solc compiler not available') +@pytest.mark.skipif(not SOLIDITY_AVAILABLE, + reason='solc compiler not available') def test_library_from_file(): state = tester.state() state.env.config['HOMESTEAD_FORK_BLKNUM'] = 0 # enable CALLCODE opcode @@ -44,7 +45,8 @@ def test_library_from_file(): assert contract.test() == 7 -@pytest.mark.skipif(not SOLIDITY_AVAILABLE, reason='solc compiler not available') +@pytest.mark.skipif(not SOLIDITY_AVAILABLE, + reason='solc compiler not available') def test_library_from_code(): with open(path.join(CONTRACTS_DIR, 'seven_library.sol')) as handler: library_code = handler.read() @@ -97,9 +99,12 @@ def test_names(): def test_symbols(): - assert _solidity.solidity_library_symbol('a') == '__a_____________________________________' - assert _solidity.solidity_library_symbol('aaa') == '__aaa___________________________________' - assert _solidity.solidity_library_symbol('a' * 40) == '__aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa__' + assert _solidity.solidity_library_symbol( + 'a') == '__a_____________________________________' + assert _solidity.solidity_library_symbol( + 'aaa') == '__aaa___________________________________' + assert _solidity.solidity_library_symbol( + 'a' * 40) == '__aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa__' # the address should be sanitized when it's given to the function with pytest.raises(Exception): @@ -124,14 +129,15 @@ def test_symbols(): ) == 'beef1111111111111111111111111111111111111111cafe' -@pytest.mark.skipif(not SOLIDITY_AVAILABLE, reason='solc compiler not available') +@pytest.mark.skipif(not SOLIDITY_AVAILABLE, + reason='solc compiler not available') def test_interop(): serpent_contract = """ extern solidity: [sub2:[]:i] - + def main(a): return(a.sub2() * 2) - + def sub1(): return(5) """ @@ -154,7 +160,9 @@ def sub1(): state = tester.state() serpent_abi = state.abi_contract(serpent_contract) - solidity_abi = state.abi_contract(solidity_contract, language='solidity') # should be zoo + solidity_abi = state.abi_contract( + solidity_contract, + language='solidity') # should be zoo solidity_address = utils.encode_hex(solidity_abi.address) # pylint: disable=no-member @@ -162,11 +170,13 @@ def sub1(): assert serpent_abi.main(solidity_abi.address) == 14 assert solidity_abi.sub2() == 7 - assert solidity_abi.sub3(utils.encode_hex(solidity_abi.address)) == solidity_address + assert solidity_abi.sub3(utils.encode_hex( + solidity_abi.address)) == solidity_address assert solidity_abi.main(serpent_abi.address) == 10 -@pytest.mark.skipif(not SOLIDITY_AVAILABLE, reason='solc compiler not available') +@pytest.mark.skipif(not SOLIDITY_AVAILABLE, + reason='solc compiler not available') def test_constructor(): constructor_contract = """ contract testme { @@ -191,7 +201,8 @@ def test_constructor(): assert contract.getValue() == 2 -@pytest.mark.skipif(not SOLIDITY_AVAILABLE, reason='solc compiler not available') +@pytest.mark.skipif(not SOLIDITY_AVAILABLE, + reason='solc compiler not available') def test_solidity_compile_rich(): compile_rich_contract = """ contract contract_add { @@ -228,7 +239,8 @@ def test_solidity_compile_rich(): } == {'subtract7', 'subtract42'} -@pytest.mark.skipif(not SOLIDITY_AVAILABLE, reason='solc compiler not available') +@pytest.mark.skipif(not SOLIDITY_AVAILABLE, + reason='solc compiler not available') def test_abi_contract(): one_contract = """ contract foo { @@ -250,7 +262,8 @@ def test_abi_contract(): assert contract.mul2(-2) == -4 -@pytest.mark.skipif(not SOLIDITY_AVAILABLE, reason='solc compiler not available') +@pytest.mark.skipif(not SOLIDITY_AVAILABLE, + reason='solc compiler not available') def test_extra_args(): src = """ contract foo { @@ -271,6 +284,7 @@ def test_extra_args(): ) assert bytecode_is_generated(contract_info, 'foo') + def test_missing_solc(monkeypatch): monkeypatch.setattr(_solidity, 'get_compiler_path', lambda: None) assert _solidity.get_compiler_path() is None diff --git a/ethereum/todo_tests/test_vm.py b/ethereum/todo_tests/test_vm.py index afb25460b..ad45d1de0 100644 --- a/ethereum/todo_tests/test_vm.py +++ b/ethereum/todo_tests/test_vm.py @@ -26,7 +26,7 @@ def main(): # load fixtures from specified file or dir try: fixtures = testutils.get_tests_from_file_or_dir(sys.argv[1]) - except: + except BaseException: fixtures = {'stdin': json.loads(sys.argv[1])} for filename, tests in list(fixtures.items()): for testname, testdata in list(tests.items()): diff --git a/ethereum/todo_tests/test_vm_failing.py b/ethereum/todo_tests/test_vm_failing.py index b45098909..e7ea761ce 100644 --- a/ethereum/todo_tests/test_vm_failing.py +++ b/ethereum/todo_tests/test_vm_failing.py @@ -34,6 +34,7 @@ def do_test_vm(filename, testname=None, testdata=None, limit=99999999): def mk_test_func(filename, testname, testdata): return lambda: do_test_vm(filename, testname, testdata) + collected = [] for filename, tests in list(fixtures.items()): for testname, testdata in list(tests.items()): diff --git a/ethereum/todo_tests/tst_frontier.py b/ethereum/todo_tests/tst_frontier.py index fdb73107f..c4fdccad3 100644 --- a/ethereum/todo_tests/tst_frontier.py +++ b/ethereum/todo_tests/tst_frontier.py @@ -46,11 +46,14 @@ c = chain.Chain(json.load(open(STATE_LOAD_FN)), Env()) print('loaded.') elif 'genesis_frontier.json' not in os.listdir(os.getcwd()): - print('Please download genesis_frontier.json from ' + \ - 'http://vitalik.ca/files/genesis_frontier.json') + print('Please download genesis_frontier.json from ' + + 'http://vitalik.ca/files/genesis_frontier.json') sys.exit() else: - c = chain.Chain(json.load(open('genesis_frontier.json')), Env(LevelDB(DB_DIR))) + c = chain.Chain( + json.load( + open('genesis_frontier.json')), Env( + LevelDB(DB_DIR))) assert c.state.trie.root_hash.encode('hex') == \ 'd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544' assert c.state.prev_headers[0].hash.encode('hex') == \ @@ -59,7 +62,7 @@ print('Attempting to open %s' % RLP_BLOCKS_FILE) _path, _file = os.path.split(RLP_BLOCKS_FILE) if not _path or _file not in os.listdir(_path): - print('Please download 200kblocks.rlp from http://vitalik.ca/files/200kblocks.rlp ' + \ + print('Please download 200kblocks.rlp from http://vitalik.ca/files/200kblocks.rlp ' + 'and put it in this directory to continue the test') sys.exit() @@ -70,16 +73,18 @@ block_rlps = [] while pos < len(block_source_data): _, l1, l2 = rlp.codec.consume_length_prefix(block_source_data, pos) - block_rlps.append(block_source_data[pos: l1+l2]) + block_rlps.append(block_source_data[pos: l1 + l2]) pos = l1 + l2 + def report(st, num_blks, num_txs, gas_used): now = time.time() elapsed = now - st tps = num_txs / elapsed bps = num_blks / elapsed gps = gas_used / elapsed - print('%.2f >>> elapsed:%d blocks:%d txs:%d gas:%d bps:%d tps:%d gps:%d' % (now, elapsed, num_blks, num_txs, gas_used, bps, tps, gps)) + print('%.2f >>> elapsed:%d blocks:%d txs:%d gas:%d bps:%d tps:%d gps:%d' % + (now, elapsed, num_blks, num_txs, gas_used, bps, tps, gps)) def check_snapshot_consistency(snapshot, env=None): @@ -111,6 +116,7 @@ def snapshot(c, num_blocks): fn = STATE_STORE_FN open(fn, 'w').write(json.dumps(snapshot, indent=4)) + REPORT_INTERVAL = 1000 SAVE_INTERVAL = 999999 SNAPSHOT_INTERVAL = 999999 @@ -121,8 +127,8 @@ def snapshot(c, num_blocks): # don't check pow BlockHeader.check_pow = lambda *args: True -#print(block_rlps[116525].encode('hex')) -#sys.exit() +# print(block_rlps[116525].encode('hex')) +# sys.exit() # process blocks st = time.time() @@ -132,7 +138,7 @@ def snapshot(c, num_blocks): for i, block in list(enumerate(block_rlps))[1:250000]: # print 'prevh:', s.prev_headers block = rlp.decode(block, Block) - #if i == 116525: + # if i == 116525: # configure_logging(config_string=config_string) assert c.add_block(block) num_blks += 1 diff --git a/ethereum/tools/_solidity.py b/ethereum/tools/_solidity.py index b1b1d979c..05380b6bf 100644 --- a/ethereum/tools/_solidity.py +++ b/ethereum/tools/_solidity.py @@ -36,7 +36,8 @@ def get_compiler_path(): path = path.strip('"') executable_path = os.path.join(path, BINARY) - if os.path.isfile(executable_path) and os.access(executable_path, os.X_OK): + if os.path.isfile(executable_path) and os.access( + executable_path, os.X_OK): return executable_path return None @@ -50,7 +51,8 @@ def get_solidity(): return solc_wrapper -def solc_arguments(libraries=None, combined='bin,abi', optimize=True, extra_args=None): +def solc_arguments(libraries=None, combined='bin,abi', + optimize=True, extra_args=None): """ Build the arguments to call the solc binary. """ args = [ '--combined-json', combined, @@ -63,12 +65,13 @@ def solc_arguments(libraries=None, combined='bin,abi', optimize=True, extra_args if extra_args: try: args.extend(shlex.split(extra_args)) - except: # if not a parseable string then treat it as a list + except BaseException: # if not a parseable string then treat it as a list args.extend(extra_args) if libraries is not None and len(libraries): addresses = [ - '{name}:{address}'.format(name=name, address=address.decode('utf8')) + '{name}:{address}'.format( + name=name, address=address.decode('utf8')) for name, address in libraries.items() ] args.extend([ @@ -84,7 +87,8 @@ def solc_parse_output(compiler_output): # At the moment some solc output like --hashes or -- gas will not output # json at all so if used with those arguments the logic here will break. # Perhaps solidity will slowly switch to a json only output and this comment - # can eventually go away and we will not need to add more logic here at all. + # can eventually go away and we will not need to add more logic here at + # all. result = yaml.safe_load(compiler_output)['contracts'] if 'bin' in tuple(result.values())[0]: @@ -160,20 +164,22 @@ def solidity_names(code): # pylint: disable=too-many-branches comment = '/*' if char == 'c' and code[pos: pos + 8] == 'contract': - result = re.match('^contract[^_$a-zA-Z]+([_$a-zA-Z][_$a-zA-Z0-9]*)', code[pos:]) + result = re.match( + '^contract[^_$a-zA-Z]+([_$a-zA-Z][_$a-zA-Z0-9]*)', code[pos:]) if result: names.append(('contract', result.groups()[0])) if char == 'i' and code[pos: pos + 9] == 'interface': - result = re.match('^interface[^_$a-zA-Z]+([_$a-zA-Z][_$a-zA-Z0-9]*)', code[pos:]) + result = re.match( + '^interface[^_$a-zA-Z]+([_$a-zA-Z][_$a-zA-Z0-9]*)', code[pos:]) if result: names.append(('contract', result.groups()[0])) - if char == 'l' and code[pos: pos + 7] == 'library': - result = re.match('^library[^_$a-zA-Z]+([_$a-zA-Z][_$a-zA-Z0-9]*)', code[pos:]) + result = re.match( + '^library[^_$a-zA-Z]+([_$a-zA-Z][_$a-zA-Z0-9]*)', code[pos:]) if result: names.append(('library', result.groups()[0])) @@ -214,7 +220,8 @@ def solidity_resolve_address(hex_code, library_symbol, library_address): try: decode_hex(library_address) except TypeError: - raise ValueError('library_address contains invalid characters, it must be hex encoded.') + raise ValueError( + 'library_address contains invalid characters, it must be hex encoded.') if len(library_symbol) != 40 or len(library_address) != 40: raise ValueError('Address with wrong length') @@ -248,7 +255,8 @@ def solidity_unresolved_symbols(hex_code): return set(re.findall(r"_.{39}", hex_code)) -def compile_file(filepath, libraries=None, combined='bin,abi', optimize=True, extra_args=None): +def compile_file(filepath, libraries=None, combined='bin,abi', + optimize=True, extra_args=None): """ Return the compile contract code. Args: @@ -263,7 +271,11 @@ def compile_file(filepath, libraries=None, combined='bin,abi', optimize=True, ex workdir, filename = os.path.split(filepath) - args = solc_arguments(libraries=libraries, combined=combined, optimize=optimize, extra_args=extra_args) + args = solc_arguments( + libraries=libraries, + combined=combined, + optimize=optimize, + extra_args=extra_args) args.insert(0, get_compiler_path()) args.append(filename) @@ -277,7 +289,7 @@ def solidity_get_contract_data(all_contracts, filepath, contract_name): of a solc --combined-json output""" try: contract_data = all_contracts[contract_name] - except: + except BaseException: if filepath is None: filename = '' else: @@ -300,7 +312,8 @@ def solidity_get_contract_key(all_contracts, filepath, contract_name): return contract_key if contract_key in all_contracts else None -def compile_contract(filepath, contract_name, libraries=None, combined='bin,abi', optimize=True, extra_args=None): +def compile_contract(filepath, contract_name, libraries=None, + combined='bin,abi', optimize=True, extra_args=None): all_contracts = compile_file( filepath, libraries=libraries, @@ -311,7 +324,8 @@ def compile_contract(filepath, contract_name, libraries=None, combined='bin,abi' return solidity_get_contract_data(all_contracts, filepath, contract_name) -def compile_last_contract(filepath, libraries=None, combined='bin,abi', optimize=True, extra_args=None): +def compile_last_contract(filepath, libraries=None, + combined='bin,abi', optimize=True, extra_args=None): with open(filepath) as handler: all_names = solidity_names(handler.read()) @@ -332,15 +346,25 @@ def compile_last_contract(filepath, libraries=None, combined='bin,abi', optimize ) -def compile_code(sourcecode, libraries=None, combined='bin,abi', optimize=True, extra_args=None): - args = solc_arguments(libraries=libraries, combined=combined, optimize=optimize, extra_args=extra_args) +def compile_code(sourcecode, libraries=None, combined='bin,abi', + optimize=True, extra_args=None): + args = solc_arguments( + libraries=libraries, + combined=combined, + optimize=optimize, + extra_args=extra_args) compiler = get_compiler_path() if compiler is None: raise SolcMissing("solc not found") args.insert(0, compiler) - process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdoutdata, stderrdata = process.communicate(input=utils.to_string(sourcecode)) + process = subprocess.Popen( + args, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdoutdata, stderrdata = process.communicate( + input=utils.to_string(sourcecode)) if process.returncode != 0: raise CompileError(stderrdata) @@ -356,17 +380,21 @@ class Solc(object): compiler_version = staticmethod(compiler_version) @staticmethod - def _code_or_path(sourcecode, path, contract_name, libraries, combined, extra_args): - warnings.warn('solc_wrapper is deprecated, please use the functions compile_file or compile_code') + def _code_or_path(sourcecode, path, contract_name, + libraries, combined, extra_args): + warnings.warn( + 'solc_wrapper is deprecated, please use the functions compile_file or compile_code') if sourcecode and path: raise ValueError('sourcecode and path are mutually exclusive.') if path and contract_name: - return compile_contract(path, contract_name, libraries=libraries, combined=combined, extra_args=extra_args) + return compile_contract( + path, contract_name, libraries=libraries, combined=combined, extra_args=extra_args) if path: - return compile_last_contract(path, libraries=libraries, combined=combined, extra_args=extra_args) + return compile_last_contract( + path, libraries=libraries, combined=combined, extra_args=extra_args) all_names = solidity_names(sourcecode) all_contract_names = [ @@ -375,20 +403,38 @@ def _code_or_path(sourcecode, path, contract_name, libraries, combined, extra_ar ] last_contract = all_contract_names[-1] - result = compile_code(sourcecode, libraries=libraries, combined=combined, extra_args=extra_args) + result = compile_code( + sourcecode, + libraries=libraries, + combined=combined, + extra_args=extra_args) return solidity_get_contract_data(result, path, last_contract) @classmethod - def compile(cls, code, path=None, libraries=None, contract_name='', extra_args=None): + def compile(cls, code, path=None, libraries=None, + contract_name='', extra_args=None): """ Return the binary of last contract in code. """ - result = cls._code_or_path(code, path, contract_name, libraries, 'bin', extra_args) + result = cls._code_or_path( + code, + path, + contract_name, + libraries, + 'bin', + extra_args) return result['bin'] @classmethod - def mk_full_signature(cls, code, path=None, libraries=None, contract_name='', extra_args=None): + def mk_full_signature(cls, code, path=None, libraries=None, + contract_name='', extra_args=None): "returns signature of last contract in code" - result = cls._code_or_path(code, path, contract_name, libraries, 'abi', extra_args) + result = cls._code_or_path( + code, + path, + contract_name, + libraries, + 'abi', + extra_args) return result['abi'] @classmethod diff --git a/ethereum/tools/keys.py b/ethereum/tools/keys.py index e9520c0f5..4e01a3236 100644 --- a/ethereum/tools/keys.py +++ b/ethereum/tools/keys.py @@ -27,7 +27,11 @@ import struct from math import ceil from Crypto.Hash import keccak -sha3_256 = lambda x: keccak.new(digest_bits=256, data=x) + + +def sha3_256(x): return keccak.new(digest_bits=256, data=x) + + from Crypto.Cipher import AES from Crypto.Hash import SHA256 from Crypto.Util import Counter @@ -50,7 +54,7 @@ def aes_ctr_encrypt(text, key, params): iv = big_endian_to_int(decode_hex(params["iv"])) - ctr = Counter.new(128, initial_value=iv, allow_wraparound=True) + ctr = Counter.new(128, initial_value=iv, allow_wraparound=True) mode = AES.MODE_CTR encryptor = AES.new(key, mode, counter=ctr) return encryptor.encrypt(text) @@ -58,7 +62,7 @@ def aes_ctr_encrypt(text, key, params): def aes_ctr_decrypt(text, key, params): iv = big_endian_to_int(decode_hex(params["iv"])) - ctr = Counter.new(128, initial_value=iv, allow_wraparound=True) + ctr = Counter.new(128, initial_value=iv, allow_wraparound=True) mode = AES.MODE_CTR encryptor = AES.new(key, mode, counter=ctr) return encryptor.decrypt(text) @@ -214,8 +218,8 @@ def decode_keystore_json(jsondata, pw): return o -# Utility functions (done separately from utils so as to make this a standalone file) - +# Utility functions (done separately from utils so as to make this a +# standalone file) def sha3(seed): return sha3_256(seed).digest() diff --git a/ethereum/tools/new_statetest_utils.py b/ethereum/tools/new_statetest_utils.py index 30935aa22..728d788e9 100644 --- a/ethereum/tools/new_statetest_utils.py +++ b/ethereum/tools/new_statetest_utils.py @@ -13,7 +13,7 @@ from ethereum.slogging import LogRecorder, configure_logging, set_level config_string = ':info,eth.vm.log:trace,eth.vm.op:trace,eth.vm.stack:trace,eth.vm.exit:trace,eth.pb.msg:trace,eth.pb.tx:debug' -konfig=copy.copy(default_config) +konfig = copy.copy(default_config) # configure_logging(config_string=config_string) @@ -21,11 +21,13 @@ fake_headers = {} + def mk_fake_header(blknum): if blknum not in fake_headers: fake_headers[blknum] = FakeHeader(sha3(to_string(blknum))) return fake_headers[blknum] + basic_env = { "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "currentDifficulty": "0x020000", @@ -45,6 +47,8 @@ def mk_fake_header(blknum): } # Makes a diff between a prev and post state + + def mk_state_diff(prev, post): o = {} for k in prev.keys(): @@ -67,11 +71,14 @@ def mk_state_diff(prev, post): if sk not in prev[k]["storage"]: ok["storage"][sk] = ["+", post[k]["storage"][sk]] else: - ok["storage"][sk] = [prev[k]["storage"][sk], "->", post[k]["storage"][sk]] + ok["storage"][sk] = [ + prev[k]["storage"][sk], "->", post[k]["storage"][sk]] o[k] = ok return o # Compute a single unit of a state test + + def compute_state_test_unit(state, txdata, indices, konfig): state.env.config = konfig s = state.snapshot() @@ -80,7 +87,8 @@ def compute_state_test_unit(state, txdata, indices, konfig): tx = transactions.Transaction( nonce=parse_int_or_hex(txdata['nonce'] or b"0"), gasprice=parse_int_or_hex(txdata['gasPrice'] or b"0"), - startgas=parse_int_or_hex(txdata['gasLimit'][indices["gas"]] or b"0"), + startgas=parse_int_or_hex( + txdata['gasLimit'][indices["gas"]] or b"0"), to=decode_hex(remove_0x_head(txdata['to'])), value=parse_int_or_hex(txdata['value'][indices["value"]] or b"0"), data=decode_hex(remove_0x_head(txdata['data'][indices["data"]]))) @@ -114,8 +122,8 @@ def init_state(env, pre): state = State( env=Env(config=konfig), block_prevhash=decode_hex(remove_0x_head(env['previousHash'])), - prev_headers=[mk_fake_header(i) for i in range(parse_int_or_hex(env['currentNumber']) -1, - max(-1, parse_int_or_hex(env['currentNumber']) -257), -1)], + prev_headers=[mk_fake_header(i) for i in range(parse_int_or_hex(env['currentNumber']) - 1, + max(-1, parse_int_or_hex(env['currentNumber']) - 257), -1)], block_number=parse_int_or_hex(env['currentNumber']), block_coinbase=decode_hex(remove_0x_head(env['currentCoinbase'])), block_difficulty=parse_int_or_hex(env['currentDifficulty']), @@ -139,10 +147,13 @@ def init_state(env, pre): # state.commit() return state + class EnvNotFoundException(Exception): pass # Verify a state test + + def verify_state_test(test): print("Verifying state test") if "env" not in test: @@ -158,17 +169,22 @@ def verify_state_test(test): if len(data) > 2000: data = "data<%d>" % (len(data) // 2 - 1) print("Checking for values: g %d v %d d %s (indexes g %d v %d d %d)" % ( - parse_int_or_hex(test["transaction"]['gasLimit'][result["indexes"]["gas"]]), - parse_int_or_hex(test["transaction"]['value'][result["indexes"]["value"]]), + parse_int_or_hex(test["transaction"] + ['gasLimit'][result["indexes"]["gas"]]), + parse_int_or_hex(test["transaction"] + ['value'][result["indexes"]["value"]]), data, result["indexes"]["gas"], result["indexes"]["value"], result["indexes"]["data"])) - computed = compute_state_test_unit(_state, test["transaction"], result["indexes"], configs[config_name]) + computed = compute_state_test_unit( + _state, test["transaction"], result["indexes"], configs[config_name]) if computed["hash"][-64:] != result["hash"][-64:]: for k in computed["diff"]: print(k, computed["diff"][k]) - raise Exception("Hash mismatch, computed: %s, supplied: %s" % (computed["hash"], result["hash"])) + raise Exception( + "Hash mismatch, computed: %s, supplied: %s" % + (computed["hash"], result["hash"])) else: # for k in computed["diff"]: # print(k, computed["diff"][k]) diff --git a/ethereum/tools/tester.py b/ethereum/tools/tester.py index 02791a43e..71e1ce707 100644 --- a/ethereum/tools/tester.py +++ b/ethereum/tools/tester.py @@ -50,9 +50,11 @@ except ImportError: pass + class TransactionFailed(Exception): pass + from ethereum.abi import ContractTranslator import types @@ -110,6 +112,7 @@ def kall(self, *args, **kwargs): return o[0] if len(o) == 1 else o return kall + def get_env(env): d = { None: config_spurious, @@ -126,7 +129,8 @@ class State(object): def __init__(self, genesis): self.state = genesis - def tx(self, sender=k0, to=b'\x00' * 20, value=0, data=b'', startgas=STARTGAS, gasprice=GASPRICE): + def tx(self, sender=k0, to=b'\x00' * 20, value=0, + data=b'', startgas=STARTGAS, gasprice=GASPRICE): sender_addr = privtoaddr(sender) transaction = Transaction(self.state.get_nonce(sender_addr), gasprice, startgas, to, value, data).sign(sender) @@ -135,21 +139,35 @@ def tx(self, sender=k0, to=b'\x00' * 20, value=0, data=b'', startgas=STARTGAS, g raise TransactionFailed() return output - def call(self, sender=k0, to=b'\x00' * 20, value=0, data=b'', startgas=STARTGAS, gasprice=GASPRICE): + def call(self, sender=k0, to=b'\x00' * 20, value=0, + data=b'', startgas=STARTGAS, gasprice=GASPRICE): sender_addr = privtoaddr(sender) - result = apply_message(self.state.ephemeral_clone(), sender=sender_addr, to=to, value=value, data=data, gas=startgas) + result = apply_message( + self.state.ephemeral_clone(), + sender=sender_addr, + to=to, + value=value, + data=data, + gas=startgas) if result is None: raise TransactionFailed() return result + class Chain(object): def __init__(self, alloc=base_alloc, env=None, genesis=None): if genesis: self.chain = pow_chain.Chain(genesis, reset_genesis=True) else: - self.chain = pow_chain.Chain(mk_basic_state(alloc, None, get_env(env)), reset_genesis=True) + self.chain = pow_chain.Chain( + mk_basic_state( + alloc, + None, + get_env(env)), + reset_genesis=True) self.cs = get_consensus_strategy(self.chain.env.config) - self.block = mk_block_from_prevstate(self.chain, timestamp=self.chain.state.timestamp + 1) + self.block = mk_block_from_prevstate( + self.chain, timestamp=self.chain.state.timestamp + 1) self.head_state = self.chain.state.ephemeral_clone() self.cs.initialize(self.head_state, self.block) self.last_sender = None @@ -157,7 +175,8 @@ def __init__(self, alloc=base_alloc, env=None, genesis=None): def direct_tx(self, transaction): self.last_tx = transaction - if self.last_sender is not None and privtoaddr(self.last_sender) != transaction.sender: + if self.last_sender is not None and privtoaddr( + self.last_sender) != transaction.sender: self.last_sender = None success, output = apply_transaction(self.head_state, transaction) self.block.transactions.append(transaction) @@ -165,7 +184,8 @@ def direct_tx(self, transaction): raise TransactionFailed() return output - def tx(self, sender=k0, to=b'\x00' * 20, value=0, data=b'', startgas=STARTGAS, gasprice=GASPRICE): + def tx(self, sender=k0, to=b'\x00' * 20, value=0, + data=b'', startgas=STARTGAS, gasprice=GASPRICE): sender_addr = privtoaddr(sender) self.last_sender = sender transaction = Transaction(self.head_state.get_nonce(sender_addr), gasprice, startgas, @@ -173,9 +193,16 @@ def tx(self, sender=k0, to=b'\x00' * 20, value=0, data=b'', startgas=STARTGAS, g output = self.direct_tx(transaction) return output - def call(self, sender=k0, to=b'\x00' * 20, value=0, data=b'', startgas=STARTGAS, gasprice=GASPRICE): + def call(self, sender=k0, to=b'\x00' * 20, value=0, + data=b'', startgas=STARTGAS, gasprice=GASPRICE): sender_addr = privtoaddr(sender) - result = apply_message(self.head_state.ephemeral_clone(), sender=sender_addr, to=to, value=value, data=data, gas=startgas) + result = apply_message( + self.head_state.ephemeral_clone(), + sender=sender_addr, + to=to, + value=value, + data=data, + gas=startgas) if result is None: raise TransactionFailed() return result @@ -184,21 +211,31 @@ def last_gas_used(self, with_tx=False): if len(self.head_state.receipts) == 1: diff = self.head_state.receipts[-1].gas_used else: - diff = self.head_state.receipts[-1].gas_used - self.head_state.receipts[-2].gas_used + diff = self.head_state.receipts[-1].gas_used - \ + self.head_state.receipts[-2].gas_used return diff - (not with_tx) * self.last_tx.intrinsic_gas_used - def contract(self, sourcecode, args=[], sender=k0, value=0, language=None, l=None, startgas=STARTGAS, gasprice=GASPRICE): + def contract(self, sourcecode, args=[], sender=k0, value=0, + language=None, l=None, startgas=STARTGAS, gasprice=GASPRICE): assert not (l and language) language = l or language if language == 'evm': assert len(args) == 0 - return self.tx(sender=sender, to=b'', value=value, data=sourcecode, startgas=startgas, gasprice=gasprice) + return self.tx(sender=sender, to=b'', value=value, + data=sourcecode, startgas=startgas, gasprice=gasprice) else: compiler = languages[language] interface = compiler.mk_full_signature(sourcecode) ct = ContractTranslator(interface) - code = compiler.compile(sourcecode) + (ct.encode_constructor_arguments(args) if args else b'') - addr = self.tx(sender=sender, to=b'', value=value, data=code, startgas=startgas, gasprice=gasprice) + code = compiler.compile( + sourcecode) + (ct.encode_constructor_arguments(args) if args else b'') + addr = self.tx( + sender=sender, + to=b'', + value=value, + data=code, + startgas=startgas, + gasprice=gasprice) return ABIContract(self, ct, addr) def mine(self, number_of_blocks=1, coinbase=a0): @@ -208,20 +245,27 @@ def mine(self, number_of_blocks=1, coinbase=a0): assert self.chain.add_block(self.block) b = self.block for i in range(1, number_of_blocks): - b, _ = make_head_candidate(self.chain, parent=b, timestamp=self.chain.state.timestamp + 14, coinbase=coinbase) + b, _ = make_head_candidate( + self.chain, parent=b, timestamp=self.chain.state.timestamp + 14, coinbase=coinbase) b = Miner(b).mine(rounds=100, start_nonce=0) assert self.chain.add_block(b) self.change_head(b.header.hash, coinbase) return b def change_head(self, parent, coinbase=a0): - self.head_state = self.chain.mk_poststate_of_blockhash(parent).ephemeral_clone() - self.block = mk_block_from_prevstate(self.chain, self.head_state, timestamp=self.chain.state.timestamp, coinbase=coinbase) + self.head_state = self.chain.mk_poststate_of_blockhash( + parent).ephemeral_clone() + self.block = mk_block_from_prevstate( + self.chain, + self.head_state, + timestamp=self.chain.state.timestamp, + coinbase=coinbase) self.cs.initialize(self.head_state, self.block) def snapshot(self): self.head_state.commit() - return self.head_state.snapshot(), len(self.block.transactions), self.block.number + return self.head_state.snapshot(), len( + self.block.transactions), self.block.number def revert(self, snapshot): state_snapshot, txcount, blknum = snapshot @@ -229,6 +273,7 @@ def revert(self, snapshot): self.block.transactions = self.block.transactions[:txcount] self.head_state.revert(state_snapshot) + def int_to_0x_hex(v): o = encode_hex(int_to_big_endian(v)) if o and o[0] == '0': @@ -244,21 +289,22 @@ def mk_state_test_prefill(c): "currentGasLimit": int_to_0x_hex(c.head_state.gas_limit), "currentNumber": int_to_0x_hex(c.head_state.block_number), "currentTimestamp": int_to_0x_hex(c.head_state.timestamp), - "previousHash": "0x"+encode_hex(c.head_state.prev_headers[0].hash), + "previousHash": "0x" + encode_hex(c.head_state.prev_headers[0].hash), } pre = c.head_state.to_dict() return {"env": env, "pre": pre} + def mk_state_test_postfill(c, prefill, filler_mode=False): txdata = c.last_tx.to_dict() modified_tx_data = { - "data": [ txdata["data"] ], - "gasLimit": [ int_to_0x_hex(txdata["startgas"]) ], + "data": [txdata["data"]], + "gasLimit": [int_to_0x_hex(txdata["startgas"])], "gasPrice": int_to_0x_hex(txdata["gasprice"]), "nonce": int_to_0x_hex(txdata["nonce"]), "secretKey": '0x' + encode_hex(c.last_sender), "to": txdata["to"], - "value": [ int_to_0x_hex(txdata["value"]) ], + "value": [int_to_0x_hex(txdata["value"])], } c.head_state.commit() postStateHash = '0x' + encode_hex(c.head_state.trie.root_hash) @@ -278,7 +324,9 @@ def mk_state_test_postfill(c, prefill, filler_mode=False): "transaction": modified_tx_data, } if not filler_mode: - o["post"] = {config: [ { "hash": postStateHash, "indexes": {"data": 0, "gas": 0, "value": 0} } ] } + o["post"] = {config: [{"hash": postStateHash, + "indexes": {"data": 0, "gas": 0, "value": 0}}]} else: - o["expect"] = [ {"indexes": {"data": 0, "gas": 0, "value": 0}, "network": ["Metropolis"], "result": c.head_state.to_dict() } ] + o["expect"] = [{"indexes": {"data": 0, "gas": 0, "value": 0}, "network": [ + "Metropolis"], "result": c.head_state.to_dict()}] return o diff --git a/ethereum/tools/testutils.py b/ethereum/tools/testutils.py index a8f8fcdda..380df01e2 100644 --- a/ethereum/tools/testutils.py +++ b/ethereum/tools/testutils.py @@ -10,12 +10,17 @@ fixture_path = os.path.join(os.path.dirname(__file__), '../..', 'fixtures') -fill_abi_test = lambda params: run_abi_test(params, FILL) -check_abi_test = lambda params: run_abi_test(params, VERIFY) + +def fill_abi_test(params): return run_abi_test(params, FILL) + + +def check_abi_test(params): return run_abi_test(params, VERIFY) + def bytesify(li): return [str_to_bytes(x) if isinstance(x, str) else x for x in li] + def run_abi_test(params, mode): types, args = params['types'], params['args'] out = abi.encode_abi(types, args) @@ -35,7 +40,9 @@ def run_abi_test(params, mode): 'decoding': time.time() - y } -def generate_test_params(testsource, metafunc, skip_func=None, exclude_func=None): + +def generate_test_params(testsource, metafunc, + skip_func=None, exclude_func=None): import pytest if ['filename', 'testname', 'testdata'] != metafunc.fixturenames: return @@ -78,6 +85,7 @@ def get_tests_from_file_or_dir(dname, json_only=False): o = {} for f in os.listdir(dname): fullpath = os.path.join(dname, f) - for k, v in list(get_tests_from_file_or_dir(fullpath, True).items()): + for k, v in list(get_tests_from_file_or_dir( + fullpath, True).items()): o[k] = v return o diff --git a/ethereum/transaction_queue.py b/ethereum/transaction_queue.py index 834622cb4..f188ca45c 100644 --- a/ethereum/transaction_queue.py +++ b/ethereum/transaction_queue.py @@ -2,6 +2,7 @@ heapq.heaptop = lambda x: x[0] PRIO_INFINITY = -2**100 + class OrderableTx(object): def __init__(self, prio, counter, tx): @@ -33,7 +34,8 @@ def add_transaction(self, tx, force=False): heapq.heappush(self.txs, OrderableTx(prio, self.counter, tx)) self.counter += 1 - def pop_transaction(self, max_gas=9999999999, max_seek_depth=16, min_gasprice=0): + def pop_transaction(self, max_gas=9999999999, + max_seek_depth=16, min_gasprice=0): while len(self.aside) and max_gas >= heapq.heaptop(self.aside).prio: item = heapq.heappop(self.aside) item.prio = -item.tx.gasprice diff --git a/ethereum/transactions.py b/ethereum/transactions.py index 970858e40..4e00f2fe9 100644 --- a/ethereum/transactions.py +++ b/ethereum/transactions.py @@ -14,7 +14,8 @@ log = get_logger('eth.chain.tx') -# in the yellow paper it is specified that s should be smaller than secpk1n (eq.205) +# in the yellow paper it is specified that s should be smaller than +# secpk1n (eq.205) secpk1n = 115792089237316195423570985008687907852837564279074904382605163141518161494337 null_address = b'\xff' * 20 @@ -53,12 +54,24 @@ class Transaction(rlp.Serializable): _sender = None - def __init__(self, nonce, gasprice, startgas, to, value, data, v=0, r=0, s=0): + def __init__(self, nonce, gasprice, startgas, + to, value, data, v=0, r=0, s=0): self.data = None to = utils.normalize_address(to, allow_blank=True) - super(Transaction, self).__init__(nonce, gasprice, startgas, to, value, data, v, r, s) + super( + Transaction, + self).__init__( + nonce, + gasprice, + startgas, + to, + value, + data, + v, + r, + s) if self.gasprice >= TT256 or self.startgas >= TT256 or \ self.value >= TT256 or self.nonce >= TT256: @@ -77,7 +90,8 @@ def sender(self): elif self.v >= 37: vee = self.v - self.network_id * 2 - 8 assert vee in (27, 28) - rlpdata = rlp.encode(rlp.infer_sedes(self).serialize(self)[:-3] + [self.network_id, '', '']) + rlpdata = rlp.encode(rlp.infer_sedes(self).serialize(self)[ + :-3] + [self.network_id, '', '']) sighash = utils.sha3(rlpdata) else: raise InvalidTransaction("Invalid V value") @@ -85,7 +99,8 @@ def sender(self): raise InvalidTransaction("Invalid signature values!") pub = ecrecover_to_pub(sighash, vee, self.r, self.s) if pub == b"\x00" * 64: - raise InvalidTransaction("Invalid signature (zero privkey cannot sign)") + raise InvalidTransaction( + "Invalid signature (zero privkey cannot sign)") self._sender = utils.sha3(pub)[-20:] return self._sender @@ -111,7 +126,8 @@ def sign(self, key, network_id=None): rawhash = utils.sha3(rlp.encode(self, UnsignedTransaction)) else: assert 1 <= network_id < 2**63 - 18 - rlpdata = rlp.encode(rlp.infer_sedes(self).serialize(self)[:-3] + [network_id, b'', b'']) + rlpdata = rlp.encode(rlp.infer_sedes(self).serialize(self)[ + :-3] + [network_id, b'', b'']) rawhash = utils.sha3(rlpdata) key = normalize_key(key) @@ -142,7 +158,7 @@ def intrinsic_gas_used(self): num_zero_bytes = str_to_bytes(self.data).count(ascii_chr(0)) num_non_zero_bytes = len(self.data) - num_zero_bytes return (opcodes.GTXCOST - # + (0 if self.to else opcodes.CREATE[3]) + # + (0 if self.to else opcodes.CREATE[3]) + opcodes.GTXDATAZERO * num_zero_bytes + opcodes.GTXDATANONZERO * num_non_zero_bytes) diff --git a/ethereum/trie.py b/ethereum/trie.py index b47290ff1..b0faa8d5e 100644 --- a/ethereum/trie.py +++ b/ethereum/trie.py @@ -49,6 +49,7 @@ def nibbles_to_bin(nibbles): NIBBLE_TERMINATOR = 16 + def with_terminator(nibbles): nibbles = nibbles[:] if not nibbles or nibbles[-1] != NIBBLE_TERMINATOR: @@ -132,11 +133,11 @@ def is_key_value_type(node_type): return node_type in [NODE_TYPE_LEAF, NODE_TYPE_EXTENSION] + BLANK_NODE = b'' BLANK_ROOT = utils.sha3rlp(b'') - class Trie(object): def __init__(self, db, root_hash=BLANK_ROOT): @@ -387,7 +388,11 @@ def _getany(self, node, reverse=False, path=[]): if reverse: scan_range.reverse() for i in scan_range: - o = self._getany(self._decode_to_node(node[i]), reverse=reverse, path=path + [i]) + o = self._getany( + self._decode_to_node( + node[i]), + reverse=reverse, + path=path + [i]) if o is not None: # print('found@', [i] + o, path) return [i] + o @@ -403,7 +408,8 @@ def _getany(self, node, reverse=False, path=[]): if node_type == NODE_TYPE_EXTENSION: curr_key = without_terminator(unpack_to_nibbles(node[0])) sub_node = self._decode_to_node(node[1]) - return curr_key + self._getany(sub_node, reverse=reverse, path=path + curr_key) + return curr_key + \ + self._getany(sub_node, reverse=reverse, path=path + curr_key) def _split(self, node, key): node_type = self._get_node_type(node) @@ -414,7 +420,7 @@ def _split(self, node, key): elif node_type == NODE_TYPE_BRANCH: b1 = node[:key[0]] b1 += [''] * (17 - len(b1)) - b2 = node[key[0]+1:] + b2 = node[key[0] + 1:] b2 = [''] * (17 - len(b2)) + b2 b1[16], b2[16] = b2[16], b1[16] sub = self._decode_to_node(node[key[0]]) @@ -422,7 +428,8 @@ def _split(self, node, key): b1[key[0]] = self._encode_node(sub1) if sub1 else '' b2[key[0]] = self._encode_node(sub2) if sub2 else '' return self._normalize_branch_node(b1) if len([x for x in b1 if x]) else BLANK_NODE, \ - self._normalize_branch_node(b2) if len([x for x in b2 if x]) else BLANK_NODE + self._normalize_branch_node(b2) if len( + [x for x in b2 if x]) else BLANK_NODE descend_key = without_terminator(unpack_to_nibbles(node[0])) if node_type == NODE_TYPE_LEAF: @@ -440,17 +447,21 @@ def _split(self, node, key): if not sub1: o1 = BLANK_NODE elif subtype1 in (NODE_TYPE_LEAF, NODE_TYPE_EXTENSION): - new_key = key[:len(descend_key)] + unpack_to_nibbles(sub1[0]) + new_key = key[:len(descend_key)] + \ + unpack_to_nibbles(sub1[0]) o1 = [pack_nibbles(new_key), sub1[1]] else: - o1 = [pack_nibbles(key[:len(descend_key)]), self._encode_node(sub1)] + o1 = [pack_nibbles(key[:len(descend_key)]), + self._encode_node(sub1)] if not sub2: o2 = BLANK_NODE elif subtype2 in (NODE_TYPE_LEAF, NODE_TYPE_EXTENSION): - new_key = key[:len(descend_key)] + unpack_to_nibbles(sub2[0]) + new_key = key[:len(descend_key)] + \ + unpack_to_nibbles(sub2[0]) o2 = [pack_nibbles(new_key), sub2[1]] else: - o2 = [pack_nibbles(key[:len(descend_key)]), self._encode_node(sub2)] + o2 = [pack_nibbles(key[:len(descend_key)]), + self._encode_node(sub2)] return o1, o2 elif descend_key < key[:len(descend_key)]: return node, BLANK_NODE @@ -485,12 +496,14 @@ def _merge(self, node1, node2): break prefix_length = i + 1 if prefix_length: - sub1 = self._decode_to_node(node1[1]) if node_type1 == NODE_TYPE_EXTENSION else node1[1] + sub1 = self._decode_to_node( + node1[1]) if node_type1 == NODE_TYPE_EXTENSION else node1[1] new_sub1 = [ pack_nibbles(descend_key1[prefix_length:]), sub1 ] if descend_key1[prefix_length:] else sub1 - sub2 = self._decode_to_node(node2[1]) if node_type2 == NODE_TYPE_EXTENSION else node2[1] + sub2 = self._decode_to_node( + node2[1]) if node_type2 == NODE_TYPE_EXTENSION else node2[1] new_sub2 = [ pack_nibbles(descend_key2[prefix_length:]), sub2 @@ -510,7 +523,12 @@ def _merge(self, node1, node2): node[0] = new_node node1, node2 = nodes[0][0], nodes[1][0] assert len([i for i in range(17) if node1[i] and node2[i]]) <= 1 - new_node = [self._encode_node(self._merge(self._decode_to_node(node1[i]), self._decode_to_node(node2[i]))) if node1[i] and node2[i] else node1[i] or node2[i] for i in range(17)] + new_node = [ + self._encode_node( + self._merge( + self._decode_to_node( + node1[i]), self._decode_to_node( + node2[i]))) if node1[i] and node2[i] else node1[i] or node2[i] for i in range(17)] return new_node @classmethod @@ -797,7 +815,11 @@ def _iter_branch(self, node): for i in range(16): sub_tree = self._iter_branch(self._decode_to_node(node[i])) for sub_key, sub_value in sub_tree: - full_key = (str_to_bytes(str(i)) + b'+' + sub_key).strip(b'+') + full_key = ( + str_to_bytes( + str(i)) + + b'+' + + sub_key).strip(b'+') yield (full_key, sub_value) if node[16]: yield (to_string(NIBBLE_TERMINATOR), node[-1]) @@ -847,7 +869,11 @@ def _to_dict(self, node): sub_dict = self._to_dict(self._decode_to_node(node[i])) for sub_key, sub_value in sub_dict.items(): - full_key = (str_to_bytes(str(i)) + b'+' + sub_key).strip(b'+') + full_key = ( + str_to_bytes( + str(i)) + + b'+' + + sub_key).strip(b'+') res[full_key] = sub_value if node[16]: diff --git a/ethereum/utils.py b/ethereum/utils.py index e82ab0c53..8bc8b9854 100644 --- a/ethereum/utils.py +++ b/ethereum/utils.py @@ -1,9 +1,11 @@ try: from Crypto.Hash import keccak - sha3_256 = lambda x: keccak.new(digest_bits=256, data=x).digest() + + def sha3_256(x): return keccak.new(digest_bits=256, data=x).digest() except ImportError: import sha3 as _sha3 - sha3_256 = lambda x: _sha3.keccak_256(x).digest() + + def sha3_256(x): return _sha3.keccak_256(x).digest() from py_ecc.secp256k1 import privtopub, ecdsa_raw_sign, ecdsa_raw_recover import sys import rlp @@ -19,8 +21,12 @@ warnings.warn('could not import coincurve', ImportWarning) coincurve = None -big_endian_to_int = lambda x: big_endian_int.deserialize(str_to_bytes(x).lstrip(b'\x00')) -int_to_big_endian = lambda x: big_endian_int.serialize(x) + +def big_endian_to_int(x): return big_endian_int.deserialize( + str_to_bytes(x).lstrip(b'\x00')) + + +def int_to_big_endian(x): return big_endian_int.serialize(x) TT256 = 2 ** 256 @@ -29,8 +35,9 @@ SECP256K1P = 2**256 - 4294968273 if sys.version_info.major == 2: - is_numeric = lambda x: isinstance(x, (int, long)) - is_string = lambda x: isinstance(x, (str, unicode)) + def is_numeric(x): return isinstance(x, (int, long)) + + def is_string(x): return isinstance(x, (str, unicode)) def to_string(value): return str(value) @@ -54,8 +61,9 @@ def bytes_to_int(value): return big_endian_to_int(bytes(''.join(chr(c) for c in value))) else: - is_numeric = lambda x: isinstance(x, int) - is_string = lambda x: isinstance(x, bytes) + def is_numeric(x): return isinstance(x, int) + + def is_string(x): return isinstance(x, bytes) def to_string(value): if isinstance(value, bytes): @@ -94,7 +102,7 @@ def ecrecover_to_pub(rawhash, v, r, s): hasher=None, ) pub = pk.format(compressed=False)[1:] - except: + except BaseException: pub = b"\x00" * 64 else: x, y = ecdsa_raw_recover(rawhash, (v, r, s)) @@ -171,16 +179,18 @@ def int_to_32bytearray(i): def sha3(seed): return sha3_256(to_string(seed)) -assert encode_hex(sha3(b'')) == 'c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470' + +assert encode_hex( + sha3(b'')) == 'c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470' def privtoaddr(k): k = normalize_key(k) - x, y = privtopub(k) + x, y = privtopub(k) return sha3(encode_int32(x) + encode_int32(y))[12:] -def checksum_encode(addr): # Takes a 20-byte binary address as input +def checksum_encode(addr): # Takes a 20-byte binary address as input addr = normalize_address(addr) o = '' v = big_endian_to_int(sha3(encode_hex(addr))) @@ -188,12 +198,14 @@ def checksum_encode(addr): # Takes a 20-byte binary address as input if c in '0123456789': o += c else: - o += c.upper() if (v & (2**(255 - 4*i))) else c.lower() - return '0x'+o + o += c.upper() if (v & (2**(255 - 4 * i))) else c.lower() + return '0x' + o + def check_checksum(addr): return checksum_encode(normalize_address(addr)) == addr + def normalize_address(x, allow_blank=False): if is_numeric(x): return int_to_addr(x) @@ -210,6 +222,7 @@ def normalize_address(x, allow_blank=False): raise Exception("Invalid address format: %r" % x) return x + def normalize_key(key): if is_numeric(key): o = encode_int32(key) @@ -225,6 +238,7 @@ def normalize_key(key): raise Exception("Zero privkey invalid") return o + def zpad(x, l): """ Left zero pad value `x` at least to length `l`. @@ -239,6 +253,7 @@ def zpad(x, l): """ return b'\x00' * max(0, l - len(x)) + x + def rzpad(value, total_length): """ Right zero pad value `x` at least to length `l`. @@ -253,6 +268,7 @@ def rzpad(value, total_length): """ return value + b'\x00' * max(0, total_length - len(value)) + def int_to_addr(x): o = [b''] * 20 for i in range(20): @@ -432,7 +448,8 @@ def parse_as_bin(s): def parse_as_int(s): - return s if is_numeric(s) else int('0' + s[2:], 16) if s[:2] == '0x' else int(s) + return s if is_numeric(s) else int( + '0' + s[2:], 16) if s[:2] == '0x' else int(s) def print_func_call(ignore_first_arg=False, max_call_number=100): @@ -454,7 +471,7 @@ def display(x): x = to_string(x) try: x.decode('ascii') - except: + except BaseException: return 'NON_PRINTABLE' return x diff --git a/ethereum/vm.py b/ethereum/vm.py index 200049720..5bcc3eb73 100644 --- a/ethereum/vm.py +++ b/ethereum/vm.py @@ -34,6 +34,7 @@ MAX_DEPTH = 1024 + # Wrapper to store call data. This is needed because it is possible to # call a contract N times with N bytes of data with a gas cost of O(N); # if implemented naively this would require O(N**2) bytes of data @@ -75,12 +76,13 @@ def extract_copy(self, mem, memstart, datastart, size): class Message(object): def __init__(self, sender, to, value=0, gas=1000000, data='', depth=0, - code_address=None, is_create=False, transfers_value=True, static=False): + code_address=None, is_create=False, transfers_value=True, static=False): self.sender = sender self.to = to self.value = value self.gas = gas - self.data = CallData(list(map(utils.safe_ord, data))) if isinstance(data, (str, bytes)) else data + self.data = CallData(list(map(utils.safe_ord, data))) if isinstance( + data, (str, bytes)) else data self.depth = depth self.logs = [] self.code_address = to if code_address is None else code_address @@ -118,7 +120,8 @@ def preprocess_code(code): if codebyte == 0x5b: o |= 1 << i if 0x60 <= codebyte <= 0x7f: - pushcache[i] = utils.big_endian_to_int(code[i + 1: i + codebyte - 0x5e]) + pushcache[i] = utils.big_endian_to_int( + code[i + 1: i + codebyte - 0x5e]) i += codebyte - 0x5e else: i += 1 @@ -248,11 +251,11 @@ def vm_execute(ext, msg, code): if len(compustate.memory) < 4096: trace_data['memory'] = \ ''.join([encode_hex(ascii_chr(x)) for x - in compustate.memory]) + in compustate.memory]) else: trace_data['sha3memory'] = \ encode_hex(utils.sha3(b''.join([ascii_chr(x) for - x in compustate.memory]))) + x in compustate.memory]))) if _prevop in ('SSTORE',) or steps == 0: trace_data['storage'] = ext.log_storage(msg.to) trace_data['gas'] = to_string(compustate.gas + fee) @@ -273,7 +276,8 @@ def vm_execute(ext, msg, code): # Pushes first because they are very frequent if 0x60 <= opcode <= 0x7f: stk.append(pushcache[compustate.pc - 1]) - compustate.pc += opcode - 0x5f # Move 1 byte forward for 0x60, up to 32 bytes for 0x7f + # Move 1 byte forward for 0x60, up to 32 bytes for 0x7f + compustate.pc += opcode - 0x5f # Arithmetic elif opcode < 0x10: if op == 'STOP': @@ -372,7 +376,8 @@ def vm_execute(ext, msg, code): stk.append(utils.coerce_to_int(msg.to)) elif op == 'BALANCE': if ext.post_anti_dos_hardfork(): - if not eat_gas(compustate, opcodes.BALANCE_SUPPLEMENTAL_GAS): + if not eat_gas(compustate, + opcodes.BALANCE_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) stk.append(ext.get_balance(addr)) @@ -421,13 +426,15 @@ def vm_execute(ext, msg, code): stk.append(ext.tx_gasprice) elif op == 'EXTCODESIZE': if ext.post_anti_dos_hardfork(): - if not eat_gas(compustate, opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS): + if not eat_gas(compustate, + opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) stk.append(len(ext.get_code(addr) or b'')) elif op == 'EXTCODECOPY': if ext.post_anti_dos_hardfork(): - if not eat_gas(compustate, opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS): + if not eat_gas(compustate, + opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) start, s2, size = stk.pop(), stk.pop(), stk.pop() @@ -449,7 +456,10 @@ def vm_execute(ext, msg, code): bh_addr = ext.blockhash_store stk.append(ext.get_storage_data(bh_addr, stk.pop())) else: - stk.append(utils.big_endian_to_int(ext.block_hash(stk.pop()))) + stk.append( + utils.big_endian_to_int( + ext.block_hash( + stk.pop()))) elif op == 'COINBASE': stk.append(utils.big_endian_to_int(ext.block_coinbase)) elif op == 'TIMESTAMP': @@ -487,7 +497,8 @@ def vm_execute(ext, msg, code): elif op == 'SSTORE': s0, s1 = stk.pop(), stk.pop() if msg.static: - return vm_exception('Cannot SSTORE inside a static context') + return vm_exception( + 'Cannot SSTORE inside a static context') if ext.get_storage_data(msg.to, s0): gascost = opcodes.GSTORAGEMOD if s1 else opcodes.GSTORAGEKILL refund = 0 if s1 else opcodes.GSTORAGEREFUND @@ -497,17 +508,20 @@ def vm_execute(ext, msg, code): if compustate.gas < gascost: return vm_exception('OUT OF GAS') compustate.gas -= gascost - ext.add_refund(refund) # adds neg gascost as a refund if below zero + # adds neg gascost as a refund if below zero + ext.add_refund(refund) ext.set_storage_data(msg.to, s0, s1) elif op == 'JUMP': compustate.pc = stk.pop() - if compustate.pc >= codelen or not ((1 << compustate.pc) & jumpdest_mask): + if compustate.pc >= codelen or not ( + (1 << compustate.pc) & jumpdest_mask): return vm_exception('BAD JUMPDEST') elif op == 'JUMPI': s0, s1 = stk.pop(), stk.pop() if s1: compustate.pc = s0 - if compustate.pc >= codelen or not ((1 << compustate.pc) & jumpdest_mask): + if compustate.pc >= codelen or not ( + (1 << compustate.pc) & jumpdest_mask): return vm_exception('BAD JUMPDEST') elif op == 'PC': stk.append(compustate.pc - 1) @@ -517,10 +531,12 @@ def vm_execute(ext, msg, code): stk.append(compustate.gas) # AFTER subtracting cost 1 # DUPn (eg. DUP1: a b c -> a b c c, DUP3: a b c -> a b c a) elif op[:3] == 'DUP': - stk.append(stk[0x7f - opcode]) # 0x7f - opcode is a negative number, -1 for 0x80 ... -16 for 0x8f + # 0x7f - opcode is a negative number, -1 for 0x80 ... -16 for 0x8f + stk.append(stk[0x7f - opcode]) # SWAPn (eg. SWAP1: a b c d -> a b d c, SWAP3: a b c d -> d b c a) elif op[:4] == 'SWAP': - temp = stk[0x8e - opcode] # 0x8e - opcode is a negative number, -2 for 0x90 ... -17 for 0x9f + # 0x8e - opcode is a negative number, -2 for 0x90 ... -17 for 0x9f + temp = stk[0x8e - opcode] stk[0x8e - opcode] = stk[-1] stk[-1] = temp # Logs (aka "events") @@ -547,7 +563,8 @@ def vm_execute(ext, msg, code): return vm_exception('OOG EXTENDING MEMORY') data = bytearray_to_bytestr(mem[mstart: mstart + msz]) ext.log(msg.to, topics, data) - log_log.trace('LOG', to=msg.to, topics=topics, data=list(map(utils.safe_ord, data))) + log_log.trace('LOG', to=msg.to, topics=topics, + data=list(map(utils.safe_ord, data))) # print('LOG', msg.to, topics, list(map(ord, data))) # Create a new contract elif op == 'CREATE': @@ -561,7 +578,8 @@ def vm_execute(ext, msg, code): ingas = compustate.gas if ext.post_anti_dos_hardfork(): ingas = all_but_1n(ingas, opcodes.CALL_CHILD_LIMIT_DENOM) - create_msg = Message(msg.to, b'', value, ingas, cd, msg.depth + 1) + create_msg = Message( + msg.to, b'', value, ingas, cd, msg.depth + 1) o, gas, addr = ext.create(create_msg) if o: stk.append(utils.coerce_to_int(addr)) @@ -582,7 +600,8 @@ def vm_execute(ext, msg, code): value = 0 # Static context prohibition if msg.static and value > 0 and op == 'CALL': - return vm_exception('Cannot make a non-zero-value call inside a static context') + return vm_exception( + 'Cannot make a non-zero-value call inside a static context') # Expand memory if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ not mem_extend(mem, compustate, op, memoutstart, memoutsz): @@ -591,7 +610,8 @@ def vm_execute(ext, msg, code): # Extra gas costs based on various factors extra_gas = 0 # Creating a new account - if op == 'CALL' and not ext.account_exists(to) and (value > 0 or not ext.post_spurious_dragon_hardfork()): + if op == 'CALL' and not ext.account_exists(to) and ( + value > 0 or not ext.post_spurious_dragon_hardfork()): extra_gas += opcodes.GCALLNEWACCOUNT # Value transfer if value > 0: @@ -603,10 +623,15 @@ def vm_execute(ext, msg, code): if ext.post_anti_dos_hardfork(): if compustate.gas < extra_gas: return vm_exception('OUT OF GAS', needed=extra_gas) - gas = min(gas, all_but_1n(compustate.gas - extra_gas, opcodes.CALL_CHILD_LIMIT_DENOM)) + gas = min( + gas, + all_but_1n( + compustate.gas - + extra_gas, + opcodes.CALL_CHILD_LIMIT_DENOM)) else: if compustate.gas < gas + extra_gas: - return vm_exception('OUT OF GAS', needed=gas+extra_gas) + return vm_exception('OUT OF GAS', needed=gas + extra_gas) submsg_gas = gas + opcodes.GSTIPEND * (value > 0) # Verify that there is sufficient balance and depth if ext.get_balance(msg.to) < value or msg.depth >= MAX_DEPTH: @@ -668,13 +693,19 @@ def vm_execute(ext, msg, code): xfer = ext.get_balance(msg.to) if ext.post_anti_dos_hardfork(): extra_gas = opcodes.SUICIDE_SUPPLEMENTAL_GAS + \ - (not ext.account_exists(to)) * (xfer > 0 or not ext.post_spurious_dragon_hardfork()) * opcodes.GCALLNEWACCOUNT + (not ext.account_exists(to)) * (xfer > + 0 or not ext.post_spurious_dragon_hardfork()) * opcodes.GCALLNEWACCOUNT if not eat_gas(compustate, extra_gas): return vm_exception("OUT OF GAS") ext.set_balance(to, ext.get_balance(to) + xfer) ext.set_balance(msg.to, 0) ext.add_suicide(msg.to) - log_msg.debug('SUICIDING', addr=utils.checksum_encode(msg.to), to=utils.checksum_encode(to), xferring=xfer) + log_msg.debug( + 'SUICIDING', + addr=utils.checksum_encode( + msg.to), + to=utils.checksum_encode(to), + xferring=xfer) return peaceful_exit('SUICIDED', compustate.gas, []) return peaceful_exit('CODE OUT OF RANGE', compustate.gas, []) diff --git a/setup.py b/setup.py index c2b1c6220..ed12940bb 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,9 @@ install_requires_replacements = { 'https://github.com/ethereum/ethash/tarball/master': 'pyethash', } -install_requires = [install_requires_replacements.get(r, r) for r in install_requires] +install_requires = [ + install_requires_replacements.get( + r, r) for r in install_requires] # dev requirements tests_require = set(x.strip() for x in open('dev_requirements.txt')) @@ -20,7 +22,8 @@ tests_require = [tests_require_replacements.get(r, r) for r in tests_require] # *IMPORTANT*: Don't manually change the version here. Use the 'bumpversion' utility. -# see: https://github.com/ethereum/pyethapp/wiki/Development:-Versions-and-Releases +# see: +# https://github.com/ethereum/pyethapp/wiki/Development:-Versions-and-Releases version = '2.0.4' setup( @@ -32,7 +35,7 @@ install_requires=install_requires, tests_require=tests_require, setup_requires=[ - # 'pytest-runner==2.7' + # 'pytest-runner==2.7' ], version=version, classifiers=[ diff --git a/tools/fixture_to_example.py b/tools/fixture_to_example.py index d48e1ac78..d4758ad9a 100644 --- a/tools/fixture_to_example.py +++ b/tools/fixture_to_example.py @@ -29,8 +29,7 @@ def fixture_to_tables(fixture): rows = [] # header(keyword) row - keys = content.keys() - keys.sort() + keys = sorted(content.keys()) rows.append(tuple(keys)) # item(value) row diff --git a/tools/keystorer.py b/tools/keystorer.py index 70c5d844c..93d703762 100644 --- a/tools/keystorer.py +++ b/tools/keystorer.py @@ -1,13 +1,15 @@ #!/usr/bin/python2.7 -import sys, json, os +import sys +import json +import os import getpass try: import keys -except: +except BaseException: try: import ethereum.keys as keys - except: + except BaseException: raise Exception("keys module not found") @@ -26,7 +28,7 @@ print("Applying hard key derivation function. Wait a little") j = keys.make_keystore_json(key, pw) print(j) - open(j["id"]+'.json', 'w').write(json.dumps(j, indent=4)) + open(j["id"] + '.json', 'w').write(json.dumps(j, indent=4)) print("Wallet creation successful, file saved at: " + j["id"] + ".json") # Decode a json elif sys.argv[1] in ('getprivkey', 'getaddress'): diff --git a/tools/mk_ecadd_tests.py b/tools/mk_ecadd_tests.py index 43f4c830f..83dc73733 100644 --- a/tools/mk_ecadd_tests.py +++ b/tools/mk_ecadd_tests.py @@ -19,6 +19,7 @@ def foo(x: bytes <= 192) -> bytes <= 64: x1 = c.contract(kode, language='viper') + def mk_ecadd_data(p1, p2): if isinstance(p1[0], py_pairing.FQ): p1 = py_pairing.normalize(p1) @@ -26,18 +27,31 @@ def mk_ecadd_data(p1, p2): if isinstance(p2[0], py_pairing.FQ): p2 = py_pairing.normalize(p2) p2 = (p2[0].n, p2[1].n) - return encode_int32(p1[0]) + encode_int32(p1[1]) + encode_int32(p2[0]) + encode_int32(p2[1]) + return encode_int32(p1[0]) + encode_int32(p1[1]) + \ + encode_int32(p2[0]) + encode_int32(p2[1]) + def intrinsic_gas_of_data(d): - return opcodes.GTXDATAZERO * d.count(0) + opcodes.GTXDATANONZERO * (len(d) - d.count(0)) + return opcodes.GTXDATAZERO * \ + d.count(0) + opcodes.GTXDATANONZERO * (len(d) - d.count(0)) + def mk_test(p1, p2, execgas, datarestrict=128): - encoded = mk_ecadd_data(p1, p2)[:datarestrict] + b'\x00' * max(datarestrict - 128, 0) + encoded = mk_ecadd_data(p1, p2)[:datarestrict] + \ + b'\x00' * max(datarestrict - 128, 0) pre = tester.mk_state_test_prefill(c) try: - o = x1.foo(encoded, startgas=21000 + intrinsic_gas_of_data(x1.translator.encode('foo', [encoded])) + execgas) + o = x1.foo( + encoded, + startgas=21000 + + intrinsic_gas_of_data( + x1.translator.encode( + 'foo', + [encoded])) + + execgas) x, y = big_endian_to_int(o[:32]), big_endian_to_int(o[32:]) - if py_pairing.normalize(py_pairing.add(p1, p2)) != (py_pairing.FQ(x), py_pairing.FQ(y)): + if py_pairing.normalize(py_pairing.add(p1, p2)) != ( + py_pairing.FQ(x), py_pairing.FQ(y)): raise Exception("Mismatch! %r %r %d, expected %r computed %r" % (p1, p2, datarestrict, py_pairing.normalize(py_pairing.add(p1, p2)), (x, y))) print('Succeeded! %r %r %d %r' % (p1, p2, datarestrict, (x, y))) @@ -48,6 +62,7 @@ def mk_test(p1, p2, execgas, datarestrict=128): assert new_statetest_utils.verify_state_test(o) return o, o2 + gaslimits = [21000, 25000] zero = (py_pairing.FQ(1), py_pairing.FQ(1), py_pairing.FQ(0)) @@ -71,8 +86,14 @@ def mk_test(p1, p2, execgas, datarestrict=128): tests.append((py_pairing.G1, zero, g, 192)) tests.append((py_pairing.G1, py_pairing.G1, g, 128)) tests.append((py_pairing.G1, py_pairing.G1, g, 192)) - tests.append((py_pairing.multiply(py_pairing.G1, 5), py_pairing.multiply(py_pairing.G1, 9), g, 128)) - tests.append((py_pairing.multiply(py_pairing.G1, 5), py_pairing.multiply(py_pairing.G1, py_pairing.curve_order - 5), g, 192)) + tests.append( + (py_pairing.multiply( + py_pairing.G1, 5), py_pairing.multiply( + py_pairing.G1, 9), g, 128)) + tests.append( + (py_pairing.multiply( + py_pairing.G1, 5), py_pairing.multiply( + py_pairing.G1, py_pairing.curve_order - 5), g, 192)) tests.append((zero, wrong1, g, 128)) tests.append((wrong1, zero, g, 80)) tests.append((wrong2, py_pairing.G1, g, 128)) @@ -84,8 +105,16 @@ def mk_test(p1, p2, execgas, datarestrict=128): for test in tests: o1, o2 = mk_test(*test) n1, n2 = py_pairing.normalize(test[0]), py_pairing.normalize(test[1]) - testout["ecadd_%r-%r_%r-%r_%d_%d" % (n1[0], n1[1], n2[0], n2[1], test[2], test[3])] = o1 - o2["explanation"] = "Puts the points %r and %r into the ECADD precompile, truncating or expanding the input data to %d bytes. Gives the execution %d bytes" % (n1, n2, test[3], test[2]) - testout_filler["ecadd_%r-%r_%r-%r_%d_%d" % (n1[0], n1[1], n2[0], n2[1], test[2], test[3])] = o2 + testout["ecadd_%r-%r_%r-%r_%d_%d" % + (n1[0], n1[1], n2[0], n2[1], test[2], test[3])] = o1 + o2["explanation"] = "Puts the points %r and %r into the ECADD precompile, truncating or expanding the input data to %d bytes. Gives the execution %d bytes" % ( + n1, n2, test[3], test[2]) + testout_filler["ecadd_%r-%r_%r-%r_%d_%d" % + (n1[0], n1[1], n2[0], n2[1], test[2], test[3])] = o2 open('ecadd_tests.json', 'w').write(json.dumps(testout, indent=4)) -open('ecadd_tests_filler.json', 'w').write(json.dumps(testout_filler, indent=4)) +open( + 'ecadd_tests_filler.json', + 'w').write( + json.dumps( + testout_filler, + indent=4)) diff --git a/tools/mk_ecmul_tests.py b/tools/mk_ecmul_tests.py index bbbc5e4ef..a855bfab0 100644 --- a/tools/mk_ecmul_tests.py +++ b/tools/mk_ecmul_tests.py @@ -19,22 +19,35 @@ def foo(x: bytes <= 192) -> bytes <= 64: x1 = c.contract(kode, language='viper') + def mk_ecmul_data(p1, m): if isinstance(p1[0], py_pairing.FQ): p1 = py_pairing.normalize(p1) p1 = (p1[0].n, p1[1].n) return encode_int32(p1[0]) + encode_int32(p1[1]) + encode_int32(m) + def intrinsic_gas_of_data(d): - return opcodes.GTXDATAZERO * d.count(0) + opcodes.GTXDATANONZERO * (len(d) - d.count(0)) + return opcodes.GTXDATAZERO * \ + d.count(0) + opcodes.GTXDATANONZERO * (len(d) - d.count(0)) + def mk_test(p1, m, execgas, datarestrict=96): - encoded = mk_ecmul_data(p1, m)[:datarestrict] + b'\x00' * max(datarestrict - 96, 0) + encoded = mk_ecmul_data(p1, m)[:datarestrict] + \ + b'\x00' * max(datarestrict - 96, 0) pre = tester.mk_state_test_prefill(c) try: - o = x1.foo(encoded, startgas=21000 + intrinsic_gas_of_data(x1.translator.encode('foo', [encoded])) + execgas) + o = x1.foo( + encoded, + startgas=21000 + + intrinsic_gas_of_data( + x1.translator.encode( + 'foo', + [encoded])) + + execgas) x, y = big_endian_to_int(o[:32]), big_endian_to_int(o[32:]) - if py_pairing.normalize(py_pairing.multiply(p1, m)) != (py_pairing.FQ(x), py_pairing.FQ(y)): + if py_pairing.normalize(py_pairing.multiply(p1, m)) != ( + py_pairing.FQ(x), py_pairing.FQ(y)): raise Exception("Mismatch! %r %r %d, expected %r computed %r" % (p1, m, datarestrict, py_pairing.normalize(py_pairing.multiply(p1, m)), (x, y))) print('Succeeded! %r %d %d %r' % (p1, m, datarestrict, (x, y))) @@ -52,8 +65,25 @@ def mk_test(p1, m, execgas, datarestrict=96): wrong2 = (py_pairing.FQ(0), py_pairing.FQ(3), py_pairing.FQ(1)) gaslimits = [21000, 28000] -mults = [0, 1, 2, 9, 2**128, py_pairing.curve_order - 1, py_pairing.curve_order, 2**256 - 1] -pts = [zero, py_pairing.G1, py_pairing.multiply(py_pairing.G1, 98723629835235), wrong1, wrong2] +mults = [ + 0, + 1, + 2, + 9, + 2**128, + py_pairing.curve_order - + 1, + py_pairing.curve_order, + 2**256 - + 1] +pts = [ + zero, + py_pairing.G1, + py_pairing.multiply( + py_pairing.G1, + 98723629835235), + wrong1, + wrong2] tests = [] for g in gaslimits: @@ -75,8 +105,16 @@ def mk_test(p1, m, execgas, datarestrict=96): for test in tests: o1, o2 = mk_test(*test) n = py_pairing.normalize(test[0]) - testout["ecmul_%r-%r_%d_%d_%d" % (n[0], n[1], test[1], test[2], test[3])] = o1 - o2["explanation"] = "Puts the point %r and the factor %d into the ECMUL precompile, truncating or expanding the input data to %d bytes. Gives the execution %d bytes" % (n, test[1], test[3], test[2]) - testout_filler["ecmul_%r-%r_%d_%d_%d" % (n[0], n[1], test[1], test[2], test[3])] = o2 + testout["ecmul_%r-%r_%d_%d_%d" % + (n[0], n[1], test[1], test[2], test[3])] = o1 + o2["explanation"] = "Puts the point %r and the factor %d into the ECMUL precompile, truncating or expanding the input data to %d bytes. Gives the execution %d bytes" % ( + n, test[1], test[3], test[2]) + testout_filler["ecmul_%r-%r_%d_%d_%d" % + (n[0], n[1], test[1], test[2], test[3])] = o2 open('ecmul_tests.json', 'w').write(json.dumps(testout, indent=4)) -open('ecmul_tests_filler.json', 'w').write(json.dumps(testout_filler, indent=4)) +open( + 'ecmul_tests_filler.json', + 'w').write( + json.dumps( + testout_filler, + indent=4)) diff --git a/tools/mk_ecpairing_tests.py b/tools/mk_ecpairing_tests.py index bac9c3c1c..19a2cccb4 100644 --- a/tools/mk_ecpairing_tests.py +++ b/tools/mk_ecpairing_tests.py @@ -24,7 +24,8 @@ def foo(x: bytes <= 1920) -> bytes <= 32: # Generate a point on the G2 curve, but not in the correct subgroup fake_point = None FQ2_one = py_pairing.FQ2.one() -big_order = py_pairing.curve_order * (py_pairing.field_modulus * 2 - py_pairing.curve_order) +big_order = py_pairing.curve_order * \ + (py_pairing.field_modulus * 2 - py_pairing.curve_order) G1_zero = (py_pairing.FQ.one(), py_pairing.FQ.one(), py_pairing.FQ.zero()) G2_zero = (FQ2_one, FQ2_one, py_pairing.FQ2.zero()) for i in range(200): @@ -33,10 +34,12 @@ def foo(x: bytes <= 1920) -> bytes <= 32: y = ysquared ** ((py_pairing.field_modulus ** 2 + 15) // 32) if y ** 2 == ysquared: assert py_pairing.multiply((x, y, FQ2_one), big_order) == G2_zero - assert py_pairing.multiply((x, y, FQ2_one), py_pairing.curve_order) != G2_zero + assert py_pairing.multiply( + (x, y, FQ2_one), py_pairing.curve_order) != G2_zero fake_point = (x, y, FQ2_one) break + def mk_ecpairing_data(pts): o = b'' for p, q in pts: @@ -46,16 +49,29 @@ def mk_ecpairing_data(pts): encode_int32(nq[1].coeffs[1]) + encode_int32(nq[1].coeffs[0]) return o + def perturb(inp, pos, by): - return inp[:pos] + encode_int32(big_endian_to_int(inp[pos: pos + 32]) + by) + inp[pos + 32:] + return inp[:pos] + \ + encode_int32(big_endian_to_int( + inp[pos: pos + 32]) + by) + inp[pos + 32:] + def intrinsic_gas_of_data(d): - return opcodes.GTXDATAZERO * d.count(0) + opcodes.GTXDATANONZERO * (len(d) - d.count(0)) + return opcodes.GTXDATAZERO * \ + d.count(0) + opcodes.GTXDATANONZERO * (len(d) - d.count(0)) + def mk_test(encoded, execgas, expect): pre = tester.mk_state_test_prefill(c) try: - o = x1.foo(encoded, startgas=21000 + intrinsic_gas_of_data(x1.translator.encode('foo', [encoded])) + execgas) + o = x1.foo( + encoded, + startgas=21000 + + intrinsic_gas_of_data( + x1.translator.encode( + 'foo', + [encoded])) + + execgas) except tester.TransactionFailed: o = False if o is False: @@ -74,6 +90,7 @@ def mk_test(encoded, execgas, expect): assert new_statetest_utils.verify_state_test(o) return o, o2 + tests = [] G1, G2 = py_pairing.G1, py_pairing.G2 m = py_pairing.multiply @@ -81,33 +98,58 @@ def mk_test(encoded, execgas, expect): fm = py_pairing.field_modulus tests.append((b'', GPB - 1, 'error', 'empty_data_insufficient_gas')) tests.append((b'', GPB + 30000, 'yes', 'empty_data')) -tests.append((mk_ecpairing_data([(G1, G2)]), GPB + 30000, 'error', 'one_point_insufficient_gas')) -tests.append((mk_ecpairing_data([(G1, G2)]), GPB + GPP + 30000, 'no', 'one_point_fail')) -tests.append((mk_ecpairing_data([(G1_zero, G2)]), GPB + GPP + 30000, 'yes', 'one_point_with_g1_zero')) -tests.append((mk_ecpairing_data([(G1, G2_zero)]), GPB + GPP + 30000, 'yes', 'one_point_with_g2_zero')) -tests.append((mk_ecpairing_data([(G1, G2)])[:191], GPB + GPP + 30000, 'error', 'bad_length_191')) -tests.append((mk_ecpairing_data([(G1, G2)]) + b'\x00', GPB + GPP + 30000, 'error', 'bad_length_193')) -tests.append((mk_ecpairing_data([(G1, G2), (G1, G2)]), GPB + GPP * 2 + 30000, 'no', 'two_point_fail_1')) -tests.append((mk_ecpairing_data([(G1, G2_zero), (G1, G2)]), GPB + GPP * 2 + 30000, 'no', 'two_points_with_one_g2_zero')) -tests.append((mk_ecpairing_data([(G1, G2), (m(G1, co - 1), G2)]), GPB + GPP * 2 + 30000, 'yes', 'two_point_match_1')) -tests.append((mk_ecpairing_data([(G1, G2), (m(G1, co - 1), G2)]), GPB + GPP + 30000, 'error', 'two_point_oog')) -tests.append((mk_ecpairing_data([(G1, G2), (G1, m(G2, co - 1))]), GPB + GPP * 2 + 30000, 'yes', 'two_point_match_2')) -tests.append((mk_ecpairing_data([(G1, m(G2, 2)), (m(G1, co - 2), G2)]), GPB + GPP * 2 + 30000, 'yes', 'two_point_match_3')) -tests.append((mk_ecpairing_data([(m(G1, 27), m(G2, 37)), (G1, m(G2, co - 999))]), GPB + GPP * 2 + 30000, 'yes', 'two_point_match_4')) -tests.append((mk_ecpairing_data([(m(G1, 27), m(G2, 37)), (G1, m(G2, 998))]), GPB + GPP * 2 + 30000, 'no', 'two_point_fail_2')) -tests.append((mk_ecpairing_data([(G1, G2_zero), (G1_zero, G2)]), GPB + GPP * 2 + 30000, 'yes', 'two_point_match_5')) +tests.append((mk_ecpairing_data([(G1, G2)]), GPB + + 30000, 'error', 'one_point_insufficient_gas')) +tests.append((mk_ecpairing_data([(G1, G2)]), + GPB + GPP + 30000, 'no', 'one_point_fail')) +tests.append((mk_ecpairing_data([(G1_zero, G2)]), + GPB + GPP + 30000, 'yes', 'one_point_with_g1_zero')) +tests.append((mk_ecpairing_data([(G1, G2_zero)]), + GPB + GPP + 30000, 'yes', 'one_point_with_g2_zero')) +tests.append((mk_ecpairing_data([(G1, G2)])[ + :191], GPB + GPP + 30000, 'error', 'bad_length_191')) +tests.append((mk_ecpairing_data([(G1, G2)]) + + b'\x00', GPB + + GPP + + 30000, 'error', 'bad_length_193')) +tests.append((mk_ecpairing_data([(G1, G2), (G1, G2)]), + GPB + GPP * 2 + 30000, 'no', 'two_point_fail_1')) +tests.append((mk_ecpairing_data([(G1, G2_zero), (G1, G2)]), + GPB + GPP * 2 + 30000, 'no', 'two_points_with_one_g2_zero')) +tests.append((mk_ecpairing_data([(G1, G2), (m(G1, co - 1), G2)]), + GPB + GPP * 2 + 30000, 'yes', 'two_point_match_1')) +tests.append((mk_ecpairing_data( + [(G1, G2), (m(G1, co - 1), G2)]), GPB + GPP + 30000, 'error', 'two_point_oog')) +tests.append((mk_ecpairing_data([(G1, G2), (G1, m(G2, co - 1))]), + GPB + GPP * 2 + 30000, 'yes', 'two_point_match_2')) +tests.append((mk_ecpairing_data([(G1, m(G2, 2)), (m( + G1, co - 2), G2)]), GPB + GPP * 2 + 30000, 'yes', 'two_point_match_3')) +tests.append((mk_ecpairing_data([(m(G1, 27), m(G2, 37)), (G1, m( + G2, co - 999))]), GPB + GPP * 2 + 30000, 'yes', 'two_point_match_4')) +tests.append((mk_ecpairing_data([(m(G1, 27), m(G2, 37)), (G1, m( + G2, 998))]), GPB + GPP * 2 + 30000, 'no', 'two_point_fail_2')) +tests.append((mk_ecpairing_data([(G1, G2_zero), (G1_zero, G2)]), + GPB + GPP * 2 + 30000, 'yes', 'two_point_match_5')) tests.append((mk_ecpairing_data([(m(G1, 27), m(G2, 37)), (G1, m(G2, co - 999)), (G1, G2_zero)]), - GPB + GPP * 3 + 30000, 'yes', 'three_point_match_1')) + GPB + GPP * 3 + 30000, 'yes', 'three_point_match_1')) tests.append((mk_ecpairing_data([(m(G1, 27), m(G2, 37)), (G1, m(G2, 999)), (G1, G2)]), - GPB + GPP * 3 + 30000, 'no','three_point_fail_1')) -tests.append((mk_ecpairing_data([(G1_zero, fake_point)]), GPB + GPP + 30000, 'error', 'one_point_not_in_subgroup')) -tests.append((perturb(mk_ecpairing_data([(G1_zero, G2)]), 0, 1), GPB + GPP + 30000, 'error', 'perturb_zeropoint_by_one')) -tests.append((perturb(mk_ecpairing_data([(G1_zero, G2)]), 0, co), GPB + GPP + 30000, 'error', 'perturb_zeropoint_by_curve_order')) -tests.append((perturb(mk_ecpairing_data([(G1_zero, G2)]), 0, fm), GPB + GPP + 30000, 'error', 'perturb_zeropoint_by_field_modulus')) -tests.append((perturb(mk_ecpairing_data([(G1_zero, G2)]), 64, 1), GPB + GPP + 30000, 'error', 'perturb_g2_by_one')) -tests.append((perturb(mk_ecpairing_data([(G1_zero, G2)]), 96, co), GPB + GPP + 30000, 'error', 'perturb_g2_by_curve_order')) -tests.append((perturb(mk_ecpairing_data([(G1_zero, G2)]), 128, fm), GPB + GPP + 30000, 'error', 'perturb_g2_by_field_modulus')) -tests.append((perturb(mk_ecpairing_data([(G1_zero, G2)]), 160, fm), GPB + GPP + 30000, 'error', 'perturb_g2_by_field_modulus_again')) + GPB + GPP * 3 + 30000, 'no', 'three_point_fail_1')) +tests.append((mk_ecpairing_data([(G1_zero, fake_point)]), + GPB + GPP + 30000, 'error', 'one_point_not_in_subgroup')) +tests.append((perturb(mk_ecpairing_data( + [(G1_zero, G2)]), 0, 1), GPB + GPP + 30000, 'error', 'perturb_zeropoint_by_one')) +tests.append((perturb(mk_ecpairing_data( + [(G1_zero, G2)]), 0, co), GPB + GPP + 30000, 'error', 'perturb_zeropoint_by_curve_order')) +tests.append((perturb(mk_ecpairing_data([(G1_zero, G2)]), 0, fm), + GPB + GPP + 30000, 'error', 'perturb_zeropoint_by_field_modulus')) +tests.append((perturb(mk_ecpairing_data( + [(G1_zero, G2)]), 64, 1), GPB + GPP + 30000, 'error', 'perturb_g2_by_one')) +tests.append((perturb(mk_ecpairing_data( + [(G1_zero, G2)]), 96, co), GPB + GPP + 30000, 'error', 'perturb_g2_by_curve_order')) +tests.append((perturb(mk_ecpairing_data( + [(G1_zero, G2)]), 128, fm), GPB + GPP + 30000, 'error', 'perturb_g2_by_field_modulus')) +tests.append((perturb(mk_ecpairing_data([(G1_zero, G2)]), 160, fm), + GPB + GPP + 30000, 'error', 'perturb_g2_by_field_modulus_again')) testout = {} testout_filler = {} @@ -119,4 +161,9 @@ def mk_test(encoded, execgas, expect): o2["explanation"] = "Puts the given data into the ECPAIRING precompile" testout_filler["ecpairing_" + desc] = o2 open('ecpairing_tests.json', 'w').write(json.dumps(testout, indent=4)) -open('ecpairing_tests_filler.json', 'w').write(json.dumps(testout_filler, indent=4)) +open( + 'ecpairing_tests_filler.json', + 'w').write( + json.dumps( + testout_filler, + indent=4)) diff --git a/tools/mk_modexp_tests.py b/tools/mk_modexp_tests.py index 0e69a0234..c828a3bbd 100644 --- a/tools/mk_modexp_tests.py +++ b/tools/mk_modexp_tests.py @@ -16,27 +16,42 @@ def foo(x: bytes <= %d) -> bytes <= %d: return o """ + def mk_modexp_data(b, e, m): benc = int_to_big_endian(b) eenc = int_to_big_endian(e) menc = int_to_big_endian(m) - return encode_int32(len(benc)) + encode_int32(len(eenc)) + encode_int32(len(menc)) + benc + eenc + menc + return encode_int32(len(benc)) + encode_int32(len(eenc)) + \ + encode_int32(len(menc)) + benc + eenc + menc + def intlen(o): return len(int_to_big_endian(o)) + def intrinsic_gas_of_data(d): - return opcodes.GTXDATAZERO * d.count(0) + opcodes.GTXDATANONZERO * (len(d) - d.count(0)) + return opcodes.GTXDATAZERO * \ + d.count(0) + opcodes.GTXDATANONZERO * (len(d) - d.count(0)) + def mk_test(b, e, m, execgas): encoded = mk_modexp_data(b, e, m) s = c.snapshot() - x = c.contract(kode % (len(encoded) + 36, max(intlen(m), 1), max(intlen(m), 1)), language='viper') + x = c.contract(kode % (len(encoded) + 36, max(intlen(m), 1), + max(intlen(m), 1)), language='viper') pre = tester.mk_state_test_prefill(c) try: - o = x.foo(encoded, startgas=21000 + intrinsic_gas_of_data(x.translator.encode('foo', [encoded])) + execgas) + o = x.foo( + encoded, + startgas=21000 + + intrinsic_gas_of_data( + x.translator.encode( + 'foo', + [encoded])) + + execgas) if big_endian_to_int(o[:intlen(m)]) != (pow(b, e, m) if m else 0): - raise Exception("Mismatch! %d %d %d expected %d computed %d" % (b, e, m, pow(b, e, m), big_endian_to_int(o[:intlen(m)]))) + raise Exception("Mismatch! %d %d %d expected %d computed %d" % ( + b, e, m, pow(b, e, m), big_endian_to_int(o[:intlen(m)]))) print("Succeeded %d %d %d sg %d" % (b, e, m, execgas)) except tester.TransactionFailed: print('OOG %d %d %d sg %d' % (b, e, m, execgas)) @@ -47,6 +62,7 @@ def mk_test(b, e, m, execgas): c.revert(s) return o, o2 + gaslimits = [20500, 22000, 25000, 35000, 155000, 1000000] tests = [] @@ -92,4 +108,9 @@ def mk_test(b, e, m, execgas): o2["explanation"] = "Puts the base %d, exponent %d and modulus %d into the MODEXP precompile, saves the hash of the result. Gives the execution %d gas" % test testout_filler["modexp_%d_%d_%d_%d" % test] = o2 open('modexp_tests.json', 'w').write(json.dumps(testout, indent=4)) -open('modexp_tests_filler.json', 'w').write(json.dumps(testout_filler, indent=4)) +open( + 'modexp_tests_filler.json', + 'w').write( + json.dumps( + testout_filler, + indent=4)) diff --git a/tools/random_vm_test_generator.py b/tools/random_vm_test_generator.py index 7f33cd3c3..6f8b01364 100644 --- a/tools/random_vm_test_generator.py +++ b/tools/random_vm_test_generator.py @@ -7,12 +7,13 @@ import random from rlp.utils import encode_hex, ascii_chr + def mkrndgen(seed): state = [0, 0] def rnd(n): if state[0] < 2**32: - state[0] = u.big_endian_to_int(u.sha3(seed+str(state[1]+1))) + state[0] = u.big_endian_to_int(u.sha3(seed + str(state[1] + 1))) state[1] += 1 o = state[0] % n state[0] /= n @@ -47,45 +48,45 @@ def apply_msg_wrapper(_block, _tx, msg, code): pb.apply_msg = apply_msg_wrapper - while 1: - CODE = gen_random_code(mkrndgen(seed+str(i))) - DATA = gen_random_code(mkrndgen(seed+str(i+1))) - i += 2 - VAL = 0 - s = t.state(1) - FROM = t.keys[0] - FROMADDR = t.accounts[0] - TO = t.accounts[1] - s.block.delta_balance(TO, 1) - pre = s.block.to_dict()['state'] - env = { - "currentCoinbase": s.block.coinbase, - "currentDifficulty": str(s.block.difficulty), - "currentGasLimit": str(s.block.gas_limit), - "currentNumber": str(s.block.number), - "currentTimestamp": str(s.block.timestamp), - "previousHash": encode_hex(s.block.prevhash) - } - apply_message_calls = [] + while True: + CODE = gen_random_code(mkrndgen(seed + str(i))) + DATA = gen_random_code(mkrndgen(seed + str(i + 1))) + i += 2 + VAL = 0 + s = t.state(1) + FROM = t.keys[0] + FROMADDR = t.accounts[0] + TO = t.accounts[1] + s.block.delta_balance(TO, 1) + pre = s.block.to_dict()['state'] + env = { + "currentCoinbase": s.block.coinbase, + "currentDifficulty": str(s.block.difficulty), + "currentGasLimit": str(s.block.gas_limit), + "currentNumber": str(s.block.number), + "currentTimestamp": str(s.block.timestamp), + "previousHash": encode_hex(s.block.prevhash) + } + apply_message_calls = [] - tx = pyethereum.transactions.Transaction(1, 10**12, 10000, TO, VAL, DATA)\ - .sign(FROM) - msg = pb.Message(FROMADDR, TO, VAL, 10000, DATA) - exek = { - "address": msg.to, - "caller": msg.sender, - "code": '0x' + encode_hex(CODE), - "data": '0x' + encode_hex(DATA), - "gas": str(10000), - "gasPrice": str(10**12), - "origin": tx.sender, - "value": str(VAL) - } - success, gas, o = pb.apply_msg(s.block, tx, msg, CODE) - post = s.block.to_dict()['state'] - callcreates = apply_message_calls[1:] - if success: - break + tx = pyethereum.transactions.Transaction(1, 10**12, 10000, TO, VAL, DATA)\ + .sign(FROM) + msg = pb.Message(FROMADDR, TO, VAL, 10000, DATA) + exek = { + "address": msg.to, + "caller": msg.sender, + "code": '0x' + encode_hex(CODE), + "data": '0x' + encode_hex(DATA), + "gas": str(10000), + "gasPrice": str(10**12), + "origin": tx.sender, + "value": str(VAL) + } + success, gas, o = pb.apply_msg(s.block, tx, msg, CODE) + post = s.block.to_dict()['state'] + callcreates = apply_message_calls[1:] + if success: + break return { "callcreates": callcreates, @@ -97,6 +98,7 @@ def apply_msg_wrapper(_block, _tx, msg, code): "out": '0x' + encode_hex(''.join(map(ascii_chr, o))) } + if __name__ == "__main__": o = gen_test((sys.argv + [str(random.randrange(10**50))])[2]) print(json.dumps({sys.argv[1]: o}, indent=4)) diff --git a/tools/vm_test_generator.py b/tools/vm_test_generator.py index ad0adb806..6b8ac2c35 100644 --- a/tools/vm_test_generator.py +++ b/tools/vm_test_generator.py @@ -10,7 +10,7 @@ # Code: serpent code # Tx:[ val, data ] def gen_test(code, val, data): - while 1: + while True: s = t.state(1) c = s.contract(code) pre = s.block.to_dict()['state'] @@ -62,9 +62,10 @@ def apply_msg_wrapper(_block, _tx, msg, code): "post": post, "exec": exek, "gas": str(gas), - "out": '0x'+encode_hex(''.join(map(ascii_chr, o))) + "out": '0x' + encode_hex(''.join(map(ascii_chr, o))) } + if __name__ == "__main__": o = gen_test(sys.argv[2], int(sys.argv[3]), sys.argv[4:]) print(json.dumps({sys.argv[1]: o}, indent=4))