diff --git a/yarn-project/aztec-node/src/aztec-node/server.test.ts b/yarn-project/aztec-node/src/aztec-node/server.test.ts index 0638a90c397e..a139ac0611ee 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.test.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.test.ts @@ -14,7 +14,7 @@ import { RollupValidationRequests } from '@aztec/stdlib/kernel'; import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging'; import { mockTx } from '@aztec/stdlib/testing'; import { MerkleTreeId, PublicDataTreeLeaf, PublicDataTreeLeafPreimage } from '@aztec/stdlib/trees'; -import { BlockHeader, GlobalVariables, MaxBlockNumber } from '@aztec/stdlib/tx'; +import { BlockHeader, GlobalVariables, MaxBlockNumber, TX_ERROR_INVALID_BLOCK_NUMBER } from '@aztec/stdlib/tx'; import { readFileSync } from 'fs'; import { type MockProxy, mock } from 'jest-mock-extended'; @@ -219,7 +219,7 @@ describe('aztec node', () => { // Tx with max block number < current block number should be invalid expect(await node.isValidTx(invalidMaxBlockNumberMetadata)).toEqual({ result: 'invalid', - reason: ['Invalid block number'], + reason: [TX_ERROR_INVALID_BLOCK_NUMBER], }); // Tx with max block number >= current block number should be valid expect(await node.isValidTx(validMaxBlockNumberMetadata)).toEqual({ result: 'valid' }); diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 73d576dc15c1..add57779aecf 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -463,13 +463,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable { * @param tx - The transaction to be submitted. */ public async sendTx(tx: Tx) { - await this.txQueue - .put(async () => { - await this.#sendTx(tx); - }) - .catch(error => { - this.log.error(`Error sending tx`, { error }); - }); + await this.txQueue.put(() => this.#sendTx(tx)); } async #sendTx(tx: Tx) { @@ -480,10 +474,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable { if (valid.result !== 'valid') { const reason = valid.reason.join(', '); this.metrics.receivedTx(timer.ms(), false); - this.log.warn(`Invalid tx ${txHash}: ${reason}`, { txHash }); - // TODO(#10967): Throw when receiving an invalid tx instead of just returning - // throw new Error(`Invalid tx: ${reason}`); - return; + this.log.warn(`Received invalid tx ${txHash}: ${reason}`, { txHash }); + throw new Error(`Invalid tx: ${reason}`); } await this.p2pClient!.sendTx(tx); diff --git a/yarn-project/end-to-end/src/e2e_block_building.test.ts b/yarn-project/end-to-end/src/e2e_block_building.test.ts index 3840c06eb70b..a9218ff6b1ac 100644 --- a/yarn-project/end-to-end/src/e2e_block_building.test.ts +++ b/yarn-project/end-to-end/src/e2e_block_building.test.ts @@ -34,7 +34,7 @@ import { TelemetryPublicTxSimulator, } from '@aztec/simulator/server'; import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client'; -import type { Tx } from '@aztec/stdlib/tx'; +import { TX_ERROR_EXISTING_NULLIFIER, type Tx } from '@aztec/stdlib/tx'; import type { TelemetryClient } from '@aztec/telemetry-client'; import { jest } from '@jest/globals'; @@ -369,7 +369,9 @@ describe('e2e_block_building', () => { it('private -> private', async () => { const nullifier = Fr.random(); await contract.methods.emit_nullifier(nullifier).send().wait(); - await expect(contract.methods.emit_nullifier(nullifier).send().wait()).rejects.toThrow('dropped'); + await expect(contract.methods.emit_nullifier(nullifier).send().wait()).rejects.toThrow( + TX_ERROR_EXISTING_NULLIFIER, + ); }); it('public -> public', async () => { @@ -391,7 +393,9 @@ describe('e2e_block_building', () => { it('public -> private', async () => { const nullifier = Fr.random(); await contract.methods.emit_nullifier_public(nullifier).send().wait(); - await expect(contract.methods.emit_nullifier(nullifier).send().wait()).rejects.toThrow('dropped'); + await expect(contract.methods.emit_nullifier(nullifier).send().wait()).rejects.toThrow( + TX_ERROR_EXISTING_NULLIFIER, + ); }); }); }); diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract/legacy.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract/legacy.test.ts index ac1496d36178..ca9b326faede 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract/legacy.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract/legacy.test.ts @@ -12,6 +12,7 @@ import { import { StatefulTestContract } from '@aztec/noir-contracts.js/StatefulTest'; import { TestContractArtifact } from '@aztec/noir-contracts.js/Test'; import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token'; +import { TX_ERROR_EXISTING_NULLIFIER } from '@aztec/stdlib/tx'; import { DeployTest } from './deploy_test.js'; @@ -82,7 +83,7 @@ describe('e2e_deploy_contract legacy', () => { const deployer = new ContractDeployer(TestContractArtifact, wallet); await deployer.deploy().send({ contractAddressSalt }).wait({ wallet }); - await expect(deployer.deploy().send({ contractAddressSalt }).wait()).rejects.toThrow(/dropped/); + await expect(deployer.deploy().send({ contractAddressSalt }).wait()).rejects.toThrow(TX_ERROR_EXISTING_NULLIFIER); }); it('should not deploy a contract which failed the public part of the execution', async () => { diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract/private_initialization.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract/private_initialization.test.ts index f0a9b5b8ab39..463e3e33f2e4 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract/private_initialization.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract/private_initialization.test.ts @@ -2,6 +2,7 @@ import { type AztecNode, BatchCall, Fr, type Logger, type Wallet } from '@aztec/ import { StatefulTestContract } from '@aztec/noir-contracts.js/StatefulTest'; import { TestContract } from '@aztec/noir-contracts.js/Test'; import { siloNullifier } from '@aztec/stdlib/hash'; +import { TX_ERROR_EXISTING_NULLIFIER } from '@aztec/stdlib/tx'; import { DeployTest, type StatefulContractCtorArgs } from './deploy_test.js'; @@ -87,7 +88,7 @@ describe('e2e_deploy_contract private initialization', () => { .constructor(...initArgs) .send() .wait(), - ).rejects.toThrow(/dropped/); + ).rejects.toThrow(TX_ERROR_EXISTING_NULLIFIER); }); it('refuses to call a private function that requires initialization', async () => { diff --git a/yarn-project/end-to-end/src/e2e_fees/fee_settings.test.ts b/yarn-project/end-to-end/src/e2e_fees/fee_settings.test.ts index a3ca4d1407cb..22bc1e41a1b3 100644 --- a/yarn-project/end-to-end/src/e2e_fees/fee_settings.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/fee_settings.test.ts @@ -9,6 +9,7 @@ import { CheatCodes } from '@aztec/aztec.js/testing'; import { Fr } from '@aztec/foundation/fields'; import { TestContract } from '@aztec/noir-contracts.js/Test'; import type { GasSettings } from '@aztec/stdlib/gas'; +import { TX_ERROR_INSUFFICIENT_FEE_PER_GAS } from '@aztec/stdlib/tx'; import { inspect } from 'util'; @@ -82,7 +83,7 @@ describe('e2e_fees fee settings', () => { const sentWithNoPadding = txWithNoPadding.send(); const sentWithDefaultPadding = txWithDefaultPadding.send(); t.logger.info(`Awaiting txs`); - await expect(sentWithNoPadding.wait({ timeout: 30 })).rejects.toThrow(/dropped./i); + await expect(sentWithNoPadding.wait({ timeout: 30 })).rejects.toThrow(TX_ERROR_INSUFFICIENT_FEE_PER_GAS); await sentWithDefaultPadding.wait({ timeout: 30 }); }); }); diff --git a/yarn-project/end-to-end/src/e2e_max_block_number.test.ts b/yarn-project/end-to-end/src/e2e_max_block_number.test.ts index b83d613ad36a..f3be958e55ec 100644 --- a/yarn-project/end-to-end/src/e2e_max_block_number.test.ts +++ b/yarn-project/end-to-end/src/e2e_max_block_number.test.ts @@ -1,5 +1,6 @@ import { Fr, type PXE, type Wallet } from '@aztec/aztec.js'; import { TestContract } from '@aztec/noir-contracts.js/Test'; +import { TX_ERROR_INVALID_BLOCK_NUMBER } from '@aztec/stdlib/tx'; import { setup } from './fixtures/utils.js'; @@ -72,7 +73,7 @@ describe('e2e_max_block_number', () => { it('invalidates the transaction', async () => { await expect( contract.methods.set_tx_max_block_number(maxBlockNumber, enqueuePublicCall).send().wait(), - ).rejects.toThrow('dropped'); + ).rejects.toThrow(TX_ERROR_INVALID_BLOCK_NUMBER); }); }); @@ -88,7 +89,7 @@ describe('e2e_max_block_number', () => { it('invalidates the transaction', async () => { await expect( contract.methods.set_tx_max_block_number(maxBlockNumber, enqueuePublicCall).send().wait(), - ).rejects.toThrow('dropped'); + ).rejects.toThrow(TX_ERROR_INVALID_BLOCK_NUMBER); }); }); }); diff --git a/yarn-project/end-to-end/src/e2e_private_voting_contract.test.ts b/yarn-project/end-to-end/src/e2e_private_voting_contract.test.ts index 353bd81b11ed..9c2c4f0c5fc4 100644 --- a/yarn-project/end-to-end/src/e2e_private_voting_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_private_voting_contract.test.ts @@ -1,5 +1,6 @@ import { type AccountWallet, type AztecAddress, Fr, type Logger } from '@aztec/aztec.js'; import { EasyPrivateVotingContract } from '@aztec/noir-contracts.js/EasyPrivateVoting'; +import { TX_ERROR_EXISTING_NULLIFIER } from '@aztec/stdlib/tx'; import { setup } from './fixtures/utils.js'; @@ -33,10 +34,10 @@ describe('e2e_voting_contract', () => { // We try voting again, but our TX is dropped due to trying to emit duplicate nullifiers // first confirm that it fails simulation await expect(votingContract.methods.cast_vote(candidate).send().wait()).rejects.toThrow(/Nullifier collision/); - // if we skip simulation, tx is dropped + // if we skip simulation, tx fails await expect( votingContract.methods.cast_vote(candidate).send({ skipPublicSimulation: true }).wait(), - ).rejects.toThrow('Reason: Tx dropped by P2P node.'); + ).rejects.toThrow(TX_ERROR_EXISTING_NULLIFIER); }); }); }); diff --git a/yarn-project/end-to-end/src/e2e_prover/full.test.ts b/yarn-project/end-to-end/src/e2e_prover/full.test.ts index 5513acf3b731..ec11af9b07c5 100644 --- a/yarn-project/end-to-end/src/e2e_prover/full.test.ts +++ b/yarn-project/end-to-end/src/e2e_prover/full.test.ts @@ -8,6 +8,7 @@ import { FeeJuicePortalAbi, RewardDistributorAbi, TestERC20Abi } from '@aztec/l1 import { Gas } from '@aztec/stdlib/gas'; import { PrivateKernelTailCircuitPublicInputs } from '@aztec/stdlib/kernel'; import { ClientIvcProof } from '@aztec/stdlib/proofs'; +import { TX_ERROR_INVALID_PROOF } from '@aztec/stdlib/tx'; import TOML from '@iarna/toml'; import '@jest/globals'; @@ -285,8 +286,8 @@ describe('full_prover', () => { sentPublicTx.wait({ timeout: 10, interval: 0.1 }), ]); - expect(String((results[0] as PromiseRejectedResult).reason)).toMatch(/Tx dropped by P2P node/); - expect(String((results[1] as PromiseRejectedResult).reason)).toMatch(/Tx dropped by P2P node/); + expect(String((results[0] as PromiseRejectedResult).reason)).toMatch(TX_ERROR_INVALID_PROOF); + expect(String((results[1] as PromiseRejectedResult).reason)).toMatch(TX_ERROR_INVALID_PROOF); }); it( @@ -352,9 +353,7 @@ describe('full_prover', () => { // Assert that the large influx of invalid txs are rejected and do not ddos the node for (let i = 0; i < NUM_INVALID_TXS; i++) { - const invalidTxReceipt = (results[i] as PromiseFulfilledResult>).value; - expect(invalidTxReceipt.status).toBe(TxStatus.DROPPED); - expect(invalidTxReceipt.error).toMatch(/Tx dropped by P2P node/); + expect(String((results[i] as PromiseRejectedResult).reason)).toMatch(TX_ERROR_INVALID_PROOF); } // Assert that the valid tx is successfully sent and mined diff --git a/yarn-project/end-to-end/src/fixtures/fixtures.ts b/yarn-project/end-to-end/src/fixtures/fixtures.ts index e4241b665dc4..119b4ecae46f 100644 --- a/yarn-project/end-to-end/src/fixtures/fixtures.ts +++ b/yarn-project/end-to-end/src/fixtures/fixtures.ts @@ -18,7 +18,7 @@ export const U128_UNDERFLOW_ERROR = "Assertion failed: attempt to subtract with export const U128_OVERFLOW_ERROR = "Assertion failed: attempt to add with overflow 'self + other'"; export const BITSIZE_TOO_BIG_ERROR = "Assertion failed: call to assert_max_bit_size 'self.__assert_max_bit_size'"; // TODO(https://github.com/AztecProtocol/aztec-packages/issues/5818): Make these a fixed error after transition. -export const DUPLICATE_NULLIFIER_ERROR = /dropped|duplicate nullifier|reverted|Nullifier collision/; +export const DUPLICATE_NULLIFIER_ERROR = /dropped|nullifier|reverted/i; export const NO_L1_TO_L2_MSG_ERROR = /No non-nullified L1 to L2 message found for message hash|Tried to consume nonexistent L1-to-L2 message/; export const STATIC_CALL_STATE_MODIFICATION_ERROR = diff --git a/yarn-project/end-to-end/src/guides/dapp_testing.test.ts b/yarn-project/end-to-end/src/guides/dapp_testing.test.ts index 0d0c9f68cace..770ada9d6446 100644 --- a/yarn-project/end-to-end/src/guides/dapp_testing.test.ts +++ b/yarn-project/end-to-end/src/guides/dapp_testing.test.ts @@ -142,7 +142,7 @@ describe('guides/dapp/testing', () => { const provenCall2 = await call2.prove(); await provenCall1.send().wait(); - await expect(provenCall2.send().wait()).rejects.toThrow(/dropped/); + await expect(provenCall2.send().wait()).rejects.toThrow(/dropped|nullifier/i); // docs:end:tx-dropped }); diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/block_header_validator.test.ts b/yarn-project/p2p/src/msg_validators/tx_validator/block_header_validator.test.ts index d884db8b1504..6ffc57e619a0 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/block_header_validator.test.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/block_header_validator.test.ts @@ -1,6 +1,6 @@ import { Fr } from '@aztec/foundation/fields'; import { mockTxForRollup } from '@aztec/stdlib/testing'; -import type { AnyTx, TxValidationResult } from '@aztec/stdlib/tx'; +import { type AnyTx, TX_ERROR_BLOCK_HEADER, type TxValidationResult } from '@aztec/stdlib/tx'; import { type MockProxy, mock, mockFn } from 'jest-mock-extended'; @@ -35,7 +35,7 @@ describe('BlockHeaderTxValidator', () => { await expect(txValidator.validateTx(goodTx)).resolves.toEqual({ result: 'valid' } satisfies TxValidationResult); await expect(txValidator.validateTx(badTx)).resolves.toEqual({ result: 'invalid', - reason: ['Block header not found'], + reason: [TX_ERROR_BLOCK_HEADER], } satisfies TxValidationResult); }); }); diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/block_header_validator.ts b/yarn-project/p2p/src/msg_validators/tx_validator/block_header_validator.ts index 7fc56869ed56..266ea84efe06 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/block_header_validator.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/block_header_validator.ts @@ -1,6 +1,6 @@ import type { Fr } from '@aztec/foundation/fields'; import { createLogger } from '@aztec/foundation/log'; -import { type AnyTx, Tx, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx'; +import { type AnyTx, TX_ERROR_BLOCK_HEADER, Tx, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx'; export interface ArchiveSource { getArchiveIndices: (archives: Fr[]) => Promise<(bigint | undefined)[]>; @@ -18,7 +18,7 @@ export class BlockHeaderTxValidator implements TxValidator { const [index] = await this.#archiveSource.getArchiveIndices([await tx.data.constants.historicalHeader.hash()]); if (index === undefined) { this.#log.warn(`Rejecting tx ${await Tx.getHash(tx)} for referencing an unknown block header`); - return { result: 'invalid', reason: ['Block header not found'] }; + return { result: 'invalid', reason: [TX_ERROR_BLOCK_HEADER] }; } return { result: 'valid' }; } diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/data_validator.test.ts b/yarn-project/p2p/src/msg_validators/tx_validator/data_validator.test.ts index 866f8e978883..e8f51b574522 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/data_validator.test.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/data_validator.test.ts @@ -5,7 +5,15 @@ import { AztecAddress } from '@aztec/stdlib/aztec-address'; import { ScopedLogHash } from '@aztec/stdlib/kernel'; import { ContractClassLog } from '@aztec/stdlib/logs'; import { mockTx } from '@aztec/stdlib/testing'; -import type { Tx } from '@aztec/stdlib/tx'; +import { + TX_ERROR_CALLDATA_COUNT_MISMATCH, + TX_ERROR_CALLDATA_COUNT_TOO_LARGE, + TX_ERROR_CONTRACT_CLASS_LOGS, + TX_ERROR_CONTRACT_CLASS_LOG_COUNT, + TX_ERROR_CONTRACT_CLASS_LOG_LENGTH, + TX_ERROR_INCORRECT_CALLDATA, + type Tx, +} from '@aztec/stdlib/tx'; import { DataTxValidator } from './data_validator.js'; @@ -98,7 +106,7 @@ describe('TxDataValidator', () => { for (let i = 0; i < badTxSettings.length; i++) { const badTx = await mockTx(2, badTxSettings[i]); - await expectInvalid(badTx, 'Total calldata too large for enqueued public calls'); + await expectInvalid(badTx, TX_ERROR_CALLDATA_COUNT_TOO_LARGE); } }); @@ -110,8 +118,8 @@ describe('TxDataValidator', () => { await expectValid(goodTxs); - await expectInvalid(badTxs[0], 'Incorrect calldata for public call'); - await expectInvalid(badTxs[1], 'Incorrect calldata for public call'); + await expectInvalid(badTxs[0], TX_ERROR_INCORRECT_CALLDATA); + await expectInvalid(badTxs[1], TX_ERROR_INCORRECT_CALLDATA); }); it('rejects txs with mismatch calldata for revertible public calls', async () => { @@ -122,8 +130,8 @@ describe('TxDataValidator', () => { await expectValid(goodTxs); - await expectInvalid(badTxs[0], 'Incorrect calldata for public call'); - await expectInvalid(badTxs[1], 'Incorrect calldata for public call'); + await expectInvalid(badTxs[0], TX_ERROR_INCORRECT_CALLDATA); + await expectInvalid(badTxs[1], TX_ERROR_INCORRECT_CALLDATA); }); it('rejects txs with mismatch calldata for teardown call', async () => { @@ -134,8 +142,8 @@ describe('TxDataValidator', () => { await expectValid(goodTxs); - await expectInvalid(badTxs[0], 'Incorrect calldata for public call'); - await expectInvalid(badTxs[1], 'Incorrect calldata for public call'); + await expectInvalid(badTxs[0], TX_ERROR_INCORRECT_CALLDATA); + await expectInvalid(badTxs[1], TX_ERROR_INCORRECT_CALLDATA); }); it('rejects txs with mismatch number of calldata', async () => { @@ -148,8 +156,8 @@ describe('TxDataValidator', () => { await expectValid(goodTxs); - await expectInvalid(badTxs[0], 'Wrong number of calldata for public calls'); - await expectInvalid(badTxs[1], 'Wrong number of calldata for public calls'); + await expectInvalid(badTxs[0], TX_ERROR_CALLDATA_COUNT_MISMATCH); + await expectInvalid(badTxs[1], TX_ERROR_CALLDATA_COUNT_MISMATCH); }); it('rejects txs with mismatch number of contract class logs', async () => { @@ -169,8 +177,8 @@ describe('TxDataValidator', () => { await expectValid(goodTxs); - await expectInvalid(badTxs[0], 'Mismatched number of contract class logs'); - await expectInvalid(badTxs[1], 'Mismatched number of contract class logs'); + await expectInvalid(badTxs[0], TX_ERROR_CONTRACT_CLASS_LOG_COUNT); + await expectInvalid(badTxs[1], TX_ERROR_CONTRACT_CLASS_LOG_COUNT); }); // Can uncomment below if MAX_CONTRACT_CLASS_LOGS_PER_TX > 1: @@ -201,8 +209,8 @@ describe('TxDataValidator', () => { await expectValid(goodTxs); - await expectInvalid(badTxs[0], 'Mismatched contract class logs'); - await expectInvalid(badTxs[1], 'Mismatched contract class logs'); + await expectInvalid(badTxs[0], TX_ERROR_CONTRACT_CLASS_LOGS); + await expectInvalid(badTxs[1], TX_ERROR_CONTRACT_CLASS_LOGS); }); it('rejects txs with mismatched contract class logs length', async () => { @@ -217,7 +225,7 @@ describe('TxDataValidator', () => { await expectValid(goodTxs); - await expectInvalid(badTxs[0], 'Mismatched contract class logs length'); - await expectInvalid(badTxs[1], 'Mismatched contract class logs length'); + await expectInvalid(badTxs[0], TX_ERROR_CONTRACT_CLASS_LOG_LENGTH); + await expectInvalid(badTxs[1], TX_ERROR_CONTRACT_CLASS_LOG_LENGTH); }); }); diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/data_validator.ts b/yarn-project/p2p/src/msg_validators/tx_validator/data_validator.ts index ce913332b381..939d7d7c7198 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/data_validator.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/data_validator.ts @@ -1,7 +1,18 @@ import { MAX_FR_CALLDATA_TO_ALL_ENQUEUED_CALLS } from '@aztec/constants'; import { createLogger } from '@aztec/foundation/log'; import { computeCalldataHash } from '@aztec/stdlib/hash'; -import { Tx, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx'; +import { + TX_ERROR_CALLDATA_COUNT_MISMATCH, + TX_ERROR_CALLDATA_COUNT_TOO_LARGE, + TX_ERROR_CONTRACT_CLASS_LOGS, + TX_ERROR_CONTRACT_CLASS_LOG_COUNT, + TX_ERROR_CONTRACT_CLASS_LOG_LENGTH, + TX_ERROR_CONTRACT_CLASS_LOG_SORTING, + TX_ERROR_INCORRECT_CALLDATA, + Tx, + type TxValidationResult, + type TxValidator, +} from '@aztec/stdlib/tx'; export class DataTxValidator implements TxValidator { #log = createLogger('p2p:tx_validator:tx_data'); @@ -14,7 +25,7 @@ export class DataTxValidator implements TxValidator { async #hasCorrectCalldata(tx: Tx): Promise { if (tx.publicFunctionCalldata.length !== tx.numberOfPublicCalls()) { - const reason = 'Wrong number of calldata for public calls'; + const reason = TX_ERROR_CALLDATA_COUNT_MISMATCH; this.#log.warn( `Rejecting tx ${await Tx.getHash(tx)}. Reason: ${reason}. Expected ${tx.numberOfPublicCalls()}. Got ${ tx.publicFunctionCalldata.length @@ -24,7 +35,7 @@ export class DataTxValidator implements TxValidator { } if (tx.getTotalPublicCalldataCount() > MAX_FR_CALLDATA_TO_ALL_ENQUEUED_CALLS) { - const reason = 'Total calldata too large for enqueued public calls'; + const reason = TX_ERROR_CALLDATA_COUNT_TOO_LARGE; this.#log.warn( `Rejecting tx ${await Tx.getHash( tx, @@ -38,7 +49,7 @@ export class DataTxValidator implements TxValidator { const { request, calldata } = callRequests[i]; const hash = await computeCalldataHash(calldata); if (!hash.equals(request.calldataHash)) { - const reason = 'Incorrect calldata for public call'; + const reason = TX_ERROR_INCORRECT_CALLDATA; this.#log.warn(`Rejecting tx ${await Tx.getHash(tx)}. Reason: ${reason}. Call request index: ${i}.`); return { result: 'invalid', reason: [reason] }; } @@ -56,7 +67,7 @@ export class DataTxValidator implements TxValidator { contractClassLogsHashes.length }. Got ${hashedContractClasslogs.length}.`, ); - return { result: 'invalid', reason: ['Mismatched number of contract class logs'] }; + return { result: 'invalid', reason: [TX_ERROR_CONTRACT_CLASS_LOG_COUNT] }; } for (const [i, logHash] of contractClassLogsHashes.entries()) { const hashedLog = hashedContractClasslogs[i]; @@ -68,14 +79,14 @@ export class DataTxValidator implements TxValidator { tx, )} because of mismatched contract class logs indices. Expected ${i} from the kernel's log hashes. Got ${matchingLogIndex} in the tx.`, ); - return { result: 'invalid', reason: ['Incorrectly sorted contract class logs'] }; + return { result: 'invalid', reason: [TX_ERROR_CONTRACT_CLASS_LOG_SORTING] }; } else { this.#log.warn( `Rejecting tx ${await Tx.getHash(tx)} because of mismatched contract class logs. Expected hash ${ logHash.value } from the kernels. Got ${hashedLog} in the tx.`, ); - return { result: 'invalid', reason: ['Mismatched contract class logs'] }; + return { result: 'invalid', reason: [TX_ERROR_CONTRACT_CLASS_LOGS] }; } } if (logHash.logHash.length !== tx.contractClassLogs[i].getEmittedLength()) { @@ -84,7 +95,7 @@ export class DataTxValidator implements TxValidator { logHash.logHash.length } from the kernel's log hashes. Got ${tx.contractClassLogs[i].getEmittedLength()} in the tx.`, ); - return { result: 'invalid', reason: ['Mismatched contract class logs length'] }; + return { result: 'invalid', reason: [TX_ERROR_CONTRACT_CLASS_LOG_LENGTH] }; } } return { result: 'valid' }; diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/double_spend_validator.test.ts b/yarn-project/p2p/src/msg_validators/tx_validator/double_spend_validator.test.ts index 4ad6b44e3af6..2085acbab360 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/double_spend_validator.test.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/double_spend_validator.test.ts @@ -1,5 +1,5 @@ import { mockTx, mockTxForRollup } from '@aztec/stdlib/testing'; -import type { AnyTx } from '@aztec/stdlib/tx'; +import { type AnyTx, TX_ERROR_DUPLICATE_NULLIFIER_IN_TX, TX_ERROR_EXISTING_NULLIFIER } from '@aztec/stdlib/tx'; import { type MockProxy, mock } from 'jest-mock-extended'; @@ -29,7 +29,7 @@ describe('DoubleSpendTxValidator', () => { }); badTx.data.forPublic!.nonRevertibleAccumulatedData.nullifiers[1] = badTx.data.forPublic!.nonRevertibleAccumulatedData.nullifiers[0]; - await expectInvalid(badTx, 'Duplicate nullifier in tx'); + await expectInvalid(badTx, TX_ERROR_DUPLICATE_NULLIFIER_IN_TX); }); it('rejects duplicates in revertible data', async () => { @@ -40,7 +40,7 @@ describe('DoubleSpendTxValidator', () => { }); badTx.data.forPublic!.revertibleAccumulatedData.nullifiers[1] = badTx.data.forPublic!.revertibleAccumulatedData.nullifiers[0]; - await expectInvalid(badTx, 'Duplicate nullifier in tx'); + await expectInvalid(badTx, TX_ERROR_DUPLICATE_NULLIFIER_IN_TX); }); it('rejects duplicates against history', async () => { @@ -49,7 +49,7 @@ describe('DoubleSpendTxValidator', () => { numberOfRevertiblePublicCallRequests: 0, }); nullifierSource.nullifiersExist.mockResolvedValue([true]); - await expectInvalid(badTx, 'Existing nullifier'); + await expectInvalid(badTx, TX_ERROR_EXISTING_NULLIFIER); }); it('accepts txs with no duplicates', async () => { diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/double_spend_validator.ts b/yarn-project/p2p/src/msg_validators/tx_validator/double_spend_validator.ts index 8416d92f8191..f3307bd111b1 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/double_spend_validator.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/double_spend_validator.ts @@ -1,5 +1,12 @@ import { createLogger } from '@aztec/foundation/log'; -import { type AnyTx, Tx, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx'; +import { + type AnyTx, + TX_ERROR_DUPLICATE_NULLIFIER_IN_TX, + TX_ERROR_EXISTING_NULLIFIER, + Tx, + type TxValidationResult, + type TxValidator, +} from '@aztec/stdlib/tx'; export interface NullifierSource { nullifiersExist: (nullifiers: Buffer[]) => Promise; @@ -20,12 +27,12 @@ export class DoubleSpendTxValidator implements TxValidator { const uniqueNullifiers = new Set(nullifiers); if (uniqueNullifiers.size !== nullifiers.length) { this.#log.warn(`Rejecting tx ${await Tx.getHash(tx)} for emitting duplicate nullifiers`); - return { result: 'invalid', reason: ['Duplicate nullifier in tx'] }; + return { result: 'invalid', reason: [TX_ERROR_DUPLICATE_NULLIFIER_IN_TX] }; } if ((await this.#nullifierSource.nullifiersExist(nullifiers.map(n => n.toBuffer()))).some(Boolean)) { this.#log.warn(`Rejecting tx ${await Tx.getHash(tx)} for repeating a nullifier`); - return { result: 'invalid', reason: ['Existing nullifier'] }; + return { result: 'invalid', reason: [TX_ERROR_EXISTING_NULLIFIER] }; } return { result: 'valid' }; diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.test.ts b/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.test.ts index 46ac4608fa96..aff8a307c4bc 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.test.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.test.ts @@ -7,7 +7,7 @@ import { AztecAddress } from '@aztec/stdlib/aztec-address'; import { GasFees, GasSettings } from '@aztec/stdlib/gas'; import { mockTx } from '@aztec/stdlib/testing'; import type { PublicStateSource } from '@aztec/stdlib/trees'; -import type { Tx } from '@aztec/stdlib/tx'; +import { TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE, TX_ERROR_INSUFFICIENT_FEE_PER_GAS, type Tx } from '@aztec/stdlib/tx'; import { type MockProxy, mock, mockFn } from 'jest-mock-extended'; @@ -82,11 +82,11 @@ describe('GasTxValidator', () => { it('rejects txs if fee payer has not enough balance', async () => { mockBalance(feeLimit - 1n); - await expectInvalid(tx, 'Insufficient fee payer balance'); + await expectInvalid(tx, TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE); }); it('rejects txs if fee payer has zero balance', async () => { - await expectInvalid(tx, 'Insufficient fee payer balance'); + await expectInvalid(tx, TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE); }); it('rejects txs if fee payer claims balance outside setup', async () => { @@ -95,16 +95,16 @@ describe('GasTxValidator', () => { selector: await FunctionSelector.fromSignature('_increase_public_balance((Field),u128)'), args: [payer.toField(), new Fr(1n)], }); - await expectInvalid(tx, 'Insufficient fee payer balance'); + await expectInvalid(tx, TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE); }); it('skips txs with not enough fee per da gas', async () => { gasFees.feePerDaGas = gasFees.feePerDaGas.add(new Fr(1)); - await expectSkipped(tx, 'Insufficient fee per gas'); + await expectSkipped(tx, TX_ERROR_INSUFFICIENT_FEE_PER_GAS); }); it('skips txs with not enough fee per l2 gas', async () => { gasFees.feePerL2Gas = gasFees.feePerL2Gas.add(new Fr(1)); - await expectSkipped(tx, 'Insufficient fee per gas'); + await expectSkipped(tx, TX_ERROR_INSUFFICIENT_FEE_PER_GAS); }); }); diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.ts b/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.ts index b6760290d83e..d3e81cf025b3 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.ts @@ -5,7 +5,14 @@ import { FunctionSelector } from '@aztec/stdlib/abi'; import type { AztecAddress } from '@aztec/stdlib/aztec-address'; import type { GasFees } from '@aztec/stdlib/gas'; import type { PublicStateSource } from '@aztec/stdlib/trees'; -import { type Tx, TxExecutionPhase, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx'; +import { + TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE, + TX_ERROR_INSUFFICIENT_FEE_PER_GAS, + type Tx, + TxExecutionPhase, + type TxValidationResult, + type TxValidator, +} from '@aztec/stdlib/tx'; export class GasTxValidator implements TxValidator { #log = createLogger('sequencer:tx_validator:tx_gas'); @@ -21,7 +28,7 @@ export class GasTxValidator implements TxValidator { async validateTx(tx: Tx): Promise { if (await this.#shouldSkip(tx)) { - return Promise.resolve({ result: 'skipped', reason: ['Insufficient fee per gas'] }); + return Promise.resolve({ result: 'skipped', reason: [TX_ERROR_INSUFFICIENT_FEE_PER_GAS] }); } return this.#validateTxFee(tx); } @@ -88,7 +95,7 @@ export class GasTxValidator implements TxValidator { balance: balance.toBigInt(), feeLimit: feeLimit.toBigInt(), }); - return { result: 'invalid', reason: ['Insufficient fee payer balance'] }; + return { result: 'invalid', reason: [TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE] }; } return { result: 'valid' }; } diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/metadata_validator.test.ts b/yarn-project/p2p/src/msg_validators/tx_validator/metadata_validator.test.ts index 726c81842b50..55ec48b37ba7 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/metadata_validator.test.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/metadata_validator.test.ts @@ -1,7 +1,12 @@ import { Fr } from '@aztec/foundation/fields'; import { mockTx, mockTxForRollup } from '@aztec/stdlib/testing'; import type { AnyTx, Tx } from '@aztec/stdlib/tx'; -import { MaxBlockNumber } from '@aztec/stdlib/tx'; +import { + MaxBlockNumber, + TX_ERROR_INCORRECT_CHAIN_ID, + TX_ERROR_INCORRECT_ROLLUP_VERSION, + TX_ERROR_INVALID_BLOCK_NUMBER, +} from '@aztec/stdlib/tx'; import { MetadataTxValidator } from './metadata_validator.js'; @@ -42,8 +47,8 @@ describe('MetadataTxValidator', () => { await expectValid(goodTxs[0]); await expectValid(goodTxs[1]); - await expectInvalid(badTxs[0], 'Incorrect chain id'); - await expectInvalid(badTxs[1], 'Incorrect chain id'); + await expectInvalid(badTxs[0], TX_ERROR_INCORRECT_CHAIN_ID); + await expectInvalid(badTxs[1], TX_ERROR_INCORRECT_CHAIN_ID); }); it('allows only transactions for the right rollup', async () => { @@ -62,8 +67,8 @@ describe('MetadataTxValidator', () => { await expectValid(goodTxs[0]); await expectValid(goodTxs[1]); - await expectInvalid(badTxs[0], 'Incorrect rollup version'); - await expectInvalid(badTxs[1], 'Incorrect rollup version'); + await expectInvalid(badTxs[0], TX_ERROR_INCORRECT_ROLLUP_VERSION); + await expectInvalid(badTxs[1], TX_ERROR_INCORRECT_ROLLUP_VERSION); }); it.each([42, 43])('allows txs with valid max block number', async maxBlockNumber => { @@ -90,6 +95,6 @@ describe('MetadataTxValidator', () => { badTx.data.constants.txContext.version = rollupVersion; badTx.data.rollupValidationRequests.maxBlockNumber = new MaxBlockNumber(true, blockNumber.sub(new Fr(1))); - await expectInvalid(badTx, 'Invalid block number'); + await expectInvalid(badTx, TX_ERROR_INVALID_BLOCK_NUMBER); }); }); diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/metadata_validator.ts b/yarn-project/p2p/src/msg_validators/tx_validator/metadata_validator.ts index a610140ca35d..e4ae0019bff7 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/metadata_validator.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/metadata_validator.ts @@ -1,6 +1,14 @@ import type { Fr } from '@aztec/foundation/fields'; import { createLogger } from '@aztec/foundation/log'; -import { type AnyTx, Tx, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx'; +import { + type AnyTx, + TX_ERROR_INCORRECT_CHAIN_ID, + TX_ERROR_INCORRECT_ROLLUP_VERSION, + TX_ERROR_INVALID_BLOCK_NUMBER, + Tx, + type TxValidationResult, + type TxValidator, +} from '@aztec/stdlib/tx'; export class MetadataTxValidator implements TxValidator { #log = createLogger('p2p:tx_validator:tx_metadata'); @@ -10,13 +18,13 @@ export class MetadataTxValidator implements TxValidator { async validateTx(tx: T): Promise { const errors = []; if (!(await this.#hasCorrectChainId(tx))) { - errors.push('Incorrect chain id'); + errors.push(TX_ERROR_INCORRECT_CHAIN_ID); } if (!(await this.#hasCorrectRollupVersion(tx))) { - errors.push('Incorrect rollup version'); + errors.push(TX_ERROR_INCORRECT_ROLLUP_VERSION); } if (!(await this.#isValidForBlockNumber(tx))) { - errors.push('Invalid block number'); + errors.push(TX_ERROR_INVALID_BLOCK_NUMBER); } return errors.length > 0 ? { result: 'invalid', reason: errors } : { result: 'valid' }; } diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/phases_validator.test.ts b/yarn-project/p2p/src/msg_validators/tx_validator/phases_validator.test.ts index 1cd5799d6955..a67a619e2c20 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/phases_validator.test.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/phases_validator.test.ts @@ -3,7 +3,7 @@ import type { FunctionSelector } from '@aztec/stdlib/abi'; import type { AztecAddress } from '@aztec/stdlib/aztec-address'; import type { ContractDataSource } from '@aztec/stdlib/contract'; import { makeAztecAddress, makeSelector, mockTx } from '@aztec/stdlib/testing'; -import type { Tx } from '@aztec/stdlib/tx'; +import { TX_ERROR_SETUP_FUNCTION_NOT_ALLOWED, type Tx } from '@aztec/stdlib/tx'; import { type MockProxy, mock, mockFn } from 'jest-mock-extended'; @@ -100,7 +100,7 @@ describe('PhasesTxValidator', () => { it('rejects txs with setup functions not on the allow list', async () => { const tx = await mockTx(1, { numberOfNonRevertiblePublicCallRequests: 2 }); - await expectInvalid(tx, 'Setup function not on allow list'); + await expectInvalid(tx, TX_ERROR_SETUP_FUNCTION_NOT_ALLOWED); }); it('rejects setup functions not on the contracts class list', async () => { @@ -121,7 +121,7 @@ describe('PhasesTxValidator', () => { } }); - await expectInvalid(tx, 'Setup function not on allow list'); + await expectInvalid(tx, TX_ERROR_SETUP_FUNCTION_NOT_ALLOWED); }); it('allows multiple setup functions on the allow list', async () => { @@ -136,6 +136,6 @@ describe('PhasesTxValidator', () => { const tx = await mockTx(1, { numberOfNonRevertiblePublicCallRequests: 2 }); await patchNonRevertibleFn(tx, 0, { address: allowedContract, selector: allowedSetupSelector1 }); - await expectInvalid(tx, 'Setup function not on allow list'); + await expectInvalid(tx, TX_ERROR_SETUP_FUNCTION_NOT_ALLOWED); }); }); diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/phases_validator.ts b/yarn-project/p2p/src/msg_validators/tx_validator/phases_validator.ts index e69301fcd1d2..87a315eb2489 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/phases_validator.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/phases_validator.ts @@ -4,6 +4,8 @@ import type { ContractDataSource } from '@aztec/stdlib/contract'; import type { AllowedElement } from '@aztec/stdlib/interfaces/server'; import { type PublicCallRequestWithCalldata, + TX_ERROR_DURING_VALIDATION, + TX_ERROR_SETUP_FUNCTION_NOT_ALLOWED, Tx, TxExecutionPhase, type TxValidationResult, @@ -42,11 +44,14 @@ export class PhasesTxValidator implements TxValidator { { allowList: this.setupAllowList }, ); - return { result: 'invalid', reason: ['Setup function not on allow list'] }; + return { result: 'invalid', reason: [TX_ERROR_SETUP_FUNCTION_NOT_ALLOWED] }; } } return { result: 'valid' }; + } catch (err) { + this.#log.error(`Error validating phases for tx`, err); + return { result: 'invalid', reason: [TX_ERROR_DURING_VALIDATION] }; } finally { this.contractsDB.clearContractsForTx(); } diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/tx_proof_validator.ts b/yarn-project/p2p/src/msg_validators/tx_validator/tx_proof_validator.ts index 568f599a7c5a..0bd6d6e90862 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/tx_proof_validator.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/tx_proof_validator.ts @@ -1,6 +1,6 @@ import { createLogger } from '@aztec/foundation/log'; import type { ClientProtocolCircuitVerifier } from '@aztec/stdlib/interfaces/server'; -import { Tx, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx'; +import { TX_ERROR_INVALID_PROOF, Tx, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx'; export class TxProofValidator implements TxValidator { #log = createLogger('p2p:tx_validator:private_proof'); @@ -10,7 +10,7 @@ export class TxProofValidator implements TxValidator { async validateTx(tx: Tx): Promise { if (!(await this.verifier.verifyProof(tx))) { this.#log.warn(`Rejecting tx ${await Tx.getHash(tx)} for invalid proof`); - return { result: 'invalid', reason: ['Invalid proof'] }; + return { result: 'invalid', reason: [TX_ERROR_INVALID_PROOF] }; } this.#log.trace(`Accepted ${await Tx.getHash(tx)} with valid proof`); return { result: 'valid' }; diff --git a/yarn-project/stdlib/src/tx/index.ts b/yarn-project/stdlib/src/tx/index.ts index ff7f392e1494..8acb046549e9 100644 --- a/yarn-project/stdlib/src/tx/index.ts +++ b/yarn-project/stdlib/src/tx/index.ts @@ -24,6 +24,7 @@ export * from './public_simulation_output.js'; export * from './tx_execution_request.js'; export * from './validator/tx_validator.js'; export * from './validator/empty_validator.js'; +export * from './validator/error_texts.js'; export * from './capsule.js'; export * from './global_variable_builder.js'; export * from './hashed_values.js'; diff --git a/yarn-project/stdlib/src/tx/validator/error_texts.ts b/yarn-project/stdlib/src/tx/validator/error_texts.ts new file mode 100644 index 000000000000..e9a97a4d6b00 --- /dev/null +++ b/yarn-project/stdlib/src/tx/validator/error_texts.ts @@ -0,0 +1,33 @@ +// Gas and fees +export const TX_ERROR_INSUFFICIENT_FEE_PER_GAS = 'Insufficient fee per gas'; +export const TX_ERROR_INSUFFICIENT_FEE_PAYER_BALANCE = 'Insufficient fee payer balance'; + +// Phases +export const TX_ERROR_SETUP_FUNCTION_NOT_ALLOWED = 'Setup function not on allow list'; + +// Nullifiers +export const TX_ERROR_DUPLICATE_NULLIFIER_IN_TX = 'Duplicate nullifier in tx'; +export const TX_ERROR_EXISTING_NULLIFIER = 'Existing nullifier'; + +// Metadata +export const TX_ERROR_INVALID_BLOCK_NUMBER = 'Invalid block number'; +export const TX_ERROR_INCORRECT_CHAIN_ID = 'Incorrect chain id'; +export const TX_ERROR_INCORRECT_ROLLUP_VERSION = 'Incorrect rollup version'; + +// Proof +export const TX_ERROR_INVALID_PROOF = 'Invalid proof'; + +//Data +export const TX_ERROR_INCORRECT_CALLDATA = 'Incorrect calldata for public call'; +export const TX_ERROR_CALLDATA_COUNT_MISMATCH = 'Wrong number of calldata for public calls'; +export const TX_ERROR_CALLDATA_COUNT_TOO_LARGE = 'Total calldata too large for enqueued public calls'; +export const TX_ERROR_CONTRACT_CLASS_LOG_COUNT = 'Mismatched number of contract class logs'; +export const TX_ERROR_CONTRACT_CLASS_LOG_LENGTH = 'Mismatched contract class logs length'; +export const TX_ERROR_CONTRACT_CLASS_LOGS = 'Mismatched contract class logs'; +export const TX_ERROR_CONTRACT_CLASS_LOG_SORTING = 'Incorrectly sorted contract class logs'; + +// Block header +export const TX_ERROR_BLOCK_HEADER = 'Block header not found'; + +// General +export const TX_ERROR_DURING_VALIDATION = 'Unexpected error during validation';