@aztec/p2p 0.0.1-commit.d1f2d6c → 0.0.1-commit.d431d1c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +3 -3
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +2 -3
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +2 -3
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +3 -3
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +1 -8
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +3 -3
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -2
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +3 -3
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +9 -40
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +3 -3
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +4 -11
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +3 -3
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +12 -43
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +3 -3
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +11 -66
- package/dest/services/libp2p/libp2p_service.d.ts +5 -5
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +24 -24
- package/dest/services/reqresp/interface.d.ts +3 -3
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +2 -2
- package/dest/services/tx_collection/slow_tx_collection.d.ts +3 -3
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.d.ts +5 -5
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_provider.d.ts +3 -3
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +1 -2
- package/package.json +14 -14
- package/src/client/p2p_client.ts +5 -5
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +2 -2
- package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +1 -2
- package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +1 -2
- package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +7 -10
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +2 -4
- package/src/msg_validators/attestation_validator/attestation_validator.ts +13 -25
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +6 -6
- package/src/msg_validators/proposal_validator/proposal_validator.ts +11 -18
- package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +14 -53
- package/src/services/libp2p/libp2p_service.ts +29 -39
- package/src/services/reqresp/interface.ts +2 -2
- package/src/services/tx_collection/slow_tx_collection.ts +2 -2
- package/src/services/tx_collection/tx_collection.ts +4 -4
- package/src/services/tx_provider.ts +2 -2
- package/src/testbench/p2p_client_testbench_worker.ts +1 -1
- package/dest/msg_validators/clock_tolerance.d.ts +0 -21
- package/dest/msg_validators/clock_tolerance.d.ts.map +0 -1
- package/dest/msg_validators/clock_tolerance.js +0 -37
- package/src/msg_validators/clock_tolerance.ts +0 -51
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tx_provider.d.ts","sourceRoot":"","sources":["../../src/services/tx_provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAElE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"tx_provider.d.ts","sourceRoot":"","sources":["../../src/services/tx_provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAElE,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AAEnF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,EAA8B,YAAY,EAAE,MAAM,kCAAkC,CAAC;AACjG,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAE7E;;;GAGG;AACH,qBAAa,UAAW,YAAW,WAAW;IAI1C,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,GAAG;IANb,SAAS,CAAC,eAAe,EAAE,yBAAyB,CAAC;IAErD,YACU,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EACxC,GAAG,GAAE,MAAyC,EACtD,MAAM,GAAE,eAAsC,EAG/C;IAED,sDAAsD;IACzC,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,EAAE,EAAE,CAAC;QAAC,UAAU,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAkB7F;IAED,kFAAkF;IAC3E,sBAAsB,CAC3B,aAAa,EAAE,aAAa,EAC5B,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE,GACvD,OAAO,CAAC;QAAE,GAAG,EAAE,EAAE,EAAE,CAAC;QAAC,UAAU,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAO9C;IAED,mEAAmE;IAC5D,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,EAAE,EAAE,CAAC;QAAC,UAAU,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAO/G;YAEa,2BAA2B;IAgCzC,OAAO,CAAC,QAAQ;YAKF,oBAAoB;YAyFpB,cAAc;IAY5B,OAAO,CAAC,mBAAmB;YAOb,kBAAkB;CAOjC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/p2p",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.d431d1c",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -67,17 +67,17 @@
|
|
|
67
67
|
]
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@aztec/constants": "0.0.1-commit.
|
|
71
|
-
"@aztec/epoch-cache": "0.0.1-commit.
|
|
72
|
-
"@aztec/ethereum": "0.0.1-commit.
|
|
73
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
74
|
-
"@aztec/kv-store": "0.0.1-commit.
|
|
75
|
-
"@aztec/noir-contracts.js": "0.0.1-commit.
|
|
76
|
-
"@aztec/noir-protocol-circuits-types": "0.0.1-commit.
|
|
77
|
-
"@aztec/protocol-contracts": "0.0.1-commit.
|
|
78
|
-
"@aztec/simulator": "0.0.1-commit.
|
|
79
|
-
"@aztec/stdlib": "0.0.1-commit.
|
|
80
|
-
"@aztec/telemetry-client": "0.0.1-commit.
|
|
70
|
+
"@aztec/constants": "0.0.1-commit.d431d1c",
|
|
71
|
+
"@aztec/epoch-cache": "0.0.1-commit.d431d1c",
|
|
72
|
+
"@aztec/ethereum": "0.0.1-commit.d431d1c",
|
|
73
|
+
"@aztec/foundation": "0.0.1-commit.d431d1c",
|
|
74
|
+
"@aztec/kv-store": "0.0.1-commit.d431d1c",
|
|
75
|
+
"@aztec/noir-contracts.js": "0.0.1-commit.d431d1c",
|
|
76
|
+
"@aztec/noir-protocol-circuits-types": "0.0.1-commit.d431d1c",
|
|
77
|
+
"@aztec/protocol-contracts": "0.0.1-commit.d431d1c",
|
|
78
|
+
"@aztec/simulator": "0.0.1-commit.d431d1c",
|
|
79
|
+
"@aztec/stdlib": "0.0.1-commit.d431d1c",
|
|
80
|
+
"@aztec/telemetry-client": "0.0.1-commit.d431d1c",
|
|
81
81
|
"@chainsafe/libp2p-gossipsub": "13.0.0",
|
|
82
82
|
"@chainsafe/libp2p-noise": "^15.0.0",
|
|
83
83
|
"@chainsafe/libp2p-yamux": "^6.0.2",
|
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
"xxhash-wasm": "^1.1.0"
|
|
105
105
|
},
|
|
106
106
|
"devDependencies": {
|
|
107
|
-
"@aztec/archiver": "0.0.1-commit.
|
|
108
|
-
"@aztec/world-state": "0.0.1-commit.
|
|
107
|
+
"@aztec/archiver": "0.0.1-commit.d431d1c",
|
|
108
|
+
"@aztec/world-state": "0.0.1-commit.d431d1c",
|
|
109
109
|
"@jest/globals": "^30.0.0",
|
|
110
110
|
"@types/jest": "^30.0.0",
|
|
111
111
|
"@types/node": "^22.15.17",
|
package/src/client/p2p_client.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { AztecAsyncKVStore, AztecAsyncSingleton } from '@aztec/kv-store';
|
|
|
6
6
|
import { L2TipsKVStore } from '@aztec/kv-store/stores';
|
|
7
7
|
import {
|
|
8
8
|
type EthAddress,
|
|
9
|
-
type
|
|
9
|
+
type L2BlockNew,
|
|
10
10
|
type L2BlockSource,
|
|
11
11
|
L2BlockStream,
|
|
12
12
|
type L2BlockStreamEvent,
|
|
@@ -659,7 +659,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
659
659
|
* @param blocks - A list of existing blocks with txs that the P2P client needs to ensure the tx pool is reconciled with.
|
|
660
660
|
* @returns Empty promise.
|
|
661
661
|
*/
|
|
662
|
-
private async markTxsAsMinedFromBlocks(blocks:
|
|
662
|
+
private async markTxsAsMinedFromBlocks(blocks: L2BlockNew[]): Promise<void> {
|
|
663
663
|
for (const block of blocks) {
|
|
664
664
|
const txHashes = block.body.txEffects.map(txEffect => txEffect.txHash);
|
|
665
665
|
await this.txPool.markAsMined(txHashes, block.header);
|
|
@@ -671,7 +671,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
671
671
|
* @param blocks - A list of existing blocks with txs that the P2P client needs to ensure the tx pool is reconciled with.
|
|
672
672
|
* @returns Empty promise.
|
|
673
673
|
*/
|
|
674
|
-
private async handleLatestL2Blocks(blocks:
|
|
674
|
+
private async handleLatestL2Blocks(blocks: L2BlockNew[]): Promise<void> {
|
|
675
675
|
if (!blocks.length) {
|
|
676
676
|
return Promise.resolve();
|
|
677
677
|
}
|
|
@@ -686,7 +686,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
686
686
|
}
|
|
687
687
|
|
|
688
688
|
/** Request txs for unproven blocks so the prover node has more chances to get them. */
|
|
689
|
-
private async startCollectingMissingTxs(blocks:
|
|
689
|
+
private async startCollectingMissingTxs(blocks: L2BlockNew[]): Promise<void> {
|
|
690
690
|
try {
|
|
691
691
|
// TODO(#15435): If the archiver has lagged behind L1, the reported proven block number may
|
|
692
692
|
// be much lower than the actual one, and it does not update until the pending chain is
|
|
@@ -719,7 +719,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
719
719
|
* @param blocks - A list of finalized L2 blocks.
|
|
720
720
|
* @returns Empty promise.
|
|
721
721
|
*/
|
|
722
|
-
private async handleFinalizedL2Blocks(blocks:
|
|
722
|
+
private async handleFinalizedL2Blocks(blocks: L2BlockNew[]): Promise<void> {
|
|
723
723
|
if (!blocks.length) {
|
|
724
724
|
return Promise.resolve();
|
|
725
725
|
}
|
|
@@ -6,7 +6,7 @@ import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
|
6
6
|
import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
7
7
|
import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncMultiMap } from '@aztec/kv-store';
|
|
8
8
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
9
|
-
import type { MerkleTreeReadOperations,
|
|
9
|
+
import type { MerkleTreeReadOperations, ReadonlyWorldStateAccess } from '@aztec/stdlib/interfaces/server';
|
|
10
10
|
import { ChonkProof } from '@aztec/stdlib/proofs';
|
|
11
11
|
import type { TxAddedToPoolStats } from '@aztec/stdlib/stats';
|
|
12
12
|
import { BlockHeader, Tx, TxHash } from '@aztec/stdlib/tx';
|
|
@@ -99,7 +99,7 @@ export class AztecKVTxPool
|
|
|
99
99
|
constructor(
|
|
100
100
|
store: AztecAsyncKVStore,
|
|
101
101
|
archive: AztecAsyncKVStore,
|
|
102
|
-
worldState:
|
|
102
|
+
worldState: ReadonlyWorldStateAccess,
|
|
103
103
|
telemetry: TelemetryClient = getTelemetryClient(),
|
|
104
104
|
config: TxPoolOptions = {},
|
|
105
105
|
log = createLogger('p2p:tx_pool'),
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { findIndexInSortedArray, insertIntoSortedArray } from '@aztec/foundation/array';
|
|
2
|
-
import type { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
2
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
5
4
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
@@ -51,7 +50,7 @@ export class EvictionManager {
|
|
|
51
50
|
await this.runEvictionRules(ctx);
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
public async evictAfterChainPrune(blockNumber:
|
|
53
|
+
public async evictAfterChainPrune(blockNumber: number): Promise<void> {
|
|
55
54
|
const ctx: EvictionContext = {
|
|
56
55
|
event: EvictionEvent.CHAIN_PRUNED,
|
|
57
56
|
blockNumber,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
1
|
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
3
2
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
3
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
@@ -25,7 +24,7 @@ export type EvictionContext =
|
|
|
25
24
|
}
|
|
26
25
|
| {
|
|
27
26
|
event: typeof EvictionEvent.CHAIN_PRUNED;
|
|
28
|
-
blockNumber:
|
|
27
|
+
blockNumber: number;
|
|
29
28
|
}
|
|
30
29
|
| {
|
|
31
30
|
event: typeof EvictionEvent.BLOCK_MINED;
|
|
@@ -2,7 +2,7 @@ import { createLogger } from '@aztec/foundation/log';
|
|
|
2
2
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
3
3
|
import { computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
|
|
4
4
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
5
|
-
import type {
|
|
5
|
+
import type { ReadonlyWorldStateAccess } from '@aztec/stdlib/interfaces/server';
|
|
6
6
|
import { DatabasePublicStateSource, type MerkleTreeReadOperations } from '@aztec/stdlib/trees';
|
|
7
7
|
import type { TxHash } from '@aztec/stdlib/tx';
|
|
8
8
|
|
|
@@ -22,7 +22,7 @@ export class FeePayerBalanceEvictionRule implements EvictionRule {
|
|
|
22
22
|
|
|
23
23
|
private log = createLogger('p2p:mempool:tx_pool:fee_payer_balance_eviction_rule');
|
|
24
24
|
|
|
25
|
-
constructor(private worldState:
|
|
25
|
+
constructor(private worldState: ReadonlyWorldStateAccess) {}
|
|
26
26
|
|
|
27
27
|
async evict(context: EvictionContext, txPool: TxPoolOperations): Promise<EvictionResult> {
|
|
28
28
|
try {
|
|
@@ -31,12 +31,11 @@ export class FeePayerBalanceEvictionRule implements EvictionRule {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
if (context.event === EvictionEvent.BLOCK_MINED) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return await this.evictForFeePayers(context.feePayers, this.worldState.getSnapshot(blockNumber), txPool);
|
|
34
|
+
return await this.evictForFeePayers(
|
|
35
|
+
context.feePayers,
|
|
36
|
+
this.worldState.getSnapshot(context.block.getBlockNumber()),
|
|
37
|
+
txPool,
|
|
38
|
+
);
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
// TODO: fix this edge-case
|
|
@@ -50,8 +49,6 @@ export class FeePayerBalanceEvictionRule implements EvictionRule {
|
|
|
50
49
|
// -----
|
|
51
50
|
// Proposed fix: evict only if node is synched
|
|
52
51
|
if (context.event === EvictionEvent.CHAIN_PRUNED) {
|
|
53
|
-
// Ensure world state is synced to this block before accessing the snapshot.
|
|
54
|
-
await this.worldState.syncImmediate(context.blockNumber);
|
|
55
52
|
const feePayers = await txPool.getPendingFeePayers();
|
|
56
53
|
return await this.evictForFeePayers(feePayers, this.worldState.getSnapshot(context.blockNumber), txPool);
|
|
57
54
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { findIndexInSortedArray, insertIntoSortedArray } from '@aztec/foundation/array';
|
|
2
2
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
|
-
import type {
|
|
4
|
+
import type { ReadonlyWorldStateAccess } from '@aztec/stdlib/interfaces/server';
|
|
5
5
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
6
6
|
import type { TxHash } from '@aztec/stdlib/tx';
|
|
7
7
|
|
|
@@ -26,7 +26,7 @@ export class InvalidTxsAfterReorgRule implements EvictionRule {
|
|
|
26
26
|
|
|
27
27
|
private log = createLogger('p2p:mempool:tx_pool:invalid_txs_after_reorg_rule');
|
|
28
28
|
|
|
29
|
-
public constructor(private worldState:
|
|
29
|
+
public constructor(private worldState: ReadonlyWorldStateAccess) {}
|
|
30
30
|
|
|
31
31
|
async evict(context: EvictionContext, txPool: TxPoolOperations): Promise<EvictionResult> {
|
|
32
32
|
if (context.event !== EvictionEvent.CHAIN_PRUNED) {
|
|
@@ -46,8 +46,6 @@ export class InvalidTxsAfterReorgRule implements EvictionRule {
|
|
|
46
46
|
insertIntoSortedArray(uniqueBlockHashes, blockHash, Fr.cmp, false);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
// Ensure world state is synced to this block before accessing the snapshot.
|
|
50
|
-
await this.worldState.syncImmediate(context.blockNumber);
|
|
51
49
|
const db = this.worldState.getSnapshot(context.blockNumber);
|
|
52
50
|
const blocksFromDb = await db.findLeafIndices(MerkleTreeId.ARCHIVE, uniqueBlockHashes);
|
|
53
51
|
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
2
|
import { NoCommitteeError } from '@aztec/ethereum/contracts';
|
|
3
3
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
4
|
-
import {
|
|
5
|
-
type CheckpointAttestation,
|
|
6
|
-
type P2PValidator,
|
|
7
|
-
PeerErrorSeverity,
|
|
8
|
-
type ValidationResult,
|
|
9
|
-
} from '@aztec/stdlib/p2p';
|
|
10
|
-
|
|
11
|
-
import { isWithinClockTolerance } from '../clock_tolerance.js';
|
|
4
|
+
import { type CheckpointAttestation, type P2PValidator, PeerErrorSeverity } from '@aztec/stdlib/p2p';
|
|
12
5
|
|
|
13
6
|
export class CheckpointAttestationValidator implements P2PValidator<CheckpointAttestation> {
|
|
14
7
|
protected epochCache: EpochCacheInterface;
|
|
@@ -19,35 +12,30 @@ export class CheckpointAttestationValidator implements P2PValidator<CheckpointAt
|
|
|
19
12
|
this.logger = createLogger('p2p:checkpoint-attestation-validator');
|
|
20
13
|
}
|
|
21
14
|
|
|
22
|
-
async validate(message: CheckpointAttestation): Promise<
|
|
15
|
+
async validate(message: CheckpointAttestation): Promise<PeerErrorSeverity | undefined> {
|
|
23
16
|
const slotNumber = message.payload.header.slotNumber;
|
|
24
17
|
|
|
25
18
|
try {
|
|
26
19
|
const { currentSlot, nextSlot } = this.epochCache.getCurrentAndNextSlot();
|
|
27
20
|
|
|
28
21
|
if (slotNumber !== currentSlot && slotNumber !== nextSlot) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
);
|
|
34
|
-
return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
|
|
35
|
-
}
|
|
36
|
-
this.logger.debug(`Ignoring checkpoint attestation for previous slot ${slotNumber} within clock tolerance`);
|
|
37
|
-
return { result: 'ignore' };
|
|
22
|
+
this.logger.warn(
|
|
23
|
+
`Checkpoint attestation slot ${slotNumber} is not current (${currentSlot}) or next (${nextSlot}) slot`,
|
|
24
|
+
);
|
|
25
|
+
return PeerErrorSeverity.HighToleranceError;
|
|
38
26
|
}
|
|
39
27
|
|
|
40
28
|
// Verify the signature is valid
|
|
41
29
|
const attester = message.getSender();
|
|
42
30
|
if (attester === undefined) {
|
|
43
31
|
this.logger.warn(`Invalid signature in checkpoint attestation for slot ${slotNumber}`);
|
|
44
|
-
return
|
|
32
|
+
return PeerErrorSeverity.LowToleranceError;
|
|
45
33
|
}
|
|
46
34
|
|
|
47
35
|
// Verify the attester is in the committee for this slot
|
|
48
36
|
if (!(await this.epochCache.isInCommittee(slotNumber, attester))) {
|
|
49
37
|
this.logger.warn(`Attester ${attester.toString()} is not in committee for slot ${slotNumber}`);
|
|
50
|
-
return
|
|
38
|
+
return PeerErrorSeverity.HighToleranceError;
|
|
51
39
|
}
|
|
52
40
|
|
|
53
41
|
// Verify the proposer signature matches the expected proposer for the attestation's slot
|
|
@@ -57,26 +45,26 @@ export class CheckpointAttestationValidator implements P2PValidator<CheckpointAt
|
|
|
57
45
|
const expectedProposer = await this.epochCache.getProposerAttesterAddressInSlot(slotNumber);
|
|
58
46
|
if (!expectedProposer) {
|
|
59
47
|
this.logger.warn(`No proposer defined for slot ${slotNumber}`);
|
|
60
|
-
return
|
|
48
|
+
return PeerErrorSeverity.HighToleranceError;
|
|
61
49
|
}
|
|
62
50
|
if (!proposer) {
|
|
63
51
|
this.logger.warn(`Invalid proposer signature in checkpoint attestation for slot ${slotNumber}`);
|
|
64
|
-
return
|
|
52
|
+
return PeerErrorSeverity.LowToleranceError;
|
|
65
53
|
}
|
|
66
54
|
if (!proposer.equals(expectedProposer)) {
|
|
67
55
|
this.logger.warn(
|
|
68
56
|
`Proposer signature mismatch in checkpoint attestation. ` +
|
|
69
57
|
`Expected ${expectedProposer?.toString() ?? 'none'} but got ${proposer.toString()} for slot ${slotNumber}`,
|
|
70
58
|
);
|
|
71
|
-
return
|
|
59
|
+
return PeerErrorSeverity.HighToleranceError;
|
|
72
60
|
}
|
|
73
61
|
|
|
74
|
-
return
|
|
62
|
+
return undefined;
|
|
75
63
|
} catch (e) {
|
|
76
64
|
// People shouldn't be sending us attestations if the committee doesn't exist
|
|
77
65
|
if (e instanceof NoCommitteeError) {
|
|
78
66
|
this.logger.warn(`No committee exists for checkpoint attestation for slot ${slotNumber}`);
|
|
79
|
-
return
|
|
67
|
+
return PeerErrorSeverity.LowToleranceError;
|
|
80
68
|
}
|
|
81
69
|
throw e;
|
|
82
70
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import { type CheckpointAttestation, PeerErrorSeverity
|
|
2
|
+
import { type CheckpointAttestation, PeerErrorSeverity } from '@aztec/stdlib/p2p';
|
|
3
3
|
import { Attributes, Metrics, type TelemetryClient } from '@aztec/telemetry-client';
|
|
4
4
|
|
|
5
5
|
import type { AttestationPool } from '../../mem_pools/attestation_pool/attestation_pool.js';
|
|
@@ -28,10 +28,10 @@ export class FishermanAttestationValidator extends CheckpointAttestationValidato
|
|
|
28
28
|
this.invalidAttestationCounter = meter.createUpDownCounter(Metrics.VALIDATOR_INVALID_ATTESTATION_RECEIVED_COUNT);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
override async validate(message: CheckpointAttestation): Promise<
|
|
31
|
+
override async validate(message: CheckpointAttestation): Promise<PeerErrorSeverity | undefined> {
|
|
32
32
|
// First run the standard validation
|
|
33
33
|
const baseValidationResult = await super.validate(message);
|
|
34
|
-
if (baseValidationResult
|
|
34
|
+
if (baseValidationResult !== undefined) {
|
|
35
35
|
// Track base validation failures (invalid signature, wrong committee, etc.)
|
|
36
36
|
this.invalidAttestationCounter.add(1, {
|
|
37
37
|
[Attributes.ERROR_TYPE]: 'base_validation_failed',
|
|
@@ -45,7 +45,7 @@ export class FishermanAttestationValidator extends CheckpointAttestationValidato
|
|
|
45
45
|
const proposer = message.getProposer();
|
|
46
46
|
|
|
47
47
|
if (!attester || !proposer) {
|
|
48
|
-
return
|
|
48
|
+
return undefined;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
const proposalId = message.archive.toString();
|
|
@@ -74,7 +74,7 @@ export class FishermanAttestationValidator extends CheckpointAttestationValidato
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
// Return error to reject the message, but LibP2PService won't penalize in fisherman mode
|
|
77
|
-
return
|
|
77
|
+
return PeerErrorSeverity.LowToleranceError;
|
|
78
78
|
}
|
|
79
79
|
} else {
|
|
80
80
|
// We might receive attestations before proposals in some cases
|
|
@@ -83,6 +83,6 @@ export class FishermanAttestationValidator extends CheckpointAttestationValidato
|
|
|
83
83
|
);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
return
|
|
86
|
+
return undefined;
|
|
87
87
|
}
|
|
88
88
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
2
|
import { NoCommitteeError } from '@aztec/ethereum/contracts';
|
|
3
3
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
4
|
-
import { BlockProposal, CheckpointProposal, PeerErrorSeverity
|
|
5
|
-
|
|
6
|
-
import { isWithinClockTolerance } from '../clock_tolerance.js';
|
|
4
|
+
import { BlockProposal, CheckpointProposal, PeerErrorSeverity } from '@aztec/stdlib/p2p';
|
|
7
5
|
|
|
8
6
|
export abstract class ProposalValidator<TProposal extends BlockProposal | CheckpointProposal> {
|
|
9
7
|
protected epochCache: EpochCacheInterface;
|
|
@@ -16,26 +14,21 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
|
|
|
16
14
|
this.logger = createLogger(loggerName);
|
|
17
15
|
}
|
|
18
16
|
|
|
19
|
-
public async validate(proposal: TProposal): Promise<
|
|
17
|
+
public async validate(proposal: TProposal): Promise<PeerErrorSeverity | undefined> {
|
|
20
18
|
try {
|
|
21
19
|
// Slot check
|
|
22
20
|
const { currentSlot, nextSlot } = this.epochCache.getCurrentAndNextSlot();
|
|
23
21
|
const slotNumber = proposal.slotNumber;
|
|
24
22
|
if (slotNumber !== currentSlot && slotNumber !== nextSlot) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
this.logger.debug(`Penalizing peer for invalid slot number ${slotNumber}`, { currentSlot, nextSlot });
|
|
28
|
-
return { result: 'reject', severity: PeerErrorSeverity.HighToleranceError };
|
|
29
|
-
}
|
|
30
|
-
this.logger.debug(`Ignoring proposal for previous slot ${slotNumber} within clock tolerance`);
|
|
31
|
-
return { result: 'ignore' };
|
|
23
|
+
this.logger.debug(`Penalizing peer for invalid slot number ${slotNumber}`, { currentSlot, nextSlot });
|
|
24
|
+
return PeerErrorSeverity.HighToleranceError;
|
|
32
25
|
}
|
|
33
26
|
|
|
34
27
|
// Signature validity
|
|
35
28
|
const proposer = proposal.getSender();
|
|
36
29
|
if (!proposer) {
|
|
37
30
|
this.logger.debug(`Penalizing peer for proposal with invalid signature`);
|
|
38
|
-
return
|
|
31
|
+
return PeerErrorSeverity.MidToleranceError;
|
|
39
32
|
}
|
|
40
33
|
|
|
41
34
|
// Transactions permitted check
|
|
@@ -44,7 +37,7 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
|
|
|
44
37
|
this.logger.debug(
|
|
45
38
|
`Penalizing peer for proposal with ${proposal.txHashes.length} transaction(s) when transactions are not permitted`,
|
|
46
39
|
);
|
|
47
|
-
return
|
|
40
|
+
return PeerErrorSeverity.MidToleranceError;
|
|
48
41
|
}
|
|
49
42
|
|
|
50
43
|
// Embedded txs must be listed in txHashes
|
|
@@ -59,7 +52,7 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
|
|
|
59
52
|
txHashesLength: proposal.txHashes.length,
|
|
60
53
|
missingTxHashes,
|
|
61
54
|
});
|
|
62
|
-
return
|
|
55
|
+
return PeerErrorSeverity.MidToleranceError;
|
|
63
56
|
}
|
|
64
57
|
|
|
65
58
|
// Proposer check
|
|
@@ -69,7 +62,7 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
|
|
|
69
62
|
expectedProposer,
|
|
70
63
|
proposer: proposer.toString(),
|
|
71
64
|
});
|
|
72
|
-
return
|
|
65
|
+
return PeerErrorSeverity.MidToleranceError;
|
|
73
66
|
}
|
|
74
67
|
|
|
75
68
|
// Validate tx hashes for all txs embedded in the proposal
|
|
@@ -78,13 +71,13 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
|
|
|
78
71
|
proposer,
|
|
79
72
|
slotNumber,
|
|
80
73
|
});
|
|
81
|
-
return
|
|
74
|
+
return PeerErrorSeverity.LowToleranceError;
|
|
82
75
|
}
|
|
83
76
|
|
|
84
|
-
return
|
|
77
|
+
return undefined;
|
|
85
78
|
} catch (e) {
|
|
86
79
|
if (e instanceof NoCommitteeError) {
|
|
87
|
-
return
|
|
80
|
+
return PeerErrorSeverity.LowToleranceError;
|
|
88
81
|
}
|
|
89
82
|
throw e;
|
|
90
83
|
}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
2
|
import type { Secp256k1Signer } from '@aztec/foundation/crypto/secp256k1-signer';
|
|
3
3
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
|
-
import {
|
|
5
|
-
type BlockProposal,
|
|
6
|
-
type CheckpointProposal,
|
|
7
|
-
PeerErrorSeverity,
|
|
8
|
-
type ValidationResult,
|
|
9
|
-
} from '@aztec/stdlib/p2p';
|
|
4
|
+
import { type BlockProposal, type CheckpointProposal, PeerErrorSeverity } from '@aztec/stdlib/p2p';
|
|
10
5
|
import type { TxHash } from '@aztec/stdlib/tx';
|
|
11
6
|
|
|
12
7
|
import type { MockProxy } from 'jest-mock-extended';
|
|
@@ -15,7 +10,7 @@ export interface ProposalValidatorTestParams<TProposal extends BlockProposal | C
|
|
|
15
10
|
validatorFactory: (
|
|
16
11
|
epochCache: EpochCacheInterface,
|
|
17
12
|
opts: { txsPermitted: boolean },
|
|
18
|
-
) => { validate: (proposal: TProposal) => Promise<
|
|
13
|
+
) => { validate: (proposal: TProposal) => Promise<PeerErrorSeverity | undefined> };
|
|
19
14
|
makeProposal: (options?: any) => Promise<TProposal>;
|
|
20
15
|
makeHeader: (epochNumber: number | bigint, slotNumber: number | bigint, blockNumber: number | bigint) => any;
|
|
21
16
|
getSigner: () => Secp256k1Signer;
|
|
@@ -34,12 +29,11 @@ export function sharedProposalValidatorTests<TProposal extends BlockProposal | C
|
|
|
34
29
|
|
|
35
30
|
describe('shared proposal validation logic', () => {
|
|
36
31
|
let epochCache: MockProxy<EpochCacheInterface>;
|
|
37
|
-
let validator: { validate: (proposal: TProposal) => Promise<
|
|
38
|
-
const previousSlot = getSlot(99);
|
|
32
|
+
let validator: { validate: (proposal: TProposal) => Promise<PeerErrorSeverity | undefined> };
|
|
39
33
|
const currentSlot = getSlot(100);
|
|
40
34
|
const nextSlot = getSlot(101);
|
|
41
35
|
|
|
42
|
-
function mockGetProposer(currentProposer: EthAddress, nextProposer: EthAddress
|
|
36
|
+
function mockGetProposer(currentProposer: EthAddress, nextProposer: EthAddress) {
|
|
43
37
|
epochCache.getProposerAttesterAddressInSlot.mockImplementation(slot => {
|
|
44
38
|
if (slot === currentSlot) {
|
|
45
39
|
return Promise.resolve(currentProposer);
|
|
@@ -47,9 +41,6 @@ export function sharedProposalValidatorTests<TProposal extends BlockProposal | C
|
|
|
47
41
|
if (slot === nextSlot) {
|
|
48
42
|
return Promise.resolve(nextProposer);
|
|
49
43
|
}
|
|
50
|
-
if (slot === previousSlot && previousProposer) {
|
|
51
|
-
return Promise.resolve(previousProposer);
|
|
52
|
-
}
|
|
53
44
|
throw new Error('Unexpected argument');
|
|
54
45
|
});
|
|
55
46
|
}
|
|
@@ -63,48 +54,18 @@ export function sharedProposalValidatorTests<TProposal extends BlockProposal | C
|
|
|
63
54
|
});
|
|
64
55
|
});
|
|
65
56
|
|
|
66
|
-
it('returns high tolerance error if slot number is not current or next slot
|
|
57
|
+
it('returns high tolerance error if slot number is not current or next slot', async () => {
|
|
67
58
|
const header = makeHeader(1, 99, 99);
|
|
68
59
|
const mockProposal = await makeProposal({ blockHeader: header, lastBlockHeader: header });
|
|
69
60
|
|
|
70
|
-
// Mock getEpochAndSlotNow to return time OUTSIDE clock tolerance (1000ms elapsed)
|
|
71
|
-
epochCache.getEpochAndSlotNow.mockReturnValue({
|
|
72
|
-
epoch: 1 as any,
|
|
73
|
-
slot: currentSlot,
|
|
74
|
-
ts: 1000n, // slot started at 1000 seconds
|
|
75
|
-
nowMs: 1001000n, // 1000ms elapsed, outside 500ms tolerance
|
|
76
|
-
});
|
|
77
|
-
|
|
78
61
|
epochCache.getProposerAttesterAddressInSlot.mockResolvedValue(getAddress());
|
|
79
62
|
const result = await validator.validate(mockProposal);
|
|
80
|
-
expect(result).
|
|
63
|
+
expect(result).toBe(PeerErrorSeverity.HighToleranceError);
|
|
81
64
|
|
|
82
65
|
// Should not try to resolve proposers if base validation fails
|
|
83
66
|
expect(epochCache.getProposerAttesterAddressInSlot).not.toHaveBeenCalled();
|
|
84
67
|
});
|
|
85
68
|
|
|
86
|
-
it('returns ignore if previous slot proposal is within clock tolerance', async () => {
|
|
87
|
-
const previousProposer = getSigner();
|
|
88
|
-
const header = makeHeader(1, 99, 99);
|
|
89
|
-
const mockProposal = await makeProposal({
|
|
90
|
-
blockHeader: header,
|
|
91
|
-
lastBlockHeader: header,
|
|
92
|
-
signer: previousProposer,
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// Mock getEpochAndSlotNow to return time WITHIN clock tolerance (100ms elapsed)
|
|
96
|
-
epochCache.getEpochAndSlotNow.mockReturnValue({
|
|
97
|
-
epoch: 1 as any,
|
|
98
|
-
slot: currentSlot,
|
|
99
|
-
ts: 1000n, // slot started at 1000 seconds
|
|
100
|
-
nowMs: 1000100n, // 100ms elapsed, within 500ms tolerance
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
mockGetProposer(getAddress(), getAddress(), getAddress(previousProposer));
|
|
104
|
-
const result = await validator.validate(mockProposal);
|
|
105
|
-
expect(result).toEqual({ result: 'ignore' });
|
|
106
|
-
});
|
|
107
|
-
|
|
108
69
|
it('returns mid tolerance error if proposer is not current proposer for current slot', async () => {
|
|
109
70
|
const currentProposer = getSigner();
|
|
110
71
|
const nextProposer = getSigner();
|
|
@@ -118,7 +79,7 @@ export function sharedProposalValidatorTests<TProposal extends BlockProposal | C
|
|
|
118
79
|
|
|
119
80
|
mockGetProposer(getAddress(currentProposer), getAddress(nextProposer));
|
|
120
81
|
const result = await validator.validate(mockProposal);
|
|
121
|
-
expect(result).
|
|
82
|
+
expect(result).toBe(PeerErrorSeverity.MidToleranceError);
|
|
122
83
|
});
|
|
123
84
|
|
|
124
85
|
it('returns mid tolerance error if proposer is not next proposer for next slot', async () => {
|
|
@@ -134,7 +95,7 @@ export function sharedProposalValidatorTests<TProposal extends BlockProposal | C
|
|
|
134
95
|
|
|
135
96
|
mockGetProposer(getAddress(currentProposer), getAddress(nextProposer));
|
|
136
97
|
const result = await validator.validate(mockProposal);
|
|
137
|
-
expect(result).
|
|
98
|
+
expect(result).toBe(PeerErrorSeverity.MidToleranceError);
|
|
138
99
|
});
|
|
139
100
|
|
|
140
101
|
it('returns mid tolerance error if proposer is current proposer but proposal is for next slot', async () => {
|
|
@@ -149,7 +110,7 @@ export function sharedProposalValidatorTests<TProposal extends BlockProposal | C
|
|
|
149
110
|
|
|
150
111
|
mockGetProposer(getAddress(currentProposer), getAddress(nextProposer));
|
|
151
112
|
const result = await validator.validate(mockProposal);
|
|
152
|
-
expect(result).
|
|
113
|
+
expect(result).toBe(PeerErrorSeverity.MidToleranceError);
|
|
153
114
|
});
|
|
154
115
|
|
|
155
116
|
it('returns undefined if proposal is valid for current slot and proposer', async () => {
|
|
@@ -164,7 +125,7 @@ export function sharedProposalValidatorTests<TProposal extends BlockProposal | C
|
|
|
164
125
|
|
|
165
126
|
mockGetProposer(getAddress(currentProposer), getAddress(nextProposer));
|
|
166
127
|
const result = await validator.validate(mockProposal);
|
|
167
|
-
expect(result).
|
|
128
|
+
expect(result).toBeUndefined();
|
|
168
129
|
});
|
|
169
130
|
|
|
170
131
|
it('returns undefined if proposal is valid for next slot and proposer', async () => {
|
|
@@ -175,7 +136,7 @@ export function sharedProposalValidatorTests<TProposal extends BlockProposal | C
|
|
|
175
136
|
|
|
176
137
|
mockGetProposer(getAddress(currentProposer), getAddress(nextProposer));
|
|
177
138
|
const result = await validator.validate(mockProposal);
|
|
178
|
-
expect(result).
|
|
139
|
+
expect(result).toBeUndefined();
|
|
179
140
|
});
|
|
180
141
|
|
|
181
142
|
describe('transaction permission validation', () => {
|
|
@@ -192,7 +153,7 @@ export function sharedProposalValidatorTests<TProposal extends BlockProposal | C
|
|
|
192
153
|
|
|
193
154
|
mockGetProposer(getAddress(currentProposer), getAddress());
|
|
194
155
|
const result = await validatorWithTxsDisabled.validate(mockProposal);
|
|
195
|
-
expect(result).
|
|
156
|
+
expect(result).toBe(PeerErrorSeverity.MidToleranceError);
|
|
196
157
|
});
|
|
197
158
|
|
|
198
159
|
it('returns undefined if txs not permitted but proposal has no txHashes', async () => {
|
|
@@ -208,7 +169,7 @@ export function sharedProposalValidatorTests<TProposal extends BlockProposal | C
|
|
|
208
169
|
|
|
209
170
|
mockGetProposer(getAddress(currentProposer), getAddress());
|
|
210
171
|
const result = await validatorWithTxsDisabled.validate(mockProposal);
|
|
211
|
-
expect(result).
|
|
172
|
+
expect(result).toBeUndefined();
|
|
212
173
|
});
|
|
213
174
|
|
|
214
175
|
it('returns undefined if txs permitted and proposal contains txHashes', async () => {
|
|
@@ -223,7 +184,7 @@ export function sharedProposalValidatorTests<TProposal extends BlockProposal | C
|
|
|
223
184
|
|
|
224
185
|
mockGetProposer(getAddress(currentProposer), getAddress());
|
|
225
186
|
const result = await validator.validate(mockProposal);
|
|
226
|
-
expect(result).
|
|
187
|
+
expect(result).toBeUndefined();
|
|
227
188
|
});
|
|
228
189
|
});
|
|
229
190
|
});
|