From 4d1137b1cd8ddb3bc4ecd4f8ca6756835efba68d Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Mon, 20 May 2024 16:05:13 +0400 Subject: [PATCH 01/21] add mode --- src/processors/index.ts | 3 +++ src/service/mainnet/index.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/processors/index.ts b/src/processors/index.ts index e8340b2..2bc81aa 100644 --- a/src/processors/index.ts +++ b/src/processors/index.ts @@ -91,6 +91,9 @@ export class Processors { case "full": modes.push(Mode.FULL); break; + case "reverse full": + modes.push(Mode.FULL); + break; default: throw new Error("No avaiable mode from mainnet smart contract API"); } diff --git a/src/service/mainnet/index.ts b/src/service/mainnet/index.ts index 500d7b2..91057a9 100644 --- a/src/service/mainnet/index.ts +++ b/src/service/mainnet/index.ts @@ -144,7 +144,7 @@ export class MainnetService { } } - async Mode(): Promise<"lite"| "full"> { + async Mode(): Promise<"lite"| "full"| "reverse full"> { try { return this.smartContractInstance.methods.MODE().call(); } catch (error) { From 859fe57e90d98fc19af0a55d9073b421ce842ba4 Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Mon, 3 Jun 2024 18:37:11 +0400 Subject: [PATCH 02/21] extend code to allow reverse relayer --- src/config.ts | 27 ++- src/processors/full.ts | 4 +- src/processors/lite.ts | 2 + src/processors/reverseFull.ts | 228 +++++++++++++++++ src/processors/reverseZero.ts | 83 +++++++ src/service/mainnet/extensions.ts | 62 ++++- src/service/mainnet/index.ts | 79 +++++- src/service/subnet/ABI/FullABI.json | 267 ++++++++++++++++++++ src/service/subnet/ABI/LiteABI.json | 364 ++++++++++++++++++++++++++++ src/service/subnet/extensions.ts | 22 +- src/service/subnet/index.ts | 76 +++++- 11 files changed, 1193 insertions(+), 21 deletions(-) create mode 100644 src/processors/reverseFull.ts create mode 100644 src/processors/reverseZero.ts create mode 100644 src/service/subnet/ABI/FullABI.json create mode 100644 src/service/subnet/ABI/LiteABI.json diff --git a/src/config.ts b/src/config.ts index c0697d0..15527a8 100644 --- a/src/config.ts +++ b/src/config.ts @@ -4,10 +4,14 @@ dotenv.config({ path: ".env" }); export interface SubnetConfig { url: string; fetchWaitingTime: number; + smartContractAddress: string; + accountPK: string; + submitTransactionWaitingTime: number; } export interface MainnetConfig { url: string; + fetchWaitingTime: number; smartContractAddress: string; accountPK: string; submitTransactionWaitingTime: number; @@ -24,6 +28,7 @@ export interface XdcZeroConfig { subnetZeroContractAddress?: string; parentChainZeroContractAddress?: string; walletPk?: string; + subnetWalletPk?: string; } export interface Config { @@ -43,18 +48,22 @@ export interface Config { relayerCsc: { isEnabled: boolean; } + reverseRelayerCsc:{ + isEnabled: boolean; + } } const environment = process.env.NODE_ENV || "production"; export const devMode = environment != "production"; const getZeroConfig = (): XdcZeroConfig => { - const isEnabled: boolean = "PARENTNET_ZERO_WALLET_PK" in process.env && "SUBNET_ZERO_CONTRACT" in process.env && "PARENTNET_ZERO_CONTRACT" in process.env; + const isEnabled: boolean = "PARENTNET_ZERO_WALLET_PK" in process.env && "SUBNET_ZERO_WALLET_PK" in process.env && "SUBNET_ZERO_CONTRACT" in process.env && "PARENTNET_ZERO_CONTRACT" in process.env; return isEnabled ? { isEnabled, subnetZeroContractAddress: process.env.SUBNET_ZERO_CONTRACT, parentChainZeroContractAddress: process.env.PARENTNET_ZERO_CONTRACT, - walletPk: process.env.PARENTNET_ZERO_WALLET_PK.startsWith("0x") ? process.env.PARENTNET_ZERO_WALLET_PK : `0x${process.env.PARENTNET_ZERO_WALLET_PK}` + walletPk: process.env.PARENTNET_ZERO_WALLET_PK.startsWith("0x") ? process.env.PARENTNET_ZERO_WALLET_PK : `0x${process.env.PARENTNET_ZERO_WALLET_PK}`, + subnetWalletPk: process.env.SUBNET_WALLET_PK.startsWith("0x") ? process.env.SUBNET_WALLET_PK : `0x${process.env.SUBNET_WALLET_PK}` }: { isEnabled: false }; }; @@ -67,22 +76,30 @@ const config: Config = { zeroJobExpression: "*/10 * * * * *", // every 10s }, subnet: { - url: process.env.SUBNET_URL || "https://devnetstats.apothem.network/subnet", + url: process.env.SUBNET_URL || "", + smartContractAddress: process.env.REVERSE_CHECKPOINT_CONTRACT || "", + accountPK: + process.env.SUBNET_WALLET_PK || + "0xa6538b992365dd26bbc2391ae6639bac0ed8599f8b45bca7c28c105959f02af0", // Default to a dummy key fetchWaitingTime: +process.env.SN_FETCHING_WAITING_TIME || 0, + submitTransactionWaitingTime: +process.env.MN_TX_SUBMIT_WAITING_TIME || 100, }, mainnet: { url: - process.env.PARENTNET_URL || - "https://devnetstats.apothem.network/mainnet", + process.env.PARENTNET_URL || "", smartContractAddress: process.env.CHECKPOINT_CONTRACT || "", accountPK: process.env.PARENTNET_WALLET_PK || "0xa6538b992365dd26bbc2391ae6639bac0ed8599f8b45bca7c28c105959f02af4", // Default to a dummy key + fetchWaitingTime: +process.env.SN_FETCHING_WAITING_TIME || 0, submitTransactionWaitingTime: +process.env.MN_TX_SUBMIT_WAITING_TIME || 100, }, relayerCsc: { isEnabled: "PARENTNET_WALLET_PK" in process.env && "CHECKPOINT_CONTRACT" in process.env && "PARENTNET_URL" in process.env }, + reverseRelayerCsc: { + isEnabled: "SUBNET_WALLET_PK" in process.env && "REVERSE_CHECKPOINT_CONTRACT" in process.env && "SUBNET_URL" in process.env + }, xdcZero: getZeroConfig(), reBootstrapWaitingTime: +process.env.BOOTSTRAP_FAILURE_WAIT_TIME || 120000, notification: { diff --git a/src/processors/full.ts b/src/processors/full.ts index b25b405..325ae0d 100644 --- a/src/processors/full.ts +++ b/src/processors/full.ts @@ -1,7 +1,7 @@ import bunyan from "bunyan"; import { config } from "../config"; import { MainnetService, SmartContractData } from "../service/mainnet"; -import { SubnetBlockInfo, SubnetService } from "../service/subnet"; +import { SubnetService, SubnetBlockInfo } from "../service/subnet"; import { chunkBy, sleep } from "../utils"; import { ForkingError } from "../errors/forkingError"; import { BaseProcessor } from "./base"; @@ -27,6 +27,8 @@ export class Full extends BaseProcessor { init() { this.logger.info("Initialising XDC relayer"); + //TODO: check CSC mode is correct at init + this.queue.process(async (_, done) => { this.logger.info("⏰ Executing normal flow periodically"); try { diff --git a/src/processors/lite.ts b/src/processors/lite.ts index 16b2c91..98f7a36 100644 --- a/src/processors/lite.ts +++ b/src/processors/lite.ts @@ -22,6 +22,8 @@ export class Lite extends BaseProcessor { init() { this.logger.info("Initialising XDC Lite relayer"); + //TODO: check CSC mode is correct at init + this.queue.process(async (_, done) => { this.logger.info("⏰ Executing lite flow periodically"); try { diff --git a/src/processors/reverseFull.ts b/src/processors/reverseFull.ts new file mode 100644 index 0000000..1d9bb44 --- /dev/null +++ b/src/processors/reverseFull.ts @@ -0,0 +1,228 @@ +import bunyan from "bunyan"; +import { config } from "../config"; +// import { MainnetService, SmartContractData } from "../service/mainnet"; +// import { SubnetBlockInfo, SubnetService } from "../service/subnet"; +import {SubnetService, SmartContractData } from "../service/subnet"; +import {MainnetService, MainnetBlockInfo} from "../service/mainnet"; +import { chunkBy, sleep } from "../utils"; +import { ForkingError } from "../errors/forkingError"; +import { BaseProcessor } from "./base"; + +const chunkByMaxFetchSize = chunkBy(config.chunkSize); +export const NAME = "REVERSE-FULL"; +const REPEAT_JOB_OPT = { jobId: NAME, repeat: { cron: config.cronJob.jobExpression}}; +export class ReverseFull extends BaseProcessor { + private mainnetService: MainnetService; + private subnetService: SubnetService; + logger: bunyan; + + constructor(logger: bunyan) { + super(NAME); + this.logger = logger; + this.mainnetService = new MainnetService(config.mainnet, logger); + this.subnetService = new SubnetService(config.subnet, logger); + } + + getQueue() { + return this.queue; + } + + init() { + this.logger.info("Initialising Reverse XDC relayer"); + //TODO: check CSC mode is correct at init + + this.queue.process(async (_, done) => { + this.logger.info("⏰ Executing normal flow periodically"); + try { + done(null, await this.processEvent()); + } catch (error) { + this.logger.error("Fail to process full reverse relayer job", { + message: error.message, + }); + // Report the error + done(error); + await this.reset(); + } + }); + return this; + } + + // Reset and start the state sync until success + async reset() { + await this.queue.add({}, REPEAT_JOB_OPT); + } + + async processEvent() { + // Pull latest confirmed tx from mainnet + const smartContractData = await this.subnetService.getLastAuditedBlock(); + // Pull latest confirmed block from subnet + const latestMainnetCommittedBlock = + await this.mainnetService.getLastCommittedBlockInfo(); + + const { shouldProcess, from, msg } = await this.shouldProcessSync( + smartContractData, + latestMainnetCommittedBlock + ); + + if (shouldProcess) { + await this.submitTxs( + from, + latestMainnetCommittedBlock.mainnetBlockNumber + ); + return `Completed sync from ${from} to ${latestMainnetCommittedBlock.mainnetBlockNumber}`; + } + return msg; + }; + + // "from" is exclusive, we submit blocks "from + 1" till "to" + private async submitTxs(from: number, to: number): Promise { + let startingBlockNumberToFetch = from + 1; + const blocksToFetchInChunks = chunkByMaxFetchSize(to - from); + this.logger.info( + `Start syncing with smart contract from block ${startingBlockNumberToFetch} to ${to}` + ); + for await (const numOfBlocks of blocksToFetchInChunks) { + const results = await this.subnetService.bulkGetRlpHeaders( + startingBlockNumberToFetch, + numOfBlocks + ); + await this.mainnetService.submitTxs(results); + startingBlockNumberToFetch += numOfBlocks; + } + this.logger.info("Sync completed!"); + return; + } + + + // This method does all the necessary verifications before submit blocks as transactions into mainnet XDC + private async shouldProcessSync( + smartContractData: SmartContractData, + lastestSubnetCommittedBlock: MainnetBlockInfo + ): Promise<{ shouldProcess: boolean; msg?: string, from?: number }> { + const { mainnetBlockHash, mainnetBlockNumber } = lastestSubnetCommittedBlock; + const { + smartContractHash, + smartContractHeight, + smartContractCommittedHash, + smartContractCommittedHeight, + } = smartContractData; + + if (mainnetBlockNumber < smartContractCommittedHeight) { + const subnetHashInSmartContract = + await this.mainnetService.getBlockHashByNumber(mainnetBlockNumber); + + if (subnetHashInSmartContract != mainnetBlockHash) { + this.logger.error( + "⛔️ WARNING: Forking detected when smart contract is ahead of subnet" + ); + throw new ForkingError( + mainnetBlockNumber, + subnetHashInSmartContract, + mainnetBlockHash + ); + } + const msg = "Smart contract is ahead of subnet, nothing needs to be done, just wait"; + return { shouldProcess: false, msg }; + } else if (mainnetBlockNumber == smartContractCommittedHeight) { + if (smartContractCommittedHash != mainnetBlockHash) { + this.logger.error( + "⛔️ WARNING: Forking detected when subnet and smart contract having the same height" + ); + throw new ForkingError( + smartContractCommittedHeight, + smartContractCommittedHash, + mainnetBlockHash + ); + } + return { shouldProcess: false, msg: "Smart contract committed and subnet are already in sync, nothing needs to be done, waiting for new blocks" }; + } else { + // Check the committed + const auditedCommittedBlockInfoInSubnet = + await this.subnetService.getCommittedBlockInfoByNum( + smartContractCommittedHeight + ); + if ( + auditedCommittedBlockInfoInSubnet.subnetBlockHash != + smartContractCommittedHash + ) { + this.logger.error( + "⛔️ WARNING: Forking detected when subnet is ahead of smart contract" + ); + throw new ForkingError( + smartContractCommittedHeight, + smartContractCommittedHash, + auditedCommittedBlockInfoInSubnet.subnetBlockHash + ); + } + // Verification for committed blocks are completed! We need to check where we shall start sync based on the last audited block (smartContractHash and height) in mainnet + if (smartContractHash == mainnetBlockHash) { + // Same block height and hash + return { shouldProcess: false, msg: "Smart contract latest and subnet are already in sync, nothing needs to be done, waiting for new blocks" }; + } else if (mainnetBlockNumber < smartContractHeight) { + // This is when subnet is behind the mainnet latest audited + const subnetHashInSmartContract = + await this.mainnetService.getBlockHashByNumber(mainnetBlockNumber); + if (subnetHashInSmartContract != mainnetBlockHash) { + // This only happens when there is a forking happened but not yet committed on mainnet, we will need to recursively submit subnet headers from diverging point + const { divergingHeight } = await this.findDivergingPoint( + mainnetBlockNumber + ); + return { + shouldProcess: true, + from: divergingHeight, + msg: `Forking happened but not yet committed on mainnet, we will need to recursively submit subnet headers from diverging point of ${divergingHeight}` + }; + } + return { + shouldProcess: false, + msg: "Subnet is behind mainnet latest audited blocks! This usually means there is another relayer on a different node who is ahead of this relayer in terms of mining and submitting txs. OR there gonna be forking soon!" + }; + } + // Below is the case where subnet is ahead of mainnet and we need to do some more checks before submit txs + const auditedBlockInfoInSubnet = + await this.subnetService.getCommittedBlockInfoByNum( + smartContractHeight + ); + if (auditedBlockInfoInSubnet.subnetBlockHash != smartContractHash) { + const { divergingHeight } = await this.findDivergingPoint( + smartContractHeight + ); + return { + shouldProcess: true, + from: divergingHeight + }; + } + // Everything seems normal, we will just submit txs from this point onwards. + return { + shouldProcess: true, + from: smartContractHeight, + }; + } + } + + // Find the point where after this "divering block", chain start to split (fork) + private async findDivergingPoint( + heightToSearchFrom: number + ): Promise<{ divergingHeight: number; divergingHash: string }> { + let currentHeight = heightToSearchFrom; + // let mainnetHash: string; + let subnetHash: string; + // let subnetBlockInfo: SubnetBlockInfo; + let mainnetBlockInfo: MainnetBlockInfo; + + while (currentHeight > 0) { + subnetHash = await this.subnetService.getBlockHashByNumber(currentHeight); + mainnetBlockInfo = await this.mainnetService.getCommittedBlockInfoByNum(currentHeight); + + if (subnetHash != mainnetBlockInfo.mainnetBlockHash) { + currentHeight--; + } else { + break; + } + } + return { + divergingHash: subnetHash, + divergingHeight: currentHeight + }; + } +} \ No newline at end of file diff --git a/src/processors/reverseZero.ts b/src/processors/reverseZero.ts new file mode 100644 index 0000000..3119c9c --- /dev/null +++ b/src/processors/reverseZero.ts @@ -0,0 +1,83 @@ +import bunyan from "bunyan"; +import { ZeroService } from "../service/zero"; +import { config } from "../config"; +import { BaseProcessor } from "./base"; + +export const NAME = "REVERSE-ZERO"; +const REPEAT_JOB_OPT = { + jobId: NAME, + repeat: { cron: config.cronJob.zeroJobExpression }, +}; + +export class ReverseZero extends BaseProcessor { + private logger: bunyan; + private zeroService: ZeroService; + + constructor(logger: bunyan) { + super(NAME); + this.logger = logger; + this.zeroService = new ZeroService(logger); + } + init() { + this.logger.info("Initialising Reverse XDC-Zero"); + this.zeroService.init(); + this.queue.process(async (_, done) => { + this.logger.info("⏰ Executing xdc-zero periodically"); + try { + done(null, await this.processEvent()); + } catch (error) { + this.logger.error("Fail to process reverse xdc-zero job", { + message: error.message, + }); + // Report the error + done(error); + await this.reset(); + } + }); + return this; + } + + async reset(): Promise { + await this.queue.add({}, REPEAT_JOB_OPT); + } + + async processEvent() { + const payloads = await this.zeroService.getPayloads(); + if (payloads.length == 0) { + const msg = "Nothing to process in xdc-zero, wait for the next event log"; + this.logger.info(msg); + return msg; + } + const lastPayload = payloads[payloads.length - 1]; + const lastIndexFromSubnet = lastPayload[0]; + + const lastIndexfromParentnet = + await this.zeroService.getIndexFromParentnet(); + + const lastBlockNumber = lastPayload[7]; + const cscBlockNumber = await this.zeroService.getLatestBlockNumberFromCsc(); + if (cscBlockNumber < lastBlockNumber) { + const msg = `Wait for csc block lastBlockNumber: ${lastBlockNumber}, cscBlockNumber: ${cscBlockNumber}`; + this.logger.info(msg); + return msg; + } + + if (lastIndexFromSubnet > lastIndexfromParentnet) { + for (let i = lastIndexfromParentnet; i < lastIndexFromSubnet; i++) { + if (payloads?.[i]?.[6]) { + const proof = await this.zeroService.getProof(payloads[i][6]); + await this.zeroService.validateTransactionProof( + proof.key, + proof.receiptProofValues, + proof.txProofValues, + proof.blockHash + ); + this.logger.info("sync zero index " + i + " success"); + } + } + } + const msg = `Completed the xdc-zero sync up till ${lastIndexFromSubnet} from subnet, wait for the next cycle`; + this.logger.info(msg); + return msg; + } +} diff --git a/src/service/mainnet/extensions.ts b/src/service/mainnet/extensions.ts index 4d4060b..2f95c8d 100644 --- a/src/service/mainnet/extensions.ts +++ b/src/service/mainnet/extensions.ts @@ -4,18 +4,74 @@ import { NetworkInformation } from "../types"; const MAINNET_EXTENSION_NAME = "xdcMainnet"; export interface Web3WithExtension extends Web3 { - xdcMainnet: { - getNetworkInformation: () => Promise + xdcMainnet:{ + getLatestCommittedBlockInfo: () => Promise + getV2Block: (number: string) => Promise + getV2BlockByNumber: (bluckNum: string) => Promise + getV2BlockByHash: (blockHash: string) => Promise + getNetworkInformation: () => Promise + getTransactionAndReceiptProof: (txHash: string) => Promise } } +export interface CommittedBlockInfo { + Hash: string; + Number: number; + Round: number; +} + +export interface FetchedV2BlockInfo { + Committed: boolean; + Hash: string; + ParentHash: string; + Number: number; + Round: number; + HexRLP: string; + Error: string; +} + +export interface TxReceiptProof { + blockHash: string; + key: string; + receiptProofKeys: string[]; + receiptProofValues: string[]; + receiptRoot: string; + txProofKeys: string; + txProofValues: string[]; + txRoot: string; +} + export const mainnetExtensions = { property: MAINNET_EXTENSION_NAME, methods: [ { name: "getNetworkInformation", + params: 0, call: "XDPoS_networkInformation" + }, + { + name: "getLatestCommittedBlockInfo", + call: "XDPoS_getLatestCommittedBlockHeader" + }, + { + name: "getV2Block", + params: 1, + call: "XDPoS_getV2BlockByNumber" + }, + { + name: "getV2BlockByNumber", + params: 1, + call: "XDPoS_getV2BlockByNumber" + }, + { + name: "getV2BlockByHash", + params: 1, + call: "XDPoS_getV2BlockByHash" + }, + { + name: "getTransactionAndReceiptProof", + params: 1, + call: "eth_getTransactionAndReceiptProof" } ] }; - diff --git a/src/service/mainnet/index.ts b/src/service/mainnet/index.ts index 91057a9..9915f90 100644 --- a/src/service/mainnet/index.ts +++ b/src/service/mainnet/index.ts @@ -11,6 +11,13 @@ import LiteABI from "./ABI/LiteABI.json"; import { Web3WithExtension, mainnetExtensions } from "./extensions"; import { NetworkInformation } from "../types"; +export interface MainnetBlockInfo { + mainnetBlockHash: string; + mainnetBlockNumber: number; + mainnetBlockRound: number; + hexRLP: string; + parentHash: string; +} export interface SmartContractData { smartContractHash: string; smartContractHeight: number; @@ -18,7 +25,7 @@ export interface SmartContractData { smartContractCommittedHash: string; } -const TRANSACTION_GAS_NUMBER = 12500000000; +const TRANSACTION_GAS_NUMBER = 12500000000; //TODO: check this is different now?, is there better way to handle? export class MainnetService { private web3: Web3WithExtension; @@ -144,6 +151,67 @@ export class MainnetService { } } + async getCommittedBlockInfoByNum(blockNum: number): Promise { + try { + const { Hash, Number, Round, HexRLP, ParentHash } = + await this.web3.xdcMainnet.getV2Block(`0x${blockNum.toString(16)}`); + if (!Hash || !Number || !HexRLP || !ParentHash) { + this.logger.error( + "Invalid block hash or height or encodedRlp or ParentHash received", + Hash, + Number, + HexRLP, + ParentHash + ); + throw new Error("Unable to get committed block information by height"); + } + return { + mainnetBlockHash: Hash, + mainnetBlockNumber: Number, + mainnetBlockRound: Round, + hexRLP: HexRLP, + parentHash: ParentHash, + }; + } catch (error) { + this.logger.error( + "Error while trying to fetch blockInfo by number from subnet blockNum:", + blockNum, + { message: error.message } + ); + throw error; + } + } + + async getLastCommittedBlockInfo(): Promise { + try { + const { Hash, Number, Round, HexRLP, ParentHash } = + await this.web3.xdcMainnet.getV2Block("committed"); + if (!Hash || !Number || !HexRLP || !ParentHash) { + this.logger.error( + "Invalid block hash or height or encodedRlp or ParentHash received", + Hash, + Number, + HexRLP, + ParentHash + ); + throw new Error("Unable to get latest committed block information"); + } + return { + mainnetBlockHash: Hash, + mainnetBlockNumber: Number, + mainnetBlockRound: Round, + hexRLP: HexRLP, + parentHash: ParentHash, + }; + } catch (error) { + this.logger.error( + "Error getLastCommittedBlockInfo while trying to fetch blockInfo by number from subnet", + { message: error.message } + ); + throw error; + } + } + async Mode(): Promise<"lite"| "full"| "reverse full"> { try { return this.smartContractInstance.methods.MODE().call(); @@ -347,4 +415,13 @@ export class LiteMainnetService { throw error; } } + async Mode(): Promise<"lite"| "full"| "reverse full"> { + try { + return this.liteSmartContractInstance.methods.MODE().call(); + } catch (error) { + this.logger.error("Fail to get mode from mainnet smart contract"); + throw error; + } + } + } diff --git a/src/service/subnet/ABI/FullABI.json b/src/service/subnet/ABI/FullABI.json new file mode 100644 index 0000000..3330338 --- /dev/null +++ b/src/service/subnet/ABI/FullABI.json @@ -0,0 +1,267 @@ +[ + { + "inputs": [ + { + "internalType": "address[]", + "name": "initialValidatorSet", + "type": "address[]" + }, + { + "internalType": "bytes", + "name": "genesisHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "block1Header", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "initGap", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "initEpoch", + "type": "uint64" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "int256", + "name": "number", + "type": "int256" + } + ], + "name": "SubnetBlockAccepted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "int256", + "name": "number", + "type": "int256" + } + ], + "name": "SubnetBlockFinalized", + "type": "event" + }, + { + "inputs": [], + "name": "INIT_EPOCH", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "INIT_GAP", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MODE", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCurrentValidators", + "outputs": [ + { + "components": [ + { + "internalType": "address[]", + "name": "set", + "type": "address[]" + }, + { + "internalType": "int256", + "name": "threshold", + "type": "int256" + } + ], + "internalType": "struct FullCheckpoint.Validators", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + } + ], + "name": "getHeader", + "outputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "parentHash", + "type": "bytes32" + }, + { + "internalType": "int256", + "name": "number", + "type": "int256" + }, + { + "internalType": "uint64", + "name": "roundNum", + "type": "uint64" + }, + { + "internalType": "int256", + "name": "mainnetNum", + "type": "int256" + }, + { + "internalType": "bool", + "name": "finalized", + "type": "bool" + } + ], + "internalType": "struct FullCheckpoint.HeaderInfo", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int256", + "name": "number", + "type": "int256" + } + ], + "name": "getHeaderByNumber", + "outputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + }, + { + "internalType": "int256", + "name": "number", + "type": "int256" + } + ], + "internalType": "struct FullCheckpoint.BlockLite", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getLatestBlocks", + "outputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + }, + { + "internalType": "int256", + "name": "number", + "type": "int256" + } + ], + "internalType": "struct FullCheckpoint.BlockLite", + "name": "", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + }, + { + "internalType": "int256", + "name": "number", + "type": "int256" + } + ], + "internalType": "struct FullCheckpoint.BlockLite", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "headers", + "type": "bytes[]" + } + ], + "name": "receiveHeader", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/src/service/subnet/ABI/LiteABI.json b/src/service/subnet/ABI/LiteABI.json new file mode 100644 index 0000000..2490496 --- /dev/null +++ b/src/service/subnet/ABI/LiteABI.json @@ -0,0 +1,364 @@ +[ + { + "inputs": [ + { + "internalType": "address[]", + "name": "initialValidatorSet", + "type": "address[]" + }, + { + "internalType": "bytes", + "name": "block1", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "initGap", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "initEpoch", + "type": "uint64" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "number", + "type": "uint64" + } + ], + "name": "SubnetEpochBlockAccepted", + "type": "event" + }, + { + "inputs": [], + "name": "INIT_EPOCH", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "INIT_GAP", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MODE", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "epochHash", + "type": "bytes32" + }, + { + "internalType": "bytes[]", + "name": "headers", + "type": "bytes[]" + } + ], + "name": "commitHeader", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "headers", + "type": "bytes[]" + } + ], + "name": "commitHeaderByNumber", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "epochNum", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "idx", + "type": "uint256" + } + ], + "name": "getCurrentEpochBlockByIndex", + "outputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "number", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "roundNum", + "type": "uint64" + }, + { + "internalType": "int64", + "name": "mainnetNum", + "type": "int64" + } + ], + "internalType": "struct LiteCheckpoint.HeaderInfo", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCurrentValidators", + "outputs": [ + { + "components": [ + { + "internalType": "address[]", + "name": "set", + "type": "address[]" + }, + { + "internalType": "int256", + "name": "threshold", + "type": "int256" + } + ], + "internalType": "struct LiteCheckpoint.Validators", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + } + ], + "name": "getHeader", + "outputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "number", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "roundNum", + "type": "uint64" + }, + { + "internalType": "int64", + "name": "mainnetNum", + "type": "int64" + } + ], + "internalType": "struct LiteCheckpoint.HeaderInfo", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + } + ], + "name": "getHeaderByNumber", + "outputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "number", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "roundNum", + "type": "uint64" + }, + { + "internalType": "int64", + "name": "mainnetNum", + "type": "int64" + } + ], + "internalType": "struct LiteCheckpoint.HeaderInfo", + "name": "", + "type": "tuple" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getLatestBlocks", + "outputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "number", + "type": "uint64" + } + ], + "internalType": "struct LiteCheckpoint.BlockLite", + "name": "", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "number", + "type": "uint64" + } + ], + "internalType": "struct LiteCheckpoint.BlockLite", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + } + ], + "name": "getUnCommittedHeader", + "outputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "sequence", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "lastRoundNum", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "lastNum", + "type": "uint64" + } + ], + "internalType": "struct LiteCheckpoint.UnCommittedHeaderInfo", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "headers", + "type": "bytes[]" + } + ], + "name": "receiveHeader", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/src/service/subnet/extensions.ts b/src/service/subnet/extensions.ts index 3023632..e1049f0 100644 --- a/src/service/subnet/extensions.ts +++ b/src/service/subnet/extensions.ts @@ -3,6 +3,17 @@ import { NetworkInformation } from "../types"; const SUBNET_EXTENSION_NAME = "xdcSubnet"; +export interface Web3WithExtension extends Web3 { + xdcSubnet: { + getLatestCommittedBlockInfo: () => Promise + getV2Block: (number: string) => Promise + getV2BlockByNumber: (bluckNum: string) => Promise + getV2BlockByHash: (blockHash: string) => Promise + getNetworkInformation: () => Promise + getTransactionAndReceiptProof: (txHash: string) => Promise + } +} + export interface CommittedBlockInfo { Hash: string; Number: number; @@ -30,16 +41,7 @@ export interface TxReceiptProof { txRoot: string; } -export interface Web3WithExtension extends Web3 { - xdcSubnet: { - getLatestCommittedBlockInfo: () => Promise - getV2Block: (number: string) => Promise - getV2BlockByNumber: (bluckNum: string) => Promise - getV2BlockByHash: (blockHash: string) => Promise - getNetworkInformation: () => Promise - getTransactionAndReceiptProof: (txHash: string) => Promise - } -} + export const subnetExtensions = { property: SUBNET_EXTENSION_NAME, diff --git a/src/service/subnet/index.ts b/src/service/subnet/index.ts index a03e4bc..88b03a6 100644 --- a/src/service/subnet/index.ts +++ b/src/service/subnet/index.ts @@ -5,6 +5,9 @@ import { SubnetConfig } from "../../config"; import { sleep } from "../../utils/index"; import { subnetExtensions, Web3WithExtension } from "./extensions"; import { NetworkInformation } from "../types"; +import { Contract } from "web3-eth-contract"; +import { AbiItem } from "web3-utils"; +import { Account } from "web3-core"; export interface SubnetBlockInfo { subnetBlockHash: string; @@ -14,9 +17,18 @@ export interface SubnetBlockInfo { parentHash: string; } +export interface SmartContractData { + smartContractHash: string; + smartContractHeight: number; + smartContractCommittedHeight: number; + smartContractCommittedHash: string; +} + export class SubnetService { protected web3: Web3WithExtension; - protected subnetConfig: SubnetConfig; + private smartContractInstance: Contract; + private subnetAccount: Account; + private subnetConfig: SubnetConfig; logger: bunyan; constructor(config: SubnetConfig, logger: bunyan) { @@ -159,4 +171,66 @@ export class SubnetService { } return rlpHeaders; } + + // Below shall be given height provide the SM hash + async getBlockHashByNumber(height: number): Promise { + try { + const result = await this.smartContractInstance.methods + .getHeaderByNumber(height) + .call(); + return result[0]; + } catch (error) { + this.logger.error("Fail to get block hash by number from mainnet", { + height, + message: error.message, + }); + throw error; + } + } + + async getLastAuditedBlock(): Promise { + try { + const result = await this.smartContractInstance.methods + .getLatestBlocks() + .call(); + const [latestBlockHash, latestBlockHeight] = result[0]; + const [latestSmComittedHash, latestSmHeight] = result[1]; + if ( + !latestBlockHash || + !latestBlockHeight || + !latestSmComittedHash || + !latestSmHeight + ) { + this.logger.error( + "Invalid block hash or height received", + latestBlockHash, + latestBlockHeight, + latestSmComittedHash, + latestSmHeight + ); + throw new Error("Unable to get last audited block informations"); + } + return { + smartContractHash: latestBlockHash, + smartContractHeight: parseInt(latestBlockHeight), + smartContractCommittedHash: latestSmComittedHash, + smartContractCommittedHeight: parseInt(latestSmHeight), + }; + } catch (error) { + this.logger.error( + "Error while trying to fetch the last audited subnet's block in XDC mainnet", + { message: error.message } + ); + throw error; + } + } + + async Mode(): Promise<"lite"| "full"| "reverse full"> { + try { + return this.smartContractInstance.methods.MODE().call(); + } catch (error) { + this.logger.error("Fail to get mode from mainnet smart contract"); + throw error; + } + } } From c499c34d66bcb58f743622c3816bd64c8075f51c Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Wed, 5 Jun 2024 14:26:24 +0400 Subject: [PATCH 03/21] switch subnet <> mainnet for reverse csc --- src/processors/index.ts | 35 ++++++++-- src/processors/lite.ts | 2 +- src/processors/reverseFull.ts | 43 ++++++------ src/service/mainnet/extensions.ts | 2 +- src/service/mainnet/index.ts | 80 ++++++++++++++++------ src/service/subnet/extensions.ts | 2 +- src/service/subnet/index.ts | 107 ++++++++++++++++++++++++------ 7 files changed, 203 insertions(+), 68 deletions(-) diff --git a/src/processors/index.ts b/src/processors/index.ts index 2bc81aa..401c9d1 100644 --- a/src/processors/index.ts +++ b/src/processors/index.ts @@ -4,16 +4,21 @@ import { createBullBoard } from '@bull-board/api'; import { BullAdapter } from '@bull-board/api/bullAdapter'; import { ExpressAdapter } from '@bull-board/express'; -import { Zero, NAME as zeroName } from "./zero"; import { config } from "./../config"; import { Lite, NAME as liteName } from "./lite"; import { Full, NAME as fullName } from "./full"; +import { ReverseFull, NAME as ReverseFullName } from "./reverseFull"; +import { Zero, NAME as zeroName } from "./zero"; +import { ReverseZero, NAME as ReverseZeroName } from "./reverseZero"; import { MainnetService } from "../service/mainnet"; +import { SubnetService } from "../service/subnet"; enum Mode { LITE = liteName, FULL = fullName, - ZERO = zeroName + REVERSE_FULL = ReverseFullName, + ZERO = zeroName, + REVERSE_ZERO = ReverseZeroName } export class Processors { @@ -21,19 +26,25 @@ export class Processors { private processors: { lite: Lite; full: Full; + reverseFull: ReverseFull; zero: Zero; + reverseZero: ReverseZero; } private mainnetService: MainnetService; + private subnetService: SubnetService; constructor(logger: bunyan) { this.logger = logger; this.processors = { lite: new Lite(logger), full: new Full(logger), - zero: new Zero(logger) + reverseFull: new ReverseFull(logger), + zero: new Zero(logger), + reverseZero: new ReverseZero(logger), // Register more processors here }; this.mainnetService = new MainnetService(config.mainnet, logger); + this.subnetService = new SubnetService(config.subnet, logger); } // Register the event process. NOTE: this won't actually start the job processing until you call the reset @@ -71,9 +82,15 @@ export class Processors { case Mode.FULL: await this.processors.full.reset(); break; + case Mode.REVERSE_FULL: + await this.processors.reverseFull.reset(); + break; case Mode.ZERO: await this.processors.zero.reset(); break; + case Mode.REVERSE_ZERO: + await this.processors.reverseZero.reset(); + break; default: throw new Error("No avaiable modes to choose from"); } @@ -91,16 +108,24 @@ export class Processors { case "full": modes.push(Mode.FULL); break; + default: + throw new Error("No avaiable mode from PARENTNET smart contract API"); + } + } + if (config.reverseRelayerCsc.isEnabled){ + const subnetSmartContractMode = await this.subnetService.Mode(); + switch (subnetSmartContractMode) { case "reverse full": - modes.push(Mode.FULL); + modes.push(Mode.REVERSE_FULL); break; default: - throw new Error("No avaiable mode from mainnet smart contract API"); + throw new Error("No available mode from SUBNET smart contract API"); } } if (config.xdcZero.isEnabled) { modes.push(Mode.ZERO); + modes.push(Mode.REVERSE_ZERO); } this.logger.info("Running modes: ", modes); diff --git a/src/processors/lite.ts b/src/processors/lite.ts index 98f7a36..cea03dd 100644 --- a/src/processors/lite.ts +++ b/src/processors/lite.ts @@ -17,7 +17,7 @@ export class Lite extends BaseProcessor { super(NAME); this.logger = logger; this.liteMainnetService = new LiteMainnetService(config.mainnet, logger); - this.subnetService = new SubnetService(config.subnet, logger); + // this.subnetService = new SubnetService(config.subnet, logger); } init() { diff --git a/src/processors/reverseFull.ts b/src/processors/reverseFull.ts index 1d9bb44..cba79f3 100644 --- a/src/processors/reverseFull.ts +++ b/src/processors/reverseFull.ts @@ -53,11 +53,15 @@ export class ReverseFull extends BaseProcessor { } async processEvent() { - // Pull latest confirmed tx from mainnet + // Pull latest confirmed tx from subnet const smartContractData = await this.subnetService.getLastAuditedBlock(); - // Pull latest confirmed block from subnet + this.logger.error("gram sm data from subnet"); + this.logger.error(smartContractData); + // Pull latest confirmed block from mainnet const latestMainnetCommittedBlock = await this.mainnetService.getLastCommittedBlockInfo(); + this.logger.error("grab mainnet committed block"); + this.logger.error(latestMainnetCommittedBlock.mainnetBlockNumber); const { shouldProcess, from, msg } = await this.shouldProcessSync( smartContractData, @@ -82,11 +86,11 @@ export class ReverseFull extends BaseProcessor { `Start syncing with smart contract from block ${startingBlockNumberToFetch} to ${to}` ); for await (const numOfBlocks of blocksToFetchInChunks) { - const results = await this.subnetService.bulkGetRlpHeaders( + const results = await this.mainnetService.bulkGetRlpHeaders( startingBlockNumberToFetch, numOfBlocks ); - await this.mainnetService.submitTxs(results); + await this.subnetService.submitTxs(results); startingBlockNumberToFetch += numOfBlocks; } this.logger.info("Sync completed!"); @@ -97,9 +101,9 @@ export class ReverseFull extends BaseProcessor { // This method does all the necessary verifications before submit blocks as transactions into mainnet XDC private async shouldProcessSync( smartContractData: SmartContractData, - lastestSubnetCommittedBlock: MainnetBlockInfo + latestMainnetCommittedBlock: MainnetBlockInfo ): Promise<{ shouldProcess: boolean; msg?: string, from?: number }> { - const { mainnetBlockHash, mainnetBlockNumber } = lastestSubnetCommittedBlock; + const { mainnetBlockHash, mainnetBlockNumber } = latestMainnetCommittedBlock; const { smartContractHash, smartContractHeight, @@ -108,16 +112,16 @@ export class ReverseFull extends BaseProcessor { } = smartContractData; if (mainnetBlockNumber < smartContractCommittedHeight) { - const subnetHashInSmartContract = + const mainnetHashInSmartContract = await this.mainnetService.getBlockHashByNumber(mainnetBlockNumber); - if (subnetHashInSmartContract != mainnetBlockHash) { + if (mainnetHashInSmartContract != mainnetBlockHash) { this.logger.error( "⛔️ WARNING: Forking detected when smart contract is ahead of subnet" ); throw new ForkingError( mainnetBlockNumber, - subnetHashInSmartContract, + mainnetHashInSmartContract, mainnetBlockHash ); } @@ -137,12 +141,12 @@ export class ReverseFull extends BaseProcessor { return { shouldProcess: false, msg: "Smart contract committed and subnet are already in sync, nothing needs to be done, waiting for new blocks" }; } else { // Check the committed - const auditedCommittedBlockInfoInSubnet = - await this.subnetService.getCommittedBlockInfoByNum( + const auditedCommittedBlockInfoInMainnet = + await this.mainnetService.getCommittedBlockInfoByNum( smartContractCommittedHeight ); if ( - auditedCommittedBlockInfoInSubnet.subnetBlockHash != + auditedCommittedBlockInfoInMainnet.mainnetBlockHash != smartContractCommittedHash ) { this.logger.error( @@ -151,19 +155,16 @@ export class ReverseFull extends BaseProcessor { throw new ForkingError( smartContractCommittedHeight, smartContractCommittedHash, - auditedCommittedBlockInfoInSubnet.subnetBlockHash + auditedCommittedBlockInfoInMainnet.mainnetBlockHash ); } - // Verification for committed blocks are completed! We need to check where we shall start sync based on the last audited block (smartContractHash and height) in mainnet if (smartContractHash == mainnetBlockHash) { // Same block height and hash return { shouldProcess: false, msg: "Smart contract latest and subnet are already in sync, nothing needs to be done, waiting for new blocks" }; } else if (mainnetBlockNumber < smartContractHeight) { - // This is when subnet is behind the mainnet latest audited - const subnetHashInSmartContract = + const mainnetHashInSmartContract = await this.mainnetService.getBlockHashByNumber(mainnetBlockNumber); - if (subnetHashInSmartContract != mainnetBlockHash) { - // This only happens when there is a forking happened but not yet committed on mainnet, we will need to recursively submit subnet headers from diverging point + if ( mainnetHashInSmartContract != mainnetBlockHash) { const { divergingHeight } = await this.findDivergingPoint( mainnetBlockNumber ); @@ -179,11 +180,11 @@ export class ReverseFull extends BaseProcessor { }; } // Below is the case where subnet is ahead of mainnet and we need to do some more checks before submit txs - const auditedBlockInfoInSubnet = - await this.subnetService.getCommittedBlockInfoByNum( + const auditedBlockInfoInMainnet = + await this.mainnetService.getCommittedBlockInfoByNum( smartContractHeight ); - if (auditedBlockInfoInSubnet.subnetBlockHash != smartContractHash) { + if (auditedBlockInfoInMainnet.mainnetBlockHash != smartContractHash) { const { divergingHeight } = await this.findDivergingPoint( smartContractHeight ); diff --git a/src/service/mainnet/extensions.ts b/src/service/mainnet/extensions.ts index 2f95c8d..17cb43c 100644 --- a/src/service/mainnet/extensions.ts +++ b/src/service/mainnet/extensions.ts @@ -26,7 +26,7 @@ export interface FetchedV2BlockInfo { ParentHash: string; Number: number; Round: number; - HexRLP: string; + EncodedRLP: string; Error: string; } diff --git a/src/service/mainnet/index.ts b/src/service/mainnet/index.ts index 9915f90..a6c2838 100644 --- a/src/service/mainnet/index.ts +++ b/src/service/mainnet/index.ts @@ -1,8 +1,8 @@ import Web3 from "web3"; import { Contract } from "web3-eth-contract"; import { AbiItem } from "web3-utils"; -import { HttpsAgent } from "agentkeepalive"; import { Account } from "web3-core"; +import { HttpsAgent } from "agentkeepalive"; import bunyan from "bunyan"; import { MainnetConfig } from "../../config"; import { sleep } from "../../utils/index"; @@ -11,6 +11,8 @@ import LiteABI from "./ABI/LiteABI.json"; import { Web3WithExtension, mainnetExtensions } from "./extensions"; import { NetworkInformation } from "../types"; +const TRANSACTION_GAS_NUMBER = 12500000000; //TODO: check this is different now?, is there better way to handle? + export interface MainnetBlockInfo { mainnetBlockHash: string; mainnetBlockNumber: number; @@ -25,7 +27,6 @@ export interface SmartContractData { smartContractCommittedHash: string; } -const TRANSACTION_GAS_NUMBER = 12500000000; //TODO: check this is different now?, is there better way to handle? export class MainnetService { private web3: Web3WithExtension; @@ -79,7 +80,7 @@ export class MainnetService { latestSmComittedHash, latestSmHeight ); - throw new Error("Unable to get last audited block informations"); + throw new Error("Unable to get last audited block informations from PARENTNET"); } return { smartContractHash: latestBlockHash, @@ -89,7 +90,7 @@ export class MainnetService { }; } catch (error) { this.logger.error( - "Error while trying to fetch the last audited subnet's block in XDC mainnet", + "Error while trying to fetch the last audited subnet's block in XDC PARENTNET", { message: error.message } ); throw error; @@ -104,7 +105,7 @@ export class MainnetService { this.logger.info( `Submit the subnet block up to ${ results[results.length - 1].blockNum - } as tx into mainnet` + } as tx into PARENTNET` ); //const encodedHexArray = results.map(r => "0x" + Buffer.from(r.encodedRLP, "base64").toString("hex")); //old method for reference const hexArray = results.map((r) => "0x" + r.hexRLP); @@ -128,7 +129,7 @@ export class MainnetService { await sleep(this.mainnetConfig.submitTransactionWaitingTime); } catch (error) { - this.logger.error("Fail to submit transactions into mainnet", { + this.logger.error("Fail to submit transactions into PARENTNET", { message: error.message, }); throw error; @@ -143,7 +144,7 @@ export class MainnetService { .call(); return result[0]; } catch (error) { - this.logger.error("Fail to get block hash by number from mainnet", { + this.logger.error("Fail to get block hash by number from PARENTNET", { height, message: error.message, }); @@ -153,8 +154,9 @@ export class MainnetService { async getCommittedBlockInfoByNum(blockNum: number): Promise { try { - const { Hash, Number, Round, HexRLP, ParentHash } = + const { Hash, Number, Round, EncodedRLP, ParentHash } = await this.web3.xdcMainnet.getV2Block(`0x${blockNum.toString(16)}`); + const HexRLP = EncodedRLP; if (!Hash || !Number || !HexRLP || !ParentHash) { this.logger.error( "Invalid block hash or height or encodedRlp or ParentHash received", @@ -163,7 +165,7 @@ export class MainnetService { HexRLP, ParentHash ); - throw new Error("Unable to get committed block information by height"); + throw new Error("Unable to get committed block information by height from PARENTNET"); } return { mainnetBlockHash: Hash, @@ -174,7 +176,7 @@ export class MainnetService { }; } catch (error) { this.logger.error( - "Error while trying to fetch blockInfo by number from subnet blockNum:", + "Error while trying to fetch blockInfo by number from PARENTNET blockNum:", blockNum, { message: error.message } ); @@ -184,8 +186,9 @@ export class MainnetService { async getLastCommittedBlockInfo(): Promise { try { - const { Hash, Number, Round, HexRLP, ParentHash } = + const { Hash, Number, Round, EncodedRLP, ParentHash } = await this.web3.xdcMainnet.getV2Block("committed"); + const HexRLP = EncodedRLP; if (!Hash || !Number || !HexRLP || !ParentHash) { this.logger.error( "Invalid block hash or height or encodedRlp or ParentHash received", @@ -194,7 +197,7 @@ export class MainnetService { HexRLP, ParentHash ); - throw new Error("Unable to get latest committed block information"); + throw new Error("Unable to get latest committed block information from PARENTNET"); } return { mainnetBlockHash: Hash, @@ -205,18 +208,41 @@ export class MainnetService { }; } catch (error) { this.logger.error( - "Error getLastCommittedBlockInfo while trying to fetch blockInfo by number from subnet", + "Error getLastCommittedBlockInfo while trying to fetch blockInfo by number from PARENTNET", { message: error.message } ); throw error; } } + async bulkGetRlpHeaders( + startingBlockNumber: number, + numberOfBlocksToFetch: number + ): Promise> { + this.logger.info( + "Fetch subnet node data from " + + startingBlockNumber + + " to " + + (startingBlockNumber + numberOfBlocksToFetch - 1) + ); + const rlpHeaders: Array<{ hexRLP: string; blockNum: number }> = []; + for ( + let i = startingBlockNumber; + i < startingBlockNumber + numberOfBlocksToFetch; + i++ + ) { + const { hexRLP } = await this.getCommittedBlockInfoByNum(i); + rlpHeaders.push({ hexRLP, blockNum: i }); + await sleep(this.mainnetConfig.fetchWaitingTime); + } + return rlpHeaders; + } + async Mode(): Promise<"lite"| "full"| "reverse full"> { try { return this.smartContractInstance.methods.MODE().call(); } catch (error) { - this.logger.error("Fail to get mode from mainnet smart contract"); + this.logger.error("Fail to get mode from PARENTNET smart contract"); throw error; } } @@ -270,7 +296,7 @@ export class LiteMainnetService { latestSmComittedHash, latestSmHeight ); - throw new Error("Unable to get last audited block informations"); + throw new Error("Unable to get last audited block informations from PARENTNET"); } return { smartContractHash: latestBlockHash, @@ -280,7 +306,7 @@ export class LiteMainnetService { }; } catch (error) { this.logger.error( - "Error while trying to fetch the last audited subnet's block in XDC mainnet", + "Error while trying to fetch the last audited subnet's block in XDC PARENTNET", { message: error.message } ); throw error; @@ -297,7 +323,7 @@ export class LiteMainnetService { results[0].blockNum } and commit block up to ${ results[results.length - 1].blockNum - } as tx into mainnet` + } as tx into PARENTNET` ); //const encodedHexArray = results.map(r => "0x" + Buffer.from(r.encodedRLP, "base64").toString("hex")); //old method for reference @@ -323,7 +349,7 @@ export class LiteMainnetService { await sleep(this.mainnetConfig.submitTransactionWaitingTime); } catch (error) { - this.logger.error("Fail to submit transactions into mainnet", { + this.logger.error("Fail to submit transactions into PARENTNET", { message: error.message, }); throw error; @@ -338,7 +364,7 @@ export class LiteMainnetService { .call(); return result[0]; } catch (error) { - this.logger.error("Fail to get block hash by number from mainnet", { + this.logger.error("Fail to get block hash by number from PARENTNET", { height, message: error.message, }); @@ -357,7 +383,7 @@ export class LiteMainnetService { .call(); return { gap, epoch }; } catch (error) { - this.logger.error("Fail to getGapAndEpoch from mainnet", { + this.logger.error("Fail to getGapAndEpoch from PARENTNET", { message: error.message, }); throw error; @@ -425,3 +451,17 @@ export class LiteMainnetService { } } + +function base64ToHex(base64String: string) { + // Step 1: Decode base64 string to binary data + const binaryString = atob(base64String); + + // Step 2: Convert binary data to hex + let hexString = ""; + for (let i = 0; i < binaryString.length; i++) { + const hex = binaryString.charCodeAt(i).toString(16); + hexString += hex.length === 2 ? hex : "0" + hex; + } + + return hexString; +} \ No newline at end of file diff --git a/src/service/subnet/extensions.ts b/src/service/subnet/extensions.ts index e1049f0..5133edc 100644 --- a/src/service/subnet/extensions.ts +++ b/src/service/subnet/extensions.ts @@ -26,7 +26,7 @@ export interface FetchedV2BlockInfo { ParentHash: string; Number: number; Round: number; - HexRLP: string; + EncodedRLP: string; Error: string; } diff --git a/src/service/subnet/index.ts b/src/service/subnet/index.ts index 88b03a6..0c94d3d 100644 --- a/src/service/subnet/index.ts +++ b/src/service/subnet/index.ts @@ -1,13 +1,16 @@ import Web3 from "web3"; +import { Contract } from "web3-eth-contract"; +import { AbiItem } from "web3-utils"; +import { Account } from "web3-core"; import { HttpsAgent } from "agentkeepalive"; import bunyan from "bunyan"; import { SubnetConfig } from "../../config"; import { sleep } from "../../utils/index"; import { subnetExtensions, Web3WithExtension } from "./extensions"; import { NetworkInformation } from "../types"; -import { Contract } from "web3-eth-contract"; -import { AbiItem } from "web3-utils"; -import { Account } from "web3-core"; +import FullABI from "./ABI/FullABI.json"; + +const TRANSACTION_GAS_NUMBER = 12500000000; //TODO: check this is different now?, is there better way to handle? export interface SubnetBlockInfo { subnetBlockHash: string; @@ -38,9 +41,15 @@ export class SubnetService { keepAlive: true, agent: { https: keepaliveAgent }, }); - - this.subnetConfig = config; this.web3 = new Web3(provider).extend(subnetExtensions); + this.smartContractInstance = new this.web3.eth.Contract( + FullABI as AbiItem[], + config.smartContractAddress + ); + this.subnetAccount = this.web3.eth.accounts.privateKeyToAccount( + config.accountPK + ); + this.subnetConfig = config; } async getNetworkInformation(): Promise { @@ -49,8 +58,12 @@ export class SubnetService { async getLastCommittedBlockInfo(): Promise { try { - const { Hash, Number, Round, HexRLP, ParentHash } = - await this.web3.xdcSubnet.getV2Block("committed"); + const x = await this.web3.xdcSubnet.getV2Block("committed"); + console.log(x); + const { Hash, Number, Round, EncodedRLP, ParentHash } = + // await this.web3.xdcSubnet.getV2Block("committed"); + await this.web3.xdcSubnet.getV2Block("latest"); + const HexRLP = EncodedRLP; if (!Hash || !Number || !HexRLP || !ParentHash) { this.logger.error( "Invalid block hash or height or encodedRlp or ParentHash received", @@ -59,7 +72,7 @@ export class SubnetService { HexRLP, ParentHash ); - throw new Error("Unable to get latest committed block information"); + throw new Error("Unable to get latest committed block information on SUBNET"); } return { subnetBlockHash: Hash, @@ -79,8 +92,9 @@ export class SubnetService { async getCommittedBlockInfoByNum(blockNum: number): Promise { try { - const { Hash, Number, Round, HexRLP, ParentHash } = + const { Hash, Number, Round, EncodedRLP, ParentHash } = await this.web3.xdcSubnet.getV2Block(`0x${blockNum.toString(16)}`); + const HexRLP = EncodedRLP; if (!Hash || !Number || !HexRLP || !ParentHash) { this.logger.error( "Invalid block hash or height or encodedRlp or ParentHash received", @@ -89,7 +103,7 @@ export class SubnetService { HexRLP, ParentHash ); - throw new Error("Unable to get committed block information by height"); + throw new Error("Unable to get committed block information by height on SUBNET"); } return { subnetBlockHash: Hash, @@ -100,7 +114,7 @@ export class SubnetService { }; } catch (error) { this.logger.error( - "Error while trying to fetch blockInfo by number from subnet blockNum:", + "Error while trying to fetch blockInfo by number from SUBNET blockNum:", blockNum, { message: error.message } ); @@ -112,8 +126,9 @@ export class SubnetService { blockHash: string ): Promise { try { - const { Hash, Number, Round, HexRLP, ParentHash } = + const { Hash, Number, Round, EncodedRLP, ParentHash } = await this.web3.xdcSubnet.getV2BlockByHash(blockHash); + const HexRLP = EncodedRLP; if (!Hash || !Number || !HexRLP || !ParentHash) { this.logger.error( "Invalid block hash or height or encodedRlp or ParentHash received", @@ -122,7 +137,7 @@ export class SubnetService { HexRLP, ParentHash ); - throw new Error("Unable to get committed block information by hash"); + throw new Error("Unable to get committed block information by hash on SUBNET"); } return { subnetBlockHash: Hash, @@ -133,7 +148,7 @@ export class SubnetService { }; } catch (error) { this.logger.error( - "Error while trying to fetch blockInfo by hash from subnet", + "Error while trying to fetch blockInfo by hash from SUBNET", { message: error.message, blockHash } ); throw error; @@ -144,7 +159,7 @@ export class SubnetService { try { return this.web3.xdcSubnet.getTransactionAndReceiptProof(txHash); } catch (error) { - this.logger.error("Error while trying to fetch the transaction receipt proof", error); + this.logger.error("Error while trying to fetch the transaction receipt proof on SUBNET", error); throw error; } } @@ -180,7 +195,7 @@ export class SubnetService { .call(); return result[0]; } catch (error) { - this.logger.error("Fail to get block hash by number from mainnet", { + this.logger.error("Fail to get block hash by number from SUBNET", { height, message: error.message, }); @@ -208,7 +223,7 @@ export class SubnetService { latestSmComittedHash, latestSmHeight ); - throw new Error("Unable to get last audited block informations"); + throw new Error("Unable to get last audited block informations on SUBNET"); } return { smartContractHash: latestBlockHash, @@ -218,19 +233,73 @@ export class SubnetService { }; } catch (error) { this.logger.error( - "Error while trying to fetch the last audited subnet's block in XDC mainnet", + "Error while trying to fetch the last audited subnet's block in XDC SUBNET", { message: error.message } ); throw error; } } + async submitTxs( + results: Array<{ hexRLP: string; blockNum: number }> + ): Promise { + try { + if (!results.length) return; + this.logger.info( + `Submit the subnet block up to ${ + results[results.length - 1].blockNum + } as tx into PARENTNET` + ); + //const encodedHexArray = results.map(r => "0x" + Buffer.from(r.encodedRLP, "base64").toString("hex")); //old method for reference + const hexArray = results.map((r) => "0x" + r.hexRLP); + const transactionToBeSent = + await this.smartContractInstance.methods.receiveHeader(hexArray); + const gas = await transactionToBeSent.estimateGas({ + from: this.subnetAccount.address, + }); + const options = { + to: transactionToBeSent._parent._address, + data: transactionToBeSent.encodeABI(), + gas, + gasPrice: TRANSACTION_GAS_NUMBER, + }; + const signed = await this.web3.eth.accounts.signTransaction( + options, + this.subnetAccount.privateKey + ); + + await this.web3.eth.sendSignedTransaction(signed.rawTransaction); + + await sleep(this.subnetConfig.submitTransactionWaitingTime); + } catch (error) { + this.logger.error("Fail to submit transactions into PARENTNET", { + message: error.message, + }); + throw error; + } + } + + async Mode(): Promise<"lite"| "full"| "reverse full"> { try { return this.smartContractInstance.methods.MODE().call(); } catch (error) { - this.logger.error("Fail to get mode from mainnet smart contract"); + this.logger.error("Fail to get mode from SUBNET smart contract"); throw error; } } } + +function base64ToHex(base64String: string) { + // Step 1: Decode base64 string to binary data + const binaryString = atob(base64String); + + // Step 2: Convert binary data to hex + let hexString = ""; + for (let i = 0; i < binaryString.length; i++) { + const hex = binaryString.charCodeAt(i).toString(16); + hexString += hex.length === 2 ? hex : "0" + hex; + } + + return hexString; +} \ No newline at end of file From 3c9d94d0d4af70cb20d7380beecb5ff07d0576e8 Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Wed, 5 Jun 2024 16:32:48 +0400 Subject: [PATCH 04/21] hexRLP > encodedRLP --- src/processors/lite.ts | 2 +- src/processors/reverseFull.ts | 10 ++---- src/service/mainnet/index.ts | 52 +++++++++++--------------------- src/service/subnet/index.ts | 57 ++++++++++++----------------------- 4 files changed, 39 insertions(+), 82 deletions(-) diff --git a/src/processors/lite.ts b/src/processors/lite.ts index cea03dd..1f42922 100644 --- a/src/processors/lite.ts +++ b/src/processors/lite.ts @@ -103,7 +103,7 @@ export class Lite extends BaseProcessor { await this.liteMainnetService.commitHeader( scHash, results.map((item) => { - return "0x" + item.hexRLP; + return "0x" + item.encodedRLP; }) ); } else { diff --git a/src/processors/reverseFull.ts b/src/processors/reverseFull.ts index cba79f3..99294e8 100644 --- a/src/processors/reverseFull.ts +++ b/src/processors/reverseFull.ts @@ -1,9 +1,7 @@ import bunyan from "bunyan"; import { config } from "../config"; -// import { MainnetService, SmartContractData } from "../service/mainnet"; -// import { SubnetBlockInfo, SubnetService } from "../service/subnet"; -import {SubnetService, SmartContractData } from "../service/subnet"; -import {MainnetService, MainnetBlockInfo} from "../service/mainnet"; +import { SubnetService, SmartContractData } from "../service/subnet"; +import { MainnetService, MainnetBlockInfo } from "../service/mainnet"; import { chunkBy, sleep } from "../utils"; import { ForkingError } from "../errors/forkingError"; import { BaseProcessor } from "./base"; @@ -55,13 +53,9 @@ export class ReverseFull extends BaseProcessor { async processEvent() { // Pull latest confirmed tx from subnet const smartContractData = await this.subnetService.getLastAuditedBlock(); - this.logger.error("gram sm data from subnet"); - this.logger.error(smartContractData); // Pull latest confirmed block from mainnet const latestMainnetCommittedBlock = await this.mainnetService.getLastCommittedBlockInfo(); - this.logger.error("grab mainnet committed block"); - this.logger.error(latestMainnetCommittedBlock.mainnetBlockNumber); const { shouldProcess, from, msg } = await this.shouldProcessSync( smartContractData, diff --git a/src/service/mainnet/index.ts b/src/service/mainnet/index.ts index a6c2838..29ce38a 100644 --- a/src/service/mainnet/index.ts +++ b/src/service/mainnet/index.ts @@ -17,7 +17,7 @@ export interface MainnetBlockInfo { mainnetBlockHash: string; mainnetBlockNumber: number; mainnetBlockRound: number; - hexRLP: string; + encodedRLP: string; parentHash: string; } export interface SmartContractData { @@ -98,7 +98,7 @@ export class MainnetService { } async submitTxs( - results: Array<{ hexRLP: string; blockNum: number }> + results: Array<{ encodedRLP: string; blockNum: number }> ): Promise { try { if (!results.length) return; @@ -107,10 +107,9 @@ export class MainnetService { results[results.length - 1].blockNum } as tx into PARENTNET` ); - //const encodedHexArray = results.map(r => "0x" + Buffer.from(r.encodedRLP, "base64").toString("hex")); //old method for reference - const hexArray = results.map((r) => "0x" + r.hexRLP); + const encodedHexArray = results.map(r => "0x" + Buffer.from(r.encodedRLP, "base64").toString("hex")); const transactionToBeSent = - await this.smartContractInstance.methods.receiveHeader(hexArray); + await this.smartContractInstance.methods.receiveHeader(encodedHexArray); const gas = await transactionToBeSent.estimateGas({ from: this.mainnetAccount.address, }); @@ -156,13 +155,12 @@ export class MainnetService { try { const { Hash, Number, Round, EncodedRLP, ParentHash } = await this.web3.xdcMainnet.getV2Block(`0x${blockNum.toString(16)}`); - const HexRLP = EncodedRLP; - if (!Hash || !Number || !HexRLP || !ParentHash) { + if (!Hash || !Number || !EncodedRLP || !ParentHash) { this.logger.error( "Invalid block hash or height or encodedRlp or ParentHash received", Hash, Number, - HexRLP, + EncodedRLP, ParentHash ); throw new Error("Unable to get committed block information by height from PARENTNET"); @@ -171,7 +169,7 @@ export class MainnetService { mainnetBlockHash: Hash, mainnetBlockNumber: Number, mainnetBlockRound: Round, - hexRLP: HexRLP, + encodedRLP: EncodedRLP, parentHash: ParentHash, }; } catch (error) { @@ -188,13 +186,12 @@ export class MainnetService { try { const { Hash, Number, Round, EncodedRLP, ParentHash } = await this.web3.xdcMainnet.getV2Block("committed"); - const HexRLP = EncodedRLP; - if (!Hash || !Number || !HexRLP || !ParentHash) { + if (!Hash || !Number || !EncodedRLP || !ParentHash) { this.logger.error( "Invalid block hash or height or encodedRlp or ParentHash received", Hash, Number, - HexRLP, + EncodedRLP, ParentHash ); throw new Error("Unable to get latest committed block information from PARENTNET"); @@ -203,7 +200,7 @@ export class MainnetService { mainnetBlockHash: Hash, mainnetBlockNumber: Number, mainnetBlockRound: Round, - hexRLP: HexRLP, + encodedRLP: EncodedRLP, parentHash: ParentHash, }; } catch (error) { @@ -218,21 +215,21 @@ export class MainnetService { async bulkGetRlpHeaders( startingBlockNumber: number, numberOfBlocksToFetch: number - ): Promise> { + ): Promise> { this.logger.info( "Fetch subnet node data from " + startingBlockNumber + " to " + (startingBlockNumber + numberOfBlocksToFetch - 1) ); - const rlpHeaders: Array<{ hexRLP: string; blockNum: number }> = []; + const rlpHeaders: Array<{ encodedRLP: string; blockNum: number }> = []; for ( let i = startingBlockNumber; i < startingBlockNumber + numberOfBlocksToFetch; i++ ) { - const { hexRLP } = await this.getCommittedBlockInfoByNum(i); - rlpHeaders.push({ hexRLP, blockNum: i }); + const { encodedRLP } = await this.getCommittedBlockInfoByNum(i); + rlpHeaders.push({ encodedRLP, blockNum: i }); await sleep(this.mainnetConfig.fetchWaitingTime); } return rlpHeaders; @@ -314,7 +311,7 @@ export class LiteMainnetService { } async submitTxs( - results: Array<{ hexRLP: string; blockNum: number }> + results: Array<{ encodedRLP: string; blockNum: number }> ): Promise { try { if (!results.length) return; @@ -326,10 +323,9 @@ export class LiteMainnetService { } as tx into PARENTNET` ); - //const encodedHexArray = results.map(r => "0x" + Buffer.from(r.encodedRLP, "base64").toString("hex")); //old method for reference - const hexArray = results.map((r) => "0x" + r.hexRLP); + const encodedHexArray = results.map(r => "0x" + Buffer.from(r.encodedRLP, "base64").toString("hex")); const transactionToBeSent = - await this.liteSmartContractInstance.methods.receiveHeader(hexArray); + await this.liteSmartContractInstance.methods.receiveHeader(encodedHexArray); const gas = await transactionToBeSent.estimateGas({ from: this.mainnetAccount.address, @@ -451,17 +447,3 @@ export class LiteMainnetService { } } - -function base64ToHex(base64String: string) { - // Step 1: Decode base64 string to binary data - const binaryString = atob(base64String); - - // Step 2: Convert binary data to hex - let hexString = ""; - for (let i = 0; i < binaryString.length; i++) { - const hex = binaryString.charCodeAt(i).toString(16); - hexString += hex.length === 2 ? hex : "0" + hex; - } - - return hexString; -} \ No newline at end of file diff --git a/src/service/subnet/index.ts b/src/service/subnet/index.ts index 0c94d3d..a53a887 100644 --- a/src/service/subnet/index.ts +++ b/src/service/subnet/index.ts @@ -16,7 +16,7 @@ export interface SubnetBlockInfo { subnetBlockHash: string; subnetBlockNumber: number; subnetBlockRound: number; - hexRLP: string; + encodedRLP: string; parentHash: string; } @@ -59,17 +59,15 @@ export class SubnetService { async getLastCommittedBlockInfo(): Promise { try { const x = await this.web3.xdcSubnet.getV2Block("committed"); - console.log(x); const { Hash, Number, Round, EncodedRLP, ParentHash } = // await this.web3.xdcSubnet.getV2Block("committed"); await this.web3.xdcSubnet.getV2Block("latest"); - const HexRLP = EncodedRLP; - if (!Hash || !Number || !HexRLP || !ParentHash) { + if (!Hash || !Number || !EncodedRLP || !ParentHash) { this.logger.error( "Invalid block hash or height or encodedRlp or ParentHash received", Hash, Number, - HexRLP, + EncodedRLP, ParentHash ); throw new Error("Unable to get latest committed block information on SUBNET"); @@ -78,7 +76,7 @@ export class SubnetService { subnetBlockHash: Hash, subnetBlockNumber: Number, subnetBlockRound: Round, - hexRLP: HexRLP, + encodedRLP: EncodedRLP, parentHash: ParentHash, }; } catch (error) { @@ -94,13 +92,12 @@ export class SubnetService { try { const { Hash, Number, Round, EncodedRLP, ParentHash } = await this.web3.xdcSubnet.getV2Block(`0x${blockNum.toString(16)}`); - const HexRLP = EncodedRLP; - if (!Hash || !Number || !HexRLP || !ParentHash) { + if (!Hash || !Number || !EncodedRLP || !ParentHash) { this.logger.error( "Invalid block hash or height or encodedRlp or ParentHash received", Hash, Number, - HexRLP, + EncodedRLP, ParentHash ); throw new Error("Unable to get committed block information by height on SUBNET"); @@ -109,7 +106,7 @@ export class SubnetService { subnetBlockHash: Hash, subnetBlockNumber: Number, subnetBlockRound: Round, - hexRLP: HexRLP, + encodedRLP: EncodedRLP, parentHash: ParentHash, }; } catch (error) { @@ -128,13 +125,12 @@ export class SubnetService { try { const { Hash, Number, Round, EncodedRLP, ParentHash } = await this.web3.xdcSubnet.getV2BlockByHash(blockHash); - const HexRLP = EncodedRLP; - if (!Hash || !Number || !HexRLP || !ParentHash) { + if (!Hash || !Number || !EncodedRLP || !ParentHash) { this.logger.error( "Invalid block hash or height or encodedRlp or ParentHash received", Hash, Number, - HexRLP, + EncodedRLP, ParentHash ); throw new Error("Unable to get committed block information by hash on SUBNET"); @@ -143,7 +139,7 @@ export class SubnetService { subnetBlockHash: Hash, subnetBlockNumber: Number, subnetBlockRound: Round, - hexRLP: HexRLP, + encodedRLP: EncodedRLP, parentHash: ParentHash, }; } catch (error) { @@ -167,21 +163,21 @@ export class SubnetService { async bulkGetRlpHeaders( startingBlockNumber: number, numberOfBlocksToFetch: number - ): Promise> { + ): Promise> { this.logger.info( "Fetch subnet node data from " + startingBlockNumber + " to " + (startingBlockNumber + numberOfBlocksToFetch - 1) ); - const rlpHeaders: Array<{ hexRLP: string; blockNum: number }> = []; + const rlpHeaders: Array<{ encodedRLP: string; blockNum: number }> = []; for ( let i = startingBlockNumber; i < startingBlockNumber + numberOfBlocksToFetch; i++ ) { - const { hexRLP } = await this.getCommittedBlockInfoByNum(i); - rlpHeaders.push({ hexRLP, blockNum: i }); + const { encodedRLP } = await this.getCommittedBlockInfoByNum(i); + rlpHeaders.push({ encodedRLP, blockNum: i }); await sleep(this.subnetConfig.fetchWaitingTime); } return rlpHeaders; @@ -241,19 +237,18 @@ export class SubnetService { } async submitTxs( - results: Array<{ hexRLP: string; blockNum: number }> + results: Array<{ encodedRLP: string; blockNum: number }> ): Promise { try { if (!results.length) return; this.logger.info( `Submit the subnet block up to ${ results[results.length - 1].blockNum - } as tx into PARENTNET` + } as tx into SUBNET` ); - //const encodedHexArray = results.map(r => "0x" + Buffer.from(r.encodedRLP, "base64").toString("hex")); //old method for reference - const hexArray = results.map((r) => "0x" + r.hexRLP); + const encodedHexArray = results.map(r => "0x" + Buffer.from(r.encodedRLP, "base64").toString("hex")); //old method for reference const transactionToBeSent = - await this.smartContractInstance.methods.receiveHeader(hexArray); + await this.smartContractInstance.methods.receiveHeader(encodedHexArray); const gas = await transactionToBeSent.estimateGas({ from: this.subnetAccount.address, }); @@ -272,7 +267,7 @@ export class SubnetService { await sleep(this.subnetConfig.submitTransactionWaitingTime); } catch (error) { - this.logger.error("Fail to submit transactions into PARENTNET", { + this.logger.error("Fail to submit transactions into SUBNET", { message: error.message, }); throw error; @@ -289,17 +284,3 @@ export class SubnetService { } } } - -function base64ToHex(base64String: string) { - // Step 1: Decode base64 string to binary data - const binaryString = atob(base64String); - - // Step 2: Convert binary data to hex - let hexString = ""; - for (let i = 0; i < binaryString.length; i++) { - const hex = binaryString.charCodeAt(i).toString(16); - hexString += hex.length === 2 ? hex : "0" + hex; - } - - return hexString; -} \ No newline at end of file From 130e12697c656af9eea63d9e2a48668d86d9927d Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Fri, 7 Jun 2024 16:46:42 +0400 Subject: [PATCH 05/21] change mode string from CSC --- src/processors/index.ts | 2 +- src/service/mainnet/index.ts | 4 ++-- src/service/subnet/index.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/processors/index.ts b/src/processors/index.ts index 401c9d1..7702c33 100644 --- a/src/processors/index.ts +++ b/src/processors/index.ts @@ -115,7 +115,7 @@ export class Processors { if (config.reverseRelayerCsc.isEnabled){ const subnetSmartContractMode = await this.subnetService.Mode(); switch (subnetSmartContractMode) { - case "reverse full": + case "reverse_full": modes.push(Mode.REVERSE_FULL); break; default: diff --git a/src/service/mainnet/index.ts b/src/service/mainnet/index.ts index 29ce38a..f79523f 100644 --- a/src/service/mainnet/index.ts +++ b/src/service/mainnet/index.ts @@ -235,7 +235,7 @@ export class MainnetService { return rlpHeaders; } - async Mode(): Promise<"lite"| "full"| "reverse full"> { + async Mode(): Promise<"lite"| "full"| "reverse_full"> { try { return this.smartContractInstance.methods.MODE().call(); } catch (error) { @@ -437,7 +437,7 @@ export class LiteMainnetService { throw error; } } - async Mode(): Promise<"lite"| "full"| "reverse full"> { + async Mode(): Promise<"lite"| "full"| "reverse_full"> { try { return this.liteSmartContractInstance.methods.MODE().call(); } catch (error) { diff --git a/src/service/subnet/index.ts b/src/service/subnet/index.ts index a53a887..7999c59 100644 --- a/src/service/subnet/index.ts +++ b/src/service/subnet/index.ts @@ -275,7 +275,7 @@ export class SubnetService { } - async Mode(): Promise<"lite"| "full"| "reverse full"> { + async Mode(): Promise<"lite"| "full"| "reverse_full"> { try { return this.smartContractInstance.methods.MODE().call(); } catch (error) { From 4c803ac20b6c0532faa0b20c90ec0dbf362b1b19 Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Sat, 8 Jun 2024 13:40:39 +0400 Subject: [PATCH 06/21] more clarity logging --- src/processors/full.ts | 4 ++-- src/processors/lite.ts | 2 +- src/processors/reverseFull.ts | 4 ++-- src/service/mainnet/index.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/processors/full.ts b/src/processors/full.ts index 325ae0d..d684c32 100644 --- a/src/processors/full.ts +++ b/src/processors/full.ts @@ -30,7 +30,7 @@ export class Full extends BaseProcessor { //TODO: check CSC mode is correct at init this.queue.process(async (_, done) => { - this.logger.info("⏰ Executing normal flow periodically"); + this.logger.info("⏰ Full Relayer: Executing normal flow periodically"); try { done(null, await this.processEvent()); } catch (error) { @@ -87,7 +87,7 @@ export class Full extends BaseProcessor { await this.mainnetService.submitTxs(results); startingBlockNumberToFetch += numOfBlocks; } - this.logger.info("Sync completed!"); + this.logger.info("Full CSC Sync completed!"); return; } diff --git a/src/processors/lite.ts b/src/processors/lite.ts index 1f42922..2fda866 100644 --- a/src/processors/lite.ts +++ b/src/processors/lite.ts @@ -131,7 +131,7 @@ export class Lite extends BaseProcessor { scCommittedHeight = last.smartContractCommittedHeight; scHash = last.smartContractHash; } - this.logger.info("Sync completed!"); + this.logger.info("Lite CSC Sync completed!"); return; } } \ No newline at end of file diff --git a/src/processors/reverseFull.ts b/src/processors/reverseFull.ts index 99294e8..ceb24b5 100644 --- a/src/processors/reverseFull.ts +++ b/src/processors/reverseFull.ts @@ -30,7 +30,7 @@ export class ReverseFull extends BaseProcessor { //TODO: check CSC mode is correct at init this.queue.process(async (_, done) => { - this.logger.info("⏰ Executing normal flow periodically"); + this.logger.info("⏰ Reverse Relayer: Executing normal flow periodically"); try { done(null, await this.processEvent()); } catch (error) { @@ -87,7 +87,7 @@ export class ReverseFull extends BaseProcessor { await this.subnetService.submitTxs(results); startingBlockNumberToFetch += numOfBlocks; } - this.logger.info("Sync completed!"); + this.logger.info("Reverse Full CSC Sync completed!"); return; } diff --git a/src/service/mainnet/index.ts b/src/service/mainnet/index.ts index f79523f..f1a7a10 100644 --- a/src/service/mainnet/index.ts +++ b/src/service/mainnet/index.ts @@ -217,7 +217,7 @@ export class MainnetService { numberOfBlocksToFetch: number ): Promise> { this.logger.info( - "Fetch subnet node data from " + + "Fetch parentnet node data from " + startingBlockNumber + " to " + (startingBlockNumber + numberOfBlocksToFetch - 1) From 7976feb8e59d2003f193f9c6a82f80bba355f9b4 Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Sat, 8 Jun 2024 15:32:31 +0400 Subject: [PATCH 07/21] add dynamic txs --- src/processors/full.ts | 2 +- src/processors/reverseFull.ts | 2 +- src/service/mainnet/index.ts | 26 ++++++++++++++++++++++++-- src/service/subnet/index.ts | 23 ++++++++++++++++++++++- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/processors/full.ts b/src/processors/full.ts index d684c32..67bdfee 100644 --- a/src/processors/full.ts +++ b/src/processors/full.ts @@ -84,7 +84,7 @@ export class Full extends BaseProcessor { startingBlockNumberToFetch, numOfBlocks ); - await this.mainnetService.submitTxs(results); + await this.mainnetService.submitTxsDynamic(results); startingBlockNumberToFetch += numOfBlocks; } this.logger.info("Full CSC Sync completed!"); diff --git a/src/processors/reverseFull.ts b/src/processors/reverseFull.ts index ceb24b5..295be25 100644 --- a/src/processors/reverseFull.ts +++ b/src/processors/reverseFull.ts @@ -84,7 +84,7 @@ export class ReverseFull extends BaseProcessor { startingBlockNumberToFetch, numOfBlocks ); - await this.subnetService.submitTxs(results); + await this.subnetService.submitTxsDynamic(results); startingBlockNumberToFetch += numOfBlocks; } this.logger.info("Reverse Full CSC Sync completed!"); diff --git a/src/service/mainnet/index.ts b/src/service/mainnet/index.ts index f1a7a10..2fd0b36 100644 --- a/src/service/mainnet/index.ts +++ b/src/service/mainnet/index.ts @@ -103,8 +103,8 @@ export class MainnetService { try { if (!results.length) return; this.logger.info( - `Submit the subnet block up to ${ - results[results.length - 1].blockNum + `Submit the subnet block from ${results[0].blockNum} to ${ + results[results.length - 1].blockNum } as tx into PARENTNET` ); const encodedHexArray = results.map(r => "0x" + Buffer.from(r.encodedRLP, "base64").toString("hex")); @@ -135,6 +135,28 @@ export class MainnetService { } } + async submitTxsDynamic(results: Array<{ encodedRLP: string; blockNum: number }>): Promise { + const blocksPerTx = [30, 5, 1]; + while (results.length) { + let i = 0; + while (i < blocksPerTx.length){ + const val = blocksPerTx[i]; + if (results.length >= val){ + try{ + this.logger.debug("submitDynamic startblock", results[0].blockNum, "pushing", val, "blocks", "remaining(inclusive)", results.length); + await this.submitTxs(results.slice(0, val)); + results = results.slice(val, results.length); + break; //if push success, reset push size + } catch (error){ + if (i < blocksPerTx.length){ + i++; + } + } + } + } + } + } + // Below shall be given height provide the SM hash async getBlockHashByNumber(height: number): Promise { try { diff --git a/src/service/subnet/index.ts b/src/service/subnet/index.ts index 7999c59..b758504 100644 --- a/src/service/subnet/index.ts +++ b/src/service/subnet/index.ts @@ -242,7 +242,7 @@ export class SubnetService { try { if (!results.length) return; this.logger.info( - `Submit the subnet block up to ${ + `Submit the parentnet block from ${results[0].blockNum} to ${ results[results.length - 1].blockNum } as tx into SUBNET` ); @@ -274,6 +274,27 @@ export class SubnetService { } } + async submitTxsDynamic(results: Array<{ encodedRLP: string; blockNum: number }>): Promise { + const blocksPerTx = [5, 1]; + while (results.length) { + let i = 0; + while (i < blocksPerTx.length){ + const val = blocksPerTx[i]; + if (results.length >= val){ + try{ + this.logger.debug("submitDynamic startblock", results[0].blockNum, "pushing", val, "blocks", results.length, "remaining(inclusive)"); + await this.submitTxs(results.slice(0, val)); + results = results.slice(val, results.length); + break; //if push success, reset push size + } catch (error){ + if (i < blocksPerTx.length){ + i++; + } + } + } + } + } + } async Mode(): Promise<"lite"| "full"| "reverse_full"> { try { From b385971981b2c0de6f9030b792c89018991e0cd5 Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Sat, 8 Jun 2024 21:09:41 +0400 Subject: [PATCH 08/21] optimize fetch time with batch --- src/service/mainnet/index.ts | 66 +++++++++++++++++++++++----------- src/service/subnet/index.ts | 69 +++++++++++++++++++++++++----------- 2 files changed, 94 insertions(+), 41 deletions(-) diff --git a/src/service/mainnet/index.ts b/src/service/mainnet/index.ts index 2fd0b36..c282c71 100644 --- a/src/service/mainnet/index.ts +++ b/src/service/mainnet/index.ts @@ -10,6 +10,7 @@ import FullABI from "./ABI/FullABI.json"; import LiteABI from "./ABI/LiteABI.json"; import { Web3WithExtension, mainnetExtensions } from "./extensions"; import { NetworkInformation } from "../types"; +import axios, { AxiosInstance } from "axios"; const TRANSACTION_GAS_NUMBER = 12500000000; //TODO: check this is different now?, is there better way to handle? @@ -27,7 +28,6 @@ export interface SmartContractData { smartContractCommittedHash: string; } - export class MainnetService { private web3: Web3WithExtension; private smartContractInstance: Contract; @@ -102,11 +102,6 @@ export class MainnetService { ): Promise { try { if (!results.length) return; - this.logger.info( - `Submit the subnet block from ${results[0].blockNum} to ${ - results[results.length - 1].blockNum - } as tx into PARENTNET` - ); const encodedHexArray = results.map(r => "0x" + Buffer.from(r.encodedRLP, "base64").toString("hex")); const transactionToBeSent = await this.smartContractInstance.methods.receiveHeader(encodedHexArray); @@ -143,15 +138,14 @@ export class MainnetService { const val = blocksPerTx[i]; if (results.length >= val){ try{ - this.logger.debug("submitDynamic startblock", results[0].blockNum, "pushing", val, "blocks", "remaining(inclusive)", results.length); + this.logger.info("submitDynamic startblock", results[0].blockNum, "pushing", val, "blocks,",results.length, "remaining(inclusive) into PARENTNET"); await this.submitTxs(results.slice(0, val)); results = results.slice(val, results.length); break; //if push success, reset push size - } catch (error){ - if (i < blocksPerTx.length){ - i++; - } - } + } catch (error){} + } + if (i < blocksPerTx.length){ + i++; } } } @@ -204,6 +198,40 @@ export class MainnetService { } } + //bypassing web3 with axios here, really hard to use batch web3 in version 1.8.2, maybe later we upgrade to 4.x.x and utilize web3 batch + async getCommittedBlockInfoBatch(startBlockNum: number, numToFetch: number): Promise { + const data = []; + const blockInfoList: MainnetBlockInfo[] = []; + for (let i = startBlockNum; i { + for (let i=0; i { + this.logger.error("Axios Fetching Error:", error); + }); + return blockInfoList; + } + async getLastCommittedBlockInfo(): Promise { try { const { Hash, Number, Round, EncodedRLP, ParentHash } = @@ -245,14 +273,12 @@ export class MainnetService { (startingBlockNumber + numberOfBlocksToFetch - 1) ); const rlpHeaders: Array<{ encodedRLP: string; blockNum: number }> = []; - for ( - let i = startingBlockNumber; - i < startingBlockNumber + numberOfBlocksToFetch; - i++ - ) { - const { encodedRLP } = await this.getCommittedBlockInfoByNum(i); - rlpHeaders.push({ encodedRLP, blockNum: i }); - await sleep(this.mainnetConfig.fetchWaitingTime); + const blockInfoList = await this.getCommittedBlockInfoBatch(startingBlockNumber, numberOfBlocksToFetch); + for (let i=0; i { return this.web3.xdcSubnet.getNetworkInformation(); } - + + //bypassing web3 with axios here, really hard to use batch web3 in version 1.8.2, maybe later we upgrade to 4.x.x and utilize web3 batch + async getCommittedBlockInfoBatch(startBlockNum: number, numToFetch: number): Promise { + const data = []; + const blockInfoList: SubnetBlockInfo[] = []; + for (let i = startBlockNum; i { + for (let i=0; i { + this.logger.error("Axios Fetching Error:", error); + }); + return blockInfoList; + } + async getLastCommittedBlockInfo(): Promise { try { const x = await this.web3.xdcSubnet.getV2Block("committed"); @@ -171,14 +206,12 @@ export class SubnetService { (startingBlockNumber + numberOfBlocksToFetch - 1) ); const rlpHeaders: Array<{ encodedRLP: string; blockNum: number }> = []; - for ( - let i = startingBlockNumber; - i < startingBlockNumber + numberOfBlocksToFetch; - i++ - ) { - const { encodedRLP } = await this.getCommittedBlockInfoByNum(i); - rlpHeaders.push({ encodedRLP, blockNum: i }); - await sleep(this.subnetConfig.fetchWaitingTime); + const blockInfoList = await this.getCommittedBlockInfoBatch(startingBlockNumber, numberOfBlocksToFetch); + for (let i=0; i { try { if (!results.length) return; - this.logger.info( - `Submit the parentnet block from ${results[0].blockNum} to ${ - results[results.length - 1].blockNum - } as tx into SUBNET` - ); - const encodedHexArray = results.map(r => "0x" + Buffer.from(r.encodedRLP, "base64").toString("hex")); //old method for reference + const encodedHexArray = results.map(r => "0x" + Buffer.from(r.encodedRLP, "base64").toString("hex")); const transactionToBeSent = await this.smartContractInstance.methods.receiveHeader(encodedHexArray); const gas = await transactionToBeSent.estimateGas({ @@ -282,15 +310,14 @@ export class SubnetService { const val = blocksPerTx[i]; if (results.length >= val){ try{ - this.logger.debug("submitDynamic startblock", results[0].blockNum, "pushing", val, "blocks", results.length, "remaining(inclusive)"); + this.logger.info("submitDynamic startblock", results[0].blockNum, "pushing", val, "blocks,", results.length, "remaining(inclusive) into SUBNET"); await this.submitTxs(results.slice(0, val)); results = results.slice(val, results.length); break; //if push success, reset push size - } catch (error){ - if (i < blocksPerTx.length){ - i++; - } - } + } catch (error){} + } + if (i < blocksPerTx.length){ + i++; } } } From a1656315dcb261c48099da70532937fb7a13faeb Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Sat, 8 Jun 2024 21:29:39 +0400 Subject: [PATCH 09/21] update default --- src/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.ts b/src/config.ts index 15527a8..18b567b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -109,7 +109,7 @@ const config: Config = { } : undefined, }, - chunkSize : parseInt(process.env.MAX_FETCH_BLOCK_SIZE) || 30, + chunkSize : parseInt(process.env.MAX_FETCH_BLOCK_SIZE) || 120, }; export { config }; From b73e303caf6b49797cd847ebeda9a8fae7abcd57 Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Sun, 9 Jun 2024 00:46:33 +0400 Subject: [PATCH 10/21] fix --- src/service/mainnet/index.ts | 2 +- src/service/subnet/index.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/service/mainnet/index.ts b/src/service/mainnet/index.ts index c282c71..221e888 100644 --- a/src/service/mainnet/index.ts +++ b/src/service/mainnet/index.ts @@ -131,7 +131,7 @@ export class MainnetService { } async submitTxsDynamic(results: Array<{ encodedRLP: string; blockNum: number }>): Promise { - const blocksPerTx = [30, 5, 1]; + const blocksPerTx = [30, 15, 5, 1]; while (results.length) { let i = 0; while (i < blocksPerTx.length){ diff --git a/src/service/subnet/index.ts b/src/service/subnet/index.ts index 3815e19..d5fb19c 100644 --- a/src/service/subnet/index.ts +++ b/src/service/subnet/index.ts @@ -93,7 +93,6 @@ export class SubnetService { async getLastCommittedBlockInfo(): Promise { try { - const x = await this.web3.xdcSubnet.getV2Block("committed"); const { Hash, Number, Round, EncodedRLP, ParentHash } = // await this.web3.xdcSubnet.getV2Block("committed"); await this.web3.xdcSubnet.getV2Block("latest"); From d909cc7abd7213f59ed1af594b6640a6483b7753 Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Sun, 9 Jun 2024 01:17:29 +0400 Subject: [PATCH 11/21] tune for txpool increase --- src/service/subnet/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/subnet/index.ts b/src/service/subnet/index.ts index d5fb19c..ce418ba 100644 --- a/src/service/subnet/index.ts +++ b/src/service/subnet/index.ts @@ -302,7 +302,7 @@ export class SubnetService { } async submitTxsDynamic(results: Array<{ encodedRLP: string; blockNum: number }>): Promise { - const blocksPerTx = [5, 1]; + const blocksPerTx = [20, 10, 5, 1]; while (results.length) { let i = 0; while (i < blocksPerTx.length){ From d5cbc383fc0e1aeaf00f5a8c82d32a05c2d8d33a Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Sun, 9 Jun 2024 01:42:08 +0400 Subject: [PATCH 12/21] optimize dynamic tx --- src/service/mainnet/index.ts | 10 ++++++++++ src/service/subnet/index.ts | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/src/service/mainnet/index.ts b/src/service/mainnet/index.ts index 221e888..c79ba98 100644 --- a/src/service/mainnet/index.ts +++ b/src/service/mainnet/index.ts @@ -132,6 +132,16 @@ export class MainnetService { async submitTxsDynamic(results: Array<{ encodedRLP: string; blockNum: number }>): Promise { const blocksPerTx = [30, 15, 5, 1]; + //make 1 initial try, this is for when blocks are caught up + if (results.length < blocksPerTx[0]){ + try{ + this.logger.info("submitDynamic startblock", results[0].blockNum, "pushing", results.length, "blocks,",results.length, "remaining(inclusive) into PARENTNET"); + await this.submitTxs(results); + return; + } catch (error){} + } + + //loop while reducing tx size while (results.length) { let i = 0; while (i < blocksPerTx.length){ diff --git a/src/service/subnet/index.ts b/src/service/subnet/index.ts index ce418ba..a3cae3f 100644 --- a/src/service/subnet/index.ts +++ b/src/service/subnet/index.ts @@ -303,6 +303,14 @@ export class SubnetService { async submitTxsDynamic(results: Array<{ encodedRLP: string; blockNum: number }>): Promise { const blocksPerTx = [20, 10, 5, 1]; + //make 1 initial try, this is for when blocks are caught up + if (results.length < blocksPerTx[0]){ + try{ + this.logger.info("submitDynamic startblock", results[0].blockNum, "pushing", results.length, "blocks,",results.length, "remaining(inclusive) into SUBNET"); + await this.submitTxs(results); + return; + } catch (error){} + } while (results.length) { let i = 0; while (i < blocksPerTx.length){ From 207db484133bf11cdd0bec291f0bf4fb89a4b286 Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Sun, 9 Jun 2024 12:37:47 +0400 Subject: [PATCH 13/21] implement xdc zero in a temporary way (fix after demo) --- src/processors/reverseZero.ts | 11 +- src/processors/zero.ts | 2 +- src/service/reverse_zero/index.ts | 203 ++++++++++++++++++++++++++++++ 3 files changed, 210 insertions(+), 6 deletions(-) create mode 100644 src/service/reverse_zero/index.ts diff --git a/src/processors/reverseZero.ts b/src/processors/reverseZero.ts index 3119c9c..1422d82 100644 --- a/src/processors/reverseZero.ts +++ b/src/processors/reverseZero.ts @@ -1,5 +1,6 @@ import bunyan from "bunyan"; import { ZeroService } from "../service/zero"; +import { ReverseZeroService } from "../service/reverse_zero"; import { config } from "../config"; import { BaseProcessor } from "./base"; @@ -11,18 +12,18 @@ const REPEAT_JOB_OPT = { export class ReverseZero extends BaseProcessor { private logger: bunyan; - private zeroService: ZeroService; + private zeroService: ReverseZeroService; constructor(logger: bunyan) { super(NAME); this.logger = logger; - this.zeroService = new ZeroService(logger); + this.zeroService = new ReverseZeroService(logger); } init() { this.logger.info("Initialising Reverse XDC-Zero"); this.zeroService.init(); this.queue.process(async (_, done) => { - this.logger.info("⏰ Executing xdc-zero periodically"); + this.logger.info("⏰ Executing reverse xdc-zero periodically"); try { done(null, await this.processEvent()); } catch (error) { @@ -72,11 +73,11 @@ export class ReverseZero extends BaseProcessor { proof.txProofValues, proof.blockHash ); - this.logger.info("sync zero index " + i + " success"); + this.logger.info("Reverse Zero: sync index " + i + " success"); } } } - const msg = `Completed the xdc-zero sync up till ${lastIndexFromSubnet} from subnet, wait for the next cycle`; + const msg = `Completed the reverse xdc-zero sync up till ${lastIndexFromSubnet} from parentnet, wait for the next cycle`; this.logger.info(msg); return msg; } diff --git a/src/processors/zero.ts b/src/processors/zero.ts index f3abac0..a046d7f 100644 --- a/src/processors/zero.ts +++ b/src/processors/zero.ts @@ -72,7 +72,7 @@ export class Zero extends BaseProcessor { proof.txProofValues, proof.blockHash ); - this.logger.info("sync zero index " + i + " success"); + this.logger.info("Zero: sync index " + i + " success"); } } } diff --git a/src/service/reverse_zero/index.ts b/src/service/reverse_zero/index.ts new file mode 100644 index 0000000..ad98b6c --- /dev/null +++ b/src/service/reverse_zero/index.ts @@ -0,0 +1,203 @@ +import { + Hex, + PrivateKeyAccount, + createWalletClient, + PublicClient, + WalletClient, + createPublicClient, + decodeAbiParameters, + http, +} from "viem"; +import bunyan from "bunyan"; +import { config } from "../../config"; +import { SubnetService } from "../subnet"; +import endpointABI from "../../abi/endpointABI.json"; +import cscABI from "../../abi/cscABI.json"; +import { MainnetService } from "../mainnet"; +import Logger from "bunyan"; +import { privateKeyToAccount } from "viem/accounts"; + +// This class must be called with init() in order to use it +export class ReverseZeroService { + private subnetViemClient: PublicClient; + private mainnetViemClient: PublicClient; + private mainnetWalletClient: WalletClient; + private subnetService: SubnetService; + private mainnetService: MainnetService; + private logger: Logger; + + private parentChainWalletAccount: PrivateKeyAccount; + + private zeroWalletPk: PrivateKeyAccount; + private subnetUrl: string; + private parentnetUrl: string; + private subnetZeroAddress: string; + private parentnetZeroAddress: string; + private subnetCSCAddress: string; + private parentnetCSCAddress: string; + + constructor(logger: bunyan) { + this.subnetService = new SubnetService(config.mainnet, logger); //TODO: temp swap + this.mainnetService = new MainnetService(config.subnet, logger); //TODO: fix temp swap + this.subnetUrl = config.mainnet.url; + this.parentnetUrl = config.subnet.url; + this.subnetCSCAddress = config.mainnet.smartContractAddress; + this.parentnetCSCAddress = config.subnet.smartContractAddress; + this.subnetZeroAddress = config.xdcZero.parentChainZeroContractAddress; + this.parentnetZeroAddress = config.xdcZero.subnetZeroContractAddress; + + this.logger = logger; + this.parentChainWalletAccount = privateKeyToAccount(config.xdcZero.subnetWalletPk as Hex); + } + + // Initialise the client services + async init() { + const subnetNetworkInformation = + await this.subnetService.getNetworkInformation(); + const subnetInfo = { + id: subnetNetworkInformation.NetworkId, + name: subnetNetworkInformation.NetworkName, + network: subnetNetworkInformation.NetworkName, + nativeCurrency: { + decimals: 18, + name: subnetNetworkInformation.Denom, + symbol: subnetNetworkInformation.Denom, + }, + rpcUrls: { + public: { http: [this.subnetUrl]}, + default: { http: [this.subnetUrl] }, + }, + }; + + this.subnetViemClient = createPublicClient({ + chain: subnetInfo, + transport: http(), + }); + + const mainnetNetworkInformation = + await this.mainnetService.getNetworkInformation(); + const mainnetInfo = { + id: mainnetNetworkInformation.NetworkId, + name: mainnetNetworkInformation.NetworkName, + network: mainnetNetworkInformation.NetworkName, + nativeCurrency: { + decimals: 18, + name: mainnetNetworkInformation.Denom, + symbol: mainnetNetworkInformation.Denom, + }, + rpcUrls: { + public: { http: [this.parentnetUrl] }, + default: { http: [this.parentnetUrl] }, + }, + }; + + this.mainnetViemClient = createPublicClient({ + chain: mainnetInfo, + transport: http(), + }); + + this.mainnetWalletClient = createWalletClient({ + account: this.parentChainWalletAccount, + chain: mainnetInfo, + transport: http(), + }); + } + + async getPayloads() { + const payloads = [] as any; + const subnetEndpointContract = { + // address: config.xdcZero.subnetZeroContractAddress, + address: this.subnetZeroAddress, + abi: endpointABI, + }; + + const logs = await this.subnetViemClient.getContractEvents({ + ...(subnetEndpointContract as any), + fromBlock: BigInt(0), + eventName: "Packet", + }); + + const parentChainId = await this.mainnetViemClient.getChainId(); + + logs?.forEach((log) => { + const values = decodeAbiParameters( + [ + { name: "index", type: "uint" }, + { name: "sid", type: "uint" }, + { name: "sua", type: "address" }, + { name: "rid", type: "uint" }, + { name: "rua", type: "address" }, + { name: "data", type: "bytes" }, + ], + `0x${log.data.substring(130)}` + ); + + if (Number(values[3]) == parentChainId) { + const list = [...values]; + list.push(log.transactionHash); + list.push(log.blockNumber); + payloads.push(list); + } + }); + + return payloads; + } + + async getIndexFromParentnet() { + const subnetChainId = await this.subnetViemClient.getChainId(); + const parentnetEndpointContract = { + // address: config.xdcZero.parentChainZeroContractAddress, + address: this.parentnetZeroAddress, + abi: endpointABI, + }; + const chain = (await this.mainnetViemClient.readContract({ + ...(parentnetEndpointContract as any), + functionName: "getChain", + args: [subnetChainId], + })) as { lastIndex: number }; + + return chain?.lastIndex; + } + + async getLatestBlockNumberFromCsc() { + const parentnetCSCContract = { + // address: config.mainnet.smartContractAddress, + address: this.parentnetCSCAddress, + abi: cscABI, + }; + const blocks = (await this.mainnetViemClient.readContract({ + ...(parentnetCSCContract as any), + functionName: "getLatestBlocks", + args: [], + })) as [any, any]; + + return blocks[1]?.number; + } + + async getProof(txHash: string) { + return this.subnetService.getTransactionAndReceiptProof(txHash); + } + + async validateTransactionProof( + key: string, + receiptProof: string[], + transactionProof: string[], + blockhash: string + ) { + const parentnetEndpointContract = { + // address: config.xdcZero.parentChainZeroContractAddress, + address: this.parentnetZeroAddress, + abi: endpointABI, + }; + const subnetChainId = await this.subnetViemClient.getChainId(); + const { request } = await this.mainnetViemClient.simulateContract({ + ...(parentnetEndpointContract as any), + functionName: "validateTransactionProof", + args: [subnetChainId, key, receiptProof, transactionProof, blockhash], + account: this.parentChainWalletAccount, + }); + + const tx = await this.mainnetWalletClient.writeContract(request as any); + this.logger.info(tx); + } +} From 58e2bf5bc9db30c4dc634e984937a63eca38fdbe Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Mon, 10 Jun 2024 18:33:27 +0400 Subject: [PATCH 14/21] trig build --- src/utils/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/index.ts b/src/utils/index.ts index b1023b4..bc83dfe 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -13,3 +13,4 @@ export const chunkBy = (chunkValue: number) => (numToChunk: number): number[] => return chunks; }; + \ No newline at end of file From f8f783ae77d5668b57099ae355774afe4d5b808c Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Wed, 12 Jun 2024 16:54:21 +0400 Subject: [PATCH 15/21] test generic zero --- src/processors/reverseZero.ts | 5 +- src/processors/zero.ts | 5 +- src/service/generic_zero/index.ts | 212 ++++++++++++++++++++++++++++++ 3 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 src/service/generic_zero/index.ts diff --git a/src/processors/reverseZero.ts b/src/processors/reverseZero.ts index 1422d82..acdfd5b 100644 --- a/src/processors/reverseZero.ts +++ b/src/processors/reverseZero.ts @@ -3,6 +3,7 @@ import { ZeroService } from "../service/zero"; import { ReverseZeroService } from "../service/reverse_zero"; import { config } from "../config"; import { BaseProcessor } from "./base"; +import { GenericZeroService } from "../service/generic_zero"; export const NAME = "REVERSE-ZERO"; const REPEAT_JOB_OPT = { @@ -12,12 +13,12 @@ const REPEAT_JOB_OPT = { export class ReverseZero extends BaseProcessor { private logger: bunyan; - private zeroService: ReverseZeroService; + private zeroService: GenericZeroService; constructor(logger: bunyan) { super(NAME); this.logger = logger; - this.zeroService = new ReverseZeroService(logger); + this.zeroService = new GenericZeroService(logger, "reverse"); } init() { this.logger.info("Initialising Reverse XDC-Zero"); diff --git a/src/processors/zero.ts b/src/processors/zero.ts index a046d7f..60a4f67 100644 --- a/src/processors/zero.ts +++ b/src/processors/zero.ts @@ -2,6 +2,7 @@ import bunyan from "bunyan"; import { ZeroService } from "../service/zero"; import { config } from "../config"; import { BaseProcessor } from "./base"; +import { GenericZeroService } from "../service/generic_zero"; export const NAME = "ZERO"; const REPEAT_JOB_OPT = { @@ -11,12 +12,12 @@ const REPEAT_JOB_OPT = { export class Zero extends BaseProcessor { private logger: bunyan; - private zeroService: ZeroService; + private zeroService: GenericZeroService; constructor(logger: bunyan) { super(NAME); this.logger = logger; - this.zeroService = new ZeroService(logger); + this.zeroService = new GenericZeroService(logger, "normal"); } init() { this.logger.info("Initialising XDC-Zero"); diff --git a/src/service/generic_zero/index.ts b/src/service/generic_zero/index.ts new file mode 100644 index 0000000..1fade98 --- /dev/null +++ b/src/service/generic_zero/index.ts @@ -0,0 +1,212 @@ +import { + Hex, + PrivateKeyAccount, + createWalletClient, + PublicClient, + WalletClient, + createPublicClient, + decodeAbiParameters, + http, +} from "viem"; +import bunyan from "bunyan"; +import { config } from "../../config"; +import { SubnetService } from "../subnet"; +import endpointABI from "../../abi/endpointABI.json"; +import cscABI from "../../abi/cscABI.json"; +import { MainnetService } from "../mainnet"; +import Logger from "bunyan"; +import { privateKeyToAccount } from "viem/accounts"; + +// This class must be called with init() in order to use it + +//Parentnet = chain where zero contract is deployed +//Childnet = chain where data transfer is initiated +// Zero triggers once in a while to to check if there is zero-requests in childnet then store that info into parentnet zero contract +export class GenericZeroService { + private childnetViemClient: PublicClient; + private parentnetViemClient: PublicClient; + private parentnetWalletClient: WalletClient; + private childnetService: SubnetService; + private parentnetService: MainnetService; + private logger: Logger; + private parentnetWalletAccount: PrivateKeyAccount; + private childnetUrl: string; + private parentnetUrl: string; + private subnetZeroAddress: string; + private parentnetZeroAddress: string; + private parentnetCSCAddress: string; + + constructor(logger: bunyan, mode: "reverse" | string ) { + this.logger = logger; + if (mode == "reverse"){ + this.childnetService = new SubnetService(config.mainnet, logger); + this.parentnetService = new MainnetService(config.subnet, logger); + this.childnetUrl = config.mainnet.url; + this.parentnetUrl = config.subnet.url; + this.parentnetCSCAddress = config.subnet.smartContractAddress; + this.subnetZeroAddress = config.xdcZero.parentChainZeroContractAddress; + this.parentnetZeroAddress = config.xdcZero.subnetZeroContractAddress; + this.parentnetWalletAccount = privateKeyToAccount(config.xdcZero.subnetWalletPk as Hex); + } else { + this.childnetService = new SubnetService(config.subnet, logger); + this.parentnetService = new MainnetService(config.mainnet, logger); + this.childnetUrl = config.subnet.url; + this.parentnetUrl = config.mainnet.url; + this.parentnetCSCAddress = config.mainnet.smartContractAddress; + this.subnetZeroAddress = config.xdcZero.subnetZeroContractAddress; + this.parentnetZeroAddress = config.xdcZero.parentChainZeroContractAddress; + this.parentnetWalletAccount = privateKeyToAccount(config.xdcZero.subnetWalletPk as Hex); + } + } + + // Initialise the client services + async init() { + const subnetNetworkInformation = + await this.childnetService.getNetworkInformation(); + const subnetInfo = { + id: subnetNetworkInformation.NetworkId, + name: subnetNetworkInformation.NetworkName, + network: subnetNetworkInformation.NetworkName, + nativeCurrency: { + decimals: 18, + name: subnetNetworkInformation.Denom, + symbol: subnetNetworkInformation.Denom, + }, + rpcUrls: { + public: { http: [this.childnetUrl]}, + default: { http: [this.childnetUrl] }, + }, + }; + + this.childnetViemClient = createPublicClient({ + chain: subnetInfo, + transport: http(), + }); + + const mainnetNetworkInformation = + await this.parentnetService.getNetworkInformation(); + const mainnetInfo = { + id: mainnetNetworkInformation.NetworkId, + name: mainnetNetworkInformation.NetworkName, + network: mainnetNetworkInformation.NetworkName, + nativeCurrency: { + decimals: 18, + name: mainnetNetworkInformation.Denom, + symbol: mainnetNetworkInformation.Denom, + }, + rpcUrls: { + public: { http: [this.parentnetUrl] }, + default: { http: [this.parentnetUrl] }, + }, + }; + + this.parentnetViemClient = createPublicClient({ + chain: mainnetInfo, + transport: http(), + }); + + this.parentnetWalletClient = createWalletClient({ + account: this.parentnetWalletAccount, + chain: mainnetInfo, + transport: http(), + }); + } + + async getPayloads() { + const payloads = [] as any; + const subnetEndpointContract = { + // address: config.xdcZero.subnetZeroContractAddress, + address: this.subnetZeroAddress, + abi: endpointABI, + }; + + const logs = await this.childnetViemClient.getContractEvents({ + ...(subnetEndpointContract as any), + fromBlock: BigInt(0), + eventName: "Packet", + }); + + const parentChainId = await this.parentnetViemClient.getChainId(); + + logs?.forEach((log) => { + const values = decodeAbiParameters( + [ + { name: "index", type: "uint" }, + { name: "sid", type: "uint" }, + { name: "sua", type: "address" }, + { name: "rid", type: "uint" }, + { name: "rua", type: "address" }, + { name: "data", type: "bytes" }, + ], + `0x${log.data.substring(130)}` + ); + + if (Number(values[3]) == parentChainId) { + const list = [...values]; + list.push(log.transactionHash); + list.push(log.blockNumber); + payloads.push(list); + } + }); + + return payloads; + } + + async getIndexFromParentnet() { + const subnetChainId = await this.childnetViemClient.getChainId(); + const parentnetEndpointContract = { + // address: config.xdcZero.parentChainZeroContractAddress, + address: this.parentnetZeroAddress, + abi: endpointABI, + }; + const chain = (await this.parentnetViemClient.readContract({ + ...(parentnetEndpointContract as any), + functionName: "getChain", + args: [subnetChainId], + })) as { lastIndex: number }; + + return chain?.lastIndex; + } + + async getLatestBlockNumberFromCsc() { + const parentnetCSCContract = { + // address: config.mainnet.smartContractAddress, + address: this.parentnetCSCAddress, + abi: cscABI, + }; + const blocks = (await this.parentnetViemClient.readContract({ + ...(parentnetCSCContract as any), + functionName: "getLatestBlocks", + args: [], + })) as [any, any]; + + return blocks[1]?.number; + } + + async getProof(txHash: string) { + return this.childnetService.getTransactionAndReceiptProof(txHash); + } + + async validateTransactionProof( + key: string, + receiptProof: string[], + transactionProof: string[], + blockhash: string + ) { + const parentnetEndpointContract = { + // address: config.xdcZero.parentChainZeroContractAddress, + address: this.parentnetZeroAddress, + abi: endpointABI, + }; + const subnetChainId = await this.childnetViemClient.getChainId(); + const { request } = await this.parentnetViemClient.simulateContract({ + ...(parentnetEndpointContract as any), + functionName: "validateTransactionProof", + args: [subnetChainId, key, receiptProof, transactionProof, blockhash], + account: this.parentnetWalletAccount, + }); + + const tx = await this.parentnetWalletClient.writeContract(request as any); + this.logger.info(tx); + } +} From 38bf19e8a64df7923efadde832e4a2b86c7eb0eb Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Wed, 12 Jun 2024 17:21:36 +0400 Subject: [PATCH 16/21] cleanup --- src/config.ts | 4 ++-- src/processors/full.ts | 1 - src/processors/lite.ts | 1 - src/processors/reverseFull.ts | 5 +---- src/processors/reverseZero.ts | 2 +- src/service/generic_zero/index.ts | 2 +- src/service/zero/index.ts | 4 ++-- 7 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/config.ts b/src/config.ts index 18b567b..cb5e757 100644 --- a/src/config.ts +++ b/src/config.ts @@ -27,7 +27,7 @@ export interface XdcZeroConfig { isEnabled: boolean; subnetZeroContractAddress?: string; parentChainZeroContractAddress?: string; - walletPk?: string; + parentnetWalletPk?: string; subnetWalletPk?: string; } @@ -62,7 +62,7 @@ const getZeroConfig = (): XdcZeroConfig => { isEnabled, subnetZeroContractAddress: process.env.SUBNET_ZERO_CONTRACT, parentChainZeroContractAddress: process.env.PARENTNET_ZERO_CONTRACT, - walletPk: process.env.PARENTNET_ZERO_WALLET_PK.startsWith("0x") ? process.env.PARENTNET_ZERO_WALLET_PK : `0x${process.env.PARENTNET_ZERO_WALLET_PK}`, + parentnetWalletPk: process.env.PARENTNET_ZERO_WALLET_PK.startsWith("0x") ? process.env.PARENTNET_ZERO_WALLET_PK : `0x${process.env.PARENTNET_ZERO_WALLET_PK}`, subnetWalletPk: process.env.SUBNET_WALLET_PK.startsWith("0x") ? process.env.SUBNET_WALLET_PK : `0x${process.env.SUBNET_WALLET_PK}` }: { isEnabled: false }; }; diff --git a/src/processors/full.ts b/src/processors/full.ts index 67bdfee..c331cbf 100644 --- a/src/processors/full.ts +++ b/src/processors/full.ts @@ -27,7 +27,6 @@ export class Full extends BaseProcessor { init() { this.logger.info("Initialising XDC relayer"); - //TODO: check CSC mode is correct at init this.queue.process(async (_, done) => { this.logger.info("⏰ Full Relayer: Executing normal flow periodically"); diff --git a/src/processors/lite.ts b/src/processors/lite.ts index 2fda866..d9ec42c 100644 --- a/src/processors/lite.ts +++ b/src/processors/lite.ts @@ -22,7 +22,6 @@ export class Lite extends BaseProcessor { init() { this.logger.info("Initialising XDC Lite relayer"); - //TODO: check CSC mode is correct at init this.queue.process(async (_, done) => { this.logger.info("⏰ Executing lite flow periodically"); diff --git a/src/processors/reverseFull.ts b/src/processors/reverseFull.ts index 295be25..03ee27a 100644 --- a/src/processors/reverseFull.ts +++ b/src/processors/reverseFull.ts @@ -7,7 +7,7 @@ import { ForkingError } from "../errors/forkingError"; import { BaseProcessor } from "./base"; const chunkByMaxFetchSize = chunkBy(config.chunkSize); -export const NAME = "REVERSE-FULL"; +export const NAME = "REVERSE_FULL"; const REPEAT_JOB_OPT = { jobId: NAME, repeat: { cron: config.cronJob.jobExpression}}; export class ReverseFull extends BaseProcessor { private mainnetService: MainnetService; @@ -27,7 +27,6 @@ export class ReverseFull extends BaseProcessor { init() { this.logger.info("Initialising Reverse XDC relayer"); - //TODO: check CSC mode is correct at init this.queue.process(async (_, done) => { this.logger.info("⏰ Reverse Relayer: Executing normal flow periodically"); @@ -200,9 +199,7 @@ export class ReverseFull extends BaseProcessor { heightToSearchFrom: number ): Promise<{ divergingHeight: number; divergingHash: string }> { let currentHeight = heightToSearchFrom; - // let mainnetHash: string; let subnetHash: string; - // let subnetBlockInfo: SubnetBlockInfo; let mainnetBlockInfo: MainnetBlockInfo; while (currentHeight > 0) { diff --git a/src/processors/reverseZero.ts b/src/processors/reverseZero.ts index acdfd5b..0e353ee 100644 --- a/src/processors/reverseZero.ts +++ b/src/processors/reverseZero.ts @@ -5,7 +5,7 @@ import { config } from "../config"; import { BaseProcessor } from "./base"; import { GenericZeroService } from "../service/generic_zero"; -export const NAME = "REVERSE-ZERO"; +export const NAME = "REVERSE_ZERO"; const REPEAT_JOB_OPT = { jobId: NAME, repeat: { cron: config.cronJob.zeroJobExpression }, diff --git a/src/service/generic_zero/index.ts b/src/service/generic_zero/index.ts index 1fade98..5e1f153 100644 --- a/src/service/generic_zero/index.ts +++ b/src/service/generic_zero/index.ts @@ -55,7 +55,7 @@ export class GenericZeroService { this.parentnetCSCAddress = config.mainnet.smartContractAddress; this.subnetZeroAddress = config.xdcZero.subnetZeroContractAddress; this.parentnetZeroAddress = config.xdcZero.parentChainZeroContractAddress; - this.parentnetWalletAccount = privateKeyToAccount(config.xdcZero.subnetWalletPk as Hex); + this.parentnetWalletAccount = privateKeyToAccount(config.xdcZero.parentnetWalletPk as Hex); } } diff --git a/src/service/zero/index.ts b/src/service/zero/index.ts index 5cbdc54..a0b5cb1 100644 --- a/src/service/zero/index.ts +++ b/src/service/zero/index.ts @@ -36,9 +36,9 @@ export class ZeroService { // Initialise the client services async init() { - if (config.xdcZero.walletPk) { + if (config.xdcZero.parentnetWalletPk) { this.parentChainWalletAccount = privateKeyToAccount( - config.xdcZero.walletPk as Hex + config.xdcZero.parentnetWalletPk as Hex ); } From f612ce86d76ca5547fc6d428f55980c801edc63c Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Wed, 12 Jun 2024 18:32:56 +0400 Subject: [PATCH 17/21] throw error to prevent bug --- src/service/mainnet/index.ts | 1 + src/service/subnet/index.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/service/mainnet/index.ts b/src/service/mainnet/index.ts index c79ba98..413715f 100644 --- a/src/service/mainnet/index.ts +++ b/src/service/mainnet/index.ts @@ -238,6 +238,7 @@ export class MainnetService { } }).catch((error) => { this.logger.error("Axios Fetching Error:", error); + throw error; }); return blockInfoList; } diff --git a/src/service/subnet/index.ts b/src/service/subnet/index.ts index a3cae3f..7baef40 100644 --- a/src/service/subnet/index.ts +++ b/src/service/subnet/index.ts @@ -87,6 +87,7 @@ export class SubnetService { } }).catch((error) => { this.logger.error("Axios Fetching Error:", error); + throw error; }); return blockInfoList; } From 71ea37739a27bd27619cfb05936eebc7f5d77bf0 Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Wed, 12 Jun 2024 18:33:39 +0400 Subject: [PATCH 18/21] better logs --- src/service/mainnet/index.ts | 2 +- src/service/subnet/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/mainnet/index.ts b/src/service/mainnet/index.ts index 413715f..03525a8 100644 --- a/src/service/mainnet/index.ts +++ b/src/service/mainnet/index.ts @@ -237,7 +237,7 @@ export class MainnetService { }); } }).catch((error) => { - this.logger.error("Axios Fetching Error:", error); + this.logger.error("Axios Parentnet Fetching Error:", error); throw error; }); return blockInfoList; diff --git a/src/service/subnet/index.ts b/src/service/subnet/index.ts index 7baef40..a7cda13 100644 --- a/src/service/subnet/index.ts +++ b/src/service/subnet/index.ts @@ -86,7 +86,7 @@ export class SubnetService { }); } }).catch((error) => { - this.logger.error("Axios Fetching Error:", error); + this.logger.error("Axios Subnet Fetching Error:", error); throw error; }); return blockInfoList; From 6a55af9cbf0e83ac6bac42db77c6ddb215ac522c Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Wed, 12 Jun 2024 18:39:50 +0400 Subject: [PATCH 19/21] add explanation --- src/config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config.ts b/src/config.ts index cb5e757..8894dcd 100644 --- a/src/config.ts +++ b/src/config.ts @@ -45,10 +45,10 @@ export interface Config { notification: NotificationConfig; chunkSize: number; xdcZero: XdcZeroConfig; - relayerCsc: { + relayerCsc: { //Checkpoint Smart Contract is deployed on the Parentnet and stores Subnet data, check https://github.com/XinFinOrg/XDC-CSC isEnabled: boolean; } - reverseRelayerCsc:{ + reverseRelayerCsc:{ //Reverse Checkpoint Smart Contract is deployed in the Subnet and stores Parentnet data, check https://github.com/XinFinOrg/XDC-CSC isEnabled: boolean; } } From 94f19aaf28351a284d971514ab3157aeeb7d64cc Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Wed, 12 Jun 2024 18:43:43 +0400 Subject: [PATCH 20/21] GenericZero > ZeroService --- src/processors/reverseZero.ts | 8 +- src/processors/zero.ts | 7 +- src/service/generic_zero/index.ts | 212 ------------------------------ src/service/reverse_zero/index.ts | 203 ---------------------------- src/service/zero/index.ts | 105 +++++++++------ 5 files changed, 70 insertions(+), 465 deletions(-) delete mode 100644 src/service/generic_zero/index.ts delete mode 100644 src/service/reverse_zero/index.ts diff --git a/src/processors/reverseZero.ts b/src/processors/reverseZero.ts index 0e353ee..0f4f0ed 100644 --- a/src/processors/reverseZero.ts +++ b/src/processors/reverseZero.ts @@ -1,9 +1,7 @@ import bunyan from "bunyan"; -import { ZeroService } from "../service/zero"; -import { ReverseZeroService } from "../service/reverse_zero"; +import { ZeroService } from "../service/zero/index"; import { config } from "../config"; import { BaseProcessor } from "./base"; -import { GenericZeroService } from "../service/generic_zero"; export const NAME = "REVERSE_ZERO"; const REPEAT_JOB_OPT = { @@ -13,12 +11,12 @@ const REPEAT_JOB_OPT = { export class ReverseZero extends BaseProcessor { private logger: bunyan; - private zeroService: GenericZeroService; + private zeroService: ZeroService; constructor(logger: bunyan) { super(NAME); this.logger = logger; - this.zeroService = new GenericZeroService(logger, "reverse"); + this.zeroService = new ZeroService(logger, "reverse"); } init() { this.logger.info("Initialising Reverse XDC-Zero"); diff --git a/src/processors/zero.ts b/src/processors/zero.ts index 60a4f67..6fd10ca 100644 --- a/src/processors/zero.ts +++ b/src/processors/zero.ts @@ -1,8 +1,7 @@ import bunyan from "bunyan"; -import { ZeroService } from "../service/zero"; +import { ZeroService } from "../service/zero/index"; import { config } from "../config"; import { BaseProcessor } from "./base"; -import { GenericZeroService } from "../service/generic_zero"; export const NAME = "ZERO"; const REPEAT_JOB_OPT = { @@ -12,12 +11,12 @@ const REPEAT_JOB_OPT = { export class Zero extends BaseProcessor { private logger: bunyan; - private zeroService: GenericZeroService; + private zeroService: ZeroService; constructor(logger: bunyan) { super(NAME); this.logger = logger; - this.zeroService = new GenericZeroService(logger, "normal"); + this.zeroService = new ZeroService(logger, "normal"); } init() { this.logger.info("Initialising XDC-Zero"); diff --git a/src/service/generic_zero/index.ts b/src/service/generic_zero/index.ts deleted file mode 100644 index 5e1f153..0000000 --- a/src/service/generic_zero/index.ts +++ /dev/null @@ -1,212 +0,0 @@ -import { - Hex, - PrivateKeyAccount, - createWalletClient, - PublicClient, - WalletClient, - createPublicClient, - decodeAbiParameters, - http, -} from "viem"; -import bunyan from "bunyan"; -import { config } from "../../config"; -import { SubnetService } from "../subnet"; -import endpointABI from "../../abi/endpointABI.json"; -import cscABI from "../../abi/cscABI.json"; -import { MainnetService } from "../mainnet"; -import Logger from "bunyan"; -import { privateKeyToAccount } from "viem/accounts"; - -// This class must be called with init() in order to use it - -//Parentnet = chain where zero contract is deployed -//Childnet = chain where data transfer is initiated -// Zero triggers once in a while to to check if there is zero-requests in childnet then store that info into parentnet zero contract -export class GenericZeroService { - private childnetViemClient: PublicClient; - private parentnetViemClient: PublicClient; - private parentnetWalletClient: WalletClient; - private childnetService: SubnetService; - private parentnetService: MainnetService; - private logger: Logger; - private parentnetWalletAccount: PrivateKeyAccount; - private childnetUrl: string; - private parentnetUrl: string; - private subnetZeroAddress: string; - private parentnetZeroAddress: string; - private parentnetCSCAddress: string; - - constructor(logger: bunyan, mode: "reverse" | string ) { - this.logger = logger; - if (mode == "reverse"){ - this.childnetService = new SubnetService(config.mainnet, logger); - this.parentnetService = new MainnetService(config.subnet, logger); - this.childnetUrl = config.mainnet.url; - this.parentnetUrl = config.subnet.url; - this.parentnetCSCAddress = config.subnet.smartContractAddress; - this.subnetZeroAddress = config.xdcZero.parentChainZeroContractAddress; - this.parentnetZeroAddress = config.xdcZero.subnetZeroContractAddress; - this.parentnetWalletAccount = privateKeyToAccount(config.xdcZero.subnetWalletPk as Hex); - } else { - this.childnetService = new SubnetService(config.subnet, logger); - this.parentnetService = new MainnetService(config.mainnet, logger); - this.childnetUrl = config.subnet.url; - this.parentnetUrl = config.mainnet.url; - this.parentnetCSCAddress = config.mainnet.smartContractAddress; - this.subnetZeroAddress = config.xdcZero.subnetZeroContractAddress; - this.parentnetZeroAddress = config.xdcZero.parentChainZeroContractAddress; - this.parentnetWalletAccount = privateKeyToAccount(config.xdcZero.parentnetWalletPk as Hex); - } - } - - // Initialise the client services - async init() { - const subnetNetworkInformation = - await this.childnetService.getNetworkInformation(); - const subnetInfo = { - id: subnetNetworkInformation.NetworkId, - name: subnetNetworkInformation.NetworkName, - network: subnetNetworkInformation.NetworkName, - nativeCurrency: { - decimals: 18, - name: subnetNetworkInformation.Denom, - symbol: subnetNetworkInformation.Denom, - }, - rpcUrls: { - public: { http: [this.childnetUrl]}, - default: { http: [this.childnetUrl] }, - }, - }; - - this.childnetViemClient = createPublicClient({ - chain: subnetInfo, - transport: http(), - }); - - const mainnetNetworkInformation = - await this.parentnetService.getNetworkInformation(); - const mainnetInfo = { - id: mainnetNetworkInformation.NetworkId, - name: mainnetNetworkInformation.NetworkName, - network: mainnetNetworkInformation.NetworkName, - nativeCurrency: { - decimals: 18, - name: mainnetNetworkInformation.Denom, - symbol: mainnetNetworkInformation.Denom, - }, - rpcUrls: { - public: { http: [this.parentnetUrl] }, - default: { http: [this.parentnetUrl] }, - }, - }; - - this.parentnetViemClient = createPublicClient({ - chain: mainnetInfo, - transport: http(), - }); - - this.parentnetWalletClient = createWalletClient({ - account: this.parentnetWalletAccount, - chain: mainnetInfo, - transport: http(), - }); - } - - async getPayloads() { - const payloads = [] as any; - const subnetEndpointContract = { - // address: config.xdcZero.subnetZeroContractAddress, - address: this.subnetZeroAddress, - abi: endpointABI, - }; - - const logs = await this.childnetViemClient.getContractEvents({ - ...(subnetEndpointContract as any), - fromBlock: BigInt(0), - eventName: "Packet", - }); - - const parentChainId = await this.parentnetViemClient.getChainId(); - - logs?.forEach((log) => { - const values = decodeAbiParameters( - [ - { name: "index", type: "uint" }, - { name: "sid", type: "uint" }, - { name: "sua", type: "address" }, - { name: "rid", type: "uint" }, - { name: "rua", type: "address" }, - { name: "data", type: "bytes" }, - ], - `0x${log.data.substring(130)}` - ); - - if (Number(values[3]) == parentChainId) { - const list = [...values]; - list.push(log.transactionHash); - list.push(log.blockNumber); - payloads.push(list); - } - }); - - return payloads; - } - - async getIndexFromParentnet() { - const subnetChainId = await this.childnetViemClient.getChainId(); - const parentnetEndpointContract = { - // address: config.xdcZero.parentChainZeroContractAddress, - address: this.parentnetZeroAddress, - abi: endpointABI, - }; - const chain = (await this.parentnetViemClient.readContract({ - ...(parentnetEndpointContract as any), - functionName: "getChain", - args: [subnetChainId], - })) as { lastIndex: number }; - - return chain?.lastIndex; - } - - async getLatestBlockNumberFromCsc() { - const parentnetCSCContract = { - // address: config.mainnet.smartContractAddress, - address: this.parentnetCSCAddress, - abi: cscABI, - }; - const blocks = (await this.parentnetViemClient.readContract({ - ...(parentnetCSCContract as any), - functionName: "getLatestBlocks", - args: [], - })) as [any, any]; - - return blocks[1]?.number; - } - - async getProof(txHash: string) { - return this.childnetService.getTransactionAndReceiptProof(txHash); - } - - async validateTransactionProof( - key: string, - receiptProof: string[], - transactionProof: string[], - blockhash: string - ) { - const parentnetEndpointContract = { - // address: config.xdcZero.parentChainZeroContractAddress, - address: this.parentnetZeroAddress, - abi: endpointABI, - }; - const subnetChainId = await this.childnetViemClient.getChainId(); - const { request } = await this.parentnetViemClient.simulateContract({ - ...(parentnetEndpointContract as any), - functionName: "validateTransactionProof", - args: [subnetChainId, key, receiptProof, transactionProof, blockhash], - account: this.parentnetWalletAccount, - }); - - const tx = await this.parentnetWalletClient.writeContract(request as any); - this.logger.info(tx); - } -} diff --git a/src/service/reverse_zero/index.ts b/src/service/reverse_zero/index.ts deleted file mode 100644 index ad98b6c..0000000 --- a/src/service/reverse_zero/index.ts +++ /dev/null @@ -1,203 +0,0 @@ -import { - Hex, - PrivateKeyAccount, - createWalletClient, - PublicClient, - WalletClient, - createPublicClient, - decodeAbiParameters, - http, -} from "viem"; -import bunyan from "bunyan"; -import { config } from "../../config"; -import { SubnetService } from "../subnet"; -import endpointABI from "../../abi/endpointABI.json"; -import cscABI from "../../abi/cscABI.json"; -import { MainnetService } from "../mainnet"; -import Logger from "bunyan"; -import { privateKeyToAccount } from "viem/accounts"; - -// This class must be called with init() in order to use it -export class ReverseZeroService { - private subnetViemClient: PublicClient; - private mainnetViemClient: PublicClient; - private mainnetWalletClient: WalletClient; - private subnetService: SubnetService; - private mainnetService: MainnetService; - private logger: Logger; - - private parentChainWalletAccount: PrivateKeyAccount; - - private zeroWalletPk: PrivateKeyAccount; - private subnetUrl: string; - private parentnetUrl: string; - private subnetZeroAddress: string; - private parentnetZeroAddress: string; - private subnetCSCAddress: string; - private parentnetCSCAddress: string; - - constructor(logger: bunyan) { - this.subnetService = new SubnetService(config.mainnet, logger); //TODO: temp swap - this.mainnetService = new MainnetService(config.subnet, logger); //TODO: fix temp swap - this.subnetUrl = config.mainnet.url; - this.parentnetUrl = config.subnet.url; - this.subnetCSCAddress = config.mainnet.smartContractAddress; - this.parentnetCSCAddress = config.subnet.smartContractAddress; - this.subnetZeroAddress = config.xdcZero.parentChainZeroContractAddress; - this.parentnetZeroAddress = config.xdcZero.subnetZeroContractAddress; - - this.logger = logger; - this.parentChainWalletAccount = privateKeyToAccount(config.xdcZero.subnetWalletPk as Hex); - } - - // Initialise the client services - async init() { - const subnetNetworkInformation = - await this.subnetService.getNetworkInformation(); - const subnetInfo = { - id: subnetNetworkInformation.NetworkId, - name: subnetNetworkInformation.NetworkName, - network: subnetNetworkInformation.NetworkName, - nativeCurrency: { - decimals: 18, - name: subnetNetworkInformation.Denom, - symbol: subnetNetworkInformation.Denom, - }, - rpcUrls: { - public: { http: [this.subnetUrl]}, - default: { http: [this.subnetUrl] }, - }, - }; - - this.subnetViemClient = createPublicClient({ - chain: subnetInfo, - transport: http(), - }); - - const mainnetNetworkInformation = - await this.mainnetService.getNetworkInformation(); - const mainnetInfo = { - id: mainnetNetworkInformation.NetworkId, - name: mainnetNetworkInformation.NetworkName, - network: mainnetNetworkInformation.NetworkName, - nativeCurrency: { - decimals: 18, - name: mainnetNetworkInformation.Denom, - symbol: mainnetNetworkInformation.Denom, - }, - rpcUrls: { - public: { http: [this.parentnetUrl] }, - default: { http: [this.parentnetUrl] }, - }, - }; - - this.mainnetViemClient = createPublicClient({ - chain: mainnetInfo, - transport: http(), - }); - - this.mainnetWalletClient = createWalletClient({ - account: this.parentChainWalletAccount, - chain: mainnetInfo, - transport: http(), - }); - } - - async getPayloads() { - const payloads = [] as any; - const subnetEndpointContract = { - // address: config.xdcZero.subnetZeroContractAddress, - address: this.subnetZeroAddress, - abi: endpointABI, - }; - - const logs = await this.subnetViemClient.getContractEvents({ - ...(subnetEndpointContract as any), - fromBlock: BigInt(0), - eventName: "Packet", - }); - - const parentChainId = await this.mainnetViemClient.getChainId(); - - logs?.forEach((log) => { - const values = decodeAbiParameters( - [ - { name: "index", type: "uint" }, - { name: "sid", type: "uint" }, - { name: "sua", type: "address" }, - { name: "rid", type: "uint" }, - { name: "rua", type: "address" }, - { name: "data", type: "bytes" }, - ], - `0x${log.data.substring(130)}` - ); - - if (Number(values[3]) == parentChainId) { - const list = [...values]; - list.push(log.transactionHash); - list.push(log.blockNumber); - payloads.push(list); - } - }); - - return payloads; - } - - async getIndexFromParentnet() { - const subnetChainId = await this.subnetViemClient.getChainId(); - const parentnetEndpointContract = { - // address: config.xdcZero.parentChainZeroContractAddress, - address: this.parentnetZeroAddress, - abi: endpointABI, - }; - const chain = (await this.mainnetViemClient.readContract({ - ...(parentnetEndpointContract as any), - functionName: "getChain", - args: [subnetChainId], - })) as { lastIndex: number }; - - return chain?.lastIndex; - } - - async getLatestBlockNumberFromCsc() { - const parentnetCSCContract = { - // address: config.mainnet.smartContractAddress, - address: this.parentnetCSCAddress, - abi: cscABI, - }; - const blocks = (await this.mainnetViemClient.readContract({ - ...(parentnetCSCContract as any), - functionName: "getLatestBlocks", - args: [], - })) as [any, any]; - - return blocks[1]?.number; - } - - async getProof(txHash: string) { - return this.subnetService.getTransactionAndReceiptProof(txHash); - } - - async validateTransactionProof( - key: string, - receiptProof: string[], - transactionProof: string[], - blockhash: string - ) { - const parentnetEndpointContract = { - // address: config.xdcZero.parentChainZeroContractAddress, - address: this.parentnetZeroAddress, - abi: endpointABI, - }; - const subnetChainId = await this.subnetViemClient.getChainId(); - const { request } = await this.mainnetViemClient.simulateContract({ - ...(parentnetEndpointContract as any), - functionName: "validateTransactionProof", - args: [subnetChainId, key, receiptProof, transactionProof, blockhash], - account: this.parentChainWalletAccount, - }); - - const tx = await this.mainnetWalletClient.writeContract(request as any); - this.logger.info(tx); - } -} diff --git a/src/service/zero/index.ts b/src/service/zero/index.ts index a0b5cb1..772fdcb 100644 --- a/src/service/zero/index.ts +++ b/src/service/zero/index.ts @@ -18,32 +18,51 @@ import Logger from "bunyan"; import { privateKeyToAccount } from "viem/accounts"; // This class must be called with init() in order to use it + +//Parentnet = chain where zero contract is deployed +//Childnet = chain where data transfer is initiated +// Zero triggers once in a while to to check if there is zero-requests in childnet then store that info into parentnet zero contract export class ZeroService { - private subnetViemClient: PublicClient; - private mainnetViemClient: PublicClient; - private mainnetWalletClient: WalletClient; - private subnetService: SubnetService; - private mainnetService: MainnetService; + private childnetViemClient: PublicClient; + private parentnetViemClient: PublicClient; + private parentnetWalletClient: WalletClient; + private childnetService: SubnetService; + private parentnetService: MainnetService; private logger: Logger; - - private parentChainWalletAccount: PrivateKeyAccount; - - constructor(logger: bunyan) { - this.subnetService = new SubnetService(config.subnet, logger); - this.mainnetService = new MainnetService(config.mainnet, logger); + private parentnetWalletAccount: PrivateKeyAccount; + private childnetUrl: string; + private parentnetUrl: string; + private subnetZeroAddress: string; + private parentnetZeroAddress: string; + private parentnetCSCAddress: string; + + constructor(logger: bunyan, mode: "reverse" | string ) { this.logger = logger; + if (mode == "reverse"){ + this.childnetService = new SubnetService(config.mainnet, logger); + this.parentnetService = new MainnetService(config.subnet, logger); + this.childnetUrl = config.mainnet.url; + this.parentnetUrl = config.subnet.url; + this.parentnetCSCAddress = config.subnet.smartContractAddress; + this.subnetZeroAddress = config.xdcZero.parentChainZeroContractAddress; + this.parentnetZeroAddress = config.xdcZero.subnetZeroContractAddress; + this.parentnetWalletAccount = privateKeyToAccount(config.xdcZero.subnetWalletPk as Hex); + } else { + this.childnetService = new SubnetService(config.subnet, logger); + this.parentnetService = new MainnetService(config.mainnet, logger); + this.childnetUrl = config.subnet.url; + this.parentnetUrl = config.mainnet.url; + this.parentnetCSCAddress = config.mainnet.smartContractAddress; + this.subnetZeroAddress = config.xdcZero.subnetZeroContractAddress; + this.parentnetZeroAddress = config.xdcZero.parentChainZeroContractAddress; + this.parentnetWalletAccount = privateKeyToAccount(config.xdcZero.parentnetWalletPk as Hex); + } } // Initialise the client services async init() { - if (config.xdcZero.parentnetWalletPk) { - this.parentChainWalletAccount = privateKeyToAccount( - config.xdcZero.parentnetWalletPk as Hex - ); - } - const subnetNetworkInformation = - await this.subnetService.getNetworkInformation(); + await this.childnetService.getNetworkInformation(); const subnetInfo = { id: subnetNetworkInformation.NetworkId, name: subnetNetworkInformation.NetworkName, @@ -54,18 +73,18 @@ export class ZeroService { symbol: subnetNetworkInformation.Denom, }, rpcUrls: { - public: { http: [config.subnet.url] }, - default: { http: [config.subnet.url] }, + public: { http: [this.childnetUrl]}, + default: { http: [this.childnetUrl] }, }, }; - this.subnetViemClient = createPublicClient({ + this.childnetViemClient = createPublicClient({ chain: subnetInfo, transport: http(), }); const mainnetNetworkInformation = - await this.mainnetService.getNetworkInformation(); + await this.parentnetService.getNetworkInformation(); const mainnetInfo = { id: mainnetNetworkInformation.NetworkId, name: mainnetNetworkInformation.NetworkName, @@ -76,18 +95,18 @@ export class ZeroService { symbol: mainnetNetworkInformation.Denom, }, rpcUrls: { - public: { http: [config.mainnet.url] }, - default: { http: [config.mainnet.url] }, + public: { http: [this.parentnetUrl] }, + default: { http: [this.parentnetUrl] }, }, }; - this.mainnetViemClient = createPublicClient({ + this.parentnetViemClient = createPublicClient({ chain: mainnetInfo, transport: http(), }); - this.mainnetWalletClient = createWalletClient({ - account: this.parentChainWalletAccount, + this.parentnetWalletClient = createWalletClient({ + account: this.parentnetWalletAccount, chain: mainnetInfo, transport: http(), }); @@ -96,17 +115,18 @@ export class ZeroService { async getPayloads() { const payloads = [] as any; const subnetEndpointContract = { - address: config.xdcZero.subnetZeroContractAddress, + // address: config.xdcZero.subnetZeroContractAddress, + address: this.subnetZeroAddress, abi: endpointABI, }; - const logs = await this.subnetViemClient.getContractEvents({ + const logs = await this.childnetViemClient.getContractEvents({ ...(subnetEndpointContract as any), fromBlock: BigInt(0), eventName: "Packet", }); - const parentChainId = await this.mainnetViemClient.getChainId(); + const parentChainId = await this.parentnetViemClient.getChainId(); logs?.forEach((log) => { const values = decodeAbiParameters( @@ -133,12 +153,13 @@ export class ZeroService { } async getIndexFromParentnet() { - const subnetChainId = await this.subnetViemClient.getChainId(); + const subnetChainId = await this.childnetViemClient.getChainId(); const parentnetEndpointContract = { - address: config.xdcZero.parentChainZeroContractAddress, + // address: config.xdcZero.parentChainZeroContractAddress, + address: this.parentnetZeroAddress, abi: endpointABI, }; - const chain = (await this.mainnetViemClient.readContract({ + const chain = (await this.parentnetViemClient.readContract({ ...(parentnetEndpointContract as any), functionName: "getChain", args: [subnetChainId], @@ -149,10 +170,11 @@ export class ZeroService { async getLatestBlockNumberFromCsc() { const parentnetCSCContract = { - address: config.mainnet.smartContractAddress, + // address: config.mainnet.smartContractAddress, + address: this.parentnetCSCAddress, abi: cscABI, }; - const blocks = (await this.mainnetViemClient.readContract({ + const blocks = (await this.parentnetViemClient.readContract({ ...(parentnetCSCContract as any), functionName: "getLatestBlocks", args: [], @@ -162,7 +184,7 @@ export class ZeroService { } async getProof(txHash: string) { - return this.subnetService.getTransactionAndReceiptProof(txHash); + return this.childnetService.getTransactionAndReceiptProof(txHash); } async validateTransactionProof( @@ -172,18 +194,19 @@ export class ZeroService { blockhash: string ) { const parentnetEndpointContract = { - address: config.xdcZero.parentChainZeroContractAddress, + // address: config.xdcZero.parentChainZeroContractAddress, + address: this.parentnetZeroAddress, abi: endpointABI, }; - const subnetChainId = await this.subnetViemClient.getChainId(); - const { request } = await this.mainnetViemClient.simulateContract({ + const subnetChainId = await this.childnetViemClient.getChainId(); + const { request } = await this.parentnetViemClient.simulateContract({ ...(parentnetEndpointContract as any), functionName: "validateTransactionProof", args: [subnetChainId, key, receiptProof, transactionProof, blockhash], - account: this.parentChainWalletAccount, + account: this.parentnetWalletAccount, }); - const tx = await this.mainnetWalletClient.writeContract(request as any); + const tx = await this.parentnetWalletClient.writeContract(request as any); this.logger.info(tx); } } From d09e84920ccb90f5074b6e0a7b630db7fbce99c0 Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Thu, 13 Jun 2024 11:27:03 +0400 Subject: [PATCH 21/21] log --- src/processors/reverseZero.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/processors/reverseZero.ts b/src/processors/reverseZero.ts index 0f4f0ed..a349672 100644 --- a/src/processors/reverseZero.ts +++ b/src/processors/reverseZero.ts @@ -44,7 +44,7 @@ export class ReverseZero extends BaseProcessor { async processEvent() { const payloads = await this.zeroService.getPayloads(); if (payloads.length == 0) { - const msg = "Nothing to process in xdc-zero, wait for the next event log"; + const msg = "Nothing to process in reverse xdc-zero, wait for the next event log"; this.logger.info(msg); return msg; }