def test_uncle_block_inclusion_validity(vm_fn): # This test ensures that a forked block which is behind by # more than 6 layers cannot act as an ancestor to the current block OTHER_MINER_ADDRESS = 20 * b'\x01' chain = build( MiningChain, vm_fn(0), disable_pow_check(), genesis(), mine_block(), # 1 mine_block(), # 2 ) fork_chain = build( chain, at_block_number(1), mine_block(extra_data=b'fork-it!', coinbase=OTHER_MINER_ADDRESS), # fork 2 ) # we don't use canonical head here because the fork chain is non-canonical. uncle = fork_chain.get_block_header_by_hash(fork_chain.header.parent_hash) assert uncle.block_number == 2 with pytest.raises(ValidationError): chain = build( chain, # Mines blocks from 3 to 8 (both numbers inclusive) mine_blocks(6), # Mine block 9 with uncle mine_block(uncles=[uncle]), )
def test_chain_builder_initialize_chain_default(chain_class): chain = pipe( chain_class, genesis(), ) header = chain.get_canonical_head() assert header == chain.get_canonical_block_by_number(0).header assert header.parent_hash == constants.GENESIS_PARENT_HASH assert header.uncles_hash == constants.EMPTY_UNCLE_HASH assert header.coinbase == constants.GENESIS_COINBASE assert header.state_root == constants.BLANK_ROOT_HASH assert header.transaction_root == constants.BLANK_ROOT_HASH assert header.receipt_root == constants.BLANK_ROOT_HASH assert header.bloom == 0 assert header.difficulty == 1 assert header.block_number == constants.GENESIS_BLOCK_NUMBER assert header.gas_limit == constants.GENESIS_GAS_LIMIT assert header.gas_used == 0 # account for runtime. should run in less than few seconds and should be # effectively "now" assert abs(header.timestamp - time.time()) < 2 assert header.extra_data == constants.GENESIS_EXTRA_DATA assert header.mix_hash == constants.GENESIS_MIX_HASH assert header.nonce == constants.GENESIS_NONCE
def test_chain_builder_initialize_chain_with_params(chain_class): chain = pipe(chain_class, genesis(params={'difficulty': 12345}, )) header = chain.get_canonical_head() assert header == chain.get_canonical_block_by_number(0).header assert header.difficulty == 12345
def get_chain(vm: Type[BaseVM], genesis_state: GenesisState) -> MiningChain: chain = build(MiningChain, fork_at(vm, constants.GENESIS_BLOCK_NUMBER), disable_pow_check(), genesis(params=GENESIS_PARAMS, state=genesis_state)) return chain
def test_eip1559_txn_rewards(max_total_price, max_priority_price, expected_miner_tips, funded_address, funded_address_private_key): chain = build( MiningChain, berlin_at(0), london_at(1), # Start London at block one to get easy 1gwei base fee disable_pow_check(), genesis( params=dict(gas_limit=10**7), state={funded_address: dict(balance=10**20)}, ), ) vm = chain.get_vm() txn = new_dynamic_fee_transaction( vm, from_=funded_address, to=funded_address, private_key=funded_address_private_key, max_priority_fee_per_gas=max_priority_price, max_fee_per_gas=max_total_price, ) MINER = b'\x0f' * 20 original_balance = vm.state.get_balance(MINER) chain.mine_all([txn], coinbase=MINER) new_balance = chain.get_vm().state.get_balance(MINER) BLOCK_REWARD = 2 * (10**18) assert original_balance + BLOCK_REWARD + expected_miner_tips == new_balance
def test_chain_builder_without_any_mining_config(): chain = build( MiningChain, frontier_at(0), genesis(), ) with pytest.raises(ValidationError, match='mix hash mismatch'): chain.mine_block()
def bob_chain(): chain = build( MiningChain, latest_mainnet_at(0), disable_pow_check(), genesis(), ) return chain
def test_chain_builder_enable_pow_mining(): chain = build( MiningChain, frontier_at(0), enable_pow_mining(), genesis(), ) block = chain.mine_block() check_eccpow(block.header.parent_hash, block.header.mining_hash, 24, 3, 6)
def test_chain_builder_initialize_chain_with_state_simple(chain_class): chain = pipe(chain_class, genesis(state=((ADDRESS_A, 'balance', 1), ), )) header = chain.get_canonical_head() assert header == chain.get_canonical_block_by_number(0).header assert header.state_root != constants.BLANK_ROOT_HASH state = chain.get_vm().state assert state.get_balance(ADDRESS_A) == 1
def mining_chain_params(funded_address): return ( MiningChain, frontier_at(0), disable_pow_check, genesis(params={'gas_limit': 1000000}, state={funded_address: { 'balance': to_wei(1000, 'ether') }}), )
def alice_chain(bob_chain): bob_genesis = bob_chain.headerdb.get_canonical_block_header_by_number(0) chain = build( MiningChain, latest_mainnet_at(0), disable_pow_check(), genesis(params={"timestamp": bob_genesis.timestamp}), ) return chain
def test_rewards_nephew_uncle_different_vm(vm_fn_uncle, vm_fn_nephew, miner_1_balance, miner_2_balance): OTHER_MINER_ADDRESS = 20 * b'\x01' TOTAL_BLOCKS_CANONICAL_CHAIN = 10 VM_CHANGE_BLOCK_NUMBER = 4 chain = build( MiningChain, vm_fn_uncle(0), vm_fn_nephew(VM_CHANGE_BLOCK_NUMBER), disable_pow_check(), genesis(), mine_blocks(TOTAL_BLOCKS_CANONICAL_CHAIN - 1), ) fork_chain = build( chain, at_block_number(3), mine_block(extra_data=b'fork-it!', coinbase=OTHER_MINER_ADDRESS), # fork 2 ) # we don't use canonical head here because the fork chain is non-canonical. uncle = fork_chain.get_block_header_by_hash(fork_chain.header.parent_hash) assert uncle.block_number == 4 chain = build( chain, mine_block(uncles=[uncle]), ) header = chain.get_canonical_head() block = chain.get_block_by_hash(header.hash) assert len(block.uncles) == 1 assert block.uncles[0] == uncle vm = chain.get_vm() coinbase_balance = vm.state.get_balance(block.header.coinbase) other_miner_balance = vm.state.get_balance(uncle.coinbase) uncle_vm = chain.get_vm_class_for_block_number(0) nephew_vm = chain.get_vm_class_for_block_number(VM_CHANGE_BLOCK_NUMBER) # We first test if the balance matches what we would determine # if we made all the API calls involved ourselves. assert coinbase_balance == (uncle_vm.get_block_reward() * 3 + nephew_vm.get_block_reward() * (TOTAL_BLOCKS_CANONICAL_CHAIN - 3) + vm.get_nephew_reward()) assert other_miner_balance == vm.get_uncle_reward(block.number, uncle) # But we also ensure the balance matches the numbers that we calculated on paper assert coinbase_balance == to_wei(miner_1_balance, 'ether') assert other_miner_balance == to_wei(miner_2_balance, 'ether')
def test_mining_tools_proof_of_work_mining(base_vm_class): vm_class = type(base_vm_class.__name__, (POWMiningMixin, base_vm_class), {}) class ChainClass(MiningChain): vm_configuration = ((0, vm_class), ) chain = genesis(ChainClass) block = chain.mine_block() check_eccpow(block.header.parent_hash, block.header.mining_hash, 24, 3, 6)
def get_chain(vm: Type[VirtualMachineAPI], genesis_state: GenesisState) -> Iterable[MiningChain]: with tempfile.TemporaryDirectory() as temp_dir: level_db_obj = LevelDB(Path(temp_dir)) level_db_chain = build( MiningChain, fork_at(vm, constants.GENESIS_BLOCK_NUMBER), disable_pow_check(), genesis(db=level_db_obj, params=GENESIS_PARAMS, state=genesis_state)) yield level_db_chain
def _create(cls, model_class: Type[AsyncHeaderDB], *args: Any, **kwargs: Any) -> AsyncHeaderDB: headerdb = model_class(*args, **kwargs) from eth.chains.base import Chain from eth.tools.builder.chain import build, latest_mainnet_at, genesis build( Chain, latest_mainnet_at(0), genesis(db=headerdb.db), ) return headerdb
def test_chain_builder_initialize_chain_with_state_multiple(chain_class): chain = pipe( chain_class, genesis(state=((ADDRESS_A, 'balance', 1), (ADDRESS_B, 'balance', 2)), )) header = chain.get_canonical_head() assert header == chain.get_canonical_block_by_number(0).header assert header.state_root != constants.BLANK_ROOT_HASH account_db = chain.get_vm().state.account_db assert account_db.get_balance(ADDRESS_A) == 1 assert account_db.get_balance(ADDRESS_B) == 2
def _create(cls, model_class: Type[AsyncHeaderDB], *args: Any, **kwargs: Any) -> AsyncHeaderDB: from eth.chains.base import Chain from eth.tools.builder.chain import build, latest_mainnet_at, genesis genesis_params = kwargs.pop('genesis_params', None) headerdb = model_class(*args, **kwargs) build( Chain, latest_mainnet_at(0), genesis(db=headerdb.db, params=genesis_params), ) return headerdb
def test_chain_builder_enable_pow_mining(): chain = build( MiningChain, frontier_at(0), enable_pow_mining(), genesis(), ) block = chain.mine_block() check_pow( block.number, block.header.mining_hash, block.header.mix_hash, block.header.nonce, block.header.difficulty, )
def test_chain_builder_disable_pow_check(): chain = build( MiningChain, frontier_at(0), disable_pow_check(), genesis(), ) block = chain.mine_block() with pytest.raises(ValidationError, match='mix hash mismatch'): check_pow( block.number, block.header.mining_hash, block.header.mix_hash, block.header.nonce, block.header.difficulty, )
def test_chain_builder_disable_pow_check(): chain = build( MiningChain, frontier_at(0), disable_pow_check(), genesis(), ) block = chain.mine_block() # check_eccpow( # block.header.parent_hash, # block.header.mining_hash, # 24, 3, 6) with pytest.raises(ValidationError, match='mix hash mismatch'): # ToDo: Have to change difficulty check_eccpow(block.header.parent_hash, block.header.mining_hash, 24, 3, 6)
def test_rewards_uncle_created_at_different_generations( vm_fn, fork_at_block_number, miner_1_balance, miner_2_balance): OTHER_MINER_ADDRESS = 20 * b'\x01' TOTAL_BLOCKS_CANONICAL_CHAIN = 10 chain = build( MiningChain, vm_fn(0), disable_pow_check(), genesis(), mine_blocks(TOTAL_BLOCKS_CANONICAL_CHAIN - 1), ) fork_chain = build( chain, at_block_number(fork_at_block_number), mine_block(extra_data=b'fork-it!', coinbase=OTHER_MINER_ADDRESS), # fork 2 ) # we don't use canonical head here because the fork chain is non-canonical. uncle = fork_chain.get_block_header_by_hash(fork_chain.header.parent_hash) assert uncle.block_number == fork_at_block_number + 1 chain = build( chain, mine_block(uncles=[uncle]), ) header = chain.get_canonical_head() block = chain.get_block_by_hash(header.hash) vm = chain.get_vm() coinbase_balance = vm.state.account_db.get_balance(block.header.coinbase) other_miner_balance = vm.state.account_db.get_balance(uncle.coinbase) # We first test if the balance matches what we would determine # if we made all the API calls involved ourselves. assert coinbase_balance == ( vm.get_block_reward() * TOTAL_BLOCKS_CANONICAL_CHAIN + vm.get_nephew_reward()) assert other_miner_balance == vm.get_uncle_reward(block.number, uncle) # But we also ensure the balance matches the numbers that we calculated on paper assert coinbase_balance == to_wei(miner_1_balance, 'ether') assert other_miner_balance == to_wei(miner_2_balance, 'ether')
def test_chain_builder_initialize_chain_with_params_and_state(chain_class): chain = pipe( chain_class, genesis( params={'difficulty': 12345}, state=((ADDRESS_A, 'balance', 1), ), )) header = chain.get_canonical_head() assert header == chain.get_canonical_block_by_number(0).header assert header.difficulty == 12345 assert header.state_root != constants.BLANK_ROOT_HASH state = chain.get_vm().state assert state.get_balance(ADDRESS_A) == 1
def test_mining_tools_proof_of_work_mining(base_vm_class): vm_class = type(base_vm_class.__name__, (POWMiningMixin, base_vm_class), {}) class ChainClass(MiningChain): vm_configuration = ((0, vm_class), ) chain = genesis(ChainClass) block = chain.mine_block() check_pow( block.number, block.header.mining_hash, block.header.mix_hash, block.header.nonce, block.header.difficulty, )
def _create(cls, model_class: Type[AsyncHeaderDB], *args: Any, **kwargs: Any) -> AsyncHeaderDB: from eth.chains.base import Chain from eth.tools.builder.chain import build, latest_mainnet_at, genesis genesis_params = kwargs.pop('genesis_params', None) headerdb = model_class(*args, **kwargs) # SIDE EFFECT! # This uses the side effect of initializing a chain using the `builder` # tool to populate the genesis state into the database. build( Chain, latest_mainnet_at(0), genesis(db=headerdb.db, params=genesis_params), ) return headerdb
def load_mining_chain(db): GENESIS_PARAMS = { 'coinbase': constants.ZERO_ADDRESS, 'difficulty': 5, 'gas_limit': 3141592, 'timestamp': 1514764800, } GENESIS_STATE = { FUNDED_ACCT.public_key.to_canonical_address(): { "balance": 100000000000000000, } } return build( FakeAsyncChain, byzantium_at(0), enable_pow_mining(), genesis(db=db, params=GENESIS_PARAMS, state=GENESIS_STATE), )
def load_mining_chain(db, *chain_builder_fns): GENESIS_PARAMS = { 'coinbase': ZERO_ADDRESS, 'difficulty': 5, 'gas_limit': 3141592, 'timestamp': 1514764800, } GENESIS_STATE = { FUNDED_ACCT.public_key.to_canonical_address(): { "balance": 100000000000000000, } } chain_builder_fns = (latest_mainnet_at(0),) if not chain_builder_fns else chain_builder_fns return build( AsyncMiningChain, *chain_builder_fns, enable_pow_mining(), genesis(db=db, params=GENESIS_PARAMS, state=GENESIS_STATE), )
genesis(params={'gas_limit': 1000000}, state={funded_address: { 'balance': to_wei(1000, 'ether') }}), ) @pytest.fixture def mining_chain(mining_chain_params): return build(*mining_chain_params) REGULAR_CHAIN_PARAMS = ( Chain, frontier_at(0), genesis(), ) @pytest.fixture def regular_chain(): return build(*REGULAR_CHAIN_PARAMS) def test_chain_builder_build_single_default_block(mining_chain): chain = build( mining_chain, mine_block(), ) header = chain.get_canonical_head()