diff --git a/eth/db/chain.py b/eth/db/chain.py index fa480d18dd..e5a135bbf5 100644 --- a/eth/db/chain.py +++ b/eth/db/chain.py @@ -75,10 +75,6 @@ class TransactionKey(rlp.Serializable): class BaseChainDB(BaseHeaderDB): db: BaseAtomicDB = None - @abstractmethod - def __init__(self, db: BaseAtomicDB) -> None: - raise NotImplementedError("ChainDB classes must implement this method") - # # Header API # @@ -166,9 +162,6 @@ def persist_trie_data_dict(self, trie_data_dict: Dict[Hash32, bytes]) -> None: class ChainDB(HeaderDB, BaseChainDB): - def __init__(self, db: BaseAtomicDB) -> None: - self.db = db - # # Header API # diff --git a/eth/db/header.py b/eth/db/header.py index 8e35f5f648..d1f107796b 100644 --- a/eth/db/header.py +++ b/eth/db/header.py @@ -33,7 +33,7 @@ BaseAtomicDB, BaseDB, ) -from eth.db.schema import SchemaV1 +from eth.db.schema import SchemaV1, Schemas, ensure_schema from eth.rlp.headers import BlockHeader from eth.validation import ( validate_block_number, @@ -44,8 +44,12 @@ class BaseHeaderDB(ABC): db: BaseAtomicDB = None - def __init__(self, db: BaseAtomicDB) -> None: + def __init__(self, db: BaseAtomicDB, + expected_schema: Schemas = Schemas.DEFAULT) -> None: self.db = db + self.schema = expected_schema + + ensure_schema(db, expected_schema) # # Canonical Chain API diff --git a/eth/db/schema.py b/eth/db/schema.py index 05e868b97c..1efab2c65b 100644 --- a/eth/db/schema.py +++ b/eth/db/schema.py @@ -1,4 +1,12 @@ from abc import ABC, abstractmethod +from enum import Enum + +from eth.exceptions import ( + SchemaDoesNotMatchError, + SchemaNotRecognizedError, +) + +from eth.db.backends.base import BaseDB from eth_typing import ( BlockNumber, @@ -6,6 +14,11 @@ ) +class Schemas(Enum): + DEFAULT = b'default' + TURBO = b'turbo' + + class BaseSchema(ABC): @staticmethod @abstractmethod @@ -45,3 +58,29 @@ def make_block_hash_to_score_lookup_key(block_hash: Hash32) -> bytes: @staticmethod def make_transaction_hash_to_block_lookup_key(transaction_hash: Hash32) -> bytes: return b'transaction-hash-to-block:%s' % transaction_hash + + +class SchemaTurbo(SchemaV1): + current_schema_lookup_key: bytes = b'current-schema' + + +def get_schema(db: BaseDB) -> Schemas: + try: + current_schema = db[SchemaTurbo.current_schema_lookup_key] + except KeyError: + return Schemas.DEFAULT + + try: + return Schemas(current_schema) + except ValueError: + raise SchemaNotRecognizedError(current_schema) + + +def set_schema(db: BaseDB, schema: Schemas) -> None: + db.set(SchemaTurbo.current_schema_lookup_key, schema.value) + + +def ensure_schema(db: BaseDB, expected_schema: Schemas) -> None: + reported_schema = get_schema(db) + if reported_schema != expected_schema: + raise SchemaDoesNotMatchError(reported_schema) diff --git a/eth/exceptions.py b/eth/exceptions.py index 87c0775618..6287ec687c 100644 --- a/eth/exceptions.py +++ b/eth/exceptions.py @@ -8,6 +8,18 @@ class PyEVMError(Exception): pass +class SchemaNotRecognizedError(PyEVMError): + """ + The database uses a schema which this version of py-evm does not support. + """ + + +class SchemaDoesNotMatchError(PyEVMError): + """ + The database schema does not match the expected schema. It might need to be migrated. + """ + + class VMNotFound(PyEVMError): """ Raised when no VM is available for the provided block number. diff --git a/eth/vm/state.py b/eth/vm/state.py index d3600cd403..d691bc2c54 100644 --- a/eth/vm/state.py +++ b/eth/vm/state.py @@ -29,6 +29,7 @@ from eth.db.backends.base import ( BaseAtomicDB, ) +from eth.db.schema import ensure_schema, Schemas from eth.exceptions import StateRootNotFound from eth.tools.logging import ( ExtendedDebugLogger, @@ -86,11 +87,14 @@ def __init__( self, db: BaseAtomicDB, execution_context: ExecutionContext, - state_root: bytes) -> None: + state_root: bytes, + expected_schema: Schemas = Schemas.DEFAULT) -> None: self._db = db self.execution_context = execution_context self._account_db = self.get_account_db_class()(db, state_root) + ensure_schema(db, expected_schema) + # # Logging #