Skip to content

Commit

Permalink
adding timestamp
Browse files Browse the repository at this point in the history
  • Loading branch information
fersirni committed Oct 10, 2022
1 parent 6178e91 commit f13e717
Show file tree
Hide file tree
Showing 14 changed files with 69 additions and 16 deletions.
1 change: 1 addition & 0 deletions mocks/blocks-mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export const mockBlock = {
hash: '0x03b26a67c6c7fda467f7b96d09b99d04ef9a8163043e72b5e5474358631afad2',
parentHash: '0x9b0f818b9cac7d9451819de6172e308d67c4b8ff8c2f1f6773cdb20c40573858',
number: 27,
timestamp: 1590000000,
createdDate: '2022-08-25 22:49:21.843575',
}

Expand Down
5 changes: 5 additions & 0 deletions mocks/transactions-mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const mockTransaction = {
signer: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
nonce: 37,
tip: 0,
timestamp: 1600000000000,
createdDate: '2022-08-25 23:42:49.006343',
}

Expand Down Expand Up @@ -41,6 +42,8 @@ export const mockTransactions = [
},
]

export const mockTimestamp = 1600000000000

export const mockExtrinsics = [
{
hash: stringToHex('0x01c780fccc47dc4e9652180876a8267dc9f9dd501ed249f077e32c1653a89f2a'),
Expand All @@ -57,6 +60,7 @@ export const mockExtrinsics = [
method: {
method: 'set',
section: 'timestamp',
args: [mockTimestamp],
},
},
{
Expand All @@ -74,6 +78,7 @@ export const mockExtrinsics = [
method: {
method: 'call',
section: 'timestamp',
args: [mockTimestamp],
},
},
]
Expand Down
4 changes: 4 additions & 0 deletions src/blocks/blocks.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,15 @@ describe('BlocksService', () => {
parentHash: mockBlock.parentHash,
number,
} as any) || {},
mockBlock.timestamp,
),
).resolves.toBe(mockBlock)
expect(repo.create).toBeCalledTimes(1)
expect(repo.create).toBeCalledWith({
hash: mockBlock.hash,
parentHash: mockBlock.parentHash,
number: mockBlock.number,
timestamp: mockBlock.timestamp,
})
// TODO: fix repo.save called
// expect(repo.save).toBeCalledTimes(1)
Expand All @@ -109,13 +111,15 @@ describe('BlocksService', () => {
parentHash: mockBlock.parentHash,
number,
} as any) || {},
mockBlock.timestamp,
),
).resolves.toBe(mockBlock)
expect(repo.create).toBeCalledTimes(1)
expect(repo.create).toBeCalledWith({
hash: mockBlock.hash,
parentHash: mockBlock.parentHash,
number: mockBlock.number,
timestamp: mockBlock.timestamp,
})
expect(repo.save).toBeCalledTimes(0)
})
Expand Down
3 changes: 2 additions & 1 deletion src/blocks/blocks.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@ export class BlocksService {
return this.blockRepository.find(args)
}

async createFromHeader(header: Header): Promise<Block> {
async createFromHeader(header: Header, timestamp: number): Promise<Block> {
try {
const { hash, parentHash, number } = header
const block = this.blockRepository.create({
hash: hash.toString().toLowerCase(),
parentHash: parentHash.toString().toLowerCase(),
number: parseInt(number.toHex()),
timestamp,
})
const persistedBlock = await retry(
async () => {
Expand Down
6 changes: 5 additions & 1 deletion src/blocks/entity/block.entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Field, Int, ObjectType } from '@nestjs/graphql'
import { Field, Float, Int, ObjectType } from '@nestjs/graphql'
import { BaseEntity, Column, CreateDateColumn, Entity, Index, OneToMany, PrimaryColumn } from 'typeorm'
import { Transaction } from '../../transactions/entity/transaction.entity'

Expand All @@ -20,6 +20,10 @@ export class Block extends BaseEntity {
@Field(/* istanbul ignore next */ () => Int)
number!: number

@Column('bigint')
@Field(/* istanbul ignore next */ () => Float)
timestamp!: number

@OneToMany(
/* istanbul ignore next */ () => Transaction,
/* istanbul ignore next */ (transaction: Transaction) => transaction.block,
Expand Down
6 changes: 5 additions & 1 deletion src/events/entity/event.entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Field, ObjectType } from '@nestjs/graphql'
import { Field, Float, ObjectType } from '@nestjs/graphql'
import { Codec } from '@polkadot/types-codec/types'
import { IEventData } from '@polkadot/types/types'
import { BaseEntity, Column, Entity, JoinColumn, ManyToOne, PrimaryColumn, CreateDateColumn } from 'typeorm'
Expand Down Expand Up @@ -39,6 +39,10 @@ export class Event extends BaseEntity {
@Field(/* istanbul ignore next */ () => String)
topics!: string

@Column('bigint')
@Field(/* istanbul ignore next */ () => Float)
timestamp!: number

@ManyToOne(
/* istanbul ignore next */ () => Transaction,
/* istanbul ignore next */ (transaction: Transaction) => transaction.events,
Expand Down
14 changes: 12 additions & 2 deletions src/events/events.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,12 @@ describe('EventsService', () => {
.mockResolvedValueOnce(mockEvents[0] as never)
.mockResolvedValueOnce(mockEvents[1] as never)

const events = await service.createEventsFromRecords(mockRecords as any, 1, mockTransaction.hash)
const events = await service.createEventsFromRecords(
mockRecords as any,
1,
mockTransaction.hash,
mockTransaction.timestamp,
)

expect(events).toStrictEqual(mockEvents)
})
Expand All @@ -131,7 +136,12 @@ describe('EventsService', () => {
.mockResolvedValueOnce(mockEvents[0] as never)
.mockResolvedValueOnce(mockEvents[1] as never)

const events = await service.createEventsFromRecords(mockRecords as any, 1, mockTransaction.hash)
const events = await service.createEventsFromRecords(
mockRecords as any,
1,
mockTransaction.hash,
mockTransaction.timestamp,
)

expect(events).toStrictEqual(mockEvents)
})
Expand Down
2 changes: 2 additions & 0 deletions src/events/events.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export class EventsService {
records: Vec<FrameSystemEventRecord>,
extrinsicIndex: number,
transactionHash: string,
timestamp: number,
): Promise<Event[]> {
const events = records.filter(({ phase }) => phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(extrinsicIndex))
const contractEmittedEvents = events.filter((record) => record?.event?.method === 'ContractEmitted')
Expand Down Expand Up @@ -66,6 +67,7 @@ export class EventsService {
topics: topics.toString(),
data,
transactionHash: transactionHash.toString().toLowerCase(),
timestamp,
})
})
return Promise.all(eventsToSave.map((event) => this.eventRepository.save(event)))
Expand Down
3 changes: 3 additions & 0 deletions src/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ type Block {
hash: String!
number: Int!
parentHash: String!
timestamp: Float!
transactions: [Transaction!]!
}

Expand All @@ -21,6 +22,7 @@ type Event {
index: String!
method: String!
section: String!
timestamp: Float!
topics: String!
transactionHash: String
}
Expand Down Expand Up @@ -57,6 +59,7 @@ type Transaction {

"""Address of the signer"""
signer: String
timestamp: Float!

"""Extra gas paid for the Tx as tip"""
tip: Int
Expand Down
3 changes: 2 additions & 1 deletion src/subscriptions/subscriptions.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { apiMock } from '../../mocks/api-mock'
import { mockBlock, mockBlocks } from '../../mocks/blocks-mocks'
import { mockEvents } from '../../mocks/events-mocks'
import { mockPinoService } from '../../mocks/pino-mocks'
import { mockExtrinsics, mockTransactions } from '../../mocks/transactions-mock'
import { mockExtrinsics, mockTimestamp, mockTransactions } from '../../mocks/transactions-mock'
import { BlocksService } from '../blocks/blocks.service'
import { EventsService } from '../events/events.service'
import { TransactionsService } from '../transactions/transactions.service'
Expand Down Expand Up @@ -133,6 +133,7 @@ describe('subscriptionsService', () => {
},
extrinsics: mockExtrinsics,
records: [],
timestamp: mockTimestamp,
}),
)
})
Expand Down
16 changes: 11 additions & 5 deletions src/subscriptions/subscriptions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ export class SubscriptionsService implements OnModuleInit {
async getBlockData(api: ApiPromise, hash: BlockHash) {
const [block, records] = await Promise.all([api.rpc.chain.getBlock(hash), api.query.system.events.at(hash)])
const { header, extrinsics } = block.block || {}
return { header, extrinsics, records }
const timestampArgs = extrinsics.map((e) => e.method).find((m) => m.section === 'timestamp' && m.method === 'set')
const timestamp = Number(timestampArgs?.args[0].toString())
return { header, extrinsics, records, timestamp }
}

getBlocksToLoad(from: number, to: number): number[] {
Expand Down Expand Up @@ -116,11 +118,15 @@ export class SubscriptionsService implements OnModuleInit {
}

async registerBlockData(blockData: any) {
const { header, extrinsics, records } = blockData
const block = await this.blocksService.createFromHeader(header)
const transactions = await this.transactionsService.createTransactionsFromExtrinsics(extrinsics, block.hash)
const { header, extrinsics, records, timestamp } = blockData
const block = await this.blocksService.createFromHeader(header, timestamp)
const transactions = await this.transactionsService.createTransactionsFromExtrinsics(
extrinsics,
block.hash,
timestamp,
)
for (const [index, tx] of transactions.entries()) {
await this.eventsService.createEventsFromRecords(records, index, tx.hash)
await this.eventsService.createEventsFromRecords(records, index, tx.hash, timestamp)
}
return block
}
Expand Down
6 changes: 5 additions & 1 deletion src/transactions/entity/transaction.entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Field, Int, ObjectType } from '@nestjs/graphql'
import { Field, Float, Int, ObjectType } from '@nestjs/graphql'
import {
BaseEntity,
Column,
Expand Down Expand Up @@ -35,6 +35,10 @@ export class Transaction extends BaseEntity {
@Field(/* istanbul ignore next */ () => String)
section!: string

@Column('bigint')
@Field(/* istanbul ignore next */ () => Float)
timestamp!: number

@ManyToOne(/* istanbul ignore next */ () => Block, /* istanbul ignore next */ (block: Block) => block.transactions, {
onDelete: 'SET NULL',
nullable: true,
Expand Down
14 changes: 10 additions & 4 deletions src/transactions/transactions.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import { Test, TestingModule } from '@nestjs/testing'
import { getRepositoryToken } from '@nestjs/typeorm'
import { Repository } from 'typeorm'
import { mockPinoService } from '../../mocks/pino-mocks'
import { mockExtrinsics, mockSavedTransactions, mockTransaction, mockTransactions } from '../../mocks/transactions-mock'
import {
mockExtrinsics,
mockSavedTransactions,
mockTimestamp,
mockTransaction,
mockTransactions,
} from '../../mocks/transactions-mock'
import { Transaction } from './entity/transaction.entity'
import { TransactionsService } from './transactions.service'

Expand Down Expand Up @@ -66,7 +72,7 @@ describe('TransactionsService', () => {
.mockResolvedValueOnce(mockSavedTransactions[0])
.mockResolvedValueOnce(mockSavedTransactions[1])
const blockHash = '0xffcfae3ecc9ab7b79fc0cd451dad35477a32219b219b29584b968826ac04c1a1'
const savedTxs = await service.createTransactionsFromExtrinsics(mockExtrinsics as any, blockHash)
const savedTxs = await service.createTransactionsFromExtrinsics(mockExtrinsics as any, blockHash, mockTimestamp)
mockSavedTransactions.forEach((tx, i) => {
expect(savedTxs[i].hash).toEqual(tx.hash)
expect(savedTxs[i].blockHash).toEqual(tx.blockHash)
Expand All @@ -87,7 +93,7 @@ describe('TransactionsService', () => {
.mockResolvedValueOnce(mockSavedTransactions[0])
.mockResolvedValueOnce(mockSavedTransactions[1])
const blockHash = '0xffcfae3ecc9ab7b79fc0cd451dad35477a32219b219b29584b968826ac04c1a1'
const savedTxs = await service.createTransactionsFromExtrinsics(mockExtrinsics as any, blockHash)
const savedTxs = await service.createTransactionsFromExtrinsics(mockExtrinsics as any, blockHash, mockTimestamp)
mockSavedTransactions.forEach((tx, i) => {
expect(savedTxs[i].hash).toEqual(tx.hash)
expect(savedTxs[i].blockHash).toEqual(tx.blockHash)
Expand All @@ -107,7 +113,7 @@ describe('TransactionsService', () => {
try {
jest.spyOn(repo, 'findOneBy').mockResolvedValue(Promise.reject("Can't connect to database"))
const blockHash = '0xffcfae3ecc9ab7b79fc0cd451dad35477a32219b219b29584b968826ac04c1a1'
await service.createTransactionsFromExtrinsics(mockExtrinsics as any, blockHash)
await service.createTransactionsFromExtrinsics(mockExtrinsics as any, blockHash, mockTimestamp)
fail("Shouldn't reach this point")
} catch (error) {
expect(error).toEqual("Can't connect to database")
Expand Down
2 changes: 2 additions & 0 deletions src/transactions/transactions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export class TransactionsService {
async createTransactionsFromExtrinsics(
extrinsics: Vec<GenericExtrinsic<AnyTuple>>,
blockHash: string,
timestamp: number,
): Promise<Transaction[]> {
return Promise.all(
extrinsics.map(async (extrinsic) => {
Expand All @@ -50,6 +51,7 @@ export class TransactionsService {
signer: signer.toString(),
tip: tip.toNumber(),
blockHash: blockHash.toLowerCase(),
timestamp,
})
const transaction = await retry(
async () => {
Expand Down

0 comments on commit f13e717

Please sign in to comment.