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

Release - v4.0.0 #111

Merged
merged 18 commits into from
Jun 19, 2020
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"]
}