├── eth ├── vm │ ├── __init__.py │ ├── logic │ │ ├── __init__.py │ │ ├── invalid.py │ │ ├── sha3.py │ │ ├── block.py │ │ ├── duplication.py │ │ ├── swap.py │ │ ├── memory.py │ │ ├── flow.py │ │ ├── logging.py │ │ └── storage.py │ ├── forks │ │ ├── constantinople │ │ │ ├── constants.py │ │ │ ├── state.py │ │ │ ├── headers.py │ │ │ ├── blocks.py │ │ │ ├── computation.py │ │ │ ├── transactions.py │ │ │ ├── __init__.py │ │ │ └── opcodes.py │ │ ├── frontier │ │ │ ├── transaction_context.py │ │ │ ├── constants.py │ │ │ └── validation.py │ │ ├── homestead │ │ │ ├── constants.py │ │ │ ├── validation.py │ │ │ ├── blocks.py │ │ │ ├── state.py │ │ │ ├── opcodes.py │ │ │ └── __init__.py │ │ ├── byzantium │ │ │ ├── state.py │ │ │ ├── constants.py │ │ │ ├── blocks.py │ │ │ ├── transactions.py │ │ │ └── computation.py │ │ ├── tangerine_whistle │ │ │ ├── state.py │ │ │ ├── constants.py │ │ │ ├── computation.py │ │ │ └── __init__.py │ │ ├── spurious_dragon │ │ │ ├── constants.py │ │ │ ├── blocks.py │ │ │ ├── __init__.py │ │ │ ├── opcodes.py │ │ │ ├── state.py │ │ │ └── utils.py │ │ └── __init__.py │ ├── transaction_context.py │ └── execution_context.py ├── rlp │ ├── __init__.py │ ├── sedes.py │ ├── logs.py │ ├── accounts.py │ └── receipts.py ├── tools │ ├── __init__.py │ ├── _utils │ │ ├── __init__.py │ │ ├── git.py │ │ ├── hashing.py │ │ ├── vyper.py │ │ └── mappings.py │ ├── builder │ │ └── __init__.py │ ├── fixtures │ │ ├── fillers │ │ │ ├── __init__.py │ │ │ ├── main.py │ │ │ └── vm.py │ │ ├── __init__.py │ │ └── _utils.py │ ├── logging.py │ ├── mining.py │ └── rlp.py ├── utils │ ├── __init__.py │ ├── logging.py │ ├── empty.py │ ├── hexadecimal.py │ ├── padding.py │ ├── version.py │ ├── bn128.py │ ├── address.py │ ├── db.py │ ├── state.py │ └── module_loading.py ├── consensus │ └── __init__.py ├── db │ ├── backends │ │ ├── __init__.py │ │ └── memory.py │ ├── hash_trie.py │ ├── __init__.py │ ├── cache.py │ ├── keymap.py │ ├── trie.py │ └── schema.py ├── chains │ ├── __init__.py │ ├── ropsten │ │ └── constants.py │ └── mainnet │ │ └── constants.py ├── precompiles │ ├── __init__.py │ ├── identity.py │ ├── sha256.py │ ├── ripemd160.py │ ├── ecmul.py │ ├── ecadd.py │ └── ecrecover.py ├── estimators │ └── __init__.py └── __init__.py ├── tests ├── __init__.py ├── fillers │ ├── __init__.py │ └── vm_fillers │ │ └── __init__.py ├── p2p │ ├── fixtures │ │ ├── __init__.py │ │ ├── README │ │ └── sample_1000_headers_rlp │ ├── conftest.py │ ├── test_peer_subscriber.py │ └── test_peer_collect_sub_proto_msgs.py ├── trinity │ ├── integration │ │ └── fixtures │ │ │ └── geth_lightchain_datadir │ │ │ └── geth │ │ │ ├── LOCK │ │ │ ├── chaindata │ │ │ ├── LOCK │ │ │ ├── CURRENT │ │ │ ├── 000014.ldb │ │ │ ├── 000015.ldb │ │ │ ├── 000018.ldb │ │ │ ├── 000021.ldb │ │ │ ├── 000022.log │ │ │ └── MANIFEST-000023 │ │ │ ├── transactions.rlp │ │ │ └── nodekey │ └── core │ │ ├── utils │ │ └── test_version.py │ │ ├── chain-management │ │ ├── test_light_peer_chain.py │ │ ├── test_initialize_database.py │ │ └── test_is_database_initialized.py │ │ ├── filesystem-utils │ │ └── test_is_under_path.py │ │ ├── cli │ │ ├── test_trinity_repl.py │ │ └── test_log_level_configuration.py │ │ └── header-utils │ │ └── test_block_number_sequence_builder.py ├── core │ ├── numeric-utils │ │ ├── test_get_highest_bit_length.py │ │ └── test_int_to_bytes32.py │ ├── padding-utils │ │ └── test_padding.py │ ├── env-utils │ │ ├── test_get.py │ │ ├── test_env_float.py │ │ └── test_env_string.py │ ├── consensus │ │ └── test_pow_mining.py │ ├── vm │ │ └── test_vm_state.py │ ├── hexadecimal-utils │ │ └── test_encode_and_decode.py │ └── fixtures.py └── database │ ├── test_hash_trie.py │ └── test_leveldb_db_backend.py ├── p2p ├── tools │ ├── __init__.py │ └── paragon │ │ ├── __init__.py │ │ ├── commands.py │ │ ├── proto.py │ │ └── peer.py ├── __init__.py ├── events.py └── cancellable.py ├── trinity ├── db │ └── __init__.py ├── p2p │ └── __init__.py ├── rlp │ ├── __init__.py │ ├── block_body.py │ └── sedes.py ├── nodes │ ├── __init__.py │ ├── mainnet.py │ └── ropsten.py ├── plugins │ ├── __init__.py │ ├── builtin │ │ ├── __init__.py │ │ ├── attach │ │ │ ├── __init__.py │ │ │ └── plugin.py │ │ ├── tx_pool │ │ │ └── __init__.py │ │ ├── json_rpc │ │ │ └── __init__.py │ │ ├── fix_unclean_shutdown │ │ │ └── __init__.py │ │ └── light_peer_chain_bridge │ │ │ └── __init__.py │ └── registry.py ├── protocol │ ├── __init__.py │ ├── eth │ │ ├── __init__.py │ │ ├── constants.py │ │ └── handlers.py │ ├── les │ │ ├── __init__.py │ │ ├── handlers.py │ │ ├── constants.py │ │ ├── normalizers.py │ │ ├── validators.py │ │ ├── trackers.py │ │ └── requests.py │ └── common │ │ ├── __init__.py │ │ ├── commands.py │ │ ├── context.py │ │ ├── normalizers.py │ │ ├── types.py │ │ ├── requests.py │ │ └── handlers.py ├── sync │ ├── __init__.py │ ├── common │ │ └── __init__.py │ ├── full │ │ ├── __init__.py │ │ └── constants.py │ └── light │ │ └── __init__.py ├── tools │ └── __init__.py ├── utils │ ├── __init__.py │ ├── les.py │ ├── decorators.py │ ├── log_messages.py │ ├── async_errors.py │ ├── async_dispatch.py │ ├── version.py │ ├── timer.py │ ├── shutdown.py │ ├── async_iter.py │ ├── profiling.py │ ├── mp.py │ ├── db.py │ ├── headers.py │ ├── xdg.py │ ├── db_proxy.py │ ├── validation.py │ └── queues.py ├── rpc │ ├── __init__.py │ └── modules │ │ ├── __init__.py │ │ ├── main.py │ │ ├── web3.py │ │ ├── net.py │ │ └── evm.py ├── events.py ├── constants.py ├── chains │ ├── coro.py │ ├── mainnet.py │ └── ropsten.py ├── extensibility │ ├── __init__.py │ └── events.py ├── README.md ├── __init__.py └── exceptions.py ├── scripts ├── benchmark │ ├── __init__.py │ ├── utils │ │ ├── __init__.py │ │ ├── shellart.py │ │ ├── format.py │ │ ├── meters.py │ │ ├── address.py │ │ ├── tx.py │ │ └── compile.py │ ├── checks │ │ ├── __init__.py │ │ ├── mine_empty_blocks.py │ │ ├── import_empty_blocks.py │ │ └── base_benchmark.py │ └── contract_data │ │ ├── __init__.py │ │ └── DOSContract.sol └── db-shell.py ├── stubs ├── eth_keys │ ├── utils │ │ ├── __init__.pyi │ │ ├── address.pyi │ │ └── module_loading.pyi │ ├── __init__.pyi │ ├── backends │ │ ├── native │ │ │ ├── __init__.pyi │ │ │ ├── main.pyi │ │ │ ├── jacobian.pyi │ │ │ └── ecdsa.pyi │ │ ├── __init__.pyi │ │ ├── coincurve.pyi │ │ └── base.pyi │ ├── validation.pyi │ └── main.pyi └── README.md ├── docs ├── quickstart.rst ├── images │ ├── trinity_layers.png │ └── trinity_processes.png ├── api │ ├── eth │ │ ├── vm │ │ │ ├── api.vm.stack.rst │ │ │ ├── api.vm.memory.rst │ │ │ ├── api.vm.opcode.rst │ │ │ ├── api.vm.message.rst │ │ │ ├── api.vm.gas_meter.rst │ │ │ ├── api.vm.code_stream.rst │ │ │ ├── api.vm.execution_context.rst │ │ │ ├── api.vm.transaction_context.rst │ │ │ ├── api.vm.computation.rst │ │ │ ├── api.vm.state.rst │ │ │ └── api.vm.vm.rst │ │ ├── api.exceptions.rst │ │ ├── rlp │ │ │ ├── api.rlp.logs.rst │ │ │ ├── api.rlp.accounts.rst │ │ │ ├── api.rlp.blocks.rst │ │ │ ├── api.rlp.receipts.rst │ │ │ ├── api.rlp.headers.rst │ │ │ └── api.rlp.transactions.rst │ │ ├── db │ │ │ ├── api.db.journal.rst │ │ │ ├── api.db.chain.rst │ │ │ ├── api.db.account.rst │ │ │ └── api.db.backends.rst │ │ ├── api.tools.rst │ │ ├── api.chain.rst │ │ ├── api.db.rst │ │ ├── api.rlp.rst │ │ ├── index.rst │ │ └── api.vm.rst │ └── index.rst ├── release_notes │ └── index.rst ├── guides │ ├── index.rst │ ├── trinity │ │ └── index.rst │ └── eth │ │ └── index.rst ├── index.rst ├── Makefile ├── fragments │ └── virtualenv_explainer.rst └── introduction.rst ├── pytest.ini ├── .gitmodules ├── MANIFEST.in ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── .readthedocs.yml ├── Dockerfile ├── .bumpversion.cfg ├── .circleci └── merge_pr.sh ├── DEVELOPMENT.md ├── .gitignore ├── LICENSE └── setup_trinity.py /eth/vm/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eth/rlp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eth/tools/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eth/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eth/utils/logging.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /p2p/tools/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/db/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/p2p/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/rlp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eth/consensus/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eth/db/backends/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eth/tools/_utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eth/vm/logic/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fillers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/nodes/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/protocol/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/sync/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/tools/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eth/tools/builder/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scripts/benchmark/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /stubs/eth_keys/utils/__init__.pyi: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/p2p/fixtures/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/protocol/eth/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/protocol/les/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/sync/common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/sync/full/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/sync/light/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scripts/benchmark/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fillers/vm_fillers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/plugins/builtin/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/protocol/common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/plugins/builtin/attach/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/plugins/builtin/tx_pool/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/plugins/builtin/json_rpc/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/plugins/builtin/fix_unclean_shutdown/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/quickstart.rst: -------------------------------------------------------------------------------- 1 | .. include:: guides/trinity/quickstart.rst -------------------------------------------------------------------------------- /tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/LOCK: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /trinity/rpc/__init__.py: -------------------------------------------------------------------------------- 1 | from .main import RPCServer # noqa: F401 2 | -------------------------------------------------------------------------------- /tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/chaindata/LOCK: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /stubs/eth_keys/__init__.pyi: -------------------------------------------------------------------------------- 1 | from .main import KeyAPI 2 | 3 | 4 | keys: KeyAPI 5 | -------------------------------------------------------------------------------- /stubs/eth_keys/backends/native/__init__.pyi: -------------------------------------------------------------------------------- 1 | from .main import NativeECCBackend 2 | -------------------------------------------------------------------------------- /tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/transactions.rlp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eth/utils/empty.py: -------------------------------------------------------------------------------- 1 | class Empty(object): 2 | pass 3 | 4 | 5 | empty = Empty() 6 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | addopts= --showlocals 3 | python_paths= . 4 | xfail_strict=true 5 | -------------------------------------------------------------------------------- /tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/chaindata/CURRENT: -------------------------------------------------------------------------------- 1 | MANIFEST-000023 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "fixtures"] 2 | path = fixtures 3 | url = https://github.com/ethereum/tests.git 4 | -------------------------------------------------------------------------------- /stubs/eth_keys/utils/address.pyi: -------------------------------------------------------------------------------- 1 | def public_key_bytes_to_address(public_key_bytes: bytes) -> bytes: ... 2 | -------------------------------------------------------------------------------- /docs/images/trinity_layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/py-evm/HEAD/docs/images/trinity_layers.png -------------------------------------------------------------------------------- /docs/api/eth/vm/api.vm.stack.rst: -------------------------------------------------------------------------------- 1 | Stack 2 | ===== 3 | 4 | .. autoclass:: eth.vm.stack.Stack 5 | :members: 6 | 7 | -------------------------------------------------------------------------------- /docs/images/trinity_processes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/py-evm/HEAD/docs/images/trinity_processes.png -------------------------------------------------------------------------------- /docs/api/eth/api.exceptions.rst: -------------------------------------------------------------------------------- 1 | Exceptions 2 | ========== 3 | 4 | 5 | .. automodule:: eth.exceptions 6 | :members: 7 | -------------------------------------------------------------------------------- /docs/api/eth/vm/api.vm.memory.rst: -------------------------------------------------------------------------------- 1 | Memory 2 | ====== 3 | 4 | .. autoclass:: eth.vm.memory.Memory 5 | :members: 6 | 7 | -------------------------------------------------------------------------------- /docs/api/eth/vm/api.vm.opcode.rst: -------------------------------------------------------------------------------- 1 | Opcode 2 | ======= 3 | 4 | .. autoclass:: eth.vm.opcode.Opcode 5 | :members: 6 | 7 | -------------------------------------------------------------------------------- /docs/api/eth/vm/api.vm.message.rst: -------------------------------------------------------------------------------- 1 | Message 2 | ======= 3 | 4 | .. autoclass:: eth.vm.message.Message 5 | :members: 6 | 7 | -------------------------------------------------------------------------------- /tests/p2p/fixtures/README: -------------------------------------------------------------------------------- 1 | sample_1000_headers_rlp: First 1000 headers from mainnet, stored as CountableList(BlockHeader) 2 | -------------------------------------------------------------------------------- /trinity/events.py: -------------------------------------------------------------------------------- 1 | from lahja import ( 2 | BaseEvent 3 | ) 4 | 5 | 6 | class ShutdownRequest(BaseEvent): 7 | pass 8 | -------------------------------------------------------------------------------- /docs/api/eth/rlp/api.rlp.logs.rst: -------------------------------------------------------------------------------- 1 | Logs 2 | ==== 3 | 4 | Log 5 | --- 6 | 7 | .. autoclass:: eth.rlp.logs.Log 8 | :members: 9 | -------------------------------------------------------------------------------- /docs/api/eth/vm/api.vm.gas_meter.rst: -------------------------------------------------------------------------------- 1 | GasMeter 2 | ======== 3 | 4 | .. autoclass:: eth.vm.gas_meter.GasMeter 5 | :members: 6 | 7 | -------------------------------------------------------------------------------- /p2p/__init__.py: -------------------------------------------------------------------------------- 1 | # This is to ensure we call setup_trace_logging() before anything else. 2 | import eth as _eth_module # noqa: F401 3 | -------------------------------------------------------------------------------- /tests/p2p/fixtures/sample_1000_headers_rlp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/py-evm/HEAD/tests/p2p/fixtures/sample_1000_headers_rlp -------------------------------------------------------------------------------- /tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/nodekey: -------------------------------------------------------------------------------- 1 | 6cb1a5fc574fd8e1353d2f90aec20695db7d7917d8e6ade739bc36872c88eb0f -------------------------------------------------------------------------------- /docs/api/eth/vm/api.vm.code_stream.rst: -------------------------------------------------------------------------------- 1 | CodeStream 2 | ========== 3 | 4 | .. autoclass:: eth.vm.code_stream.CodeStream 5 | :members: 6 | 7 | -------------------------------------------------------------------------------- /docs/api/eth/db/api.db.journal.rst: -------------------------------------------------------------------------------- 1 | Journal 2 | ======= 3 | 4 | JournalDB 5 | --------- 6 | 7 | .. autoclass:: eth.db.journal.JournalDB 8 | :members: -------------------------------------------------------------------------------- /stubs/eth_keys/utils/module_loading.pyi: -------------------------------------------------------------------------------- 1 | def import_string(dotted_path: str) -> type: ... 2 | def split_at_longest_importable_path(dotted_path): ... 3 | -------------------------------------------------------------------------------- /docs/api/eth/rlp/api.rlp.accounts.rst: -------------------------------------------------------------------------------- 1 | Accounts 2 | ======== 3 | 4 | Account 5 | ------- 6 | 7 | .. autoclass:: eth.rlp.accounts.Account 8 | :members: 9 | -------------------------------------------------------------------------------- /docs/api/eth/rlp/api.rlp.blocks.rst: -------------------------------------------------------------------------------- 1 | Blocks 2 | ====== 3 | 4 | BaseBlock 5 | --------- 6 | 7 | .. autoclass:: eth.rlp.blocks.BaseBlock 8 | :members: 9 | -------------------------------------------------------------------------------- /docs/api/eth/rlp/api.rlp.receipts.rst: -------------------------------------------------------------------------------- 1 | Receipts 2 | ======== 3 | 4 | Receipt 5 | ------- 6 | 7 | .. autoclass:: eth.rlp.receipts.Receipt 8 | :members: 9 | -------------------------------------------------------------------------------- /docs/api/eth/rlp/api.rlp.headers.rst: -------------------------------------------------------------------------------- 1 | Headers 2 | ======= 3 | 4 | BlockHeader 5 | ----------- 6 | 7 | .. autoclass:: eth.rlp.headers.BlockHeader 8 | :members: 9 | -------------------------------------------------------------------------------- /eth/vm/forks/constantinople/constants.py: -------------------------------------------------------------------------------- 1 | from eth_utils import denoms 2 | 3 | 4 | GAS_EXTCODEHASH_EIP1052 = 400 5 | 6 | EIP1234_BLOCK_REWARD = 2 * denoms.ether 7 | -------------------------------------------------------------------------------- /docs/api/eth/vm/api.vm.execution_context.rst: -------------------------------------------------------------------------------- 1 | ExecutionContext 2 | ================ 3 | 4 | .. autoclass:: eth.vm.execution_context.ExecutionContext 5 | :members: 6 | 7 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include VERSION 3 | include README.md 4 | include requirements.txt 5 | 6 | recursive-exclude * __pycache__ 7 | recursive-exclude * *.py[co] 8 | -------------------------------------------------------------------------------- /trinity/utils/les.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from eth_utils import big_endian_to_int 4 | 5 | 6 | def gen_request_id() -> int: 7 | return big_endian_to_int(os.urandom(8)) 8 | -------------------------------------------------------------------------------- /eth/db/hash_trie.py: -------------------------------------------------------------------------------- 1 | from eth_hash.auto import keccak 2 | 3 | from eth.db.keymap import ( 4 | KeyMapDB, 5 | ) 6 | 7 | 8 | class HashTrie(KeyMapDB): 9 | keymap = keccak 10 | -------------------------------------------------------------------------------- /trinity/plugins/builtin/light_peer_chain_bridge/__init__.py: -------------------------------------------------------------------------------- 1 | from .light_peer_chain_bridge import ( # noqa: F401 2 | EventBusLightPeerChain, 3 | LightPeerChainEventBusHandler, 4 | ) 5 | -------------------------------------------------------------------------------- /docs/api/eth/vm/api.vm.transaction_context.rst: -------------------------------------------------------------------------------- 1 | BaseTransactionContext 2 | ====================== 3 | 4 | .. autoclass:: eth.vm.transaction_context.BaseTransactionContext 5 | :members: 6 | 7 | -------------------------------------------------------------------------------- /eth/vm/forks/frontier/transaction_context.py: -------------------------------------------------------------------------------- 1 | from eth.vm.transaction_context import BaseTransactionContext 2 | 3 | 4 | class FrontierTransactionContext(BaseTransactionContext): 5 | pass 6 | -------------------------------------------------------------------------------- /trinity/sync/full/constants.py: -------------------------------------------------------------------------------- 1 | # How old (in seconds) must our local head be to cause us to start with a 2 | # fast-sync before we switch to regular-sync. 3 | FAST_SYNC_CUTOFF = 60 * 60 * 24 4 | -------------------------------------------------------------------------------- /eth/vm/forks/homestead/constants.py: -------------------------------------------------------------------------------- 1 | # 2 | # Difficulty 3 | # 4 | HOMESTEAD_DIFFICULTY_ADJUSTMENT_CUTOFF = 10 5 | 6 | 7 | # 8 | # Gas Costs and Refunds 9 | # 10 | GAS_CODEDEPOSIT = 200 11 | -------------------------------------------------------------------------------- /docs/api/eth/vm/api.vm.computation.rst: -------------------------------------------------------------------------------- 1 | Computation 2 | =========== 3 | 4 | BaseComputation 5 | --------------- 6 | 7 | .. autoclass:: eth.vm.computation.BaseComputation 8 | :members: 9 | 10 | -------------------------------------------------------------------------------- /trinity/constants.py: -------------------------------------------------------------------------------- 1 | SYNC_FULL = 'full' 2 | SYNC_LIGHT = 'light' 3 | 4 | MAIN_EVENTBUS_ENDPOINT = 'main' 5 | NETWORKING_EVENTBUS_ENDPOINT = 'networking' 6 | 7 | MAXIMUM_OBJECT_MEMORY_BYTES = 10000000 8 | -------------------------------------------------------------------------------- /tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/chaindata/000014.ldb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/py-evm/HEAD/tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/chaindata/000014.ldb -------------------------------------------------------------------------------- /tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/chaindata/000015.ldb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/py-evm/HEAD/tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/chaindata/000015.ldb -------------------------------------------------------------------------------- /tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/chaindata/000018.ldb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/py-evm/HEAD/tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/chaindata/000018.ldb -------------------------------------------------------------------------------- /tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/chaindata/000021.ldb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/py-evm/HEAD/tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/chaindata/000021.ldb -------------------------------------------------------------------------------- /tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/chaindata/000022.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/py-evm/HEAD/tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/chaindata/000022.log -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### What was wrong? 2 | 3 | 4 | 5 | ### How was it fixed? 6 | 7 | 8 | 9 | #### Cute Animal Picture 10 | 11 | ![put a cute animal picture link inside the parentheses]() 12 | -------------------------------------------------------------------------------- /tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/chaindata/MANIFEST-000023: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/py-evm/HEAD/tests/trinity/integration/fixtures/geth_lightchain_datadir/geth/chaindata/MANIFEST-000023 -------------------------------------------------------------------------------- /trinity/utils/decorators.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Any, 3 | ) 4 | 5 | 6 | class classproperty(property): 7 | def __get__(self, obj: Any, objtype: Any = None) -> Any: 8 | return super().__get__(objtype) 9 | -------------------------------------------------------------------------------- /docs/api/eth/api.tools.rst: -------------------------------------------------------------------------------- 1 | Tools 2 | ===== 3 | 4 | 5 | .. toctree:: 6 | :maxdepth: 4 7 | :name: toc-eth-api-tools 8 | :caption: Tools 9 | 10 | tools/api.tools.builders 11 | tools/api.tools.fixtures 12 | -------------------------------------------------------------------------------- /eth/tools/_utils/git.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | from eth_utils import to_text 4 | 5 | 6 | def get_version_from_git(): 7 | version = subprocess.check_output(["git", "describe"]).strip() 8 | return to_text(version) 9 | -------------------------------------------------------------------------------- /docs/api/eth/api.chain.rst: -------------------------------------------------------------------------------- 1 | Chain 2 | ===== 3 | 4 | BaseChain 5 | --------- 6 | 7 | .. autoclass:: eth.chains.base.BaseChain 8 | :members: 9 | 10 | Chain 11 | ----- 12 | 13 | .. autoclass:: eth.chains.base.Chain 14 | :members: -------------------------------------------------------------------------------- /trinity/rpc/modules/__init__.py: -------------------------------------------------------------------------------- 1 | from .main import RPCModule # noqa: F401 2 | 3 | from .eth import Eth # noqa: F401 4 | from .evm import EVM # noqa: F401 5 | from .net import Net # noqa: F401 6 | from .web3 import Web3 # noqa: F401 7 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # https://docs.readthedocs.io/en/latest/yaml-config.html 2 | build: 3 | image: latest 4 | python: 5 | version: 3.6 6 | pip_install: True 7 | extra_requirements: 8 | - p2p 9 | - trinity 10 | - doc 11 | -------------------------------------------------------------------------------- /tests/trinity/core/utils/test_version.py: -------------------------------------------------------------------------------- 1 | from trinity.utils.version import construct_trinity_client_identifier 2 | 3 | 4 | def test_construct_trinity_client_identifier(): 5 | assert construct_trinity_client_identifier().startswith('Trinity/') 6 | -------------------------------------------------------------------------------- /docs/api/eth/api.db.rst: -------------------------------------------------------------------------------- 1 | DataBase 2 | ======== 3 | 4 | 5 | .. toctree:: 6 | :maxdepth: 4 7 | :name: toc-eth-api-db 8 | :caption: Database 9 | 10 | db/api.db.backends 11 | db/api.db.account 12 | db/api.db.journal 13 | db/api.db.chain -------------------------------------------------------------------------------- /docs/api/eth/db/api.db.chain.rst: -------------------------------------------------------------------------------- 1 | Chain 2 | ===== 3 | 4 | BaseChainDB 5 | ~~~~~~~~~~~ 6 | 7 | .. autoclass:: eth.db.chain.BaseChainDB 8 | :members: 9 | 10 | ChainDB 11 | ~~~~~~~ 12 | 13 | .. autoclass:: eth.db.chain.ChainDB 14 | :members: 15 | -------------------------------------------------------------------------------- /eth/vm/forks/byzantium/state.py: -------------------------------------------------------------------------------- 1 | from eth.vm.forks.spurious_dragon.state import SpuriousDragonState 2 | 3 | from .computation import ByzantiumComputation 4 | 5 | 6 | class ByzantiumState(SpuriousDragonState): 7 | computation_class = ByzantiumComputation 8 | -------------------------------------------------------------------------------- /docs/release_notes/index.rst: -------------------------------------------------------------------------------- 1 | Release notes 2 | ============= 3 | 4 | Trinity and Py-EVM are moving fast. Learn about the latest improvements in the release notes. 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | :name: toc-release-notes 9 | 10 | trinity.rst 11 | -------------------------------------------------------------------------------- /eth/vm/forks/tangerine_whistle/state.py: -------------------------------------------------------------------------------- 1 | from eth.vm.forks.homestead.state import HomesteadState 2 | 3 | from .computation import TangerineWhistleComputation 4 | 5 | 6 | class TangerineWhistleState(HomesteadState): 7 | computation_class = TangerineWhistleComputation 8 | -------------------------------------------------------------------------------- /docs/api/eth/db/api.db.account.rst: -------------------------------------------------------------------------------- 1 | Account 2 | ======== 3 | 4 | BaseAccountDB 5 | ------------- 6 | 7 | .. autoclass:: eth.db.account.BaseAccountDB 8 | :members: 9 | 10 | AccountDB 11 | ------------- 12 | 13 | .. autoclass:: eth.db.account.AccountDB 14 | :members: 15 | -------------------------------------------------------------------------------- /eth/vm/forks/constantinople/state.py: -------------------------------------------------------------------------------- 1 | from eth.vm.forks.byzantium.state import ( 2 | ByzantiumState 3 | ) 4 | 5 | from .computation import ConstantinopleComputation 6 | 7 | 8 | class ConstantinopleState(ByzantiumState): 9 | computation_class = ConstantinopleComputation 10 | -------------------------------------------------------------------------------- /docs/api/eth/vm/api.vm.state.rst: -------------------------------------------------------------------------------- 1 | State 2 | ===== 3 | 4 | BaseState 5 | --------- 6 | 7 | .. autoclass:: eth.vm.state.BaseState 8 | :members: 9 | 10 | 11 | BaseTransactionExecutor 12 | ----------------------- 13 | 14 | .. autoclass:: eth.vm.state.BaseTransactionExecutor 15 | :members: 16 | -------------------------------------------------------------------------------- /trinity/protocol/eth/constants.py: -------------------------------------------------------------------------------- 1 | # Max number of items we can ask for in ETH requests. These are the values used 2 | # in geth and if we ask for more than this the peers will disconnect from us. 3 | MAX_STATE_FETCH = 384 4 | MAX_BODIES_FETCH = 128 5 | MAX_RECEIPTS_FETCH = 256 6 | MAX_HEADERS_FETCH = 192 7 | -------------------------------------------------------------------------------- /eth/vm/forks/byzantium/constants.py: -------------------------------------------------------------------------------- 1 | from eth_utils import denoms 2 | 3 | # 4 | # Difficulty 5 | # 6 | BYZANTIUM_DIFFICULTY_ADJUSTMENT_CUTOFF = 9 7 | 8 | 9 | EIP649_BLOCK_REWARD = 3 * denoms.ether 10 | 11 | EIP658_TRANSACTION_STATUS_CODE_FAILURE = b'' 12 | EIP658_TRANSACTION_STATUS_CODE_SUCCESS = b'\x01' 13 | -------------------------------------------------------------------------------- /eth/chains/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import ( # noqa: F401 2 | AsyncChain, 3 | Chain, 4 | ) 5 | from .mainnet import ( # noqa: F401 6 | MainnetChain, 7 | ) 8 | from .ropsten import ( # noqa: F401 9 | RopstenChain, 10 | ) 11 | from .tester import ( # noqa: F401 12 | MainnetTesterChain, 13 | ) 14 | -------------------------------------------------------------------------------- /eth/vm/forks/spurious_dragon/constants.py: -------------------------------------------------------------------------------- 1 | # 2 | # Gas Costs and Refunds 3 | # 4 | GAS_CODEDEPOSIT = 200 5 | 6 | 7 | # https://github.com/ethereum/EIPs/issues/160 8 | GAS_EXP_EIP160 = 10 9 | GAS_EXPBYTE_EIP160 = 50 10 | 11 | 12 | # https://github.com/ethereum/EIPs/issues/170 13 | EIP170_CODE_SIZE_LIMIT = 24577 14 | -------------------------------------------------------------------------------- /docs/api/eth/api.rlp.rst: -------------------------------------------------------------------------------- 1 | RLP 2 | === 3 | 4 | 5 | .. toctree:: 6 | :maxdepth: 4 7 | :name: toc-eth-api-rlp 8 | :caption: RLP Objects 9 | 10 | rlp/api.rlp.accounts 11 | rlp/api.rlp.blocks 12 | rlp/api.rlp.headers 13 | rlp/api.rlp.logs 14 | rlp/api.rlp.receipts 15 | rlp/api.rlp.transactions 16 | -------------------------------------------------------------------------------- /eth/vm/forks/tangerine_whistle/constants.py: -------------------------------------------------------------------------------- 1 | # 2 | # EIP150 Mainnet Block 3 | # 4 | TANGERINE_WHISTLE_MAINNET_BLOCK = 2463000 5 | 6 | 7 | # 8 | # Gas Costs and Refunds 9 | # 10 | GAS_SELFDESTRUCT_EIP150 = 5000 11 | GAS_CALL_EIP150 = 700 12 | GAS_EXTCODE_EIP150 = 700 13 | GAS_BALANCE_EIP150 = 400 14 | GAS_SLOAD_EIP150 = 200 15 | -------------------------------------------------------------------------------- /scripts/benchmark/checks/__init__.py: -------------------------------------------------------------------------------- 1 | from .mine_empty_blocks import ( # noqa: F401 2 | MineEmptyBlocksBenchmark 3 | ) 4 | 5 | from .import_empty_blocks import ( # noqa: F401 6 | ImportEmptyBlocksBenchmark 7 | ) 8 | 9 | from .simple_value_transfers import ( # noqa: F401 10 | SimpleValueTransferBenchmark, 11 | ) 12 | -------------------------------------------------------------------------------- /eth/utils/hexadecimal.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | import codecs 4 | 5 | 6 | def encode_hex(value): 7 | return '0x' + codecs.decode(codecs.encode(value, 'hex'), 'utf8') 8 | 9 | 10 | def decode_hex(value): 11 | _, _, hex_part = value.rpartition('x') 12 | return codecs.decode(hex_part, 'hex') 13 | -------------------------------------------------------------------------------- /docs/guides/index.rst: -------------------------------------------------------------------------------- 1 | Guides 2 | ====== 3 | 4 | This section aims to provide hands-on guides to demonstrate how to use Trinity and the Py-EVM. If you are looking for detailed API descriptions check out the :doc:`API section `. 5 | 6 | .. toctree:: 7 | :maxdepth: 1 8 | :name: toc-guides 9 | 10 | trinity/index 11 | eth/index 12 | -------------------------------------------------------------------------------- /docs/api/eth/db/api.db.backends.rst: -------------------------------------------------------------------------------- 1 | Backends 2 | ======== 3 | 4 | BaseDB 5 | ------ 6 | 7 | .. autoclass:: eth.db.backends.base.BaseDB 8 | :members: 9 | 10 | LevelDB 11 | ------- 12 | 13 | .. autoclass:: eth.db.backends.level.LevelDB 14 | :members: 15 | 16 | MemoryDB 17 | -------- 18 | 19 | .. autoclass:: eth.db.backends.memory.MemoryDB 20 | :members: -------------------------------------------------------------------------------- /stubs/README.md: -------------------------------------------------------------------------------- 1 | This is a temporary placeholder for [typeshed](https://github.com/python/typeshed) stubs we write 2 | for the libraries we depend on. They should all eventually be submitted to typeshed, but it makes 3 | sense to keep them here for a while until our libs' APIs are stable and we work out any rough 4 | edges on the type definitions in the stubs themselves. 5 | -------------------------------------------------------------------------------- /docs/api/eth/vm/api.vm.vm.rst: -------------------------------------------------------------------------------- 1 | VM 2 | == 3 | 4 | BaseVM 5 | ------ 6 | 7 | .. autoclass:: eth.vm.base.BaseVM 8 | :members: 9 | 10 | 11 | VM 12 | -- 13 | 14 | .. # We need to exclude the `get_prev_hashes` method as the functool decorator breaks autodoc 15 | 16 | .. autoclass:: eth.vm.base.VM 17 | :members: 18 | :exclude-members: get_prev_hashes 19 | 20 | -------------------------------------------------------------------------------- /trinity/chains/coro.py: -------------------------------------------------------------------------------- 1 | from trinity.utils.async_dispatch import ( 2 | async_method, 3 | ) 4 | 5 | 6 | class AsyncChainMixin: 7 | 8 | coro_get_canonical_block_by_number = async_method('get_canonical_block_by_number') 9 | coro_get_block_by_hash = async_method('get_block_by_hash') 10 | coro_get_block_by_header = async_method('get_block_by_header') 11 | -------------------------------------------------------------------------------- /docs/guides/trinity/index.rst: -------------------------------------------------------------------------------- 1 | Trinity 2 | ======= 3 | 4 | This section aims to provide hands-on guides to demonstrate how to use Trinity. If you are looking for detailed API descriptions check out the :doc:`API section `. 5 | 6 | .. toctree:: 7 | :maxdepth: 3 8 | :name: toc-trinity-guides 9 | :caption: Guides 10 | 11 | quickstart 12 | architecture -------------------------------------------------------------------------------- /eth/tools/fixtures/fillers/__init__.py: -------------------------------------------------------------------------------- 1 | from .vm import ( # noqa: F401 2 | fill_vm_test, 3 | ) 4 | from .state import ( # noqa: F401 5 | fill_state_test, 6 | ) 7 | from .common import ( # noqa: F401 8 | execution, 9 | expect, 10 | pre_state, 11 | setup_filler, 12 | setup_main_filler, 13 | ) 14 | from .main import ( # noqa: F401 15 | fill_test, 16 | ) 17 | -------------------------------------------------------------------------------- /trinity/protocol/les/handlers.py: -------------------------------------------------------------------------------- 1 | from trinity.protocol.common.handlers import ( 2 | BaseExchangeHandler, 3 | ) 4 | 5 | from .exchanges import GetBlockHeadersExchange 6 | 7 | 8 | class LESExchangeHandler(BaseExchangeHandler): 9 | _exchange_config = { 10 | 'get_block_headers': GetBlockHeadersExchange, 11 | } 12 | 13 | get_block_headers: GetBlockHeadersExchange 14 | -------------------------------------------------------------------------------- /trinity/rlp/block_body.py: -------------------------------------------------------------------------------- 1 | import rlp 2 | from rlp import sedes 3 | 4 | 5 | from eth.rlp.headers import BlockHeader 6 | from eth.rlp.transactions import BaseTransactionFields 7 | 8 | 9 | class BlockBody(rlp.Serializable): 10 | fields = [ 11 | ('transactions', sedes.CountableList(BaseTransactionFields)), 12 | ('uncles', sedes.CountableList(BlockHeader)) 13 | ] 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6 2 | # Set up code directory 3 | RUN mkdir -p /usr/src/app 4 | WORKDIR /usr/src/app 5 | 6 | COPY . /usr/src/app 7 | 8 | RUN pip install -e .[dev] --no-cache-dir 9 | RUN pip install -U trinity --no-cache-dir 10 | 11 | RUN echo "Type \`trinity\` to boot or \`trinity --help\` for an overview of commands" 12 | 13 | EXPOSE 30303 30303/udp 14 | ENTRYPOINT ["trinity"] 15 | -------------------------------------------------------------------------------- /eth/precompiles/__init__.py: -------------------------------------------------------------------------------- 1 | from .sha256 import sha256 # noqa: F401 2 | from .identity import identity # noqa: F401 3 | from .ecrecover import ecrecover # noqa: F401 4 | from .ripemd160 import ripemd160 # noqa: F401 5 | from .modexp import modexp # noqa: F401 6 | from .ecadd import ecadd # noqa: F401 7 | from .ecmul import ecmul # noqa: F401 8 | from .ecpairing import ecpairing # noqa: F401 9 | -------------------------------------------------------------------------------- /scripts/benchmark/contract_data/__init__.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | from typing import ( 3 | Iterable 4 | ) 5 | CONTRACTS_ROOT = "./scripts/benchmark/contract_data/" 6 | 7 | CONTRACTS = [ 8 | "erc20.sol", 9 | "DOSContract.sol" 10 | ] 11 | 12 | 13 | def get_contracts() -> Iterable[pathlib.Path]: 14 | for val in CONTRACTS: 15 | yield pathlib.Path(CONTRACTS_ROOT) / pathlib.Path(val) 16 | -------------------------------------------------------------------------------- /stubs/eth_keys/backends/__init__.pyi: -------------------------------------------------------------------------------- 1 | from .base import BaseECCBackend 2 | from .coincurve import CoinCurveECCBackend, is_coincurve_available 3 | from .native import NativeECCBackend 4 | from typing import Optional 5 | 6 | def get_default_backend_class() -> str: ... 7 | def get_backend_class(import_path: Optional[str]=...) -> type: ... 8 | def get_backend(import_path: Optional[str]=...) -> BaseECCBackend: ... 9 | -------------------------------------------------------------------------------- /eth/estimators/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import Callable 3 | 4 | from eth.utils.module_loading import ( 5 | import_string, 6 | ) 7 | 8 | 9 | def get_gas_estimator() -> Callable: 10 | import_path = os.environ.get( 11 | 'GAS_ESTIMATOR_BACKEND_FUNC', 12 | 'eth.estimators.gas.binary_gas_search_intrinsic_tolerance', 13 | ) 14 | return import_string(import_path) 15 | -------------------------------------------------------------------------------- /eth/vm/forks/frontier/constants.py: -------------------------------------------------------------------------------- 1 | from eth_typing import ( 2 | Address 3 | ) 4 | 5 | CREATE_CONTRACT_ADDRESS = Address(b'') 6 | 7 | 8 | # 9 | # Difficulty 10 | # 11 | FRONTIER_DIFFICULTY_ADJUSTMENT_CUTOFF = 13 12 | 13 | 14 | # 15 | # Stack Limit 16 | # 17 | STACK_DEPTH_LIMIT = 1024 18 | 19 | 20 | # 21 | # Gas Costs and Refunds 22 | # 23 | REFUND_SELFDESTRUCT = 24000 24 | GAS_CODEDEPOSIT = 200 25 | -------------------------------------------------------------------------------- /trinity/nodes/mainnet.py: -------------------------------------------------------------------------------- 1 | from trinity.chains.mainnet import ( 2 | MainnetFullChain, 3 | MainnetLightDispatchChain, 4 | ) 5 | from trinity.nodes.light import LightNode 6 | from trinity.nodes.full import FullNode 7 | 8 | 9 | class MainnetFullNode(FullNode): 10 | chain_class = MainnetFullChain 11 | 12 | 13 | class MainnetLightNode(LightNode): 14 | chain_class = MainnetLightDispatchChain 15 | -------------------------------------------------------------------------------- /trinity/nodes/ropsten.py: -------------------------------------------------------------------------------- 1 | from trinity.chains.ropsten import ( 2 | RopstenFullChain, 3 | RopstenLightDispatchChain, 4 | ) 5 | from trinity.nodes.light import LightNode 6 | from trinity.nodes.full import FullNode 7 | 8 | 9 | class RopstenFullNode(FullNode): 10 | chain_class = RopstenFullChain 11 | 12 | 13 | class RopstenLightNode(LightNode): 14 | chain_class = RopstenLightDispatchChain 15 | -------------------------------------------------------------------------------- /trinity/utils/log_messages.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | 4 | def create_missing_ipc_error_message(ipc_path: Path) -> str: 5 | log_message = ( 6 | "The IPC path at {0} is not found. \n" 7 | "Please run " 8 | "'trinity --data-dir attach' " 9 | "to specify the IPC path." 10 | ).format(str(ipc_path)) 11 | return log_message 12 | -------------------------------------------------------------------------------- /trinity/chains/mainnet.py: -------------------------------------------------------------------------------- 1 | from eth.chains.mainnet import ( 2 | BaseMainnetChain, 3 | MainnetChain 4 | ) 5 | 6 | from trinity.chains.coro import AsyncChainMixin 7 | from trinity.chains.light import LightDispatchChain 8 | 9 | 10 | class MainnetFullChain(MainnetChain, AsyncChainMixin): 11 | pass 12 | 13 | 14 | class MainnetLightDispatchChain(BaseMainnetChain, LightDispatchChain): 15 | pass 16 | -------------------------------------------------------------------------------- /trinity/chains/ropsten.py: -------------------------------------------------------------------------------- 1 | from eth.chains.ropsten import ( 2 | BaseRopstenChain, 3 | RopstenChain 4 | ) 5 | 6 | from trinity.chains.coro import AsyncChainMixin 7 | from trinity.chains.light import LightDispatchChain 8 | 9 | 10 | class RopstenFullChain(RopstenChain, AsyncChainMixin): 11 | pass 12 | 13 | 14 | class RopstenLightDispatchChain(BaseRopstenChain, LightDispatchChain): 15 | pass 16 | -------------------------------------------------------------------------------- /docs/api/index.rst: -------------------------------------------------------------------------------- 1 | API 2 | ===== 3 | 4 | This section aims to provide a detailed description of all APIs. If you are looking for something more hands-on or higher-level check out the existing :doc:`guides `. 5 | 6 | .. warning:: 7 | 8 | We expect each alpha release to have breaking changes to the API. 9 | 10 | .. toctree:: 11 | :maxdepth: 3 12 | :name: toc-api 13 | 14 | trinity/index 15 | eth/index 16 | -------------------------------------------------------------------------------- /eth/rlp/sedes.py: -------------------------------------------------------------------------------- 1 | from rlp.sedes import ( 2 | BigEndianInt, 3 | Binary, 4 | ) 5 | 6 | from eth.constants import ( 7 | COLLATION_SIZE, 8 | ) 9 | 10 | 11 | address = Binary.fixed_length(20, allow_empty=True) 12 | collation_body = Binary.fixed_length(COLLATION_SIZE) 13 | hash32 = Binary.fixed_length(32) 14 | int32 = BigEndianInt(32) 15 | int256 = BigEndianInt(256) 16 | trie_root = Binary.fixed_length(32, allow_empty=True) 17 | -------------------------------------------------------------------------------- /eth/utils/padding.py: -------------------------------------------------------------------------------- 1 | from cytoolz import ( 2 | curry, 3 | ) 4 | 5 | 6 | ZERO_BYTE = b'\x00' 7 | 8 | 9 | @curry 10 | def zpad_right(value: bytes, to_size: int) -> bytes: 11 | return value.ljust(to_size, ZERO_BYTE) 12 | 13 | 14 | @curry 15 | def zpad_left(value: bytes, to_size: int) -> bytes: 16 | return value.rjust(to_size, ZERO_BYTE) 17 | 18 | 19 | pad32 = zpad_left(to_size=32) 20 | pad32r = zpad_right(to_size=32) 21 | -------------------------------------------------------------------------------- /eth/chains/ropsten/constants.py: -------------------------------------------------------------------------------- 1 | # 2 | # Byzantium Block 3 | # 4 | BYZANTIUM_ROPSTEN_BLOCK = 1700000 5 | 6 | 7 | # 8 | # DAO Block 9 | # 10 | DAO_FORK_ROPSTEN_BLOCK = 0 11 | 12 | 13 | # 14 | # Tangerine Whistle Block 15 | # 16 | TANGERINE_WHISTLE_ROPSTEN_BLOCK = 0 17 | 18 | 19 | # 20 | # Homestead Block 21 | # 22 | HOMESTEAD_ROPSTEN_BLOCK = 0 23 | 24 | 25 | # 26 | # Spurious Dragon Block 27 | # 28 | SPURIOUS_DRAGON_ROPSTEN_BLOCK = 10 29 | -------------------------------------------------------------------------------- /trinity/rpc/modules/main.py: -------------------------------------------------------------------------------- 1 | from eth.chains.base import ( 2 | AsyncChain 3 | ) 4 | 5 | from lahja import ( 6 | Endpoint 7 | ) 8 | 9 | 10 | class RPCModule: 11 | _chain = None 12 | 13 | def __init__(self, chain: AsyncChain, event_bus: Endpoint) -> None: 14 | self._chain = chain 15 | self._event_bus = event_bus 16 | 17 | def set_chain(self, chain: AsyncChain) -> None: 18 | self._chain = chain 19 | -------------------------------------------------------------------------------- /docs/api/eth/index.rst: -------------------------------------------------------------------------------- 1 | Py-EVM 2 | ====== 3 | 4 | This section aims to provide a detailed description of all APIs. If you are looking for something more hands-on or higher-level check out the existing :doc:`EVM guides `. 5 | 6 | .. toctree:: 7 | :maxdepth: 4 8 | :name: toc-api-eth 9 | :caption: API 10 | 11 | 12 | api.chain 13 | api.db 14 | api.exceptions 15 | api.rlp 16 | api.tools 17 | api.vm 18 | -------------------------------------------------------------------------------- /eth/precompiles/identity.py: -------------------------------------------------------------------------------- 1 | from eth import constants 2 | from eth.utils.numeric import ( 3 | ceil32, 4 | ) 5 | 6 | 7 | def identity(computation): 8 | word_count = ceil32(len(computation.msg.data)) // 32 9 | gas_fee = constants.GAS_IDENTITY + word_count * constants.GAS_IDENTITYWORD 10 | 11 | computation.consume_gas(gas_fee, reason="Identity Precompile") 12 | 13 | computation.output = computation.msg.data 14 | return computation 15 | -------------------------------------------------------------------------------- /eth/tools/_utils/hashing.py: -------------------------------------------------------------------------------- 1 | from eth_hash.auto import keccak 2 | 3 | import rlp 4 | 5 | from eth.rlp.logs import Log 6 | 7 | 8 | def hash_log_entries(log_entries): 9 | """ 10 | Helper function for computing the RLP hash of the logs from transaction 11 | execution. 12 | """ 13 | logs = [Log(*entry) for entry in log_entries] 14 | encoded_logs = rlp.encode(logs) 15 | logs_hash = keccak(encoded_logs) 16 | return logs_hash 17 | -------------------------------------------------------------------------------- /trinity/protocol/les/constants.py: -------------------------------------------------------------------------------- 1 | # Max number of items we can ask for in LES requests. These are the values used in geth and if we 2 | # ask for more than this the peers will disconnect from us. 3 | MAX_HEADERS_FETCH = 192 4 | MAX_BODIES_FETCH = 32 5 | MAX_RECEIPTS_FETCH = 128 6 | MAX_CODE_FETCH = 64 7 | MAX_PROOFS_FETCH = 64 8 | MAX_HEADER_PROOFS_FETCH = 64 9 | 10 | # Types of LES Announce messages 11 | LES_ANNOUNCE_SIMPLE = 1 12 | LES_ANNOUNCE_SIGNED = 2 13 | -------------------------------------------------------------------------------- /trinity/utils/async_errors.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Awaitable, 3 | Optional, 4 | Tuple, 5 | TypeVar, 6 | ) 7 | 8 | 9 | TReturn = TypeVar("TReturn") 10 | 11 | 12 | async def await_and_wrap_errors( 13 | awaitable: Awaitable[TReturn]) -> Tuple[Optional[TReturn], Optional[Exception]]: 14 | try: 15 | val = await awaitable 16 | except Exception as e: 17 | return None, e 18 | else: 19 | return val, None 20 | -------------------------------------------------------------------------------- /scripts/benchmark/utils/shellart.py: -------------------------------------------------------------------------------- 1 | from termcolor import colored 2 | 3 | 4 | def bold_green(txt: str) -> str: 5 | return colored(txt, 'green', attrs=['bold']) 6 | 7 | 8 | def bold_red(txt: str) -> str: 9 | return colored(txt, 'red', attrs=['bold']) 10 | 11 | 12 | def bold_yellow(txt: str) -> str: 13 | return colored(txt, 'yellow', attrs=['bold']) 14 | 15 | 16 | def bold_white(txt: str) -> str: 17 | return colored(txt, 'white', attrs=['bold']) 18 | -------------------------------------------------------------------------------- /docs/guides/eth/index.rst: -------------------------------------------------------------------------------- 1 | Py-EVM 2 | ====== 3 | 4 | This section aims to provide hands-on guides to demonstrate how to use Py-EVM. If you are looking for detailed API descriptions check out the :doc:`API section `. 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | :name: toc-eth-guides 9 | :caption: Guides 10 | 11 | quickstart 12 | building_an_app_that_uses_pyevm 13 | architecture 14 | understanding_the_mining_process 15 | creating_opcodes 16 | -------------------------------------------------------------------------------- /eth/vm/forks/constantinople/headers.py: -------------------------------------------------------------------------------- 1 | from eth.vm.forks.byzantium.headers import ( 2 | configure_header, 3 | create_header_from_parent, 4 | compute_difficulty, 5 | ) 6 | 7 | 8 | compute_constantinople_difficulty = compute_difficulty(5000000) 9 | 10 | create_constantinople_header_from_parent = create_header_from_parent( 11 | compute_constantinople_difficulty 12 | ) 13 | configure_constantinople_header = configure_header(compute_constantinople_difficulty) 14 | -------------------------------------------------------------------------------- /eth/vm/forks/__init__.py: -------------------------------------------------------------------------------- 1 | from .tangerine_whistle import ( # noqa: F401 2 | TangerineWhistleVM, 3 | ) 4 | from .frontier import ( # noqa: F401 5 | FrontierVM, 6 | ) 7 | from .homestead import ( # noqa: F401 8 | HomesteadVM, 9 | ) 10 | from .spurious_dragon import ( # noqa: F401 11 | SpuriousDragonVM, 12 | ) 13 | from .byzantium import ( # noqa: F401 14 | ByzantiumVM, 15 | ) 16 | from .constantinople import ( # noqa: F401 17 | ConstantinopleVM 18 | ) 19 | -------------------------------------------------------------------------------- /trinity/protocol/common/commands.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from typing import Tuple 3 | 4 | from eth.rlp.headers import BlockHeader 5 | 6 | from p2p.protocol import ( 7 | Command, 8 | _DecodedMsgType, 9 | ) 10 | 11 | 12 | class BaseBlockHeaders(ABC, Command): 13 | 14 | @abstractmethod 15 | def extract_headers(self, msg: _DecodedMsgType) -> Tuple[BlockHeader, ...]: 16 | raise NotImplementedError("Must be implemented by subclasses") 17 | -------------------------------------------------------------------------------- /eth/vm/forks/tangerine_whistle/computation.py: -------------------------------------------------------------------------------- 1 | from ..homestead.computation import HomesteadComputation 2 | 3 | from .opcodes import TANGERINE_WHISTLE_OPCODES 4 | 5 | 6 | class TangerineWhistleComputation(HomesteadComputation): 7 | """ 8 | A class for all execution computations in the ``TangerineWhistle`` fork. 9 | Inherits from :class:`~eth.vm.forks.homestead.computation.HomesteadComputation` 10 | """ 11 | # Override 12 | opcodes = TANGERINE_WHISTLE_OPCODES 13 | -------------------------------------------------------------------------------- /tests/core/numeric-utils/test_get_highest_bit_length.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from eth.utils.numeric import ( 4 | get_highest_bit_index, 5 | ) 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'value,expected', 10 | ( 11 | (1, 0), 12 | (2, 1), 13 | (3, 1), 14 | (255, 7), 15 | (256, 8), 16 | ) 17 | ) 18 | def test_get_highest_bit_index(value, expected): 19 | actual = get_highest_bit_index(value) 20 | assert actual == expected 21 | -------------------------------------------------------------------------------- /trinity/rlp/sedes.py: -------------------------------------------------------------------------------- 1 | from rlp import sedes 2 | 3 | 4 | class HashOrNumber: 5 | 6 | def serialize(self, obj: int) -> bytes: 7 | if isinstance(obj, int): 8 | return sedes.big_endian_int.serialize(obj) 9 | return sedes.binary.serialize(obj) 10 | 11 | def deserialize(self, serial: bytes) -> int: 12 | if len(serial) == 32: 13 | return sedes.binary.deserialize(serial) 14 | return sedes.big_endian_int.deserialize(serial) 15 | -------------------------------------------------------------------------------- /docs/api/eth/api.vm.rst: -------------------------------------------------------------------------------- 1 | Virtual Machine 2 | =============== 3 | 4 | 5 | .. toctree:: 6 | :maxdepth: 4 7 | :name: toc-eth-api-vm 8 | :caption: Virtual Machine 9 | 10 | vm/api.vm.computation 11 | vm/api.vm.code_stream 12 | vm/api.vm.execution_context 13 | vm/api.vm.gas_meter 14 | vm/api.vm.memory 15 | vm/api.vm.message 16 | vm/api.vm.opcode 17 | vm/api.vm.vm 18 | vm/api.vm.stack 19 | vm/api.vm.state 20 | vm/api.vm.transaction_context 21 | vm/api.vm.forks -------------------------------------------------------------------------------- /scripts/benchmark/utils/format.py: -------------------------------------------------------------------------------- 1 | from eth.rlp.blocks import BaseBlock 2 | from eth.utils.hexadecimal import ( 3 | encode_hex, 4 | ) 5 | 6 | 7 | def format_block(block: BaseBlock) -> str: 8 | return ( 9 | "\n\n" 10 | "------------------------Block------------------------------------\n" 11 | "Number #{b.number:>12} Hash {hash}\n" 12 | "-----------------------------------------------------------------\n" 13 | ).format(b=block, hash=encode_hex(block.hash)) 14 | -------------------------------------------------------------------------------- /trinity/extensibility/__init__.py: -------------------------------------------------------------------------------- 1 | from trinity.extensibility.events import ( # noqa: F401 2 | BaseEvent 3 | ) 4 | from trinity.extensibility.plugin import ( # noqa: F401 5 | BasePlugin, 6 | BaseIsolatedPlugin, 7 | DebugPlugin, 8 | PluginContext, 9 | PluginProcessScope, 10 | ) 11 | from trinity.extensibility.plugin_manager import ( # noqa: F401 12 | MainAndIsolatedProcessScope, 13 | PluginManager, 14 | ManagerProcessScope, 15 | SharedProcessScope, 16 | ) 17 | -------------------------------------------------------------------------------- /eth/tools/logging.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Any 3 | 4 | TRACE_LEVEL_NUM = 5 5 | 6 | 7 | class TraceLogger(logging.Logger): 8 | 9 | def trace(self, message: str, *args: Any, **kwargs: Any) -> None: 10 | self.log(TRACE_LEVEL_NUM, message, *args, **kwargs) 11 | 12 | 13 | def setup_trace_logging() -> None: 14 | logging.setLoggerClass(TraceLogger) 15 | logging.addLevelName(TRACE_LEVEL_NUM, 'TRACE') 16 | setattr(logging, 'TRACE', TRACE_LEVEL_NUM) # typing: ignore 17 | -------------------------------------------------------------------------------- /eth/vm/logic/invalid.py: -------------------------------------------------------------------------------- 1 | from eth.exceptions import InvalidInstruction 2 | from eth.vm.opcode import Opcode 3 | 4 | 5 | class InvalidOpcode(Opcode): 6 | mnemonic = "INVALID" 7 | gas_cost = 0 8 | 9 | def __init__(self, value): 10 | self.value = value 11 | super().__init__() 12 | 13 | def __call__(self, computation): 14 | raise InvalidInstruction("Invalid opcode 0x{0:x} @ {1}".format( 15 | self.value, 16 | computation.code.pc - 1, 17 | )) 18 | -------------------------------------------------------------------------------- /p2p/events.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Type, 3 | ) 4 | 5 | from lahja import ( 6 | BaseEvent, 7 | BaseRequestResponseEvent, 8 | ) 9 | 10 | 11 | class PeerCountResponse(BaseEvent): 12 | 13 | def __init__(self, peer_count: int) -> None: 14 | self.peer_count = peer_count 15 | 16 | 17 | class PeerCountRequest(BaseRequestResponseEvent[PeerCountResponse]): 18 | 19 | @staticmethod 20 | def expected_response_type() -> Type[PeerCountResponse]: 21 | return PeerCountResponse 22 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. include:: introduction.rst 2 | 3 | 4 | Table of contents 5 | ============================== 6 | 7 | .. toctree:: 8 | :maxdepth: 1 9 | :caption: General 10 | 11 | introduction 12 | quickstart 13 | release_notes/index 14 | 15 | .. toctree:: 16 | :maxdepth: 1 17 | :caption: Fundamentals 18 | 19 | cookbooks/index 20 | guides/index 21 | api/index 22 | 23 | .. toctree:: 24 | :maxdepth: 1 25 | :caption: Community 26 | 27 | contributing 28 | code_of_conduct 29 | -------------------------------------------------------------------------------- /p2p/tools/paragon/__init__.py: -------------------------------------------------------------------------------- 1 | from .commands import ( # noqa: F401 2 | BroadcastData, 3 | GetSum, 4 | Sum, 5 | ) 6 | from .proto import ( # noqa: F401 7 | ParagonProtocol, 8 | ) 9 | from .peer import ( # noqa: F401 10 | ParagonContext, 11 | ParagonPeer, 12 | ParagonPeerFactory, 13 | ParagonPeerPool, 14 | ) 15 | from .helpers import ( # noqa: F401 16 | get_directly_connected_streams, 17 | get_directly_linked_peers, 18 | get_directly_linked_peers_without_handshake, 19 | ) 20 | -------------------------------------------------------------------------------- /eth/vm/forks/homestead/validation.py: -------------------------------------------------------------------------------- 1 | from eth_utils import ( 2 | ValidationError, 3 | ) 4 | 5 | from eth.constants import ( 6 | SECPK1_N, 7 | ) 8 | 9 | from eth.vm.forks.frontier.validation import ( 10 | validate_frontier_transaction, 11 | ) 12 | 13 | 14 | def validate_homestead_transaction(account_db, transaction): 15 | if transaction.s > SECPK1_N // 2 or transaction.s == 0: 16 | raise ValidationError("Invalid signature S value") 17 | 18 | validate_frontier_transaction(account_db, transaction) 19 | -------------------------------------------------------------------------------- /trinity/utils/async_dispatch.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import functools 3 | from typing import ( 4 | Any, 5 | Awaitable, 6 | Callable 7 | ) 8 | 9 | 10 | def async_method(method_name: str) -> Callable[..., Any]: 11 | async def method(self: Any, *args: Any, **kwargs: Any) -> Awaitable[Any]: 12 | loop = asyncio.get_event_loop() 13 | 14 | func = getattr(self, method_name) 15 | pfunc = functools.partial(func, *args, **kwargs) 16 | 17 | return await loop.run_in_executor(None, pfunc) 18 | return method 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | * py-evm Version: x.x.x 2 | * OS: osx/linux/win 3 | * Python Version (python --version): 4 | * Environment (output of `pip freeze`): 5 | 6 | ### What is wrong? 7 | 8 | Please include information like: 9 | 10 | * full output of the error you received 11 | * what command you ran 12 | * the code that caused the failure (see [this link](https://help.github.com/articles/basic-writing-and-formatting-syntax/) for help with formatting code) 13 | 14 | 15 | ### How can it be fixed 16 | 17 | Fill this in if you know how to fix it. 18 | -------------------------------------------------------------------------------- /eth/precompiles/sha256.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | 3 | from eth import constants 4 | 5 | from eth.utils.numeric import ( 6 | ceil32, 7 | ) 8 | 9 | 10 | def sha256(computation): 11 | word_count = ceil32(len(computation.msg.data)) // 32 12 | gas_fee = constants.GAS_SHA256 + word_count * constants.GAS_SHA256WORD 13 | 14 | computation.consume_gas(gas_fee, reason="SHA256 Precompile") 15 | input_bytes = computation.msg.data 16 | hash = hashlib.sha256(input_bytes).digest() 17 | computation.output = hash 18 | return computation 19 | -------------------------------------------------------------------------------- /p2p/tools/paragon/commands.py: -------------------------------------------------------------------------------- 1 | from rlp import sedes 2 | 3 | from p2p.protocol import ( 4 | Command, 5 | ) 6 | 7 | 8 | class BroadcastData(Command): 9 | _cmd_id = 0 10 | structure = [ 11 | ('data', sedes.binary), 12 | ] 13 | 14 | 15 | class GetSum(Command): 16 | _cmd_id = 2 17 | structure = [ 18 | ('a', sedes.big_endian_int), 19 | ('b', sedes.big_endian_int), 20 | ] 21 | 22 | 23 | class Sum(Command): 24 | _cmd_id = 3 25 | structure = [ 26 | ('result', sedes.big_endian_int), 27 | ] 28 | -------------------------------------------------------------------------------- /stubs/eth_keys/validation.pyi: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | def validate_integer(value: int) -> None: ... 4 | def validate_bytes(value: bytes) -> None: ... 5 | def validate_gte(value: int, minimum: int) -> None: ... 6 | def validate_lte(value: int, maximum: int) -> None: ... 7 | 8 | validate_lt_secpk1n: Any 9 | 10 | def validate_message_hash(value: bytes) -> None: ... 11 | def validate_public_key_bytes(value: bytes) -> None: ... 12 | def validate_private_key_bytes(value: bytes) -> None: ... 13 | def validate_signature_bytes(value: bytes) -> None: ... 14 | -------------------------------------------------------------------------------- /eth/chains/mainnet/constants.py: -------------------------------------------------------------------------------- 1 | # Blocks listed in ascending order 2 | 3 | # 4 | # Homestead Block 5 | # 6 | HOMESTEAD_MAINNET_BLOCK = 1150000 7 | 8 | 9 | # 10 | # DAO Block 11 | # 12 | DAO_FORK_MAINNET_BLOCK = 1920000 13 | 14 | DAO_FORK_MAINNET_EXTRA_DATA = b'dao-hard-fork' 15 | 16 | 17 | # 18 | # Tangerine Whistle Block 19 | # 20 | TANGERINE_WHISTLE_MAINNET_BLOCK = 2463000 21 | 22 | 23 | # 24 | # Spurious Dragon Block 25 | # 26 | SPURIOUS_DRAGON_MAINNET_BLOCK = 2675000 27 | 28 | 29 | # 30 | # Byzantium Block 31 | # 32 | BYZANTIUM_MAINNET_BLOCK = 4370000 33 | -------------------------------------------------------------------------------- /eth/tools/mining.py: -------------------------------------------------------------------------------- 1 | from eth.consensus import pow 2 | 3 | 4 | class POWMiningMixin: 5 | """ 6 | A VM that does POW mining as well. Should be used only in tests, when we 7 | need to programatically populate a ChainDB. 8 | """ 9 | def finalize_block(self, block): 10 | block = super().finalize_block(block) # type: ignore 11 | nonce, mix_hash = pow.mine_pow_nonce( 12 | block.number, block.header.mining_hash, block.header.difficulty) 13 | return block.copy(header=block.header.copy(nonce=nonce, mix_hash=mix_hash)) 14 | -------------------------------------------------------------------------------- /eth/vm/forks/homestead/blocks.py: -------------------------------------------------------------------------------- 1 | from rlp.sedes import ( 2 | CountableList, 3 | ) 4 | from eth.rlp.headers import ( 5 | BlockHeader, 6 | ) 7 | from eth.vm.forks.frontier.blocks import ( 8 | FrontierBlock, 9 | ) 10 | from .transactions import ( 11 | HomesteadTransaction, 12 | ) 13 | 14 | 15 | class HomesteadBlock(FrontierBlock): 16 | transaction_class = HomesteadTransaction 17 | fields = [ 18 | ('header', BlockHeader), 19 | ('transactions', CountableList(transaction_class)), 20 | ('uncles', CountableList(BlockHeader)) 21 | ] 22 | -------------------------------------------------------------------------------- /eth/vm/forks/homestead/state.py: -------------------------------------------------------------------------------- 1 | from eth.vm.forks.frontier.state import ( 2 | FrontierState, 3 | FrontierTransactionExecutor, 4 | ) 5 | 6 | from .computation import HomesteadComputation 7 | from .validation import validate_homestead_transaction 8 | 9 | 10 | class HomesteadState(FrontierState): 11 | computation_class = HomesteadComputation 12 | 13 | def validate_transaction(self, transaction): 14 | validate_homestead_transaction(self.account_db, transaction) 15 | 16 | 17 | class HomesteadTransactionExecutor(FrontierTransactionExecutor): 18 | pass 19 | -------------------------------------------------------------------------------- /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.2.0-alpha.32 3 | commit = True 4 | tag = True 5 | parse = (?P\d+)\.(?P\d+)\.(?P\d+)(-(?P[^.]*)\.(?P\d+))? 6 | serialize = 7 | {major}.{minor}.{patch}-{stage}.{devnum} 8 | {major}.{minor}.{patch} 9 | 10 | [bumpversion:part:stage] 11 | optional_value = stable 12 | first_value = stable 13 | values = 14 | alpha 15 | beta 16 | stable 17 | 18 | [bumpversion:part:devnum] 19 | 20 | [bumpversion:file:setup.py] 21 | search = version='{current_version}', 22 | replace = version='{new_version}', 23 | 24 | -------------------------------------------------------------------------------- /eth/__init__.py: -------------------------------------------------------------------------------- 1 | import pkg_resources 2 | import sys 3 | 4 | from eth.tools.logging import ( 5 | setup_trace_logging 6 | ) 7 | 8 | # 9 | # Setup TRACE level logging. 10 | # 11 | # This needs to be done before the other imports 12 | setup_trace_logging() 13 | 14 | from eth.chains import ( # noqa: F401 15 | Chain, 16 | MainnetChain, 17 | MainnetTesterChain, 18 | RopstenChain, 19 | ) 20 | 21 | # 22 | # Ensure we can reach 1024 frames of recursion 23 | # 24 | sys.setrecursionlimit(1024 * 10) 25 | 26 | 27 | __version__ = pkg_resources.get_distribution("py-evm").version 28 | -------------------------------------------------------------------------------- /stubs/eth_keys/backends/native/main.pyi: -------------------------------------------------------------------------------- 1 | from .ecdsa import ecdsa_raw_recover, ecdsa_raw_sign, private_key_to_public_key 2 | from eth_keys.backends.base import BaseECCBackend 3 | from eth_keys.datatypes import PrivateKey, PublicKey, Signature 4 | from typing import Optional 5 | 6 | class NativeECCBackend(BaseECCBackend): 7 | def ecdsa_sign(self, msg_hash: bytes, private_key: PrivateKey) -> Signature: ... 8 | def ecdsa_recover(self, msg_hash: bytes, signature: Signature) -> Optional[PublicKey]: ... 9 | def private_key_to_public_key(self, private_key: PrivateKey) -> PublicKey: ... 10 | -------------------------------------------------------------------------------- /eth/utils/version.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from eth import __version__ 4 | 5 | 6 | def construct_evm_runtime_identifier(): 7 | """ 8 | Constructs the EVM runtime identifier string 9 | 10 | e.g. 'Py-EVM/v1.2.3/darwin-amd64/python3.6.5' 11 | """ 12 | return "Py-EVM/{0}/{platform}/{imp.name}{v.major}.{v.minor}.{v.micro}".format( 13 | __version__, 14 | platform=sys.platform, 15 | v=sys.version_info, 16 | # mypy Doesn't recognize the `sys` module as having an `implementation` attribute. 17 | imp=sys.implementation, # type: ignore 18 | ) 19 | -------------------------------------------------------------------------------- /eth/vm/forks/byzantium/blocks.py: -------------------------------------------------------------------------------- 1 | from rlp.sedes import ( 2 | CountableList, 3 | ) 4 | from eth.rlp.headers import ( 5 | BlockHeader, 6 | ) 7 | from eth.vm.forks.spurious_dragon.blocks import ( 8 | SpuriousDragonBlock, 9 | ) 10 | 11 | from .transactions import ( 12 | ByzantiumTransaction, 13 | ) 14 | 15 | 16 | class ByzantiumBlock(SpuriousDragonBlock): 17 | transaction_class = ByzantiumTransaction 18 | fields = [ 19 | ('header', BlockHeader), 20 | ('transactions', CountableList(transaction_class)), 21 | ('uncles', CountableList(BlockHeader)) 22 | ] 23 | -------------------------------------------------------------------------------- /eth/vm/forks/spurious_dragon/blocks.py: -------------------------------------------------------------------------------- 1 | from rlp.sedes import ( 2 | CountableList, 3 | ) 4 | from eth.rlp.headers import ( 5 | BlockHeader, 6 | ) 7 | from eth.vm.forks.homestead.blocks import ( 8 | HomesteadBlock, 9 | ) 10 | from .transactions import ( 11 | SpuriousDragonTransaction, 12 | ) 13 | 14 | 15 | class SpuriousDragonBlock(HomesteadBlock): 16 | transaction_class = SpuriousDragonTransaction 17 | fields = [ 18 | ('header', BlockHeader), 19 | ('transactions', CountableList(transaction_class)), 20 | ('uncles', CountableList(BlockHeader)) 21 | ] 22 | -------------------------------------------------------------------------------- /trinity/protocol/les/normalizers.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Any, 3 | Dict, 4 | Tuple, 5 | TypeVar, 6 | ) 7 | 8 | from eth.rlp.headers import BlockHeader 9 | 10 | from trinity.protocol.common.normalizers import BaseNormalizer 11 | 12 | TResult = TypeVar('TResult') 13 | LESNormalizer = BaseNormalizer[Dict[str, Any], TResult] 14 | 15 | 16 | class BlockHeadersNormalizer(LESNormalizer[Tuple[BlockHeader, ...]]): 17 | @staticmethod 18 | def normalize_result(message: Dict[str, Any]) -> Tuple[BlockHeader, ...]: 19 | result = message['headers'] 20 | return result 21 | -------------------------------------------------------------------------------- /eth/vm/forks/constantinople/blocks.py: -------------------------------------------------------------------------------- 1 | from rlp.sedes import ( 2 | CountableList, 3 | ) 4 | from eth.rlp.headers import ( 5 | BlockHeader, 6 | ) 7 | from eth.vm.forks.byzantium.blocks import ( 8 | ByzantiumBlock, 9 | ) 10 | 11 | from .transactions import ( 12 | ConstantinopleTransaction, 13 | ) 14 | 15 | 16 | class ConstantinopleBlock(ByzantiumBlock): 17 | transaction_class = ConstantinopleTransaction 18 | fields = [ 19 | ('header', BlockHeader), 20 | ('transactions', CountableList(transaction_class)), 21 | ('uncles', CountableList(BlockHeader)) 22 | ] 23 | -------------------------------------------------------------------------------- /trinity/utils/version.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from trinity import __version__ 4 | 5 | 6 | def construct_trinity_client_identifier() -> str: 7 | """ 8 | Constructs the client identifier string 9 | 10 | e.g. 'Trinity/v1.2.3/darwin-amd64/python3.6.5' 11 | """ 12 | return "Trinity/{0}/{platform}/{imp.name}{v.major}.{v.minor}.{v.micro}".format( 13 | __version__, 14 | platform=sys.platform, 15 | v=sys.version_info, 16 | # mypy Doesn't recognize the `sys` module as having an `implementation` attribute. 17 | imp=sys.implementation, # type: ignore 18 | ) 19 | -------------------------------------------------------------------------------- /stubs/eth_keys/backends/native/jacobian.pyi: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | def inv(a: int, n: int) -> int: ... 4 | def to_jacobian(p: Tuple[int, int]) -> Tuple[int, int, int]: ... 5 | def jacobian_double(p: Tuple[int, int, int]) -> Tuple[int, int, int]: ... 6 | def jacobian_add(p: Tuple[int, int, int], q: Tuple[int, int, int]) -> Tuple[int, int, int]: ... 7 | def from_jacobian(p: Tuple[int, int, int]) -> Tuple[int, int]: ... 8 | def jacobian_multiply(a: Tuple[int, int, int], n: int) -> Tuple[int, int, int]: ... 9 | def fast_multiply(a: Tuple[int, int], n: int) -> Tuple[int, int]: ... 10 | def fast_add(a, b): ... 11 | -------------------------------------------------------------------------------- /eth/vm/forks/spurious_dragon/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import Type # noqa: F401 2 | from eth.rlp.blocks import BaseBlock # noqa: F401 3 | from eth.vm.state import BaseState # noqa: F401 4 | 5 | from ..tangerine_whistle import TangerineWhistleVM 6 | 7 | from .blocks import SpuriousDragonBlock 8 | from .state import SpuriousDragonState 9 | 10 | 11 | class SpuriousDragonVM(TangerineWhistleVM): 12 | # fork name 13 | fork = 'spurious-dragon' # type: str 14 | 15 | # classes 16 | block_class = SpuriousDragonBlock # type: Type[BaseBlock] 17 | _state_class = SpuriousDragonState # type: Type[BaseState] 18 | -------------------------------------------------------------------------------- /trinity/protocol/common/context.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Tuple, 3 | Type, 4 | ) 5 | 6 | from eth.vm.base import BaseVM 7 | 8 | from p2p.peer import BasePeerContext 9 | 10 | from trinity.db.header import BaseAsyncHeaderDB 11 | 12 | 13 | class ChainContext(BasePeerContext): 14 | def __init__(self, 15 | headerdb: BaseAsyncHeaderDB, 16 | network_id: int, 17 | vm_configuration: Tuple[Tuple[int, Type[BaseVM]], ...]) -> None: 18 | self.headerdb = headerdb 19 | self.network_id = network_id 20 | self.vm_configuration = vm_configuration 21 | -------------------------------------------------------------------------------- /eth/vm/forks/tangerine_whistle/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import Type # noqa: F401 2 | from eth.vm.state import BaseState # noqa: F401 3 | 4 | from eth.vm.forks.homestead import HomesteadVM 5 | 6 | from .state import TangerineWhistleState 7 | 8 | 9 | class TangerineWhistleVM(HomesteadVM): 10 | # fork name 11 | fork = 'tangerine-whistle' # type: str 12 | 13 | # classes 14 | _state_class = TangerineWhistleState # type: Type[BaseState] 15 | 16 | # Don't bother with any DAO logic in Tangerine VM or later 17 | # This is how we skip DAO logic on Ropsten, for example 18 | support_dao_fork = False 19 | -------------------------------------------------------------------------------- /docs/api/eth/rlp/api.rlp.transactions.rst: -------------------------------------------------------------------------------- 1 | Transactions 2 | ============ 3 | 4 | BaseTransactionMethods 5 | ---------------------- 6 | 7 | .. autoclass:: eth.rlp.transactions.BaseTransactionMethods 8 | :members: 9 | 10 | BaseTransactionFields 11 | ---------------------- 12 | 13 | .. autoclass:: eth.rlp.transactions.BaseTransactionFields 14 | :members: 15 | 16 | BaseTransaction 17 | --------------- 18 | 19 | .. autoclass:: eth.rlp.transactions.BaseTransaction 20 | :members: 21 | 22 | BaseUnsignedTransaction 23 | ----------------------- 24 | 25 | .. autoclass:: eth.rlp.transactions.BaseUnsignedTransaction 26 | :members: 27 | 28 | -------------------------------------------------------------------------------- /stubs/eth_keys/backends/coincurve.pyi: -------------------------------------------------------------------------------- 1 | from .base import BaseECCBackend 2 | from eth_keys.datatypes import PrivateKey, PublicKey, Signature 3 | from typing import Any, Optional 4 | 5 | def is_coincurve_available() -> bool: ... 6 | 7 | class CoinCurveECCBackend(BaseECCBackend): 8 | keys: Any = ... 9 | ecdsa: Any = ... 10 | def __init__(self) -> None: ... 11 | def ecdsa_sign(self, msg_hash: bytes, private_key: PrivateKey) -> Signature: ... 12 | def ecdsa_recover(self, msg_hash: bytes, signature: Signature) -> Optional[PublicKey]: ... 13 | def private_key_to_public_key(self, private_key: PrivateKey) -> PublicKey: ... 14 | -------------------------------------------------------------------------------- /scripts/benchmark/utils/meters.py: -------------------------------------------------------------------------------- 1 | import time 2 | from typing import ( 3 | Any, 4 | Callable, 5 | NamedTuple 6 | ) 7 | 8 | 9 | # FIXME: Couldn't get generics to work here. Sticking with `Any` for now 10 | # See: https://stackoverflow.com/questions/50530959/generic-namedtuple-in-python-3-6 11 | class TimedResult(NamedTuple): 12 | duration: float 13 | wrapped_value: Any 14 | 15 | 16 | def time_call(fn: Callable[..., Any]=None) -> TimedResult: 17 | start = time.perf_counter() 18 | return_value = fn() 19 | duration = time.perf_counter() - start 20 | return TimedResult(duration=duration, wrapped_value=return_value) 21 | -------------------------------------------------------------------------------- /trinity/protocol/les/validators.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Any, 3 | Dict, 4 | ) 5 | 6 | from eth_utils import ( 7 | ValidationError, 8 | ) 9 | 10 | from trinity.protocol.common.validators import ( 11 | BaseBlockHeadersValidator, 12 | ) 13 | from . import constants 14 | 15 | 16 | class GetBlockHeadersValidator(BaseBlockHeadersValidator): 17 | protocol_max_request_size = constants.MAX_HEADERS_FETCH 18 | 19 | 20 | def match_payload_request_id(request: Dict[str, Any], response: Dict[str, Any]) -> None: 21 | if request['request_id'] != response['request_id']: 22 | raise ValidationError("Request `id` does not match") 23 | -------------------------------------------------------------------------------- /.circleci/merge_pr.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ -n "${CIRCLE_PR_NUMBER}" ]]; then 4 | PR_INFO_URL=https://api.github.com/repos/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/pulls/$CIRCLE_PR_NUMBER 5 | PR_BASE_BRANCH=$(curl -L "$PR_INFO_URL" | python -c 'import json, sys; obj = json.load(sys.stdin); sys.stdout.write(obj["base"]["ref"])') 6 | git fetch origin +"$PR_BASE_BRANCH":circleci/pr-base 7 | # We need these config values or git complains when creating the 8 | # merge commit 9 | git config --global user.name "Circle CI" 10 | git config --global user.email "circleci@example.com" 11 | git merge --no-edit circleci/pr-base 12 | fi 13 | -------------------------------------------------------------------------------- /eth/vm/forks/homestead/opcodes.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | from cytoolz import merge 4 | 5 | from eth import constants 6 | from eth.vm import mnemonics 7 | from eth.vm import opcode_values 8 | from eth.vm.logic import ( 9 | call, 10 | ) 11 | 12 | from eth.vm.forks.frontier.opcodes import FRONTIER_OPCODES 13 | 14 | 15 | NEW_OPCODES = { 16 | opcode_values.DELEGATECALL: call.DelegateCall.configure( 17 | __name__='opcode:DELEGATECALL', 18 | mnemonic=mnemonics.DELEGATECALL, 19 | gas_cost=constants.GAS_CALL, 20 | )(), 21 | } 22 | 23 | 24 | HOMESTEAD_OPCODES = merge( 25 | copy.deepcopy(FRONTIER_OPCODES), 26 | NEW_OPCODES 27 | ) 28 | -------------------------------------------------------------------------------- /trinity/rpc/modules/web3.py: -------------------------------------------------------------------------------- 1 | from eth_hash.auto import keccak 2 | from eth_utils import decode_hex, encode_hex 3 | 4 | from trinity.utils.version import construct_trinity_client_identifier 5 | 6 | from trinity.rpc.modules import ( 7 | RPCModule, 8 | ) 9 | 10 | 11 | class Web3(RPCModule): 12 | async def clientVersion(self) -> str: 13 | """ 14 | Returns the current client version. 15 | """ 16 | return construct_trinity_client_identifier() 17 | 18 | async def sha3(self, data: str) -> str: 19 | """ 20 | Returns Keccak-256 of the given data. 21 | """ 22 | return encode_hex(keccak(decode_hex(data))) 23 | -------------------------------------------------------------------------------- /trinity/utils/timer.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | 4 | class Timer: 5 | _start: float = None 6 | 7 | def __init__(self, auto_start: bool = True) -> None: 8 | if auto_start: 9 | self.start() 10 | 11 | def start(self) -> None: 12 | self._start = time.perf_counter() 13 | 14 | def pop_elapsed(self) -> float: 15 | """Return time elapsed since last start, and start the timer over""" 16 | now = time.perf_counter() 17 | elapsed = now - self._start 18 | self._start = now 19 | return elapsed 20 | 21 | @property 22 | def elapsed(self) -> float: 23 | return time.perf_counter() - self._start 24 | -------------------------------------------------------------------------------- /eth/vm/logic/sha3.py: -------------------------------------------------------------------------------- 1 | from eth_hash.auto import keccak 2 | 3 | from eth import constants 4 | from eth.utils.numeric import ( 5 | ceil32, 6 | ) 7 | 8 | 9 | def sha3(computation): 10 | start_position, size = computation.stack_pop(num_items=2, type_hint=constants.UINT256) 11 | 12 | computation.extend_memory(start_position, size) 13 | 14 | sha3_bytes = computation.memory_read(start_position, size) 15 | word_count = ceil32(len(sha3_bytes)) // 32 16 | 17 | gas_cost = constants.GAS_SHA3WORD * word_count 18 | computation.consume_gas(gas_cost, reason="SHA3: word gas cost") 19 | 20 | result = keccak(sha3_bytes) 21 | 22 | computation.stack_push(result) 23 | -------------------------------------------------------------------------------- /stubs/eth_keys/backends/base.pyi: -------------------------------------------------------------------------------- 1 | from eth_keys import datatypes 2 | from typing import Any 3 | 4 | class BaseECCBackend: 5 | PublicKey: Any = ... 6 | PrivateKey: Any = ... 7 | Signature: Any = ... 8 | def __init__(self) -> None: ... 9 | def ecdsa_sign(self, msg_hash: bytes, private_key: PrivateKey) -> datatypes.Signature: ... 10 | def ecdsa_verify(self, msg_hash: bytes, signature: datatypes.Signature, public_key: datatypes.PublicKey) -> bool: ... 11 | def ecdsa_recover(self, msg_hash: bytes, signature: datatypes.Signature) -> datatypes.PublicKey: ... 12 | def private_key_to_public_key(self, private_key: datatypes.PrivateKey) -> datatypes.PublicKey: ... 13 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = py-evm 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /eth/tools/fixtures/__init__.py: -------------------------------------------------------------------------------- 1 | from .loading import ( # noqa: F401 2 | find_fixtures, 3 | filter_fixtures, 4 | load_fixture, 5 | ) 6 | from .generation import ( # noqa: F401 7 | generate_fixture_tests, 8 | ) 9 | from .helpers import ( # noqa: F401 10 | new_chain_from_fixture, 11 | genesis_params_from_fixture, 12 | apply_fixture_block_to_chain, 13 | setup_account_db, 14 | should_run_slow_tests, 15 | verify_account_db, 16 | ) 17 | from .normalization import ( # noqa: F401 18 | normalize_block, 19 | normalize_blockchain_fixtures, 20 | normalize_statetest_fixture, 21 | normalize_transactiontest_fixture, 22 | normalize_vmtest_fixture, 23 | ) 24 | -------------------------------------------------------------------------------- /docs/fragments/virtualenv_explainer.rst: -------------------------------------------------------------------------------- 1 | **Optional:** Often, the best way to guarantee a clean Python 3 environment is with 2 | `virtualenv `_. If we don't have ``virtualenv`` installed 3 | already, we first need to install it via pip. 4 | 5 | .. code:: sh 6 | 7 | pip install virtualenv 8 | 9 | Then, we can initialize a new virtual environment ``venv``, like: 10 | 11 | .. code:: sh 12 | 13 | virtualenv -p python3 venv 14 | 15 | This creates a new directory ``venv`` where packages are installed isolated from any other global 16 | packages. 17 | 18 | To activate the virtual directory we have to *source* it 19 | 20 | .. code:: sh 21 | 22 | . venv/bin/activate -------------------------------------------------------------------------------- /eth/precompiles/ripemd160.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | 3 | from eth import constants 4 | 5 | from eth.utils.numeric import ( 6 | ceil32, 7 | ) 8 | from eth.utils.padding import ( 9 | pad32, 10 | ) 11 | 12 | 13 | def ripemd160(computation): 14 | word_count = ceil32(len(computation.msg.data)) // 32 15 | gas_fee = constants.GAS_RIPEMD160 + word_count * constants.GAS_RIPEMD160WORD 16 | 17 | computation.consume_gas(gas_fee, reason="RIPEMD160 Precompile") 18 | 19 | # TODO: this only works if openssl is installed. 20 | hash = hashlib.new('ripemd160', computation.msg.data).digest() 21 | padded_hash = pad32(hash) 22 | computation.output = padded_hash 23 | return computation 24 | -------------------------------------------------------------------------------- /eth/rlp/logs.py: -------------------------------------------------------------------------------- 1 | import rlp 2 | from rlp.sedes import ( 3 | CountableList, 4 | binary, 5 | ) 6 | 7 | from .sedes import ( 8 | address, 9 | int32, 10 | ) 11 | 12 | 13 | class Log(rlp.Serializable): 14 | fields = [ 15 | ('address', address), 16 | ('topics', CountableList(int32)), 17 | ('data', binary) 18 | ] 19 | 20 | def __init__(self, address: bytes, topics: bytes, data: bytes) -> None: 21 | super().__init__(address, topics, data) 22 | 23 | @property 24 | def bloomables(self): 25 | return ( 26 | self.address, 27 | ) + tuple( 28 | int32.serialize(topic) for topic in self.topics 29 | ) 30 | -------------------------------------------------------------------------------- /tests/core/padding-utils/test_padding.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from eth.utils.padding import ( 4 | pad32, 5 | pad32r 6 | ) 7 | 8 | padding_byte = b"\x00" 9 | 10 | 11 | @pytest.mark.parametrize( 12 | "value, expected", 13 | ( 14 | (b"", padding_byte * 32), 15 | (b"\x01", (padding_byte * 31) + b"\x01") 16 | ) 17 | ) 18 | def test_pad_32(value, expected): 19 | assert pad32(value) == expected 20 | 21 | 22 | @pytest.mark.parametrize( 23 | "value, expected", 24 | ( 25 | (b"", padding_byte * 32), 26 | (b"\x01", b"\x01" + (padding_byte * 31)) 27 | ) 28 | ) 29 | def test_pad_32r(value, expected): 30 | assert pad32r(value) == expected 31 | -------------------------------------------------------------------------------- /tests/trinity/core/chain-management/test_light_peer_chain.py: -------------------------------------------------------------------------------- 1 | from trinity.sync.light.service import ( 2 | LightPeerChain 3 | ) 4 | from trinity.plugins.builtin.light_peer_chain_bridge import ( 5 | EventBusLightPeerChain, 6 | ) 7 | 8 | 9 | # These tests may seem obvious but they safe us from runtime errors where 10 | # changes are made to the `BaseLightPeerChain` that are then forgotton to 11 | # implement on both derived chains. 12 | 13 | def test_can_instantiate_eventbus_light_peer_chain(): 14 | chain = EventBusLightPeerChain(None) 15 | assert chain is not None 16 | 17 | 18 | def test_can_instantiate_light_peer_chain(): 19 | chain = LightPeerChain(None, None) 20 | assert chain is not None 21 | -------------------------------------------------------------------------------- /eth/tools/rlp.py: -------------------------------------------------------------------------------- 1 | from eth_utils import ( 2 | replace_exceptions, 3 | ValidationError, 4 | ) 5 | 6 | from eth.utils.rlp import ( 7 | validate_rlp_equal, 8 | ) 9 | 10 | 11 | assert_imported_genesis_header_unchanged = replace_exceptions({ 12 | ValidationError: AssertionError, 13 | })(validate_rlp_equal(obj_a_name='genesis header', obj_b_name='imported header')) 14 | 15 | 16 | assert_mined_block_unchanged = replace_exceptions({ 17 | ValidationError: AssertionError, 18 | })(validate_rlp_equal(obj_a_name='block', obj_b_name='mined block')) 19 | 20 | 21 | assert_headers_eq = replace_exceptions({ 22 | ValidationError: AssertionError, 23 | })(validate_rlp_equal(obj_a_name='expected', obj_b_name='actual')) 24 | -------------------------------------------------------------------------------- /eth/db/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import ( 3 | Any, 4 | Type 5 | ) 6 | 7 | from eth.utils.module_loading import ( 8 | import_string, 9 | ) 10 | from eth.db.backends.base import ( 11 | BaseAtomicDB, 12 | ) 13 | 14 | DEFAULT_DB_BACKEND = 'eth.db.atomic.AtomicDB' 15 | 16 | 17 | def get_db_backend_class(import_path: str = None) -> Type[BaseAtomicDB]: 18 | if import_path is None: 19 | import_path = os.environ.get( 20 | 'CHAIN_DB_BACKEND_CLASS', 21 | DEFAULT_DB_BACKEND, 22 | ) 23 | return import_string(import_path) 24 | 25 | 26 | def get_db_backend(import_path: str = None, **init_kwargs: Any) -> BaseAtomicDB: 27 | backend_class = get_db_backend_class(import_path) 28 | return backend_class(**init_kwargs) 29 | -------------------------------------------------------------------------------- /scripts/benchmark/contract_data/DOSContract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | contract DOSContract{ 4 | address[] deployedContracts; 5 | uint64[] liste; 6 | 7 | function createEmptyContract() public{ 8 | address newContract = new EmptyContract(); 9 | deployedContracts.push(newContract); 10 | } 11 | 12 | function storageEntropy() public{ 13 | liste.push(1); 14 | } 15 | 16 | function storageEntropyRevert() public{ 17 | liste.push(1); 18 | revert("Error"); 19 | } 20 | 21 | function createEmptyContractRevert() public{ 22 | address newContract = new EmptyContract(); 23 | deployedContracts.push(newContract); 24 | revert(); 25 | } 26 | } 27 | 28 | contract EmptyContract{ 29 | 30 | } -------------------------------------------------------------------------------- /trinity/README.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | 1. Populate CHANGELOG 4 | 2. Release `py-evm` 5 | 3. Bump py-evm dependency version in `setup_trinity.py` 6 | 4. Manual bump of trinity version in `setup_trinity.py` 7 | 5. Release `trinity` 8 | 6. Tag trinity release 9 | 10 | 11 | ## Environment Configuration 12 | 13 | - `TRINITY_MP_CONTEXT` - The context that new processes will be spawned from the python `multiprocessing` library. 14 | - `XDG_TRINITY_ROOT` - Base directory where trinity stores data 15 | - `TRINITY_DATA_DIR` - The root directory where the chain data will be stored for the currently running chain. 16 | - `TRINITY_NODEKEY` - The path to a file where the devp2p private key is stored. 17 | - `TRINITY_DATABASE_IPC` - The path to the socket which connects to the database manager. 18 | -------------------------------------------------------------------------------- /tests/core/numeric-utils/test_int_to_bytes32.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from eth.constants import ( 4 | NULL_BYTE, 5 | UINT_256_MAX, 6 | ) 7 | 8 | from eth.utils.numeric import ( 9 | int_to_bytes32, 10 | ) 11 | 12 | 13 | @pytest.mark.parametrize( 14 | 'value, expected', 15 | ( 16 | (0, NULL_BYTE * 32), 17 | (1, NULL_BYTE * 31 + b'\x01'), 18 | (UINT_256_MAX, b'\xff' * 32), 19 | ) 20 | ) 21 | def test_int_to_bytes32_valid(value, expected): 22 | assert int_to_bytes32(value) == expected 23 | 24 | 25 | @pytest.mark.parametrize( 26 | 'value', 27 | ( 28 | -1, 29 | UINT_256_MAX + 1, 30 | ) 31 | ) 32 | def test_int_to_bytes32_invalid(value): 33 | with pytest.raises(ValueError): 34 | int_to_bytes32(value) 35 | -------------------------------------------------------------------------------- /trinity/utils/shutdown.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import signal 3 | 4 | from lahja import ( 5 | Endpoint, 6 | ) 7 | 8 | from p2p.service import ( 9 | BaseService, 10 | ) 11 | 12 | 13 | async def exit_on_signal(service_to_exit: BaseService, endpoint: Endpoint = None) -> None: 14 | loop = service_to_exit.get_event_loop() 15 | sigint_received = asyncio.Event() 16 | for sig in [signal.SIGINT, signal.SIGTERM]: 17 | # TODO also support Windows 18 | loop.add_signal_handler(sig, sigint_received.set) 19 | 20 | await sigint_received.wait() 21 | try: 22 | await service_to_exit.cancel() 23 | if endpoint is not None: 24 | endpoint.stop() 25 | service_to_exit._executor.shutdown(wait=True) 26 | finally: 27 | loop.stop() 28 | -------------------------------------------------------------------------------- /eth/db/backends/memory.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Dict 3 | ) 4 | 5 | from .base import ( 6 | BaseDB, 7 | ) 8 | 9 | 10 | class MemoryDB(BaseDB): 11 | kv_store = None # type: Dict[bytes, bytes] 12 | 13 | def __init__(self, kv_store: Dict[bytes, bytes] = None) -> None: 14 | if kv_store is None: 15 | self.kv_store = {} 16 | else: 17 | self.kv_store = kv_store 18 | 19 | def __getitem__(self, key: bytes) -> bytes: 20 | return self.kv_store[key] 21 | 22 | def __setitem__(self, key: bytes, value: bytes) -> None: 23 | self.kv_store[key] = value 24 | 25 | def _exists(self, key: bytes) -> bool: 26 | return key in self.kv_store 27 | 28 | def __delitem__(self, key: bytes) -> None: 29 | del self.kv_store[key] 30 | -------------------------------------------------------------------------------- /eth/utils/bn128.py: -------------------------------------------------------------------------------- 1 | from py_ecc import ( 2 | optimized_bn128 as bn128, 3 | ) 4 | 5 | from eth_utils import ( 6 | ValidationError, 7 | ) 8 | 9 | from typing import Tuple 10 | 11 | 12 | def validate_point(x: int, y: int) -> Tuple[bn128.FQ, bn128.FQ, bn128.FQ]: 13 | FQ = bn128.FQ 14 | 15 | if x >= bn128.field_modulus: 16 | raise ValidationError("Point x value is greater than field modulus") 17 | elif y >= bn128.field_modulus: 18 | raise ValidationError("Point y value is greater than field modulus") 19 | 20 | if (x, y) != (0, 0): 21 | p1 = (FQ(x), FQ(y), FQ(1)) 22 | if not bn128.is_on_curve(p1, bn128.b): 23 | raise ValidationError("Point is not on the curve") 24 | else: 25 | p1 = (FQ(1), FQ(1), FQ(0)) 26 | 27 | return p1 28 | -------------------------------------------------------------------------------- /eth/vm/logic/block.py: -------------------------------------------------------------------------------- 1 | from eth import constants 2 | 3 | 4 | def blockhash(computation): 5 | block_number = computation.stack_pop(type_hint=constants.UINT256) 6 | 7 | block_hash = computation.state.get_ancestor_hash(block_number) 8 | 9 | computation.stack_push(block_hash) 10 | 11 | 12 | def coinbase(computation): 13 | computation.stack_push(computation.state.coinbase) 14 | 15 | 16 | def timestamp(computation): 17 | computation.stack_push(computation.state.timestamp) 18 | 19 | 20 | def number(computation): 21 | computation.stack_push(computation.state.block_number) 22 | 23 | 24 | def difficulty(computation): 25 | computation.stack_push(computation.state.difficulty) 26 | 27 | 28 | def gaslimit(computation): 29 | computation.stack_push(computation.state.gas_limit) 30 | -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | # Block Workflow 2 | 3 | The following workflows are supported for blocks. 4 | 5 | ## 1. Block Building 6 | 7 | Incremental creation 8 | 9 | 1. Initialize Block - `Header.from_parent(...)`: 10 | - `coinbase` 11 | - `parent_hash` 12 | - `difficulty` 13 | - `block_number` 14 | - `gas_limit` 15 | - `timestamp` 16 | 2. Apply Transaction(s) - `Block.apply_transaction(...)`: 17 | 3. Mine Block - `Block.mine(...)`: 18 | - `uncles_hash` 19 | - `state_root` 20 | - `transaction_root` 21 | - `receipts_root` 22 | - `bloom` 23 | - `gas_used` 24 | - `extra_data` 25 | - `mix_hash` 26 | - `nonce` 27 | 28 | 29 | ## 2. Block Ingestion 30 | 31 | > (This is actually just a special case of use case #1.) 32 | 33 | Full ingestion of a complete block. 34 | -------------------------------------------------------------------------------- /trinity/rpc/modules/net.py: -------------------------------------------------------------------------------- 1 | from p2p.events import ( 2 | PeerCountRequest 3 | ) 4 | from trinity.rpc.modules import ( 5 | RPCModule, 6 | ) 7 | 8 | 9 | class Net(RPCModule): 10 | async def version(self) -> str: 11 | """ 12 | Returns the current network ID. 13 | """ 14 | return str(self._chain.network_id) 15 | 16 | async def peerCount(self) -> str: 17 | """ 18 | Return the number of peers that are currently connected to the node 19 | """ 20 | response = await self._event_bus.request(PeerCountRequest()) 21 | return hex(response.peer_count) 22 | 23 | async def listening(self) -> bool: 24 | """ 25 | Return `True` if the client is actively listening for network connections 26 | """ 27 | return True 28 | -------------------------------------------------------------------------------- /trinity/utils/async_iter.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | AsyncIterable, 3 | Set, 4 | ) 5 | 6 | 7 | async def contains_all(async_gen: AsyncIterable[str], keywords: Set[str]) -> bool: 8 | """ 9 | Check wether an ``AsyncIterable[str]`` contains all of the given keywords. The keywords 10 | can be embedded in some larger string. Return ``True`` as soon as all keywords were matched. 11 | If not all keywords were matched by the time that the async iterable is done, return ``False``. 12 | """ 13 | seen_keywords: Set[str] = set() 14 | async for line in async_gen: 15 | for check in keywords - seen_keywords: 16 | if check in line: 17 | seen_keywords.add(check) 18 | if seen_keywords == keywords: 19 | return True 20 | 21 | return False 22 | -------------------------------------------------------------------------------- /stubs/eth_keys/backends/native/ecdsa.pyi: -------------------------------------------------------------------------------- 1 | from .jacobian import fast_add, fast_multiply, from_jacobian, inv, jacobian_add, jacobian_multiply 2 | from typing import Any, Callable, Optional, Tuple 3 | 4 | def decode_public_key(public_key_bytes): ... 5 | def encode_raw_public_key(raw_public_key: Tuple[int, int]) -> bytes: ... 6 | def private_key_to_public_key(private_key_bytes: bytes) -> bytes: ... 7 | def deterministic_generate_k(msg_hash: bytes, private_key_bytes: bytes, digest_fn: Callable[, Any]=...) -> int: ... 8 | def ecdsa_raw_sign(msg_hash: bytes, private_key_bytes: bytes) -> Tuple[int, int, int]: ... 9 | def ecdsa_raw_verify(msg_hash: bytes, vrs: Tuple[int, int, int], public_key_bytes: bytes) -> Optional[bool]: ... 10 | def ecdsa_raw_recover(msg_hash: bytes, vrs: Tuple[int, int, int]) -> Optional[bytes]: ... 11 | -------------------------------------------------------------------------------- /trinity/__init__.py: -------------------------------------------------------------------------------- 1 | import pkg_resources 2 | import sys 3 | 4 | # TODO: update this to use the `trinity` version once extracted from py-evm 5 | __version__: str 6 | try: 7 | __version__ = pkg_resources.get_distribution("trinity").version 8 | except pkg_resources.DistributionNotFound: 9 | __version__ = "eth-{0}".format( 10 | pkg_resources.get_distribution("py-evm").version, 11 | ) 12 | 13 | # This is to ensure we call setup_trace_logging() before anything else. 14 | import eth as _eth_module # noqa: F401 15 | 16 | if sys.platform in {'darwin', 'linux'}: 17 | # Set `uvloop` as the default event loop 18 | import asyncio # noqa: E402 19 | import uvloop # noqa: E402 20 | asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) 21 | 22 | from .main import ( # noqa: F401 23 | main, 24 | ) 25 | -------------------------------------------------------------------------------- /trinity/protocol/eth/handlers.py: -------------------------------------------------------------------------------- 1 | from trinity.protocol.common.handlers import ( 2 | BaseExchangeHandler, 3 | ) 4 | 5 | from .exchanges import ( 6 | GetBlockBodiesExchange, 7 | GetBlockHeadersExchange, 8 | GetNodeDataExchange, 9 | GetReceiptsExchange, 10 | ) 11 | 12 | 13 | class ETHExchangeHandler(BaseExchangeHandler): 14 | _exchange_config = { 15 | 'get_block_bodies': GetBlockBodiesExchange, 16 | 'get_block_headers': GetBlockHeadersExchange, 17 | 'get_node_data': GetNodeDataExchange, 18 | 'get_receipts': GetReceiptsExchange, 19 | } 20 | 21 | # These are needed only to please mypy. 22 | get_block_bodies: GetBlockBodiesExchange 23 | get_block_headers: GetBlockHeadersExchange 24 | get_node_data: GetNodeDataExchange 25 | get_receipts: GetReceiptsExchange 26 | -------------------------------------------------------------------------------- /eth/vm/forks/constantinople/computation.py: -------------------------------------------------------------------------------- 1 | from cytoolz import ( 2 | merge, 3 | ) 4 | 5 | from eth.vm.forks.byzantium.computation import ( 6 | BYZANTIUM_PRECOMPILES 7 | ) 8 | from eth.vm.forks.byzantium.computation import ( 9 | ByzantiumComputation 10 | ) 11 | 12 | from .opcodes import CONSTANTINOPLE_OPCODES 13 | 14 | CONSTANTINOPLE_PRECOMPILES = merge( 15 | BYZANTIUM_PRECOMPILES, 16 | { 17 | # TODO: add new precompiles 18 | }, 19 | ) 20 | 21 | 22 | class ConstantinopleComputation(ByzantiumComputation): 23 | """ 24 | A class for all execution computations in the ``Constantinople`` fork. 25 | Inherits from :class:`~eth.vm.forks.byzantium.computation.ByzantiumComputation` 26 | """ 27 | # Override 28 | opcodes = CONSTANTINOPLE_OPCODES 29 | _precompiles = CONSTANTINOPLE_PRECOMPILES 30 | -------------------------------------------------------------------------------- /eth/tools/_utils/vyper.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | try: 4 | from vyper.compile_lll import ( 5 | compile_to_assembly, 6 | assembly_to_evm, 7 | ) 8 | from vyper.parser.parser_utils import LLLnode 9 | except ImportError: 10 | vyper_available = False 11 | else: 12 | vyper_available = True 13 | 14 | 15 | def require_vyper(fn): 16 | @functools.wraps(fn) 17 | def inner(*args, **kwargs): 18 | if vyper_available: 19 | return fn(*args, **kwargs) 20 | else: 21 | raise ImportError("The `{0}` function requires the vyper compiler.") 22 | return inner 23 | 24 | 25 | @require_vyper 26 | def compile_vyper_lll(vyper_code): 27 | lll_node = LLLnode.from_list(vyper_code) 28 | assembly = compile_to_assembly(lll_node) 29 | code = assembly_to_evm(assembly) 30 | return code 31 | -------------------------------------------------------------------------------- /eth/tools/fixtures/_utils.py: -------------------------------------------------------------------------------- 1 | import fnmatch 2 | import functools 3 | import os 4 | 5 | from eth_utils import to_tuple 6 | 7 | 8 | @to_tuple 9 | def recursive_find_files(base_dir, pattern): 10 | for dirpath, _, filenames in os.walk(base_dir): 11 | for filename in filenames: 12 | if fnmatch.fnmatch(filename, pattern): 13 | yield os.path.join(dirpath, filename) 14 | 15 | 16 | def require_pytest(fn): 17 | @functools.wraps(fn) 18 | def inner(*args, **kwargs): 19 | try: 20 | import pytest # noqa: F401 21 | except ImportError: 22 | raise ImportError( 23 | 'pytest is required to use the fixture_tests. Please ensure ' 24 | 'it is installed.' 25 | ) 26 | else: 27 | return fn(*args, **kwargs) 28 | return inner 29 | -------------------------------------------------------------------------------- /eth/utils/address.py: -------------------------------------------------------------------------------- 1 | import rlp 2 | 3 | from eth_hash.auto import keccak 4 | from eth_typing import Address 5 | 6 | from eth.utils.numeric import ( 7 | int_to_big_endian, 8 | ) 9 | 10 | 11 | def force_bytes_to_address(value: bytes) -> Address: 12 | trimmed_value = value[-20:] 13 | padded_value = trimmed_value.rjust(20, b'\x00') 14 | return Address(padded_value) 15 | 16 | 17 | def generate_contract_address(address: Address, nonce: bytes) -> Address: 18 | return force_bytes_to_address(keccak(rlp.encode([address, nonce]))) 19 | 20 | 21 | def generate_safe_contract_address(address: Address, 22 | salt: int, 23 | call_data: bytes) -> Address: 24 | return force_bytes_to_address( 25 | keccak(b'\xff' + address + int_to_big_endian(salt) + keccak(call_data)) 26 | ) 27 | -------------------------------------------------------------------------------- /scripts/benchmark/utils/address.py: -------------------------------------------------------------------------------- 1 | import random 2 | from typing import ( 3 | Tuple 4 | ) 5 | 6 | from eth.utils.padding import ( 7 | pad32, 8 | ) 9 | 10 | from eth_keys import ( 11 | keys 12 | ) 13 | from eth_keys.datatypes import ( 14 | PrivateKey, 15 | PublicKey 16 | ) 17 | 18 | from eth_utils import ( 19 | int_to_big_endian, 20 | ) 21 | 22 | from eth_typing import ( 23 | Address 24 | ) 25 | 26 | 27 | def generate_random_keypair_and_address() -> Tuple[PrivateKey, PublicKey, Address]: 28 | priv_key = keys.PrivateKey(pad32(int_to_big_endian(random.getrandbits(8 * 32)))) 29 | return priv_key, priv_key.public_key, Address(priv_key.public_key.to_canonical_address()) 30 | 31 | 32 | def generate_random_address() -> Address: 33 | private_key, public_key, address = generate_random_keypair_and_address() 34 | return address 35 | -------------------------------------------------------------------------------- /tests/trinity/core/filesystem-utils/test_is_under_path.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from trinity.utils.filesystem import ( 4 | is_under_path, 5 | ) 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'base_path,path,expected', 10 | ( 11 | # Same Path 12 | ('foo', 'foo', False), 13 | ('foo', 'foo/bar/..', False), 14 | # up a directory (or two) 15 | ('foo', '..', False), 16 | ('foo', 'foo/bar/../../', False), 17 | # relative and abs 18 | ('foo', '/foo/bar', False), 19 | ('foo', '/foo', False), 20 | # actually nested 21 | ('foo', 'foo/bar.sol', True), 22 | ('foo', 'foo/bar', True), 23 | ('foo', 'foo/bar/../../foo/baz', True), 24 | ), 25 | ) 26 | def test_is_under_path(base_path, path, expected): 27 | actual = is_under_path(base_path, path) 28 | assert actual is expected 29 | -------------------------------------------------------------------------------- /eth/rlp/accounts.py: -------------------------------------------------------------------------------- 1 | import rlp 2 | from rlp.sedes import ( 3 | big_endian_int, 4 | ) 5 | 6 | from eth.constants import ( 7 | EMPTY_SHA3, 8 | BLANK_ROOT_HASH, 9 | ) 10 | 11 | from .sedes import ( 12 | trie_root, 13 | hash32, 14 | ) 15 | 16 | from typing import Any 17 | 18 | 19 | class Account(rlp.Serializable): 20 | """ 21 | RLP object for accounts. 22 | """ 23 | fields = [ 24 | ('nonce', big_endian_int), 25 | ('balance', big_endian_int), 26 | ('storage_root', trie_root), 27 | ('code_hash', hash32) 28 | ] 29 | 30 | def __init__(self, 31 | nonce: int=0, 32 | balance: int=0, 33 | storage_root: bytes=BLANK_ROOT_HASH, 34 | code_hash: bytes=EMPTY_SHA3, 35 | **kwargs: Any) -> None: 36 | super().__init__(nonce, balance, storage_root, code_hash, **kwargs) 37 | -------------------------------------------------------------------------------- /tests/trinity/core/cli/test_trinity_repl.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from trinity.plugins.builtin.attach.console import console 4 | from pathlib import Path 5 | from trinity.utils.log_messages import ( 6 | create_missing_ipc_error_message, 7 | ) 8 | 9 | 10 | def test_console(caplog, jsonrpc_ipc_pipe_path): 11 | # if ipc_path is not found, raise an exception with a useful message 12 | with pytest.raises(FileNotFoundError): 13 | console(Path(jsonrpc_ipc_pipe_path)) 14 | assert create_missing_ipc_error_message(jsonrpc_ipc_pipe_path) in caplog.text 15 | 16 | 17 | def test_python_console(caplog, jsonrpc_ipc_pipe_path): 18 | # if ipc_path is not found, raise an exception with a useful message 19 | with pytest.raises(FileNotFoundError): 20 | console(Path(jsonrpc_ipc_pipe_path), use_ipython=False) 21 | assert create_missing_ipc_error_message(jsonrpc_ipc_pipe_path) in caplog.text 22 | -------------------------------------------------------------------------------- /tests/core/env-utils/test_get.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from eth.utils.env import ( 4 | get, 5 | ) 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'type,expected', 10 | ( 11 | ('int', 42), 12 | (int, 42), 13 | 14 | ('bool', False), 15 | (bool, True), 16 | 17 | ('string', 'ozymandias'), 18 | (str, 'hannibal'), 19 | 20 | ('float', 42.0), 21 | (float, 42.0), 22 | ) 23 | ) 24 | def test_get_mapping(type, expected): 25 | actual = get('ENV_VARIABLE', default=expected, type=type) 26 | assert actual == expected 27 | 28 | 29 | @pytest.mark.parametrize( 30 | 'type,default,expected', 31 | ( 32 | ('list', '1,2,3', ['1', '2', '3']), 33 | (list, '3,2,1', ['3', '2', '1']), 34 | ) 35 | ) 36 | def test_get_mapping_for_lists(type, default, expected): 37 | actual = get('ENV_VARIABLE', default=default, type=type) 38 | assert actual == expected 39 | -------------------------------------------------------------------------------- /tests/core/consensus/test_pow_mining.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from eth.chains.base import MiningChain 4 | from eth.chains.mainnet import MAINNET_VMS 5 | from eth.consensus.pow import check_pow 6 | from eth.tools.mining import POWMiningMixin 7 | from eth.tools.builder.chain import ( 8 | genesis, 9 | ) 10 | 11 | 12 | @pytest.mark.parametrize( 13 | 'base_vm_class', 14 | MAINNET_VMS, 15 | ) 16 | def test_mining_tools_proof_of_work_mining(base_vm_class): 17 | vm_class = type(base_vm_class.__name__, (POWMiningMixin, base_vm_class), {}) 18 | 19 | class ChainClass(MiningChain): 20 | vm_configuration = ( 21 | (0, vm_class), 22 | ) 23 | 24 | chain = genesis(ChainClass) 25 | 26 | block = chain.mine_block() 27 | check_pow( 28 | block.number, 29 | block.header.mining_hash, 30 | block.header.mix_hash, 31 | block.header.nonce, 32 | block.header.difficulty, 33 | ) 34 | -------------------------------------------------------------------------------- /tests/trinity/core/chain-management/test_initialize_database.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | # TODO: use a custom chain class only for testing. 4 | from eth.db.backends.level import LevelDB 5 | from eth.db.chain import ChainDB 6 | 7 | from trinity.chains import ( 8 | initialize_data_dir, 9 | initialize_database, 10 | is_database_initialized, 11 | ) 12 | from trinity.config import ( 13 | ChainConfig, 14 | ) 15 | 16 | 17 | @pytest.fixture 18 | def chain_config(): 19 | _chain_config = ChainConfig(network_id=1, max_peers=1) 20 | initialize_data_dir(_chain_config) 21 | return _chain_config 22 | 23 | 24 | @pytest.fixture 25 | def chaindb(chain_config): 26 | return ChainDB(LevelDB(db_path=chain_config.database_dir)) 27 | 28 | 29 | def test_initialize_database(chain_config, chaindb): 30 | assert not is_database_initialized(chaindb) 31 | initialize_database(chain_config, chaindb) 32 | assert is_database_initialized(chaindb) 33 | -------------------------------------------------------------------------------- /eth/db/cache.py: -------------------------------------------------------------------------------- 1 | from lru import LRU 2 | 3 | from eth.db.backends.base import BaseDB 4 | 5 | 6 | class CacheDB(BaseDB): 7 | """ 8 | Set and get decoded RLP objects, where the underlying db stores 9 | encoded objects. 10 | """ 11 | def __init__(self, db, cache_size=2048): 12 | self._db = db 13 | self._cache_size = cache_size 14 | self.reset_cache() 15 | 16 | def reset_cache(self): 17 | self._cached_values = LRU(self._cache_size) 18 | 19 | def __getitem__(self, key): 20 | if key not in self._cached_values: 21 | self._cached_values[key] = self._db[key] 22 | return self._cached_values[key] 23 | 24 | def __setitem__(self, key, value): 25 | self._cached_values[key] = value 26 | self._db[key] = value 27 | 28 | def __delitem__(self, key): 29 | if key in self._cached_values: 30 | del self._cached_values[key] 31 | del self._db[key] 32 | -------------------------------------------------------------------------------- /trinity/utils/profiling.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import cProfile 3 | import functools 4 | from typing import ( 5 | Any, 6 | Callable, 7 | Iterator, 8 | ) 9 | 10 | 11 | @contextlib.contextmanager 12 | def profiler(filename: str) -> Iterator[None]: 13 | pr = cProfile.Profile() 14 | pr.enable() 15 | try: 16 | yield 17 | finally: 18 | pr.disable() 19 | pr.dump_stats(filename) 20 | 21 | 22 | def setup_cprofiler(filename: str) -> Callable[..., Any]: 23 | def outer(fn: Callable[..., Any]) -> Callable[..., Any]: 24 | @functools.wraps(fn) 25 | def inner(*args: Any, **kwargs: Any) -> None: 26 | should_profile = kwargs.pop('profile', False) 27 | if should_profile: 28 | with profiler(filename): 29 | return fn(*args, **kwargs) 30 | else: 31 | return fn(*args, **kwargs) 32 | return inner 33 | return outer 34 | -------------------------------------------------------------------------------- /stubs/eth_keys/main.pyi: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Any, 3 | Optional, 4 | Type, 5 | Union 6 | ) 7 | 8 | from .datatypes import ( 9 | LazyBackend, 10 | ) 11 | 12 | import datatypes 13 | 14 | 15 | class KeyAPI(LazyBackend): 16 | PublicKey: Type[datatypes.PublicKey] = ... 17 | PrivateKey: Type[datatypes.PrivateKey] = ... 18 | Signature: Type[datatypes.Signature] = ... 19 | def ecdsa_sign(self, message_hash: bytes, private_key: Union[datatypes.PrivateKey, bytes]) -> Optional[datatypes.Signature]: ... 20 | def ecdsa_verify(self, message_hash: bytes, signature: Union[datatypes.Signature, bytes], public_key: Union[datatypes.PublicKey, bytes]) -> Optional[bool]: ... 21 | def ecdsa_recover(self, message_hash: bytes, signature: Union[datatypes.Signature, bytes]) -> Optional[datatypes.PublicKey]: ... 22 | def private_key_to_public_key(self, private_key: datatypes.PrivateKey) -> datatypes.PublicKey: ... 23 | 24 | lazy_key_api: KeyAPI 25 | -------------------------------------------------------------------------------- /scripts/benchmark/utils/tx.py: -------------------------------------------------------------------------------- 1 | from eth_typing import ( 2 | Address 3 | ) 4 | 5 | from eth.rlp.transactions import ( 6 | BaseTransaction 7 | ) 8 | from eth.vm.base import ( 9 | VM 10 | ) 11 | 12 | from eth_keys.datatypes import ( 13 | PrivateKey 14 | ) 15 | 16 | 17 | def new_transaction( 18 | vm: VM, 19 | from_: Address, 20 | to: Address, 21 | amount: int=0, 22 | private_key: PrivateKey=None, 23 | gas_price: int=10, 24 | gas: int=100000, 25 | data: bytes=b'') -> BaseTransaction: 26 | """ 27 | Create and return a transaction sending amount from to . 28 | 29 | The transaction will be signed with the given private key. 30 | """ 31 | nonce = vm.state.account_db.get_nonce(from_) 32 | tx = vm.create_unsigned_transaction( 33 | nonce=nonce, gas_price=gas_price, gas=gas, to=to, value=amount, data=data) 34 | 35 | return tx.as_signed_transaction(private_key) 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | var 14 | sdist 15 | develop-eggs 16 | .installed.cfg 17 | lib 18 | lib64 19 | 20 | # Installer logs 21 | pip-log.txt 22 | 23 | # Unit test / coverage reports 24 | .coverage 25 | .tox 26 | nosetests.xml 27 | 28 | # Translations 29 | *.mo 30 | 31 | # Mr Developer 32 | .mr.developer.cfg 33 | .project 34 | .pydevproject 35 | 36 | # Complexity 37 | output/*.html 38 | output/*/index.html 39 | 40 | # Sphinx 41 | docs/_build 42 | docs/modules.rst 43 | 44 | # pytest 45 | .cache/ 46 | .pytest_cache/ 47 | 48 | # fixtures 49 | ./fixtures/** 50 | 51 | # profiling 52 | prof/** 53 | 54 | # hypothesis 55 | .hypothesis/ 56 | 57 | # mypy 58 | .mypy_cache/ 59 | *.swp 60 | docs/evm.*rst 61 | venv* 62 | .eggs/ 63 | 64 | # vscode 65 | .vscode/** 66 | 67 | # monkeytype 68 | monkeytype.sqlite3 69 | 70 | # pyenv 71 | .python-version 72 | 73 | # idea 74 | .idea/** 75 | -------------------------------------------------------------------------------- /eth/vm/logic/duplication.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | 4 | def dup_XX(computation, position): 5 | """ 6 | Stack item duplication. 7 | """ 8 | computation.stack_dup(position) 9 | 10 | 11 | dup1 = functools.partial(dup_XX, position=1) 12 | dup2 = functools.partial(dup_XX, position=2) 13 | dup3 = functools.partial(dup_XX, position=3) 14 | dup4 = functools.partial(dup_XX, position=4) 15 | dup5 = functools.partial(dup_XX, position=5) 16 | dup6 = functools.partial(dup_XX, position=6) 17 | dup7 = functools.partial(dup_XX, position=7) 18 | dup8 = functools.partial(dup_XX, position=8) 19 | dup9 = functools.partial(dup_XX, position=9) 20 | dup10 = functools.partial(dup_XX, position=10) 21 | dup11 = functools.partial(dup_XX, position=11) 22 | dup12 = functools.partial(dup_XX, position=12) 23 | dup13 = functools.partial(dup_XX, position=13) 24 | dup14 = functools.partial(dup_XX, position=14) 25 | dup15 = functools.partial(dup_XX, position=15) 26 | dup16 = functools.partial(dup_XX, position=16) 27 | -------------------------------------------------------------------------------- /eth/vm/transaction_context.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | 3 | from eth.validation import ( 4 | validate_canonical_address, 5 | validate_uint256, 6 | ) 7 | 8 | 9 | class BaseTransactionContext: 10 | """ 11 | This immutable object houses information that remains constant for the entire context of the VM 12 | execution. 13 | """ 14 | __slots__ = ['_gas_price', '_origin', '_log_counter'] 15 | 16 | def __init__(self, gas_price, origin): 17 | validate_uint256(gas_price, title="TransactionContext.gas_price") 18 | self._gas_price = gas_price 19 | validate_canonical_address(origin, title="TransactionContext.origin") 20 | self._origin = origin 21 | self._log_counter = itertools.count() 22 | 23 | def get_next_log_counter(self): 24 | return next(self._log_counter) 25 | 26 | @property 27 | def gas_price(self): 28 | return self._gas_price 29 | 30 | @property 31 | def origin(self): 32 | return self._origin 33 | -------------------------------------------------------------------------------- /eth/vm/logic/swap.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | 4 | def swap_XX(computation, position): 5 | """ 6 | Stack item swapping 7 | """ 8 | computation.stack_swap(position) 9 | 10 | 11 | swap1 = functools.partial(swap_XX, position=1) 12 | swap2 = functools.partial(swap_XX, position=2) 13 | swap3 = functools.partial(swap_XX, position=3) 14 | swap4 = functools.partial(swap_XX, position=4) 15 | swap5 = functools.partial(swap_XX, position=5) 16 | swap6 = functools.partial(swap_XX, position=6) 17 | swap7 = functools.partial(swap_XX, position=7) 18 | swap8 = functools.partial(swap_XX, position=8) 19 | swap9 = functools.partial(swap_XX, position=9) 20 | swap10 = functools.partial(swap_XX, position=10) 21 | swap11 = functools.partial(swap_XX, position=11) 22 | swap12 = functools.partial(swap_XX, position=12) 23 | swap13 = functools.partial(swap_XX, position=13) 24 | swap14 = functools.partial(swap_XX, position=14) 25 | swap15 = functools.partial(swap_XX, position=15) 26 | swap16 = functools.partial(swap_XX, position=16) 27 | -------------------------------------------------------------------------------- /tests/p2p/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | """ 5 | # Uncomment the following lines to globally change the logging level for all 6 | # `p2p` namespaced loggers. Useful for debugging failing tests in async code 7 | # when the only output you get is a timeout or something else which doens't 8 | # indicate where things failed. 9 | import pytest 10 | 11 | @pytest.fixture(autouse=True, scope="session") 12 | def p2p_logger(): 13 | import logging 14 | import sys 15 | 16 | logger = logging.getLogger('p2p') 17 | 18 | handler = logging.StreamHandler(sys.stdout) 19 | 20 | # level = TRACE_LEVEL_NUM 21 | level = logging.DEBUG 22 | level = logging.INFO 23 | 24 | logger.setLevel(level) 25 | handler.setLevel(level) 26 | 27 | logger.addHandler(handler) 28 | 29 | return logger 30 | """ 31 | 32 | 33 | @pytest.fixture(autouse=True) 34 | def _network_sim(router): 35 | network = router.get_network(name='simulated') 36 | with network.patch_asyncio(): 37 | yield network 38 | -------------------------------------------------------------------------------- /trinity/utils/mp.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import functools 3 | import multiprocessing 4 | import os 5 | from typing import ( 6 | Any, 7 | Awaitable, 8 | Callable 9 | ) 10 | 11 | 12 | MP_CONTEXT = os.environ.get('TRINITY_MP_CONTEXT', 'spawn') 13 | 14 | 15 | # sets the type of process that multiprocessing will create. 16 | ctx = multiprocessing.get_context(MP_CONTEXT) 17 | 18 | 19 | def async_method(method_name: str) -> Callable[..., Any]: 20 | async def method(self: Any, *args: Any, **kwargs: Any) -> Awaitable[Any]: 21 | loop = asyncio.get_event_loop() 22 | 23 | return await loop.run_in_executor( 24 | None, 25 | functools.partial(self._callmethod, kwds=kwargs), 26 | method_name, 27 | args, 28 | ) 29 | return method 30 | 31 | 32 | def sync_method(method_name: str) -> Callable[..., Any]: 33 | def method(self: Any, *args: Any, **kwargs: Any) -> Any: 34 | return self._callmethod(method_name, args, kwargs) 35 | return method 36 | -------------------------------------------------------------------------------- /tests/core/vm/test_vm_state.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from eth.db.backends.memory import MemoryDB 4 | from eth.exceptions import StateRootNotFound 5 | from eth.vm.forks.frontier.state import FrontierState 6 | 7 | 8 | @pytest.fixture 9 | def state(chain_without_block_validation): 10 | return chain_without_block_validation.get_vm().state 11 | 12 | 13 | def test_block_properties(chain_without_block_validation): 14 | chain = chain_without_block_validation 15 | vm = chain.get_vm() 16 | block, _, _ = chain.import_block(vm.mine_block()) 17 | 18 | assert vm.state.coinbase == block.header.coinbase 19 | assert vm.state.timestamp == block.header.timestamp 20 | assert vm.state.block_number == block.header.block_number 21 | assert vm.state.difficulty == block.header.difficulty 22 | assert vm.state.gas_limit == block.header.gas_limit 23 | 24 | 25 | def test_missing_state_root(): 26 | context = None 27 | state = FrontierState(MemoryDB(), context, b'\x0f' * 32) 28 | with pytest.raises(StateRootNotFound): 29 | state.apply_transaction(None) 30 | -------------------------------------------------------------------------------- /eth/vm/forks/byzantium/transactions.py: -------------------------------------------------------------------------------- 1 | from eth.vm.forks.spurious_dragon.transactions import ( 2 | SpuriousDragonTransaction, 3 | SpuriousDragonUnsignedTransaction, 4 | ) 5 | 6 | from eth.utils.transactions import ( 7 | create_transaction_signature, 8 | ) 9 | 10 | 11 | class ByzantiumTransaction(SpuriousDragonTransaction): 12 | @classmethod 13 | def create_unsigned_transaction(cls, nonce, gas_price, gas, to, value, data): 14 | return ByzantiumUnsignedTransaction(nonce, gas_price, gas, to, value, data) 15 | 16 | 17 | class ByzantiumUnsignedTransaction(SpuriousDragonUnsignedTransaction): 18 | def as_signed_transaction(self, private_key, chain_id=None): 19 | v, r, s = create_transaction_signature(self, private_key, chain_id=chain_id) 20 | return ByzantiumTransaction( 21 | nonce=self.nonce, 22 | gas_price=self.gas_price, 23 | gas=self.gas, 24 | to=self.to, 25 | value=self.value, 26 | data=self.data, 27 | v=v, 28 | r=r, 29 | s=s, 30 | ) 31 | -------------------------------------------------------------------------------- /eth/vm/forks/constantinople/transactions.py: -------------------------------------------------------------------------------- 1 | from eth.vm.forks.byzantium.transactions import ( 2 | ByzantiumTransaction, 3 | ByzantiumUnsignedTransaction, 4 | ) 5 | 6 | from eth.utils.transactions import ( 7 | create_transaction_signature, 8 | ) 9 | 10 | 11 | class ConstantinopleTransaction(ByzantiumTransaction): 12 | @classmethod 13 | def create_unsigned_transaction(cls, nonce, gas_price, gas, to, value, data): 14 | return ConstantinopleUnsignedTransaction(nonce, gas_price, gas, to, value, data) 15 | 16 | 17 | class ConstantinopleUnsignedTransaction(ByzantiumUnsignedTransaction): 18 | def as_signed_transaction(self, private_key, chain_id=None): 19 | v, r, s = create_transaction_signature(self, private_key, chain_id=chain_id) 20 | return ConstantinopleTransaction( 21 | nonce=self.nonce, 22 | gas_price=self.gas_price, 23 | gas=self.gas, 24 | to=self.to, 25 | value=self.value, 26 | data=self.data, 27 | v=v, 28 | r=r, 29 | s=s, 30 | ) 31 | -------------------------------------------------------------------------------- /eth/vm/forks/byzantium/computation.py: -------------------------------------------------------------------------------- 1 | from cytoolz import ( 2 | merge, 3 | ) 4 | 5 | from eth import precompiles 6 | from eth.utils.address import ( 7 | force_bytes_to_address, 8 | ) 9 | from eth.vm.forks.frontier.computation import FRONTIER_PRECOMPILES 10 | from eth.vm.forks.spurious_dragon.computation import SpuriousDragonComputation 11 | 12 | from .opcodes import BYZANTIUM_OPCODES 13 | 14 | BYZANTIUM_PRECOMPILES = merge( 15 | FRONTIER_PRECOMPILES, 16 | { 17 | force_bytes_to_address(b'\x05'): precompiles.modexp, 18 | force_bytes_to_address(b'\x06'): precompiles.ecadd, 19 | force_bytes_to_address(b'\x07'): precompiles.ecmul, 20 | force_bytes_to_address(b'\x08'): precompiles.ecpairing, 21 | }, 22 | ) 23 | 24 | 25 | class ByzantiumComputation(SpuriousDragonComputation): 26 | """ 27 | A class for all execution computations in the ``Byzantium`` fork. 28 | Inherits from :class:`~eth.vm.forks.spurious_dragon.computation.SpuriousDragonComputation` 29 | """ 30 | # Override 31 | opcodes = BYZANTIUM_OPCODES 32 | _precompiles = BYZANTIUM_PRECOMPILES 33 | -------------------------------------------------------------------------------- /trinity/utils/db.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | 4 | class MemoryDB: 5 | kv_store: Dict[bytes, bytes] = None 6 | 7 | def __init__(self, kv_store: Dict[bytes, bytes]=None) -> None: 8 | if kv_store is None: 9 | self.kv_store = {} 10 | else: 11 | self.kv_store = kv_store 12 | 13 | def get(self, key: bytes) -> bytes: 14 | return self.kv_store[key] 15 | 16 | def set(self, key: bytes, value: bytes) -> None: 17 | self.kv_store[key] = value 18 | 19 | def exists(self, key: bytes) -> bool: 20 | return key in self.kv_store 21 | 22 | def delete(self, key: bytes) -> None: 23 | del self.kv_store[key] 24 | 25 | # 26 | # Dictionary API 27 | # 28 | def __getitem__(self, key: bytes) -> bytes: 29 | return self.get(key) 30 | 31 | def __setitem__(self, key: bytes, value: bytes) -> None: 32 | return self.set(key, value) 33 | 34 | def __delitem__(self, key: bytes) -> None: 35 | return self.delete(key) 36 | 37 | def __contains__(self, key: bytes) -> bool: 38 | return self.exists(key) 39 | -------------------------------------------------------------------------------- /eth/utils/db.py: -------------------------------------------------------------------------------- 1 | from eth.rlp.headers import BlockHeader 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | if TYPE_CHECKING: 6 | from eth.db.chain import BaseChainDB # noqa: F401 7 | 8 | 9 | def get_parent_header(block_header: BlockHeader, db: 'BaseChainDB') -> BlockHeader: 10 | """ 11 | Returns the header for the parent block. 12 | """ 13 | return db.get_block_header_by_hash(block_header.parent_hash) 14 | 15 | 16 | def get_block_header_by_hash(block_hash: BlockHeader, db: 'BaseChainDB') -> BlockHeader: 17 | """ 18 | Returns the header for the parent block. 19 | """ 20 | return db.get_block_header_by_hash(block_hash) 21 | 22 | 23 | def apply_state_dict(account_db, state_dict): 24 | for account, account_data in state_dict.items(): 25 | account_db.set_balance(account, account_data["balance"]) 26 | account_db.set_nonce(account, account_data["nonce"]) 27 | account_db.set_code(account, account_data["code"]) 28 | 29 | for slot, value in account_data["storage"].items(): 30 | account_db.set_storage(account, slot, value) 31 | 32 | return account_db 33 | -------------------------------------------------------------------------------- /tests/trinity/core/chain-management/test_is_database_initialized.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | # TODO: use a custom chain class only for testing. 4 | from eth.chains.ropsten import ROPSTEN_GENESIS_HEADER 5 | from eth.db.backends.level import LevelDB 6 | from eth.db.chain import ChainDB 7 | 8 | from trinity.chains import ( 9 | initialize_data_dir, 10 | is_database_initialized, 11 | ) 12 | from trinity.config import ( 13 | ChainConfig, 14 | ) 15 | 16 | 17 | @pytest.fixture 18 | def chain_config(): 19 | _chain_config = ChainConfig(network_id=1, max_peers=1) 20 | initialize_data_dir(_chain_config) 21 | return _chain_config 22 | 23 | 24 | @pytest.fixture 25 | def chaindb(chain_config): 26 | return ChainDB(LevelDB(db_path=chain_config.database_dir)) 27 | 28 | 29 | def test_database_dir_not_initialized_without_canonical_head_block(chaindb): 30 | assert not is_database_initialized(chaindb) 31 | 32 | 33 | def test_fully_initialized_database_dir(chaindb): 34 | assert not is_database_initialized(chaindb) 35 | chaindb.persist_header(ROPSTEN_GENESIS_HEADER) 36 | assert is_database_initialized(chaindb) 37 | -------------------------------------------------------------------------------- /trinity/protocol/common/normalizers.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod, ABC 2 | from typing import ( 3 | Generic, 4 | TypeVar, 5 | ) 6 | 7 | from p2p.protocol import PayloadType 8 | 9 | from .types import ( 10 | TResponsePayload, 11 | TResult, 12 | ) 13 | 14 | 15 | class BaseNormalizer(ABC, Generic[TResponsePayload, TResult]): 16 | is_normalization_slow = False 17 | """ 18 | This variable indicates how slow normalization is. If normalization requires 19 | any non-trivial computation, consider it slow. Then, the Manager will run it in 20 | a different process. 21 | """ 22 | 23 | @staticmethod 24 | @abstractmethod 25 | def normalize_result(message: TResponsePayload) -> TResult: 26 | """ 27 | Convert underlying peer message to final result 28 | """ 29 | raise NotImplementedError() 30 | 31 | 32 | TPassthrough = TypeVar('TPassthrough', bound=PayloadType) 33 | 34 | 35 | class NoopNormalizer(BaseNormalizer[TPassthrough, TPassthrough]): 36 | @staticmethod 37 | def normalize_result(message: TPassthrough) -> TPassthrough: 38 | return message 39 | -------------------------------------------------------------------------------- /trinity/utils/headers.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Tuple, 3 | ) 4 | 5 | from eth.constants import UINT_256_MAX 6 | 7 | from trinity.constants import MAXIMUM_OBJECT_MEMORY_BYTES 8 | from trinity.exceptions import OversizeObject 9 | 10 | 11 | def sequence_builder(start_number: int, 12 | max_length: int, 13 | skip: int, 14 | reverse: bool) -> Tuple[int, ...]: 15 | # Limit the in-memory size of this sequence. 16 | # A tuple of 64-bit ints is about 8 bytes per value 17 | # Ignore the cutoffs at 0 and UINT_256_MAX, because this is just a gut check anyway, 18 | # we should never be approaching this value. 19 | if max_length > MAXIMUM_OBJECT_MEMORY_BYTES // 8: 20 | raise OversizeObject("Sequence is too big to fit in memory: {}".format(max_length)) 21 | 22 | if reverse: 23 | step = -1 * (skip + 1) 24 | else: 25 | step = skip + 1 26 | 27 | cutoff_number = start_number + step * max_length 28 | 29 | whole_range = range(start_number, cutoff_number, step) 30 | 31 | return tuple(number for number in whole_range if 0 <= number <= UINT_256_MAX) 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2017-2018 Ethereum Foundation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /p2p/tools/paragon/proto.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from p2p.protocol import ( 4 | Protocol, 5 | ) 6 | 7 | from .commands import ( 8 | BroadcastData, 9 | GetSum, 10 | Sum, 11 | ) 12 | 13 | 14 | class ParagonProtocol(Protocol): 15 | name = 'paragon' 16 | version = 1 17 | _commands = [ 18 | BroadcastData, 19 | GetSum, Sum, 20 | ] 21 | cmd_length = 3 22 | logger = logging.getLogger("p2p.tools.paragon.proto.ParagonProtocol") 23 | 24 | # 25 | # Broadcast 26 | # 27 | def send_broadcast_data(self, data: bytes) -> None: 28 | cmd = BroadcastData(self.cmd_id_offset) 29 | header, body = cmd.encode({'data': data}) 30 | self.send(header, body) 31 | 32 | # 33 | # Sum 34 | # 35 | def send_get_sum(self, value_a: int, value_b: int) -> None: 36 | cmd = GetSum(self.cmd_id_offset) 37 | header, body = cmd.encode({'a': value_a, 'b': value_b}) 38 | self.send(header, body) 39 | 40 | def send_sum(self, result: int) -> None: 41 | cmd = GetSum(self.cmd_id_offset) 42 | header, body = cmd.encode({'result': result}) 43 | self.send(header, body) 44 | -------------------------------------------------------------------------------- /eth/vm/forks/homestead/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import Type # noqa: F401 2 | from eth.rlp.blocks import BaseBlock # noqa: F401 3 | from eth.vm.state import BaseState # noqa: F401 4 | 5 | from eth.chains.mainnet.constants import ( 6 | DAO_FORK_MAINNET_BLOCK 7 | ) 8 | from eth.vm.forks.frontier import FrontierVM 9 | 10 | from .blocks import HomesteadBlock 11 | from .headers import ( 12 | create_homestead_header_from_parent, 13 | compute_homestead_difficulty, 14 | configure_homestead_header, 15 | ) 16 | from .state import HomesteadState 17 | 18 | 19 | class MetaHomesteadVM(FrontierVM): 20 | support_dao_fork = True 21 | dao_fork_block_number = DAO_FORK_MAINNET_BLOCK 22 | 23 | 24 | class HomesteadVM(MetaHomesteadVM): 25 | # fork name 26 | fork = 'homestead' # type: str 27 | 28 | # classes 29 | block_class = HomesteadBlock # type: Type[BaseBlock] 30 | _state_class = HomesteadState # type: Type[BaseState] 31 | 32 | # method overrides 33 | create_header_from_parent = staticmethod(create_homestead_header_from_parent) 34 | compute_difficulty = staticmethod(compute_homestead_difficulty) 35 | configure_header = configure_homestead_header 36 | -------------------------------------------------------------------------------- /p2p/tools/paragon/peer.py: -------------------------------------------------------------------------------- 1 | from p2p.peer import ( 2 | BasePeer, 3 | BasePeerContext, 4 | BasePeerPool, 5 | BasePeerFactory, 6 | ) 7 | from p2p.protocol import ( 8 | Command, 9 | _DecodedMsgType, 10 | ) 11 | 12 | from .proto import ParagonProtocol 13 | 14 | 15 | class ParagonPeer(BasePeer): 16 | _supported_sub_protocols = [ParagonProtocol] 17 | sub_proto: ParagonProtocol = None 18 | 19 | async def send_sub_proto_handshake(self) -> None: 20 | pass 21 | 22 | async def process_sub_proto_handshake( 23 | self, cmd: Command, msg: _DecodedMsgType) -> None: 24 | pass 25 | 26 | async def do_sub_proto_handshake(self) -> None: 27 | pass 28 | 29 | 30 | class ParagonContext(BasePeerContext): 31 | # nothing magic here. Simply an example of how the context class can be 32 | # used to store data specific to a certain peer class. 33 | paragon: str = "paragon" 34 | 35 | 36 | class ParagonPeerFactory(BasePeerFactory): 37 | peer_class = ParagonPeer 38 | context: ParagonContext 39 | 40 | 41 | class ParagonPeerPool(BasePeerPool): 42 | peer_factory_class = ParagonPeerFactory 43 | context: ParagonContext 44 | -------------------------------------------------------------------------------- /trinity/utils/xdg.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pathlib import Path 4 | 5 | from trinity.exceptions import ( 6 | AmbigiousFileSystem 7 | ) 8 | 9 | 10 | def get_home() -> Path: 11 | try: 12 | return Path(os.environ['HOME']) 13 | except KeyError: 14 | raise AmbigiousFileSystem('$HOME environment variable not set') 15 | 16 | 17 | def get_xdg_cache_home() -> Path: 18 | try: 19 | return Path(os.environ['XDG_CACHE_HOME']) 20 | except KeyError: 21 | return get_home() / '.cache' 22 | 23 | 24 | def get_xdg_config_home() -> Path: 25 | try: 26 | return Path(os.environ['XDG_CONFIG_HOME']) 27 | except KeyError: 28 | return get_home() / '.config' 29 | 30 | 31 | def get_xdg_data_home() -> Path: 32 | try: 33 | return Path(os.environ['XDG_DATA_HOME']) 34 | except KeyError: 35 | return get_home() / '.local' / 'share' 36 | 37 | 38 | def get_xdg_trinity_root() -> Path: 39 | """ 40 | Returns the base directory under which trinity will store all data. 41 | """ 42 | try: 43 | return Path(os.environ['XDG_TRINITY_ROOT']) 44 | except KeyError: 45 | return get_xdg_data_home() / 'trinity' 46 | -------------------------------------------------------------------------------- /scripts/benchmark/utils/compile.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pathlib 3 | import subprocess 4 | from typing import ( 5 | Dict, 6 | Iterable 7 | ) 8 | 9 | 10 | def derive_compile_path(contract_path: pathlib.Path) -> pathlib.Path: 11 | return contract_path.with_name('{}-compiled'.format(contract_path.name)) 12 | 13 | 14 | def compile_contract(contract_path: pathlib.Path) -> None: 15 | out_path = derive_compile_path(contract_path) 16 | subprocess.run([ 17 | 'solc', 18 | contract_path, 19 | '--pretty-json', 20 | '--combined-json', 21 | 'bin,abi', 22 | '--overwrite', 23 | '-o', 24 | out_path 25 | ], stdout=subprocess.PIPE) 26 | 27 | 28 | def compile_contracts(contract_paths: Iterable[pathlib.Path]) -> None: 29 | for path in contract_paths: 30 | compile_contract(path) 31 | 32 | 33 | def get_compiled_contract(contract_path: pathlib.Path, contract_name: str) -> Dict[str, str]: 34 | compiled_path = derive_compile_path(contract_path) / "combined.json" 35 | 36 | with open(compiled_path) as file: 37 | data = json.load(file) 38 | return data["contracts"]["{}:{}".format(contract_path, contract_name)] 39 | -------------------------------------------------------------------------------- /eth/vm/execution_context.py: -------------------------------------------------------------------------------- 1 | class ExecutionContext: 2 | _coinbase = None 3 | 4 | _timestamp = None 5 | _number = None 6 | _difficulty = None 7 | _gas_limit = None 8 | _prev_hashes = None 9 | 10 | def __init__( 11 | self, 12 | coinbase, 13 | timestamp, 14 | block_number, 15 | difficulty, 16 | gas_limit, 17 | prev_hashes): 18 | self._coinbase = coinbase 19 | self._timestamp = timestamp 20 | self._block_number = block_number 21 | self._difficulty = difficulty 22 | self._gas_limit = gas_limit 23 | self._prev_hashes = prev_hashes 24 | 25 | @property 26 | def coinbase(self): 27 | return self._coinbase 28 | 29 | @property 30 | def timestamp(self): 31 | return self._timestamp 32 | 33 | @property 34 | def block_number(self): 35 | return self._block_number 36 | 37 | @property 38 | def difficulty(self): 39 | return self._difficulty 40 | 41 | @property 42 | def gas_limit(self): 43 | return self._gas_limit 44 | 45 | @property 46 | def prev_hashes(self): 47 | return self._prev_hashes 48 | -------------------------------------------------------------------------------- /trinity/plugins/registry.py: -------------------------------------------------------------------------------- 1 | import pkg_resources 2 | 3 | from trinity.plugins.builtin.attach.plugin import ( 4 | AttachPlugin 5 | ) 6 | from trinity.plugins.builtin.fix_unclean_shutdown.plugin import ( 7 | FixUncleanShutdownPlugin 8 | ) 9 | from trinity.plugins.builtin.json_rpc.plugin import ( 10 | JsonRpcServerPlugin, 11 | ) 12 | from trinity.plugins.builtin.tx_pool.plugin import ( 13 | TxPlugin, 14 | ) 15 | from trinity.plugins.builtin.light_peer_chain_bridge.plugin import ( 16 | LightPeerChainBridgePlugin 17 | ) 18 | 19 | 20 | def is_ipython_available() -> bool: 21 | try: 22 | pkg_resources.get_distribution('IPython') 23 | except pkg_resources.DistributionNotFound: 24 | return False 25 | else: 26 | return True 27 | 28 | 29 | # This is our poor mans central plugin registry for now. In the future, 30 | # we'll be able to load plugins from some path and control via Trinity 31 | # config file which plugin is enabled or not 32 | 33 | ENABLED_PLUGINS = [ 34 | AttachPlugin() if is_ipython_available() else AttachPlugin(use_ipython=False), 35 | FixUncleanShutdownPlugin(), 36 | JsonRpcServerPlugin(), 37 | LightPeerChainBridgePlugin(), 38 | TxPlugin(), 39 | ] 40 | -------------------------------------------------------------------------------- /setup_trinity.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | from setuptools import setup 4 | 5 | 6 | setup( 7 | name='trinity', 8 | # *IMPORTANT*: Don't manually change the version here. Use the 'bumpversion' utility. 9 | # NOT CURRENTLY APPLICABLE. VERSION BUMPS MANUAL FOR NOW 10 | version='0.1.0-alpha.15', 11 | description='The Trinity Ethereum Client', 12 | author='Ethereum Foundation', 13 | author_email='piper@pipermerriam.com', 14 | url='https://github.com/ethereum/py-evm', 15 | include_package_data=True, 16 | py_modules=[], 17 | install_requires=[ 18 | # DON'T FORGET TO BUMP THIS TOOOOOO!!!!!!! 19 | 'py-evm[trinity,p2p]==0.2.0a32', 20 | ], 21 | license='MIT', 22 | zip_safe=False, 23 | keywords='ethereum blockchain evm trinity', 24 | packages=[], 25 | classifiers=[ 26 | 'Development Status :: 2 - Pre-Alpha', 27 | 'Intended Audience :: Developers', 28 | 'License :: OSI Approved :: MIT License', 29 | 'Natural Language :: English', 30 | 'Programming Language :: Python :: 3.6', 31 | ], 32 | # trinity 33 | entry_points={ 34 | 'console_scripts': ['trinity=trinity:main'], 35 | }, 36 | ) 37 | -------------------------------------------------------------------------------- /eth/vm/logic/memory.py: -------------------------------------------------------------------------------- 1 | from eth import constants 2 | 3 | 4 | def mstore(computation): 5 | start_position = computation.stack_pop(type_hint=constants.UINT256) 6 | value = computation.stack_pop(type_hint=constants.BYTES) 7 | 8 | padded_value = value.rjust(32, b'\x00') 9 | normalized_value = padded_value[-32:] 10 | 11 | computation.extend_memory(start_position, 32) 12 | 13 | computation.memory_write(start_position, 32, normalized_value) 14 | 15 | 16 | def mstore8(computation): 17 | start_position = computation.stack_pop(type_hint=constants.UINT256) 18 | value = computation.stack_pop(type_hint=constants.BYTES) 19 | 20 | padded_value = value.rjust(1, b'\x00') 21 | normalized_value = padded_value[-1:] 22 | 23 | computation.extend_memory(start_position, 1) 24 | 25 | computation.memory_write(start_position, 1, normalized_value) 26 | 27 | 28 | def mload(computation): 29 | start_position = computation.stack_pop(type_hint=constants.UINT256) 30 | 31 | computation.extend_memory(start_position, 32) 32 | 33 | value = computation.memory_read(start_position, 32) 34 | computation.stack_push(value) 35 | 36 | 37 | def msize(computation): 38 | computation.stack_push(len(computation._memory)) 39 | -------------------------------------------------------------------------------- /eth/db/keymap.py: -------------------------------------------------------------------------------- 1 | from abc import ( 2 | abstractmethod, 3 | ) 4 | 5 | from eth.db.backends.base import BaseDB 6 | 7 | 8 | class KeyMapDB(BaseDB): 9 | """ 10 | Modify keys when accessing the database, according to the 11 | abstract keymap function set in the subclass. 12 | """ 13 | def __init__(self, db): 14 | self._db = db 15 | 16 | @staticmethod 17 | @abstractmethod 18 | def keymap(key: bytes) -> bytes: 19 | raise NotImplementedError 20 | 21 | def __getitem__(self, key): 22 | mapped_key = self.keymap(key) 23 | return self._db[mapped_key] 24 | 25 | def __setitem__(self, key, val): 26 | mapped_key = self.keymap(key) 27 | self._db[mapped_key] = val 28 | 29 | def __delitem__(self, key): 30 | mapped_key = self.keymap(key) 31 | del self._db[mapped_key] 32 | 33 | def __contains__(self, key): 34 | mapped_key = self.keymap(key) 35 | return mapped_key in self._db 36 | 37 | def __getattr__(self, attr): 38 | return getattr(self._db, attr) 39 | 40 | def __setattr__(self, attr, val): 41 | if attr in ('_db', 'keymap'): 42 | super().__setattr__(attr, val) 43 | else: 44 | setattr(self._db, attr, val) 45 | -------------------------------------------------------------------------------- /eth/vm/forks/frontier/validation.py: -------------------------------------------------------------------------------- 1 | from eth_utils import ( 2 | ValidationError, 3 | ) 4 | 5 | 6 | def validate_frontier_transaction(account_db, transaction): 7 | gas_cost = transaction.gas * transaction.gas_price 8 | sender_balance = account_db.get_balance(transaction.sender) 9 | 10 | if sender_balance < gas_cost: 11 | raise ValidationError( 12 | "Sender account balance cannot afford txn gas: `{0}`".format(transaction.sender) 13 | ) 14 | 15 | total_cost = transaction.value + gas_cost 16 | 17 | if sender_balance < total_cost: 18 | raise ValidationError("Sender account balance cannot afford txn") 19 | 20 | if account_db.get_nonce(transaction.sender) != transaction.nonce: 21 | raise ValidationError("Invalid transaction nonce") 22 | 23 | 24 | def validate_frontier_transaction_against_header(_vm, base_header, transaction): 25 | if base_header.gas_used + transaction.gas > base_header.gas_limit: 26 | raise ValidationError( 27 | "Transaction exceeds gas limit: using {}, bringing total to {}, but limit is {}".format( 28 | transaction.gas, 29 | base_header.gas_used + transaction.gas, 30 | base_header.gas_limit, 31 | ) 32 | ) 33 | -------------------------------------------------------------------------------- /eth/vm/forks/constantinople/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import ( # noqa: F401 2 | Type, 3 | ) 4 | 5 | from eth.rlp.blocks import BaseBlock # noqa: F401 6 | from eth.vm.forks.byzantium import ( 7 | ByzantiumVM, 8 | get_uncle_reward, 9 | ) 10 | from eth.vm.state import BaseState # noqa: F401 11 | 12 | from .blocks import ConstantinopleBlock 13 | from .constants import EIP1234_BLOCK_REWARD 14 | from .headers import ( 15 | compute_constantinople_difficulty, 16 | configure_constantinople_header, 17 | create_constantinople_header_from_parent, 18 | ) 19 | from .state import ConstantinopleState 20 | 21 | 22 | class ConstantinopleVM(ByzantiumVM): 23 | # fork name 24 | fork = 'constantinople' 25 | 26 | # classes 27 | block_class = ConstantinopleBlock # type: Type[BaseBlock] 28 | _state_class = ConstantinopleState # type: Type[BaseState] 29 | 30 | # Methods 31 | create_header_from_parent = staticmethod(create_constantinople_header_from_parent) 32 | compute_difficulty = staticmethod(compute_constantinople_difficulty) 33 | configure_header = configure_constantinople_header 34 | get_uncle_reward = staticmethod(get_uncle_reward(EIP1234_BLOCK_REWARD)) 35 | 36 | @staticmethod 37 | def get_block_reward(): 38 | return EIP1234_BLOCK_REWARD 39 | -------------------------------------------------------------------------------- /trinity/plugins/builtin/attach/plugin.py: -------------------------------------------------------------------------------- 1 | from argparse import ( 2 | ArgumentParser, 3 | Namespace, 4 | _SubParsersAction, 5 | ) 6 | import sys 7 | 8 | from trinity.config import ( 9 | ChainConfig, 10 | ) 11 | from trinity.extensibility import ( 12 | BasePlugin, 13 | ) 14 | 15 | from trinity.plugins.builtin.attach.console import ( 16 | console, 17 | ) 18 | 19 | 20 | class AttachPlugin(BasePlugin): 21 | 22 | def __init__(self, use_ipython: bool = True) -> None: 23 | super().__init__() 24 | self.use_ipython = use_ipython 25 | 26 | @property 27 | def name(self) -> str: 28 | return "Attach" 29 | 30 | def configure_parser(self, arg_parser: ArgumentParser, subparser: _SubParsersAction) -> None: 31 | 32 | attach_parser = subparser.add_parser( 33 | 'attach', 34 | help='open an REPL attached to a currently running chain', 35 | ) 36 | 37 | attach_parser.set_defaults(func=self.run_console) 38 | 39 | def run_console(self, args: Namespace, chain_config: ChainConfig) -> None: 40 | try: 41 | console(chain_config.jsonrpc_ipc_path, use_ipython=self.use_ipython) 42 | except FileNotFoundError as err: 43 | self.logger.error(str(err)) 44 | sys.exit(1) 45 | -------------------------------------------------------------------------------- /trinity/protocol/common/types.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Dict, 3 | Tuple, 4 | TypeVar, 5 | ) 6 | 7 | from eth.rlp.receipts import Receipt 8 | from eth_typing import ( 9 | Hash32, 10 | ) 11 | from p2p.peer import BasePeer 12 | from p2p.protocol import PayloadType 13 | 14 | from trinity.rlp.block_body import BlockBody 15 | 16 | TPeer = TypeVar('TPeer', bound=BasePeer) 17 | 18 | # A payload delivered by a responding command 19 | TResponsePayload = TypeVar('TResponsePayload', bound=PayloadType) 20 | 21 | # The returned value at the end of an exchange 22 | TResult = TypeVar('TResult') 23 | 24 | # ( 25 | # (node_hash, node), 26 | # ... 27 | # ) 28 | NodeDataBundles = Tuple[Tuple[Hash32, bytes], ...] 29 | 30 | # (receipts_in_block_a, receipts_in_block_b, ...) 31 | ReceiptsByBlock = Tuple[Tuple[Receipt, ...], ...] 32 | 33 | # ( 34 | # (receipts_in_block_a, (receipts_root_hash, receipts_trie_nodes), 35 | # (receipts_in_block_b, (receipts_root_hash, receipts_trie_nodes), 36 | # ... 37 | # ( 38 | ReceiptsBundles = Tuple[Tuple[Tuple[Receipt, ...], Tuple[Hash32, Dict[Hash32, bytes]]], ...] 39 | 40 | # (BlockBody, (txn_root, txn_trie_data), uncles_hash) 41 | BlockBodyBundles = Tuple[Tuple[ 42 | BlockBody, 43 | Tuple[Hash32, Dict[Hash32, bytes]], 44 | Hash32, 45 | ], ...] 46 | -------------------------------------------------------------------------------- /trinity/protocol/les/trackers.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Optional, 3 | Tuple, 4 | ) 5 | 6 | from eth.rlp.headers import BlockHeader 7 | 8 | from trinity.protocol.common.trackers import BasePerformanceTracker 9 | from trinity.utils.headers import sequence_builder 10 | 11 | from .requests import ( 12 | GetBlockHeadersRequest, 13 | ) 14 | 15 | 16 | BaseGetBlockHeadersTracker = BasePerformanceTracker[ 17 | GetBlockHeadersRequest, 18 | Tuple[BlockHeader, ...], 19 | ] 20 | 21 | 22 | class GetBlockHeadersTracker(BaseGetBlockHeadersTracker): 23 | def _get_request_size(self, request: GetBlockHeadersRequest) -> Optional[int]: 24 | payload = request.command_payload['query'] 25 | if isinstance(payload['block_number_or_hash'], int): 26 | return len(sequence_builder( 27 | start_number=payload['block_number_or_hash'], 28 | max_length=payload['max_headers'], 29 | skip=payload['skip'], 30 | reverse=payload['reverse'], 31 | )) 32 | else: 33 | return None 34 | 35 | def _get_result_size(self, result: Tuple[BlockHeader, ...]) -> int: 36 | return len(result) 37 | 38 | def _get_result_item_count(self, result: Tuple[BlockHeader, ...]) -> int: 39 | return len(result) 40 | -------------------------------------------------------------------------------- /eth/vm/forks/spurious_dragon/opcodes.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | from cytoolz import merge 4 | 5 | from eth.vm.forks.tangerine_whistle.constants import ( 6 | GAS_SELFDESTRUCT_EIP150, 7 | GAS_CALL_EIP150 8 | ) 9 | from eth.vm import mnemonics 10 | from eth.vm import opcode_values 11 | from eth.vm.forks.tangerine_whistle.opcodes import TANGERINE_WHISTLE_OPCODES 12 | from eth.vm.logic import ( 13 | arithmetic, 14 | system, 15 | call, 16 | ) 17 | from eth.vm.opcode import as_opcode 18 | 19 | from .constants import ( 20 | GAS_EXP_EIP160, 21 | GAS_EXPBYTE_EIP160 22 | ) 23 | 24 | 25 | UPDATED_OPCODES = { 26 | opcode_values.EXP: as_opcode( 27 | logic_fn=arithmetic.exp(gas_per_byte=GAS_EXPBYTE_EIP160), 28 | mnemonic=mnemonics.EXP, 29 | gas_cost=GAS_EXP_EIP160, 30 | ), 31 | opcode_values.SELFDESTRUCT: as_opcode( 32 | logic_fn=system.selfdestruct_eip161, 33 | mnemonic=mnemonics.SELFDESTRUCT, 34 | gas_cost=GAS_SELFDESTRUCT_EIP150, 35 | ), 36 | opcode_values.CALL: call.CallEIP161.configure( 37 | __name__='opcode:CALL', 38 | mnemonic=mnemonics.CALL, 39 | gas_cost=GAS_CALL_EIP150, 40 | )(), 41 | } 42 | 43 | 44 | SPURIOUS_DRAGON_OPCODES = merge( 45 | copy.deepcopy(TANGERINE_WHISTLE_OPCODES), 46 | UPDATED_OPCODES, 47 | ) 48 | -------------------------------------------------------------------------------- /trinity/exceptions.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | 3 | 4 | class BaseTrinityError(Exception): 5 | """ 6 | The base class for all Trinity errors. 7 | """ 8 | pass 9 | 10 | 11 | class AmbigiousFileSystem(BaseTrinityError): 12 | """ 13 | Raised when the file system paths are unclear 14 | """ 15 | pass 16 | 17 | 18 | class MissingPath(BaseTrinityError): 19 | """ 20 | Raised when an expected path is missing 21 | """ 22 | def __init__(self, msg: str, path: pathlib.Path) -> None: 23 | super().__init__(msg) 24 | self.path = path 25 | 26 | 27 | class AlreadyWaiting(BaseTrinityError): 28 | """ 29 | Raised when an attempt is made to wait for a certain message type from a 30 | peer when there is already an active wait for that message type. 31 | """ 32 | pass 33 | 34 | 35 | class SyncRequestAlreadyProcessed(BaseTrinityError): 36 | """ 37 | Raised when a trie SyncRequest has already been processed. 38 | """ 39 | pass 40 | 41 | 42 | class OversizeObject(BaseTrinityError): 43 | """ 44 | Raised when an object is bigger than comfortably fits in memory. 45 | """ 46 | pass 47 | 48 | 49 | class DAOForkCheckFailure(BaseTrinityError): 50 | """ 51 | Raised when the DAO fork check with a certain peer is unsuccessful. 52 | """ 53 | pass 54 | -------------------------------------------------------------------------------- /scripts/db-shell.py: -------------------------------------------------------------------------------- 1 | """Provide access to the local database via a ChainDB instance. 2 | 3 | Run with `python -i db-shell.py` to get an interactive shell with a ChainDB instance available 4 | as `chaindb`. 5 | 6 | By default it will use the mainnet full DB. 7 | """ 8 | import argparse 9 | 10 | from eth_utils import encode_hex 11 | 12 | from eth.chains.mainnet import MAINNET_NETWORK_ID 13 | from eth.chains.ropsten import ROPSTEN_NETWORK_ID 14 | from eth.db.chain import ChainDB 15 | from eth.db.backends.level import LevelDB 16 | 17 | from trinity.config import ChainConfig 18 | from trinity.constants import SYNC_FULL, SYNC_LIGHT 19 | 20 | 21 | if __name__ == '__main__': 22 | parser = argparse.ArgumentParser() 23 | parser.add_argument('-ropsten', action='store_true') 24 | parser.add_argument('-light', action='store_true') 25 | args = parser.parse_args() 26 | 27 | network_id = MAINNET_NETWORK_ID 28 | if args.ropsten: 29 | network_id = ROPSTEN_NETWORK_ID 30 | sync_mode = SYNC_FULL 31 | if args.light: 32 | sync_mode = SYNC_LIGHT 33 | 34 | cfg = ChainConfig(network_id, sync_mode=sync_mode) 35 | chaindb = ChainDB(LevelDB(cfg.database_dir)) 36 | head = chaindb.get_canonical_head() 37 | print("Head #%d; hash: %s, state_root: %s" % ( 38 | head.block_number, head.hex_hash, encode_hex(head.state_root))) 39 | -------------------------------------------------------------------------------- /eth/rlp/receipts.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | 3 | import rlp 4 | from rlp.sedes import ( 5 | big_endian_int, 6 | CountableList, 7 | binary, 8 | ) 9 | 10 | from eth_bloom import BloomFilter 11 | 12 | from .sedes import ( 13 | int256, 14 | ) 15 | 16 | from .logs import Log 17 | 18 | from typing import Iterable 19 | 20 | 21 | class Receipt(rlp.Serializable): 22 | 23 | fields = [ 24 | ('state_root', binary), 25 | ('gas_used', big_endian_int), 26 | ('bloom', int256), 27 | ('logs', CountableList(Log)) 28 | ] 29 | 30 | def __init__(self, 31 | state_root: bytes, 32 | gas_used: int, 33 | logs: Iterable[Log], 34 | bloom: int=None) -> None: 35 | 36 | if bloom is None: 37 | bloomables = itertools.chain.from_iterable(log.bloomables for log in logs) 38 | bloom = int(BloomFilter.from_iterable(bloomables)) 39 | 40 | super().__init__( 41 | state_root=state_root, 42 | gas_used=gas_used, 43 | bloom=bloom, 44 | logs=logs, 45 | ) 46 | 47 | @property 48 | def bloom_filter(self) -> BloomFilter: 49 | return BloomFilter(self.bloom) 50 | 51 | @bloom_filter.setter 52 | def bloom_filter(self, value: BloomFilter) -> None: 53 | self.bloom = int(value) 54 | -------------------------------------------------------------------------------- /eth/tools/fixtures/fillers/main.py: -------------------------------------------------------------------------------- 1 | from cytoolz import ( 2 | assoc_in, 3 | merge, 4 | ) 5 | 6 | from eth.tools.fixtures.helpers import ( 7 | get_test_name, 8 | ) 9 | from eth.tools._utils.git import get_version_from_git 10 | 11 | from .formatters import ( 12 | filled_state_test_formatter, 13 | filled_vm_test_formatter, 14 | ) 15 | from .state import fill_state_test 16 | from .vm import fill_vm_test 17 | 18 | 19 | FILLED_WITH_TEMPLATE = "py-evm-{version}" 20 | 21 | 22 | # 23 | # Primary test filler 24 | # 25 | def fill_test(filler, info=None, apply_formatter=True, **kwargs): 26 | test_name = get_test_name(filler) 27 | test = filler[test_name] 28 | 29 | if "transaction" in test: 30 | filled = fill_state_test(filler) 31 | formatter = filled_state_test_formatter 32 | elif "exec" in test: 33 | filled = fill_vm_test(filler, **kwargs) 34 | formatter = filled_vm_test_formatter 35 | else: 36 | raise ValueError("Given filler does not appear to be for VM or state test") 37 | 38 | info = merge( 39 | {"filledwith": FILLED_WITH_TEMPLATE.format(version=get_version_from_git())}, 40 | info if info else {} 41 | ) 42 | filled = assoc_in(filled, [test_name, "_info"], info) 43 | 44 | if apply_formatter: 45 | return formatter(filled) 46 | else: 47 | return filled 48 | -------------------------------------------------------------------------------- /eth/utils/state.py: -------------------------------------------------------------------------------- 1 | from eth_utils import ( 2 | to_tuple, 3 | ) 4 | 5 | 6 | @to_tuple 7 | def diff_account_db(expected_state, account_db): 8 | for account, account_data in sorted(expected_state.items()): 9 | expected_nonce = account_data['nonce'] 10 | expected_code = account_data['code'] 11 | expected_balance = account_data['balance'] 12 | 13 | actual_nonce = account_db.get_nonce(account) 14 | actual_code = account_db.get_code(account) 15 | actual_balance = account_db.get_balance(account) 16 | 17 | if actual_nonce != expected_nonce: 18 | yield (account, 'nonce', actual_nonce, expected_nonce) 19 | if actual_code != expected_code: 20 | yield (account, 'code', actual_code, expected_code) 21 | if actual_balance != expected_balance: 22 | yield (account, 'balance', actual_balance, expected_balance) 23 | 24 | for slot, expected_storage_value in sorted(account_data['storage'].items()): 25 | actual_storage_value = account_db.get_storage(account, slot) 26 | if actual_storage_value != expected_storage_value: 27 | yield ( 28 | account, 29 | 'storage[{0}]'.format(slot), 30 | actual_storage_value, 31 | expected_storage_value, 32 | ) 33 | -------------------------------------------------------------------------------- /trinity/rpc/modules/evm.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Any 3 | ) 4 | from eth_utils import ( 5 | encode_hex, 6 | ) 7 | 8 | from eth.chains.base import ( 9 | Chain 10 | ) 11 | from eth.tools.fixtures import ( 12 | apply_fixture_block_to_chain, 13 | new_chain_from_fixture, 14 | normalize_block, 15 | normalize_blockchain_fixtures, 16 | ) 17 | 18 | from trinity.rpc.format import ( 19 | format_params, 20 | ) 21 | from trinity.rpc.modules import ( 22 | RPCModule, 23 | ) 24 | 25 | 26 | class EVM(RPCModule): 27 | @format_params(normalize_blockchain_fixtures) 28 | async def resetToGenesisFixture(self, chain_info: Any) -> Chain: 29 | ''' 30 | This method is a special case. It returns a new chain object 31 | which is then replaced inside :class:`~trinity.rpc.main.RPCServer` 32 | for all future calls. 33 | ''' 34 | return new_chain_from_fixture(chain_info, type(self._chain)) 35 | 36 | @format_params(normalize_block) 37 | async def applyBlockFixture(self, block_info: Any) -> str: 38 | ''' 39 | This method is a special case. It returns a new chain object 40 | which is then replaced inside :class:`~trinity.rpc.main.RPCServer` 41 | for all future calls. 42 | ''' 43 | _, _, rlp_encoded = apply_fixture_block_to_chain(block_info, self._chain) 44 | return encode_hex(rlp_encoded) 45 | -------------------------------------------------------------------------------- /eth/precompiles/ecmul.py: -------------------------------------------------------------------------------- 1 | from py_ecc import ( 2 | optimized_bn128 as bn128, 3 | ) 4 | 5 | from eth_utils import ( 6 | ValidationError, 7 | ) 8 | 9 | from eth import constants 10 | 11 | from eth.exceptions import ( 12 | VMError, 13 | ) 14 | from eth.utils.bn128 import ( 15 | validate_point, 16 | ) 17 | from eth.utils.numeric import ( 18 | big_endian_to_int, 19 | int_to_big_endian, 20 | ) 21 | from eth.utils.padding import ( 22 | pad32, 23 | pad32r, 24 | ) 25 | 26 | 27 | def ecmul(computation): 28 | computation.consume_gas(constants.GAS_ECMUL, reason='ECMUL Precompile') 29 | 30 | try: 31 | result = _ecmull(computation.msg.data) 32 | except ValidationError: 33 | raise VMError("Invalid ECMUL parameters") 34 | 35 | result_x, result_y = result 36 | result_bytes = b''.join(( 37 | pad32(int_to_big_endian(result_x.n)), 38 | pad32(int_to_big_endian(result_y.n)), 39 | )) 40 | computation.output = result_bytes 41 | return computation 42 | 43 | 44 | def _ecmull(data): 45 | x_bytes = pad32r(data[:32]) 46 | y_bytes = pad32r(data[32:64]) 47 | m_bytes = pad32r(data[64:96]) 48 | 49 | x = big_endian_to_int(x_bytes) 50 | y = big_endian_to_int(y_bytes) 51 | m = big_endian_to_int(m_bytes) 52 | 53 | p = validate_point(x, y) 54 | 55 | result = bn128.normalize(bn128.multiply(p, m)) 56 | return result 57 | -------------------------------------------------------------------------------- /trinity/utils/db_proxy.py: -------------------------------------------------------------------------------- 1 | from multiprocessing.managers import ( 2 | BaseManager, 3 | ) 4 | import pathlib 5 | 6 | from trinity.chains import ( 7 | AsyncHeaderChainProxy, 8 | ChainProxy, 9 | ) 10 | from trinity.db.chain import ChainDBProxy 11 | from trinity.db.base import DBProxy 12 | from trinity.db.header import ( 13 | AsyncHeaderDBProxy 14 | ) 15 | 16 | 17 | def create_db_manager(ipc_path: pathlib.Path) -> BaseManager: 18 | """ 19 | We're still using 'str' here on param ipc_path because an issue with 20 | multi-processing not being able to interpret 'Path' objects correctly 21 | """ 22 | class DBManager(BaseManager): 23 | pass 24 | 25 | # Typeshed definitions for multiprocessing.managers is incomplete, so ignore them for now: 26 | # https://github.com/python/typeshed/blob/85a788dbcaa5e9e9a62e55f15d44530cd28ba830/stdlib/3/multiprocessing/managers.pyi#L3 27 | DBManager.register('get_db', proxytype=DBProxy) # type: ignore 28 | DBManager.register('get_chaindb', proxytype=ChainDBProxy) # type: ignore 29 | DBManager.register('get_chain', proxytype=ChainProxy) # type: ignore 30 | DBManager.register('get_headerdb', proxytype=AsyncHeaderDBProxy) # type: ignore 31 | DBManager.register('get_header_chain', proxytype=AsyncHeaderChainProxy) # type: ignore 32 | 33 | manager = DBManager(address=str(ipc_path)) # type: ignore 34 | return manager 35 | -------------------------------------------------------------------------------- /tests/core/env-utils/test_env_float.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pytest 3 | 4 | from eth.utils.env import ( 5 | env_float, 6 | ) 7 | 8 | 9 | @pytest.mark.parametrize( 10 | 'env_value,expected', 11 | ( 12 | ('1.01', 1.01), 13 | ('123.0', 123.0), 14 | ('-123.99', -123.99), 15 | ) 16 | ) 17 | def test_env_float_not_required_with_no_default(monkeypatch, env_value, expected): 18 | """ 19 | Test that when the environment variable is present that it is parsed to a float. 20 | """ 21 | monkeypatch.setenv('TEST_FLOAT_ENV_VARIABLE', env_value) 22 | 23 | actual = env_float('TEST_FLOAT_ENV_VARIABLE') 24 | assert actual == expected 25 | 26 | 27 | def test_env_float_not_required_and_not_set(): 28 | """ 29 | Test that when the env variable is not set and not required it raises a 30 | ValueError 31 | """ 32 | # sanity check 33 | assert 'TEST_FLOAT_ENV_VARIABLE' not in os.environ 34 | 35 | with pytest.raises(ValueError): 36 | env_float('TEST_FLOAT_ENV_VARIABLE') 37 | 38 | 39 | def test_env_float_when_missing_and_required_is_error(): 40 | """ 41 | Test that when the env variable is not set and is required, it raises an 42 | error. 43 | """ 44 | # sanity check 45 | assert 'TEST_FLOAT_ENV_VARIABLE' not in os.environ 46 | 47 | with pytest.raises(KeyError): 48 | env_float('TEST_FLOAT_ENV_VARIABLE', required=True) 49 | -------------------------------------------------------------------------------- /tests/core/env-utils/test_env_string.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pytest 3 | 4 | from eth.utils.env import ( 5 | env_string, 6 | ) 7 | 8 | 9 | def test_env_string_with_basic_usage(monkeypatch): 10 | """ 11 | Test that when the environment variable is present that it is returned as a 12 | string. 13 | """ 14 | monkeypatch.setenv('TEST_BOOLEAN_ENV_VARIABLE', 'test-value') 15 | 16 | actual = env_string('TEST_BOOLEAN_ENV_VARIABLE') 17 | assert actual == 'test-value' 18 | 19 | 20 | def test_env_string_with_default_value(monkeypatch): 21 | """ 22 | Test that when the environment variable is missing and a default is 23 | provided, the default is retured. 24 | """ 25 | assert 'TEST_BOOLEAN_ENV_VARIABLE' not in os.environ 26 | 27 | actual = env_string('TEST_BOOLEAN_ENV_VARIABLE', default='test-value') 28 | assert actual == 'test-value' 29 | 30 | 31 | def test_env_string_with_required(): 32 | """ 33 | Test that when the environment variable is missing and a default is 34 | provided, the default is retured. 35 | """ 36 | assert 'TEST_BOOLEAN_ENV_VARIABLE' not in os.environ 37 | 38 | with pytest.raises(KeyError): 39 | env_string('TEST_BOOLEAN_ENV_VARIABLE', required=True) 40 | 41 | 42 | def test_env_string_with_required_and_default_is_error(): 43 | with pytest.raises(ValueError): 44 | env_string('TEST_BOOLEAN_ENV_VARIABLE', required=True, default='test-value') 45 | -------------------------------------------------------------------------------- /eth/vm/forks/spurious_dragon/state.py: -------------------------------------------------------------------------------- 1 | 2 | from eth.utils.hexadecimal import ( 3 | encode_hex, 4 | ) 5 | from eth.vm.forks.homestead.state import ( 6 | HomesteadState, 7 | HomesteadTransactionExecutor, 8 | ) 9 | 10 | from .computation import SpuriousDragonComputation 11 | from .utils import collect_touched_accounts 12 | 13 | 14 | class SpuriousDragonTransactionExecutor(HomesteadTransactionExecutor): 15 | def finalize_computation(self, transaction, computation): 16 | computation = super().finalize_computation(transaction, computation) 17 | 18 | # 19 | # EIP161 state clearing 20 | # 21 | touched_accounts = collect_touched_accounts(computation) 22 | 23 | for account in touched_accounts: 24 | should_delete = ( 25 | self.vm_state.account_db.account_exists(account) and 26 | self.vm_state.account_db.account_is_empty(account) 27 | ) 28 | if should_delete: 29 | self.vm_state.logger.trace( 30 | "CLEARING EMPTY ACCOUNT: %s", 31 | encode_hex(account), 32 | ) 33 | self.vm_state.account_db.delete_account(account) 34 | 35 | return computation 36 | 37 | 38 | class SpuriousDragonState(HomesteadState): 39 | computation_class = SpuriousDragonComputation 40 | transaction_executor = SpuriousDragonTransactionExecutor # Type[BaseTransactionExecutor] 41 | -------------------------------------------------------------------------------- /scripts/benchmark/checks/mine_empty_blocks.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from eth.chains.base import ( 4 | MiningChain 5 | ) 6 | 7 | from .base_benchmark import ( 8 | BaseBenchmark 9 | ) 10 | from utils.chain_plumbing import ( 11 | get_all_chains 12 | ) 13 | from utils.format import ( 14 | format_block 15 | ) 16 | from utils.reporting import ( 17 | DefaultStat 18 | ) 19 | 20 | 21 | class MineEmptyBlocksBenchmark(BaseBenchmark): 22 | 23 | def __init__(self, num_blocks: int = 500) -> None: 24 | self.num_blocks = num_blocks 25 | 26 | @property 27 | def name(self) -> str: 28 | return 'Empty block mining' 29 | 30 | def execute(self) -> DefaultStat: 31 | total_stat = DefaultStat() 32 | 33 | for chain in get_all_chains(): 34 | 35 | value = self.as_timed_result(lambda: self.mine_empty_blocks(chain, self.num_blocks)) 36 | 37 | stat = DefaultStat( 38 | caption=chain.get_vm().fork, 39 | total_blocks=self.num_blocks, 40 | total_seconds=value.duration 41 | ) 42 | total_stat = total_stat.cumulate(stat) 43 | self.print_stat_line(stat) 44 | 45 | return total_stat 46 | 47 | def mine_empty_blocks(self, chain: MiningChain, number_blocks: int) -> None: 48 | 49 | for _ in range(1, number_blocks + 1): 50 | block = chain.mine_block() 51 | logging.debug(format_block(block)) 52 | -------------------------------------------------------------------------------- /eth/db/trie.py: -------------------------------------------------------------------------------- 1 | import functools 2 | from typing import Dict, Tuple, Union 3 | 4 | import rlp 5 | from trie import ( 6 | HexaryTrie, 7 | ) 8 | 9 | from eth_typing import Hash32 10 | 11 | from eth.constants import ( 12 | BLANK_ROOT_HASH, 13 | ) 14 | from eth.rlp.receipts import Receipt 15 | from eth.rlp.transactions import BaseTransaction 16 | 17 | TransactionsOrReceipts = Union[Tuple[Receipt, ...], Tuple[BaseTransaction, ...]] 18 | TrieRootAndData = Tuple[Hash32, Dict[Hash32, bytes]] 19 | 20 | 21 | def make_trie_root_and_nodes(items: TransactionsOrReceipts) -> TrieRootAndData: 22 | return _make_trie_root_and_nodes(tuple(rlp.encode(item) for item in items)) 23 | 24 | 25 | # This cache is expected to be useful when importing blocks as we call this once when importing 26 | # and again when validating the imported block. But it should also help for post-Byzantium blocks 27 | # as it's common for them to have duplicate receipt_roots. Given that, it probably makes sense to 28 | # use a relatively small cache size here. 29 | @functools.lru_cache(128) 30 | def _make_trie_root_and_nodes(items: Tuple[bytes, ...]) -> TrieRootAndData: 31 | kv_store = {} # type: Dict[Hash32, bytes] 32 | trie = HexaryTrie(kv_store, BLANK_ROOT_HASH) 33 | with trie.squash_changes() as memory_trie: 34 | for index, item in enumerate(items): 35 | index_key = rlp.encode(index, sedes=rlp.sedes.big_endian_int) 36 | memory_trie[index_key] = item 37 | return trie.root_hash, kv_store 38 | -------------------------------------------------------------------------------- /tests/p2p/test_peer_subscriber.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | 4 | import pytest 5 | 6 | from p2p.peer import PeerSubscriber 7 | from p2p.protocol import Command 8 | 9 | from p2p.tools.paragon import GetSum 10 | from p2p.tools.paragon.helpers import get_directly_linked_peers 11 | 12 | 13 | logger = logging.getLogger('testing.p2p.PeerSubscriber') 14 | 15 | 16 | class GetSumSubscriber(PeerSubscriber): 17 | logger = logger 18 | msg_queue_maxsize = 10 19 | subscription_msg_types = {GetSum} 20 | 21 | 22 | class AllSubscriber(PeerSubscriber): 23 | logger = logger 24 | msg_queue_maxsize = 10 25 | subscription_msg_types = {Command} 26 | 27 | 28 | @pytest.mark.asyncio 29 | async def test_peer_subscriber_filters_messages(request, event_loop): 30 | peer, remote = await get_directly_linked_peers(request, event_loop) 31 | 32 | get_sum_subscriber = GetSumSubscriber() 33 | all_subscriber = AllSubscriber() 34 | 35 | peer.add_subscriber(get_sum_subscriber) 36 | peer.add_subscriber(all_subscriber) 37 | 38 | remote.sub_proto.send_broadcast_data(b'value-a') 39 | remote.sub_proto.send_broadcast_data(b'value-b') 40 | remote.sub_proto.send_get_sum(7, 8) 41 | remote.sub_proto.send_get_sum(1234, 4321) 42 | remote.sub_proto.send_broadcast_data(b'value-b') 43 | 44 | # yeild to let remote and peer transmit. 45 | await asyncio.sleep(0.02) 46 | 47 | assert get_sum_subscriber.queue_size == 2 48 | assert all_subscriber.queue_size == 5 49 | -------------------------------------------------------------------------------- /eth/tools/_utils/mappings.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Mapping 2 | import itertools 3 | 4 | from cytoolz import merge_with 5 | 6 | 7 | def merge_if_dicts(values): 8 | if all(isinstance(item, Mapping) for item in values): 9 | return merge_with(merge_if_dicts, *values) 10 | else: 11 | return values[-1] 12 | 13 | 14 | def deep_merge(*dicts): 15 | return merge_with(merge_if_dicts, *dicts) 16 | 17 | 18 | def is_cleanly_mergable(*dicts): 19 | """Check that nothing will be overwritten when dictionaries are merged using `deep_merge`. 20 | 21 | Examples: 22 | 23 | >>> is_cleanly_mergable({"a": 1}, {"b": 2}, {"c": 3}) 24 | True 25 | >>> is_cleanly_mergable({"a": 1}, {"b": 2}, {"a": 0, c": 3}) 26 | False 27 | >>> is_cleanly_mergable({"a": 1, "b": {"ba": 2}}, {"c": 3, {"b": {"bb": 4}}) 28 | True 29 | >>> is_cleanly_mergable({"a": 1, "b": {"ba": 2}}, {"b": {"ba": 4}}) 30 | False 31 | 32 | """ 33 | if len(dicts) <= 1: 34 | return True 35 | elif len(dicts) == 2: 36 | if not all(isinstance(d, Mapping) for d in dicts): 37 | return False 38 | else: 39 | shared_keys = set(dicts[0].keys()) & set(dicts[1].keys()) 40 | return all(is_cleanly_mergable(dicts[0][key], dicts[1][key]) for key in shared_keys) 41 | else: 42 | dict_combinations = itertools.combinations(dicts, 2) 43 | return all(is_cleanly_mergable(*combination) for combination in dict_combinations) 44 | -------------------------------------------------------------------------------- /p2p/cancellable.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Awaitable, 3 | TypeVar, 4 | ) 5 | 6 | from cancel_token import CancelToken 7 | 8 | 9 | class CancellableMixin: 10 | cancel_token: CancelToken = None 11 | 12 | _TReturn = TypeVar('_TReturn') 13 | 14 | async def wait(self, 15 | awaitable: Awaitable[_TReturn], 16 | token: CancelToken = None, 17 | timeout: float = None) -> _TReturn: 18 | """See wait_first()""" 19 | return await self.wait_first(awaitable, token=token, timeout=timeout) 20 | 21 | async def wait_first(self, 22 | *awaitables: Awaitable[_TReturn], 23 | token: CancelToken = None, 24 | timeout: float = None) -> _TReturn: 25 | """ 26 | Wait for the first awaitable to complete, unless we timeout or the token chain is triggered. 27 | 28 | The given token is chained with this service's token, so triggering either will cancel 29 | this. 30 | 31 | Returns the result of the first one to complete. 32 | 33 | Raises TimeoutError if we timeout or OperationCancelled if the token chain is triggered. 34 | 35 | All pending futures are cancelled before returning. 36 | """ 37 | if token is None: 38 | token_chain = self.cancel_token 39 | else: 40 | token_chain = token.chain(self.cancel_token) 41 | return await token_chain.cancellable_wait(*awaitables, timeout=timeout) 42 | -------------------------------------------------------------------------------- /eth/precompiles/ecadd.py: -------------------------------------------------------------------------------- 1 | from py_ecc import ( 2 | optimized_bn128 as bn128, 3 | ) 4 | 5 | from eth_utils import ( 6 | ValidationError, 7 | ) 8 | 9 | from eth import constants 10 | 11 | from eth.exceptions import ( 12 | VMError, 13 | ) 14 | from eth.utils.bn128 import ( 15 | validate_point, 16 | ) 17 | from eth.utils.numeric import ( 18 | big_endian_to_int, 19 | int_to_big_endian, 20 | ) 21 | from eth.utils.padding import ( 22 | pad32, 23 | pad32r, 24 | ) 25 | 26 | 27 | def ecadd(computation): 28 | computation.consume_gas(constants.GAS_ECADD, reason='ECADD Precompile') 29 | 30 | try: 31 | result = _ecadd(computation.msg.data) 32 | except ValidationError: 33 | raise VMError("Invalid ECADD parameters") 34 | 35 | result_x, result_y = result 36 | result_bytes = b''.join(( 37 | pad32(int_to_big_endian(result_x.n)), 38 | pad32(int_to_big_endian(result_y.n)), 39 | )) 40 | computation.output = result_bytes 41 | return computation 42 | 43 | 44 | def _ecadd(data): 45 | x1_bytes = pad32r(data[:32]) 46 | y1_bytes = pad32r(data[32:64]) 47 | x2_bytes = pad32r(data[64:96]) 48 | y2_bytes = pad32r(data[96:128]) 49 | 50 | x1 = big_endian_to_int(x1_bytes) 51 | y1 = big_endian_to_int(y1_bytes) 52 | x2 = big_endian_to_int(x2_bytes) 53 | y2 = big_endian_to_int(y2_bytes) 54 | 55 | p1 = validate_point(x1, y1) 56 | p2 = validate_point(x2, y2) 57 | 58 | result = bn128.normalize(bn128.add(p1, p2)) 59 | return result 60 | -------------------------------------------------------------------------------- /tests/p2p/test_peer_collect_sub_proto_msgs.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | 4 | import pytest 5 | 6 | from p2p.tools.paragon import BroadcastData, GetSum 7 | from p2p.tools.paragon.helpers import ( 8 | get_directly_linked_peers, 9 | ) 10 | 11 | 12 | logger = logging.getLogger('testing.p2p.PeerSubscriber') 13 | 14 | 15 | @pytest.mark.asyncio 16 | async def test_peer_subscriber_filters_messages(request, event_loop): 17 | peer, remote = await get_directly_linked_peers(request, event_loop) 18 | 19 | with peer.collect_sub_proto_messages() as collector: 20 | assert collector in peer._subscribers 21 | remote.sub_proto.send_broadcast_data(b'broadcast-a') 22 | remote.sub_proto.send_broadcast_data(b'broadcast-b') 23 | remote.sub_proto.send_get_sum(7, 8) 24 | remote.sub_proto.send_broadcast_data(b'broadcast-c') 25 | await asyncio.sleep(0.01) 26 | 27 | assert collector not in peer._subscribers 28 | 29 | # yield to let remote and peer transmit. 30 | 31 | all_messages = collector.get_messages() 32 | assert len(all_messages) == 4 33 | 34 | assert isinstance(all_messages[0][1], BroadcastData) 35 | assert isinstance(all_messages[1][1], BroadcastData) 36 | assert isinstance(all_messages[2][1], GetSum) 37 | assert isinstance(all_messages[3][1], BroadcastData) 38 | 39 | # make sure it isn't still collecting 40 | remote.sub_proto.send_broadcast_data(b'broadcast-d') 41 | 42 | await asyncio.sleep(0.01) 43 | 44 | assert len(collector.get_messages()) == 0 45 | -------------------------------------------------------------------------------- /trinity/protocol/common/requests.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from typing import ( 3 | Tuple, 4 | cast, 5 | ) 6 | 7 | from eth_typing import BlockIdentifier, BlockNumber 8 | 9 | from trinity.utils.headers import sequence_builder 10 | 11 | 12 | class BaseHeaderRequest(ABC): 13 | block_number_or_hash: BlockIdentifier 14 | max_headers: int 15 | skip: int 16 | reverse: bool 17 | 18 | @property 19 | @abstractmethod 20 | def max_size(self) -> int: 21 | pass 22 | 23 | def generate_block_numbers(self, block_number: BlockNumber=None) -> Tuple[BlockNumber, ...]: 24 | if block_number is None and not self.is_numbered: 25 | raise TypeError( 26 | "A `block_number` must be supplied to generate block numbers " 27 | "for hash based header requests" 28 | ) 29 | elif block_number is not None and self.is_numbered: 30 | raise TypeError( 31 | "The `block_number` parameter may not be used for number based " 32 | "header requests" 33 | ) 34 | elif block_number is None: 35 | block_number = cast(BlockNumber, self.block_number_or_hash) 36 | 37 | max_headers = min(self.max_size, self.max_headers) 38 | 39 | return sequence_builder( 40 | block_number, 41 | max_headers, 42 | self.skip, 43 | self.reverse, 44 | ) 45 | 46 | @property 47 | def is_numbered(self) -> bool: 48 | return isinstance(self.block_number_or_hash, int) 49 | -------------------------------------------------------------------------------- /eth/vm/forks/constantinople/opcodes.py: -------------------------------------------------------------------------------- 1 | import copy 2 | from cytoolz import ( 3 | merge 4 | ) 5 | 6 | from eth import ( 7 | constants 8 | ) 9 | from eth.vm import ( 10 | mnemonics, 11 | opcode_values, 12 | ) 13 | from eth.vm.forks.byzantium.opcodes import ( 14 | BYZANTIUM_OPCODES 15 | ) 16 | from eth.vm.forks.constantinople.constants import ( 17 | GAS_EXTCODEHASH_EIP1052 18 | ) 19 | from eth.vm.logic import ( 20 | arithmetic, 21 | context, 22 | system, 23 | ) 24 | from eth.vm.opcode import ( 25 | as_opcode 26 | ) 27 | 28 | 29 | UPDATED_OPCODES = { 30 | opcode_values.SHL: as_opcode( 31 | logic_fn=arithmetic.shl, 32 | mnemonic=mnemonics.SHL, 33 | gas_cost=constants.GAS_VERYLOW, 34 | ), 35 | opcode_values.SHR: as_opcode( 36 | logic_fn=arithmetic.shr, 37 | mnemonic=mnemonics.SHR, 38 | gas_cost=constants.GAS_VERYLOW, 39 | ), 40 | opcode_values.SAR: as_opcode( 41 | logic_fn=arithmetic.sar, 42 | mnemonic=mnemonics.SAR, 43 | gas_cost=constants.GAS_VERYLOW, 44 | ), 45 | opcode_values.EXTCODEHASH: as_opcode( 46 | logic_fn=context.extcodehash, 47 | mnemonic=mnemonics.EXTCODEHASH, 48 | gas_cost=GAS_EXTCODEHASH_EIP1052, 49 | ), 50 | opcode_values.CREATE2: system.Create2.configure( 51 | __name__='opcode:CREATE2', 52 | mnemonic=mnemonics.CREATE2, 53 | gas_cost=constants.GAS_CREATE, 54 | )(), 55 | } 56 | 57 | CONSTANTINOPLE_OPCODES = merge( 58 | copy.deepcopy(BYZANTIUM_OPCODES), 59 | UPDATED_OPCODES, 60 | ) 61 | -------------------------------------------------------------------------------- /trinity/utils/validation.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Any, 3 | Dict, 4 | ) 5 | 6 | from eth_utils import ( 7 | is_address, 8 | ) 9 | 10 | from eth.vm.base import ( 11 | BaseVM, 12 | ) 13 | 14 | 15 | FORBIDDEN_KEYS = {'v', 'r', 's', 'nonce'} 16 | DERIVED_KEYS = {'from'} 17 | RENAMED_KEYS = {'gas_price': 'gasPrice'} 18 | 19 | 20 | def validate_transaction_gas_estimation_dict(transaction_dict: Dict[str, Any], vm: BaseVM) -> None: 21 | """Validate a transaction dictionary supplied for an RPC method call""" 22 | transaction_class = vm.get_transaction_class() 23 | 24 | all_keys = set(transaction_class._meta.field_names) 25 | allowed_keys = all_keys.difference(FORBIDDEN_KEYS).union(DERIVED_KEYS) 26 | spec_keys = set(RENAMED_KEYS.get(field_name, field_name) for field_name in allowed_keys) 27 | 28 | superfluous_keys = set(transaction_dict).difference(spec_keys) 29 | 30 | if superfluous_keys: 31 | raise ValueError( 32 | "The following invalid fields were given in a transaction: %r. Only %r are allowed" % ( 33 | list(sorted(superfluous_keys)), 34 | list(sorted(spec_keys)), 35 | ) 36 | ) 37 | 38 | 39 | def validate_transaction_call_dict(transaction_dict: Dict[str, Any], vm: BaseVM) -> None: 40 | validate_transaction_gas_estimation_dict(transaction_dict, vm) 41 | 42 | # 'to' is required in a call, but not a gas estimation 43 | if not is_address(transaction_dict.get('to', None)): 44 | raise ValueError("The 'to' field must be supplied when getting the result of a transaction") 45 | -------------------------------------------------------------------------------- /eth/vm/logic/flow.py: -------------------------------------------------------------------------------- 1 | from eth import constants 2 | from eth.exceptions import ( 3 | InvalidJumpDestination, 4 | InvalidInstruction, 5 | Halt, 6 | ) 7 | from eth.vm.opcode_values import ( 8 | JUMPDEST, 9 | ) 10 | 11 | 12 | def stop(computation): 13 | raise Halt('STOP') 14 | 15 | 16 | def jump(computation): 17 | jump_dest = computation.stack_pop(type_hint=constants.UINT256) 18 | 19 | computation.code.pc = jump_dest 20 | 21 | next_opcode = computation.code.peek() 22 | 23 | if next_opcode != JUMPDEST: 24 | raise InvalidJumpDestination("Invalid Jump Destination") 25 | 26 | if not computation.code.is_valid_opcode(jump_dest): 27 | raise InvalidInstruction("Jump resulted in invalid instruction") 28 | 29 | 30 | def jumpi(computation): 31 | jump_dest, check_value = computation.stack_pop(num_items=2, type_hint=constants.UINT256) 32 | 33 | if check_value: 34 | computation.code.pc = jump_dest 35 | 36 | next_opcode = computation.code.peek() 37 | 38 | if next_opcode != JUMPDEST: 39 | raise InvalidJumpDestination("Invalid Jump Destination") 40 | 41 | if not computation.code.is_valid_opcode(jump_dest): 42 | raise InvalidInstruction("Jump resulted in invalid instruction") 43 | 44 | 45 | def jumpdest(computation): 46 | pass 47 | 48 | 49 | def pc(computation): 50 | pc = max(computation.code.pc - 1, 0) 51 | 52 | computation.stack_push(pc) 53 | 54 | 55 | def gas(computation): 56 | gas_remaining = computation.get_gas_remaining() 57 | 58 | computation.stack_push(gas_remaining) 59 | -------------------------------------------------------------------------------- /eth/vm/logic/logging.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | import functools 3 | from typing import List # noqa: F401 4 | 5 | from eth import constants 6 | 7 | 8 | def log_XX(computation, topic_count): 9 | if topic_count < 0 or topic_count > 4: 10 | raise TypeError("Invalid log topic size. Must be 0, 1, 2, 3, or 4") 11 | 12 | mem_start_position, size = computation.stack_pop(num_items=2, type_hint=constants.UINT256) 13 | 14 | if not topic_count: 15 | topics = [] # type: List[int] 16 | elif topic_count > 1: 17 | topics = computation.stack_pop(num_items=topic_count, type_hint=constants.UINT256) 18 | else: 19 | topics = [computation.stack_pop(num_items=topic_count, type_hint=constants.UINT256)] 20 | 21 | data_gas_cost = constants.GAS_LOGDATA * size 22 | topic_gas_cost = constants.GAS_LOGTOPIC * topic_count 23 | total_gas_cost = data_gas_cost + topic_gas_cost 24 | 25 | computation.consume_gas( 26 | total_gas_cost, 27 | reason="Log topic and data gas cost", 28 | ) 29 | 30 | computation.extend_memory(mem_start_position, size) 31 | log_data = computation.memory_read(mem_start_position, size) 32 | 33 | computation.add_log_entry( 34 | account=computation.msg.storage_address, 35 | topics=topics, 36 | data=log_data, 37 | ) 38 | 39 | 40 | log0 = functools.partial(log_XX, topic_count=0) 41 | log1 = functools.partial(log_XX, topic_count=1) 42 | log2 = functools.partial(log_XX, topic_count=2) 43 | log3 = functools.partial(log_XX, topic_count=3) 44 | log4 = functools.partial(log_XX, topic_count=4) 45 | -------------------------------------------------------------------------------- /scripts/benchmark/checks/import_empty_blocks.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from eth.chains.base import ( 4 | Chain 5 | ) 6 | 7 | from .base_benchmark import ( 8 | BaseBenchmark 9 | ) 10 | from utils.chain_plumbing import ( 11 | get_all_chains 12 | ) 13 | from utils.format import ( 14 | format_block 15 | ) 16 | from utils.reporting import ( 17 | DefaultStat 18 | ) 19 | 20 | 21 | class ImportEmptyBlocksBenchmark(BaseBenchmark): 22 | 23 | def __init__(self, num_blocks: int = 500) -> None: 24 | self.num_blocks = num_blocks 25 | 26 | @property 27 | def name(self) -> str: 28 | return 'Empty block import' 29 | 30 | def execute(self) -> DefaultStat: 31 | total_stat = DefaultStat() 32 | 33 | for chain in get_all_chains(): 34 | 35 | val = self.as_timed_result(lambda: self.import_empty_blocks(chain, self.num_blocks)) 36 | stat = DefaultStat( 37 | caption=chain.get_vm().fork, 38 | total_blocks=self.num_blocks, 39 | total_seconds=val.duration 40 | ) 41 | total_stat = total_stat.cumulate(stat) 42 | self.print_stat_line(stat) 43 | 44 | return total_stat 45 | 46 | def import_empty_blocks(self, chain: Chain, number_blocks: int) -> int: 47 | 48 | total_gas_used = 0 49 | for _ in range(1, number_blocks + 1): 50 | block, _, _ = chain.import_block(chain.get_vm().block, False) 51 | 52 | total_gas_used = total_gas_used + block.header.gas_used 53 | logging.debug(format_block(block)) 54 | 55 | return total_gas_used 56 | -------------------------------------------------------------------------------- /trinity/protocol/common/handlers.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from typing import ( 3 | Any, 4 | Dict, 5 | Iterator, 6 | Type, 7 | ) 8 | 9 | from p2p.peer import BasePeer 10 | 11 | from trinity.protocol.common.exchanges import ( 12 | BaseExchange, 13 | ) 14 | from trinity.protocol.common.managers import ( 15 | ExchangeManager, 16 | ) 17 | 18 | 19 | class BaseExchangeHandler(ABC): 20 | @property 21 | @abstractmethod 22 | def _exchange_config(self) -> Dict[str, Type[BaseExchange[Any, Any, Any]]]: 23 | pass 24 | 25 | def __init__(self, peer: BasePeer) -> None: 26 | self._peer = peer 27 | 28 | for attr, exchange_cls in self._exchange_config.items(): 29 | if hasattr(self, attr): 30 | raise AttributeError( 31 | "Unable to set manager on attribute `{0}` which is already " 32 | "present on the class: {1}".format(attr, getattr(self, attr)) 33 | ) 34 | manager: ExchangeManager[Any, Any, Any] 35 | manager = ExchangeManager(self._peer, exchange_cls.response_cmd_type, peer.cancel_token) 36 | exchange = exchange_cls(manager) 37 | setattr(self, attr, exchange) 38 | 39 | def __iter__(self) -> Iterator[BaseExchange[Any, Any, Any]]: 40 | for key in self._exchange_config.keys(): 41 | yield getattr(self, key) 42 | 43 | def get_stats(self) -> Dict[str, str]: 44 | return { 45 | exchange.response_cmd_type.__name__: exchange.tracker.get_stats() 46 | for exchange 47 | in self 48 | } 49 | -------------------------------------------------------------------------------- /tests/database/test_hash_trie.py: -------------------------------------------------------------------------------- 1 | from hypothesis import ( 2 | given, 3 | strategies as st, 4 | ) 5 | 6 | from eth_hash.auto import keccak 7 | from trie import HexaryTrie 8 | 9 | from eth.db.hash_trie import ( 10 | HashTrie, 11 | ) 12 | 13 | 14 | class ExplicitHashTrie(object): 15 | _trie = None 16 | 17 | def __init__(self, trie): 18 | self._trie = trie 19 | 20 | def __setitem__(self, key, value): 21 | self._trie[keccak(key)] = value 22 | 23 | def __getitem__(self, key): 24 | return self._trie[keccak(key)] 25 | 26 | def __delitem__(self, key): 27 | del self._trie[keccak(key)] 28 | 29 | def __contains__(self, key): 30 | return keccak(key) in self._trie 31 | 32 | @property 33 | def root_hash(self): 34 | return self._trie.root_hash 35 | 36 | @root_hash.setter 37 | def root_hash(self, value): 38 | self._trie.root_hash = value 39 | 40 | 41 | @given(st.binary(), st.binary()) 42 | def test_keymap_equivalence(key, val): 43 | explicit_db = {} 44 | composed_db = {} 45 | 46 | explicit_trie = HexaryTrie(explicit_db) 47 | composed_trie = HexaryTrie(composed_db) 48 | 49 | explicit = ExplicitHashTrie(explicit_trie) 50 | composed = HashTrie(composed_trie) 51 | 52 | explicit[key] = val 53 | composed[key] = val 54 | 55 | assert explicit[key] == composed[key] 56 | assert explicit_db == composed_db 57 | assert explicit.root_hash == composed.root_hash 58 | 59 | explicit.root_hash = b'\0' * 32 60 | composed.root_hash = b'\0' * 32 61 | 62 | assert explicit_trie.root_hash == composed_trie.root_hash 63 | -------------------------------------------------------------------------------- /scripts/benchmark/checks/base_benchmark.py: -------------------------------------------------------------------------------- 1 | from abc import ( 2 | ABC, 3 | abstractmethod, 4 | ) 5 | import logging 6 | from typing import ( 7 | Any, 8 | Callable 9 | ) 10 | 11 | from utils.meters import ( 12 | time_call, 13 | TimedResult 14 | ) 15 | from utils.reporting import ( 16 | DefaultStat, 17 | print_default_benchmark_result_header, 18 | print_default_benchmark_stat_line, 19 | print_default_benchmark_total_line, 20 | ) 21 | from utils.shellart import ( 22 | bold_yellow 23 | ) 24 | 25 | 26 | class BaseBenchmark(ABC): 27 | 28 | @abstractmethod 29 | def execute(self) -> DefaultStat: 30 | raise NotImplementedError( 31 | "Must be implemented by subclasses" 32 | ) 33 | 34 | @property 35 | @abstractmethod 36 | def name(self) -> DefaultStat: 37 | raise NotImplementedError( 38 | "Must be implemented by subclasses" 39 | ) 40 | 41 | def print_result_header(self) -> None: 42 | print_default_benchmark_result_header() 43 | 44 | def print_stat_line(self, stat: DefaultStat) -> None: 45 | print_default_benchmark_stat_line(stat) 46 | 47 | def print_total_line(self, stat: DefaultStat) -> None: 48 | print_default_benchmark_total_line(stat) 49 | 50 | def run(self) -> DefaultStat: 51 | logging.info(bold_yellow('Starting benchmark: {}\n'.format(self.name))) 52 | self.print_result_header() 53 | stat = self.execute() 54 | self.print_total_line(stat) 55 | return stat 56 | 57 | def as_timed_result(self, fn: Callable[..., Any]=None) -> TimedResult: 58 | return time_call(fn) 59 | -------------------------------------------------------------------------------- /tests/core/hexadecimal-utils/test_encode_and_decode.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | import pytest 4 | 5 | from hypothesis import ( 6 | given, 7 | strategies as st, 8 | ) 9 | 10 | from eth.utils.hexadecimal import ( 11 | encode_hex, 12 | decode_hex, 13 | ) 14 | 15 | 16 | @pytest.mark.parametrize( 17 | 'value,expected', 18 | ( 19 | (b'', '0x'), 20 | (b'\x00', '0x00'), 21 | (b'\x01', '0x01'), 22 | ), 23 | ) 24 | def test_basic_hexadecimal_encoding(value, expected): 25 | actual = encode_hex(value) 26 | assert actual == expected 27 | 28 | 29 | @pytest.mark.parametrize( 30 | 'value,expected', 31 | ( 32 | ('0x', b''), 33 | ('0x00', b'\x00'), 34 | ('0x01', b'\x01'), 35 | ), 36 | ) 37 | def test_basic_hexadecimal_decoding(value, expected): 38 | actual = decode_hex(value) 39 | assert actual == expected 40 | 41 | 42 | @given(value=st.binary(min_size=0, max_size=256)) 43 | def test_round_trip_with_bytestring_start(value): 44 | intermediate_value = encode_hex(value) 45 | round_trip_value = decode_hex(intermediate_value) 46 | assert round_trip_value == value 47 | 48 | 49 | HEX_ALPHABET = '1234567890abcdef' 50 | 51 | 52 | def _coerce_to_even_hex(raw_hex): 53 | return '0x' + raw_hex[:2 * (len(raw_hex) // 2)] 54 | 55 | 56 | @given( 57 | value=st.text(alphabet=HEX_ALPHABET, min_size=0, max_size=256).map(_coerce_to_even_hex) 58 | ) 59 | def test_round_trip_with_hex_string_start(value): 60 | intermediate_value = decode_hex(value) 61 | round_trip_value = encode_hex(intermediate_value) 62 | assert round_trip_value == value 63 | -------------------------------------------------------------------------------- /trinity/extensibility/events.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Any, 3 | Type, 4 | TYPE_CHECKING, 5 | ) 6 | from argparse import ( 7 | Namespace, 8 | ) 9 | 10 | from trinity.config import ( 11 | ChainConfig, 12 | ) 13 | 14 | 15 | if TYPE_CHECKING: 16 | from trinity.extensibility import ( # noqa: F401 17 | BasePlugin, 18 | ) 19 | 20 | 21 | class BaseEvent: 22 | """ 23 | The base class for all plugin events. Plugin events can be broadcasted for all different 24 | kind of reasons. Plugins can act based on these events and consume the events even before 25 | the plugin is started, giving plugins the chance to start based on an event or a series of 26 | events. The startup of Trinity itself can be an event as well as the start of a plugin itself 27 | which, for instance, gives other plugins the chance to start based on these previous events. 28 | """ 29 | pass 30 | 31 | 32 | class TrinityStartupEvent(BaseEvent): 33 | """ 34 | Broadcasted when Trinity is starting. 35 | """ 36 | def __init__(self, args: Namespace, chain_config: ChainConfig) -> None: 37 | self.args = args 38 | self.chain_config = chain_config 39 | 40 | 41 | class PluginStartedEvent(BaseEvent): 42 | """ 43 | Broadcasted when a plugin was started 44 | """ 45 | def __init__(self, plugin: 'BasePlugin') -> None: 46 | self.plugin = plugin 47 | 48 | 49 | class ResourceAvailableEvent(BaseEvent): 50 | """ 51 | Broadcasted when a resource becomes available 52 | """ 53 | def __init__(self, resource: Any, resource_type: Type[Any]) -> None: 54 | self.resource = resource 55 | self.resource_type = resource_type 56 | -------------------------------------------------------------------------------- /eth/utils/module_loading.py: -------------------------------------------------------------------------------- 1 | import operator 2 | from importlib import import_module 3 | 4 | 5 | def import_string(dotted_path): 6 | """ 7 | Source: django.utils.module_loading 8 | Import a dotted module path and return the attribute/class designated by the 9 | last name in the path. Raise ImportError if the import failed. 10 | """ 11 | try: 12 | module_path, class_name = dotted_path.rsplit('.', 1) 13 | except ValueError: 14 | msg = "%s doesn't look like a module path" % dotted_path 15 | raise ImportError(msg) 16 | 17 | module = import_module(module_path) 18 | 19 | try: 20 | return getattr(module, class_name) 21 | except AttributeError: 22 | msg = 'Module "%s" does not define a "%s" attribute/class' % ( 23 | module_path, class_name) 24 | raise ImportError(msg) 25 | 26 | 27 | def split_at_longest_importable_path(dotted_path): 28 | num_path_parts = len(dotted_path.split('.')) 29 | 30 | for i in range(1, num_path_parts): 31 | path_parts = dotted_path.rsplit('.', i) 32 | import_part = path_parts[0] 33 | remainder = '.'.join(path_parts[1:]) 34 | 35 | try: 36 | module = import_module(import_part) 37 | except ImportError: 38 | continue 39 | 40 | try: 41 | operator.attrgetter(remainder)(module) 42 | except AttributeError: 43 | raise ImportError( 44 | "Unable to derive appropriate import path for {0}".format( 45 | dotted_path, 46 | ) 47 | ) 48 | else: 49 | return import_part, remainder 50 | else: 51 | return '', dotted_path 52 | -------------------------------------------------------------------------------- /eth/db/schema.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | 3 | from eth_typing import ( 4 | BlockNumber, 5 | Hash32, 6 | ) 7 | 8 | 9 | class BaseSchema(ABC): 10 | @staticmethod 11 | @abstractmethod 12 | def make_canonical_head_hash_lookup_key() -> bytes: 13 | raise NotImplementedError('Must be implemented by subclasses') 14 | 15 | @staticmethod 16 | @abstractmethod 17 | def make_block_number_to_hash_lookup_key(block_number: BlockNumber) -> bytes: 18 | raise NotImplementedError('Must be implemented by subclasses') 19 | 20 | @staticmethod 21 | @abstractmethod 22 | def make_block_hash_to_score_lookup_key(block_hash: Hash32) -> bytes: 23 | raise NotImplementedError('Must be implemented by subclasses') 24 | 25 | @staticmethod 26 | @abstractmethod 27 | def make_transaction_hash_to_block_lookup_key(transaction_hash: Hash32) -> bytes: 28 | raise NotImplementedError('Must be implemented by subclasses') 29 | 30 | 31 | class SchemaV1(BaseSchema): 32 | @staticmethod 33 | def make_canonical_head_hash_lookup_key() -> bytes: 34 | return b'v1:canonical_head_hash' 35 | 36 | @staticmethod 37 | def make_block_number_to_hash_lookup_key(block_number: BlockNumber) -> bytes: 38 | number_to_hash_key = b'block-number-to-hash:%d' % block_number 39 | return number_to_hash_key 40 | 41 | @staticmethod 42 | def make_block_hash_to_score_lookup_key(block_hash: Hash32) -> bytes: 43 | return b'block-hash-to-score:%s' % block_hash 44 | 45 | @staticmethod 46 | def make_transaction_hash_to_block_lookup_key(transaction_hash: Hash32) -> bytes: 47 | return b'transaction-hash-to-block:%s' % transaction_hash 48 | -------------------------------------------------------------------------------- /eth/vm/forks/spurious_dragon/utils.py: -------------------------------------------------------------------------------- 1 | from eth_utils import to_set 2 | 3 | from eth import constants 4 | 5 | from eth.utils.address import ( 6 | force_bytes_to_address, 7 | ) 8 | 9 | 10 | THREE = force_bytes_to_address(b'\x03') 11 | 12 | 13 | @to_set 14 | def collect_touched_accounts(computation): 15 | """ 16 | Collect all of the accounts that *may* need to be deleted based on EIP161: 17 | 18 | https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md 19 | 20 | also see: https://github.com/ethereum/EIPs/issues/716 21 | """ 22 | if computation.is_origin_computation and computation.transaction_context.gas_price == 0: 23 | yield computation.state.coinbase 24 | 25 | for beneficiary in sorted(set(computation.accounts_to_delete.values())): 26 | if computation.is_error and computation.is_origin_computation: 27 | # Special case to account for geth+parity bug 28 | # https://github.com/ethereum/EIPs/issues/716 29 | if beneficiary == THREE: 30 | yield beneficiary 31 | continue 32 | else: 33 | yield beneficiary 34 | 35 | if computation.msg.to != constants.CREATE_CONTRACT_ADDRESS: 36 | if computation.is_error and computation.is_origin_computation: 37 | # Special case to account for geth+parity bug 38 | # https://github.com/ethereum/EIPs/issues/716 39 | if computation.msg.to == THREE: 40 | yield computation.msg.to 41 | else: 42 | yield computation.msg.to 43 | 44 | if not computation.is_origin_computation or not computation.is_error: 45 | for child in computation.children: 46 | yield from collect_touched_accounts(child) 47 | -------------------------------------------------------------------------------- /docs/introduction.rst: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | Trinity & Py-EVM 5 | ~~~~~~~~~~~~~~~~ 6 | 7 | Py-EVM is a new implementation of the Ethereum Virtual Machine (EVM) written in Python. Trinity is 8 | the client software that connects to the Ethereum network and runs on top of Py-EVM. 9 | 10 | Trinity and Py-EVM aim to replace existing Python Ethereum implementations to eventually become the 11 | defacto standard for the Python ecosystem. 12 | 13 | If none of this makes sense to you yet we recommend to checkout the 14 | `Ethereum `_ website as well as a 15 | `higher level description `_ 16 | of the Ethereum project. 17 | 18 | Goals 19 | ----- 20 | 21 | The main focus is to enrich the Ethereum ecosystem with a Python implementation that is: 22 | 23 | * Well documented 24 | * Easy to understand 25 | * Has clear APIs 26 | * Runs fast and resource friendly 27 | * Is highly flexible to support: 28 | 29 | * Public chains 30 | * Private chains 31 | * Consortium chains 32 | * Advanced research 33 | 34 | .. note:: 35 | 36 | Trinity is currently in **public alpha** and can connect and sync to the main ethereum network. 37 | While it isn't meant for production use yet, we encourage the adventurous to try it out. 38 | Follow along the :doc:`Trinity Quickstart ` to get things going. 39 | 40 | Further reading 41 | --------------- 42 | 43 | Here are a couple more useful links to check out. 44 | 45 | * :doc:`Trinity Quickstart ` 46 | * `Source Code on GitHub `_ 47 | * `Public Gitter Chat `_ 48 | * :doc:`Get involved ` -------------------------------------------------------------------------------- /eth/precompiles/ecrecover.py: -------------------------------------------------------------------------------- 1 | from eth_keys import keys 2 | from eth_keys.exceptions import ( 3 | BadSignature, 4 | ) 5 | 6 | from eth_utils import ( 7 | ValidationError, 8 | ) 9 | 10 | from eth import constants 11 | 12 | from eth.validation import ( 13 | validate_lt_secpk1n, 14 | validate_gte, 15 | validate_lte, 16 | ) 17 | 18 | from eth.utils.numeric import ( 19 | big_endian_to_int, 20 | ) 21 | from eth.utils.padding import ( 22 | pad32, 23 | pad32r, 24 | ) 25 | 26 | 27 | def ecrecover(computation): 28 | computation.consume_gas(constants.GAS_ECRECOVER, reason="ECRecover Precompile") 29 | raw_message_hash = computation.msg.data[:32] 30 | message_hash = pad32r(raw_message_hash) 31 | 32 | v_bytes = pad32r(computation.msg.data[32:64]) 33 | v = big_endian_to_int(v_bytes) 34 | 35 | r_bytes = pad32r(computation.msg.data[64:96]) 36 | r = big_endian_to_int(r_bytes) 37 | 38 | s_bytes = pad32r(computation.msg.data[96:128]) 39 | s = big_endian_to_int(s_bytes) 40 | 41 | try: 42 | validate_lt_secpk1n(r, title="ECRecover: R") 43 | validate_lt_secpk1n(s, title="ECRecover: S") 44 | validate_lte(v, 28, title="ECRecover: V") 45 | validate_gte(v, 27, title="ECRecover: V") 46 | except ValidationError: 47 | return computation 48 | 49 | canonical_v = v - 27 50 | 51 | try: 52 | signature = keys.Signature(vrs=(canonical_v, r, s)) 53 | public_key = signature.recover_public_key_from_msg_hash(message_hash) 54 | except BadSignature: 55 | return computation 56 | 57 | address = public_key.to_canonical_address() 58 | padded_address = pad32(address) 59 | 60 | computation.output = padded_address 61 | return computation 62 | -------------------------------------------------------------------------------- /tests/trinity/core/cli/test_log_level_configuration.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from trinity.cli_parser import ( 4 | parser, 5 | LOG_LEVEL_CHOICES, 6 | ) 7 | 8 | 9 | def test_cli_log_level_not_specified(): 10 | ns = parser.parse_args([]) 11 | assert ns.log_levels is None 12 | 13 | 14 | @pytest.mark.parametrize( 15 | 'level,expected', 16 | LOG_LEVEL_CHOICES.items(), 17 | ) 18 | def test_cli_log_level_global_values(level, expected): 19 | ns = parser.parse_args(['--log-level', level]) 20 | assert ns.log_levels == {None: expected} 21 | 22 | 23 | @pytest.mark.parametrize( 24 | 'level,expected', 25 | LOG_LEVEL_CHOICES.items(), 26 | ) 27 | def test_cli_log_level_module_value(level, expected): 28 | ns = parser.parse_args(['--log-level', "module={0}".format(level)]) 29 | assert ns.log_levels == {'module': expected} 30 | 31 | 32 | def test_cli_log_level_error_for_multiple_globals(capsys): 33 | with pytest.raises(SystemExit): 34 | parser.parse_args([ 35 | '--log-level', 'DEBUG', 36 | '--log-level', 'modue=DEBUG', 37 | '--log-level', 'ERROR', 38 | ]) 39 | # this prevents the messaging that this error prints to stdout from 40 | # escaping the test run. 41 | capsys.readouterr() 42 | 43 | 44 | def test_cli_log_level_error_for_repeated_name(capsys): 45 | with pytest.raises(SystemExit): 46 | parser.parse_args([ 47 | '--log-level', 'DEBUG', 48 | '--log-level', 'modue_a=DEBUG', 49 | '--log-level', 'modue_b=DEBUG', 50 | '--log-level', 'modue_a=DEBUG', 51 | ]) 52 | # this prevents the messaging that this error prints to stdout from 53 | # escaping the test run. 54 | capsys.readouterr() 55 | -------------------------------------------------------------------------------- /eth/tools/fixtures/fillers/vm.py: -------------------------------------------------------------------------------- 1 | from eth.tools.fixtures.helpers import ( 2 | get_test_name, 3 | ) 4 | from eth.tools.fixtures.normalization import ( 5 | normalize_bytes, 6 | normalize_call_creates, 7 | normalize_environment, 8 | normalize_execution, 9 | normalize_int, 10 | normalize_logs, 11 | normalize_state, 12 | ) 13 | from eth.tools._utils.hashing import hash_log_entries 14 | from eth.tools._utils.mappings import deep_merge 15 | 16 | 17 | def fill_vm_test( 18 | filler, 19 | *, 20 | call_creates=None, 21 | gas_price=None, 22 | gas_remaining=0, 23 | logs=None, 24 | output=b"" 25 | ): 26 | test_name = get_test_name(filler) 27 | test = filler[test_name] 28 | 29 | environment = normalize_environment(test["env"]) 30 | pre_state = normalize_state(test["pre"]) 31 | execution = normalize_execution(test["exec"]) 32 | 33 | assert len(test["expect"]) == 1 34 | expect = test["expect"][0] 35 | assert "network" not in test 36 | assert "indexes" not in test 37 | 38 | result = normalize_state(expect["result"]) 39 | post_state = deep_merge(pre_state, result) 40 | 41 | call_creates = normalize_call_creates(call_creates or []) 42 | gas_remaining = normalize_int(gas_remaining) 43 | output = normalize_bytes(output) 44 | 45 | logs = normalize_logs(logs or []) 46 | log_hash = hash_log_entries(logs) 47 | 48 | return { 49 | test_name: { 50 | "env": environment, 51 | "pre": pre_state, 52 | "exec": execution, 53 | "post": post_state, 54 | "callcreates": call_creates, 55 | "gas": gas_remaining, 56 | "output": output, 57 | "logs": log_hash, 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /trinity/protocol/les/requests.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Any, 3 | Dict, 4 | ) 5 | 6 | from eth_typing import BlockIdentifier 7 | 8 | from p2p.protocol import BaseRequest 9 | 10 | from trinity.protocol.common.requests import ( 11 | BaseHeaderRequest, 12 | ) 13 | 14 | from trinity.protocol.les.constants import MAX_HEADERS_FETCH 15 | from .commands import ( 16 | BlockHeaders, 17 | GetBlockHeaders, 18 | GetBlockHeadersQuery, 19 | ) 20 | 21 | 22 | HeadersResponseDict = Dict[str, Any] 23 | 24 | 25 | class HeaderRequest(BaseHeaderRequest): 26 | request_id: int 27 | 28 | max_size = MAX_HEADERS_FETCH 29 | 30 | def __init__(self, 31 | block_number_or_hash: BlockIdentifier, 32 | max_headers: int, 33 | skip: int, 34 | reverse: bool, 35 | request_id: int) -> None: 36 | self.block_number_or_hash = block_number_or_hash 37 | self.max_headers = max_headers 38 | self.skip = skip 39 | self.reverse = reverse 40 | self.request_id = request_id 41 | 42 | 43 | class GetBlockHeadersRequest(BaseRequest[Dict[str, Any]]): 44 | cmd_type = GetBlockHeaders 45 | response_type = BlockHeaders 46 | 47 | def __init__(self, 48 | block_number_or_hash: BlockIdentifier, 49 | max_headers: int, 50 | skip: int, 51 | reverse: bool, 52 | request_id: int) -> None: 53 | self.command_payload = { 54 | 'request_id': request_id, 55 | 'query': GetBlockHeadersQuery( 56 | block_number_or_hash, 57 | max_headers, 58 | skip, 59 | reverse, 60 | ), 61 | } 62 | -------------------------------------------------------------------------------- /tests/trinity/core/header-utils/test_block_number_sequence_builder.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from eth.constants import UINT_256_MAX 4 | 5 | from trinity.exceptions import OversizeObject 6 | from trinity.utils.headers import sequence_builder 7 | 8 | 9 | @pytest.mark.parametrize( 10 | 'start_num, max_length, skip, reverse, expected', 11 | ( 12 | (0, 0, 0, False, ()), 13 | (0, 0, 0, True, ()), 14 | (0, 0, 1, False, ()), 15 | (0, 0, 1, True, ()), 16 | (0, 1, 0, False, (0, )), 17 | (0, 1, 0, True, (0, )), 18 | (0, 1, 1, False, (0, )), 19 | (0, 1, 1, True, (0, )), 20 | (9, 1, 0, False, (9, )), 21 | (9, 1, 0, True, (9, )), 22 | (1, 3, 0, False, (1, 2, 3)), 23 | (0, 5, 1, False, (0, 2, 4, 6, 8)), 24 | (9, 5, 1, True, (9, 7, 5, 3, 1)), 25 | (1, 9, 0, True, (1, 0)), 26 | (UINT_256_MAX - 1, 4, 0, False, (UINT_256_MAX - 1, UINT_256_MAX, )), 27 | # can handle mildly large numbers 28 | (400000000, 1000000, 0, False, tuple(range(400000000, 401000000))), 29 | ), 30 | ) 31 | def test_sequence(start_num, max_length, skip, reverse, expected): 32 | assert sequence_builder(start_num, max_length, skip, reverse) == expected 33 | 34 | 35 | TOO_LONG = 2000000 36 | 37 | 38 | @pytest.mark.parametrize('reverse', (True, False)) 39 | @pytest.mark.parametrize('start_num', (0, 400000000)) 40 | @pytest.mark.parametrize('skip', (0, 10000)) 41 | def test_oversize_sequence(start_num, skip, reverse): 42 | # Instead of using the specific constant, just use a rough TOO_LONG number 43 | # We don't need to worry about edge cases for this gut check 44 | with pytest.raises(OversizeObject): 45 | sequence_builder(start_num, TOO_LONG, skip, reverse) 46 | -------------------------------------------------------------------------------- /eth/vm/logic/storage.py: -------------------------------------------------------------------------------- 1 | from eth import constants 2 | 3 | from eth.utils.hexadecimal import ( 4 | encode_hex, 5 | ) 6 | 7 | 8 | def sstore(computation): 9 | slot, value = computation.stack_pop(num_items=2, type_hint=constants.UINT256) 10 | 11 | current_value = computation.state.account_db.get_storage( 12 | address=computation.msg.storage_address, 13 | slot=slot, 14 | ) 15 | 16 | is_currently_empty = not bool(current_value) 17 | is_going_to_be_empty = not bool(value) 18 | 19 | if is_currently_empty: 20 | gas_refund = 0 21 | elif is_going_to_be_empty: 22 | gas_refund = constants.REFUND_SCLEAR 23 | else: 24 | gas_refund = 0 25 | 26 | if is_currently_empty and is_going_to_be_empty: 27 | gas_cost = constants.GAS_SRESET 28 | elif is_currently_empty: 29 | gas_cost = constants.GAS_SSET 30 | elif is_going_to_be_empty: 31 | gas_cost = constants.GAS_SRESET 32 | else: 33 | gas_cost = constants.GAS_SRESET 34 | 35 | computation.consume_gas(gas_cost, reason="SSTORE: {0}[{1}] -> {2} ({3})".format( 36 | encode_hex(computation.msg.storage_address), 37 | slot, 38 | value, 39 | current_value, 40 | )) 41 | 42 | if gas_refund: 43 | computation.refund_gas(gas_refund) 44 | 45 | computation.state.account_db.set_storage( 46 | address=computation.msg.storage_address, 47 | slot=slot, 48 | value=value, 49 | ) 50 | 51 | 52 | def sload(computation): 53 | slot = computation.stack_pop(type_hint=constants.UINT256) 54 | 55 | value = computation.state.account_db.get_storage( 56 | address=computation.msg.storage_address, 57 | slot=slot, 58 | ) 59 | computation.stack_push(value) 60 | -------------------------------------------------------------------------------- /trinity/utils/queues.py: -------------------------------------------------------------------------------- 1 | from asyncio import ( # noqa: F401 2 | Queue, 3 | ) 4 | from typing import ( 5 | Tuple, 6 | TypeVar, 7 | ) 8 | 9 | from eth_utils import ( 10 | ValidationError, 11 | ) 12 | 13 | TQueueItem = TypeVar('TQueueItem') 14 | 15 | 16 | async def queue_get_batch( 17 | queue: 'Queue[TQueueItem]', 18 | max_results: int = None) -> Tuple[TQueueItem, ...]: 19 | """ 20 | Wait until at least one result is available, and return it and any 21 | other results that are immediately available, up to max_results. 22 | """ 23 | if max_results is not None and max_results < 1: 24 | raise ValidationError("Must request at least one item from a queue, not {max_results!r}") 25 | 26 | # if the queue is empty, wait until at least one item is available 27 | if queue.empty(): 28 | first_item = await queue.get() 29 | else: 30 | first_item = queue.get_nowait() 31 | 32 | # In order to return from queue_get_batch() as soon as possible, never await again. 33 | # Instead, take only the items that are already available. 34 | if max_results is None: 35 | remaining_count = None 36 | else: 37 | remaining_count = max_results - 1 38 | remaining_items = queue_get_nowait(queue, remaining_count) 39 | 40 | # Combine the first and remaining items 41 | return (first_item, ) + remaining_items 42 | 43 | 44 | def queue_get_nowait(queue: 'Queue[TQueueItem]', max_results: int = None) -> Tuple[TQueueItem, ...]: 45 | # How many results do we want? 46 | available = queue.qsize() 47 | if max_results is None: 48 | num_items = available 49 | else: 50 | num_items = min((available, max_results)) 51 | 52 | return tuple(queue.get_nowait() for _ in range(num_items)) 53 | -------------------------------------------------------------------------------- /tests/core/fixtures.py: -------------------------------------------------------------------------------- 1 | from eth_utils import ( 2 | decode_hex, 3 | ) 4 | 5 | 6 | # This block is a child of the genesis defined in the chain fixture above and contains a single tx 7 | # that transfers 10 wei from 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b to 8 | # 0x095e7baea6a6c7c4c2dfeb977efac326af552d87. 9 | valid_block_rlp = decode_hex( 10 | "0x" 11 | "f90260f901f9a07285abd5b24742f184ad676e31f6054663b3529bc35ea2fcad" 12 | "8a3e0f642a46f7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413" 13 | "f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0964e" 14 | "6c9995e7e3757e934391b4f16b50c20409ee4eb9abd4c4617cb805449b9aa053" 15 | "d5b71a8fbb9590de82d69dfa4ac31923b0c8afce0d30d0d8d1e931f25030dca0" 16 | "bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52" 17 | "b901000000000000000000000000000000000000000000000000000000000000" 18 | "0000000000000000000000000000000000000000000000000000000000000000" 19 | "0000000000000000000000000000000000000000000000000000000000000000" 20 | "0000000000000000000000000000000000000000000000000000000000000000" 21 | "0000000000000000000000000000000000000000000000000000000000000000" 22 | "0000000000000000000000000000000000000000000000000000000000000000" 23 | "0000000000000000000000000000000000000000000000000000000000000000" 24 | "0000000000000000000000000000000000000000000000000000000000000000" 25 | "0000008302000001832fefd8825208845754132380a0194605bacef646779359" 26 | "318c7b5899559a5bf4074bbe2cfb7e1b83b1504182dd88e0205813b22e5a9cf8" 27 | "61f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801b" 28 | "a0f3266921c93d600c43f6fa4724b7abae079b35b9e95df592f95f9f3445e94c" 29 | "88a012f977552ebdb7a492cf35f3106df16ccb4576ebad4113056ee1f52cbe49" 30 | "78c1c0" 31 | ) 32 | -------------------------------------------------------------------------------- /tests/database/test_leveldb_db_backend.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from eth.db.backends.memory import MemoryDB 4 | from eth.db.atomic import AtomicDB 5 | from eth.db import ( 6 | get_db_backend, 7 | ) 8 | 9 | 10 | pytest.importorskip('leveldb') 11 | 12 | 13 | # Sets db backend to leveldb 14 | @pytest.fixture 15 | def config_env(monkeypatch): 16 | monkeypatch.setenv('CHAIN_DB_BACKEND_CLASS', 17 | 'eth.db.backends.level.LevelDB') 18 | 19 | 20 | @pytest.fixture 21 | def level_db(config_env, tmpdir): 22 | level_db_path = str(tmpdir.mkdir("level_db_path")) 23 | return get_db_backend(db_path=level_db_path) 24 | 25 | 26 | @pytest.fixture 27 | def memory_db(): 28 | return MemoryDB() 29 | 30 | 31 | @pytest.fixture 32 | def atomic_db(): 33 | return AtomicDB() 34 | 35 | 36 | def test_raises_if_db_path_is_not_specified(config_env): 37 | with pytest.raises(TypeError): 38 | get_db_backend() 39 | 40 | 41 | def test_set_and_get(memory_db, level_db): 42 | level_db.set(b'1', b'1') 43 | memory_db.set(b'1', b'1') 44 | assert level_db.get(b'1') == memory_db.get(b'1') 45 | 46 | 47 | def test_set_on_existing_value(level_db, memory_db): 48 | level_db.set(b'1', b'2') 49 | level_db.set(b'1', b'3') 50 | memory_db.set(b'1', b'2') 51 | memory_db.set(b'1', b'3') 52 | assert level_db.get(b'1') == memory_db.get(b'1') 53 | 54 | 55 | def test_exists(level_db, memory_db): 56 | level_db.set(b'1', b'2') 57 | memory_db.set(b'1', b'1') 58 | level_db.exists(b'1') == memory_db.exists(b'1') 59 | 60 | 61 | def test_delete(level_db, memory_db): 62 | level_db.set(b'1', b'1') 63 | memory_db.set(b'1', b'1') 64 | level_db.delete(b'1') 65 | memory_db.delete(b'1') 66 | assert level_db.exists(b'1') == memory_db.exists(b'1') 67 | --------------------------------------------------------------------------------