diff --git a/src/src/blockchain-indexer/processor/transaction/transaction-factory/TransactionFactory.ts b/src/src/blockchain-indexer/processor/transaction/transaction-factory/TransactionFactory.ts index 25d8c4508..3811c6da4 100644 --- a/src/src/blockchain-indexer/processor/transaction/transaction-factory/TransactionFactory.ts +++ b/src/src/blockchain-indexer/processor/transaction/transaction-factory/TransactionFactory.ts @@ -11,6 +11,9 @@ import { OPNetConsensus } from '../../../../poc/configurations/OPNetConsensus.js const EXPIRED_TRANSACTION_ERROR: string = 'Transaction was pending in the mempool for too long. It is no longer valid.'; +const MINER_SOLUTION_INVALID: string = + 'The provided solution does not match any of the allowed challenges for the miner. The transaction is no longer valid.'; + const INVALID_MINER_CHALLENGE_ERROR: string = 'The provided miner address does not have a valid challenge solution.'; @@ -37,17 +40,19 @@ export class TransactionFactory { // return; //} + //console.log('allowedChallenges', allowedChallenges, 'miner', miner, toHex(miner)); + const hasMiner = allowedChallenges.solutions.get(miner); if (!hasMiner) { throw new Error(EXPIRED_TRANSACTION_ERROR); } - const hasSolution = hasMiner.some((challenge) => { + const hasSolution = hasMiner.some((challenge: Uint8Array) => { return equals(challenge, preimage); }); if (!hasSolution) { - throw new Error(EXPIRED_TRANSACTION_ERROR); + throw new Error(MINER_SOLUTION_INVALID); } if (OPNetConsensus.allowUnsafeSignatures) { diff --git a/src/src/poc/mempool/manager/Mempool.ts b/src/src/poc/mempool/manager/Mempool.ts index f30233162..fcfb345ba 100644 --- a/src/src/poc/mempool/manager/Mempool.ts +++ b/src/src/poc/mempool/manager/Mempool.ts @@ -13,7 +13,10 @@ import { } from '../../../threading/interfaces/thread-messages/messages/api/RPCMessage.js'; import { BitcoinRPCThreadMessageType } from '../../../blockchain-indexer/rpc/thread/messages/BitcoinRPCThreadMessage.js'; import { OPNetBroadcastData } from '../../../threading/interfaces/thread-messages/messages/api/BroadcastTransactionOPNet.js'; -import { TransactionVerifierManager } from '../transaction/TransactionVerifierManager.js'; +import { + InvalidTransaction, + TransactionVerifierManager, +} from '../transaction/TransactionVerifierManager.js'; import { BitcoinRPC, FeeEstimation, SmartFeeEstimation } from '@btc-vision/bitcoin-rpc'; import { Config } from '../../../config/Config.js'; import { MempoolRepository } from '../../../db/repositories/MempoolRepository.js'; @@ -200,7 +203,7 @@ export class Mempool extends Logger { private async watchBlockchain(): Promise { this.blockchainInformationRepository.watchBlockChanges(async (blockHeight: bigint) => { - if (OPNetConsensus.getBlockHeight() < blockHeight) { + if (OPNetConsensus.getBlockHeight() <= blockHeight) { await this.onBlockChange(blockHeight); } @@ -219,6 +222,8 @@ export class Mempool extends Logger { try { OPNetConsensus.setBlockHeight(blockHeight); + this.log(`[MEM] Block changed to height ${blockHeight}`); + await this.transactionVerifier.onBlockChange(blockHeight); /*if (Config.MEMPOOL.ENABLE_BLOCK_PURGE) { @@ -382,10 +387,10 @@ export class Mempool extends Logger { } const decodedTransaction = await this.transactionVerifier.verify(transaction); - if (!decodedTransaction) { + if (!decodedTransaction || !decodedTransaction.success) { return { success: false, - result: 'Could not decode transaction.', + result: `Could not decode transaction (${(decodedTransaction as InvalidTransaction).error})`, }; } diff --git a/src/src/poc/mempool/transaction/TransactionVerifierManager.ts b/src/src/poc/mempool/transaction/TransactionVerifierManager.ts index 87e36d27a..8f804dfa5 100644 --- a/src/src/poc/mempool/transaction/TransactionVerifierManager.ts +++ b/src/src/poc/mempool/transaction/TransactionVerifierManager.ts @@ -21,11 +21,19 @@ export interface PSBTDecodedData { readonly estimatedFees: bigint; } -export interface IKnownTransaction { +export interface MempoolTransaction { + readonly success: boolean; +} + +export interface IKnownTransaction extends MempoolTransaction { readonly type: TransactionTypes; readonly version: Consensus; } +export interface InvalidTransaction extends MempoolTransaction { + readonly error: string; +} + export interface KnownPSBTObject extends IKnownTransaction { readonly psbt: Psbt; readonly data: PSBTDecodedData; @@ -66,7 +74,7 @@ export class TransactionVerifierManager extends Logger { public async verify( tx: IMempoolTransactionObj, txData?: TransactionData, - ): Promise { + ): Promise { const psbtType: TransactionTypes = tx.data[0]; const verificator = this.verificator.find((v) => @@ -82,7 +90,10 @@ export class TransactionVerifierManager extends Logger { } if (!psbtOrTransaction) { - return false; + return { + success: false, + error: 'PSBTs are not allowed.', + }; } return await verificator.verify(tx, psbtOrTransaction, txData); diff --git a/src/src/poc/mempool/verificator/TransactionVerifier.ts b/src/src/poc/mempool/verificator/TransactionVerifier.ts index 4c4c21374..7ed1759e3 100644 --- a/src/src/poc/mempool/verificator/TransactionVerifier.ts +++ b/src/src/poc/mempool/verificator/TransactionVerifier.ts @@ -1,7 +1,10 @@ import { ConfigurableDBManager, Logger } from '@btc-vision/bsi-common'; import { TransactionTypes } from '../transaction/TransactionTypes.js'; import { Network, networks, Psbt, Transaction } from '@btc-vision/bitcoin'; -import { IKnownTransaction } from '../transaction/TransactionVerifierManager.js'; +import { + IKnownTransaction, + InvalidTransaction, +} from '../transaction/TransactionVerifierManager.js'; import { IMempoolTransactionObj } from '../../../db/interfaces/IMempoolTransaction.js'; import { BitcoinRPC, TransactionData } from '@btc-vision/bitcoin-rpc'; @@ -35,7 +38,7 @@ export abstract class TransactionVerifier< tx: IMempoolTransactionObj, data: Psbt | Transaction, txData?: TransactionData, - ): Promise; + ): Promise; protected abstract onBlockChange(blockHeight: bigint): void | Promise; diff --git a/src/src/poc/mempool/verificator/bitcoin/v2/BitcoinTransactionVerificatorV2.ts b/src/src/poc/mempool/verificator/bitcoin/v2/BitcoinTransactionVerificatorV2.ts index c7f6ff860..93a32dcef 100644 --- a/src/src/poc/mempool/verificator/bitcoin/v2/BitcoinTransactionVerificatorV2.ts +++ b/src/src/poc/mempool/verificator/bitcoin/v2/BitcoinTransactionVerificatorV2.ts @@ -2,9 +2,11 @@ import { TransactionVerifier } from '../../TransactionVerifier.js'; import { TransactionTypes } from '../../../transaction/TransactionTypes.js'; import { Network, networks, toHex, Transaction } from '@btc-vision/bitcoin'; import { ConfigurableDBManager } from '@btc-vision/bsi-common'; -import { KnownTransaction } from '../../../transaction/TransactionVerifierManager.js'; +import { InvalidTransaction, KnownTransaction, } from '../../../transaction/TransactionVerifierManager.js'; import { Config } from '../../../../../config/Config.js'; -import { TransactionFactory } from '../../../../../blockchain-indexer/processor/transaction/transaction-factory/TransactionFactory.js'; +import { + TransactionFactory +} from '../../../../../blockchain-indexer/processor/transaction/transaction-factory/TransactionFactory.js'; import { IMempoolTransactionObj } from '../../../../../db/interfaces/IMempoolTransaction.js'; import { TransactionData, VOut } from '@btc-vision/bitcoin-rpc/src/rpc/types/BlockData.js'; import { BitcoinRPC } from '@btc-vision/bitcoin-rpc'; @@ -14,10 +16,18 @@ import { OPNetConsensus } from '../../../../configurations/OPNetConsensus.js'; import { ChallengeSolution } from '../../../../../blockchain-indexer/processor/interfaces/TransactionPreimage.js'; import { AddressMap } from '@btc-vision/transaction'; import { EpochRepository } from '../../../../../db/repositories/EpochRepository.js'; -import { OPNetTransactionTypes } from '../../../../../blockchain-indexer/processor/transaction/enums/OPNetTransactionTypes.js'; -import { Transaction as OPNetDecodedTransaction } from '../../../../../blockchain-indexer/processor/transaction/Transaction.js'; -import { InteractionTransaction } from '../../../../../blockchain-indexer/processor/transaction/transactions/InteractionTransaction.js'; -import { DeploymentTransaction } from '../../../../../blockchain-indexer/processor/transaction/transactions/DeploymentTransaction.js'; +import { + OPNetTransactionTypes +} from '../../../../../blockchain-indexer/processor/transaction/enums/OPNetTransactionTypes.js'; +import { + Transaction as OPNetDecodedTransaction +} from '../../../../../blockchain-indexer/processor/transaction/Transaction.js'; +import { + InteractionTransaction +} from '../../../../../blockchain-indexer/processor/transaction/transactions/InteractionTransaction.js'; +import { + DeploymentTransaction +} from '../../../../../blockchain-indexer/processor/transaction/transactions/DeploymentTransaction.js'; const EMPTY_BLOCK_HASH = toHex(new Uint8Array(32)); @@ -34,6 +44,9 @@ export class BitcoinTransactionVerificatorV2 extends TransactionVerifier = Promise.resolve(); + private currentSolutionsHeight: bigint = -1n; + public constructor( db: ConfigurableDBManager, rpc: BitcoinRPC, @@ -52,11 +65,26 @@ export class BitcoinTransactionVerificatorV2 extends TransactionVerifier { + public onBlockChange(blockHeight: bigint): Promise { + this.blockChangeQueue = this.blockChangeQueue.then(async () => { + if (blockHeight === this.currentSolutionsHeight) { + return; + } + + this.allowedChallenges = + this.epochRepository.getChallengeSolutionsAtHeight(blockHeight); + await this.allowedChallenges; + this.currentSolutionsHeight = blockHeight; + }); + + return this.blockChangeQueue; + } + + /*public async onBlockChange(blockHeight: bigint): Promise { await this.allowedChallenges; // Don't flood the database on quick block changes this.allowedChallenges = this.epochRepository.getChallengeSolutionsAtHeight(blockHeight); - } + }*/ public createRepositories(): void { if (!this.db || !this.db.db) { @@ -70,10 +98,11 @@ export class BitcoinTransactionVerificatorV2 extends TransactionVerifier { - let tx: KnownTransaction | false = false; + ): Promise { + let tx: KnownTransaction | InvalidTransaction; try { const solutions = await this.allowedChallenges; + const decoded = !txData ? this.toRawTransactionData(data) : txData; const opnetDecodedTransaction = this.transactionFactory.parseTransaction( decoded, @@ -84,6 +113,7 @@ export class BitcoinTransactionVerificatorV2 extends TransactionVerifier