Skip to content

Commit

Permalink
refactor(trie): rename secure to useHashedKeys
Browse files Browse the repository at this point in the history
  • Loading branch information
faustbrian committed Aug 23, 2022
1 parent 3042ff7 commit a50c89c
Show file tree
Hide file tree
Showing 28 changed files with 225 additions and 956 deletions.
4 changes: 2 additions & 2 deletions packages/blockchain/src/genesisStates/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { RLP } from '@ethereumjs/rlp'
import { SecureTrie as Trie } from '@ethereumjs/trie'
import { CheckpointTrie as Trie } from '@ethereumjs/trie'
import { Account, isHexPrefixed, isTruthy, toBuffer, unpadBuffer } from '@ethereumjs/util'
import { keccak256 } from 'ethereum-cryptography/keccak'

Expand All @@ -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()
const trie = new Trie({ useHashedKeys: true })
for (const [key, value] of Object.entries(genesisState)) {
const address = isHexPrefixed(key) ? toBuffer(key) : Buffer.from(key, 'hex')
const account = new Account()
Expand Down
4 changes: 2 additions & 2 deletions packages/client/lib/execution/vmexecution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from '@ethereumjs/blockchain/dist/db/helpers'
import { ConsensusType, Hardfork } from '@ethereumjs/common'
import { DefaultStateManager } from '@ethereumjs/statemanager'
import { SecureTrie } from '@ethereumjs/trie'
import { CheckpointTrie } from '@ethereumjs/trie'
import { bufferToHex, isFalsy, isTruthy } from '@ethereumjs/util'
import { VM } from '@ethereumjs/vm'

Expand Down Expand Up @@ -40,7 +40,7 @@ export class VMExecution extends Execution {
super(options)

if (isFalsy(this.config.vm)) {
const trie = new SecureTrie({ db: new LevelDB(this.stateDB) })
const trie = new CheckpointTrie({ db: new LevelDB(this.stateDB), useHashedKeys: true })

const stateManager = new DefaultStateManager({
trie,
Expand Down
4 changes: 2 additions & 2 deletions packages/client/lib/util/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { Level } from 'level';
import { Common } from '@ethereumjs/common'
import { Block } from '@ethereumjs/block'
import { VM } from './lib'
import { SecureTrie as Trie } from '@ethereumjs/trie'
import { CheckpointTrie as Trie } from '@ethereumjs/trie'
import { DefaultStateManager } from './lib/state'
import { Blockchain } from '@ethereumjs/blockchain'
Expand All @@ -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 })
const trie = new Trie({ db: stateDB, useHashedKeys: true })
const stateManager = new DefaultStateManager({ trie, common })
// Ensure we run on the right root
stateManager.setStateRoot(Buffer.from('${(
Expand Down
14 changes: 9 additions & 5 deletions packages/statemanager/src/stateManager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { RLP } from '@ethereumjs/rlp'
import { SecureTrie as Trie } from '@ethereumjs/trie'
import { CheckpointTrie as Trie } from '@ethereumjs/trie'
import {
Account,
KECCAK256_NULL,
Expand Down Expand Up @@ -53,7 +53,7 @@ const CODEHASH_PREFIX = Buffer.from('c')
*/
export interface DefaultStateManagerOpts {
/**
* A {@link SecureTrie} instance
* A {@link CheckpointTrie} instance
*/
trie?: Trie
/**
Expand Down Expand Up @@ -87,7 +87,7 @@ export class DefaultStateManager extends BaseStateManager implements StateManage
constructor(opts: DefaultStateManagerOpts = {}) {
super(opts)

this._trie = opts.trie ?? new Trie()
this._trie = opts.trie ?? new Trie({ useHashedKeys: true })
this._storageTries = {}

this._prefixCodeHashes = opts.prefixCodeHashes ?? true
Expand Down Expand Up @@ -374,7 +374,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().verifyProof(rootHash, key, accountProof)
const value = await new Trie({ useHashedKeys: true }).verifyProof(rootHash, key, accountProof)

if (value === null) {
// Verify that the account is empty in the proof.
Expand Down Expand Up @@ -420,7 +420,11 @@ 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().verifyProof(storageRoot, storageKey, storageProof)
const proofValue = await new Trie({ useHashedKeys: true }).verifyProof(
storageRoot,
storageKey,
storageProof
)
const reportedValue = setLengthLeft(
Buffer.from(RLP.decode(Uint8Array.from((proofValue as Buffer) ?? [])) as Uint8Array),
32
Expand Down
8 changes: 4 additions & 4 deletions packages/statemanager/tests/cache.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SecureTrie as Trie } from '@ethereumjs/trie'
import { CheckpointTrie as Trie } from '@ethereumjs/trie'
import { Account, Address } from '@ethereumjs/util'
import * as tape from 'tape'

Expand All @@ -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()
const trie = new Trie({ useHashedKeys: true })
const getCb: getCb = async (address) => {
const innerTrie = trie
const rlp = await innerTrie.get(address.buf)
Expand All @@ -32,7 +32,7 @@ tape('cache initialization', (t) => {
})

tape('cache put and get account', (t) => {
const trie = new Trie()
const trie = new Trie({ useHashedKeys: true })
const getCb: getCb = async (address) => {
const innerTrie = trie
const rlp = await innerTrie.get(address.buf)
Expand Down Expand Up @@ -103,7 +103,7 @@ tape('cache put and get account', (t) => {
})

tape('cache checkpointing', (t) => {
const trie = new Trie()
const trie = new Trie({ useHashedKeys: true })
const getCb: getCb = async (address) => {
const innerTrie = trie
const rlp = await innerTrie.get(address.buf)
Expand Down
18 changes: 9 additions & 9 deletions packages/statemanager/tests/proofStateManager.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SecureTrie } from '@ethereumjs/trie'
import { CheckpointTrie } from '@ethereumjs/trie'
import { Address, toBuffer, zeros } from '@ethereumjs/util'
import { keccak256 } from 'ethereum-cryptography/keccak'
import * as tape from 'tape'
Expand Down Expand Up @@ -41,7 +41,7 @@ tape('ProofStateManager', (t) => {
// Account: 0xc626553e7c821d0f8308c28d56c60e3c15f8d55a
// Storage slots: empty list
const address = Address.fromString('0xc626553e7c821d0f8308c28d56c60e3c15f8d55a')
const trie = new SecureTrie()
const trie = new CheckpointTrie({ useHashedKeys: true })
const stateManager = new DefaultStateManager({ trie })
// Dump all the account proof data in the DB
let stateRoot: Buffer | undefined
Expand All @@ -68,7 +68,7 @@ tape('ProofStateManager', (t) => {
// Account: 0x68268f12253f69f66b188c95b8106b2f847859fc (this account does not exist)
// Storage slots: empty list
const address = Address.fromString('0x68268f12253f69f66b188c95b8106b2f847859fc')
const trie = new SecureTrie()
const trie = new CheckpointTrie({ useHashedKeys: true })
const stateManager = new DefaultStateManager({ trie })
// Dump all the account proof data in the DB
let stateRoot: Buffer | undefined
Expand Down Expand Up @@ -96,7 +96,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 SecureTrie()
const trie = new CheckpointTrie({ useHashedKeys: true })
const stateManager = new DefaultStateManager({ trie })
// Dump all the account proof data in the DB
let stateRoot: Buffer | undefined
Expand All @@ -109,7 +109,7 @@ tape('ProofStateManager', (t) => {
await trie.db.put(key, bufferData)
}
const storageRoot = ropsten_contractWithStorage.storageHash
const storageTrie = new SecureTrie()
const storageTrie = new CheckpointTrie({ useHashedKeys: true })
const storageKeys: Buffer[] = []
for (const storageProofsData of ropsten_contractWithStorage.storageProof) {
storageKeys.push(toBuffer(storageProofsData.key))
Expand All @@ -136,7 +136,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 SecureTrie()
const trie = new CheckpointTrie({ useHashedKeys: true })
const stateManager = new DefaultStateManager({ trie })
// Dump all the account proof data in the DB
let stateRoot: Buffer | undefined
Expand All @@ -149,7 +149,7 @@ tape('ProofStateManager', (t) => {
await trie.db.put(key, bufferData)
}
const storageRoot = ropsten_contractWithStorage.storageHash
const storageTrie = new SecureTrie()
const storageTrie = new CheckpointTrie({ useHashedKeys: true })
const storageKeys: Buffer[] = []
for (const storageProofsData of ropsten_contractWithStorage.storageProof) {
storageKeys.push(toBuffer(storageProofsData.key))
Expand Down Expand Up @@ -203,7 +203,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 SecureTrie()
const trie = new CheckpointTrie({ useHashedKeys: true })
const stateManager = new DefaultStateManager({ trie })
// Dump all the account proof data in the DB
let stateRoot: Buffer | undefined
Expand All @@ -216,7 +216,7 @@ tape('ProofStateManager', (t) => {
await trie.db.put(key, bufferData)
}
const storageRoot = ropsten_nonexistentAccount.storageHash
const storageTrie = new SecureTrie()
const storageTrie = new CheckpointTrie({ useHashedKeys: true })
storageTrie.root = toBuffer(storageRoot)
const addressHex = address.buf.toString('hex')
stateManager._storageTries[addressHex] = storageTrie
Expand Down
12 changes: 6 additions & 6 deletions packages/trie/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `secure` 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 `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).

**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.

Expand Down Expand Up @@ -166,17 +166,17 @@ You may use the `Trie.verifyRangeProof()` function to confirm if the given leaf

```typescript
import { Level } from 'level'
import { SecureTrie, LevelDB } from '@ethereumjs/trie'
import { LevelDB, Trie } from '@ethereumjs/trie'

// Set stateRoot to block #222
const stateRoot = '0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544'
// Convert the state root to a Buffer (strip the 0x prefix)
const stateRootBuffer = Buffer.from(stateRoot.slice(2), 'hex')
// Initialize trie
const trie = new Trie({
secure: true,
db: new LevelDB(new Level('YOUR_PATH_TO_THE_GETH_CHAIN_DB')),
root: stateRootBuffer,
useHashedKeys: true,
})

trie
Expand All @@ -189,16 +189,16 @@ trie

```typescript
import { Level } from 'level'
import { SecureTrie, LevelDB } from '@ethereumjs/trie'
import { Trie, LevelDB } from '@ethereumjs/trie'
import { Account, bufferToHex } from '@ethereumjs/util'
import { RLP } from '@ethereumjs/rlp'

const stateRoot = 'STATE_ROOT_OF_A_BLOCK'

const trie = new Trie({
secure: true,
db: new LevelDB(new Level('YOUR_PATH_TO_THE_GETH_CHAINDATA_FOLDER',
db: new LevelDB(new Level('YOUR_PATH_TO_THE_GETH_CHAINDATA_FOLDER')),
root: stateRoot
useHashedKeys: true,
})

const address = 'AN_ETHEREUM_ACCOUNT_ADDRESS'
Expand Down
6 changes: 3 additions & 3 deletions packages/trie/UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `secure` - 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 `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.

Updating is pretty much straight-forward:

Expand All @@ -19,13 +19,13 @@ const trie = new SecureTrie() // old
```

```typescript
const trie = new CheckpointTrie({ secure: true }) // new
const trie = new CheckpointTrie({ useHashedKeys: true }) // new
```

Note that while upgrading to `CheckpointTrie` gives you guaranteed functional equivalency you might actually want to think if you need the checkpointing functionality or if you otherwise want to upgrade to a simple base trie with:

```typescript
const trie = new Trie({ secure: true }) // new (alternative without checkpointing)
const trie = new Trie({ useHashedKeys: true }) // new (alternative without checkpointing)
```

### Database Abstraction
Expand Down
17 changes: 8 additions & 9 deletions packages/trie/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
- [LeafNode](classes/LeafNode.md)
- [MapDB](classes/MapDB.md)
- [PrioritizedTaskExecutor](classes/PrioritizedTaskExecutor.md)
- [SecureTrie](classes/SecureTrie.md)
- [Trie](classes/Trie.md)
- [TrieReadStream](classes/TrieReadStream.md)
- [WalkController](classes/WalkController.md)
Expand All @@ -31,7 +30,7 @@
- [Checkpoint](README.md#checkpoint)
- [EmbeddedNode](README.md#embeddednode)
- [FoundNodeFunction](README.md#foundnodefunction)
- [HashFunc](README.md#hashfunc)
- [HashKeysFunction](README.md#hashkeysfunction)
- [Nibbles](README.md#nibbles)
- [Proof](README.md#proof)
- [TrieNode](README.md#trienode)
Expand All @@ -55,7 +54,7 @@

#### Defined in

[packages/trie/src/types.ts:49](https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/trie/src/types.ts#L49)
[packages/trie/src/types.ts:63](https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/trie/src/types.ts#L63)

___

Expand All @@ -72,7 +71,7 @@ ___

#### Defined in

[packages/trie/src/types.ts:96](https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/trie/src/types.ts#L96)
[packages/trie/src/types.ts:110](https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/trie/src/types.ts#L110)

___

Expand Down Expand Up @@ -113,9 +112,9 @@ ___

___

### HashFunc
### HashKeysFunction

Ƭ **HashFunc**: (`msg`: `Uint8Array`) => `Uint8Array`
Ƭ **HashKeysFunction**: (`msg`: `Uint8Array`) => `Uint8Array`

#### Type declaration

Expand Down Expand Up @@ -173,7 +172,7 @@ ___

#### Defined in

[packages/trie/src/types.ts:103](https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/trie/src/types.ts#L103)
[packages/trie/src/types.ts:117](https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/trie/src/types.ts#L117)

## Functions

Expand Down Expand Up @@ -239,7 +238,7 @@ ___

### verifyRangeProof

**verifyRangeProof**(`rootHash`, `firstKey`, `lastKey`, `keys`, `values`, `proof`, `hash`): `Promise`<`boolean`\>
**verifyRangeProof**(`rootHash`, `firstKey`, `lastKey`, `keys`, `values`, `proof`, `useHashedKeysFunction`): `Promise`<`boolean`\>

verifyRangeProof checks whether the given leaf nodes and edge proof
can prove the given trie leaves range is matched with the specific root.
Expand Down Expand Up @@ -270,7 +269,7 @@ NOTE: Currently only supports verification when the length of firstKey and lastK
| `keys` | [`Nibbles`](README.md#nibbles)[] | key list. |
| `values` | `Buffer`[] | value list, one-to-one correspondence with keys. |
| `proof` | ``null`` \| `Buffer`[] | proof node list, if proof is null, both `firstKey` and `lastKey` must be null |
| `hash` | [`HashFunc`](README.md#hashfunc) | - |
| `useHashedKeysFunction` | [`HashKeysFunction`](README.md#hashkeysfunction) | - |

#### Returns

Expand Down
Loading

0 comments on commit a50c89c

Please sign in to comment.