Skip to content
This repository has been archived by the owner on Jan 19, 2021. It is now read-only.

Commit

Permalink
Merge 0a6a2ca into 9ee7869
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanio authored May 27, 2020
2 parents 9ee7869 + 0a6a2ca commit b71d455
Show file tree
Hide file tree
Showing 11 changed files with 170 additions and 59 deletions.
73 changes: 73 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,79 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
(modification: no type change headlines) and this project adheres to
[Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [4.0.0] - 2020-04-17

This release introduces a major API upgrade from callbacks to Promises.

Example using async/await syntax:

```typescript
import { BaseTrie as Trie } from 'merkle-patricia-tree'
const trie = new Trie()
async function test() {
await trie.put(Buffer.from('test'), Buffer.from('one'))
const value = await trie.get(Buffer.from('test'))
console.log(value.toString()) // 'one'
}
test()
```

### Breaking Changes

#### Trie methods

See the [docs](https://github.com/ethereumjs/merkle-patricia-tree/tree/master/docs) for the latest Promise-based method signatures.

#### Trie raw methods

`getRaw`, `putRaw` and `delRaw` were deprecated in `v3.0.0` and have been removed from this release. Instead, please use `trie.db.get`, `trie.db.put`, and `trie.db.del`. If using a `SecureTrie` or `CheckpointTrie`, use `trie._maindb` to override the checkpointing mechanism and interact directly with the db.

#### SecureTrie.copy

`SecureTrie.copy` now includes checkpoint metadata by default. To maintain original behavior of _not_ copying checkpoint state, pass `false` to param `includeCheckpoints`.

### Changed

- Convert trieNode to ES6 class ([#71](https://github.com/ethereumjs/merkle-patricia-tree/pull/71))
- Merge checkpoint and secure interface with their ES6 classes ([#73](https://github.com/ethereumjs/merkle-patricia-tree/pull/73))
- Extract db-related methods from baseTrie ([#74](https://github.com/ethereumjs/merkle-patricia-tree/pull/74))
- \_lookupNode callback to use standard error, response pattern ([#83](https://github.com/ethereumjs/merkle-patricia-tree/pull/83))
- Accept leveldb in constructor, minor fixes ([#92](https://github.com/ethereumjs/merkle-patricia-tree/pull/92))
- Refactor TrieNode, add levelup types ([#98](https://github.com/ethereumjs/merkle-patricia-tree/pull/98))
- Promisify rest of library ([#107](https://github.com/ethereumjs/merkle-patricia-tree/pull/107))
- Use `Nibbles` type for `number[]` ([#115](https://github.com/ethereumjs/merkle-patricia-tree/pull/115))
- Upgrade ethereumjs-util to 7.0.0 / Upgrade level-mem to 5.0.1 ([#116](https://github.com/ethereumjs/merkle-patricia-tree/pull/116))
- Create dual ES5 and ES2017 builds ([#117](https://github.com/ethereumjs/merkle-patricia-tree/pull/117))
- Include checkpoints by default in SecureTrie.copy ([#119](https://github.com/ethereumjs/merkle-patricia-tree/pull/119))

### Added

- Support for proofs of null/absence. Dried up prove/verify. ([#82](https://github.com/ethereumjs/merkle-patricia-tree/pull/82))
- Add more Ethereum state DB focused example accessing account values ([#89](https://github.com/ethereumjs/merkle-patricia-tree/pull/89))

### Fixed

- Drop ethereumjs-testing dep and fix bug in branch value update ([#69](https://github.com/ethereumjs/merkle-patricia-tree/pull/69))
- Fix prove and verifyProof in SecureTrie ([#79](https://github.com/ethereumjs/merkle-patricia-tree/pull/79))
- Fixed src code links in docs ([#93](https://github.com/ethereumjs/merkle-patricia-tree/pull/93))

### Dev / Testing / CI

- Update tape to v4.10.1 ([#81](https://github.com/ethereumjs/merkle-patricia-tree/pull/81))
- Org links and git hooks ([#87](https://github.com/ethereumjs/merkle-patricia-tree/pull/87))
- Use module.exports syntax in util files ([#90](https://github.com/ethereumjs/merkle-patricia-tree/pull/90))
- Rename deprecated sha3 consts and func to keccak256 ([#91](https://github.com/ethereumjs/merkle-patricia-tree/pull/91))
- Migrate to Typescript ([#96](https://github.com/ethereumjs/merkle-patricia-tree/pull/96))
- Fix Travis's xvfb service ([#97](https://github.com/ethereumjs/merkle-patricia-tree/pull/97))
- Fix test cases and docs ([#104](https://github.com/ethereumjs/merkle-patricia-tree/pull/104))
- Upgrade CI Provider from Travis to GH Actions ([#105](https://github.com/ethereumjs/merkle-patricia-tree/pull/105))
- Upgrade test suite to TS ([#106](https://github.com/ethereumjs/merkle-patricia-tree/pull/106))
- Better document `_formatNode` ([#109](https://github.com/ethereumjs/merkle-patricia-tree/pull/109))
- Move `failingRefactorTests` to `secure.spec.ts` ([#110](https://github.com/ethereumjs/merkle-patricia-tree/pull/110))
- Fix test suite typos ([#114](https://github.com/ethereumjs/merkle-patricia-tree/pull/110))

[4.0.0]: https://github.com/ethereumjs/merkle-patricia-tree/compare/v3.0.0...v4.0.0

## [3.0.0] - 2019-01-03

This release comes along with some major version bump of the underlying `level`
Expand Down
68 changes: 40 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,25 @@ import { BaseTrie as Trie } from 'merkle-patricia-tree'
const db = level('./testdb')
const trie = new Trie(db)

await trie.put(Buffer.from('test'), Buffer.from('one'))
const value = await trie.get(Buffer.from('test'))
console.log(value.toString())
async function test() {
await trie.put(Buffer.from('test'), Buffer.from('one'))
const value = await trie.get(Buffer.from('test'))
console.log(value.toString()) // 'one'
}

test()
```

## Merkle Proofs

```typescript
const prove = await Trie.prove(trie, Buffer.from('test'))
const value = await Trie.verifyProof(trie.root, Buffer.from('test'), prove)
console.log(value.toString())
async function test() {
const prove = await Trie.prove(trie, Buffer.from('test'))
const value = await Trie.verifyProof(trie.root, Buffer.from('test'), prove)
console.log(value.toString())
}

test()
```

## Read stream on Geth DB
Expand Down Expand Up @@ -79,28 +87,32 @@ const trie = new Trie(db, stateRoot)

const address = 'AN_ETHEREUM_ACCOUNT_ADDRESS'

const data = await trie.get(address)
const acc = new Account(data)

console.log('-------State-------')
console.log(`nonce: ${new BN(acc.nonce)}`)
console.log(`balance in wei: ${new BN(acc.balance)}`)
console.log(`storageRoot: ${bufferToHex(acc.stateRoot)}`)
console.log(`codeHash: ${bufferToHex(acc.codeHash)}`)

let storageTrie = trie.copy()
storageTrie.root = acc.stateRoot

console.log('------Storage------')
const stream = storageTrie.createReadStream()
stream
.on('data', (data) => {
console.log(`key: ${bufferToHex(data.key)}`)
console.log(`Value: ${bufferToHex(rlp.decode(data.value))}`)
})
.on('end', () => {
console.log('Finished reading storage.')
})
async function test() {
const data = await trie.get(address)
const acc = new Account(data)

console.log('-------State-------')
console.log(`nonce: ${new BN(acc.nonce)}`)
console.log(`balance in wei: ${new BN(acc.balance)}`)
console.log(`storageRoot: ${bufferToHex(acc.stateRoot)}`)
console.log(`codeHash: ${bufferToHex(acc.codeHash)}`)

let storageTrie = trie.copy()
storageTrie.root = acc.stateRoot

console.log('------Storage------')
const stream = storageTrie.createReadStream()
stream
.on('data', (data) => {
console.log(`key: ${bufferToHex(data.key)}`)
console.log(`Value: ${bufferToHex(rlp.decode(data.value))}`)
})
.on('end', () => {
console.log('Finished reading storage.')
})
}

test()
```

# API
Expand Down
2 changes: 1 addition & 1 deletion docs/classes/_basetrie_.trie.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Class: Trie

Use `import { BaseTrie as Trie } from 'merkle-patricia-tree'` for the base interface.
In Ethereum applications stick with the Secure Trie Overlay `import { SecureTrie } from 'merkle-patricia-tree'`.
In Ethereum applications stick with the Secure Trie Overlay `import { SecureTrie as Trie } from 'merkle-patricia-tree'`.
The API for the base and the secure interface are about the same.

**`param`** A [levelup](https://github.com/Level/levelup) instance. By default creates an in-memory [memdown](https://github.com/Level/memdown) instance.
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "merkle-patricia-tree",
"version": "3.0.0",
"version": "4.0.0",
"description": "This is an implementation of the modified merkle patricia tree as specified in the Ethereum's yellow paper.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand All @@ -11,7 +11,7 @@
"browser": "dist.browser/index.js",
"scripts": {
"benchmarks": "npm run build && ts-node benchmarks/index.ts",
"build": "tsc -p tsconfig.json && tsc -p tsconfig.browser.json",
"build": "tsc -p tsconfig.prod.json && tsc -p tsconfig.browser.json",
"prepublishOnly": "npm run test && npm run build",
"coverage": "nyc --reporter=lcov npm run test:node",
"docs:build": "typedoc",
Expand Down Expand Up @@ -49,7 +49,8 @@
],
"license": "MPL-2.0",
"dependencies": {
"ethereumjs-util": "^7.0.0",
"@types/levelup": "^3.1.1",
"ethereumjs-util": "^7.0.2",
"level-mem": "^5.0.1",
"level-ws": "^2.0.0",
"readable-stream": "^3.6.0",
Expand All @@ -61,8 +62,7 @@
"@ethereumjs/config-prettier": "^1.1.1",
"@ethereumjs/config-tsc": "^1.1.1",
"@ethereumjs/config-tslint": "^1.1.1",
"@types/bn.js": "^4.11.5",
"@types/levelup": "^3.1.1",
"@types/bn.js": "^4.11.6",
"@types/tape": "^4.2.34",
"husky": "^4.2.3",
"karma": "^4.4.1",
Expand Down
2 changes: 1 addition & 1 deletion src/baseTrie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type FoundNode = (nodeRef: Buffer, node: TrieNode, key: Nibbles, walkController:

/**
* Use `import { BaseTrie as Trie } from 'merkle-patricia-tree'` for the base interface.
* In Ethereum applications stick with the Secure Trie Overlay `import { SecureTrie } from 'merkle-patricia-tree'`.
* In Ethereum applications stick with the Secure Trie Overlay `import { SecureTrie as Trie } from 'merkle-patricia-tree'`.
* The API for the base and the secure interface are about the same.
* @param {Object} [db] - A [levelup](https://github.com/Level/levelup) instance. By default creates an in-memory [memdown](https://github.com/Level/memdown) instance.
* If the db is `null` or left undefined, then the trie will be stored in memory via [memdown](https://github.com/Level/memdown)
Expand Down
14 changes: 5 additions & 9 deletions src/checkpointTrie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ export class CheckpointTrie extends BaseTrie {

/**
* Creates a checkpoint that can later be reverted to or committed.
* After this is called, no changes to the trie will be permanently saved
* until `commit` is called. Calling `db.put` overrides the checkpointing
* mechanism and would directly write to db.
* After this is called, no changes to the trie will be permanently saved until `commit` is called.
* To override the checkpointing mechanism use `_maindb.put` to write directly write to db.
*/
checkpoint() {
const wasCheckpoint = this.isCheckpoint
Expand Down Expand Up @@ -82,13 +81,10 @@ export class CheckpointTrie extends BaseTrie {
}

/**
* Returns a copy of the underlying trie with the interface
* of CheckpointTrie. If during a checkpoint, the copy will
* contain the checkpointing metadata (incl. reference to the same scratch).
* @param {boolean} includeCheckpoints - If true and during a checkpoint, the copy will
* contain the checkpointing metadata and will use the same scratch as underlying db.
* Returns a copy of the underlying trie with the interface of CheckpointTrie.
* @param {boolean} includeCheckpoints - If true and during a checkpoint, the copy will contain the checkpointing metadata and will use the same scratch as underlying db.
*/
copy(includeCheckpoints: boolean = true): CheckpointTrie {
copy(includeCheckpoints = true): CheckpointTrie {
const db = this._mainDB.copy()
const trie = new CheckpointTrie(db._leveldb, this.root)
if (includeCheckpoints && this.isCheckpoint) {
Expand Down
10 changes: 7 additions & 3 deletions src/secure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CheckpointTrie } from './checkpointTrie'

/**
* You can create a secure Trie where the keys are automatically hashed
* using **keccak256** by using `require('merkle-patricia-tree/secure')`.
* using **keccak256** by using `require('merkle-patricia-tree').SecureTrie`.
* It has the same methods and constructor as `Trie`.
* @class SecureTrie
* @extends Trie
Expand All @@ -24,8 +24,12 @@ export class SecureTrie extends CheckpointTrie {
return super.verifyProof(rootHash, hash, proof)
}

copy(): SecureTrie {
const trie = super.copy(false)
/**
* Returns a copy of the underlying trie with the interface of SecureTrie.
* @param {boolean} includeCheckpoints - If true and during a checkpoint, the copy will contain the checkpointing metadata and will use the same scratch as underlying db.
*/
copy(includeCheckpoints = true): SecureTrie {
const trie = super.copy(includeCheckpoints)
const db = trie.db.copy()
return new SecureTrie(db._leveldb, this.root)
}
Expand Down
26 changes: 26 additions & 0 deletions test/secure.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,29 @@ tape('secure tests should not crash', async function (t) {
await trie.put(gk, g)
t.end()
})

tape('SecureTrie.copy', function (it) {
it.test('created copy includes values added after checkpoint', async function (t) {
const trie = new SecureTrie()

await trie.put(Buffer.from('key1'), Buffer.from('value1'))
trie.checkpoint()
await trie.put(Buffer.from('key2'), Buffer.from('value2'))
const trieCopy = trie.copy()
const value = await trieCopy.get(Buffer.from('key2'))
t.equal(value.toString(), 'value2')
t.end()
})

it.test('created copy includes values added before checkpoint', async function (t) {
const trie = new SecureTrie()

await trie.put(Buffer.from('key1'), Buffer.from('value1'))
trie.checkpoint()
await trie.put(Buffer.from('key2'), Buffer.from('value2'))
const trieCopy = trie.copy()
const value = await trieCopy.get(Buffer.from('key1'))
t.equal(value.toString(), 'value1')
t.end()
})
})
8 changes: 4 additions & 4 deletions tsconfig.browser.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"extends": "./tsconfig.json",
"extends": "./tsconfig.prod.json",
"compilerOptions": {
"outDir": "./dist.browser",
},
"target": "es5",
"lib": ["dom", "es5"]
"target": "es5",
"lib": ["dom", "es5"]
}
}

8 changes: 0 additions & 8 deletions tsconfig.json

This file was deleted.

8 changes: 8 additions & 0 deletions tsconfig.prod.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "@ethereumjs/config-tsc",
"compilerOptions": {
"outDir": "./dist",
"target": "ES2017"
},
"include": ["src/**/*.ts"]
}

0 comments on commit b71d455

Please sign in to comment.