Skip to content

Commit

Permalink
update to mpt v4
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanio committed Jun 25, 2020
1 parent b6beae4 commit 60b5f5c
Show file tree
Hide file tree
Showing 20 changed files with 206 additions and 404 deletions.
1 change: 0 additions & 1 deletion packages/account/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
"@types/bn.js": "^4.11.6",
"@types/node": "^11.13.4",
"@types/tape": "^4.13.0",
"merkle-patricia-tree": "^3.0.0",
"nyc": "^14.0.0",
"prettier": "^2.0.5",
"tape": "^4.10.1",
Expand Down
149 changes: 6 additions & 143 deletions packages/account/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,7 @@
import * as rlp from 'rlp'

const ethUtil = require('ethereumjs-util')
import { KECCAK256_NULL, KECCAK256_NULL_S, KECCAK256_RLP, defineProperties } from 'ethereumjs-util'
const Buffer = require('safe-buffer').Buffer

interface TrieGetCb {
(err: any, value: Buffer | null): void
}
interface TriePutCb {
(err?: any): void
}

interface Trie {
root: Buffer
copy(): Trie
getRaw(key: Buffer, cb: TrieGetCb): void
putRaw(key: Buffer | string, value: Buffer, cb: TriePutCb): void
get(key: Buffer | string, cb: TrieGetCb): void
put(key: Buffer | string, value: Buffer | string, cb: TriePutCb): void
}

export default class Account {
/**
* The account's nonce.
Expand Down Expand Up @@ -80,160 +63,40 @@ export default class Account {
{
name: 'stateRoot',
length: 32,
default: ethUtil.KECCAK256_RLP,
default: KECCAK256_RLP,
},
{
name: 'codeHash',
length: 32,
default: ethUtil.KECCAK256_NULL,
default: KECCAK256_NULL,
},
]

ethUtil.defineProperties(this, fields, data)
defineProperties(this, fields, data)
}

/**
* Returns the RLP serialization of the account as a `Buffer`.
*
*/
serialize(): Buffer {
return rlp.encode([this.nonce, this.balance, this.stateRoot, this.codeHash])
}

/**
* Returns a `Boolean` deteremining if the account is a contract.
*
*/
isContract(): boolean {
return this.codeHash.toString('hex') !== ethUtil.KECCAK256_NULL_S
}

/**
* Fetches the code from the trie.
* @param trie The [trie](https://github.com/ethereumjs/merkle-patricia-tree) storing the accounts
* @param cb The callback
*/
getCode(trie: Trie, cb: TrieGetCb): void {
if (!this.isContract()) {
cb(null, Buffer.alloc(0))
return
}

trie.getRaw(this.codeHash, cb)
}

/**
* Stores the code in the trie.
*
* ~~~
* // Requires manual merkle-patricia-tree install
* const SecureTrie = require('merkle-patricia-tree/secure')
* const Account = require('./index.js').default
*
* let code = Buffer.from(
* '73095e7baea6a6c7c4c2dfeb977efac326af552d873173095e7baea6a6c7c4c2dfeb977efac326af552d873157',
* 'hex',
* )
*
* let raw = {
* nonce: '0x0',
* balance: '0x03e7',
* stateRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
* codeHash: '0xb30fb32201fe0486606ad451e1a61e2ae1748343cd3d411ed992ffcc0774edd4',
* }
* let account = new Account(raw)
* let trie = new SecureTrie()
*
* account.setCode(trie, code, function(err, codeHash) {
* console.log(`Code with hash 0x${codeHash.toString('hex')} set to trie`)
* account.getCode(trie, function(err, code) {
* console.log(`Code ${code.toString('hex')} read from trie`)
* })
* })
* ~~~
*
* @param trie The [trie](https://github.com/ethereumjs/merkle-patricia-tree) storing the accounts.
* @param {Buffer} code
* @param cb The callback.
*
*/
setCode(trie: Trie, code: Buffer, cb: (err: any, codeHash: Buffer) => void): void {
this.codeHash = ethUtil.keccak256(code)

if (this.codeHash.toString('hex') === ethUtil.KECCAK256_NULL_S) {
cb(null, Buffer.alloc(0))
return
}

trie.putRaw(this.codeHash, code, (err: any) => {
cb(err, this.codeHash)
})
}

/**
* Fetches `key` from the account's storage.
* @param trie
* @param key
* @param cb
*/
getStorage(trie: Trie, key: Buffer | string, cb: TrieGetCb) {
const t = trie.copy()
t.root = this.stateRoot
t.get(key, cb)
}

/**
* Stores a `val` at the `key` in the contract's storage.
*
* Example for `getStorage` and `setStorage`:
*
* ~~~
* // Requires manual merkle-patricia-tree install
* const SecureTrie = require('merkle-patricia-tree/secure')
* const Account = require('./index.js').default
*
* let raw = {
* nonce: '0x0',
* balance: '0x03e7',
* stateRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
* codeHash: '0xb30fb32201fe0486606ad451e1a61e2ae1748343cd3d411ed992ffcc0774edd4',
* }
* let account = new Account(raw)
* let trie = new SecureTrie()
* let key = Buffer.from('0000000000000000000000000000000000000000', 'hex')
* let value = Buffer.from('01', 'hex')
*
* account.setStorage(trie, key, value, function(err) {
* account.getStorage(trie, key, function(err, value) {
* console.log(`Value ${value.toString('hex')} set and retrieved from trie.`)
* })
* })
* ~~~
*
* @param trie
* @param key
* @param val
* @param cb
*/
setStorage(trie: Trie, key: Buffer | string, val: Buffer | string, cb: TriePutCb) {
const t = trie.copy()
t.root = this.stateRoot
t.put(key, val, (err: any) => {
if (err) return cb(err)
this.stateRoot = t.root
cb()
})
return this.codeHash.toString('hex') !== KECCAK256_NULL_S
}

/**
* Returns a `Boolean` determining if the account is empty.
*
*/
isEmpty(): boolean {
return (
this.balance.toString('hex') === '' &&
this.nonce.toString('hex') === '' &&
this.codeHash.toString('hex') === ethUtil.KECCAK256_NULL_S
this.codeHash.toString('hex') === KECCAK256_NULL_S
)
}
}
75 changes: 0 additions & 75 deletions packages/account/test/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as tape from 'tape'
import * as rlp from 'rlp'
import Account from '../src/index'
const SecureTrie = require('merkle-patricia-tree/secure')

tape('empty constructor', function (tester) {
const it = tester.test
Expand Down Expand Up @@ -132,80 +131,6 @@ tape('isContract', function (tester) {
})
})

tape('setCode && getCode', (tester) => {
const it = tester.test
it('should set and get code', (t) => {
const code = Buffer.from(
'73095e7baea6a6c7c4c2dfeb977efac326af552d873173095e7baea6a6c7c4c2dfeb977efac326af552d873157',
'hex',
)

const raw = {
nonce: '0x0',
balance: '0x03e7',
stateRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
codeHash: '0xb30fb32201fe0486606ad451e1a61e2ae1748343cd3d411ed992ffcc0774edd4',
}
const account = new Account(raw)
const trie = new SecureTrie()

account.setCode(trie, code, function (err, codeHash) {
account.getCode(trie, function (err, codeRetrieved) {
t.equals(Buffer.compare(code, codeRetrieved!), 0)
t.end()
})
})
})
it('should not get code if is not contract', (t) => {
const raw = {
nonce: '0x0',
balance: '0x03e7',
}
const account = new Account(raw)
const trie = new SecureTrie()
account.getCode(trie, function (err, code) {
t.equals(Buffer.compare(code!, Buffer.alloc(0)), 0)
t.end()
})
})
it('should set empty code', (t) => {
const raw = {
nonce: '0x0',
balance: '0x03e7',
}
const account = new Account(raw)
const trie = new SecureTrie()
const code = Buffer.alloc(0)
account.setCode(trie, code, function (err, codeHash) {
t.equals(Buffer.compare(codeHash, Buffer.alloc(0)), 0)
t.end()
})
})
})

tape('setStorage && getStorage', (tester) => {
const it = tester.test
it('should set and get storage', (t) => {
const raw = {
nonce: '0x0',
balance: '0x03e7',
stateRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
codeHash: '0xb30fb32201fe0486606ad451e1a61e2ae1748343cd3d411ed992ffcc0774edd4',
}
const account = new Account(raw)
const trie = new SecureTrie()
const key = Buffer.from('0000000000000000000000000000000000000000', 'hex')
const value = Buffer.from('01', 'hex')

account.setStorage(trie, key, value, (err) => {
account.getStorage(trie, key, (err, valueRetrieved) => {
t.equals(Buffer.compare(value, valueRetrieved!), 0)
t.end()
})
})
})
})

tape('isEmpty', (tester) => {
const it = tester.test
it('should return true for an empty account', (t) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/block/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"@ethereumjs/tx": "^2.1.2",
"@types/bn.js": "^4.11.6",
"ethereumjs-util": "^7.0.2",
"merkle-patricia-tree": "^2.3.2"
"merkle-patricia-tree": "^4.0.0"
},
"devDependencies": {
"@ethereumjs/config-nyc": "^1.1.1",
Expand Down
16 changes: 3 additions & 13 deletions packages/block/src/block.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { BaseTrie as Trie } from 'merkle-patricia-tree'
import Common from '@ethereumjs/common'
import { rlp, keccak256, KECCAK256_RLP, baToJSON } from 'ethereumjs-util'
import { BN, rlp, keccak256, KECCAK256_RLP, baToJSON } from 'ethereumjs-util'
import { Transaction, TransactionOptions } from '@ethereumjs/tx'
import { BlockHeader } from './header'
import { Blockchain, BlockData, ChainOptions } from './types'

const Trie = require('merkle-patricia-tree')
const { BN } = require('ethereumjs-util')

/**
* An object that represents the block
*/
Expand Down Expand Up @@ -254,15 +252,7 @@ export class Block {
}

private async _putTxInTrie(txIndex: number, tx: Transaction) {
await new Promise((resolve, reject) => {
this.txTrie.put(rlp.encode(txIndex), tx.serialize(), (err: any) => {
if (err) {
reject(err)
} else {
resolve()
}
})
})
await this.txTrie.put(rlp.encode(txIndex), tx.serialize())
}

private _validateUncleHeader(uncleHeader: BlockHeader, blockchain: Blockchain) {
Expand Down
18 changes: 9 additions & 9 deletions packages/vm/examples/run-blockchain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ async function main() {

await vm.runBlockchain(blockchain)

const blockchainHead = await promisify(vm.blockchain.getHead.bind(vm.blockchain))()
const blockchainHead = (await promisify(
vm.blockchain.getHead.bind(vm.blockchain),
)()) as BlockHeader

console.log('--- Finished processing the BlockChain ---')
console.log('New head:', '0x' + blockchainHead.hash().toString('hex'))
Expand All @@ -55,24 +57,23 @@ async function setupPreConditions(vm: VM, testData: any) {
await vm.stateManager.checkpoint()

for (const address of Object.keys(testData.pre)) {
const addressBuf = toBuffer(address)

const acctData = testData.pre[address]
const account = new Account({
nonce: acctData.nonce,
balance: acctData.balance,
})

const addressBuf = Buffer.from(address.slice(2), 'hex')
await vm.stateManager.putAccount(addressBuf, account)

for (const hexStorageKey of Object.keys(acctData.storage)) {
const val = toBuffer(acctData.storage[hexStorageKey])
const storageKey = setLengthLeft(toBuffer(hexStorageKey), 32)
const val = Buffer.from(acctData.storage[hexStorageKey], 'hex')
const storageKey = setLengthLeft(Buffer.from(hexStorageKey, 'hex'), 32)

await vm.stateManager.putContractStorage(addressBuf, storageKey, val)
}

const codeBuf = toBuffer(acctData.code)
const codeBuf = Buffer.from(acctData.code.slice(2), 'hex')

await vm.stateManager.putContractCode(addressBuf, codeBuf)
}
Expand All @@ -81,9 +82,8 @@ async function setupPreConditions(vm: VM, testData: any) {
}

async function setGenesisBlock(blockchain: any, hardfork: string) {
const genesisBlock = new Block({ hardfork })
genesisBlock.header = new BlockHeader(testData.genesisBlockHeader, { hardfork })

const header = new BlockHeader(testData.genesisBlockHeader, { hardfork })
const genesisBlock = new Block([header.raw, [], []], { hardfork })
await promisify(blockchain.putGenesis.bind(blockchain))(genesisBlock)
}

Expand Down
Loading

0 comments on commit 60b5f5c

Please sign in to comment.