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

Commit

Permalink
fix(blockchain): emitter confirm only its specified events
Browse files Browse the repository at this point in the history
  • Loading branch information
AuHau committed May 14, 2020
1 parent a993f34 commit 194a8d4
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 17 deletions.
5 changes: 4 additions & 1 deletion src/blockchain/event.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ export default class Event extends Model {
@Column(DataType.INTEGER)
logIndex!: number

@Column(DataType.TEXT)
event!: string

@Column(DataType.TEXT)
content!: string
}

export type EventInterface = Pick<Event, 'blockNumber' | 'transactionHash' | 'logIndex' | 'content'>
export type EventInterface = Pick<Event, 'blockNumber' | 'transactionHash' | 'logIndex' | 'event' | 'content'>
8 changes: 7 additions & 1 deletion src/blockchain/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,12 @@ export abstract class BaseEventsEmitter extends AutoStartStopEventEmitter {
*/
private async confirmEvents (currentBlockNumber: number): Promise<void> {
try {
const dbEvents = await Event.findAll({ where: { blockNumber: { [Op.lte]: currentBlockNumber - this.confirmations } } })
const dbEvents = await Event.findAll({
where: {
blockNumber: { [Op.lte]: currentBlockNumber - this.confirmations },
event: this.events
}
})

const ethEvents = dbEvents.map(event => JSON.parse(event.content)) as EventData[]
const validEthEvents = await asyncFilter(ethEvents, this.eventHasValidReceipt.bind(this))
Expand Down Expand Up @@ -348,6 +353,7 @@ export abstract class BaseEventsEmitter extends AutoStartStopEventEmitter {
blockNumber: data.blockNumber,
transactionHash: data.transactionHash,
logIndex: data.logIndex,
event: data.event,
content: JSON.stringify(data)
}
}
Expand Down
141 changes: 126 additions & 15 deletions test/blockchain/events.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
ListeningNewBlockEmitter, PollingEventsEmitter,
PollingNewBlockEmitter
} from '../../src/blockchain/events'
import { Store } from '../../src/definitions'
import { Logger, Store } from '../../src/definitions'
import { BlockHeader, Eth, TransactionReceipt } from 'web3-eth'

import { Arg, Substitute } from '@fluffy-spoon/substitute'
Expand Down Expand Up @@ -104,8 +104,14 @@ function receiptMock (blockNumber?: number, status = true): TransactionReceipt {
* Dummy implementation for testing BaseEventsEmitter
*/
export class DummyEventsEmitter extends BaseEventsEmitter {
constructor (eth: Eth, contract: Contract, events: string[], options?: EventsEmitterOptions) {
const logger = loggingFactory('blockchain:events:dummy')
constructor (eth: Eth, contract: Contract, events: string[], options?: EventsEmitterOptions, name?: string) {
let logger: Logger
if (!name) {
logger = loggingFactory('blockchain:events:dummy')
} else {
logger = loggingFactory('blockchain:events:' + name)
}

super(eth, contract, events, logger, options)
}

Expand Down Expand Up @@ -415,12 +421,12 @@ describe('BaseEventsEmitter', () => {

// Create events to be confirmed
const events = [
{ blockNumber: 7, transactionHash: '1', logIndex: 1, content: '{"transactionHash": "1", "blockNumber": 7}' },
{ blockNumber: 8, transactionHash: '2', logIndex: 1, content: '{"transactionHash": "2", "blockNumber": 8}' },
{ blockNumber: 9, transactionHash: '3', logIndex: 1, content: '{"transactionHash": "3", "blockNumber": 9}' },
{ blockNumber: 9, transactionHash: '4', logIndex: 1, content: '{"transactionHash": "4", "blockNumber": 9}' },
{ blockNumber: 10, transactionHash: '5', logIndex: 1, content: '{"transactionHash": "5", "blockNumber": 10}' },
{ blockNumber: 11, transactionHash: '6', logIndex: 1, content: '{"transactionHash": "6", "blockNumber": 11}' }
{ event: 'testEvent', blockNumber: 7, transactionHash: '1', logIndex: 1, content: '{"transactionHash": "1", "blockNumber": 7}' },
{ event: 'testEvent', blockNumber: 8, transactionHash: '2', logIndex: 1, content: '{"transactionHash": "2", "blockNumber": 8}' },
{ event: 'testEvent', blockNumber: 9, transactionHash: '3', logIndex: 1, content: '{"transactionHash": "3", "blockNumber": 9}' },
{ event: 'testEvent', blockNumber: 9, transactionHash: '4', logIndex: 1, content: '{"transactionHash": "4", "blockNumber": 9}' },
{ event: 'testEvent', blockNumber: 10, transactionHash: '5', logIndex: 1, content: '{"transactionHash": "5", "blockNumber": 10}' },
{ event: 'testEvent', blockNumber: 11, transactionHash: '6', logIndex: 1, content: '{"transactionHash": "6", "blockNumber": 11}' }
]
await Event.bulkCreate(events)

Expand Down Expand Up @@ -453,12 +459,12 @@ describe('BaseEventsEmitter', () => {

// Create events to be confirmed
const events = [
{ blockNumber: 7, transactionHash: '1', logIndex: 1, content: '{"transactionHash": "1", "blockNumber": 7}' },
{ blockNumber: 8, transactionHash: '2', logIndex: 1, content: '{"transactionHash": "2", "blockNumber": 8}' },
{ blockNumber: 9, transactionHash: '3', logIndex: 1, content: '{"transactionHash": "3", "blockNumber": 9}' },
{ blockNumber: 9, transactionHash: '4', logIndex: 1, content: '{"transactionHash": "4", "blockNumber": 9}' },
{ blockNumber: 10, transactionHash: '5', logIndex: 1, content: '{"transactionHash": "5", "blockNumber": 10}' },
{ blockNumber: 11, transactionHash: '6', logIndex: 1, content: '{"transactionHash": "6", "blockNumber": 11}' }
{ event: 'testEvent', blockNumber: 7, transactionHash: '1', logIndex: 1, content: '{"transactionHash": "1", "blockNumber": 7}' },
{ event: 'testEvent', blockNumber: 8, transactionHash: '2', logIndex: 1, content: '{"transactionHash": "2", "blockNumber": 8}' },
{ event: 'testEvent', blockNumber: 9, transactionHash: '3', logIndex: 1, content: '{"transactionHash": "3", "blockNumber": 9}' },
{ event: 'testEvent', blockNumber: 9, transactionHash: '4', logIndex: 1, content: '{"transactionHash": "4", "blockNumber": 9}' },
{ event: 'testEvent', blockNumber: 10, transactionHash: '5', logIndex: 1, content: '{"transactionHash": "5", "blockNumber": 10}' },
{ event: 'testEvent', blockNumber: 11, transactionHash: '6', logIndex: 1, content: '{"transactionHash": "6", "blockNumber": 11}' }
]
await Event.bulkCreate(events)

Expand All @@ -469,6 +475,111 @@ describe('BaseEventsEmitter', () => {
expect(emitterSpy.getCalls().length).to.be.eql(3, 'Expected three events emitted.')
expect(await Event.count()).to.eql(2)
})

it('each emitter should confirm only his events', async function () {
const eth = Substitute.for<Eth>()
eth.getBlockNumber().returns(Promise.resolve(10))

eth.getTransactionReceipt('1').returns(Promise.resolve(receiptMock(7)))
eth.getTransactionReceipt('2').returns(Promise.resolve(receiptMock(8)))
eth.getTransactionReceipt('3').returns(Promise.resolve(receiptMock(9)))
eth.getTransactionReceipt('4').returns(Promise.resolve(receiptMock(10)))
eth.getTransactionReceipt('5').returns(Promise.resolve(receiptMock(11)))

const contract = Substitute.for<Contract>()
contract.getPastEvents(Arg.all()).returns(Promise.resolve([]))

const firstBlockTracker = new BlockTracker(new StoreMock())
const firstNewBlockEmitter = new EventEmitter()
const firstOptions: EventsEmitterOptions = {
confirmations: 2,
blockTracker: firstBlockTracker,
newBlockEmitter: firstNewBlockEmitter
}
const firstEmitterSpy = sinon.spy()
const firstEventsEmitter = new DummyEventsEmitter(eth, contract, ['firstEvent'], firstOptions, 'dummy1')
firstEventsEmitter.on(DATA_EVENT_NAME, firstEmitterSpy)

const secondBlockTracker = new BlockTracker(new StoreMock())
const secondNewBlockEmitter = new EventEmitter()
const secondOptions: EventsEmitterOptions = {
confirmations: 2,
blockTracker: secondBlockTracker,
newBlockEmitter: secondNewBlockEmitter
}
const secondEmitterSpy = sinon.spy()
const secondEventsEmitter = new DummyEventsEmitter(eth, contract, ['secondEvent'], secondOptions, 'dummy2')
secondEventsEmitter.on(DATA_EVENT_NAME, secondEmitterSpy)

// Create events to be confirmed
const events = [
{
event: 'firstEvent',
blockNumber: 7,
transactionHash: '1',
logIndex: 1,
content: '{"transactionHash": "1", "blockNumber": 7, "event": "firstEvent"}'
},
{
event: 'secondEvent',
blockNumber: 8,
transactionHash: '2',
logIndex: 1,
content: '{"transactionHash": "2", "blockNumber": 8, "event": "secondEvent"}'
},
{
event: 'firstEvent',
blockNumber: 9,
transactionHash: '3',
logIndex: 1,
content: '{"transactionHash": "3", "blockNumber": 9, "event": "firstEvent"}'
},
{
event: 'secondEvent',
blockNumber: 10,
transactionHash: '4',
logIndex: 1,
content: '{"transactionHash": "4", "blockNumber": 10, "event": "secondEvent"}'
},
{
event: 'firstEvent',
blockNumber: 11,
transactionHash: '5',
logIndex: 1,
content: '{"transactionHash": "5", "blockNumber": 11, "event": "firstEvent"}'
},
{
event: 'firstEvent',
blockNumber: 12,
transactionHash: '6',
logIndex: 1,
content: '{"transactionHash": "6", "blockNumber": 12, "event": "firstEvent"}'
},
{
event: 'secondEvent',
blockNumber: 13,
transactionHash: '7',
logIndex: 1,
content: '{"transactionHash": "7", "blockNumber": 13, "event": "secondEvent"}'
}
]
await Event.bulkCreate(events)

// Start confirmations process
firstNewBlockEmitter.emit(NEW_BLOCK_EVENT, 13)
await sleep(500)

secondNewBlockEmitter.emit(NEW_BLOCK_EVENT, 13)
await sleep(500)

expect(firstEmitterSpy.getCalls().length).to.be.eql(3, 'Expected three firstEvent events emitted.')
firstEmitterSpy.getCalls().forEach(call => expect(call.args[0].event).to.eql('firstEvent'))

expect(secondEmitterSpy.getCalls().length).to.be.eql(2, 'Expected two secondEvent events emitted.')
secondEmitterSpy.getCalls().forEach(call => expect(call.args[0].event).to.eql('secondEvent'))

expect(await Event.count()).to.eql(2)
})
})

describe('no confirmations', () => {
Expand Down

0 comments on commit 194a8d4

Please sign in to comment.