diff --git a/package-lock.json b/package-lock.json
index 10afaee7d7..5efec9040d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13361,13 +13361,6 @@
       "version": "2.0.2",
       "license": "MIT"
     },
-    "node_modules/semaphore-async-await": {
-      "version": "1.5.1",
-      "license": "MIT",
-      "engines": {
-        "node": ">=4.1"
-      }
-    },
     "node_modules/semver": {
       "version": "6.3.0",
       "dev": true,
@@ -15714,8 +15707,7 @@
         "ethereum-cryptography": "^1.1.2",
         "level": "^8.0.0",
         "lru-cache": "^5.1.1",
-        "memory-level": "^1.0.0",
-        "semaphore-async-await": "^1.5.1"
+        "memory-level": "^1.0.0"
       },
       "devDependencies": {
         "@types/async": "^2.4.1",
@@ -17283,8 +17275,7 @@
         "ethereum-cryptography": "^1.1.2",
         "level": "^8.0.0",
         "lru-cache": "^5.1.1",
-        "memory-level": "^1.0.0",
-        "semaphore-async-await": "^1.5.1"
+        "memory-level": "^1.0.0"
       }
     },
     "@ethereumjs/client": {
@@ -25537,9 +25528,6 @@
         }
       }
     },
-    "semaphore-async-await": {
-      "version": "1.5.1"
-    },
     "semver": {
       "version": "6.3.0",
       "dev": true
diff --git a/packages/block/src/block.ts b/packages/block/src/block.ts
index 0916e3b6f9..24647eea7b 100644
--- a/packages/block/src/block.ts
+++ b/packages/block/src/block.ts
@@ -224,10 +224,10 @@ export class Block {
       return result
     }
 
-    if (this.txTrie.root.equals(KECCAK256_RLP)) {
+    if (this.txTrie.root().equals(KECCAK256_RLP)) {
       await this.genTxTrie()
     }
-    result = this.txTrie.root.equals(this.header.transactionsTrie)
+    result = this.txTrie.root().equals(this.header.transactionsTrie)
     return result
   }
 
diff --git a/packages/blockchain/package.json b/packages/blockchain/package.json
index 14d883b10d..3d9bef61fc 100644
--- a/packages/blockchain/package.json
+++ b/packages/blockchain/package.json
@@ -49,8 +49,7 @@
     "ethereum-cryptography": "^1.1.2",
     "level": "^8.0.0",
     "lru-cache": "^5.1.1",
-    "memory-level": "^1.0.0",
-    "semaphore-async-await": "^1.5.1"
+    "memory-level": "^1.0.0"
   },
   "devDependencies": {
     "@types/async": "^2.4.1",
diff --git a/packages/blockchain/src/blockchain.ts b/packages/blockchain/src/blockchain.ts
index 8d3ca5f0bd..608a7444d2 100644
--- a/packages/blockchain/src/blockchain.ts
+++ b/packages/blockchain/src/blockchain.ts
@@ -2,13 +2,13 @@ import { Block, BlockHeader } from '@ethereumjs/block'
 import { Chain, Common, ConsensusAlgorithm, ConsensusType, Hardfork } from '@ethereumjs/common'
 import { isFalsy, isTruthy } from '@ethereumjs/util'
 import { MemoryLevel } from 'memory-level'
-import Semaphore from 'semaphore-async-await'
 
 import { CasperConsensus, CliqueConsensus, EthashConsensus } from './consensus'
 import { DBOp, DBSaveLookups, DBSetBlockOrHeader, DBSetHashToNumber, DBSetTD } from './db/helpers'
 import { DBManager } from './db/manager'
 import { DBTarget } from './db/operation'
 import { genesisStateRoot } from './genesisStates'
+import { Semaphore } from './semaphore'
 
 import type { Consensus } from './consensus'
 import type { GenesisState } from './genesisStates'
diff --git a/packages/blockchain/src/genesisStates/index.ts b/packages/blockchain/src/genesisStates/index.ts
index 53a0c1ea0f..2e637899d7 100644
--- a/packages/blockchain/src/genesisStates/index.ts
+++ b/packages/blockchain/src/genesisStates/index.ts
@@ -21,7 +21,7 @@ export interface GenesisState {
  * Derives the stateRoot of the genesis block based on genesis allocations
  */
 export async function genesisStateRoot(genesisState: GenesisState) {
-  const trie = new Trie({ useHashedKeys: true })
+  const trie = new Trie({ useKeyHashing: true })
   for (const [key, value] of Object.entries(genesisState)) {
     const address = isHexPrefixed(key) ? toBuffer(key) : Buffer.from(key, 'hex')
     const account = new Account()
@@ -48,10 +48,10 @@ export async function genesisStateRoot(genesisState: GenesisState) {
           )
           await storageTrie.put(storageKey, storageVal)
         }
-        account.storageRoot = storageTrie.root
+        account.storageRoot = storageTrie.root()
       }
     }
     await trie.put(address, account.serialize())
   }
-  return trie.root
+  return trie.root()
 }
diff --git a/packages/blockchain/src/semaphore.ts b/packages/blockchain/src/semaphore.ts
new file mode 100644
index 0000000000..202cac6c06
--- /dev/null
+++ b/packages/blockchain/src/semaphore.ts
@@ -0,0 +1,52 @@
+// Based on https://github.com/jsoendermann/semaphore-async-await/blob/master/src/Semaphore.ts
+export class Semaphore {
+  private permits: number
+  private promiseResolverQueue: Array<(v: boolean) => void> = []
+
+  /**
+   * Creates a semaphore.
+   * @param permits  The number of permits, i.e. strands of execution being allowed
+   * to run in parallel.
+   * This number can be initialized with a negative integer.
+   */
+  constructor(permits: number) {
+    this.permits = permits
+  }
+
+  /**
+   * Returns a promise used to wait for a permit to become available. This method should be awaited on.
+   * @returns  A promise that gets resolved when execution is allowed to proceed.
+   */
+  public async acquire(): Promise<boolean> {
+    if (this.permits > 0) {
+      this.permits -= 1
+      return Promise.resolve(true)
+    }
+
+    // If there is no permit available, we return a promise that resolves once the semaphore gets
+    // signaled enough times that permits is equal to one.
+    return new Promise<boolean>((resolver) => this.promiseResolverQueue.push(resolver))
+  }
+
+  /**
+   * Increases the number of permits by one. If there are other functions waiting, one of them will
+   * continue to execute in a future iteration of the event loop.
+   */
+  public release(): void {
+    this.permits += 1
+
+    if (this.permits > 1 && this.promiseResolverQueue.length > 0) {
+      // eslint-disable-next-line no-console
+      console.warn('Semaphore.permits should never be > 0 when there is someone waiting.')
+    } else if (this.permits === 1 && this.promiseResolverQueue.length > 0) {
+      // If there is someone else waiting, immediately consume the permit that was released
+      // at the beginning of this function and let the waiting function resume.
+      this.permits -= 1
+
+      const nextResolver = this.promiseResolverQueue.shift()
+      if (nextResolver) {
+        nextResolver(true)
+      }
+    }
+  }
+}
diff --git a/packages/client/lib/execution/vmexecution.ts b/packages/client/lib/execution/vmexecution.ts
index 216ce39a8a..dbf73d0402 100644
--- a/packages/client/lib/execution/vmexecution.ts
+++ b/packages/client/lib/execution/vmexecution.ts
@@ -42,7 +42,7 @@ export class VMExecution extends Execution {
     if (isFalsy(this.config.vm)) {
       const trie = new Trie({
         db: new LevelDB(this.stateDB),
-        useHashedKeys: true,
+        useKeyHashing: true,
       })
 
       const stateManager = new DefaultStateManager({
diff --git a/packages/client/lib/rpc/modules/engine.ts b/packages/client/lib/rpc/modules/engine.ts
index 6a2928e9d6..8f42ce700b 100644
--- a/packages/client/lib/rpc/modules/engine.ts
+++ b/packages/client/lib/rpc/modules/engine.ts
@@ -136,7 +136,7 @@ const txsTrieRoot = async (txs: TypedTransaction[]) => {
   for (const [i, tx] of txs.entries()) {
     await trie.put(Buffer.from(RLP.encode(i)), tx.serialize())
   }
-  return trie.root
+  return trie.root()
 }
 
 /**
diff --git a/packages/client/lib/util/debug.ts b/packages/client/lib/util/debug.ts
index 9494206300..3c236d0d2c 100644
--- a/packages/client/lib/util/debug.ts
+++ b/packages/client/lib/util/debug.ts
@@ -40,7 +40,7 @@ const main = async () => {
     .toString('hex')}', 'hex'), { common })
 
   const stateDB = new Level('${execution.config.getDataDirectory(DataDirectory.State)}')
-  const trie = new Trie({ db: stateDB, useHashedKeys: true })
+  const trie = new Trie({ db: stateDB, useKeyHashing: true })
   const stateManager = new DefaultStateManager({ trie, common })
   // Ensure we run on the right root
   stateManager.setStateRoot(Buffer.from('${(
diff --git a/packages/statemanager/src/stateManager.ts b/packages/statemanager/src/stateManager.ts
index cdf455511a..93e5f3670a 100644
--- a/packages/statemanager/src/stateManager.ts
+++ b/packages/statemanager/src/stateManager.ts
@@ -87,7 +87,7 @@ export class DefaultStateManager extends BaseStateManager implements StateManage
   constructor(opts: DefaultStateManagerOpts = {}) {
     super(opts)
 
-    this._trie = opts.trie ?? new Trie({ useHashedKeys: true })
+    this._trie = opts.trie ?? new Trie({ useKeyHashing: true })
     this._storageTries = {}
 
     this._prefixCodeHashes = opts.prefixCodeHashes ?? true
@@ -138,7 +138,8 @@ export class DefaultStateManager extends BaseStateManager implements StateManage
     }
 
     const key = this._prefixCodeHashes ? Buffer.concat([CODEHASH_PREFIX, codeHash]) : codeHash
-    await this._trie.db.put(key, value)
+    // @ts-expect-error
+    await this._trie._db.put(key, value)
 
     if (this.DEBUG) {
       this._debug(`Update codeHash (-> ${short(codeHash)}) for account ${address}`)
@@ -160,7 +161,8 @@ export class DefaultStateManager extends BaseStateManager implements StateManage
     const key = this._prefixCodeHashes
       ? Buffer.concat([CODEHASH_PREFIX, account.codeHash])
       : account.codeHash
-    const code = await this._trie.db.get(key)
+    // @ts-expect-error
+    const code = await this._trie._db.get(key)
     return code ?? Buffer.alloc(0)
   }
 
@@ -173,8 +175,8 @@ export class DefaultStateManager extends BaseStateManager implements StateManage
     // from state trie
     const account = await this.getAccount(address)
     const storageTrie = this._trie.copy(false)
-    storageTrie.root = account.storageRoot
-    storageTrie.db.checkpoints = []
+    storageTrie.root(account.storageRoot)
+    storageTrie.flushCheckpoints()
     return storageTrie
   }
 
@@ -235,7 +237,7 @@ export class DefaultStateManager extends BaseStateManager implements StateManage
 
         // update contract storageRoot
         const contract = this._cache.get(address)
-        contract.storageRoot = storageTrie.root
+        contract.storageRoot = storageTrie.root()
 
         await this.putAccount(address, contract)
         resolve()
@@ -286,7 +288,7 @@ export class DefaultStateManager extends BaseStateManager implements StateManage
    */
   async clearContractStorage(address: Address): Promise<void> {
     await this._modifyContractStorage(address, (storageTrie, done) => {
-      storageTrie.root = storageTrie.EMPTY_TRIE_ROOT
+      storageTrie.root(storageTrie.EMPTY_TRIE_ROOT)
       done()
     })
   }
@@ -374,7 +376,7 @@ export class DefaultStateManager extends BaseStateManager implements StateManage
 
     // This returns the account if the proof is valid.
     // Verify that it matches the reported account.
-    const value = await new Trie({ useHashedKeys: true }).verifyProof(rootHash, key, accountProof)
+    const value = await new Trie({ useKeyHashing: true }).verifyProof(rootHash, key, accountProof)
 
     if (value === null) {
       // Verify that the account is empty in the proof.
@@ -420,7 +422,7 @@ export class DefaultStateManager extends BaseStateManager implements StateManage
       const storageProof = stProof.proof.map((value: PrefixedHexString) => toBuffer(value))
       const storageValue = setLengthLeft(toBuffer(stProof.value), 32)
       const storageKey = toBuffer(stProof.key)
-      const proofValue = await new Trie({ useHashedKeys: true }).verifyProof(
+      const proofValue = await new Trie({ useKeyHashing: true }).verifyProof(
         storageRoot,
         storageKey,
         storageProof
@@ -444,8 +446,7 @@ export class DefaultStateManager extends BaseStateManager implements StateManage
    */
   async getStateRoot(): Promise<Buffer> {
     await this._cache.flush()
-    const stateRoot = this._trie.root
-    return stateRoot
+    return this._trie.root()
   }
 
   /**
@@ -465,7 +466,7 @@ export class DefaultStateManager extends BaseStateManager implements StateManage
       }
     }
 
-    this._trie.root = stateRoot
+    this._trie.root(stateRoot)
     this._cache.clear()
     this._storageTries = {}
   }
diff --git a/packages/statemanager/tests/cache.spec.ts b/packages/statemanager/tests/cache.spec.ts
index 3182dadf50..20a58fadf6 100644
--- a/packages/statemanager/tests/cache.spec.ts
+++ b/packages/statemanager/tests/cache.spec.ts
@@ -10,7 +10,7 @@ import type { getCb, putCb } from '../src/cache'
 
 tape('cache initialization', (t) => {
   t.test('should initialize', async (st) => {
-    const trie = new Trie({ useHashedKeys: true })
+    const trie = new Trie({ useKeyHashing: true })
     const getCb: getCb = async (address) => {
       const innerTrie = trie
       const rlp = await innerTrie.get(address.buf)
@@ -32,7 +32,7 @@ tape('cache initialization', (t) => {
 })
 
 tape('cache put and get account', (t) => {
-  const trie = new Trie({ useHashedKeys: true })
+  const trie = new Trie({ useKeyHashing: true })
   const getCb: getCb = async (address) => {
     const innerTrie = trie
     const rlp = await innerTrie.get(address.buf)
@@ -103,7 +103,7 @@ tape('cache put and get account', (t) => {
 })
 
 tape('cache checkpointing', (t) => {
-  const trie = new Trie({ useHashedKeys: true })
+  const trie = new Trie({ useKeyHashing: true })
   const getCb: getCb = async (address) => {
     const innerTrie = trie
     const rlp = await innerTrie.get(address.buf)
diff --git a/packages/statemanager/tests/proofStateManager.spec.ts b/packages/statemanager/tests/proofStateManager.spec.ts
index 664042b885..caae1cbc11 100644
--- a/packages/statemanager/tests/proofStateManager.spec.ts
+++ b/packages/statemanager/tests/proofStateManager.spec.ts
@@ -41,7 +41,7 @@ tape('ProofStateManager', (t) => {
     // Account: 0xc626553e7c821d0f8308c28d56c60e3c15f8d55a
     // Storage slots: empty list
     const address = Address.fromString('0xc626553e7c821d0f8308c28d56c60e3c15f8d55a')
-    const trie = new Trie({ useHashedKeys: true })
+    const trie = new Trie({ useKeyHashing: true })
     const stateManager = new DefaultStateManager({ trie })
     // Dump all the account proof data in the DB
     let stateRoot: Buffer | undefined
@@ -51,9 +51,10 @@ tape('ProofStateManager', (t) => {
       if (stateRoot === undefined) {
         stateRoot = key
       }
-      await trie.db.put(key, bufferData)
+      // @ts-expect-error
+      await trie._db.put(key, bufferData)
     }
-    trie.root = stateRoot!
+    trie.root(stateRoot!)
     const proof = await stateManager.getProof(address)
     st.deepEqual(ropsten_validAccount, proof)
     st.ok(await stateManager.verifyProof(ropsten_validAccount))
@@ -68,7 +69,7 @@ tape('ProofStateManager', (t) => {
       // Account: 0x68268f12253f69f66b188c95b8106b2f847859fc (this account does not exist)
       // Storage slots: empty list
       const address = Address.fromString('0x68268f12253f69f66b188c95b8106b2f847859fc')
-      const trie = new Trie({ useHashedKeys: true })
+      const trie = new Trie({ useKeyHashing: true })
       const stateManager = new DefaultStateManager({ trie })
       // Dump all the account proof data in the DB
       let stateRoot: Buffer | undefined
@@ -78,9 +79,10 @@ tape('ProofStateManager', (t) => {
         if (stateRoot === undefined) {
           stateRoot = key
         }
-        await trie.db.put(key, bufferData)
+        // @ts-expect-error
+        await trie._db.put(key, bufferData)
       }
-      trie.root = stateRoot!
+      trie.root(stateRoot!)
       const proof = await stateManager.getProof(address)
       st.deepEqual(ropsten_nonexistentAccount, proof)
       st.ok(await stateManager.verifyProof(ropsten_nonexistentAccount))
@@ -96,7 +98,7 @@ tape('ProofStateManager', (t) => {
       // Note: the first slot has a value, but the second slot is empty
       // Note: block hash 0x1d9ea6981b8093a2b63f22f74426ceb6ba1acae3fddd7831442bbeba3fa4f146
       const address = Address.fromString('0x2D80502854FC7304c3E3457084DE549f5016B73f')
-      const trie = new Trie({ useHashedKeys: true })
+      const trie = new Trie({ useKeyHashing: true })
       const stateManager = new DefaultStateManager({ trie })
       // Dump all the account proof data in the DB
       let stateRoot: Buffer | undefined
@@ -106,22 +108,24 @@ tape('ProofStateManager', (t) => {
         if (stateRoot === undefined) {
           stateRoot = key
         }
-        await trie.db.put(key, bufferData)
+        // @ts-expect-error
+        await trie._db.put(key, bufferData)
       }
       const storageRoot = ropsten_contractWithStorage.storageHash
-      const storageTrie = new Trie({ useHashedKeys: true })
+      const storageTrie = new Trie({ useKeyHashing: true })
       const storageKeys: Buffer[] = []
       for (const storageProofsData of ropsten_contractWithStorage.storageProof) {
         storageKeys.push(toBuffer(storageProofsData.key))
         for (const storageProofData of storageProofsData.proof) {
           const key = Buffer.from(keccak256(toBuffer(storageProofData)))
-          await storageTrie.db.put(key, toBuffer(storageProofData))
+          // @ts-expect-error
+          await storageTrie._db.put(key, toBuffer(storageProofData))
         }
       }
-      storageTrie.root = toBuffer(storageRoot)
+      storageTrie.root(toBuffer(storageRoot))
       const addressHex = address.buf.toString('hex')
       stateManager._storageTries[addressHex] = storageTrie
-      trie.root = stateRoot!
+      trie.root(stateRoot!)
 
       const proof = await stateManager.getProof(address, storageKeys)
       st.deepEqual(ropsten_contractWithStorage, proof)
@@ -136,7 +140,7 @@ tape('ProofStateManager', (t) => {
     // Note: the first slot has a value, but the second slot is empty
     // Note: block hash 0x1d9ea6981b8093a2b63f22f74426ceb6ba1acae3fddd7831442bbeba3fa4f146
     const address = Address.fromString('0x2D80502854FC7304c3E3457084DE549f5016B73f')
-    const trie = new Trie({ useHashedKeys: true })
+    const trie = new Trie({ useKeyHashing: true })
     const stateManager = new DefaultStateManager({ trie })
     // Dump all the account proof data in the DB
     let stateRoot: Buffer | undefined
@@ -146,22 +150,24 @@ tape('ProofStateManager', (t) => {
       if (stateRoot === undefined) {
         stateRoot = key
       }
-      await trie.db.put(key, bufferData)
+      // @ts-expect-error
+      await trie._db.put(key, bufferData)
     }
     const storageRoot = ropsten_contractWithStorage.storageHash
-    const storageTrie = new Trie({ useHashedKeys: true })
+    const storageTrie = new Trie({ useKeyHashing: true })
     const storageKeys: Buffer[] = []
     for (const storageProofsData of ropsten_contractWithStorage.storageProof) {
       storageKeys.push(toBuffer(storageProofsData.key))
       for (const storageProofData of storageProofsData.proof) {
         const key = Buffer.from(keccak256(toBuffer(storageProofData)))
-        await storageTrie.db.put(key, toBuffer(storageProofData))
+        // @ts-expect-error
+        await storageTrie._db.put(key, toBuffer(storageProofData))
       }
     }
-    storageTrie.root = toBuffer(storageRoot)
+    storageTrie.root(toBuffer(storageRoot))
     const addressHex = address.buf.toString('hex')
     stateManager._storageTries[addressHex] = storageTrie
-    trie.root = stateRoot!
+    trie.root(stateRoot!)
 
     // tamper with account data
     const testdata = ropsten_contractWithStorage as any
@@ -203,7 +209,7 @@ tape('ProofStateManager', (t) => {
     // Note: the first slot has a value, but the second slot is empty
     // Note: block hash 0x1d9ea6981b8093a2b63f22f74426ceb6ba1acae3fddd7831442bbeba3fa4f146
     const address = Address.fromString('0x68268f12253f69f66b188c95b8106b2f847859fc')
-    const trie = new Trie({ useHashedKeys: true })
+    const trie = new Trie({ useKeyHashing: true })
     const stateManager = new DefaultStateManager({ trie })
     // Dump all the account proof data in the DB
     let stateRoot: Buffer | undefined
@@ -213,14 +219,15 @@ tape('ProofStateManager', (t) => {
       if (stateRoot === undefined) {
         stateRoot = key
       }
-      await trie.db.put(key, bufferData)
+      // @ts-expect-error
+      await trie._db.put(key, bufferData)
     }
     const storageRoot = ropsten_nonexistentAccount.storageHash
-    const storageTrie = new Trie({ useHashedKeys: true })
-    storageTrie.root = toBuffer(storageRoot)
+    const storageTrie = new Trie({ useKeyHashing: true })
+    storageTrie.root(toBuffer(storageRoot))
     const addressHex = address.buf.toString('hex')
     stateManager._storageTries[addressHex] = storageTrie
-    trie.root = stateRoot!
+    trie.root(stateRoot!)
 
     // tamper with account data
     const testdata = ropsten_nonexistentAccount as any
diff --git a/packages/statemanager/tests/stateManager.spec.ts b/packages/statemanager/tests/stateManager.spec.ts
index e0c1518b6f..aeb1234a55 100644
--- a/packages/statemanager/tests/stateManager.spec.ts
+++ b/packages/statemanager/tests/stateManager.spec.ts
@@ -22,7 +22,7 @@ tape('StateManager', (t) => {
   t.test('should instantiate', async (st) => {
     const stateManager = new DefaultStateManager()
 
-    st.deepEqual(stateManager._trie.root, KECCAK256_RLP, 'it has default root')
+    st.deepEqual(stateManager._trie.root(), KECCAK256_RLP, 'it has default root')
     const res = await stateManager.getStateRoot()
     st.deepEqual(res, KECCAK256_RLP, 'it has default root')
     st.end()
@@ -30,7 +30,7 @@ tape('StateManager', (t) => {
 
   t.test('should set the state root to empty', async (st) => {
     const stateManager = new DefaultStateManager()
-    st.ok(stateManager._trie.root.equals(KECCAK256_RLP), 'it has default root')
+    st.ok(stateManager._trie.root().equals(KECCAK256_RLP), 'it has default root')
 
     // commit some data to the trie
     const address = new Address(Buffer.from('a94f5374fce5edbc8e2a8697c15331677e6ebf0b', 'hex'))
@@ -39,7 +39,7 @@ tape('StateManager', (t) => {
     await stateManager.putAccount(address, account)
     await stateManager.commit()
     await stateManager.flush()
-    st.ok(!stateManager._trie.root.equals(KECCAK256_RLP), 'it has a new root')
+    st.ok(!stateManager._trie.root().equals(KECCAK256_RLP), 'it has a new root')
 
     // set state root to empty trie root
     const emptyTrieRoot = Buffer.from(KECCAK256_RLP_S, 'hex')
@@ -315,7 +315,8 @@ tape('StateManager', (t) => {
     await stateManager.putContractStorage(address1, key1, key2)
     await stateManager.putContractStorage(address1, key2, key2)
     const root = await stateManager.getStateRoot()
-    const rawNode = await stateManager._trie.db.get(root)
+    // @ts-expect-error
+    const rawNode = await stateManager._trie._db.get(root)
 
     await codeStateManager.putContractCode(address1, rawNode!)
 
diff --git a/packages/trie/CHANGELOG.md b/packages/trie/CHANGELOG.md
index bcc9e55e06..08bff0b382 100644
--- a/packages/trie/CHANGELOG.md
+++ b/packages/trie/CHANGELOG.md
@@ -12,15 +12,18 @@ Beta 3 release for the upcoming breaking release round on the [EthereumJS monore
 
 ### Root Hash Persistance
 
-The trie library now comes with a new constructor option `persistRoot` which is disabled by default but allows to persist state root updates along write operations directly in the DB and therefore omits the need to manually set to a new state root, see PR [#2071](https://github.com/ethereumjs/ethereumjs-monorepo/pull/2071) and PR [#2123](https://github.com/ethereumjs/ethereumjs-monorepo/pull/2123), thanks to @faustbrian for the contribution! ❤️
+The trie library now comes with a new constructor option `useRootPersistence` which is disabled by default but allows to persist state root updates along write operations directly in the DB and therefore omits the need to manually set to a new state root, see PR [#2071](https://github.com/ethereumjs/ethereumjs-monorepo/pull/2071) and PR [#2123](https://github.com/ethereumjs/ethereumjs-monorepo/pull/2123), thanks to @faustbrian for the contribution! ❤️
 
-To activate root hash persistance you can set the `persistRoot` option on instantiation:
+To activate root hash persistance you can set the `useRootPersistence` option on instantiation:
 
 ```typescript
 import { Trie, LevelDB } from '@ethereumjs/trie'
 import { Level } from 'level'
 
-const trie = new Trie({ db: new LevelDB(new Level('MY_TRIE_DB_LOCATION')), persistRoot: true })
+const trie = new Trie({
+  db: new LevelDB(new Level('MY_TRIE_DB_LOCATION')),
+  useRootPersistence: true,
+})
 ```
 
 ### Other Changes
@@ -52,7 +55,7 @@ This allows to swap out the applied `keccak256` hash functionality from the [@no
 So the usage of the following methods change and need to be updated (for all types of tries):
 
 - `Trie.createProof(trie, myKey)` -> `trie.createProof(myKey)`
-- `Trie.verifyProof(trie.root, myKey, proof)` -> `trie.verifyProof(trie.root, myKey, proof)`
+- `Trie.verifyProof(trie.root(), myKey, proof)` -> `trie.verifyProof(trie.root(), myKey, proof)`
 - `Trie.verifyRangeProof(...)` -> `trie.verifyRangeProof(...)`
 
 ## Other Changes
diff --git a/packages/trie/README.md b/packages/trie/README.md
index 204693e58e..a087ea580a 100644
--- a/packages/trie/README.md
+++ b/packages/trie/README.md
@@ -24,7 +24,7 @@ If you currently use this package in your project and plan to upgrade, please re
 
 ## Usage
 
-This class implements the basic [Modified Merkle Patricia Trie](https://ethereum.org/en/developers/docs/data-structures-and-encoding/patricia-merkle-trie/) in the `Trie` base class, which you can use with the `useHashedKeys` option set to `true` to create a trie which stores values under the `keccak256` hash of its keys (this is the Trie flavor which is used in Ethereum production systems).
+This class implements the basic [Modified Merkle Patricia Trie](https://ethereum.org/en/developers/docs/data-structures-and-encoding/patricia-merkle-trie/) in the `Trie` base class, which you can use with the `useKeyHashing` option set to `true` to create a trie which stores values under the `keccak256` hash of its keys (this is the Trie flavor which is used in Ethereum production systems).
 
 **Note:** Up to v4 of the Trie library the secure trie was implemented as a separate `SecureTrie` class, see the [upgrade guide](./UPGRADING.md) for more infos.
 
@@ -67,7 +67,7 @@ By default, the deletion of trie nodes from the underlying database does not occ
 
 #### Persistence
 
-You can enable persistence by setting the `persistRoot` option to `true` when constructing a trie through the `Trie.create` function. As such, this value is preserved when creating copies of the trie and is incapable of being modified once a trie is instantiated.
+You can enable persistence by setting the `useRootPersistence` option to `true` when constructing a trie through the `Trie.create` function. As such, this value is preserved when creating copies of the trie and is incapable of being modified once a trie is instantiated.
 
 ```typescript
 import { Trie, LevelDB } from '@ethereumjs/trie'
@@ -75,7 +75,7 @@ import { Level } from 'level'
 
 const trie = await Trie.create({
   db: new LevelDB(new Level('MY_TRIE_DB_LOCATION')),
-  persistRoot: true,
+  useRootPersistence: true,
 })
 ```
 
@@ -110,7 +110,7 @@ const trie = new Trie()
 async function test() {
   await trie.put(Buffer.from('test'), Buffer.from('one'))
   const proof = await trie.createProof(Buffer.from('test'))
-  const value = await trie.verifyProof(trie.root, Buffer.from('test'), proof)
+  const value = await trie.verifyProof(trie.root(), Buffer.from('test'), proof)
   console.log(value.toString()) // 'one'
 }
 
@@ -128,7 +128,7 @@ async function test() {
   await trie.put(Buffer.from('test'), Buffer.from('one'))
   await trie.put(Buffer.from('test2'), Buffer.from('two'))
   const proof = await trie.createProof(Buffer.from('test3'))
-  const value = await trie.verifyProof(trie.root, Buffer.from('test3'), proof)
+  const value = await trie.verifyProof(trie.root(), Buffer.from('test3'), proof)
   console.log(value.toString()) // null
 }
 
@@ -148,7 +148,7 @@ async function test() {
   const proof = await trie.createProof(Buffer.from('test2'))
   proof[1].reverse()
   try {
-    const value = await trie.verifyProof(trie.root, Buffer.from('test2'), proof)
+    const value = await trie.verifyProof(trie.root(), Buffer.from('test2'), proof)
     console.log(value.toString()) // results in error
   } catch (err) {
     console.log(err) // Missing node in DB
@@ -176,7 +176,7 @@ const stateRootBuffer = Buffer.from(stateRoot.slice(2), 'hex')
 const trie = new Trie({
   db: new LevelDB(new Level('YOUR_PATH_TO_THE_GETH_CHAIN_DB')),
   root: stateRootBuffer,
-  useHashedKeys: true,
+  useKeyHashing: true,
 })
 
 trie
@@ -198,7 +198,7 @@ const stateRoot = 'STATE_ROOT_OF_A_BLOCK'
 const trie = new Trie({
   db: new LevelDB(new Level('YOUR_PATH_TO_THE_GETH_CHAINDATA_FOLDER')),
   root: stateRoot
-  useHashedKeys: true,
+  useKeyHashing: true,
 })
 
 const address = 'AN_ETHEREUM_ACCOUNT_ADDRESS'
@@ -214,7 +214,7 @@ async function test() {
   console.log(`codeHash: ${bufferToHex(acc.codeHash)}`)
 
   const storageTrie = trie.copy()
-  storageTrie.root = acc.stateRoot
+  storageTrie.root(acc.stateRoot)
 
   console.log('------Storage------')
   const stream = storageTrie.createReadStream()
diff --git a/packages/trie/UPGRADING.md b/packages/trie/UPGRADING.md
index 5abef7892b..99b9ff7dab 100644
--- a/packages/trie/UPGRADING.md
+++ b/packages/trie/UPGRADING.md
@@ -10,7 +10,7 @@ Upgrading from v4 to v5 is relatively straightforward.
 
 ### SecureTrie as an Option
 
-In v5 the `SecureTrie` class has been removed in favor of a simple constructor option `useHashedKeys` - defaulting to `false` in the base `Trie` implementation. This reduces the level of inheritance dependencies (in the old structure it was e.g. not possible to create a secure trie without the checkpoint functionality, which are logically completely unrelated) and frees things up for future design changes and additions.
+In v5 the `SecureTrie` class has been removed in favor of a simple constructor option `useKeyHashing` - defaulting to `false` in the base `Trie` implementation. This reduces the level of inheritance dependencies (in the old structure it was e.g. not possible to create a secure trie without the checkpoint functionality, which are logically completely unrelated) and frees things up for future design changes and additions.
 
 Updating is pretty much straight-forward:
 
@@ -19,7 +19,7 @@ const trie = new SecureTrie() // old
 ```
 
 ```typescript
-const trie = new Trie({ useHashedKeys: true }) // new
+const trie = new Trie({ useKeyHashing: true }) // new
 ```
 
 ### Database Abstraction
diff --git a/packages/trie/benchmarks/suite.ts b/packages/trie/benchmarks/suite.ts
index ddb4fc29e1..d2015e8204 100644
--- a/packages/trie/benchmarks/suite.ts
+++ b/packages/trie/benchmarks/suite.ts
@@ -40,7 +40,7 @@ export function createSuite(db: DB) {
           }
 
           if (i % (eraSize as number) === 0) {
-            key = trie.root
+            key = trie.root()
           }
         }
       })
diff --git a/packages/trie/examples/merkle_patricia_trees/README.md b/packages/trie/examples/merkle_patricia_trees/README.md
index 97e03ee52b..2ce7cd83ce 100644
--- a/packages/trie/examples/merkle_patricia_trees/README.md
+++ b/packages/trie/examples/merkle_patricia_trees/README.md
@@ -42,7 +42,7 @@ Let's begin right away with a simple example. Don't worry if things aren't too c
 const { Trie } = require('@ethereumjs/trie') // We import the library required to create a basic Merkle Patricia Tree
 
 const trie = new Trie() // We create an empty Merkle Patricia Tree
-console.log('Empty trie root (Bytes): ', trie.root) // The trie root (32 bytes)
+console.log('Empty trie root (Bytes): ', trie.root()) // The trie root (32 bytes)
 ```
 
 and then store and retrieve a single key-value pair within it. Note that we needed to convert the strings (`testKey` and `testValue`) to buffers, as that is what the Trie methods expect:
@@ -55,7 +55,7 @@ async function test() {
   const retrievedValue = await trie.get(key) // We retrieve (using "get") the value at key "testKey"
   console.log('Value (Bytes): ', retrievedValue)
   console.log('Value (String): ', retrievedValue.toString())
-  console.log('Updated trie root:', trie.root) // The new trie root (32 bytes)
+  console.log('Updated trie root:', trie.root()) // The new trie root (32 bytes)
 }
 
 test()
@@ -86,14 +86,14 @@ const { Trie } = require('@ethereumjs/trie')
 const { keccak256 } = require('@ethereumjs/util')
 
 const trie = new Trie() // We create an empty Merkle Patricia Tree
-console.log('Empty trie root (Bytes): ', trie.root) // The trie root (32 bytes)
+console.log('Empty trie root (Bytes): ', trie.root()) // The trie root (32 bytes)
 
 async function test() {
   await trie.put(keccak256(Buffer.from('testKey')), Buffer.from('testValue')) // We update (using "put") the trie with the key-value pair hash("testKey"): "testValue"
   const value = await trie.get(keccak256(Buffer.from('testKey'))) // We retrieve (using "get") the value at hash("testKey"_
   console.log('Value (Bytes): ', value)
   console.log('Value (String): ', value.toString())
-  console.log('Updated trie root:', trie.root) // The new trie root (32 bytes)
+  console.log('Updated trie root:', trie.root()) // The new trie root (32 bytes)
 }
 
 test()
@@ -109,20 +109,20 @@ Nothing spectacular: only the root hash of the tree has changed, as the key has
 
 ### Example 1c - Automatically Creating and Updating a Secure Trie
 
-Fortunately, we also have an option called "useHashedKeys" that automatically takes care of the keccak256 hashing for us. We can see that it outputs the same root hash as example1b.js
+Fortunately, we also have an option called "useKeyHashing" that automatically takes care of the keccak256 hashing for us. We can see that it outputs the same root hash as example1b.js
 
 ```jsx
 const { Trie } = require('@ethereumjs/trie')// We import the class required to create a secure Merkle Patricia Tree
 
-const trie = new Trie({ useHashedKeys: true }) // We create an empty Merkle Patricia Tree
-console.log('Empty trie root (Bytes): ', trie.root) // The trie root (32 bytes)
+const trie = new Trie({ useKeyHashing: true }) // We create an empty Merkle Patricia Tree
+console.log('Empty trie root (Bytes): ', trie.root()) // The trie root (32 bytes)
 
 async function test() {
   await trie.put(Buffer.from('testKey'), Buffer.from('testValue')) // We update (using "put") the trie with the key-value pair "testKey": "testValue"
   const value = await trie.get(Buffer.from('testKey')) // We retrieve (using "get") the value at key "testKey"
   console.log('Value (Bytes): ', value)
   console.log('Value (String): ', value.toString())
-  console.log('Updated trie root:', trie.root) // The new trie root (32 bytes)
+  console.log('Updated trie root:', trie.root()) // The new trie root (32 bytes)
 }
 
 test()
@@ -134,7 +134,7 @@ Value (String):  testValue
 Updated trie root: <Buffer be ad e9 13 ab 37 dc a0 dc a2 e4 29 24 b9 18 c2 a1 ca c4 57 83 3b d8 2b 9e 32 45 de cb 87 d0 fb> // Same hash!
 ```
 
-To make the examples easier to follow, we won't be using the keccak256 of the keys (or the `useHashedKeys` option) in this tutorial. However, keep in mind that in Ethereum's Merkle Patricia Trees, keys are always hashed. If you're curious, the reason for hashing the keys is balancing the tree.
+To make the examples easier to follow, we won't be using the keccak256 of the keys (or the `useKeyHashing` option) in this tutorial. However, keep in mind that in Ethereum's Merkle Patricia Trees, keys are always hashed. If you're curious, the reason for hashing the keys is balancing the tree.
 
 ### Example 1d - Deleting a Key-Value Pair from a Trie
 
@@ -147,12 +147,12 @@ async function test() {
   await trie.put(key, value) // We update (using "put") the trie with the key-value pair "testKey": "testValue"
   const valuePre = await trie.get(key) // We retrieve (using "get") the value at key "testKey"
   console.log('Value (String): ', valuePre.toString()) // We retrieve our value
-  console.log('Updated trie root:', trie.root) // The new trie root
+  console.log('Updated trie root:', trie.root()) // The new trie root
 
   await trie.del(key)
   const valuePost = await trie.get(key) // We try to retrieve the value at (deleted) key "testKey"
   console.log('Value at key "testKey": ', valuePost) // Key not found. Value is therefore null.
-  console.log('Trie root after deletion:', trie.root) // Our trie root is back to its initial value
+  console.log('Trie root after deletion:', trie.root()) // Our trie root is back to its initial value
 }
 
 test()
diff --git a/packages/trie/examples/merkle_patricia_trees/example1a.js b/packages/trie/examples/merkle_patricia_trees/example1a.js
index 25c2099f7e..bbdb00b7c5 100644
--- a/packages/trie/examples/merkle_patricia_trees/example1a.js
+++ b/packages/trie/examples/merkle_patricia_trees/example1a.js
@@ -3,7 +3,7 @@
 const { Trie } = require('../../dist') // We import the library required to create a basic Merkle Patricia Tree
 
 const trie = new Trie() // We create an empty Merkle Patricia Tree
-console.log('Empty trie root (Bytes): ', trie.root) // The trie root (32 bytes)
+console.log('Empty trie root (Bytes): ', trie.root()) // The trie root (32 bytes)
 
 async function test() {
   const key = Buffer.from('testKey')
@@ -12,7 +12,7 @@ async function test() {
   const retrievedValue = await trie.get(key) // We retrieve (using "get") the value at key "testKey"
   console.log('Value (Bytes): ', retrievedValue)
   console.log('Value (String): ', retrievedValue.toString())
-  console.log('Updated trie root:', trie.root) // The new trie root (32 bytes)
+  console.log('Updated trie root:', trie.root()) // The new trie root (32 bytes)
 }
 
 test()
diff --git a/packages/trie/examples/merkle_patricia_trees/example1b.js b/packages/trie/examples/merkle_patricia_trees/example1b.js
index bcf0a0999b..ae34cd29c5 100644
--- a/packages/trie/examples/merkle_patricia_trees/example1b.js
+++ b/packages/trie/examples/merkle_patricia_trees/example1b.js
@@ -4,14 +4,14 @@ const { Trie } = require('../../dist') // We import the library required to crea
 const { keccak256 } = require('ethereum-cryptography/keccak')
 
 const trie = new Trie() // We create an empty Merkle Patricia Tree
-console.log('Empty trie root (Bytes): ', trie.root) // The trie root (32 bytes)
+console.log('Empty trie root (Bytes): ', trie.root()) // The trie root (32 bytes)
 
 async function test() {
   await trie.put(keccak256(Buffer.from('testKey')), Buffer.from('testValue')) // We update (using "put") the trie with the key-value pair "testKey": "testValue"
   const value = await trie.get(keccak256(Buffer.from('testKey'))) // We retrieve (using "get") the value at key "testKey"
   console.log('Value (Bytes): ', value)
   console.log('Value (String): ', value.toString())
-  console.log('Updated trie root:', trie.root) // The new trie root (32 bytes)
+  console.log('Updated trie root:', trie.root()) // The new trie root (32 bytes)
 }
 
 test()
diff --git a/packages/trie/examples/merkle_patricia_trees/example1c.js b/packages/trie/examples/merkle_patricia_trees/example1c.js
index 462b402441..b7bf67285e 100644
--- a/packages/trie/examples/merkle_patricia_trees/example1c.js
+++ b/packages/trie/examples/merkle_patricia_trees/example1c.js
@@ -2,15 +2,15 @@
 
 const { Trie } = require('../../dist') // We import the library required to create a basic Merkle Patricia Tree
 
-const trie = new Trie({ useHashedKeys: true }) // We create an empty Merkle Patricia Tree
-console.log('Empty trie root (Bytes): ', trie.root) // The trie root (32 bytes)
+const trie = new Trie({ useKeyHashing: true }) // We create an empty Merkle Patricia Tree
+console.log('Empty trie root (Bytes): ', trie.root()) // The trie root (32 bytes)
 
 async function test() {
   await trie.put(Buffer.from('testKey'), Buffer.from('testValue')) // We update (using "put") the trie with the key-value pair "testKey": "testValue"
   const value = await trie.get(Buffer.from('testKey')) // We retrieve (using "get") the value at key "testKey"
   console.log('Value (Bytes): ', value)
   console.log('Value (String): ', value.toString())
-  console.log('Updated trie root:', trie.root) // The new trie root (32 bytes)
+  console.log('Updated trie root:', trie.root()) // The new trie root (32 bytes)
 }
 
 test()
diff --git a/packages/trie/examples/merkle_patricia_trees/example1d.js b/packages/trie/examples/merkle_patricia_trees/example1d.js
index d4fc63e604..97170d4ed1 100644
--- a/packages/trie/examples/merkle_patricia_trees/example1d.js
+++ b/packages/trie/examples/merkle_patricia_trees/example1d.js
@@ -3,7 +3,7 @@
 const { Trie } = require('../../dist') // We import the library required to create a basic Merkle Patricia Tree
 
 const trie = new Trie() // We create an empty Merkle Patricia Tree
-console.log('Empty trie root: ', trie.root) // The trie root
+console.log('Empty trie root: ', trie.root()) // The trie root
 
 async function test() {
   const key = Buffer.from('testKey')
@@ -11,12 +11,12 @@ async function test() {
   await trie.put(key, value) // We update (using "put") the trie with the key-value pair "testKey": "testValue"
   const valuePre = await trie.get(key) // We retrieve (using "get") the value at key "testKey"
   console.log('Value (String): ', valuePre.toString()) // We retrieve our value
-  console.log('Updated trie root:', trie.root) // The new trie root
+  console.log('Updated trie root:', trie.root()) // The new trie root
 
   await trie.del(key)
   const valuePost = await trie.get(key) // We try to retrieve the value at (deleted) key "testKey"
   console.log('Value at key "testKey": ', valuePost) // Key not found. Value is therefore null.
-  console.log('Trie root after deletion:', trie.root) // Our trie root is back to its initial value
+  console.log('Trie root after deletion:', trie.root()) // Our trie root is back to its initial value
 }
 
 test()
diff --git a/packages/trie/src/proof/range.ts b/packages/trie/src/proof/range.ts
index 332c85c4f8..f8810011c1 100644
--- a/packages/trie/src/proof/range.ts
+++ b/packages/trie/src/proof/range.ts
@@ -54,8 +54,8 @@ async function unset(
      * remove self from parent
      */
     if (
-      key.length - pos < child.keyLength ||
-      nibblesCompare(child._nibbles, key.slice(pos, pos + child.keyLength)) !== 0
+      key.length - pos < child.keyLength() ||
+      nibblesCompare(child._nibbles, key.slice(pos, pos + child.keyLength())) !== 0
     ) {
       if (removeLeft) {
         if (nibblesCompare(child._nibbles, key.slice(pos)) < 0) {
@@ -74,7 +74,7 @@ async function unset(
       ;(parent as BranchNode).setBranch(key[pos - 1], null)
       return pos - 1
     } else {
-      const _child = await trie.lookupNode(child.value)
+      const _child = await trie.lookupNode(child.value())
       if (_child && _child instanceof LeafNode) {
         // The child of this node is leaf node, remove it from parent too
         ;(parent as BranchNode).setBranch(key[pos - 1], null)
@@ -85,7 +85,7 @@ async function unset(
       stack.push(child)
 
       // continue to the next node
-      return await unset(trie, child, _child, key, pos + child.keyLength, removeLeft, stack)
+      return await unset(trie, child, _child, key, pos + child.keyLength(), removeLeft, stack)
     }
   } else if (child === null) {
     return pos - 1
@@ -107,7 +107,7 @@ async function unsetInternal(trie: Trie, left: Nibbles, right: Nibbles): Promise
   // Parent node
   let parent: TrieNode | null = null
   // Current node
-  let node: TrieNode | null = await trie.lookupNode(trie.root)
+  let node: TrieNode | null = await trie.lookupNode(trie.root())
   let shortForkLeft!: number
   let shortForkRight!: number
   // A stack of modified nodes.
@@ -121,16 +121,16 @@ async function unsetInternal(trie: Trie, left: Nibbles, right: Nibbles): Promise
       // record this node on the stack
       stack.push(node)
 
-      if (left.length - pos < node.keyLength) {
+      if (left.length - pos < node.keyLength()) {
         shortForkLeft = nibblesCompare(left.slice(pos), node._nibbles)
       } else {
-        shortForkLeft = nibblesCompare(left.slice(pos, pos + node.keyLength), node._nibbles)
+        shortForkLeft = nibblesCompare(left.slice(pos, pos + node.keyLength()), node._nibbles)
       }
 
-      if (right.length - pos < node.keyLength) {
+      if (right.length - pos < node.keyLength()) {
         shortForkRight = nibblesCompare(right.slice(pos), node._nibbles)
       } else {
-        shortForkRight = nibblesCompare(right.slice(pos, pos + node.keyLength), node._nibbles)
+        shortForkRight = nibblesCompare(right.slice(pos, pos + node.keyLength()), node._nibbles)
       }
 
       // If one of `left` and `right` is not equal to node._nibbles, it means we found the fork point
@@ -145,8 +145,8 @@ async function unsetInternal(trie: Trie, left: Nibbles, right: Nibbles): Promise
 
       // continue to the next node
       parent = node
-      pos += node.keyLength
-      node = await trie.lookupNode(node.value)
+      pos += node.keyLength()
+      node = await trie.lookupNode(node.value())
     } else if (node instanceof BranchNode) {
       // record this node on the stack
       stack.push(node)
@@ -248,7 +248,7 @@ async function unsetInternal(trie: Trie, left: Nibbles, right: Nibbles): Promise
         return await removeSelfFromParentAndSaveStack(left)
       }
 
-      const endPos = await unset(trie, node, child, left.slice(pos), node.keyLength, false, stack)
+      const endPos = await unset(trie, node, child, left.slice(pos), node.keyLength(), false, stack)
       await saveStack(left.slice(0, pos + endPos), stack)
 
       return false
@@ -265,7 +265,7 @@ async function unsetInternal(trie: Trie, left: Nibbles, right: Nibbles): Promise
         return await removeSelfFromParentAndSaveStack(right)
       }
 
-      const endPos = await unset(trie, node, child, right.slice(pos), node.keyLength, true, stack)
+      const endPos = await unset(trie, node, child, right.slice(pos), node.keyLength(), true, stack)
       await saveStack(right.slice(0, pos + endPos), stack)
 
       return false
@@ -317,9 +317,9 @@ async function verifyProof(
   rootHash: Buffer,
   key: Buffer,
   proof: Buffer[],
-  useHashedKeysFunction: HashKeysFunction
+  useKeyHashingFunction: HashKeysFunction
 ): Promise<{ value: Buffer | null; trie: Trie }> {
-  const proofTrie = new Trie({ root: rootHash, useHashedKeysFunction })
+  const proofTrie = new Trie({ root: rootHash, useKeyHashingFunction })
   try {
     await proofTrie.fromProof(proof)
   } catch (e) {
@@ -348,7 +348,7 @@ async function verifyProof(
  */
 async function hasRightElement(trie: Trie, key: Nibbles): Promise<boolean> {
   let pos = 0
-  let node = await trie.lookupNode(trie.root)
+  let node = await trie.lookupNode(trie.root())
   while (node !== null) {
     if (node instanceof BranchNode) {
       for (let i = key[pos] + 1; i < 16; i++) {
@@ -362,13 +362,13 @@ async function hasRightElement(trie: Trie, key: Nibbles): Promise<boolean> {
       pos += 1
     } else if (node instanceof ExtensionNode) {
       if (
-        key.length - pos < node.keyLength ||
-        nibblesCompare(node._nibbles, key.slice(pos, pos + node.keyLength)) !== 0
+        key.length - pos < node.keyLength() ||
+        nibblesCompare(node._nibbles, key.slice(pos, pos + node.keyLength())) !== 0
       ) {
         return nibblesCompare(node._nibbles, key.slice(pos)) > 0
       }
 
-      pos += node.keyLength
+      pos += node.keyLength()
       node = await trie.lookupNode(node._value)
     } else if (node instanceof LeafNode) {
       return false
@@ -414,7 +414,7 @@ export async function verifyRangeProof(
   keys: Nibbles[],
   values: Buffer[],
   proof: Buffer[] | null,
-  useHashedKeysFunction: HashKeysFunction
+  useKeyHashingFunction: HashKeysFunction
 ): Promise<boolean> {
   if (keys.length !== values.length) {
     throw new Error('invalid keys length or values length')
@@ -435,11 +435,11 @@ export async function verifyRangeProof(
 
   // All elements proof
   if (proof === null && firstKey === null && lastKey === null) {
-    const trie = new Trie({ useHashedKeysFunction })
+    const trie = new Trie({ useKeyHashingFunction })
     for (let i = 0; i < keys.length; i++) {
       await trie.put(nibblesToBuffer(keys[i]), values[i])
     }
-    if (rootHash.compare(trie.root) !== 0) {
+    if (rootHash.compare(trie.root()) !== 0) {
       throw new Error('invalid all elements proof: root mismatch')
     }
     return false
@@ -457,7 +457,7 @@ export async function verifyRangeProof(
       rootHash,
       nibblesToBuffer(firstKey),
       proof,
-      useHashedKeysFunction
+      useKeyHashingFunction
     )
 
     if (value !== null || (await hasRightElement(trie, firstKey))) {
@@ -473,7 +473,7 @@ export async function verifyRangeProof(
       rootHash,
       nibblesToBuffer(firstKey),
       proof,
-      useHashedKeysFunction
+      useKeyHashingFunction
     )
 
     if (nibblesCompare(firstKey, keys[0]) !== 0) {
@@ -496,13 +496,13 @@ export async function verifyRangeProof(
     )
   }
 
-  const trie = new Trie({ root: rootHash, useHashedKeysFunction })
+  const trie = new Trie({ root: rootHash, useKeyHashingFunction })
   await trie.fromProof(proof)
 
   // Remove all nodes between two edge proofs
   const empty = await unsetInternal(trie, firstKey, lastKey)
   if (empty) {
-    trie.root = trie.EMPTY_TRIE_ROOT
+    trie.root(trie.EMPTY_TRIE_ROOT)
   }
 
   // Put all elements to the trie
@@ -511,7 +511,7 @@ export async function verifyRangeProof(
   }
 
   // Compare rootHash
-  if (trie.root.compare(rootHash) !== 0) {
+  if (trie.root().compare(rootHash) !== 0) {
     throw new Error('invalid two edge elements proof: root mismatch')
   }
 
diff --git a/packages/trie/src/trie/node/branch.ts b/packages/trie/src/trie/node/branch.ts
index 01432ce6cc..c0b50679db 100644
--- a/packages/trie/src/trie/node/branch.ts
+++ b/packages/trie/src/trie/node/branch.ts
@@ -19,12 +19,12 @@ export class BranchNode {
     return node
   }
 
-  get value(): Buffer | null {
-    return this._value && this._value.length > 0 ? this._value : null
-  }
+  value(v?: Buffer | null): Buffer | null {
+    if (v !== null && v !== undefined) {
+      this._value = v
+    }
 
-  set value(v: Buffer | null) {
-    this._value = v
+    return this._value && this._value.length > 0 ? this._value : null
   }
 
   setBranch(i: number, v: EmbeddedNode | null) {
diff --git a/packages/trie/src/trie/node/extension.ts b/packages/trie/src/trie/node/extension.ts
index d88a48c1c4..75615868b3 100644
--- a/packages/trie/src/trie/node/extension.ts
+++ b/packages/trie/src/trie/node/extension.ts
@@ -1,57 +1,15 @@
-import { RLP } from '@ethereumjs/rlp'
-import { bufArrToArr } from '@ethereumjs/util'
+import { addHexPrefix } from '../../util/hex'
 
-import { addHexPrefix, removeHexPrefix } from '../../util/hex'
-import { nibblesToBuffer } from '../../util/nibbles'
+import { Node } from './node'
 
 import type { Nibbles } from '../../types'
 
-export class ExtensionNode {
-  _nibbles: Nibbles
-  _value: Buffer
-
+export class ExtensionNode extends Node {
   constructor(nibbles: Nibbles, value: Buffer) {
-    this._nibbles = nibbles
-    this._value = value
+    super(nibbles, value, false)
   }
 
   static encodeKey(key: Nibbles): Nibbles {
     return addHexPrefix(key, false)
   }
-
-  static decodeKey(key: Nibbles): Nibbles {
-    return removeHexPrefix(key)
-  }
-
-  get key(): Nibbles {
-    return this._nibbles.slice(0)
-  }
-
-  set key(k: Nibbles) {
-    this._nibbles = k
-  }
-
-  get keyLength() {
-    return this._nibbles.length
-  }
-
-  get value(): Buffer {
-    return this._value
-  }
-
-  set value(v: Buffer) {
-    this._value = v
-  }
-
-  encodedKey(): Nibbles {
-    return ExtensionNode.encodeKey(this._nibbles.slice(0))
-  }
-
-  raw(): [Buffer, Buffer] {
-    return [nibblesToBuffer(this.encodedKey()), this._value]
-  }
-
-  serialize(): Buffer {
-    return Buffer.from(RLP.encode(bufArrToArr(this.raw())))
-  }
 }
diff --git a/packages/trie/src/trie/node/leaf.ts b/packages/trie/src/trie/node/leaf.ts
index ec7593ddc9..198c3ee4e2 100644
--- a/packages/trie/src/trie/node/leaf.ts
+++ b/packages/trie/src/trie/node/leaf.ts
@@ -1,57 +1,15 @@
-import { RLP } from '@ethereumjs/rlp'
-import { bufArrToArr } from '@ethereumjs/util'
+import { addHexPrefix } from '../../util/hex'
 
-import { addHexPrefix, removeHexPrefix } from '../../util/hex'
-import { nibblesToBuffer } from '../../util/nibbles'
+import { Node } from './node'
 
 import type { Nibbles } from '../../types'
 
-export class LeafNode {
-  _nibbles: Nibbles
-  _value: Buffer
-
+export class LeafNode extends Node {
   constructor(nibbles: Nibbles, value: Buffer) {
-    this._nibbles = nibbles
-    this._value = value
+    super(nibbles, value, true)
   }
 
   static encodeKey(key: Nibbles): Nibbles {
     return addHexPrefix(key, true)
   }
-
-  static decodeKey(encodedKey: Nibbles): Nibbles {
-    return removeHexPrefix(encodedKey)
-  }
-
-  get key(): Nibbles {
-    return this._nibbles.slice(0)
-  }
-
-  set key(k: Nibbles) {
-    this._nibbles = k
-  }
-
-  get keyLength() {
-    return this._nibbles.length
-  }
-
-  get value(): Buffer {
-    return this._value
-  }
-
-  set value(v: Buffer) {
-    this._value = v
-  }
-
-  encodedKey(): Nibbles {
-    return LeafNode.encodeKey(this._nibbles.slice(0))
-  }
-
-  raw(): [Buffer, Buffer] {
-    return [nibblesToBuffer(this.encodedKey()), this._value]
-  }
-
-  serialize(): Buffer {
-    return Buffer.from(RLP.encode(bufArrToArr(this.raw())))
-  }
 }
diff --git a/packages/trie/src/trie/node/node.ts b/packages/trie/src/trie/node/node.ts
new file mode 100644
index 0000000000..a24623bcd6
--- /dev/null
+++ b/packages/trie/src/trie/node/node.ts
@@ -0,0 +1,55 @@
+import { RLP } from '@ethereumjs/rlp'
+import { bufArrToArr } from '@ethereumjs/util'
+
+import { addHexPrefix, removeHexPrefix } from '../../util/hex'
+import { nibblesToBuffer } from '../../util/nibbles'
+
+import type { Nibbles } from '../../types'
+
+export class Node {
+  _nibbles: Nibbles
+  _value: Buffer
+  _terminator: boolean
+
+  constructor(nibbles: Nibbles, value: Buffer, terminator: boolean) {
+    this._nibbles = nibbles
+    this._value = value
+    this._terminator = terminator
+  }
+
+  static decodeKey(key: Nibbles): Nibbles {
+    return removeHexPrefix(key)
+  }
+
+  key(k?: Nibbles): Nibbles {
+    if (k !== undefined) {
+      this._nibbles = k
+    }
+
+    return this._nibbles.slice(0)
+  }
+
+  keyLength() {
+    return this._nibbles.length
+  }
+
+  value(v?: Buffer) {
+    if (v !== undefined) {
+      this._value = v
+    }
+
+    return this._value
+  }
+
+  encodedKey(): Nibbles {
+    return addHexPrefix(this._nibbles.slice(0), this._terminator)
+  }
+
+  raw(): [Buffer, Buffer] {
+    return [nibblesToBuffer(this.encodedKey()), this._value]
+  }
+
+  serialize(): Buffer {
+    return Buffer.from(RLP.encode(bufArrToArr(this.raw())))
+  }
+}
diff --git a/packages/trie/src/trie/trie.ts b/packages/trie/src/trie/trie.ts
index f138be135a..aff90e3887 100644
--- a/packages/trie/src/trie/trie.ts
+++ b/packages/trie/src/trie/trie.ts
@@ -15,12 +15,12 @@ import type {
   BatchDBOp,
   EmbeddedNode,
   FoundNodeFunction,
-  HashKeysFunction,
   Nibbles,
   Proof,
   PutBatch,
   TrieNode,
   TrieOpts,
+  TrieOptsWithDefaults,
 } from '../types'
 
 interface Path {
@@ -35,54 +35,55 @@ interface Path {
  * The API for the base and the secure interface are about the same.
  */
 export class Trie {
+  private readonly _opts: TrieOptsWithDefaults = {
+    deleteFromDB: false,
+    useKeyHashing: false,
+    useKeyHashingFunction: keccak256,
+    useRootPersistence: false,
+  }
+
   /** The root for an empty trie */
   EMPTY_TRIE_ROOT: Buffer
-  protected lock: Semaphore
 
   /** The backend DB */
-  db: CheckpointDB
-  protected _root: Buffer
-  protected _deleteFromDB: boolean
-  protected _useHashedKeys: boolean
-  protected _useHashedKeysFunction: HashKeysFunction
+  protected _db: CheckpointDB
   protected _hashLen: number
-  protected _persistRoot: boolean
+  protected _lock: Semaphore = new Semaphore(1)
+  protected _root: Buffer
 
   /**
    * Create a new trie
    * @param opts Options for instantiating the trie
    */
   constructor(opts?: TrieOpts) {
-    this.lock = new Semaphore(1)
+    if (opts !== undefined) {
+      this._opts = { ...this._opts, ...opts }
+    }
 
     if (opts?.db instanceof CheckpointDB) {
       throw new Error('Cannot pass in an instance of CheckpointDB')
     }
 
-    this.db = new CheckpointDB(opts?.db ?? new MapDB())
-    this._useHashedKeys = opts?.useHashedKeys ?? false
-    this._useHashedKeysFunction = opts?.useHashedKeysFunction ?? keccak256
+    this._db = new CheckpointDB(opts?.db ?? new MapDB())
     this.EMPTY_TRIE_ROOT = this.hash(RLP_EMPTY_STRING)
     this._hashLen = this.EMPTY_TRIE_ROOT.length
     this._root = this.EMPTY_TRIE_ROOT
-    this._deleteFromDB = opts?.deleteFromDB ?? false
-    this._persistRoot = opts?.persistRoot ?? false
 
     if (opts?.root) {
-      this.root = opts.root
+      this.root(opts.root)
     }
   }
 
   static async create(opts?: TrieOpts) {
     let key = ROOT_DB_KEY
 
-    if (opts?.useHashedKeys === true) {
-      key = (opts?.useHashedKeysFunction ?? keccak256)(ROOT_DB_KEY) as Buffer
+    if (opts?.useKeyHashing === true) {
+      key = (opts?.useKeyHashingFunction ?? keccak256)(ROOT_DB_KEY) as Buffer
     }
 
     key = Buffer.from(key)
 
-    if (opts?.db !== undefined && opts?.persistRoot === true) {
+    if (opts?.db !== undefined && opts?.useRootPersistence === true) {
       if (opts?.root === undefined) {
         opts.root = (await opts?.db.get(key)) ?? undefined
       } else {
@@ -94,21 +95,21 @@ export class Trie {
   }
 
   /**
-   * Sets the current root of the `trie`
+   * Gets and/or Sets the current root of the `trie`
    */
-  set root(value: Buffer) {
-    if (isFalsy(value)) {
-      value = this.EMPTY_TRIE_ROOT
+  root(value?: Buffer): Buffer {
+    if (value !== undefined) {
+      if (isFalsy(value)) {
+        value = this.EMPTY_TRIE_ROOT
+      }
+
+      if (value.length !== this._hashLen) {
+        throw new Error(`Invalid root length. Roots are ${this._hashLen} bytes`)
+      }
+
+      this._root = value
     }
-    if (value.length !== this._hashLen)
-      throw new Error(`Invalid root length. Roots are ${this._hashLen} bytes`)
-    this._root = value
-  }
 
-  /**
-   * Gets the current root of the `trie`
-   */
-  get root(): Buffer {
     return this._root
   }
 
@@ -138,7 +139,7 @@ export class Trie {
     const { node, remaining } = await this.findPath(this.appliedKey(key), throwIfMissing)
     let value = null
     if (node && remaining.length === 0) {
-      value = node.value
+      value = node.value()
     }
     return value
   }
@@ -151,7 +152,7 @@ export class Trie {
    * @returns A Promise that resolves once value is stored.
    */
   async put(key: Buffer, value: Buffer): Promise<void> {
-    if (this._persistRoot && key.equals(ROOT_DB_KEY)) {
+    if (this._opts.useRootPersistence && key.equals(ROOT_DB_KEY)) {
       throw new Error(`Attempted to set '${ROOT_DB_KEY.toString()}' key but it is not allowed.`)
     }
 
@@ -160,9 +161,9 @@ export class Trie {
       return await this.del(key)
     }
 
-    await this.lock.wait()
+    await this._lock.acquire()
     const appliedKey = this.appliedKey(key)
-    if (this.root.equals(this.EMPTY_TRIE_ROOT)) {
+    if (this.root().equals(this.EMPTY_TRIE_ROOT)) {
       // If no root, initialize this trie
       await this._createInitialNode(appliedKey, value)
     } else {
@@ -172,7 +173,7 @@ export class Trie {
       await this._updateNode(appliedKey, value, remaining, stack)
     }
     await this.persistRoot()
-    this.lock.signal()
+    this._lock.release()
   }
 
   /**
@@ -182,14 +183,14 @@ export class Trie {
    * @returns A Promise that resolves once value is deleted.
    */
   async del(key: Buffer): Promise<void> {
-    await this.lock.wait()
+    await this._lock.acquire()
     const appliedKey = this.appliedKey(key)
     const { node, stack } = await this.findPath(appliedKey)
     if (node) {
       await this._deleteNode(appliedKey, stack)
     }
     await this.persistRoot()
-    this.lock.signal()
+    this._lock.release()
   }
 
   /**
@@ -204,7 +205,7 @@ export class Trie {
       const stack: TrieNode[] = []
       const targetKey = bufferToNibbles(key)
 
-      const onFound: FoundNodeFunction = async (nodeRef, node, keyProgress, walkController) => {
+      const onFound: FoundNodeFunction = async (_, node, keyProgress, walkController) => {
         if (node === null) {
           return reject(new Error('Path not found'))
         }
@@ -228,7 +229,7 @@ export class Trie {
             }
           }
         } else if (node instanceof LeafNode) {
-          if (doKeysMatch(keyRemainder, node.key)) {
+          if (doKeysMatch(keyRemainder, node.key())) {
             // keys match, return node with empty key
             resolve({ node, remaining: [], stack })
           } else {
@@ -236,8 +237,8 @@ export class Trie {
             resolve({ node: null, remaining: keyRemainder, stack })
           }
         } else if (node instanceof ExtensionNode) {
-          const matchingLen = matchingNibbleLength(keyRemainder, node.key)
-          if (matchingLen !== node.key.length) {
+          const matchingLen = matchingNibbleLength(keyRemainder, node.key())
+          if (matchingLen !== node.key().length) {
             // keys don't match, fail
             resolve({ node: null, remaining: keyRemainder, stack })
           } else {
@@ -249,7 +250,7 @@ export class Trie {
 
       // walk trie and process nodes
       try {
-        await this.walkTrie(this.root, onFound)
+        await this.walkTrie(this.root(), onFound)
       } catch (error: any) {
         if (error.message === 'Missing node in DB' && !throwIfMissing) {
           // pass
@@ -281,8 +282,8 @@ export class Trie {
     const newNode = new LeafNode(bufferToNibbles(key), value)
 
     const encoded = newNode.serialize()
-    this.root = this.hash(encoded)
-    await this.db.put(this.root, encoded)
+    this.root(this.hash(encoded))
+    await this._db.put(this.root(), encoded)
     await this.persistRoot()
   }
 
@@ -295,7 +296,7 @@ export class Trie {
     }
     let value = null
     let foundNode = null
-    value = await this.db.get(node as Buffer)
+    value = await this._db.get(node as Buffer)
     if (value) {
       foundNode = decodeNode(value)
     } else {
@@ -338,12 +339,12 @@ export class Trie {
         if (n instanceof BranchNode) {
           l++
         } else {
-          l += n.key.length
+          l += n.key().length
         }
       }
 
       if (
-        matchingNibbleLength(lastNode.key, key.slice(l)) === lastNode.key.length &&
+        matchingNibbleLength(lastNode.key(), key.slice(l)) === lastNode.key().length &&
         keyRemainder.length === 0
       ) {
         matchLeaf = true
@@ -352,7 +353,7 @@ export class Trie {
 
     if (matchLeaf) {
       // just updating a found value
-      lastNode.value = value
+      lastNode.value(value)
       stack.push(lastNode as TrieNode)
     } else if (lastNode instanceof BranchNode) {
       stack.push(lastNode)
@@ -363,17 +364,17 @@ export class Trie {
         const newLeaf = new LeafNode(keyRemainder, value)
         stack.push(newLeaf)
       } else {
-        lastNode.value = value
+        lastNode.value(value)
       }
     } else {
       // create a branch node
-      const lastKey = lastNode.key
+      const lastKey = lastNode.key()
       const matchingLength = matchingNibbleLength(lastKey, keyRemainder)
       const newBranchNode = new BranchNode()
 
       // create a new extension node
       if (matchingLength !== 0) {
-        const newKey = lastNode.key.slice(0, matchingLength)
+        const newKey = lastNode.key().slice(0, matchingLength)
         const newExtNode = new ExtensionNode(newKey, value)
         stack.push(newExtNode)
         lastKey.splice(0, matchingLength)
@@ -387,16 +388,16 @@ export class Trie {
 
         if (lastKey.length !== 0 || lastNode instanceof LeafNode) {
           // shrinking extension or leaf
-          lastNode.key = lastKey
+          lastNode.key(lastKey)
           const formattedNode = this._formatNode(lastNode, false, toSave)
           newBranchNode.setBranch(branchKey, formattedNode as EmbeddedNode)
         } else {
           // remove extension or attaching
           this._formatNode(lastNode, false, toSave, true)
-          newBranchNode.setBranch(branchKey, lastNode.value)
+          newBranchNode.setBranch(branchKey, lastNode.value())
         }
       } else {
-        newBranchNode.value = lastNode.value
+        newBranchNode.value(lastNode.value())
       }
 
       if (keyRemainder.length !== 0) {
@@ -405,7 +406,7 @@ export class Trie {
         const newLeafNode = new LeafNode(keyRemainder, value)
         stack.push(newLeafNode)
       } else {
-        newBranchNode.value = value
+        newBranchNode.value(value)
       }
     }
 
@@ -439,33 +440,33 @@ export class Trie {
           stack.push(extensionNode)
           key.push(branchKey)
         } else {
-          const branchNodeKey = branchNode.key
+          const branchNodeKey = branchNode.key()
           // branch key is an extension or a leaf
           // branch->(leaf or extension)
           branchNodeKey.unshift(branchKey)
-          branchNode.key = branchNodeKey.slice(0)
+          branchNode.key(branchNodeKey.slice(0))
           key = key.concat(branchNodeKey)
         }
         stack.push(branchNode)
       } else {
         // parent is an extension
-        let parentKey = parentNode.key
+        let parentKey = parentNode.key()
 
         if (branchNode instanceof BranchNode) {
           // ext->branch
           parentKey.push(branchKey)
           key.push(branchKey)
-          parentNode.key = parentKey
+          parentNode.key(parentKey)
           stack.push(parentNode)
         } else {
-          const branchNodeKey = branchNode.key
+          const branchNodeKey = branchNode.key()
           // branch node is an leaf or extension and parent node is an exstention
           // add two keys together
           // dont push the parent node
           branchNodeKey.unshift(branchKey)
           key = key.concat(branchNodeKey)
           parentKey = parentKey.concat(branchNodeKey)
-          branchNode.key = parentKey
+          branchNode.key(parentKey)
         }
 
         stack.push(branchNode)
@@ -483,19 +484,19 @@ export class Trie {
 
     if (!parentNode) {
       // the root here has to be a leaf.
-      this.root = this.EMPTY_TRIE_ROOT
+      this.root(this.EMPTY_TRIE_ROOT)
       return
     }
 
     if (lastNode instanceof BranchNode) {
-      lastNode.value = null
+      lastNode.value(null)
     } else {
       // the lastNode has to be a leaf if it's not a branch.
       // And a leaf's parent, if it has one, must be a branch.
       if (!(parentNode instanceof BranchNode)) {
         throw new Error('Expected branch node')
       }
-      const lastNodeKey = lastNode.key
+      const lastNodeKey = lastNode.key()
       key.splice(key.length - lastNodeKey.length)
       // delete the value
       this._formatNode(lastNode, false, opStack, true)
@@ -551,11 +552,11 @@ export class Trie {
     while (stack.length) {
       const node = stack.pop() as TrieNode
       if (node instanceof LeafNode) {
-        key.splice(key.length - node.key.length)
+        key.splice(key.length - node.key().length)
       } else if (node instanceof ExtensionNode) {
-        key.splice(key.length - node.key.length)
+        key.splice(key.length - node.key().length)
         if (lastRoot) {
-          node.value = lastRoot
+          node.value(lastRoot)
         }
       } else if (node instanceof BranchNode) {
         if (lastRoot) {
@@ -567,10 +568,10 @@ export class Trie {
     }
 
     if (lastRoot) {
-      this.root = lastRoot
+      this.root(lastRoot)
     }
 
-    await this.db.batch(opStack)
+    await this._db.batch(opStack)
     await this.persistRoot()
   }
 
@@ -595,7 +596,7 @@ export class Trie {
       const hashRoot = Buffer.from(this.hash(encoded))
 
       if (remove) {
-        if (this._deleteFromDB) {
+        if (this._opts.deleteFromDB) {
           opStack.push({
             type: 'del',
             key: hashRoot,
@@ -656,11 +657,11 @@ export class Trie {
       } as PutBatch
     })
 
-    if (this.root === this.EMPTY_TRIE_ROOT && isTruthy(opStack[0])) {
-      this.root = opStack[0].key
+    if (this.root() === this.EMPTY_TRIE_ROOT && isTruthy(opStack[0])) {
+      this.root(opStack[0].key)
     }
 
-    await this.db.batch(opStack)
+    await this._db.batch(opStack)
     await this.persistRoot()
     return
   }
@@ -688,7 +689,7 @@ export class Trie {
   async verifyProof(rootHash: Buffer, key: Buffer, proof: Proof): Promise<Buffer | null> {
     const proofTrie = new Trie({
       root: rootHash,
-      useHashedKeysFunction: this._useHashedKeysFunction,
+      useKeyHashingFunction: this._opts.useKeyHashingFunction,
     })
     try {
       await proofTrie.fromProof(proof)
@@ -725,7 +726,7 @@ export class Trie {
       keys.map((k) => this.appliedKey(k)).map(bufferToNibbles),
       values,
       proof,
-      this._useHashedKeysFunction
+      this._opts.useKeyHashingFunction
     )
   }
 
@@ -743,15 +744,12 @@ export class Trie {
    */
   copy(includeCheckpoints = true): Trie {
     const trie = new Trie({
-      db: this.db.db.copy(),
-      deleteFromDB: this._deleteFromDB,
-      persistRoot: this._persistRoot,
-      root: this.root,
-      useHashedKeys: this._useHashedKeys,
-      useHashedKeysFunction: this._useHashedKeysFunction,
+      ...this._opts,
+      db: this._db.db.copy(),
+      root: this.root(),
     })
     if (includeCheckpoints && this.hasCheckpoints()) {
-      trie.db.checkpoints = [...this.db.checkpoints]
+      trie._db.checkpoints = [...this._db.checkpoints]
     }
     return trie
   }
@@ -760,8 +758,8 @@ export class Trie {
    * Persists the root hash in the underlying database
    */
   async persistRoot() {
-    if (this._persistRoot === true) {
-      await this.db.put(this.appliedKey(ROOT_DB_KEY), this.root)
+    if (this._opts.useRootPersistence) {
+      await this._db.put(this.appliedKey(ROOT_DB_KEY), this.root())
     }
   }
 
@@ -781,30 +779,30 @@ export class Trie {
         onFound(nodeRef, node, key, walkController)
       }
     }
-    await this.walkTrie(this.root, outerOnFound)
+    await this.walkTrie(this.root(), outerOnFound)
   }
 
   /**
    * Returns the key practically applied for trie construction
-   * depending on the `useHashedKeys` option being set or not.
+   * depending on the `useKeyHashing` option being set or not.
    * @param key
    */
   protected appliedKey(key: Buffer) {
-    if (this._useHashedKeys) {
+    if (this._opts.useKeyHashing) {
       return this.hash(key)
     }
     return key
   }
 
   protected hash(msg: Uint8Array): Buffer {
-    return Buffer.from(this._useHashedKeysFunction(msg))
+    return Buffer.from(this._opts.useKeyHashingFunction(msg))
   }
 
   /**
    * Is the trie during a checkpoint phase?
    */
   hasCheckpoints() {
-    return this.db.hasCheckpoints()
+    return this._db.hasCheckpoints()
   }
 
   /**
@@ -812,7 +810,7 @@ export class Trie {
    * After this is called, all changes can be reverted until `commit` is called.
    */
   checkpoint() {
-    this.db.checkpoint(this.root)
+    this._db.checkpoint(this.root())
   }
 
   /**
@@ -825,10 +823,10 @@ export class Trie {
       throw new Error('trying to commit when not checkpointed')
     }
 
-    await this.lock.wait()
-    await this.db.commit()
+    await this._lock.acquire()
+    await this._db.commit()
     await this.persistRoot()
-    this.lock.signal()
+    this._lock.release()
   }
 
   /**
@@ -841,9 +839,16 @@ export class Trie {
       throw new Error('trying to revert when not checkpointed')
     }
 
-    await this.lock.wait()
-    this.root = await this.db.revert()
+    await this._lock.acquire()
+    this.root(await this._db.revert())
     await this.persistRoot()
-    this.lock.signal()
+    this._lock.release()
+  }
+
+  /**
+   * Flushes all checkpoints, restoring the initial checkpoint state.
+   */
+  flushCheckpoints() {
+    this._db.checkpoints = []
   }
 }
diff --git a/packages/trie/src/types.ts b/packages/trie/src/types.ts
index a433b735e2..7eb73b9ce7 100644
--- a/packages/trie/src/types.ts
+++ b/packages/trie/src/types.ts
@@ -47,19 +47,26 @@ export interface TrieOpts {
    *
    * Note: This functionality has been refactored along the v5 release and was before
    * provided as a separate inherited class `SecureTrie`. Just replace with `Trie`
-   * instantiation with `useHashedKeys` set to `true`.
+   * instantiation with `useKeyHashing` set to `true`.
    */
-  useHashedKeys?: boolean
+  useKeyHashing?: boolean
 
   /**
    * Hash function used for hashing trie node and securing key.
    */
-  useHashedKeysFunction?: HashKeysFunction
+  useKeyHashingFunction?: HashKeysFunction
 
   /**
    * Store the root inside the database after every `write` operation
    */
-  persistRoot?: boolean
+  useRootPersistence?: boolean
+}
+
+export type TrieOptsWithDefaults = TrieOpts & {
+  deleteFromDB: boolean
+  useKeyHashing: boolean
+  useKeyHashingFunction: HashKeysFunction
+  useRootPersistence: boolean
 }
 
 export type BatchDBOp = PutBatch | DelBatch
diff --git a/packages/trie/src/util/readStream.ts b/packages/trie/src/util/readStream.ts
index 014bd6ad01..76d31f4986 100644
--- a/packages/trie/src/util/readStream.ts
+++ b/packages/trie/src/util/readStream.ts
@@ -28,7 +28,7 @@ export class TrieReadStream extends Readable {
         if (node !== null) {
           this.push({
             key: nibblesToBuffer(key),
-            value: node.value,
+            value: node.value(),
           })
           walkController.allChildren(node, key)
         }
@@ -53,10 +53,10 @@ export class TrieReadStream extends Readable {
       let fullKey = key
 
       if (node instanceof LeafNode) {
-        fullKey = key.concat(node.key)
+        fullKey = key.concat(node.key())
         // found leaf node!
         onFound(nodeRef, node, fullKey, walkController)
-      } else if (node instanceof BranchNode && node.value) {
+      } else if (node instanceof BranchNode && node.value()) {
         // found branch with value
         onFound(nodeRef, node, fullKey, walkController)
       } else {
@@ -66,6 +66,6 @@ export class TrieReadStream extends Readable {
         }
       }
     }
-    await this.trie.walkTrie(this.trie.root, outerOnFound)
+    await this.trie.walkTrie(this.trie.root(), outerOnFound)
   }
 }
diff --git a/packages/trie/src/util/semaphore.ts b/packages/trie/src/util/semaphore.ts
index 680ae31d91..202cac6c06 100644
--- a/packages/trie/src/util/semaphore.ts
+++ b/packages/trie/src/util/semaphore.ts
@@ -17,7 +17,7 @@ export class Semaphore {
    * Returns a promise used to wait for a permit to become available. This method should be awaited on.
    * @returns  A promise that gets resolved when execution is allowed to proceed.
    */
-  public async wait(): Promise<boolean> {
+  public async acquire(): Promise<boolean> {
     if (this.permits > 0) {
       this.permits -= 1
       return Promise.resolve(true)
@@ -32,7 +32,7 @@ export class Semaphore {
    * Increases the number of permits by one. If there are other functions waiting, one of them will
    * continue to execute in a future iteration of the event loop.
    */
-  public signal(): void {
+  public release(): void {
     this.permits += 1
 
     if (this.permits > 1 && this.promiseResolverQueue.length > 0) {
diff --git a/packages/trie/src/util/walkController.ts b/packages/trie/src/util/walkController.ts
index 2411b866d1..64e697baa4 100644
--- a/packages/trie/src/util/walkController.ts
+++ b/packages/trie/src/util/walkController.ts
@@ -72,7 +72,7 @@ export class WalkController {
     }
     let children
     if (node instanceof ExtensionNode) {
-      children = [[node.key, node.value]]
+      children = [[node.key(), node.value()]]
     } else if (node instanceof BranchNode) {
       children = node.getChildren().map((b) => [[b[0]], b[1]])
     }
diff --git a/packages/trie/test/encoding.spec.ts b/packages/trie/test/encoding.spec.ts
index 7da65d1c01..a55b8ea874 100644
--- a/packages/trie/test/encoding.spec.ts
+++ b/packages/trie/test/encoding.spec.ts
@@ -10,6 +10,6 @@ const hex = 'FF44A3B3'
 tape('encoding hex prefixes', async function (t) {
   await trie.put(Buffer.from(hex, 'hex'), Buffer.from('test'))
   await trie2.put(toBuffer(`0x${hex}`), Buffer.from('test'))
-  t.equal(trie.root.toString('hex'), trie2.root.toString('hex'))
+  t.equal(trie.root().toString('hex'), trie2.root().toString('hex'))
   t.end()
 })
diff --git a/packages/trie/test/index.spec.ts b/packages/trie/test/index.spec.ts
index 56d22401cc..926e351296 100644
--- a/packages/trie/test/index.spec.ts
+++ b/packages/trie/test/index.spec.ts
@@ -68,7 +68,7 @@ tape('simple save and retrieve', function (tester) {
     await trie.put(Buffer.from('doge'), Buffer.from('coin'))
     t.equal(
       'de8a34a8c1d558682eae1528b47523a483dd8685d6db14b291451a66066bf0fc',
-      trie.root.toString('hex')
+      trie.root().toString('hex')
     )
     t.end()
   })
@@ -95,7 +95,7 @@ tape('simple save and retrieve', function (tester) {
     it('should store a longer string', async function (t) {
       await trie.put(Buffer.from('done'), Buffer.from(longString))
       await trie.put(Buffer.from('doge'), Buffer.from('coin'))
-      t.equal(longStringRoot, trie.root.toString('hex'))
+      t.equal(longStringRoot, trie.root().toString('hex'))
       t.end()
     })
 
@@ -124,7 +124,7 @@ tape('simple save and retrieve', function (tester) {
       await trie.put(Buffer.from('do'), Buffer.from('verb'))
       t.equal(
         'f803dfcb7e8f1afd45e88eedb4699a7138d6c07b71243d9ae9bff720c99925f9',
-        trie.root.toString('hex')
+        trie.root().toString('hex')
       )
       t.end()
     })
@@ -133,7 +133,7 @@ tape('simple save and retrieve', function (tester) {
       await trie.put(Buffer.from('done'), Buffer.from('finished'))
       t.equal(
         '409cff4d820b394ed3fb1cd4497bdd19ffa68d30ae34157337a7043c94a3e8cb',
-        trie.root.toString('hex')
+        trie.root().toString('hex')
       )
       t.end()
     })
@@ -157,7 +157,7 @@ tape('simple save and retrieve', function (tester) {
       await trie.put(Buffer.from('done'), Buffer.from('finished'))
       t.equal(
         '409cff4d820b394ed3fb1cd4497bdd19ffa68d30ae34157337a7043c94a3e8cb',
-        trie.root.toString('hex')
+        trie.root().toString('hex')
       )
       t.end()
     })
@@ -252,7 +252,8 @@ tape('shall handle the case of node not found correctly', async (t) => {
   t.ok(path.node !== null, 'findPath should find a node')
 
   const { stack } = await trie.findPath(Buffer.from('aaa'))
-  await trie.db.del(Buffer.from(keccak256(stack[1].serialize()))) // delete the BranchNode -> value1 from the DB
+  // @ts-expect-error
+  await trie._db.del(Buffer.from(keccak256(stack[1].serialize()))) // delete the BranchNode -> value1 from the DB
 
   path = await trie.findPath(Buffer.from('aaa'))
 
@@ -294,7 +295,7 @@ tape('it should create the genesis state root from ethereum', function (tester)
     await trie4.put(j, rlpAccount)
     await trie4.put(v, rlpAccount)
     await trie4.put(a, rlpAccount)
-    t.equal(trie4.root.toString('hex'), genesisStateRoot)
+    t.equal(trie4.root().toString('hex'), genesisStateRoot)
     t.end()
   })
 })
@@ -338,7 +339,7 @@ tape('setting back state root (deleteFromDB)', async (t) => {
       'should return null on latest state root independently from deleteFromDB setting'
     )
 
-    s.trie.root = rootAfterK1
+    s.trie.root(rootAfterK1)
     t.deepEqual(await s.trie.get(k1), s.expected, s.msg)
   }
 
@@ -346,7 +347,7 @@ tape('setting back state root (deleteFromDB)', async (t) => {
 })
 
 tape('dummy hash', async (t) => {
-  const useHashedKeysFunction: HashKeysFunction = (msg) => {
+  const useKeyHashingFunction: HashKeysFunction = (msg) => {
     const hashLen = 32
     if (msg.length <= hashLen - 5) {
       return Buffer.concat([Buffer.from('hash_'), Buffer.alloc(hashLen - msg.length, 0), msg])
@@ -357,22 +358,22 @@ tape('dummy hash', async (t) => {
 
   const [k, v] = [Buffer.from('foo'), Buffer.from('bar')]
   const expectedRoot = Buffer.from(
-    useHashedKeysFunction(new LeafNode(bufferToNibbles(k), v).serialize())
+    useKeyHashingFunction(new LeafNode(bufferToNibbles(k), v).serialize())
   )
 
-  const trie = new Trie({ useHashedKeysFunction })
+  const trie = new Trie({ useKeyHashingFunction })
   await trie.put(k, v)
-  t.equal(trie.root.toString('hex'), expectedRoot.toString('hex'))
+  t.equal(trie.root().toString('hex'), expectedRoot.toString('hex'))
 
   t.end()
 })
 
 tape('blake2b256 trie root', async (t) => {
-  const trie = new Trie({ useHashedKeysFunction: (msg) => blake2b(msg, 32) })
+  const trie = new Trie({ useKeyHashingFunction: (msg) => blake2b(msg, 32) })
   await trie.put(Buffer.from('foo'), Buffer.from('bar'))
 
   t.equal(
-    trie.root.toString('hex'),
+    trie.root().toString('hex'),
     'e118db4e01512253df38daafa16fc1d69e03e755595b5847d275d7404ebdc74a'
   )
   t.end()
@@ -381,6 +382,6 @@ tape('blake2b256 trie root', async (t) => {
 tape('empty root', async (t) => {
   const trie = new Trie()
 
-  t.equal(trie.root.toString('hex'), KECCAK256_RLP_S)
+  t.equal(trie.root().toString('hex'), KECCAK256_RLP_S)
   t.end()
 })
diff --git a/packages/trie/test/official.spec.ts b/packages/trie/test/official.spec.ts
index f1a7b265e0..1ad27b7ba7 100644
--- a/packages/trie/test/official.spec.ts
+++ b/packages/trie/test/official.spec.ts
@@ -21,7 +21,7 @@ tape('official tests', async function (t) {
         await trie.put(Buffer.from(input[0]), input[1])
       }
     }
-    t.equal('0x' + trie.root.toString('hex'), expect)
+    t.equal('0x' + trie.root().toString('hex'), expect)
     trie = new Trie()
   }
   t.end()
@@ -48,7 +48,7 @@ tape('official tests any order', async function (t) {
 
       await trie.put(Buffer.from(key), Buffer.from(val))
     }
-    t.equal('0x' + trie.root.toString('hex'), test.root)
+    t.equal('0x' + trie.root().toString('hex'), test.root)
     trie = new Trie()
   }
   t.end()
diff --git a/packages/trie/test/proof.spec.ts b/packages/trie/test/proof.spec.ts
index b0c0eff557..fd20d4795a 100644
--- a/packages/trie/test/proof.spec.ts
+++ b/packages/trie/test/proof.spec.ts
@@ -13,28 +13,28 @@ tape('simple merkle proofs generation and verification', function (tester) {
     await trie.put(Buffer.from('key3cc'), Buffer.from('aval3'))
 
     let proof = await trie.createProof(Buffer.from('key2bb'))
-    let val = await trie.verifyProof(trie.root, Buffer.from('key2bb'), proof)
+    let val = await trie.verifyProof(trie.root(), Buffer.from('key2bb'), proof)
     t.equal(val!.toString('utf8'), 'aval2')
 
     proof = await trie.createProof(Buffer.from('key1aa'))
-    val = await trie.verifyProof(trie.root, Buffer.from('key1aa'), proof)
+    val = await trie.verifyProof(trie.root(), Buffer.from('key1aa'), proof)
     t.equal(val!.toString('utf8'), '0123456789012345678901234567890123456789xx')
 
     proof = await trie.createProof(Buffer.from('key2bb'))
-    val = await trie.verifyProof(trie.root, Buffer.from('key2'), proof)
+    val = await trie.verifyProof(trie.root(), Buffer.from('key2'), proof)
     // In this case, the proof _happens_ to contain enough nodes to prove `key2` because
     // traversing into `key22` would touch all the same nodes as traversing into `key2`
     t.equal(val, null, 'Expected value at a random key to be null')
 
     let myKey = Buffer.from('anyrandomkey')
     proof = await trie.createProof(myKey)
-    val = await trie.verifyProof(trie.root, myKey, proof)
+    val = await trie.verifyProof(trie.root(), myKey, proof)
     t.equal(val, null, 'Expected value to be null')
 
     myKey = Buffer.from('anothergarbagekey') // should generate a valid proof of null
     proof = await trie.createProof(myKey)
     proof.push(Buffer.from('123456')) // extra nodes are just ignored
-    val = await trie.verifyProof(trie.root, myKey, proof)
+    val = await trie.verifyProof(trie.root(), myKey, proof)
     t.equal(val, null, 'Expected value to be null')
 
     await trie.put(Buffer.from('another'), Buffer.from('3498h4riuhgwe'))
@@ -43,7 +43,7 @@ tape('simple merkle proofs generation and verification', function (tester) {
     proof = await trie.createProof(Buffer.from('another'))
     // and try to use that proof on another key
     try {
-      await trie.verifyProof(trie.root, Buffer.from('key1aa'), proof)
+      await trie.verifyProof(trie.root(), Buffer.from('key1aa'), proof)
       t.fail('expected error: Invalid proof provided')
     } catch (e: any) {
       t.equal(e.message, 'Invalid proof provided')
@@ -53,7 +53,7 @@ tape('simple merkle proofs generation and verification', function (tester) {
     proof = await trie.createProof(Buffer.from('key2bb'))
     proof[0].reverse()
     try {
-      await trie.verifyProof(trie.root, Buffer.from('key2bb'), proof)
+      await trie.verifyProof(trie.root(), Buffer.from('key2bb'), proof)
       t.fail('expected error: Invalid proof provided')
     } catch (e: any) {
       t.equal(e.message, 'Invalid proof provided')
@@ -63,12 +63,12 @@ tape('simple merkle proofs generation and verification', function (tester) {
     // a valid exclusion proof then making it non-null
     myKey = Buffer.from('anyrandomkey')
     proof = await trie.createProof(myKey)
-    val = await trie.verifyProof(trie.root, myKey, proof)
+    val = await trie.verifyProof(trie.root(), myKey, proof)
     t.equal(val, null, 'Expected value to be null')
     // now make the key non-null so the exclusion proof becomes invalid
     await trie.put(myKey, Buffer.from('thisisavalue'))
     try {
-      await trie.verifyProof(trie.root, myKey, proof)
+      await trie.verifyProof(trie.root(), myKey, proof)
       t.fail('expected error: Invalid proof provided')
     } catch (e: any) {
       t.equal(e.message, 'Invalid proof provided')
@@ -83,7 +83,7 @@ tape('simple merkle proofs generation and verification', function (tester) {
     await trie.put(Buffer.from('key1aa'), Buffer.from('0123456789012345678901234567890123456789xx'))
 
     const proof = await trie.createProof(Buffer.from('key1aa'))
-    const val = await trie.verifyProof(trie.root, Buffer.from('key1aa'), proof)
+    const val = await trie.verifyProof(trie.root(), Buffer.from('key1aa'), proof)
     t.equal(val!.toString('utf8'), '0123456789012345678901234567890123456789xx')
 
     t.end()
@@ -95,7 +95,7 @@ tape('simple merkle proofs generation and verification', function (tester) {
     await trie.put(Buffer.from('key1aa'), Buffer.from('01234'))
 
     const proof = await trie.createProof(Buffer.from('key1aa'))
-    const val = await trie.verifyProof(trie.root, Buffer.from('key1aa'), proof)
+    const val = await trie.verifyProof(trie.root(), Buffer.from('key1aa'), proof)
     t.equal(val!.toString('utf8'), '01234')
 
     t.end()
@@ -118,15 +118,15 @@ tape('simple merkle proofs generation and verification', function (tester) {
     await trie.put(Buffer.from('key3'), Buffer.from('1234567890123456789012345678901'))
 
     let proof = await trie.createProof(Buffer.from('key1'))
-    let val = await trie.verifyProof(trie.root, Buffer.from('key1'), proof)
+    let val = await trie.verifyProof(trie.root(), Buffer.from('key1'), proof)
     t.equal(val!.toString('utf8'), '0123456789012345678901234567890123456789Very_Long')
 
     proof = await trie.createProof(Buffer.from('key2'))
-    val = await trie.verifyProof(trie.root, Buffer.from('key2'), proof)
+    val = await trie.verifyProof(trie.root(), Buffer.from('key2'), proof)
     t.equal(val!.toString('utf8'), 'short')
 
     proof = await trie.createProof(Buffer.from('key3'))
-    val = await trie.verifyProof(trie.root, Buffer.from('key3'), proof)
+    val = await trie.verifyProof(trie.root(), Buffer.from('key3'), proof)
     t.equal(val!.toString('utf8'), '1234567890123456789012345678901')
 
     t.end()
@@ -140,15 +140,15 @@ tape('simple merkle proofs generation and verification', function (tester) {
     await trie.put(Buffer.from('c'), Buffer.from('c'))
 
     let proof = await trie.createProof(Buffer.from('a'))
-    let val = await trie.verifyProof(trie.root, Buffer.from('a'), proof)
+    let val = await trie.verifyProof(trie.root(), Buffer.from('a'), proof)
     t.equal(val!.toString('utf8'), 'a')
 
     proof = await trie.createProof(Buffer.from('b'))
-    val = await trie.verifyProof(trie.root, Buffer.from('b'), proof)
+    val = await trie.verifyProof(trie.root(), Buffer.from('b'), proof)
     t.equal(val!.toString('utf8'), 'b')
 
     proof = await trie.createProof(Buffer.from('c'))
-    val = await trie.verifyProof(trie.root, Buffer.from('c'), proof)
+    val = await trie.verifyProof(trie.root(), Buffer.from('c'), proof)
     t.equal(val!.toString('utf8'), 'c')
 
     t.end()
diff --git a/packages/trie/test/proof/range.spec.ts b/packages/trie/test/proof/range.spec.ts
index a4da3eb45f..0b6b3d9aad 100644
--- a/packages/trie/test/proof/range.spec.ts
+++ b/packages/trie/test/proof/range.spec.ts
@@ -82,7 +82,7 @@ async function verify(
   endKey = endKey ?? entries[end][0]
   const targetRange = entries.slice(start, end + 1)
   return await trie.verifyRangeProof(
-    trie.root,
+    trie.root(),
     startKey,
     endKey,
     keys ?? targetRange.map(([key]) => key),
@@ -199,7 +199,7 @@ tape('simple merkle range proofs generation and verification', function (tester)
 
     t.equal(
       await trie.verifyRangeProof(
-        trie.root,
+        trie.root(),
         null,
         null,
         entries.map(([key]) => key),
diff --git a/packages/trie/test/trie/checkpoint.spec.ts b/packages/trie/test/trie/checkpoint.spec.ts
index 8e51290d31..4ee05373f4 100644
--- a/packages/trie/test/trie/checkpoint.spec.ts
+++ b/packages/trie/test/trie/checkpoint.spec.ts
@@ -17,13 +17,13 @@ tape('testing checkpoints', function (tester) {
     trie = new Trie()
     await trie.put(Buffer.from('do'), Buffer.from('verb'))
     await trie.put(Buffer.from('doge'), Buffer.from('coin'))
-    preRoot = trie.root.toString('hex')
+    preRoot = trie.root().toString('hex')
     t.end()
   })
 
   it('should copy trie and get value added to original trie', async function (t) {
     trieCopy = trie.copy()
-    t.equal(trieCopy.root.toString('hex'), preRoot)
+    t.equal(trieCopy.root().toString('hex'), preRoot)
     const res = await trieCopy.get(Buffer.from('do'))
     t.ok(Buffer.from('verb').equals(Buffer.from(res!)))
     t.end()
@@ -38,7 +38,7 @@ tape('testing checkpoints', function (tester) {
   it('should save to the cache', async function (t) {
     await trie.put(Buffer.from('test'), Buffer.from('something'))
     await trie.put(Buffer.from('love'), Buffer.from('emotion'))
-    postRoot = trie.root.toString('hex')
+    postRoot = trie.root().toString('hex')
     t.end()
   })
 
@@ -56,8 +56,9 @@ tape('testing checkpoints', function (tester) {
 
   it('should copy trie and get upstream and cache values after checkpoint', async function (t) {
     trieCopy = trie.copy()
-    t.equal(trieCopy.root.toString('hex'), postRoot)
-    t.equal(trieCopy.db.checkpoints.length, 1)
+    t.equal(trieCopy.root().toString('hex'), postRoot)
+    // @ts-expect-error
+    t.equal(trieCopy._db.checkpoints.length, 1)
     t.ok(trieCopy.hasCheckpoints())
     const res = await trieCopy.get(Buffer.from('do'))
     t.ok(Buffer.from('verb').equals(Buffer.from(res!)))
@@ -69,8 +70,8 @@ tape('testing checkpoints', function (tester) {
   it('should copy trie and use the correct hash function', async function (t) {
     const trie = new Trie({
       db: new MapDB(),
-      useHashedKeys: true,
-      useHashedKeysFunction: (value) => createHash('sha256').update(value).digest(),
+      useKeyHashing: true,
+      useKeyHashingFunction: (value) => createHash('sha256').update(value).digest(),
     })
 
     await trie.put(Buffer.from('key1'), Buffer.from('value1'))
@@ -85,7 +86,7 @@ tape('testing checkpoints', function (tester) {
   it('should revert to the orginal root', async function (t) {
     t.ok(trie.hasCheckpoints())
     await trie.revert()
-    t.equal(trie.root.toString('hex'), preRoot)
+    t.equal(trie.root().toString('hex'), preRoot)
     t.notOk(trie.hasCheckpoints())
     t.end()
   })
@@ -102,7 +103,7 @@ tape('testing checkpoints', function (tester) {
     await trie.put(Buffer.from('love'), Buffer.from('emotion'))
     await trie.commit()
     t.equal(trie.hasCheckpoints(), false)
-    t.equal(trie.root.toString('hex'), postRoot)
+    t.equal(trie.root().toString('hex'), postRoot)
     t.end()
   })
 
@@ -115,13 +116,13 @@ tape('testing checkpoints', function (tester) {
   it('should commit a nested checkpoint', async function (t) {
     trie.checkpoint()
     await trie.put(Buffer.from('test'), Buffer.from('something else'))
-    const { root } = trie
+    const root = trie.root()
     trie.checkpoint()
     await trie.put(Buffer.from('the feels'), Buffer.from('emotion'))
     await trie.revert()
     await trie.commit()
     t.equal(trie.hasCheckpoints(), false)
-    t.equal(trie.root.toString('hex'), root.toString('hex'))
+    t.equal(trie.root().toString('hex'), root.toString('hex'))
     t.end()
   })
 
diff --git a/packages/trie/test/trie/secure.spec.ts b/packages/trie/test/trie/secure.spec.ts
index 1ce116b44d..66b8e70d7c 100644
--- a/packages/trie/test/trie/secure.spec.ts
+++ b/packages/trie/test/trie/secure.spec.ts
@@ -2,10 +2,10 @@ import { isTruthy } from '@ethereumjs/util'
 import { createHash } from 'crypto'
 import * as tape from 'tape'
 
-import { ROOT_DB_KEY, Trie } from '../../src'
+import { MapDB, ROOT_DB_KEY, Trie } from '../../src'
 
 tape('SecureTrie', function (t) {
-  const trie = new Trie({ useHashedKeys: true })
+  const trie = new Trie({ useKeyHashing: true, db: new MapDB() })
   const k = Buffer.from('foo')
   const v = Buffer.from('bar')
 
@@ -25,18 +25,18 @@ tape('SecureTrie', function (t) {
 
   tape('SecureTrie proof', function (t) {
     t.test('create a merkle proof and verify it with a single short key', async function (st) {
-      const trie = new Trie({ useHashedKeys: true })
+      const trie = new Trie({ useKeyHashing: true, db: new MapDB() })
       await trie.put(Buffer.from('key1aa'), Buffer.from('01234'))
 
       const proof = await trie.createProof(Buffer.from('key1aa'))
-      const val = await trie.verifyProof(trie.root, Buffer.from('key1aa'), proof)
+      const val = await trie.verifyProof(trie.root(), Buffer.from('key1aa'), proof)
       st.equal(val!.toString('utf8'), '01234')
       st.end()
     })
   })
 
   tape('secure tests', function (it) {
-    let trie = new Trie({ useHashedKeys: true })
+    let trie = new Trie({ useKeyHashing: true, db: new MapDB() })
     const jsonTests = require('../fixtures/trietest_secureTrie.json').tests
 
     it.test('empty values', async function (t) {
@@ -44,17 +44,17 @@ tape('SecureTrie', function (t) {
         const val = isTruthy(row[1]) ? Buffer.from(row[1]) : (null as unknown as Buffer)
         await trie.put(Buffer.from(row[0]), val)
       }
-      t.equal('0x' + trie.root.toString('hex'), jsonTests.emptyValues.root)
+      t.equal('0x' + trie.root().toString('hex'), jsonTests.emptyValues.root)
       t.end()
     })
 
     it.test('branchingTests', async function (t) {
-      trie = new Trie({ useHashedKeys: true })
+      trie = new Trie({ useKeyHashing: true, db: new MapDB() })
       for (const row of jsonTests.branchingTests.in) {
         const val = isTruthy(row[1]) ? Buffer.from(row[1]) : (null as unknown as Buffer)
         await trie.put(Buffer.from(row[0]), val)
       }
-      t.equal('0x' + trie.root.toString('hex'), jsonTests.branchingTests.root)
+      t.equal('0x' + trie.root().toString('hex'), jsonTests.branchingTests.root)
       t.end()
     })
 
@@ -66,12 +66,12 @@ tape('SecureTrie', function (t) {
         }
         await trie.put(Buffer.from(row[0].slice(2), 'hex'), val)
       }
-      t.equal('0x' + trie.root.toString('hex'), jsonTests.jeff.root.toString('hex'))
+      t.equal('0x' + trie.root().toString('hex'), jsonTests.jeff.root.toString('hex'))
       t.end()
     })
 
     it.test('put fails if the key is the ROOT_DB_KEY', async function (st) {
-      const trie = new Trie({ useHashedKeys: true, persistRoot: true })
+      const trie = new Trie({ useKeyHashing: true, db: new MapDB(), useRootPersistence: true })
 
       try {
         await trie.put(ROOT_DB_KEY, Buffer.from('bar'))
@@ -84,7 +84,7 @@ tape('SecureTrie', function (t) {
   })
 })
 
-const trie = new Trie({ useHashedKeys: true })
+const trie = new Trie({ useKeyHashing: true, db: new MapDB() })
 const a = Buffer.from(
   'f8448080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0a155280bc3c09fd31b0adebbdd4ef3d5128172c0d2008be964dc9e10e0f0fedf',
   'hex'
@@ -142,7 +142,7 @@ tape('secure tests should not crash', async function (t) {
 
 tape('SecureTrie.copy', function (it) {
   it.test('created copy includes values added after checkpoint', async function (t) {
-    const trie = new Trie({ useHashedKeys: true })
+    const trie = new Trie({ useKeyHashing: true, db: new MapDB() })
 
     await trie.put(Buffer.from('key1'), Buffer.from('value1'))
     trie.checkpoint()
@@ -154,7 +154,7 @@ tape('SecureTrie.copy', function (it) {
   })
 
   it.test('created copy includes values added before checkpoint', async function (t) {
-    const trie = new Trie({ useHashedKeys: true })
+    const trie = new Trie({ useKeyHashing: true, db: new MapDB() })
 
     await trie.put(Buffer.from('key1'), Buffer.from('value1'))
     trie.checkpoint()
@@ -167,8 +167,9 @@ tape('SecureTrie.copy', function (it) {
 
   it.test('created copy uses the correct hash function', async function (t) {
     const trie = new Trie({
-      useHashedKeys: true,
-      useHashedKeysFunction: (value) => createHash('sha256').update(value).digest(),
+      db: new MapDB(),
+      useKeyHashing: true,
+      useKeyHashingFunction: (value) => createHash('sha256').update(value).digest(),
     })
 
     await trie.put(Buffer.from('key1'), Buffer.from('value1'))
diff --git a/packages/trie/test/trie/trie.spec.ts b/packages/trie/test/trie/trie.spec.ts
index 04f06354fe..564530a99c 100644
--- a/packages/trie/test/trie/trie.spec.ts
+++ b/packages/trie/test/trie/trie.spec.ts
@@ -17,7 +17,7 @@ for (const { constructor, defaults, title } of [
     constructor: Trie,
     title: 'SecureTrie',
     defaults: {
-      useHashedKeys: true,
+      useKeyHashing: true,
     },
   },
 ]) {
@@ -41,18 +41,25 @@ for (const { constructor, defaults, title } of [
     t.test(
       'creates an instance via the static constructor `create` function and defaults to `false` with a database',
       async function (st) {
-        st.false(((await constructor.create({ ...defaults, db: new MapDB() })) as any)._persistRoot)
+        st.false(
+          ((await constructor.create({ ...defaults, db: new MapDB() })) as any)._useRootPersistence
+        )
 
         st.end()
       }
     )
 
     t.test(
-      'creates an instance via the static constructor `create` function and respects the `persistRoot` option with a database',
+      'creates an instance via the static constructor `create` function and respects the `useRootPersistence` option with a database',
       async function (st) {
         st.false(
-          ((await constructor.create({ ...defaults, db: new MapDB(), persistRoot: false })) as any)
-            ._persistRoot
+          (
+            (await constructor.create({
+              ...defaults,
+              db: new MapDB(),
+              useRootPersistence: false,
+            })) as any
+          )._useRootPersistence
         )
 
         st.end()
@@ -60,11 +67,16 @@ for (const { constructor, defaults, title } of [
     )
 
     t.test(
-      'creates an instance via the static constructor `create` function and respects the `persistRoot` option with a database',
+      'creates an instance via the static constructor `create` function and respects the `useRootPersistence` option with a database',
       async function (st) {
         st.false(
-          ((await constructor.create({ ...defaults, db: new MapDB(), persistRoot: false })) as any)
-            ._persistRoot
+          (
+            (await constructor.create({
+              ...defaults,
+              db: new MapDB(),
+              useRootPersistence: false,
+            })) as any
+          )._useRootPersistence
         )
 
         st.end()
@@ -74,20 +86,28 @@ for (const { constructor, defaults, title } of [
     t.test(
       'creates an instance via the static constructor `create` function and defaults to `false` without a database',
       async function (st) {
-        st.false(((await constructor.create({ ...defaults, db: new MapDB() })) as any)._persistRoot)
+        st.false(
+          ((await constructor.create({ ...defaults, db: new MapDB() })) as any)._useRootPersistence
+        )
 
         st.end()
       }
     )
 
-    t.test('persist the root if the `persistRoot` option is `true`', async function (st) {
-      const trie = await constructor.create({ ...defaults, db: new MapDB(), persistRoot: true })
+    t.test('persist the root if the `useRootPersistence` option is `true`', async function (st) {
+      const trie = await constructor.create({
+        ...defaults,
+        db: new MapDB(),
+        useRootPersistence: true,
+      })
 
-      st.equal(await trie.db.get(ROOT_DB_KEY), null)
+      // @ts-expect-error
+      st.equal(await trie._db.get(ROOT_DB_KEY), null)
 
       await trie.put(Buffer.from('foo'), Buffer.from('bar'))
 
-      st.equal(bytesToHex(await trie.db.get(ROOT_DB_KEY)), EXPECTED_ROOTS)
+      // @ts-expect-error
+      st.equal(bytesToHex(await trie._db.get(ROOT_DB_KEY)), EXPECTED_ROOTS)
 
       st.end()
     })
@@ -97,38 +117,51 @@ for (const { constructor, defaults, title } of [
         ...defaults,
         db: new MapDB(),
         root: KECCAK256_RLP,
-        persistRoot: true,
+        useRootPersistence: true,
       })
 
-      st.true((await trie.db.get(ROOT_DB_KEY))?.equals(KECCAK256_RLP))
+      // @ts-expect-error
+      st.true((await trie._db.get(ROOT_DB_KEY))?.equals(KECCAK256_RLP))
 
       await trie.put(Buffer.from('foo'), Buffer.from('bar'))
 
-      st.false((await trie.db.get(ROOT_DB_KEY))?.equals(KECCAK256_RLP))
+      // @ts-expect-error
+      st.false((await trie._db.get(ROOT_DB_KEY))?.equals(KECCAK256_RLP))
 
       st.end()
     })
 
-    t.test('does not persist the root if the `persistRoot` option is `false`', async function (st) {
-      const trie = await constructor.create({ ...defaults, db: new MapDB(), persistRoot: false })
+    t.test(
+      'does not persist the root if the `useRootPersistence` option is `false`',
+      async function (st) {
+        const trie = await constructor.create({
+          ...defaults,
+          db: new MapDB(),
+          useRootPersistence: false,
+        })
 
-      st.equal(await trie.db.get(ROOT_DB_KEY), null)
+        // @ts-expect-error
+        st.equal(await trie._db.get(ROOT_DB_KEY), null)
 
-      await trie.put(Buffer.from('do_not_persist_with_db'), Buffer.from('bar'))
+        await trie.put(Buffer.from('do_not_persist_with_db'), Buffer.from('bar'))
 
-      st.equal(await trie.db.get(ROOT_DB_KEY), null)
+        // @ts-expect-error
+        st.equal(await trie._db.get(ROOT_DB_KEY), null)
 
-      st.end()
-    })
+        st.end()
+      }
+    )
 
     t.test('persists the root if the `db` option is not provided', async function (st) {
-      const trie = await constructor.create({ ...defaults, persistRoot: true })
+      const trie = await constructor.create({ ...defaults, useRootPersistence: true })
 
-      st.equal(await trie.db.get(ROOT_DB_KEY), null)
+      // @ts-expect-error
+      st.equal(await trie._db.get(ROOT_DB_KEY), null)
 
       await trie.put(Buffer.from('do_not_persist_without_db'), Buffer.from('bar'))
 
-      st.notEqual(await trie.db.get(ROOT_DB_KEY), null)
+      // @ts-expect-error
+      st.notEqual(await trie._db.get(ROOT_DB_KEY), null)
 
       st.end()
     })
@@ -136,24 +169,32 @@ for (const { constructor, defaults, title } of [
     t.test('persist and restore the root', async function (st) {
       const db = new MapDB()
 
-      const trie = await constructor.create({ ...defaults, db, persistRoot: true })
-      st.equal(await trie.db.get(ROOT_DB_KEY), null)
+      const trie = await constructor.create({ ...defaults, db, useRootPersistence: true })
+      // @ts-expect-error
+      st.equal(await trie._db.get(ROOT_DB_KEY), null)
       await trie.put(Buffer.from('foo'), Buffer.from('bar'))
-      st.equal(bytesToHex(await trie.db.get(ROOT_DB_KEY)), EXPECTED_ROOTS)
+      // @ts-expect-error
+      st.equal(bytesToHex(await trie._db.get(ROOT_DB_KEY)), EXPECTED_ROOTS)
 
       // Using the same database as `trie` so we should have restored the root
-      const copy = await constructor.create({ ...defaults, db, persistRoot: true })
-      st.equal(bytesToHex(await copy.db.get(ROOT_DB_KEY)), EXPECTED_ROOTS)
+      const copy = await constructor.create({ ...defaults, db, useRootPersistence: true })
+      // @ts-expect-error
+      st.equal(bytesToHex(await copy._db.get(ROOT_DB_KEY)), EXPECTED_ROOTS)
 
       // New trie with a new database so we shouldn't find a root to restore
-      const empty = await constructor.create({ ...defaults, db: new MapDB(), persistRoot: true })
-      st.equal(await empty.db.get(ROOT_DB_KEY), null)
+      const empty = await constructor.create({
+        ...defaults,
+        db: new MapDB(),
+        useRootPersistence: true,
+      })
+      // @ts-expect-error
+      st.equal(await empty._db.get(ROOT_DB_KEY), null)
 
       st.end()
     })
 
     t.test('put fails if the key is the ROOT_DB_KEY', async function (st) {
-      const trie = new constructor({ ...defaults, db: new MapDB(), persistRoot: true })
+      const trie = new constructor({ ...defaults, db: new MapDB(), useRootPersistence: true })
 
       try {
         await trie.put(BASE_DB_KEY, Buffer.from('bar'))
diff --git a/packages/trie/test/util/semaphore.spec.ts b/packages/trie/test/util/semaphore.spec.ts
index 818141dbb0..6f14f2a1bb 100644
--- a/packages/trie/test/util/semaphore.spec.ts
+++ b/packages/trie/test/util/semaphore.spec.ts
@@ -11,11 +11,11 @@ tape('Semaphore', (t) => {
     const lock = new Semaphore(1)
 
     const f = async () => {
-      await lock.wait()
+      await lock.acquire()
       const local = global
       await wait(500)
       global = local + 1
-      lock.signal()
+      lock.release()
     }
 
     void f()
diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts
index 6365f43ada..0249657ce5 100644
--- a/packages/vm/src/buildBlock.ts
+++ b/packages/vm/src/buildBlock.ts
@@ -70,7 +70,7 @@ export class BlockBuilder {
     for (const [i, tx] of this.transactions.entries()) {
       await trie.put(Buffer.from(RLP.encode(i)), tx.serialize())
     }
-    return trie.root
+    return trie.root()
   }
 
   /**
@@ -95,7 +95,7 @@ export class BlockBuilder {
       const encodedReceipt = encodeReceipt(txResult.receipt, tx.type)
       await receiptTrie.put(Buffer.from(RLP.encode(i)), encodedReceipt)
     }
-    return receiptTrie.root
+    return receiptTrie.root()
   }
 
   /**
diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts
index 1177c02dcf..db9cc40487 100644
--- a/packages/vm/src/runBlock.ts
+++ b/packages/vm/src/runBlock.ts
@@ -318,7 +318,7 @@ async function applyTransactions(this: VM, block: Block, opts: RunBlockOpts) {
   return {
     bloom,
     gasUsed,
-    receiptRoot: receiptTrie.root,
+    receiptRoot: receiptTrie.root(),
     receipts,
     results: txResults,
   }
@@ -439,7 +439,7 @@ async function _genTxTrie(block: Block) {
   for (const [i, tx] of block.transactions.entries()) {
     await trie.put(Buffer.from(RLP.encode(i)), tx.serialize())
   }
-  return trie.root
+  return trie.root()
 }
 
 /**
diff --git a/packages/vm/tests/api/index.spec.ts b/packages/vm/tests/api/index.spec.ts
index df4c817037..07dd69eb18 100644
--- a/packages/vm/tests/api/index.spec.ts
+++ b/packages/vm/tests/api/index.spec.ts
@@ -37,7 +37,7 @@ tape('VM -> basic instantiation / boolean switches', (t) => {
     const vm = await VM.create()
     st.ok(vm.stateManager)
     st.deepEqual(
-      (vm.stateManager as DefaultStateManager)._trie.root,
+      (vm.stateManager as DefaultStateManager)._trie.root(),
       KECCAK256_RLP,
       'it has default trie'
     )
@@ -48,7 +48,7 @@ tape('VM -> basic instantiation / boolean switches', (t) => {
   t.test('should be able to activate precompiles', async (st) => {
     const vm = await VM.create({ activatePrecompiles: true })
     st.notDeepEqual(
-      (vm.stateManager as DefaultStateManager)._trie.root,
+      (vm.stateManager as DefaultStateManager)._trie.root(),
       KECCAK256_RLP,
       'it has different root'
     )
@@ -173,7 +173,7 @@ tape('VM -> hardforkByBlockNumber, hardforkByTTD, state (deprecated), blockchain
   t.test('should instantiate', async (st) => {
     const vm = await setupVM()
     st.deepEqual(
-      (vm.stateManager as DefaultStateManager)._trie.root,
+      (vm.stateManager as DefaultStateManager)._trie.root(),
       KECCAK256_RLP,
       'it has default trie'
     )
diff --git a/packages/vm/tests/api/muirGlacier/index.spec.ts b/packages/vm/tests/api/muirGlacier/index.spec.ts
index eb84e2bb52..d569b3ff7c 100644
--- a/packages/vm/tests/api/muirGlacier/index.spec.ts
+++ b/packages/vm/tests/api/muirGlacier/index.spec.ts
@@ -9,7 +9,7 @@ tape('General MuirGlacier VM tests', (t) => {
     const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.MuirGlacier })
     const vm = await VM.create({ common })
     st.ok(vm.stateManager)
-    st.deepEqual((<any>vm.stateManager)._trie.root, KECCAK256_RLP, 'it has default trie')
+    st.deepEqual((<any>vm.stateManager)._trie.root(), KECCAK256_RLP, 'it has default trie')
     st.end()
   })
 })
diff --git a/packages/vm/tests/api/runBlock.spec.ts b/packages/vm/tests/api/runBlock.spec.ts
index 5259922cb7..303ab712f8 100644
--- a/packages/vm/tests/api/runBlock.spec.ts
+++ b/packages/vm/tests/api/runBlock.spec.ts
@@ -41,14 +41,14 @@ tape('runBlock() -> successful API parameter usage', async (t) => {
 
     st.ok(
       //@ts-ignore
-      vm.stateManager._trie.root.equals(genesis.header.stateRoot),
+      vm.stateManager._trie.root().equals(genesis.header.stateRoot),
       'genesis state root should match calculated state root'
     )
 
     const res = await vm.runBlock({
       block,
       // @ts-ignore
-      root: vm.stateManager._trie.root,
+      root: vm.stateManager._trie.root(),
       skipBlockValidation: true,
     })
 
@@ -71,7 +71,7 @@ tape('runBlock() -> successful API parameter usage', async (t) => {
     await vm.runBlock({
       block: block1,
       // @ts-ignore
-      root: vm.stateManager._trie.root,
+      root: vm.stateManager._trie.root(),
       skipBlockValidation: true,
     })
 
@@ -80,7 +80,7 @@ tape('runBlock() -> successful API parameter usage', async (t) => {
     await vm.runBlock({
       block: block2,
       // @ts-ignore
-      root: vm.stateManager._trie.root,
+      root: vm.stateManager._trie.root(),
       skipBlockValidation: true,
     })
 
@@ -89,7 +89,7 @@ tape('runBlock() -> successful API parameter usage', async (t) => {
     await vm.runBlock({
       block: block3,
       // @ts-ignore
-      root: vm.stateManager._trie.root,
+      root: vm.stateManager._trie.root(),
       skipBlockValidation: true,
     })
 
diff --git a/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts b/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts
index 9a5c523ddc..58058f752f 100644
--- a/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts
+++ b/packages/vm/tests/tester/runners/BlockchainTestsRunner.ts
@@ -33,7 +33,7 @@ export async function runBlockchainTest(options: any, testData: any, t: tape.Tes
   testData.lastblockhash = stripHexPrefix(testData.lastblockhash)
 
   const cacheDB = new Level('./.cachedb')
-  const state = new Trie({ useHashedKeys: true })
+  const state = new Trie({ useKeyHashing: true })
 
   const { common }: { common: Common } = options
   common.setHardforkByBlockNumber(0)
@@ -89,7 +89,7 @@ export async function runBlockchainTest(options: any, testData: any, t: tape.Tes
   // set up pre-state
   await setupPreConditions(vm.eei, testData)
 
-  t.ok(vm.stateManager._trie.root.equals(genesisBlock.header.stateRoot), 'correct pre stateRoot')
+  t.ok(vm.stateManager._trie.root().equals(genesisBlock.header.stateRoot), 'correct pre stateRoot')
 
   async function handleError(error: string | undefined, expectException: string | boolean) {
     if (expectException !== false) {
@@ -174,7 +174,7 @@ export async function runBlockchainTest(options: any, testData: any, t: tape.Tes
       // state. Generating the genesis state is not needed because
       // blockchain tests come with their own `pre` world state.
       // TODO: Add option to `runBlockchain` not to generate genesis state.
-      vm._common.genesis().stateRoot = vm.stateManager._trie.root
+      vm._common.genesis().stateRoot = vm.stateManager._trie.root()
       try {
         await blockchain.iterator('vm', async (block: Block) => {
           const parentBlock = await blockchain!.getBlock(block.header.parentHash)
@@ -198,7 +198,7 @@ export async function runBlockchainTest(options: any, testData: any, t: tape.Tes
         if (options.debug !== true) {
           // make sure the state is set before checking post conditions
           const headBlock = await vm.blockchain.getIteratorHead()
-          vm.stateManager._trie.root = headBlock.header.stateRoot
+          vm.stateManager._trie.root(headBlock.header.stateRoot)
         } else {
           await verifyPostConditions(state, testData.postState, t)
         }
diff --git a/packages/vm/tests/tester/runners/GeneralStateTestsRunner.ts b/packages/vm/tests/tester/runners/GeneralStateTestsRunner.ts
index 2d522cff66..677746d86f 100644
--- a/packages/vm/tests/tester/runners/GeneralStateTestsRunner.ts
+++ b/packages/vm/tests/tester/runners/GeneralStateTestsRunner.ts
@@ -79,7 +79,7 @@ async function runTestCase(options: any, testData: any, t: tape.Test) {
   // Otherwise mainnet genesis will throw since this has difficulty nonzero
   const genesisBlock = new Block(undefined, undefined, undefined, { common })
   const blockchain = await Blockchain.create({ genesisBlock, common })
-  const state = new Trie({ useHashedKeys: true })
+  const state = new Trie({ useKeyHashing: true })
   const stateManager = new DefaultStateManager({
     trie: state,
   })
@@ -139,7 +139,7 @@ async function runTestCase(options: any, testData: any, t: tape.Test) {
     }
   }
 
-  const stateManagerStateRoot = vm.stateManager._trie.root
+  const stateManagerStateRoot = vm.stateManager._trie.root()
   const testDataPostStateRoot = toBuffer(testData.postStateRoot)
   const stateRootsAreEqual = stateManagerStateRoot.equals(testDataPostStateRoot)
 
diff --git a/packages/vm/tests/util.ts b/packages/vm/tests/util.ts
index 3e4cff1be1..c1f523cb53 100644
--- a/packages/vm/tests/util.ts
+++ b/packages/vm/tests/util.ts
@@ -47,7 +47,7 @@ export function dumpState(state: any, cb: Function) {
     return new Promise((resolve) => {
       const storage: any = {}
       const storageTrie = state.copy(false)
-      storageTrie.root = account.storageRoot
+      storageTrie.root(account.storageRoot)
       const storageRS = storageTrie.createReadStream()
 
       storageRS.on('data', function (data: any) {
@@ -207,7 +207,7 @@ export function verifyAccountPostConditions(
     }
 
     // validate storage
-    const origRoot = state.root
+    const origRoot = state.root()
 
     const hashedStorage: any = {}
     for (const key in acctData.storage) {
@@ -215,7 +215,7 @@ export function verifyAccountPostConditions(
         acctData.storage[key]
     }
 
-    state.root = account.storageRoot
+    state.root(account.storageRoot)
     const rs = state.createReadStream()
     rs.on('data', function (data: any) {
       let key = data.key.toString('hex')
@@ -246,7 +246,7 @@ export function verifyAccountPostConditions(
         }
       }
 
-      state.root = origRoot
+      state.root(origRoot)
       resolve()
     })
   })
@@ -347,7 +347,7 @@ export async function setupPreConditions(state: VmState, testData: any) {
     const storageRoot = (await state.getAccount(address)).storageRoot
 
     if (testData.exec?.address === addressStr) {
-      testData.root = storageRoot
+      testData.root(storageRoot)
     }
 
     // Put account data