Skip to content

Commit

Permalink
vm -> spuriousDragon: added pre-Byzantium tx receipt format (EIP-658)…
Browse files Browse the repository at this point in the history
… to runBlock.js
  • Loading branch information
holgerd77 committed Jun 26, 2020
1 parent 3129859 commit 703e806
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 13 deletions.
52 changes: 44 additions & 8 deletions packages/vm/lib/runBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,9 @@ export interface RunBlockResult {
}

/**
* Receipt generated for a transaction
* Abstract interface with common transaction receipt fields
*/
export interface TxReceipt {
/**
* Status of transaction, `1` if successful, `0` if an exception occured
*/
status: 0 | 1
interface TxReceipt {
/**
* Gas used
*/
Expand All @@ -75,6 +71,28 @@ export interface TxReceipt {
logs: any[]
}

/**
* Pre-Byzantium receipt type with a field
* for the intermediary state root
*/
export interface PreByzantiumTxReceipt extends TxReceipt {
/**
* Status of transaction, `1` if successful, `0` if an exception occured
*/
stateRoot: Buffer
}

/**
* Receipt type for Byzantium and beyond replacing the intermediary
* state root field with a status code field (EIP-658)
*/
export interface PostByzantiumTxReceipt extends TxReceipt {
/**
* Status of transaction, `1` if successful, `0` if an exception occured
*/
status: 0 | 1
}

/**
* @ignore
*/
Expand Down Expand Up @@ -221,12 +239,30 @@ async function applyTransactions(this: VM, block: any, opts: RunBlockOpts) {
// Combine blooms via bitwise OR
bloom.or(txRes.bloom)

const txReceipt: TxReceipt = {
status: txRes.execResult.exceptionError ? 0 : 1, // Receipts have a 0 as status on error
const abstractTxReceipt: TxReceipt = {
gasUsed: gasUsed.toArrayLike(Buffer),
bitvector: txRes.bloom.bitvector,
logs: txRes.execResult.logs || [],
}
let txReceipt
if (this._common.gteHardfork('byzantium')) {
txReceipt = {
status: txRes.execResult.exceptionError ? 0 : 1, // Receipts have a 0 as status on error
...abstractTxReceipt,
} as PostByzantiumTxReceipt
} else {
// This doesn't return the correct intermediary state root but just the
// initial block state root, so this just satisfies format requirements
// but can't be "used" in any way. Giving the correct intermediary state
// root would need a too depp intervention into the current checkpointing
// mechanism which hasn't been considered to be worth it on a HF backport
const stateRoot = await this.stateManager.getStateRoot(true)
txReceipt = {
stateRoot: stateRoot,
...abstractTxReceipt,
} as PreByzantiumTxReceipt
}

receipts.push(txReceipt)

// Add receipt to trie to later calculate receipt root
Expand Down
2 changes: 1 addition & 1 deletion packages/vm/lib/state/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface StateManager {
checkpoint(): Promise<void>
commit(): Promise<void>
revert(): Promise<void>
getStateRoot(): Promise<Buffer>
getStateRoot(ignoreUncommitedCheckpoints?: boolean): Promise<Buffer>
setStateRoot(stateRoot: Buffer): Promise<void>
dumpStorage(address: Buffer): Promise<StorageDump>
hasGenesisState(): Promise<boolean>
Expand Down
10 changes: 6 additions & 4 deletions packages/vm/lib/state/stateManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,11 +360,13 @@ export default class DefaultStateManager implements StateManager {
* checkpoints on the instance.
* @returns {Promise<Buffer>} - Returns the state-root of the `StateManager`
*/
async getStateRoot(): Promise<Buffer> {
if (this._checkpointCount !== 0) {
throw new Error('Cannot get state root with uncommitted checkpoints')
async getStateRoot(ignoreUncommittedCheckpoints = false): Promise<Buffer> {
if (!ignoreUncommittedCheckpoints) {
if (this._checkpointCount !== 0) {
throw new Error('Cannot get state root with uncommitted checkpoints')
}
await this._cache.flush()
}
await this._cache.flush()
const stateRoot = this._trie.root
return stateRoot
}
Expand Down
29 changes: 29 additions & 0 deletions packages/vm/tests/api/runBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,32 @@ tape('should run valid block', async (t) => {

t.end()
})

async function runWithHf(hardfork) {
const vm = setupVM({ hardfork: hardfork })
const suite = setup(vm)

const block = new Block(util.rlp.decode(suite.data.blocks[0].rlp))

await setupPreConditions(suite.vm.stateManager._trie, suite.data)

let res = await suite.p.runBlock({
block,
generate: true,
skipBlockValidation: true,
})
return res
}

tape('should return correct HF receipts', async (t) => {
let res = await runWithHf('byzantium')
t.equal(res.receipts[0].status, 1, 'should return correct post-Byzantium receipt format')

res = await runWithHf('spuriousDragon')
t.deepEqual(
res.receipts[0].stateRoot,
Buffer.from('7d883d38bc7a640dd66e5cda78cd01b52a7dc40e61f7c2ddbab7cb3ae3b8b9f2', 'hex'),
'should return correct pre-Byzantium receipt format')

t.end()
})

0 comments on commit 703e806

Please sign in to comment.