diff --git a/src/Data/Collector.ts b/src/Data/Collector.ts index 1c9a4ee0..c98377b1 100644 --- a/src/Data/Collector.ts +++ b/src/Data/Collector.ts @@ -56,8 +56,8 @@ type GET_TX_RECEIPT_RESPONSE = { export interface ReceiptVerificationResult { success: boolean - failedReason?: string - nestedCounterMessage?: string + failedReasons?: string[] + nestedCounterMessages?: string[] newReceipt?: Receipt.ArchiverReceipt } @@ -406,7 +406,9 @@ export const validateArchiverReceipt = (receipt: Receipt.ArchiverReceipt): boole export const verifyReceiptData = async ( receipt: Receipt.ArchiverReceipt, - checkReceiptRobust = true + checkReceiptRobust = true, + failedReasons = [], + nestedCounterMessages = [] ): Promise<{ success: boolean; newReceipt?: Receipt.ArchiverReceipt }> => { const result = { success: false } // Check the signed nodes are part of the execution group nodes of the tx @@ -425,14 +427,14 @@ export const verifyReceiptData = async ( } const currentCycle = getCurrentCycleCounter() if (currentCycle - cycle > 2) { - Logger.mainLogger.error( + failedReasons.push( `Found receipt with cycle older than 2 cycles ${txId}, ${cycle}, ${timestamp}, ${currentCycle}` ) } const cycleShardData = shardValuesByCycle.get(cycle) if (!cycleShardData) { - Logger.mainLogger.error('Cycle shard data not found') - if (nestedCountersInstance) nestedCountersInstance.countEvent('receipt', 'Cycle_shard_data_not_found') + failedReasons.push('Cycle shard data not found') + nestedCounterMessages.push('Cycle_shard_data_not_found') return result } // Determine the home partition index of the primary account (executionShardKey) @@ -448,14 +450,12 @@ export const verifyReceiptData = async ( ? Math.ceil(votingGroupCount * config.requiredVotesPercentage) : Math.round(votingGroupCount * config.requiredVotesPercentage) if (signatures.length < requiredSignatures) { - Logger.mainLogger.error( + failedReasons.push( `Invalid receipt appliedReceipt signatures count is less than requiredSignatures, ${signatures.length}, ${requiredSignatures}` ) - if (nestedCountersInstance) - nestedCountersInstance.countEvent( - 'receipt', - 'Invalid_receipt_appliedReceipt_signatures_count_less_than_requiredSignatures' - ) + nestedCounterMessages.push( + 'Invalid_receipt_appliedReceipt_signatures_count_less_than_requiredSignatures' + ) return result } // Refer to https://github.com/shardeum/shardus-core/blob/50b6d00f53a35996cd69210ea817bee068a893d6/src/state-manager/TransactionConsensus.ts#L2799 @@ -472,26 +472,18 @@ export const verifyReceiptData = async ( // Get the node id from the public key const node = cycleShardData.nodes.find((node) => node.publicKey === nodePubKey) if (node == null) { - Logger.mainLogger.error( + failedReasons.push( `The node with public key ${nodePubKey} of the receipt ${txId}} with ${timestamp} is not in the active nodesList of cycle ${cycle}` ) - if (nestedCountersInstance) - nestedCountersInstance.countEvent( - 'receipt', - 'appliedReceipt_signature_owner_not_in_active_nodesList' - ) + nestedCounterMessages.push('appliedReceipt_signature_owner_not_in_active_nodesList') continue } // Check if the node is in the execution group if (!cycleShardData.parititionShardDataMap.get(homePartition).coveredBy[node.id]) { - Logger.mainLogger.error( + failedReasons.push( `The node with public key ${nodePubKey} of the receipt ${txId} with ${timestamp} is not in the execution group of the tx` ) - if (nestedCountersInstance) - nestedCountersInstance.countEvent( - 'receipt', - 'appliedReceipt_signature_node_not_in_execution_group_of_tx' - ) + nestedCounterMessages.push('appliedReceipt_signature_node_not_in_execution_group_of_tx') continue } if (Crypto.verify({ ...appliedVoteHash, sign: signature })) { @@ -501,14 +493,12 @@ export const verifyReceiptData = async ( } } if (goodSignatures.size < requiredSignatures) { - Logger.mainLogger.error( + failedReasons.push( `Invalid receipt appliedReceipt valid signatures count is less than requiredSignatures ${goodSignatures.size}, ${requiredSignatures}` ) - if (nestedCountersInstance) - nestedCountersInstance.countEvent( - 'receipt', - 'Invalid_receipt_appliedReceipt_valid_signatures_count_less_than_requiredSignatures' - ) + nestedCounterMessages.push( + 'Invalid_receipt_appliedReceipt_valid_signatures_count_less_than_requiredSignatures' + ) return result } return { success: true } @@ -516,87 +506,62 @@ export const verifyReceiptData = async ( const { confirmOrChallenge } = appliedReceipt // Check if the appliedVote node is in the execution group if (!cycleShardData.nodeShardDataMap.has(appliedVote.node_id)) { - Logger.mainLogger.error('Invalid receipt appliedReceipt appliedVote node is not in the active nodesList') - if (nestedCountersInstance) - nestedCountersInstance.countEvent('receipt', 'Invalid_receipt_appliedVote_node_not_in_active_nodesList') + failedReasons.push('Invalid receipt appliedReceipt appliedVote node is not in the active nodesList') + nestedCounterMessages.push('Invalid_receipt_appliedVote_node_not_in_active_nodesList') return result } if (appliedVote.sign.owner !== cycleShardData.nodeShardDataMap.get(appliedVote.node_id).node.publicKey) { - Logger.mainLogger.error( + failedReasons.push( 'Invalid receipt appliedReceipt appliedVote node signature owner and node public key does not match' ) - if (nestedCountersInstance) - nestedCountersInstance.countEvent( - 'receipt', - 'Invalid_receipt_appliedVote_node_signature_owner_and_node_public_key_does_not_match' - ) + nestedCounterMessages.push( + 'Invalid_receipt_appliedVote_node_signature_owner_and_node_public_key_does_not_match' + ) return result } if (!cycleShardData.parititionShardDataMap.get(homePartition).coveredBy[appliedVote.node_id]) { - Logger.mainLogger.error( + failedReasons.push( 'Invalid receipt appliedReceipt appliedVote node is not in the execution group of the tx' ) - if (nestedCountersInstance) - nestedCountersInstance.countEvent( - 'receipt', - 'Invalid_receipt_appliedVote_node_not_in_execution_group_of_tx' - ) + nestedCounterMessages.push('Invalid_receipt_appliedVote_node_not_in_execution_group_of_tx') return result } if (!Crypto.verify(appliedVote)) { - Logger.mainLogger.error('Invalid receipt appliedReceipt appliedVote signature verification failed') - if (nestedCountersInstance) - nestedCountersInstance.countEvent( - 'receipt', - 'Invalid_receipt_appliedVote_signature_verification_failed' - ) + failedReasons.push('Invalid receipt appliedReceipt appliedVote signature verification failed') + nestedCounterMessages.push('Invalid_receipt_appliedVote_signature_verification_failed') return result } // Check if the confirmOrChallenge node is in the execution group if (!cycleShardData.nodeShardDataMap.has(confirmOrChallenge.nodeId)) { - Logger.mainLogger.error( + failedReasons.push( 'Invalid receipt appliedReceipt confirmOrChallenge node is not in the active nodesList' ) - if (nestedCountersInstance) - nestedCountersInstance.countEvent( - 'receipt', - 'Invalid_receipt_confirmOrChallenge_node_not_in_active_nodesList' - ) + nestedCounterMessages.push('Invalid_receipt_confirmOrChallenge_node_not_in_active_nodesList') return result } if ( confirmOrChallenge.sign.owner !== cycleShardData.nodeShardDataMap.get(confirmOrChallenge.nodeId).node.publicKey ) { - Logger.mainLogger.error( + failedReasons.push( 'Invalid receipt appliedReceipt confirmOrChallenge node signature owner and node public key does not match' ) - if (nestedCountersInstance) - nestedCountersInstance.countEvent( - 'receipt', - 'Invalid_receipt_confirmOrChallenge_signature_owner_and_node_public_key_does_not_match' - ) + nestedCounterMessages.push( + 'Invalid_receipt_confirmOrChallenge_signature_owner_and_node_public_key_does_not_match' + ) return result } if (!cycleShardData.parititionShardDataMap.get(homePartition).coveredBy[confirmOrChallenge.nodeId]) { - Logger.mainLogger.error( + failedReasons.push( 'Invalid receipt appliedReceipt confirmOrChallenge node is not in the execution group of the tx' ) - if (nestedCountersInstance) - nestedCountersInstance.countEvent( - 'receipt', - 'Invalid_receipt_confirmOrChallenge_node_not_in_execution_group_of_tx' - ) + nestedCounterMessages.push('Invalid_receipt_confirmOrChallenge_node_not_in_execution_group_of_tx') return result } if (!Crypto.verify(confirmOrChallenge)) { - Logger.mainLogger.error('Invalid receipt appliedReceipt confirmOrChallenge signature verification failed') - if (nestedCountersInstance) - nestedCountersInstance.countEvent( - 'receipt', - 'Invalid_receipt_confirmOrChallenge_signature_verification_failed' - ) + failedReasons.push('Invalid receipt appliedReceipt confirmOrChallenge signature verification failed') + nestedCounterMessages.push('Invalid_receipt_confirmOrChallenge_signature_verification_failed') return result } @@ -612,16 +577,15 @@ export const verifyReceiptData = async ( : Math.ceil(config.RECEIPT_CONFIRMATIONS / 2) // 3 out of 5 nodes const { success, newReceipt } = await isReceiptRobust(receipt, executionGroupNodes, minConfirmations) if (!success) { - Logger.mainLogger.error('Invalid receipt: Robust check failed') - if (nestedCountersInstance) - nestedCountersInstance.countEvent('receipt', 'Invalid_receipt_robust_check_failed') + failedReasons.push('Invalid receipt: Robust check failed') + nestedCounterMessages.push('Invalid_receipt_robust_check_failed') return result } if (newReceipt) return { success: true, newReceipt } return { success: true } } -const calculateVoteHash = (vote: Receipt.AppliedVote): string => { +const calculateVoteHash = (vote: Receipt.AppliedVote, failedReasons = []): string => { try { if (config.usePOQo === true) { const appliedHash = { @@ -645,7 +609,7 @@ const calculateVoteHash = (vote: Receipt.AppliedVote): string => { } return Crypto.hashObj({ ...vote, node_id: '' }) } catch { - Logger.mainLogger.error('Error in calculateVoteHash', vote) + failedReasons.push('Error in calculateVoteHash', vote) return '' } } @@ -655,6 +619,8 @@ export const verifyArchiverReceipt = async ( ): Promise => { const { txId, timestamp } = receipt.tx const existingReceipt = await Receipt.queryReceiptByReceiptId(txId) + const failedReasons = [] + const nestedCounterMessages = [] if ( config.usePOQo === false && existingReceipt && @@ -664,60 +630,65 @@ export const verifyArchiverReceipt = async ( ) { // If the existing receipt is confirmed, and the new receipt is challenged, then skip saving the new receipt if (existingReceipt.appliedReceipt.confirmOrChallenge.message === 'confirm') { - const failedReason = `Existing receipt is confirmed, but new receipt is challenged ${txId}, ${receipt.cycle}, ${timestamp}` - const nestedCounterMessage = 'Existing_receipt_is_confirmed_but_new_receipt_is_challenged' - // if (nestedCountersInstance) - // nestedCountersInstance.countEvent( - // 'receipt', - // 'Existing_receipt_is_confirmed_but_new_receipt_is_challenged' - // ) - return { success: false, failedReason, nestedCounterMessage } + failedReasons.push( + `Existing receipt is confirmed, but new receipt is challenged ${txId}, ${receipt.cycle}, ${timestamp}` + ) + nestedCounterMessages.push('Existing_receipt_is_confirmed_but_new_receipt_is_challenged') + return { success: false, failedReasons, nestedCounterMessages } } } if (config.verifyAppReceiptData) { // if (profilerInstance) profilerInstance.profileSectionStart('Verify_app_receipt_data') // if (nestedCountersInstance) nestedCountersInstance.countEvent('receipt', 'Verify_app_receipt_data') - const { valid, needToSave } = await verifyAppReceiptData(receipt, existingReceipt) + const { valid, needToSave } = await verifyAppReceiptData( + receipt, + existingReceipt, + failedReasons, + nestedCounterMessages + ) // if (profilerInstance) profilerInstance.profileSectionEnd('Verify_app_receipt_data') if (!valid) { - const failedReason = `Invalid receipt: App Receipt Verification failed ${txId}, ${receipt.cycle}, ${timestamp}` - const nestedCounterMessage = 'Invalid_receipt_app_receipt_verification_failed' - // if (nestedCountersInstance) - // nestedCountersInstance.countEvent('receipt', 'Invalid_receipt_app_receipt_verification_failed') - return { success: false, failedReason, nestedCounterMessage } + failedReasons.push( + `Invalid receipt: App Receipt Verification failed ${txId}, ${receipt.cycle}, ${timestamp}` + ) + nestedCounterMessages.push('Invalid_receipt_app_receipt_verification_failed') + return { success: false, failedReasons, nestedCounterMessages } } if (!needToSave) { - const failedReason = `Valid receipt: but no need to save ${txId}, ${receipt.cycle}, ${timestamp}` - const nestedCounterMessage = 'Valid_receipt_but_no_need_to_save' - // if (nestedCountersInstance) - // nestedCountersInstance.countEvent('receipt', 'Valid_receipt_but_no_need_to_save') - return { success: false, failedReason, nestedCounterMessage } + failedReasons.push(`Valid receipt: but no need to save ${txId}, ${receipt.cycle}, ${timestamp}`) + nestedCounterMessages.push('Valid_receipt_but_no_need_to_save') + return { success: false, failedReasons, nestedCounterMessages } } } if (config.verifyAccountData) { // if (profilerInstance) profilerInstance.profileSectionStart('Verify_receipt_account_data') // if (nestedCountersInstance) nestedCountersInstance.countEvent('receipt', 'Verify_receipt_account_data') - const result = verifyAccountHash(receipt) + const result = verifyAccountHash(receipt, failedReasons, nestedCounterMessages) // if (profilerInstance) profilerInstance.profileSectionEnd('Verify_receipt_account_data') if (!result) { - const failedReason = `Invalid receipt: Account Verification failed ${txId}, ${receipt.cycle}, ${timestamp}` - const nestedCounterMessage = 'Invalid_receipt_account_verification_failed' - // if (nestedCountersInstance) - // nestedCountersInstance.countEvent('receipt', 'Invalid_receipt_account_verification_failed') - return { success: false, failedReason, nestedCounterMessage } + failedReasons.push( + `Invalid receipt: Account Verification failed ${txId}, ${receipt.cycle}, ${timestamp}` + ) + nestedCounterMessages.push('Invalid_receipt_account_verification_failed') + return { success: false, failedReasons, nestedCounterMessages } } } if (config.verifyReceiptData) { // if (profilerInstance) profilerInstance.profileSectionStart('Verify_receipt_data') // if (nestedCountersInstance) nestedCountersInstance.countEvent('receipt', 'Verify_receipt_data') - const { success, newReceipt } = await verifyReceiptData(receipt) + const { success, newReceipt } = await verifyReceiptData( + receipt, + true, + failedReasons, + nestedCounterMessages + ) // if (profilerInstance) profilerInstance.profileSectionEnd('Verify_receipt_data') if (!success) { - const failedReason = `Invalid receipt: Verification failed ${txId}, ${receipt.cycle}, ${timestamp}` - const nestedCounterMessage = 'Invalid_receipt_verification_failed' - return { success: false, failedReason, nestedCounterMessage } + failedReasons.push(`Invalid receipt: Verification failed ${txId}, ${receipt.cycle}, ${timestamp}`) + nestedCounterMessages.push('Invalid_receipt_verification_failed') + return { success: false, failedReasons, nestedCounterMessages } } - return { success: true, failedReason: '', nestedCounterMessage: '', newReceipt } + return { success: true, failedReasons, nestedCounterMessages, newReceipt } } return { success: true } } @@ -759,12 +730,17 @@ export const storeReceiptData = async ( continue } + const stringifiedReceipt = StringUtils.safeStringify(receipt) if (verifyData) { - const result = await offloadReceipt(receipt) + const result = await offloadReceipt(txId, timestamp, stringifiedReceipt, receipt) if (result.success === false) { receiptsInValidationMap.delete(txId) - Logger.mainLogger.error(result.failedReason) - if (nestedCountersInstance) nestedCountersInstance.countEvent('receipt', result.nestedCounterMessage) + for (const message of result.failedReasons) { + Logger.mainLogger.error(message) + } + for (const message of result.nestedCounterMessages) { + if (nestedCountersInstance) nestedCountersInstance.countEvent('receipt', message) + } if (profilerInstance) profilerInstance.profileSectionEnd('Validate_receipt') continue } diff --git a/src/Data/Cycles.ts b/src/Data/Cycles.ts index d0e5a324..79b24b70 100644 --- a/src/Data/Cycles.ts +++ b/src/Data/Cycles.ts @@ -522,7 +522,7 @@ function updateShardValues(cycle: P2PTypes.CycleCreatorTypes.CycleData): void { shardValuesByCycle.set(cycleShardData.cycleNumber, cycleShardData) } -const cleanShardCycleData = (cycleNumber: number): void => { +export const cleanShardCycleData = (cycleNumber: number): void => { for (const [key] of shardValuesByCycle) { if (key < cycleNumber) { shardValuesByCycle.delete(key) diff --git a/src/primary-process/index.ts b/src/primary-process/index.ts index e07071a4..96006923 100644 --- a/src/primary-process/index.ts +++ b/src/primary-process/index.ts @@ -4,18 +4,22 @@ import { ArchiverReceipt } from '../dbstore/receipts' import { verifyArchiverReceipt, ReceiptVerificationResult } from '../Data/Collector' import { config } from '../Config' import { EventEmitter } from 'events' +import { shardValuesByCycle } from '../Data/Cycles' +import { StateManager } from '@shardus/types' const MAX_WORKERS = cpus().length - 1 // Leaving 1 core for the master process export interface ChildMessageInterface { type: string data: { - receipt?: ArchiverReceipt + receipt?: string success?: boolean err?: string txId?: string timestamp?: number verificationResult?: ReceiptVerificationResult + cycle?: number + shardValues?: StateManager.shardFunctionTypes.CycleShardData } } @@ -48,6 +52,7 @@ export const setupWorkerProcesses = (cluster: Cluster): void => { const worker = workers.pop() if (worker) extraWorkers.set(worker.process.pid, worker) } + receiptLoadTraker = 0 return } let neededWorkers = Math.ceil(receiptLoadTraker / config.receiptLoadTrakerLimit) @@ -58,6 +63,12 @@ export const setupWorkerProcesses = (cluster: Cluster): void => { for (let i = currentWorkers; i < neededWorkers; i++) { const worker = cluster.fork() workers.push(worker) + for (const [cycle, shardValues] of shardValuesByCycle) { + worker.send({ + type: 'shardValuesByCycle', + data: { cycle, shardValues }, + }) + } // results.set(worker.process.pid, { success: 0, failure: 0 }) setupWorkerListeners(worker) } @@ -163,29 +174,26 @@ const forwardReceiptVerificationResult = ( worker.on('exit', () => { resolve({ success: false, - failedReason: `Worker exited before sending the receipt verification result for ${txId} with timestamp ${timestamp}`, - nestedCounterMessage: 'Worker exited before sending the receipt verification result', + failedReasons: [ + `Worker exited before sending the receipt verification result for ${txId} with timestamp ${timestamp}`, + ], + nestedCounterMessages: ['Worker exited before sending the receipt verification result'], }) }) }) } -// goActive() { -// nestedCountersInstance.countEvent('p2p', 'goActive') -// const activePromise = new Promise((resolve, reject) => { -// Self.emitter.on('active', () => resolve()) -// }) -// //Active.requestActive() -// console.log('return goActive promise...') -// return activePromise -// } - -export const offloadReceipt = async (receipt: ArchiverReceipt): Promise => { +export const offloadReceipt = async ( + txId: string, + timestamp: number, + receipt: string, + receipt2: ArchiverReceipt +): Promise => { receivedReceiptCount++ // Increment the counter for each receipt received receiptLoadTraker++ // Increment the receipt load tracker let verificationResult: ReceiptVerificationResult if (workers.length === 0) { - verificationResult = await verifyArchiverReceipt(receipt) + verificationResult = await verifyArchiverReceipt(receipt2) } else { // Forward the request to a worker in a round-robin fashion let worker = workers[currentWorker] @@ -199,26 +207,18 @@ export const offloadReceipt = async (receipt: ArchiverReceipt): Promise { return hash } -export const verifyAccountHash = (receipt: ArchiverReceipt): boolean => { +export const verifyAccountHash = ( + receipt: ArchiverReceipt, + failedReasons = [], + nestedCounterMessages = [] +): boolean => { try { if (receipt.globalModification && config.skipGlobalTxReceiptVerification) return true // return true if global modification if (receipt.accounts.length !== receipt.appliedReceipt.appliedVote.account_state_hash_after.length) { - Logger.mainLogger.error( + failedReasons.push( `Modified account count specified in the receipt and the actual updated account count does not match! ${receipt.tx.txId} , ${receipt.cycle} , ${receipt.tx.timestamp}` ) return false @@ -70,7 +74,7 @@ export const verifyAccountHash = (receipt: ArchiverReceipt): boolean => { receipt.appliedReceipt.appliedVote.account_state_hash_before.length !== receipt.appliedReceipt.appliedVote.account_state_hash_after.length ) { - Logger.mainLogger.error( + failedReasons.push( `Account state hash before and after count does not match! ${receipt.tx.txId} , ${receipt.cycle} , ${receipt.tx.timestamp}` ) return false @@ -79,7 +83,7 @@ export const verifyAccountHash = (receipt: ArchiverReceipt): boolean => { const calculatedAccountHash = accountSpecificHash(account.data) const indexOfAccount = receipt.appliedReceipt.appliedVote.account_id.indexOf(account.accountId) if (indexOfAccount === -1) { - Logger.mainLogger.error( + failedReasons.push( `Account not found in the receipt ${account.accountId} , ${receipt.tx.txId} , ${receipt.cycle} , ${receipt.tx.timestamp}` ) return false @@ -87,7 +91,7 @@ export const verifyAccountHash = (receipt: ArchiverReceipt): boolean => { // eslint-disable-next-line security/detect-object-injection const expectedAccountHash = receipt.appliedReceipt.appliedVote.account_state_hash_after[indexOfAccount] if (calculatedAccountHash !== expectedAccountHash) { - Logger.mainLogger.error( + failedReasons.push( `Account hash does not match ${account.accountId} , ${receipt.tx.txId} , ${receipt.cycle} , ${receipt.tx.timestamp}` ) return false @@ -95,7 +99,7 @@ export const verifyAccountHash = (receipt: ArchiverReceipt): boolean => { } return true } catch (e) { - Logger.mainLogger.error('Error in verifyAccountHash', e) + failedReasons.push('Error in verifyAccountHash', e) return false } } diff --git a/src/shardeum/verifyAppReceiptData.ts b/src/shardeum/verifyAppReceiptData.ts index df8b50bf..29d121a2 100644 --- a/src/shardeum/verifyAppReceiptData.ts +++ b/src/shardeum/verifyAppReceiptData.ts @@ -11,13 +11,15 @@ export type ShardeumReceipt = object & { export const verifyAppReceiptData = async ( receipt: ArchiverReceipt, - existingReceipt?: Receipt | null + existingReceipt?: Receipt | null, + failedReasons = [], + nestedCounterMessages = [] ): Promise<{ valid: boolean; needToSave: boolean }> => { let result = { valid: false, needToSave: false } const { appReceiptData, globalModification, appliedReceipt } = receipt const newShardeumReceipt = appReceiptData.data as ShardeumReceipt if (!newShardeumReceipt.amountSpent || !newShardeumReceipt.readableReceipt) { - Logger.mainLogger.error(`appReceiptData missing amountSpent or readableReceipt`) + failedReasons.push(`appReceiptData missing amountSpent or readableReceipt`) return result } if ( @@ -32,7 +34,7 @@ export const verifyAppReceiptData = async ( // eslint-disable-next-line security/detect-object-injection !appliedReceipt.appliedVote.account_state_hash_after[i] ) { - Logger.mainLogger.error( + failedReasons.push( `The account state hash before or after is missing in the receipt! ${receipt.tx.txId} , ${receipt.cycle} , ${receipt.tx.timestamp}` ) } @@ -42,7 +44,7 @@ export const verifyAppReceiptData = async ( // eslint-disable-next-line security/detect-object-injection appliedReceipt.appliedVote.account_state_hash_after[i] ) { - Logger.mainLogger.error( + failedReasons.push( `The receipt has 0 amountSpent and status 0 but has state updated accounts! ${receipt.tx.txId} , ${receipt.cycle} , ${receipt.tx.timestamp}` ) break @@ -84,7 +86,7 @@ export const verifyAppReceiptData = async ( if (existingShardeumReceipt.readableReceipt.status === 0) { if (newShardeumReceipt.readableReceipt.status === 1) { if (existingShardeumReceipt.amountSpent !== '0x0') { - Logger.mainLogger.error( + failedReasons.push( `Success and failed receipts with gas charged`, StringUtils.safeStringify(existingReceipt), StringUtils.safeStringify(receipt) @@ -92,7 +94,7 @@ export const verifyAppReceiptData = async ( } else result = { valid: true, needToSave: true } // Success receipt } else { if (existingShardeumReceipt.amountSpent !== '0x0' && newShardeumReceipt.amountSpent !== '0x0') { - Logger.mainLogger.error( + failedReasons.push( `Both failed receipts with gas charged`, StringUtils.safeStringify(existingReceipt), StringUtils.safeStringify(receipt) @@ -103,7 +105,7 @@ export const verifyAppReceiptData = async ( } } } else if (newShardeumReceipt.readableReceipt.status === 1) { - Logger.mainLogger.error( + failedReasons.push( `Duplicate success receipt`, StringUtils.safeStringify(existingReceipt), StringUtils.safeStringify(receipt) @@ -114,9 +116,9 @@ export const verifyAppReceiptData = async ( if (globalModification && config.skipGlobalTxReceiptVerification) return { valid: true, needToSave: true } // Finally verify appReceiptData hash const appReceiptDataCopy = { ...appReceiptData } - const calculatedAppReceiptDataHash = calculateAppReceiptDataHash(appReceiptDataCopy) + const calculatedAppReceiptDataHash = calculateAppReceiptDataHash(appReceiptDataCopy, failedReasons) if (calculatedAppReceiptDataHash !== receipt.appliedReceipt.app_data_hash) { - Logger.mainLogger.error( + failedReasons.push( `appReceiptData hash mismatch: ${crypto.hashObj(appReceiptData)} != ${ receipt.appliedReceipt.app_data_hash }` @@ -127,7 +129,7 @@ export const verifyAppReceiptData = async ( } // Converting the correct appReceipt data format to get the correct hash -const calculateAppReceiptDataHash = (appReceiptData): string => { +const calculateAppReceiptDataHash = (appReceiptData: any, failedReasons = []): string => { try { if (appReceiptData.data && appReceiptData.data.receipt) { if (appReceiptData.data.receipt.bitvector) @@ -153,7 +155,7 @@ const calculateAppReceiptDataHash = (appReceiptData): string => { const hash = crypto.hashObj(appReceiptData) return hash } catch (err) { - Logger.mainLogger.error(`calculateAppReceiptDataHash error: ${err}`) + failedReasons.push(`calculateAppReceiptDataHash error: ${err}`) return '' } } diff --git a/src/worker-process/index.ts b/src/worker-process/index.ts index 98485e91..7d10a4d2 100644 --- a/src/worker-process/index.ts +++ b/src/worker-process/index.ts @@ -1,6 +1,9 @@ import { verifyArchiverReceipt, ReceiptVerificationResult } from '../Data/Collector' import { ChildMessageInterface } from '../primary-process' import { config } from '../Config' +import { Utils as StringUtils } from '@shardus/types' +import { ArchiverReceipt } from '../dbstore/receipts' +import { cleanShardCycleData, shardValuesByCycle } from '../Data/Cycles' export const initWorkerProcess = async (): Promise => { console.log(`Worker ${process.pid} started`) @@ -14,25 +17,36 @@ export const initWorkerProcess = async (): Promise => { console.error(`Worker ${process.pid} received invalid receipt for verification`, data) return } + const receipt2 = StringUtils.safeJsonParse(data.receipt) as ArchiverReceipt // console.log(`Worker ${process.pid} verifying receipt`); - let verificationResult: ReceiptVerificationResult = { success: false } + let verificationResult: ReceiptVerificationResult = { + success: false, + failedReasons: [], + nestedCounterMessages: [], + } try { - verificationResult = await verifyArchiverReceipt(data.receipt) + verificationResult = await verifyArchiverReceipt(receipt2) } catch (error) { console.error(`Error in Worker ${process.pid} while verifying receipt`, error) - verificationResult.failedReason = 'Error in Worker while verifying receipt' - verificationResult.nestedCounterMessage = 'Error in Worker while verifying receipt' + verificationResult.failedReasons.push('Error in Worker while verifying receipt') + verificationResult.nestedCounterMessages.push('Error in Worker while verifying receipt') } process.send({ type: 'receipt-verification', data: { - txId: data.receipt.tx.txId, - timestamp: data.receipt.tx.timestamp, + txId: receipt2.tx.txId, + timestamp: receipt2.tx.timestamp, verificationResult, }, }) break } + case 'shardValuesByCycle': { + const { cycle, shardValues } = data + shardValuesByCycle.set(cycle, shardValues) + cleanShardCycleData(cycle - config.maxCyclesShardDataToKeep) + break + } default: console.log(`Worker ${process.pid} received unknown message type: ${type}`) console.log(data)