Skip to content

Commit 5a1789e

Browse files
authored
Merge branch 'master' into client-fix-undefined-result
2 parents 10000f4 + a855765 commit 5a1789e

File tree

5 files changed

+142
-11
lines changed

5 files changed

+142
-11
lines changed

packages/blockchain/src/index.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -736,15 +736,16 @@ export default class Blockchain implements BlockchainInterface {
736736
*
737737
* @param name - Name of the state root head
738738
* @param onBlock - Function called on each block with params (block, reorg)
739+
* @param maxBlocks - How many blocks to run. By default, run all unprocessed blocks in the canonical chain.
739740
*/
740-
async iterator(name: string, onBlock: OnBlock) {
741-
return this._iterator(name, onBlock)
741+
async iterator(name: string, onBlock: OnBlock, maxBlocks?: number) {
742+
return this._iterator(name, onBlock, maxBlocks)
742743
}
743744

744745
/**
745746
* @hidden
746747
*/
747-
private async _iterator(name: string, onBlock: OnBlock) {
748+
private async _iterator(name: string, onBlock: OnBlock, maxBlocks?: number) {
748749
await this.initAndLock<void>(async () => {
749750
const blockHash = this._heads[name] || this._genesis
750751
let lastBlock: Block | undefined
@@ -753,11 +754,15 @@ export default class Blockchain implements BlockchainInterface {
753754
return
754755
}
755756

757+
if (maxBlocks && maxBlocks < 0) {
758+
throw 'If maxBlocks is provided, it has to be a non-negative number'
759+
}
760+
756761
const number = await this.dbManager.hashToNumber(blockHash)
757762
const blockNumber = number.addn(1)
763+
let blocksRanCounter = 0
758764

759-
// eslint-disable-next-line no-constant-condition
760-
while (true) {
765+
while (maxBlocks !== blocksRanCounter) {
761766
try {
762767
const block = await this._getBlock(blockNumber)
763768

@@ -770,6 +775,7 @@ export default class Blockchain implements BlockchainInterface {
770775
lastBlock = block
771776
await onBlock(block, reorg)
772777
blockNumber.iaddn(1)
778+
blocksRanCounter++
773779
} catch (error) {
774780
if (error.type !== 'NotFoundError') {
775781
throw error
@@ -782,6 +788,19 @@ export default class Blockchain implements BlockchainInterface {
782788
})
783789
}
784790

791+
/**
792+
* Set header hash of a certain `tag`.
793+
* When calling the iterator, the iterator will start running the first child block after the header hash currenntly stored.
794+
* @param tag - The tag to save the headHash to
795+
* @param headHash - The head hash to save
796+
*/
797+
async setHead(tag: string, headHash: Buffer) {
798+
await this.initAndLock<void>(async () => {
799+
this._heads[tag] = headHash
800+
await this._saveHeads()
801+
})
802+
}
803+
785804
/* Methods regarding re-org operations */
786805

787806
/**

packages/blockchain/test/index.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,99 @@ tape('blockchain test', (t) => {
348348
st.end()
349349
})
350350

351+
t.test(
352+
'should iterate through maxBlocks blocks if maxBlocks parameter is provided',
353+
async (st) => {
354+
const { blockchain, blocks, error } = await generateBlockchain(25)
355+
st.error(error, 'no error')
356+
let i = 0
357+
await blockchain.iterator(
358+
'test',
359+
(block: Block) => {
360+
if (block.hash().equals(blocks[i + 1].hash())) {
361+
i++
362+
}
363+
},
364+
5
365+
)
366+
st.equals(i, 5)
367+
st.end()
368+
}
369+
)
370+
371+
t.test(
372+
'should iterate through 0 blocks in case 0 maxBlocks parameter is provided',
373+
async (st) => {
374+
const { blockchain, blocks, error } = await generateBlockchain(25)
375+
st.error(error, 'no error')
376+
let i = 0
377+
await blockchain
378+
.iterator(
379+
'test',
380+
(block: Block) => {
381+
if (block.hash().equals(blocks[i + 1].hash())) {
382+
i++
383+
}
384+
},
385+
0
386+
)
387+
.catch(() => {
388+
st.fail('Promise cannot throw when running 0 blocks')
389+
})
390+
st.equals(i, 0)
391+
st.end()
392+
}
393+
)
394+
395+
t.test('should throw on a negative maxBlocks parameter in iterator', async (st) => {
396+
const { blockchain, blocks, error } = await generateBlockchain(25)
397+
st.error(error, 'no error')
398+
let i = 0
399+
await blockchain
400+
.iterator(
401+
'test',
402+
(block: Block) => {
403+
if (block.hash().equals(blocks[i + 1].hash())) {
404+
i++
405+
}
406+
},
407+
-1
408+
)
409+
.catch(() => {
410+
st.end()
411+
})
412+
// Note: if st.end() is not called (Promise did not throw), then this test fails, as it does not end.
413+
})
414+
415+
t.test('should test setHead method', async (st) => {
416+
const { blockchain, blocks, error } = await generateBlockchain(25)
417+
st.error(error, 'no error')
418+
419+
const headBlockIndex = 5
420+
421+
const headHash = blocks[headBlockIndex].hash()
422+
await blockchain.setHead('myHead', headHash)
423+
const currentHeadBlock = await blockchain.getHead('myHead')
424+
425+
st.ok(headHash.equals(currentHeadBlock.hash()), 'head hash equals the provided head hash')
426+
427+
let i = 0
428+
// check that iterator starts from this head block
429+
await blockchain.iterator(
430+
'myHead',
431+
(block: Block) => {
432+
if (block.hash().equals(blocks[headBlockIndex + 1].hash())) {
433+
i++
434+
}
435+
},
436+
5
437+
)
438+
439+
st.equals(i, 1)
440+
441+
st.end()
442+
})
443+
351444
t.test('should catch iterator func error', async (st) => {
352445
const { blockchain, error } = await generateBlockchain(25)
353446
st.error(error, 'no error')

packages/vm/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,9 @@ Our `TypeScript` VM is implemented as an [AsyncEventEmitter](https://github.com/
130130
You can subscribe to the following events:
131131

132132
- `beforeBlock`: Emits a `Block` right before running it.
133-
- `afterBlock`: Emits `RunBlockResult` right after running a block.
133+
- `afterBlock`: Emits `AfterBlockEvent` right after running a block.
134134
- `beforeTx`: Emits a `Transaction` right before running it.
135-
- `afterTx`: Emits a `RunTxResult` right after running a transaction.
135+
- `afterTx`: Emits a `AfterTxEvent` right after running a transaction.
136136
- `beforeMessage`: Emits a `Message` right after running it.
137137
- `afterMessage`: Emits an `EVMResult` right after running a message.
138138
- `step`: Emits an `InterpreterStep` right before running an EVM step.

packages/vm/lib/runBlock.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ export interface PostByzantiumTxReceipt extends TxReceipt {
104104
status: 0 | 1
105105
}
106106

107+
export interface AfterBlockEvent extends RunBlockResult {
108+
// The block which just finished processing
109+
block: Block
110+
}
111+
107112
/**
108113
* @ignore
109114
*/
@@ -183,14 +188,20 @@ export default async function runBlock(this: VM, opts: RunBlockOpts): Promise<Ru
183188

184189
const { receipts, results } = result
185190

191+
const afterBlockEvent: AfterBlockEvent = {
192+
receipts,
193+
results,
194+
block,
195+
}
196+
186197
/**
187198
* The `afterBlock` event
188199
*
189200
* @event Event: afterBlock
190-
* @type {Object}
191-
* @property {Object} result emits the results of processing a block
201+
* @type {AfterBlockEvent}
202+
* @property {AfterBlockEvent} result emits the results of processing a block
192203
*/
193-
await this._emit('afterBlock', { receipts, results })
204+
await this._emit('afterBlock', afterBlockEvent)
194205

195206
return { receipts, results }
196207
}

packages/vm/lib/runTx.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ export interface RunTxResult extends EVMResult {
4747
gasRefund?: BN
4848
}
4949

50+
export interface AfterTxEvent extends RunTxResult {
51+
/**
52+
* The transaction which just got finished
53+
*/
54+
transaction: Transaction
55+
}
56+
5057
/**
5158
* @ignore
5259
*/
@@ -199,7 +206,8 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise<RunTxResult> {
199206
* @type {Object}
200207
* @property {Object} result result of the transaction
201208
*/
202-
await this._emit('afterTx', results)
209+
const event: AfterTxEvent = { transaction: tx, ...results }
210+
await this._emit('afterTx', event)
203211

204212
return results
205213
}

0 commit comments

Comments
 (0)