mirror of
https://github.com/cerc-io/watcher-ts
synced 2024-11-19 20:36:19 +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;
|
||||
txRoot: string;
|
||||
receiptRoot: string;
|
||||
uncleHash: string;
|
||||
difficulty: string;
|
||||
gasLimit: string;
|
||||
gasUsed: string;
|
||||
}
|
||||
|
||||
export interface EventData {
|
||||
@ -263,9 +267,19 @@ export const createBlock = async (instanceExports: any, blockData: Block): Promi
|
||||
const parentHashByteArray = await ByteArray.fromHexString(parentHashStringPtr);
|
||||
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 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 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 receiptsRoot = await Bytes.fromByteArray(receiptsRootByteArray);
|
||||
|
||||
const difficultyStringPtr = await __newString(blockData.difficulty);
|
||||
const difficulty = await BigInt.fromString(difficultyStringPtr);
|
||||
|
||||
const tdStringPtr = await __newString(blockData.td);
|
||||
const totalDifficulty = await BigInt.fromString(tdStringPtr);
|
||||
|
||||
const unclesHashPtr = await Bytes.empty();
|
||||
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:
|
||||
// unclesHash
|
||||
// author
|
||||
// gasUsed
|
||||
// gasLimit
|
||||
// difficulty
|
||||
// size
|
||||
return await ethereum.Block.__new(
|
||||
blockHash,
|
||||
parentHash,
|
||||
unclesHashPtr,
|
||||
uncleHash,
|
||||
authorPtr,
|
||||
stateRoot,
|
||||
transactionsRoot,
|
||||
receiptsRoot,
|
||||
blockNumber,
|
||||
gasUsedPtr,
|
||||
gasLimitPtr,
|
||||
gasUsed,
|
||||
gasLimit,
|
||||
blockTimestamp,
|
||||
difficultyPtr,
|
||||
difficulty,
|
||||
totalDifficulty,
|
||||
null
|
||||
);
|
||||
|
@ -11,7 +11,7 @@ import { ContractInterface, utils } from 'ethers';
|
||||
|
||||
import { ResultObject } from '@vulcanize/assemblyscript/lib/loader';
|
||||
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 { Context, instantiate } from './loader';
|
||||
@ -98,13 +98,8 @@ export class GraphWatcher {
|
||||
async handleEvent (eventData: any) {
|
||||
const { contract, event, eventSignature, block, tx, eventIndex } = eventData;
|
||||
|
||||
const {
|
||||
allEthHeaderCids: {
|
||||
nodes: [
|
||||
blockData
|
||||
]
|
||||
}
|
||||
} = await this._postgraphileClient.getBlocks({ blockHash: block.hash });
|
||||
// TODO: Use blockData fetched in handleBlock.
|
||||
const blockData = await getFullBlock(this._postgraphileClient, block.hash);
|
||||
|
||||
this._context.event.block = blockData;
|
||||
|
||||
@ -150,13 +145,7 @@ export class GraphWatcher {
|
||||
}
|
||||
|
||||
async handleBlock (blockHash: string) {
|
||||
const {
|
||||
allEthHeaderCids: {
|
||||
nodes: [
|
||||
blockData
|
||||
]
|
||||
}
|
||||
} = await this._postgraphileClient.getBlocks({ blockHash });
|
||||
const blockData = await getFullBlock(this._postgraphileClient, blockHash);
|
||||
|
||||
// Call block handler(s) for each contract.
|
||||
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> {
|
||||
const { block } = await this._graphqlClient.query(ethQueries.getBlockByHash, { blockHash });
|
||||
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`
|
||||
query block($blockHash: Bytes32) {
|
||||
block(hash: $blockHash) {
|
||||
@ -133,6 +157,7 @@ export default {
|
||||
getLogs,
|
||||
getBlockWithTransactions,
|
||||
getBlocks,
|
||||
getFullBlocks,
|
||||
getBlockByHash,
|
||||
subscribeBlocks,
|
||||
subscribeTransactions
|
||||
|
@ -10,6 +10,7 @@
|
||||
"ethers": "^5.2.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"multiformats": "^9.4.8",
|
||||
"pg-boss": "^6.1.0",
|
||||
"toml": "^3.0.0"
|
||||
},
|
||||
@ -21,6 +22,7 @@
|
||||
"@vulcanize/cache": "^0.1.0",
|
||||
"@vulcanize/ipld-eth-client": "^0.1.0",
|
||||
"apollo-server-express": "^2.25.0",
|
||||
"decimal.js": "^10.3.1",
|
||||
"eslint": "^7.27.0",
|
||||
"eslint-config-semistandard": "^15.0.1",
|
||||
"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 Decimal from 'decimal.js';
|
||||
|
||||
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||
|
||||
import { DEFAULT_CONFIG_PATH } from './constants';
|
||||
import { Config } from './config';
|
||||
import { JobQueue } from './job-queue';
|
||||
import { GraphDecimal } from './graph-decimal';
|
||||
import * as EthDecoder from './eth';
|
||||
|
||||
/**
|
||||
* Method to wait for specified time.
|
||||
@ -169,3 +172,38 @@ class CustomFormatter extends providers.Formatter {
|
||||
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