From a25aad9fac293a7c073d3999a1d8c79d753f2f73 Mon Sep 17 00:00:00 2001 From: Siegfried Puchbauer Date: Fri, 14 Aug 2020 18:42:52 -0700 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20Support=20for=20Quorum?= =?UTF-8?q?=20private=20transaction=20payload?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A new settings enables ethlogger to fetch decrypted information for private transactions. This also enables ABI decoding of the data. --- config.schema.json | 4 + defaults.ethlogger.yaml | 1 + docs/cli.md | 5 + docs/configuration.md | 17 +-- src/blockwatcher.ts | 116 +++++++++++------- src/cliflags.ts | 5 + src/config.ts | 10 ++ src/eth/requests.ts | 7 +- src/format.ts | 5 +- src/index.ts | 6 +- src/msgs.ts | 7 ++ src/platforms/index.ts | 13 +- src/platforms/mock.ts | 9 ++ src/platforms/quorum.ts | 25 +++- test/__snapshots__/blockwatcher.test.ts.snap | 23 ++++ .../__snapshots__/ethdenver.test.ts.snap | 1 + test/abi/testcases/ethdenver.test.ts | 15 ++- test/abi/testcases/ost.test.ts | 15 ++- test/blockwatcher.test.ts | 15 ++- test/config.test.ts | 2 + test/failures/mainnet_overflow.test.ts | 15 ++- test/format.test.ts | 1 + 22 files changed, 237 insertions(+), 80 deletions(-) create mode 100644 src/platforms/mock.ts diff --git a/config.schema.json b/config.schema.json index 07667bc..357c4cc 100644 --- a/config.schema.json +++ b/config.schema.json @@ -38,6 +38,10 @@ "description": "Max. number of blocks to fetch at once", "type": "number" }, + "decryptPrivateTransactions": { + "description": "For chains/nodes that do support private transcations, this settings instructs block watcher to\nattempt to load the decrypted payload for private transactions", + "type": "boolean" + }, "enabled": { "description": "Specify `false` to disable the block watcher", "type": "boolean" diff --git a/defaults.ethlogger.yaml b/defaults.ethlogger.yaml index 6366598..754d1f1 100644 --- a/defaults.ethlogger.yaml +++ b/defaults.ethlogger.yaml @@ -73,6 +73,7 @@ blockWatcher: blocksMaxChunkSize: 25 maxParallelChunks: 3 startAt: genesis + decryptPrivateTransactions: false retryWaitTime: type: linear-backoff min: 0 diff --git a/docs/cli.md b/docs/cli.md index 705aba3..3d4b196 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -53,6 +53,10 @@ OPTIONS --debug Enable debug log output + --decrypt-private-txs + Enable to download decrypted content of private transactions (only available + for Quorum at the moment) + --[no-]eth-reject-invalid-certs Disable to allow ethereum client to connect to HTTPS without rejecting invalid (self-signed) certificates @@ -146,6 +150,7 @@ OPTIONS | `ETH_REJECT_INVALID_CERTS` | `boolean` | Disable to allow ethereum client to connect to HTTPS without rejecting invalid (self-signed) certificates | | `ABI_DIR` | `string` | Directory containing ABI definitions (JSON files). This directory will be searched recursively | | `START_AT_BLOCK` | `string` | First block to start ingesting from. Possible values are "genesis", "latest", an absolute block number or a negative number describing how many blocks before the latest one to start at | +| `DECRYPT_PRIVATE_TXS` | `boolean` | Enable to download decrypted content of private transactions (only available for Quorum at the moment) | | `REJECT_INVALID_CERTS` | `boolean` | Disable to allow all HTTP clients (HEC and ETH) to connect to HTTPS without rejecting invalid (self-signed) certificates | | `NETWORK_NAME` | `string` | The network name will be attached to all events sent to Splunk. This is typically either "mainnet" or "testnet". | | `CHAIN_NAME` | `string` | The name of the chain that will be attached to all events sent to Splunk | diff --git a/docs/configuration.md b/docs/configuration.md index 7791990..d19517c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -233,14 +233,15 @@ Ethlogger checks for each address it encounters whether it is a smart contract b Block watcher is the component that retrieves blocks, transactions, event logs from the node and sends them to output. -| Name | Type | Description | -| -------------------- | --------------------------- | ------------------------------------------------------------------------------------------------- | -| `enabled` | `boolean` | Specify `false` to disable the block watcher | -| `pollInterval` | [`Duration`](#Duration) | Interval in which to look for the latest block number (if not busy processing the backlog) | -| `blocksMaxChunkSize` | `number` | Max. number of blocks to fetch at once | -| `maxParallelChunks` | `number` | Max. number of chunks to process in parallel | -| `startAt` | [`StartBlock`](#StartBlock) | If no checkpoint exists (yet), this specifies which block should be chosen as the starting point. | -| `retryWaitTime` | [`WaitTime`](#WaitTime) | Wait time before retrying to fetch and process blocks after failure | +| Name | Type | Description | +| ---------------------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `enabled` | `boolean` | Specify `false` to disable the block watcher | +| `pollInterval` | [`Duration`](#Duration) | Interval in which to look for the latest block number (if not busy processing the backlog) | +| `blocksMaxChunkSize` | `number` | Max. number of blocks to fetch at once | +| `maxParallelChunks` | `number` | Max. number of chunks to process in parallel | +| `startAt` | [`StartBlock`](#StartBlock) | If no checkpoint exists (yet), this specifies which block should be chosen as the starting point. | +| `retryWaitTime` | [`WaitTime`](#WaitTime) | Wait time before retrying to fetch and process blocks after failure | +| `decryptPrivateTransactions` | `boolean` | For chains/nodes that do support private transcations, this settings instructs block watcher to attempt to load the decrypted payload for private transactions | ### NodeMetrics diff --git a/src/blockwatcher.ts b/src/blockwatcher.ts index ccdea72..46e9e48 100644 --- a/src/blockwatcher.ts +++ b/src/blockwatcher.ts @@ -2,12 +2,14 @@ import { ContractInfo, getContractInfo } from './abi/contract'; import { AbiRepository } from './abi/repo'; import { BlockRange, blockRangeSize, blockRangeToArray, chunkedBlockRanges, serializeBlockRange } from './blockrange'; import { Checkpoint } from './checkpoint'; +import { BlockWatcherConfig } from './config'; import { EthereumClient } from './eth/client'; import { blockNumber, getBlock, getTransactionReceipt } from './eth/requests'; import { RawBlockResponse, RawLogResponse, RawTransactionResponse } from './eth/responses'; import { formatBlock, formatLogEvent, formatTransaction } from './format'; -import { Address, AddressInfo, FormattedBlock, LogEventMessage } from './msgs'; +import { Address, AddressInfo, FormattedBlock, LogEventMessage, PrivateTransactionPayload } from './msgs'; import { Output, OutputMessage } from './output'; +import { isEnterprisePlatform, NodePlatformAdapter } from './platforms'; import { ABORT, AbortHandle } from './utils/abort'; import { parallel, sleep } from './utils/async'; import { bigIntToNumber } from './utils/bn'; @@ -61,10 +63,8 @@ export class BlockWatcher implements ManagedResource { private checkpoints: Checkpoint; private output: Output; private abiRepo?: AbiRepository; - private startAt: StartBlock; - private chunkSize: number = 25; - private maxParallelChunks: number = 3; - private pollInterval: number = 500; + private config: BlockWatcherConfig; + private nodePlatform: NodePlatformAdapter; private abortHandle = new AbortHandle(); private endCallbacks: Array<() => void> = []; private waitAfterFailure: WaitTime; @@ -82,36 +82,30 @@ export class BlockWatcher implements ManagedResource { checkpoints, output, abiRepo, - startAt = 'genesis', contractInfoCache, + config, waitAfterFailure = linearBackoff({ min: 0, step: 2500, max: 120_000 }), chunkQueueMaxSize = 1000, - chunkSize = 25, - maxParallelChunks = 3, - pollInterval = 500, + nodePlatform, }: { ethClient: EthereumClient; checkpoints: Checkpoint; output: Output; abiRepo: AbiRepository; - startAt: StartBlock; + config: BlockWatcherConfig; waitAfterFailure?: WaitTime; chunkQueueMaxSize?: number; contractInfoCache?: Cache>; - chunkSize: number; - maxParallelChunks: number; - pollInterval: number; + nodePlatform: NodePlatformAdapter; }) { this.ethClient = ethClient; this.checkpoints = checkpoints; this.output = output; this.abiRepo = abiRepo; - this.startAt = startAt; + this.config = config; this.waitAfterFailure = waitAfterFailure; - this.chunkSize = chunkSize; - this.maxParallelChunks = maxParallelChunks; - this.pollInterval = pollInterval; this.chunkQueueMaxSize = chunkQueueMaxSize; + this.nodePlatform = nodePlatform; if (contractInfoCache) { this.contractInfoCache = contractInfoCache; } @@ -122,25 +116,25 @@ export class BlockWatcher implements ManagedResource { const { ethClient, checkpoints } = this; if (checkpoints.isEmpty()) { - if (typeof this.startAt === 'number') { - if (this.startAt < 0) { + if (typeof this.config.startAt === 'number') { + if (this.config.startAt < 0) { const latestBlockNumber = await ethClient.request(blockNumber()); - checkpoints.initialBlockNumber = Math.max(0, latestBlockNumber + this.startAt); + checkpoints.initialBlockNumber = Math.max(0, latestBlockNumber + this.config.startAt); } else { - checkpoints.initialBlockNumber = this.startAt; + checkpoints.initialBlockNumber = this.config.startAt; } - } else if (this.startAt === 'genesis') { + } else if (this.config.startAt === 'genesis') { checkpoints.initialBlockNumber = 0; - } else if (this.startAt === 'latest') { + } else if (this.config.startAt === 'latest') { const latestBlockNumber = await ethClient.request(blockNumber()); checkpoints.initialBlockNumber = latestBlockNumber; } else { - throw new Error(`Invalid start block: ${JSON.stringify(this.startAt)}`); + throw new Error(`Invalid start block: ${JSON.stringify(this.config.startAt)}`); } info( 'Determined initial block number: %d from configured value %o', checkpoints.initialBlockNumber, - this.startAt + this.config.startAt ); } @@ -164,25 +158,27 @@ export class BlockWatcher implements ManagedResource { throw ABORT; } await parallel( - chunkedBlockRanges(range, this.chunkSize, this.chunkQueueMaxSize).map(chunk => async () => { - if (!this.active) { - return; + chunkedBlockRanges(range, this.config.blocksMaxChunkSize, this.chunkQueueMaxSize).map( + chunk => async () => { + if (!this.active) { + return; + } + await retry(() => this.processChunk(chunk), { + attempts: 100, + waitBetween: this.waitAfterFailure, + taskName: `block range ${serializeBlockRange(chunk)}`, + abortHandle: this.abortHandle, + warnOnError: true, + onRetry: attempt => + warn( + 'Retrying to process block range %s (attempt %d)', + serializeBlockRange(chunk), + attempt + ), + }); } - await retry(() => this.processChunk(chunk), { - attempts: 100, - waitBetween: this.waitAfterFailure, - taskName: `block range ${serializeBlockRange(chunk)}`, - abortHandle: this.abortHandle, - warnOnError: true, - onRetry: attempt => - warn( - 'Retrying to process block range %s (attempt %d)', - serializeBlockRange(chunk), - attempt - ), - }); - }), - { maxConcurrent: this.maxParallelChunks, abortHandle: this.abortHandle } + ), + { maxConcurrent: this.config.maxParallelChunks, abortHandle: this.abortHandle } ); failures = 0; } @@ -200,7 +196,7 @@ export class BlockWatcher implements ManagedResource { } if (this.active) { try { - await this.abortHandle.race(sleep(this.pollInterval)); + await this.abortHandle.race(sleep(this.config.pollInterval)); } catch (e) { if (e === ABORT) { break; @@ -300,9 +296,36 @@ export class BlockWatcher implements ManagedResource { contractAddresInfo = await this.lookupContractInfo(receipt.contractAddress); } + let privatePayload: PrivateTransactionPayload | undefined; + if (this.config.decryptPrivateTransactions) { + if (isEnterprisePlatform(this.nodePlatform)) { + if (this.nodePlatform.isPrivateTransaction(rawTx)) { + debug('Retrieving decrypted private transaction input %o', { + txHash: rawTx.hash, + input: rawTx.input, + }); + try { + const input = await this.nodePlatform.getRawTransactionInput(rawTx.input, this.ethClient); + debug('Successfully retrieved decrypted transaction payload %o', { input }); + privatePayload = { input }; + } catch (e) { + error('Failed to retrieve decrypted transaction payload %o', { + txHash: rawTx.hash, + input: rawTx.input, + }); + } + } + } else { + warn( + "Decryption of private transactions is enabled, but detected node type (%s) doesn't support it", + this.nodePlatform.name + ); + } + } + let callInfo; if (this.abiRepo && toInfo && toInfo.isContract) { - callInfo = this.abiRepo.decodeFunctionCall(rawTx.input, { + callInfo = this.abiRepo.decodeFunctionCall(privatePayload?.input ?? rawTx.input, { contractAddress: rawTx.to ?? undefined, contractFingerprint: toInfo.fingerprint, }); @@ -321,7 +344,8 @@ export class BlockWatcher implements ManagedResource { toAddressInfo(fromInfo), toAddressInfo(toInfo), toAddressInfo(contractAddresInfo), - callInfo + callInfo, + privatePayload ), }, ...(await Promise.all(receipt?.logs?.map(l => this.processTransactionLog(l, blockTime)) ?? [])), diff --git a/src/cliflags.ts b/src/cliflags.ts index 0222781..5b2eb49 100644 --- a/src/cliflags.ts +++ b/src/cliflags.ts @@ -157,6 +157,11 @@ export const CLI_FLAGS = { return n; }, }), + 'decrypt-private-txs': flags.boolean({ + env: 'DECRYPT_PRIVATE_TXS', + description: + 'Enable to download decrypted content of private transactions (only available for Quorum at the moment)', + }), 'reject-invalid-certs': flags.boolean({ env: 'REJECT_INVALID_CERTS', diff --git a/src/config.ts b/src/config.ts index 3dded41..7c1918e 100644 --- a/src/config.ts +++ b/src/config.ts @@ -197,6 +197,11 @@ export interface BlockWatcherConfigSchema { startAt: StartBlock; /** Wait time before retrying to fetch and process blocks after failure */ retryWaitTime: WaitTimeConfig; + /** + * For chains/nodes that do support private transcations, this settings instructs block watcher to + * attempt to load the decrypted payload for private transactions + */ + decryptPrivateTransactions: boolean; } export interface BlockWatcherConfig extends Omit { @@ -786,6 +791,11 @@ export async function loadEthloggerConfig(flags: CliFlags, dryRun: boolean = fal pollInterval: parseDuration(defaults.blockWatcher?.pollInterval) ?? 500, startAt: parseStartAt(flags['start-at-block'] ?? defaults.blockWatcher?.startAt) ?? 'genesis', retryWaitTime: waitTimeFromConfig(defaults.blockWatcher?.retryWaitTime) ?? 60000, + decryptPrivateTransactions: + flags['decrypt-private-txs'] ?? + parseBooleanEnvVar(CLI_FLAGS['decrypt-private-txs'].env) ?? + defaults.blockWatcher?.decryptPrivateTransactions ?? + false, }, checkpoint: { filename: defaults.checkpoint?.filename ?? 'checkpoint.json', diff --git a/src/eth/requests.ts b/src/eth/requests.ts index fb0985e..3ce791c 100644 --- a/src/eth/requests.ts +++ b/src/eth/requests.ts @@ -124,7 +124,7 @@ export const gethTxpool = (): EthRequest<[], GethTxpool> => ({ // Quorum specific requests -export const quroumIstanbulSnapshot = (): EthRequest<[], any> => ({ +export const quorumIstanbulSnapshot = (): EthRequest<[], any> => ({ method: 'istanbul_getSnapshot', }); @@ -144,6 +144,11 @@ export const quorumRaftCluster = (): EthRequest<[], any> => ({ method: 'raft_cluster', }); +export const quorumPrivateTransactionPayload = (id: string): EthRequest<[string], string> => ({ + method: 'eth_getQuorumPayload', + params: [id], +}); + // Parity specific requests /** Returns the node enode URI */ diff --git a/src/format.ts b/src/format.ts index bb5082a..e30ab2c 100644 --- a/src/format.ts +++ b/src/format.ts @@ -9,6 +9,7 @@ import { FormattedPendingTransaction, FormattedTransaction, FunctionCall, + PrivateTransactionPayload, } from './msgs'; import { bigIntToNumber, parseBigInt } from './utils/bn'; @@ -72,7 +73,8 @@ export function formatTransaction( fromInfo?: AddressInfo, toInfo?: AddressInfo, contractAddressInfo?: AddressInfo, - call?: FunctionCall + call?: FunctionCall, + privatePayload?: PrivateTransactionPayload ): FormattedTransaction { return { ...formatBaseTransaction(rawTx), @@ -87,6 +89,7 @@ export function formatTransaction( toInfo, contractAddressInfo, call, + privatePayload, }; } diff --git a/src/index.ts b/src/index.ts index 1e40383..688879b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -190,11 +190,9 @@ class Ethlogger extends Command { ethClient: client, output, abiRepo: abiRepo, - startAt: config.blockWatcher.startAt, + config: config.blockWatcher, contractInfoCache, - chunkSize: config.blockWatcher.blocksMaxChunkSize, - maxParallelChunks: config.blockWatcher.maxParallelChunks, - pollInterval: config.blockWatcher.pollInterval, + nodePlatform: platformAdapter, }); addResource(blockWatcher); internalStatsCollector.addSource(blockWatcher, 'blockWatcher'); diff --git a/src/msgs.ts b/src/msgs.ts index 72ce357..8b64529 100644 --- a/src/msgs.ts +++ b/src/msgs.ts @@ -125,6 +125,8 @@ export interface FormattedTransaction extends BaseFormattedTransaction { /** Information about the created contract address */ contractAddressInfo?: AddressInfo; + /** Decrypted information from private transactions */ + privatePayload?: PrivateTransactionPayload; } export interface AddressInfo { @@ -134,6 +136,11 @@ export interface AddressInfo { contractName?: string; } +export interface PrivateTransactionPayload { + /** Decrypted input data */ + input?: string; +} + export interface FunctionCall { /** Function name */ name: string; diff --git a/src/platforms/index.ts b/src/platforms/index.ts index 8beed41..020fbb4 100644 --- a/src/platforms/index.ts +++ b/src/platforms/index.ts @@ -1,6 +1,7 @@ -import { OutputMessage } from '../output'; import { EthereumClient } from '../eth/client'; +import { RawTransactionResponse } from '../eth/responses'; import { NodeInfo, NodeMetricsMessage } from '../msgs'; +import { OutputMessage } from '../output'; /** Generic interface to capture platform-specific metrics and data from nodes */ export interface NodePlatformAdapter { @@ -23,3 +24,13 @@ export interface NodePlatformAdapter { capturePeerInfo?(ethClient: EthereumClient, captureTime: number): Promise; supportsPeerInfo(ethClient: EthereumClient): Promise; } + +export interface EnterpriseNodePlatformAdapter extends NodePlatformAdapter { + supportsPrivateTransactions(): boolean; + isPrivateTransaction(tx: RawTransactionResponse): boolean; + getRawTransactionInput(input: string, ethClient: EthereumClient): Promise; +} + +export function isEnterprisePlatform(platform: NodePlatformAdapter): platform is EnterpriseNodePlatformAdapter { + return typeof (platform as any).supportsPrivateTransactions === 'function'; +} diff --git a/src/platforms/mock.ts b/src/platforms/mock.ts new file mode 100644 index 0000000..79e1e90 --- /dev/null +++ b/src/platforms/mock.ts @@ -0,0 +1,9 @@ +import { GenericNodeAdapter } from './generic'; + +export class MockNodeAdapter extends GenericNodeAdapter { + public get name(): string { + return 'mock'; + } +} + +export const MOCK_NODE_ADAPTER = new MockNodeAdapter('MOCK'); diff --git a/src/platforms/quorum.ts b/src/platforms/quorum.ts index 7e6e24d..dc4d720 100644 --- a/src/platforms/quorum.ts +++ b/src/platforms/quorum.ts @@ -1,12 +1,16 @@ +import { EnterpriseNodePlatformAdapter } from '.'; import { EthereumClient } from '../eth/client'; import { quorumIstanbulCandidates, + quorumIstanbulSnapshot, + quorumPrivateTransactionPayload, quorumRaftCluster, quorumRaftLeader, quorumRaftRole, - quroumIstanbulSnapshot, } from '../eth/requests'; +import { RawTransactionResponse } from '../eth/responses'; import { QuorumProtocolInfo } from '../msgs'; +import { bigIntToNumber } from '../utils/bn'; import { createModuleDebug } from '../utils/debug'; import { GethAdapter } from './geth'; @@ -17,7 +21,7 @@ export type QUORUM_CONSENSUS = 'istanbul' | 'raft'; export async function captureIstanbulData(ethClient: EthereumClient): Promise { debug('Capturing istanbul data from quorum node'); const [snapshot, candidates] = await Promise.all([ - ethClient.request(quroumIstanbulSnapshot()), + ethClient.request(quorumIstanbulSnapshot()), ethClient.request(quorumIstanbulCandidates()), ]); return { @@ -42,7 +46,7 @@ export async function captureRaftData(ethClient: EthereumClient): Promise { + return ethClient.request(quorumPrivateTransactionPayload(input)); + } } diff --git a/test/__snapshots__/blockwatcher.test.ts.snap b/test/__snapshots__/blockwatcher.test.ts.snap index da57665..6b47474 100644 --- a/test/__snapshots__/blockwatcher.test.ts.snap +++ b/test/__snapshots__/blockwatcher.test.ts.snap @@ -71,6 +71,7 @@ Array [ "hash": "0xcb8a0b216424903fa20463b03de99c4fa2f37d56e38db01c520ab65cf2c661cf", "input": "0x2535f762000000000000000000000000774887b0a499058c2c46310ea661a9895d5c2bcb0000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", "nonce": 0, + "privatePayload": undefined, "r": "0x81b090f89f6778e1ff3a87990cd06a34a55986db99b70c8c35e5bf16d4055880", "s": "0x54f3a17a4b272badbc258b1993c1c813a6460f1965a798f6bd326df5354526df", "status": "success", @@ -259,6 +260,7 @@ Array [ "hash": "0x908d410e5ff8fee1e1f8c89a97c3c6f9955ed87aefdac6b32bf90e9a3ba81196", "input": "0x23b872dd000000000000000000000000bcb5c62f1c8d96c0d1fe698bb931d097ad861620000000000000000000000000774887b0a499058c2c46310ea661a9895d5c2bcb000000000000000000000000000000000000000000000000000000000000487e", "nonce": 1, + "privatePayload": undefined, "r": "0x10b8c5e37247b1b6895c50ebf63a4d81e994e75eee0f2c87de8047e71d645b78", "s": "0x3b5fcbae3b9745da5dac0a23cb1fccc37a52966404f3365c5be43be92fa8391a", "status": "success", @@ -393,6 +395,7 @@ Array [ "hash": "0x1d33f73edeb683653263ba5f24d4904e778e595bbcf48313f7d57c75b23d5414", "input": "0x2535f762000000000000000000000000ce23697a91bd50ab4d3fa49dfeecd3f5ee44b4e70000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", "nonce": 1, + "privatePayload": undefined, "r": "0x6ed17c9b4b559b3bd90b66ed66441851fb48106f4363749f2b8602bde235050c", "s": "0x17ff1735183e8cbd707b8a0b131433bfc86a0c6cedd6ddffb80b35a711524c4d", "status": "success", @@ -556,6 +559,7 @@ Array [ "hash": "0xcc65b8cea5f93ef8bc8de19004e4e5a364eb3b0bf034837ab38fb35c1a0c79a6", "input": "0x2535f76200000000000000000000000065626e314349fe322d6a1de163a7788646755bcb0000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", "nonce": 0, + "privatePayload": undefined, "r": "0x53ea0c8d5149a44c117ceab61c55bb8a7104f876935982a59ab9f84a71f5ad3", "s": "0x5a2a7d7b7e1895f4a0f969711061afd50f416f4dd87418c084594c0f5a48a246", "status": "success", @@ -730,6 +734,7 @@ Array [ "hash": "0x26053a3334328fb8ae63b4a4d506c5acacc3088ba004ff99100ae99f2b02cb9a", "input": "0xa5763a1f0000000000000000000000009fd67718fb64629ffe6211d3133bce4ae1589bcb", "nonce": 289, + "privatePayload": undefined, "r": "0xeccca9887925ed4406a865f5ca47cf353227f0e416d9a1623cdd0f2c6394e838", "s": "0x5a68903219039e603d5f7be58ea33de281a362d72313c8f22fa8ca179a65cc0f", "status": "success", @@ -827,6 +832,7 @@ Array [ "hash": "0x90a7fbaaec9ad7359e5c835e695086cfb9737e483fd3c0b89586b93f96c3b44e", "input": "0x23b872dd000000000000000000000000bcba6211ffc842576497ea341e20496b58c8e8ab00000000000000000000000065626e314349fe322d6a1de163a7788646755bcb0000000000000000000000000000000000000000000000000000000000005280", "nonce": 1, + "privatePayload": undefined, "r": "0x19832bf77a6c738f247082cf4276e1a4bb38bb8f9a8b98364436640e9493b06d", "s": "0x4b7f369a0b183c3d3b74ad579f4b19eb9d46f4a1857a2db2728ad7899029b307", "status": "success", @@ -936,6 +942,7 @@ Array [ "hash": "0x47b4c3b74be82b376cd6649aa5b345f75ed3b4de4dd63c2a065067bc3086f29c", "input": "0x2535f762000000000000000000000000774887b0a499058c2c46310ea661a9895d5c2bcb0000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", "nonce": 0, + "privatePayload": undefined, "r": "0x3df332be45f1a09738ed4bdd4d61bedf4e7316e1cbb0dcb24e1aa29089aa5159", "s": "0x5af46420e77f021a465f3981f45b186715b176d5c897afc3a702edc94652f12d", "status": "success", @@ -1124,6 +1131,7 @@ Array [ "hash": "0xf76610512749adb254f5651dac1128088fbef622141283bea65e78c9125135e5", "input": "0x2535f7620000000000000000000000009e0956c736e75a5688933ecbee3e3ac044311bcb0000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", "nonce": 0, + "privatePayload": undefined, "r": "0x9ef9bb9ac2bd1bb62761e7e2d8a0e3b5e6770bb00c3fd8416b2c8c75690d679e", "s": "0x23c057a88d6631c7849366ca67448025e05d44534058e89100f55d54312c54a8", "status": "success", @@ -1287,6 +1295,7 @@ Array [ "hash": "0x1db90fc5d4378386444aba2b5951d97c1585ac30b17f51544a1ddd965c4e3df3", "input": "0x2535f7620000000000000000000000005702e889261aa37683b4087f4ccad3d1f7ef3970000000000000000000000000000000000000000000000000b469471f801400000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000b427579206d3a787663555a000000000000000000000000000000000000000000", "nonce": 0, + "privatePayload": undefined, "r": "0x3a0bb7198407a755d2e0e4069e716f34a08fa16eeef0370f8e388a6c7dd16256", "s": "0x591f1814892bf15df3f0a9f7d9caa331152aaedcdfa92349060ee94dc0ad677f", "status": "success", @@ -1450,6 +1459,7 @@ Array [ "hash": "0xae1a8c88e2c742e8676687adb29a1973f4ab5cf4487a4417ac9bff1b9f9451b5", "input": "0x2535f7620000000000000000000000009fd67718fb64629ffe6211d3133bce4ae1589bcb000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000011596f7520476f74205469636b6574203633000000000000000000000000000000", "nonce": 290, + "privatePayload": undefined, "r": "0x911095db90165be30407cec5ea5f41276543de27f6f42cb0563c31e1548093b", "s": "0x57b9fcec5c86ff7d8f893fd662a20c3dd0e1e58700d8b7ee1ec87fcca344fed1", "status": "success", @@ -1613,6 +1623,7 @@ Array [ "hash": "0xf467bb2c29601a856fccb9f59325b5698a6706e94c3182e9da4a3e6b65f08dde", "input": "0x23b872dd000000000000000000000000bcb539bb9db6bbeba94e9d2c765228ade4e796b2000000000000000000000000774887b0a499058c2c46310ea661a9895d5c2bcb0000000000000000000000000000000000000000000000000000000000004424", "nonce": 1, + "privatePayload": undefined, "r": "0xaf723af751ee11d4933621b3d119cc5bec70fbb741875610f143ce45aba46d8a", "s": "0x797922c0face966f11e785e3c07316f9b06802622305f7c51ee6c608756e619f", "status": "success", @@ -1722,6 +1733,7 @@ Array [ "hash": "0x11fcfc66549d8d487b5e1c223b1c6e8be40b7718dd921ee349d12401c029482a", "input": "0x2535f762000000000000000000000000d0bcb37593fa8ca5bd3a6b84a4dbdea36bf010e30000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000026536176652074686520776f726c64212054686572652063616e206265206f6e6c79206f6e65210000000000000000000000000000000000000000000000000000", "nonce": 0, + "privatePayload": undefined, "r": "0xabd23c03ede1a9a344a1c2984ba25e43a11d92a81bd109655b52d603e954d582", "s": "0x724eecda565fca47cbea7743aebd4857dc4dcb43d13720133620c670ee5d69e3", "status": "success", @@ -1885,6 +1897,7 @@ Array [ "hash": "0x8901cd449c4a1eb0e1cf514ba83bf0da2cf4c8c60547c5e0e16c47b18fd603af", "input": "0x2535f7620000000000000000000000009bd4767e5bae5f71c95d1130db6fed2bd7f8fbcb0000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", "nonce": 0, + "privatePayload": undefined, "r": "0x6e56430d1a9d89a491dd6cd023c6eb4e2e4f6efdc56e5e6396aba626b68d574f", "s": "0x48a23808d593b467077447ee62fccf9d66ff41c17781309537d66c84abb9ecd2", "status": "success", @@ -2073,6 +2086,7 @@ Array [ "hash": "0x196e7429cb22f63212e3e01740ce292990326a052615aa31ac719bd548ed0a44", "input": "0x23b872dd000000000000000000000000bcba9e0db39fa3f9655ee2ce1b6ce7a7c563baff0000000000000000000000009bd4767e5bae5f71c95d1130db6fed2bd7f8fbcb0000000000000000000000000000000000000000000000000000000000005482", "nonce": 1, + "privatePayload": undefined, "r": "0x745829a05864d1e3bf0d1c1971192f14aeb3364a251827214cde72b2f6431d43", "s": "0x3cb49b002054538960a6402e25a4b8613d5482f728e6530daa68e9db4cde9242", "status": "success", @@ -2182,6 +2196,7 @@ Array [ "hash": "0x720ee57f1f3c4feef29053986d36c6652c49c5acf1d52eb3d9cb1dd18fc143d4", "input": "0x23b872dd000000000000000000000000bcbaa39a2a483d5579299ea48bf31903f8bb88de0000000000000000000000009e0956c736e75a5688933ecbee3e3ac044311bcb00000000000000000000000000000000000000000000000000000000000054ab", "nonce": 1, + "privatePayload": undefined, "r": "0x52e149140629632c5904096a73a2235da6952f7d3c47deb16f8235bd5a0752a5", "s": "0x1a851e1d0e3da76039a499aa7a3efc9dadc578fb9162316f8b5bd8374b7a51c6", "status": "success", @@ -2366,6 +2381,7 @@ Array [ "hash": "0xcbfcba816b760c1bc8767098ccbe86cc5f8d702e9146c24a6e932df9ffb7f0b5", "input": "0x2535f7620000000000000000000000005702ea60fde794bd01d90b67b7b366ea541d3855000000000000000000000000000000000000000000000000d02ab486cedc00000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000b42757920703a7876665559000000000000000000000000000000000000000000", "nonce": 1, + "privatePayload": undefined, "r": "0xb036d939107379b6b8a966e4f2e984c0f1699a243461c34894f2543e9bbdda24", "s": "0x1fd552554ea14e5dfcdbb2cff80d804acd6f304d9cce1af1143220d5b0ad0b78", "status": "success", @@ -2554,6 +2570,7 @@ Array [ "hash": "0xfe8ff33ae7f6ec7a37b7b2a1127d9d57e0cf74dc05d80eb539d529b2acdc4155", "input": "0x2535f762000000000000000000000000d0bcb4d73814db53a1da0573c5fa2b7598fcdf300000000000000000000000000000000000000000000000004563918244f400000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002049206861746520747261666669632120204f6620616c6c206b696e6473212121", "nonce": 0, + "privatePayload": undefined, "r": "0x604c49f5a0d8e8f10a675e75dfb077ea98fec8f85a9ee8714a769c3f8f5512df", "s": "0x4dfd8387850777b7be78e05cf5f45819f438dc28efff36643c1c8bb80f0f53a4", "status": "success", @@ -2717,6 +2734,7 @@ Array [ "hash": "0xffce2300d40557ca164ec537291e3e8efc3744e1625859deaa569c2dc312993a", "input": "0x2535f762000000000000000000000000694d12898d1c0b40178fd575a7ba6475cced6bcb0000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", "nonce": 0, + "privatePayload": undefined, "r": "0xfe24f0b919c1ede62438f7184a7cd73eb1ea0b2e6ea57341b244355cf0bcd2f0", "s": "0x622c42f557e8d466b57d98357553bdca98e0cdda8dcd7b6124ebb0550cf0e8d", "status": "success", @@ -2880,6 +2898,7 @@ Array [ "hash": "0x3d810dc5f8ca46932efd3823e6f8457dd51b102dfcb9cd314f9320cc59245203", "input": "0x2535f76200000000000000000000000013f4e9847a607886f30fcd776810c10531729bcb0000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", "nonce": 0, + "privatePayload": undefined, "r": "0x4108287e71003ebd4ccb80c884b216bb46690f996f9025fa4df66d8099d53f92", "s": "0x477c15f6477e65d80510003d4ec10bc9eba4d2f1e8c9b6373ad5e268cba1170d", "status": "success", @@ -3043,6 +3062,7 @@ Array [ "hash": "0x6de5430b62731dd8d1aa1dde1843c126630a6b91f7fdedc35d9b826f2950fee8", "input": "0x2535f7620000000000000000000000005702e889261aa37683b4087f4ccad3d1f7ef3970000000000000000000000000000000000000000000000000d02ab486cedc00000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000b42757920703a78766b4231000000000000000000000000000000000000000000", "nonce": 0, + "privatePayload": undefined, "r": "0x290b2ae71217f9621bc94e674638dfaf7cf39ab6e755113ab8c10329fe8c64f9", "s": "0x86c5d312e9d50cc24c2ea0ae31fee594cf01228665654dded8b1b79f7f876a4", "status": "success", @@ -3231,6 +3251,7 @@ Array [ "hash": "0x321d1038ce2253a2d12b00217b2564a6bd6dd5eddb41be1ee01fa93763f82066", "input": "0x2535f762000000000000000000000000d23979a6c6de5737ce4341f31bbfcbbce8fd5bcb0000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", "nonce": 0, + "privatePayload": undefined, "r": "0xbf21fd1963ee82cf9ab924a1db095d1d1724b82dfb6acdb0c33264887f35aba5", "s": "0x7ee67dd30ba4aff0b3541c6c4ba9a782598147b2c8292fc7fc95ea648dabbedf", "status": "success", @@ -3394,6 +3415,7 @@ Array [ "hash": "0x4a49ab8bb9d4ff740645ae2beb0d2964933dd15597e83e0454041557b5b2db41", "input": "0x23b872dd000000000000000000000000bcbad3473c192463df7603a841426d8cde02725700000000000000000000000013f4e9847a607886f30fcd776810c10531729bcb0000000000000000000000000000000000000000000000000000000000005620", "nonce": 1, + "privatePayload": undefined, "r": "0x7c3ef7822e4f3a58cecefaa9eade95c9c67da1c09d1721cb51f3cad1891d5336", "s": "0x7f34df9e11364d63e24cdc7238676efd44f822e140e374103a65716d8fddb0b3", "status": "success", @@ -3503,6 +3525,7 @@ Array [ "hash": "0x563193f8a0e92018e7cc370c9a6b25cd7690e77343f1a0c751653073303e7ed3", "input": "0x23b872dd000000000000000000000000bcbccdd779e87df3c79bc2edaaa023c85f83d104000000000000000000000000694d12898d1c0b40178fd575a7ba6475cced6bcb0000000000000000000000000000000000000000000000000000000000005c8b", "nonce": 1, + "privatePayload": undefined, "r": "0x76704f23b248786afa763e1a814c86c03665357dce0829f67742d61d2a1fbef", "s": "0x38e1ab7b2027eacad3921be5946c21324dff0435f2cb8a08a1368b8fcda314c6", "status": "success", diff --git a/test/abi/testcases/__snapshots__/ethdenver.test.ts.snap b/test/abi/testcases/__snapshots__/ethdenver.test.ts.snap index c0e8181..db98c98 100644 --- a/test/abi/testcases/__snapshots__/ethdenver.test.ts.snap +++ b/test/abi/testcases/__snapshots__/ethdenver.test.ts.snap @@ -97,6 +97,7 @@ Array [ "hash": "0xff36619285cf23ef7f812ea3600a369b52ebd392e682deeb77dd758b4462f38f", "input": "0x405cec67000000000000000000000000150042aae387e5c002dfaf7844b3110828094aca0000000000000000000000006c85e15838034b7bba6c63badd8839fd4c5be60600000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000046000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000001771140000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000001e4d80106b900000000000000000000000047643fd12a9464ba6cbadd6d5afc095756640d0b000000000000000000000000bb2692ec9976975a8cb80b52832a94273fbfb43800000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000849bd9bbc60000000000000000000000000f5ef980513ca22faf70243959c92cf5ee1e531b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041fbd8c79438ff87e7cef097e14e5e820f83c637d5a963c470751916afed65148f635c56ba621c554725bf67eca7a06f600641b8fc3e2385671a15810b194baae31b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000416fb1c4d50445a989e871840ec68d891a257af43d64d59e29a2ffb4b5a0a1d41d7f79914ef0b8b6697ca3df44ca1e490c1aa3c43f345962858ef34f7c186ce5321c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "nonce": 556, + "privatePayload": undefined, "r": "0x7843ec8bc029c4f623ece12111abd8d361a96aed84a3851def9bccbec6456ae", "s": "0x42e19d62c96d87683833bb0a02150c12580e61c5d69f6c17753cab8e3c726208", "status": "success", diff --git a/test/abi/testcases/ethdenver.test.ts b/test/abi/testcases/ethdenver.test.ts index 87c4d2d..2bb8af9 100644 --- a/test/abi/testcases/ethdenver.test.ts +++ b/test/abi/testcases/ethdenver.test.ts @@ -7,6 +7,7 @@ import { Checkpoint } from '../../../src/checkpoint'; import { BatchedEthereumClient } from '../../../src/eth/client'; import { HttpTransport } from '../../../src/eth/http'; import { withRecorder } from '../../../src/eth/recorder'; +import { MOCK_NODE_ADAPTER } from '../../../src/platforms/mock'; import { enableTraceLogging, suppressDebugLogging } from '../../../src/utils/debug'; import { LRUCache } from '../../../src/utils/lru'; import { TestOutput } from '../../testoutput'; @@ -51,15 +52,21 @@ test('blockwatcher', async () => { const blockWatcher = new BlockWatcher({ abiRepo, checkpoints, - chunkSize: 1, + config: { + enabled: true, + blocksMaxChunkSize: 1, + pollInterval: 1, + maxParallelChunks: 1, + startAt: 'latest', + decryptPrivateTransactions: false, + retryWaitTime: 10, + }, ethClient, - maxParallelChunks: 1, output, - pollInterval: 1, - startAt: 'latest', chunkQueueMaxSize: 10, contractInfoCache, waitAfterFailure: 1, + nodePlatform: MOCK_NODE_ADAPTER, }); await blockWatcher.processChunk({ from: BLOCK, to: BLOCK }); diff --git a/test/abi/testcases/ost.test.ts b/test/abi/testcases/ost.test.ts index cdcf053..66dcbcb 100644 --- a/test/abi/testcases/ost.test.ts +++ b/test/abi/testcases/ost.test.ts @@ -7,6 +7,7 @@ import { Checkpoint } from '../../../src/checkpoint'; import { BatchedEthereumClient } from '../../../src/eth/client'; import { HttpTransport } from '../../../src/eth/http'; import { withRecorder } from '../../../src/eth/recorder'; +import { MOCK_NODE_ADAPTER } from '../../../src/platforms/mock'; import { enableTraceLogging, suppressDebugLogging } from '../../../src/utils/debug'; import { LRUCache } from '../../../src/utils/lru'; import { TestOutput } from '../../testoutput'; @@ -51,15 +52,21 @@ test('blockwatcher', async () => { const blockWatcher = new BlockWatcher({ abiRepo, checkpoints, - chunkSize: 1, + config: { + enabled: true, + blocksMaxChunkSize: 1, + pollInterval: 1, + maxParallelChunks: 1, + startAt: 'latest', + decryptPrivateTransactions: false, + retryWaitTime: 10, + }, ethClient, - maxParallelChunks: 1, output, - pollInterval: 1, - startAt: 'latest', chunkQueueMaxSize: 10, contractInfoCache, waitAfterFailure: 1, + nodePlatform: MOCK_NODE_ADAPTER, }); // const contractInfo = await blockWatcher.lookupContractInfo('0x3FE42c2842377a5F4dc0E521720fb0f0048Baf9A'); diff --git a/test/blockwatcher.test.ts b/test/blockwatcher.test.ts index 3bad8be..ae0a9bc 100644 --- a/test/blockwatcher.test.ts +++ b/test/blockwatcher.test.ts @@ -9,6 +9,7 @@ import { withRecorder } from '../src/eth/recorder'; import { suppressDebugLogging } from '../src/utils/debug'; import LRUCache from '../src/utils/lru'; import { TestOutput } from './testoutput'; +import { MOCK_NODE_ADAPTER } from '../src/platforms/mock'; let logHandle: any; beforeEach(() => { @@ -47,15 +48,21 @@ test('blockwatcher', async () => { const blockWatcher = new BlockWatcher({ abiRepo, checkpoints, - chunkSize: 1, + config: { + enabled: true, + blocksMaxChunkSize: 1, + pollInterval: 1, + maxParallelChunks: 1, + startAt: 'latest', + decryptPrivateTransactions: false, + retryWaitTime: 10, + }, ethClient, - maxParallelChunks: 1, output, - pollInterval: 1, - startAt: 'latest', chunkQueueMaxSize: 10, contractInfoCache, waitAfterFailure: 1, + nodePlatform: MOCK_NODE_ADAPTER, }); await blockWatcher.processChunk({ from: 6442472, to: 6442482 }); diff --git a/test/config.test.ts b/test/config.test.ts index fc290ee..7ee1652 100644 --- a/test/config.test.ts +++ b/test/config.test.ts @@ -19,6 +19,7 @@ test('defaults', async () => { }, "blockWatcher": Object { "blocksMaxChunkSize": 25, + "decryptPrivateTransactions": false, "enabled": true, "maxParallelChunks": 3, "pollInterval": 500, @@ -139,6 +140,7 @@ test('cli flags overrides', async () => { expect(config.blockWatcher).toMatchInlineSnapshot(` Object { "blocksMaxChunkSize": 25, + "decryptPrivateTransactions": false, "enabled": true, "maxParallelChunks": 3, "pollInterval": 500, diff --git a/test/failures/mainnet_overflow.test.ts b/test/failures/mainnet_overflow.test.ts index c538bc7..1852365 100644 --- a/test/failures/mainnet_overflow.test.ts +++ b/test/failures/mainnet_overflow.test.ts @@ -6,6 +6,7 @@ import { Checkpoint } from '../../src/checkpoint'; import { BatchedEthereumClient } from '../../src/eth/client'; import { HttpTransport } from '../../src/eth/http'; import { withRecorder } from '../../src/eth/recorder'; +import { MOCK_NODE_ADAPTER } from '../../src/platforms/mock'; import { suppressDebugLogging } from '../../src/utils/debug'; import { LRUCache } from '../../src/utils/lru'; import { TestOutput } from '../testoutput'; @@ -47,15 +48,21 @@ test(`mainnet overflow ${BLOCK}`, async () => { const blockWatcher = new BlockWatcher({ abiRepo, checkpoints, - chunkSize: 1, + config: { + enabled: true, + blocksMaxChunkSize: 1, + pollInterval: 1, + maxParallelChunks: 1, + startAt: 'latest', + decryptPrivateTransactions: false, + retryWaitTime: 10, + }, ethClient, - maxParallelChunks: 1, output, - pollInterval: 1, - startAt: 'latest', chunkQueueMaxSize: 10, contractInfoCache, waitAfterFailure: 1, + nodePlatform: MOCK_NODE_ADAPTER, }); await expect(blockWatcher.processChunk({ from: BLOCK, to: BLOCK })).resolves.toBeUndefined(); diff --git a/test/format.test.ts b/test/format.test.ts index 4021395..b919c36 100644 --- a/test/format.test.ts +++ b/test/format.test.ts @@ -98,6 +98,7 @@ test('formatTransaction', () => { "hash": "0xbb3a336e3f823ec18197f1e13ee875700f08f03e2cab75f0d0b118dabb44cba0", "input": "0xf7d8c88300000000000000000000000000000000000000000000000000000000000cee6100000000000000000000000000000000000000000000000000000000000ac3e1", "nonce": 24, + "privatePayload": undefined, "r": "0x2a378831cf81d99a3f06a18ae1b6ca366817ab4d88a70053c41d7a8f0368e031", "s": "0x450d831a05b6e418724436c05c155e0a1b7b921015d0fbc2f667aed709ac4fb5", "status": "success",