예제 #1
0
    def from_genesis(cls,
                     base_db: AtomicDatabaseAPI,
                     genesis_params: Dict[str, HeaderParams],
                     genesis_state: AccountState=None) -> 'BaseChain':
        genesis_vm_class = cls.get_vm_class_for_block_number(BlockNumber(0))

        pre_genesis_header = BlockHeader(difficulty=0, block_number=-1, gas_limit=0)
        chain_context = ChainContext(cls.chain_id)
        state = genesis_vm_class.build_state(base_db, pre_genesis_header, chain_context)

        if genesis_state is None:
            genesis_state = {}

        # mutation
        apply_state_dict(state, genesis_state)
        state.persist()

        if 'state_root' not in genesis_params:
            # If the genesis state_root was not specified, use the value
            # computed from the initialized state database.
            genesis_params = assoc(genesis_params, 'state_root', state.state_root)
        elif genesis_params['state_root'] != state.state_root:
            # If the genesis state_root was specified, validate that it matches
            # the computed state from the initialized state database.
            raise ValidationError(
                "The provided genesis state root does not match the computed "
                f"genesis state root.  Got {state.state_root!r}.  "
                f"Expected {genesis_params['state_root']!r}"
            )

        genesis_header = BlockHeader(**genesis_params)
        return cls.from_genesis_header(base_db, genesis_header)
예제 #2
0
def setup_computation(vm_class,
                      create_address,
                      code,
                      chain_id=None,
                      gas=1000000,
                      to=CANONICAL_ADDRESS_A,
                      data=b''):

    message = Message(
        to=to,
        sender=CANONICAL_ADDRESS_B,
        create_address=create_address,
        value=0,
        data=data,
        code=code,
        gas=gas,
    )

    chain_context = ChainContext(chain_id)

    tx_context = vm_class._state_class.transaction_context_class(
        gas_price=1,
        origin=CANONICAL_ADDRESS_B,
    )

    vm = vm_class(GENESIS_HEADER, ChainDB(AtomicDB()), chain_context)

    computation = vm_class._state_class.computation_class(
        state=vm.state,
        message=message,
        transaction_context=tx_context,
    )

    return computation
예제 #3
0
def initialize_vm_and_state(state_test):
    account_state = decode_account_state(state_test["pre"])
    # print(account_state)

    base_db = AtomicDB()
    chain = MainnetChain(base_db)

    pre_genesis_header = BlockHeader(difficulty=0,
                                     block_number=-1,
                                     gas_limit=0)
    chain_context = ChainContext(MAINNET_CHAIN_ID)
    state = IstanbulVM.build_state(base_db, pre_genesis_header, chain_context)

    # apply custom state
    apply_state_dict(state, account_state)
    state.persist()

    # print("initial state", encode_hex(state.make_state_root()))

    current_block_params = decode_current_block_params(state_test["env"])
    current_block_header = BlockHeader(**current_block_params)

    # vm = chain.get_vm()
    vm = IstanbulVM(
        header=pre_genesis_header,
        chaindb=chain.chaindb,
        chain_context=chain_context,
        consensus_context=chain.consensus_context,
    )

    return vm, state, current_block_header
예제 #4
0
    def get_vm(self, at_header: BlockHeaderAPI = None) -> VirtualMachineAPI:
        header = self.ensure_header(at_header)
        vm_class = self.get_vm_class_for_block_number(header.block_number)
        chain_context = ChainContext(self.chain_id)

        return vm_class(header=header,
                        chaindb=self.chaindb,
                        chain_context=chain_context,
                        consensus_context=self.consensus_context)
예제 #5
0
def setup_vm(vm_class, chain_id=None):
    db = AtomicDB()
    chain_context = ChainContext(chain_id)
    genesis_header = vm_class.create_genesis_header(
        difficulty=constants.GENESIS_DIFFICULTY,
        timestamp=0,
    )
    return vm_class(genesis_header, ChainDB(db), chain_context,
                    ConsensusContext(db))
예제 #6
0
def instantiate_vm(vm_class):
  GENESIS_HEADER = BlockHeader(
    difficulty=17179869184,
    block_number=BlockNumber(0),
    gas_limit=5000,
  )
  chain_context = ChainContext(None)
  db = AtomicDB()
  return vm_class(GENESIS_HEADER, ChainDB(db), chain_context, ConsensusContext(db))
예제 #7
0
 def get_vm(self, at_header: BlockHeaderAPI = None) -> VirtualMachineAPI:
     """
     Returns the VM instance for the given block number.
     """
     header = self.ensure_header(at_header)
     vm_class = self.get_vm_class_for_block_number(header.block_number)
     chain_context = ChainContext(self.chain_id)
     return vm_class(header=header,
                     chaindb=self.chaindb,
                     chain_context=chain_context)
예제 #8
0
def test_mainnet_dao_fork_header_validation(VM, header, previous_header,
                                            valid):
    chain_db = FakeChainDB({})
    consensus_context = ConsensusContext(chain_db.db)
    vm = VM(header=previous_header,
            chaindb=chain_db,
            chain_context=ChainContext(1),
            consensus_context=consensus_context)
    if valid:
        vm.validate_header(header, previous_header, check_seal=True)
    else:
        try:
            vm.validate_header(header, previous_header, check_seal=True)
        except ValidationError:
            pass
        else:
            assert False, "The invalid header %r must fail" % header
def test_vm_fixtures(fixture, vm_class, computation_getter):
    db = get_db_backend()
    chaindb = ChainDB(db)
    consensus_context = ConsensusContext(db)
    header = BlockHeader(
        coinbase=fixture['env']['currentCoinbase'],
        difficulty=fixture['env']['currentDifficulty'],
        block_number=fixture['env']['currentNumber'],
        gas_limit=fixture['env']['currentGasLimit'],
        timestamp=fixture['env']['currentTimestamp'],
    )

    # None of the VM tests (currently) test chain ID, so the setting doesn't matter here.
    #   When they *do* start testing ID, they will have to supply it as part of the environment.
    #   For now, just hard-code it to something not used in practice:
    chain_context = ChainContext(chain_id=0)

    vm = vm_class(header=header,
                  chaindb=chaindb,
                  chain_context=chain_context,
                  consensus_context=consensus_context)
    state = vm.state
    setup_state(fixture['pre'], state)
    code = state.get_code(fixture['exec']['address'])
    # Update state_root manually
    vm._block = vm.get_block().copy(header=vm.get_header().copy(
        state_root=state.state_root))

    message = Message(
        to=fixture['exec']['address'],
        sender=fixture['exec']['caller'],
        value=fixture['exec']['value'],
        data=fixture['exec']['data'],
        code=code,
        gas=fixture['exec']['gas'],
    )
    transaction_context = BaseTransactionContext(
        origin=fixture['exec']['origin'],
        gas_price=fixture['exec']['gasPrice'],
    )
    computation = vm.state.get_computation(
        message, transaction_context).apply_computation(
            vm.state,
            message,
            transaction_context,
        )
    # Update state_root manually
    vm._block = vm.get_block().copy(
        header=vm.get_header().copy(state_root=computation.state.state_root), )

    if 'post' in fixture:
        #
        # Success checks
        #
        assert not computation.is_error

        log_entries = computation.get_log_entries()
        if 'logs' in fixture:
            actual_logs_hash = hash_log_entries(log_entries)
            expected_logs_hash = fixture['logs']
            assert expected_logs_hash == actual_logs_hash
        elif log_entries:
            raise AssertionError(f"Got log entries: {log_entries}")

        expected_output = fixture['out']
        assert computation.output == expected_output

        gas_meter = computation._gas_meter

        expected_gas_remaining = fixture['gas']
        actual_gas_remaining = gas_meter.gas_remaining
        gas_delta = actual_gas_remaining - expected_gas_remaining
        assert gas_delta == 0, f"Gas difference: {gas_delta}"

        call_creates = fixture.get('callcreates', [])
        assert len(computation.children) == len(call_creates)

        call_creates = fixture.get('callcreates', [])
        for child_computation, created_call in zip(computation.children,
                                                   call_creates):
            to_address = created_call['destination']
            data = created_call['data']
            gas_limit = created_call['gasLimit']
            value = created_call['value']

            assert child_computation.msg.to == to_address
            assert data == child_computation.msg.data or child_computation.msg.code
            assert gas_limit == child_computation.msg.gas
            assert value == child_computation.msg.value
        expected_account_db = fixture['post']
    else:
        #
        # Error checks
        #
        assert computation.is_error
        assert isinstance(computation._error, VMError)
        expected_account_db = fixture['pre']

    verify_state(expected_account_db, vm.state)
예제 #10
0
def setup_vm(vm_class, chain_id=None):
    db = AtomicDB()
    chain_context = ChainContext(chain_id)
    return vm_class(GENESIS_HEADER, ChainDB(db), chain_context,
                    ConsensusContext(db))