diff --git a/packages/vm/lib/runBlock.ts b/packages/vm/lib/runBlock.ts index 59fadd70620..5a7b685bd50 100644 --- a/packages/vm/lib/runBlock.ts +++ b/packages/vm/lib/runBlock.ts @@ -52,13 +52,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 */ @@ -73,6 +69,28 @@ export interface TxReceipt { logs: any[] } +/** + * Pre-Byzantium receipt type with a field + * for the intermediary state root + */ +export interface PreByzantiumTxReceipt extends TxReceipt { + /** + * Intermediary state root + */ + 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 */ @@ -219,12 +237,28 @@ 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 is just using a dummy place holder for the state root right now. + // 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, 2020-06-26 + txReceipt = { + stateRoot: Buffer.alloc(32), + ...abstractTxReceipt, + } as PreByzantiumTxReceipt + } + receipts.push(txReceipt) // Add receipt to trie to later calculate receipt root diff --git a/packages/vm/tests/api/runBlock.js b/packages/vm/tests/api/runBlock.js index a49f583df62..92582e15956 100644 --- a/packages/vm/tests/api/runBlock.js +++ b/packages/vm/tests/api/runBlock.js @@ -145,3 +145,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.alloc(32), + 'should return correct pre-Byzantium receipt format') + + t.end() +}) \ No newline at end of file