mirror of
https://github.com/cerc-io/watcher-ts
synced 2025-07-28 11:02:07 +00:00
Get missing block fields (#51)
* Decode header and get missing block fields * Move method to get block data to misc in util * Remove unnecessary encoding of header data
This commit is contained in:
parent
800ad79baf
commit
ec3a8a31a7
@ -33,6 +33,10 @@ export interface Block {
|
|||||||
td: string;
|
td: string;
|
||||||
txRoot: string;
|
txRoot: string;
|
||||||
receiptRoot: string;
|
receiptRoot: string;
|
||||||
|
uncleHash: string;
|
||||||
|
difficulty: string;
|
||||||
|
gasLimit: string;
|
||||||
|
gasUsed: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EventData {
|
export interface EventData {
|
||||||
@ -263,9 +267,19 @@ export const createBlock = async (instanceExports: any, blockData: Block): Promi
|
|||||||
const parentHashByteArray = await ByteArray.fromHexString(parentHashStringPtr);
|
const parentHashByteArray = await ByteArray.fromHexString(parentHashStringPtr);
|
||||||
const parentHash = await Bytes.fromByteArray(parentHashByteArray);
|
const parentHash = await Bytes.fromByteArray(parentHashByteArray);
|
||||||
|
|
||||||
|
const uncleHashStringPtr = await __newString(blockData.uncleHash);
|
||||||
|
const uncleHashByteArray = await ByteArray.fromHexString(uncleHashStringPtr);
|
||||||
|
const uncleHash = await Bytes.fromByteArray(uncleHashByteArray);
|
||||||
|
|
||||||
const blockNumberStringPtr = await __newString(blockData.blockNumber);
|
const blockNumberStringPtr = await __newString(blockData.blockNumber);
|
||||||
const blockNumber = await BigInt.fromString(blockNumberStringPtr);
|
const blockNumber = await BigInt.fromString(blockNumberStringPtr);
|
||||||
|
|
||||||
|
const gasUsedStringPtr = await __newString(blockData.gasUsed);
|
||||||
|
const gasUsed = await BigInt.fromString(gasUsedStringPtr);
|
||||||
|
|
||||||
|
const gasLimitStringPtr = await __newString(blockData.gasLimit);
|
||||||
|
const gasLimit = await BigInt.fromString(gasLimitStringPtr);
|
||||||
|
|
||||||
const timestampStringPtr = await __newString(blockData.timestamp);
|
const timestampStringPtr = await __newString(blockData.timestamp);
|
||||||
const blockTimestamp = await BigInt.fromString(timestampStringPtr);
|
const blockTimestamp = await BigInt.fromString(timestampStringPtr);
|
||||||
|
|
||||||
@ -281,35 +295,30 @@ export const createBlock = async (instanceExports: any, blockData: Block): Promi
|
|||||||
const receiptsRootByteArray = await ByteArray.fromHexString(receiptRootStringPtr);
|
const receiptsRootByteArray = await ByteArray.fromHexString(receiptRootStringPtr);
|
||||||
const receiptsRoot = await Bytes.fromByteArray(receiptsRootByteArray);
|
const receiptsRoot = await Bytes.fromByteArray(receiptsRootByteArray);
|
||||||
|
|
||||||
|
const difficultyStringPtr = await __newString(blockData.difficulty);
|
||||||
|
const difficulty = await BigInt.fromString(difficultyStringPtr);
|
||||||
|
|
||||||
const tdStringPtr = await __newString(blockData.td);
|
const tdStringPtr = await __newString(blockData.td);
|
||||||
const totalDifficulty = await BigInt.fromString(tdStringPtr);
|
const totalDifficulty = await BigInt.fromString(tdStringPtr);
|
||||||
|
|
||||||
const unclesHashPtr = await Bytes.empty();
|
|
||||||
const authorPtr = await Address.zero();
|
const authorPtr = await Address.zero();
|
||||||
const gasUsedPtr = await BigInt.fromI32(0);
|
|
||||||
const gasLimitPtr = await BigInt.fromI32(0);
|
|
||||||
const difficultyPtr = await BigInt.fromI32(0);
|
|
||||||
|
|
||||||
// Missing fields from watcher in block data:
|
// Missing fields from watcher in block data:
|
||||||
// unclesHash
|
|
||||||
// author
|
// author
|
||||||
// gasUsed
|
|
||||||
// gasLimit
|
|
||||||
// difficulty
|
|
||||||
// size
|
// size
|
||||||
return await ethereum.Block.__new(
|
return await ethereum.Block.__new(
|
||||||
blockHash,
|
blockHash,
|
||||||
parentHash,
|
parentHash,
|
||||||
unclesHashPtr,
|
uncleHash,
|
||||||
authorPtr,
|
authorPtr,
|
||||||
stateRoot,
|
stateRoot,
|
||||||
transactionsRoot,
|
transactionsRoot,
|
||||||
receiptsRoot,
|
receiptsRoot,
|
||||||
blockNumber,
|
blockNumber,
|
||||||
gasUsedPtr,
|
gasUsed,
|
||||||
gasLimitPtr,
|
gasLimit,
|
||||||
blockTimestamp,
|
blockTimestamp,
|
||||||
difficultyPtr,
|
difficulty,
|
||||||
totalDifficulty,
|
totalDifficulty,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
@ -11,7 +11,7 @@ import { ContractInterface, utils } from 'ethers';
|
|||||||
|
|
||||||
import { ResultObject } from '@vulcanize/assemblyscript/lib/loader';
|
import { ResultObject } from '@vulcanize/assemblyscript/lib/loader';
|
||||||
import { EthClient } from '@vulcanize/ipld-eth-client';
|
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||||
import { IndexerInterface } from '@vulcanize/util';
|
import { IndexerInterface, getFullBlock } from '@vulcanize/util';
|
||||||
|
|
||||||
import { createBlock, createEvent, getSubgraphConfig, resolveEntityFieldConflicts } from './utils';
|
import { createBlock, createEvent, getSubgraphConfig, resolveEntityFieldConflicts } from './utils';
|
||||||
import { Context, instantiate } from './loader';
|
import { Context, instantiate } from './loader';
|
||||||
@ -98,13 +98,8 @@ export class GraphWatcher {
|
|||||||
async handleEvent (eventData: any) {
|
async handleEvent (eventData: any) {
|
||||||
const { contract, event, eventSignature, block, tx, eventIndex } = eventData;
|
const { contract, event, eventSignature, block, tx, eventIndex } = eventData;
|
||||||
|
|
||||||
const {
|
// TODO: Use blockData fetched in handleBlock.
|
||||||
allEthHeaderCids: {
|
const blockData = await getFullBlock(this._postgraphileClient, block.hash);
|
||||||
nodes: [
|
|
||||||
blockData
|
|
||||||
]
|
|
||||||
}
|
|
||||||
} = await this._postgraphileClient.getBlocks({ blockHash: block.hash });
|
|
||||||
|
|
||||||
this._context.event.block = blockData;
|
this._context.event.block = blockData;
|
||||||
|
|
||||||
@ -150,13 +145,7 @@ export class GraphWatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async handleBlock (blockHash: string) {
|
async handleBlock (blockHash: string) {
|
||||||
const {
|
const blockData = await getFullBlock(this._postgraphileClient, blockHash);
|
||||||
allEthHeaderCids: {
|
|
||||||
nodes: [
|
|
||||||
blockData
|
|
||||||
]
|
|
||||||
}
|
|
||||||
} = await this._postgraphileClient.getBlocks({ blockHash });
|
|
||||||
|
|
||||||
// Call block handler(s) for each contract.
|
// Call block handler(s) for each contract.
|
||||||
for (const dataSource of this._dataSources) {
|
for (const dataSource of this._dataSources) {
|
||||||
|
@ -82,6 +82,16 @@ export class EthClient {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getFullBlocks ({ blockNumber, blockHash }: { blockNumber?: number, blockHash?: string }): Promise<any> {
|
||||||
|
return this._graphqlClient.query(
|
||||||
|
ethQueries.getFullBlocks,
|
||||||
|
{
|
||||||
|
blockNumber,
|
||||||
|
blockHash
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async getBlockByHash (blockHash?: string): Promise<any> {
|
async getBlockByHash (blockHash?: string): Promise<any> {
|
||||||
const { block } = await this._graphqlClient.query(ethQueries.getBlockByHash, { blockHash });
|
const { block } = await this._graphqlClient.query(ethQueries.getBlockByHash, { blockHash });
|
||||||
block.number = parseInt(block.number, 16);
|
block.number = parseInt(block.number, 16);
|
||||||
|
@ -82,6 +82,30 @@ query allEthHeaderCids($blockNumber: BigInt, $blockHash: String) {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const getFullBlocks = gql`
|
||||||
|
query allEthHeaderCids($blockNumber: BigInt, $blockHash: String) {
|
||||||
|
allEthHeaderCids(condition: { blockNumber: $blockNumber, blockHash: $blockHash }) {
|
||||||
|
nodes {
|
||||||
|
cid
|
||||||
|
blockNumber
|
||||||
|
blockHash
|
||||||
|
parentHash
|
||||||
|
timestamp
|
||||||
|
stateRoot
|
||||||
|
td
|
||||||
|
txRoot
|
||||||
|
receiptRoot
|
||||||
|
uncleRoot
|
||||||
|
bloom
|
||||||
|
blockByMhKey {
|
||||||
|
key
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export const getBlockByHash = gql`
|
export const getBlockByHash = gql`
|
||||||
query block($blockHash: Bytes32) {
|
query block($blockHash: Bytes32) {
|
||||||
block(hash: $blockHash) {
|
block(hash: $blockHash) {
|
||||||
@ -133,6 +157,7 @@ export default {
|
|||||||
getLogs,
|
getLogs,
|
||||||
getBlockWithTransactions,
|
getBlockWithTransactions,
|
||||||
getBlocks,
|
getBlocks,
|
||||||
|
getFullBlocks,
|
||||||
getBlockByHash,
|
getBlockByHash,
|
||||||
subscribeBlocks,
|
subscribeBlocks,
|
||||||
subscribeTransactions
|
subscribeTransactions
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"ethers": "^5.2.0",
|
"ethers": "^5.2.0",
|
||||||
"fs-extra": "^10.0.0",
|
"fs-extra": "^10.0.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
"multiformats": "^9.4.8",
|
||||||
"pg-boss": "^6.1.0",
|
"pg-boss": "^6.1.0",
|
||||||
"toml": "^3.0.0"
|
"toml": "^3.0.0"
|
||||||
},
|
},
|
||||||
@ -21,6 +22,7 @@
|
|||||||
"@vulcanize/cache": "^0.1.0",
|
"@vulcanize/cache": "^0.1.0",
|
||||||
"@vulcanize/ipld-eth-client": "^0.1.0",
|
"@vulcanize/ipld-eth-client": "^0.1.0",
|
||||||
"apollo-server-express": "^2.25.0",
|
"apollo-server-express": "^2.25.0",
|
||||||
|
"decimal.js": "^10.3.1",
|
||||||
"eslint": "^7.27.0",
|
"eslint": "^7.27.0",
|
||||||
"eslint-config-semistandard": "^15.0.1",
|
"eslint-config-semistandard": "^15.0.1",
|
||||||
"eslint-config-standard": "^16.0.3",
|
"eslint-config-standard": "^16.0.3",
|
||||||
|
61
packages/util/src/eth.ts
Normal file
61
packages/util/src/eth.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import debug from 'debug';
|
||||||
|
import { utils } from 'ethers';
|
||||||
|
|
||||||
|
const log = debug('vulcanize:eth');
|
||||||
|
|
||||||
|
function decodeInteger(value : string, defaultValue: BigInt): BigInt
|
||||||
|
function decodeInteger(value : string) : BigInt | undefined
|
||||||
|
function decodeInteger (value : string, defaultValue?: BigInt): BigInt | undefined {
|
||||||
|
if (value === undefined || value === null || value.length === 0) return defaultValue;
|
||||||
|
if (value === '0x') return BigInt(0);
|
||||||
|
return BigInt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeNumber(value : string, defaultValue: number): number
|
||||||
|
function decodeNumber(value : string) : number | undefined
|
||||||
|
function decodeNumber (value : string, defaultValue?: number): number | undefined {
|
||||||
|
if (value === undefined || value === null || value.length === 0) return defaultValue;
|
||||||
|
if (value === '0x') return 0;
|
||||||
|
return Number(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeHex (hex: string): any {
|
||||||
|
return Buffer.from(hex.slice(2), 'hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decodeHeader (rlp : Uint8Array): any {
|
||||||
|
try {
|
||||||
|
const data = utils.RLP.decode(rlp);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return {
|
||||||
|
Parent: decodeHex(data[0]),
|
||||||
|
UnclesDigest: decodeHex(data[1]),
|
||||||
|
Beneficiary: decodeHex(data[2]),
|
||||||
|
StateRoot: decodeHex(data[4]),
|
||||||
|
TxRoot: decodeHex(data[4]),
|
||||||
|
RctRoot: decodeHex(data[5]),
|
||||||
|
Bloom: decodeHex(data[6]),
|
||||||
|
Difficulty: decodeInteger(data[7], BigInt(0)),
|
||||||
|
Number: decodeInteger(data[8], BigInt(0)),
|
||||||
|
GasLimit: decodeInteger(data[9], BigInt(0)),
|
||||||
|
GasUsed: decodeInteger(data[10], BigInt(0)),
|
||||||
|
Time: decodeNumber(data[11]) || 0,
|
||||||
|
Extra: decodeHex(data[12]),
|
||||||
|
MixDigest: decodeHex(data[13]),
|
||||||
|
Nonce: decodeInteger(data[14], BigInt(0)),
|
||||||
|
BaseFee: decodeInteger(data[15])
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
log(error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
log(error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decodeData (hexLiteral: string): Uint8Array {
|
||||||
|
return Uint8Array.from(Buffer.from(hexLiteral.slice(2), 'hex'));
|
||||||
|
}
|
@ -9,10 +9,13 @@ import { hideBin } from 'yargs/helpers';
|
|||||||
import { utils, getDefaultProvider, providers } from 'ethers';
|
import { utils, getDefaultProvider, providers } from 'ethers';
|
||||||
import Decimal from 'decimal.js';
|
import Decimal from 'decimal.js';
|
||||||
|
|
||||||
|
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||||
|
|
||||||
import { DEFAULT_CONFIG_PATH } from './constants';
|
import { DEFAULT_CONFIG_PATH } from './constants';
|
||||||
import { Config } from './config';
|
import { Config } from './config';
|
||||||
import { JobQueue } from './job-queue';
|
import { JobQueue } from './job-queue';
|
||||||
import { GraphDecimal } from './graph-decimal';
|
import { GraphDecimal } from './graph-decimal';
|
||||||
|
import * as EthDecoder from './eth';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to wait for specified time.
|
* Method to wait for specified time.
|
||||||
@ -169,3 +172,38 @@ class CustomFormatter extends providers.Formatter {
|
|||||||
throw new Error('invalid blockTag');
|
throw new Error('invalid blockTag');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getFullBlock = async (ethClient: EthClient, blockHash: string): Promise<any> => {
|
||||||
|
const {
|
||||||
|
allEthHeaderCids: {
|
||||||
|
nodes: [
|
||||||
|
fullBlock
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} = await ethClient.getFullBlocks({ blockHash });
|
||||||
|
|
||||||
|
assert(fullBlock.blockByMhKey);
|
||||||
|
|
||||||
|
// Deecode the header data.
|
||||||
|
const header = EthDecoder.decodeHeader(EthDecoder.decodeData(fullBlock.blockByMhKey.data));
|
||||||
|
assert(header);
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// 1. Get author
|
||||||
|
// 2. Calculate size
|
||||||
|
return {
|
||||||
|
cid: fullBlock.cid,
|
||||||
|
blockNumber: fullBlock.blockNumber,
|
||||||
|
blockHash: fullBlock.blockHash,
|
||||||
|
parentHash: fullBlock.parentHash,
|
||||||
|
timestamp: fullBlock.timestamp,
|
||||||
|
stateRoot: fullBlock.stateRoot,
|
||||||
|
td: fullBlock.td,
|
||||||
|
txRoot: fullBlock.txRoot,
|
||||||
|
receiptRoot: fullBlock.receiptRoot,
|
||||||
|
uncleHash: fullBlock.uncleRoot,
|
||||||
|
difficulty: header.Difficulty.toString(),
|
||||||
|
gasLimit: header.GasLimit.toString(),
|
||||||
|
gasUsed: header.GasUsed.toString()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user