@aztec/p2p 3.0.0-nightly.20251112 → 3.0.0-nightly.20251114
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/config.d.ts +3 -0
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +5 -0
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +3 -2
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +20 -0
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -0
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +67 -0
- package/dest/msg_validators/attestation_validator/index.d.ts +1 -0
- package/dest/msg_validators/attestation_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/index.js +1 -0
- package/dest/services/libp2p/libp2p_service.d.ts +1 -1
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +12 -8
- package/package.json +14 -14
- package/src/config.ts +9 -0
- package/src/msg_validators/attestation_validator/attestation_validator.ts +2 -2
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +91 -0
- package/src/msg_validators/attestation_validator/index.ts +1 -0
- package/src/services/libp2p/libp2p_service.ts +21 -7
package/dest/config.d.ts
CHANGED
|
@@ -103,6 +103,8 @@ export interface P2PConfig extends P2PReqRespConfig, ChainConfig, TxCollectionCo
|
|
|
103
103
|
dropTransactionsProbability: number;
|
|
104
104
|
/** Whether to delete transactions from the pool after a reorg instead of moving them back to pending. */
|
|
105
105
|
txPoolDeleteTxsAfterReorg: boolean;
|
|
106
|
+
/** Whether to run in fisherman mode: validates all proposals and attestations but does not broadcast attestations or participate in consensus */
|
|
107
|
+
fishermanMode: boolean;
|
|
106
108
|
}
|
|
107
109
|
export declare const DEFAULT_P2P_PORT = 40400;
|
|
108
110
|
export declare const p2pConfigMappings: ConfigMappingsType<P2PConfig>;
|
|
@@ -184,6 +186,7 @@ export declare const bootnodeConfigMappings: ConfigMappingsType<Pick<{
|
|
|
184
186
|
dropTransactions: unknown;
|
|
185
187
|
dropTransactionsProbability: unknown;
|
|
186
188
|
txPoolDeleteTxsAfterReorg: unknown;
|
|
189
|
+
fishermanMode: unknown;
|
|
187
190
|
}, "p2pPort" | "p2pBroadcastPort" | "p2pIp" | "listenAddress" | "peerIdPrivateKey" | "peerIdPrivateKeyPath" | "bootstrapNodes" | "queryForIp" | "l1ChainId" | "dataDirectory" | "dataStoreMapSizeKb">>;
|
|
188
191
|
/**
|
|
189
192
|
* Parses a string to a list of allowed elements.
|
package/dest/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dest/config.js
CHANGED
|
@@ -255,6 +255,11 @@ export const p2pConfigMappings = {
|
|
|
255
255
|
description: 'Whether to delete transactions from the pool after a reorg instead of moving them back to pending.',
|
|
256
256
|
...booleanConfigHelper(false)
|
|
257
257
|
},
|
|
258
|
+
fishermanMode: {
|
|
259
|
+
env: 'FISHERMAN_MODE',
|
|
260
|
+
description: 'Whether to run in fisherman mode: validates all proposals and attestations but does not broadcast attestations or participate in consensus.',
|
|
261
|
+
...booleanConfigHelper(false)
|
|
262
|
+
},
|
|
258
263
|
...p2pReqRespConfigMappings,
|
|
259
264
|
...chainConfigMappings,
|
|
260
265
|
...txCollectionConfigMappings
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
+
import { type Logger } from '@aztec/foundation/log';
|
|
2
3
|
import { type BlockAttestation, type P2PValidator, PeerErrorSeverity } from '@aztec/stdlib/p2p';
|
|
3
4
|
export declare class AttestationValidator implements P2PValidator<BlockAttestation> {
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
protected epochCache: EpochCacheInterface;
|
|
6
|
+
protected logger: Logger;
|
|
6
7
|
constructor(epochCache: EpochCacheInterface);
|
|
7
8
|
validate(message: BlockAttestation): Promise<PeerErrorSeverity | undefined>;
|
|
8
9
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attestation_validator.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/attestation_validator/attestation_validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"attestation_validator.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/attestation_validator/attestation_validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEhG,qBAAa,oBAAqB,YAAW,YAAY,CAAC,gBAAgB,CAAC;IACzE,SAAS,CAAC,UAAU,EAAE,mBAAmB,CAAC;IAC1C,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEb,UAAU,EAAE,mBAAmB;IAKrC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;CAwDlF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
+
import { type BlockAttestation, PeerErrorSeverity } from '@aztec/stdlib/p2p';
|
|
3
|
+
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
4
|
+
import type { AttestationPool } from '../../mem_pools/attestation_pool/attestation_pool.js';
|
|
5
|
+
import { AttestationValidator } from './attestation_validator.js';
|
|
6
|
+
/**
|
|
7
|
+
* FishermanAttestationValidator extends the base AttestationValidator to add
|
|
8
|
+
* additional validation for fisherman nodes: verifying that attestations sign
|
|
9
|
+
* the same payload as the original proposal.
|
|
10
|
+
* Invalid attestations are rejected (not propagated), but peer penalization is
|
|
11
|
+
* handled by LibP2PService based on the fishermanMode config to ensure a better
|
|
12
|
+
* view of the network.
|
|
13
|
+
*/
|
|
14
|
+
export declare class FishermanAttestationValidator extends AttestationValidator {
|
|
15
|
+
private attestationPool;
|
|
16
|
+
private invalidAttestationCounter;
|
|
17
|
+
constructor(epochCache: EpochCacheInterface, attestationPool: AttestationPool, telemetryClient: TelemetryClient);
|
|
18
|
+
validate(message: BlockAttestation): Promise<PeerErrorSeverity | undefined>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=fisherman_attestation_validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fisherman_attestation_validator.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/attestation_validator/fisherman_attestation_validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,KAAK,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAuB,KAAK,eAAe,EAAa,MAAM,yBAAyB,CAAC;AAE/F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sDAAsD,CAAC;AAC5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAElE;;;;;;;GAOG;AACH,qBAAa,6BAA8B,SAAQ,oBAAoB;IAKnE,OAAO,CAAC,eAAe;IAJzB,OAAO,CAAC,yBAAyB,CAAC;gBAGhC,UAAU,EAAE,mBAAmB,EACvB,eAAe,EAAE,eAAe,EACxC,eAAe,EAAE,eAAe;IAYnB,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;CAyD3F"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { PeerErrorSeverity } from '@aztec/stdlib/p2p';
|
|
2
|
+
import { Attributes, Metrics, ValueType } from '@aztec/telemetry-client';
|
|
3
|
+
import { AttestationValidator } from './attestation_validator.js';
|
|
4
|
+
/**
|
|
5
|
+
* FishermanAttestationValidator extends the base AttestationValidator to add
|
|
6
|
+
* additional validation for fisherman nodes: verifying that attestations sign
|
|
7
|
+
* the same payload as the original proposal.
|
|
8
|
+
* Invalid attestations are rejected (not propagated), but peer penalization is
|
|
9
|
+
* handled by LibP2PService based on the fishermanMode config to ensure a better
|
|
10
|
+
* view of the network.
|
|
11
|
+
*/ export class FishermanAttestationValidator extends AttestationValidator {
|
|
12
|
+
attestationPool;
|
|
13
|
+
invalidAttestationCounter;
|
|
14
|
+
constructor(epochCache, attestationPool, telemetryClient){
|
|
15
|
+
super(epochCache), this.attestationPool = attestationPool;
|
|
16
|
+
this.logger = this.logger.createChild('[FISHERMAN]');
|
|
17
|
+
const meter = telemetryClient.getMeter('FishermanAttestationValidator');
|
|
18
|
+
this.invalidAttestationCounter = meter.createUpDownCounter(Metrics.VALIDATOR_INVALID_ATTESTATION_RECEIVED_COUNT, {
|
|
19
|
+
description: 'The number of invalid attestations received',
|
|
20
|
+
valueType: ValueType.INT
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
async validate(message) {
|
|
24
|
+
// First run the standard validation
|
|
25
|
+
const baseValidationResult = await super.validate(message);
|
|
26
|
+
if (baseValidationResult !== undefined) {
|
|
27
|
+
// Track base validation failures (invalid signature, wrong committee, etc.)
|
|
28
|
+
this.invalidAttestationCounter.add(1, {
|
|
29
|
+
[Attributes.ERROR_TYPE]: 'base_validation_failed'
|
|
30
|
+
});
|
|
31
|
+
return baseValidationResult;
|
|
32
|
+
}
|
|
33
|
+
// fisherman validation: verify attestation payload matches proposal payload
|
|
34
|
+
const slotNumberBigInt = message.payload.header.slotNumber.toBigInt();
|
|
35
|
+
const attester = message.getSender();
|
|
36
|
+
const proposer = message.getProposer();
|
|
37
|
+
if (!attester || !proposer) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
const proposalId = message.archive.toString();
|
|
41
|
+
const proposal = await this.attestationPool.getBlockProposal(proposalId);
|
|
42
|
+
if (proposal) {
|
|
43
|
+
// Compare the attestation payload with the proposal payload
|
|
44
|
+
if (!message.payload.equals(proposal.payload)) {
|
|
45
|
+
this.logger.error(`Attestation payload mismatch for slot ${slotNumberBigInt}! ` + `Attester ${attester.toString()} signed different data than the proposal.`, {
|
|
46
|
+
slot: slotNumberBigInt.toString(),
|
|
47
|
+
attester: attester.toString(),
|
|
48
|
+
proposer: proposer.toString(),
|
|
49
|
+
proposalArchive: proposal.archive.toString(),
|
|
50
|
+
attestationArchive: message.archive.toString(),
|
|
51
|
+
proposalHeader: proposal.payload.header.hash().toString(),
|
|
52
|
+
attestationHeader: message.payload.header.hash().toString()
|
|
53
|
+
});
|
|
54
|
+
// Track invalid attestation metric
|
|
55
|
+
this.invalidAttestationCounter.add(1, {
|
|
56
|
+
[Attributes.ERROR_TYPE]: 'payload_mismatch'
|
|
57
|
+
});
|
|
58
|
+
// Return error to reject the message, but LibP2PService won't penalize in fisherman mode
|
|
59
|
+
return PeerErrorSeverity.LowToleranceError;
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
// We might receive attestations before proposals in some cases
|
|
63
|
+
this.logger.debug(`Received attestation for slot ${slotNumberBigInt} but proposal not found yet. ` + `Proposal ID: ${proposalId}`);
|
|
64
|
+
}
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/attestation_validator/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/msg_validators/attestation_validator/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sCAAsC,CAAC"}
|
|
@@ -39,7 +39,6 @@ export declare class LibP2PService<T extends P2PClientType = P2PClientType.Full>
|
|
|
39
39
|
private epochCache;
|
|
40
40
|
private proofVerifier;
|
|
41
41
|
private worldStateSynchronizer;
|
|
42
|
-
protected logger: Logger;
|
|
43
42
|
private jobQueue;
|
|
44
43
|
private discoveryRunningPromise?;
|
|
45
44
|
private msgIdSeenValidators;
|
|
@@ -56,6 +55,7 @@ export declare class LibP2PService<T extends P2PClientType = P2PClientType.Full>
|
|
|
56
55
|
private blockReceivedCallback;
|
|
57
56
|
private gossipSubEventHandler;
|
|
58
57
|
private instrumentation;
|
|
58
|
+
protected logger: Logger;
|
|
59
59
|
constructor(clientType: T, config: P2PConfig, node: PubSubLibp2p, peerDiscoveryService: PeerDiscoveryService, reqresp: ReqRespInterface, peerManager: PeerManagerInterface, mempools: MemPools<T>, archiver: L2BlockSource & ContractDataSource, epochCache: EpochCacheInterface, proofVerifier: ClientProtocolCircuitVerifier, worldStateSynchronizer: WorldStateSynchronizer, telemetry: TelemetryClient, logger?: Logger);
|
|
60
60
|
updateConfig(config: Partial<P2PReqRespConfig>): void;
|
|
61
61
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"libp2p_service.d.ts","sourceRoot":"","sources":["../../../src/services/libp2p/libp2p_service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG9D,OAAO,EAAE,KAAK,MAAM,EAA6C,MAAM,uBAAuB,CAAC;AAI/F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGzD,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,OAAO,KAAK,EAAE,6BAA6B,EAAE,QAAQ,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACvH,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,KAAK,UAAU,EACf,aAAa,EAGb,SAAS,EAIV,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,EAAE,EAA0D,MAAM,kBAAkB,CAAC;AAG9F,OAAO,EAAkC,KAAK,eAAe,EAAE,UAAU,EAAa,MAAM,yBAAyB,CAAC;AActH,OAAO,EAAE,KAAK,OAAO,EAA4B,KAAK,MAAM,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAI9G,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAGzC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"libp2p_service.d.ts","sourceRoot":"","sources":["../../../src/services/libp2p/libp2p_service.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,7 +30,7 @@ import { mplex } from '@libp2p/mplex';
|
|
|
30
30
|
import { tcp } from '@libp2p/tcp';
|
|
31
31
|
import { ENR } from '@nethermindeth/enr';
|
|
32
32
|
import { createLibp2p } from 'libp2p';
|
|
33
|
-
import { AttestationValidator, BlockProposalValidator } from '../../msg_validators/index.js';
|
|
33
|
+
import { AttestationValidator, BlockProposalValidator, FishermanAttestationValidator } from '../../msg_validators/index.js';
|
|
34
34
|
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
35
35
|
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
36
36
|
import { createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
|
|
@@ -64,7 +64,6 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
64
64
|
epochCache;
|
|
65
65
|
proofVerifier;
|
|
66
66
|
worldStateSynchronizer;
|
|
67
|
-
logger;
|
|
68
67
|
jobQueue;
|
|
69
68
|
discoveryRunningPromise;
|
|
70
69
|
msgIdSeenValidators;
|
|
@@ -81,8 +80,11 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
81
80
|
*/ blockReceivedCallback;
|
|
82
81
|
gossipSubEventHandler;
|
|
83
82
|
instrumentation;
|
|
83
|
+
logger;
|
|
84
84
|
constructor(clientType, config, node, peerDiscoveryService, reqresp, peerManager, mempools, archiver, epochCache, proofVerifier, worldStateSynchronizer, telemetry, logger = createLogger('p2p:libp2p_service')){
|
|
85
|
-
super(telemetry, 'LibP2PService'), this.clientType = clientType, this.config = config, this.node = node, this.peerDiscoveryService = peerDiscoveryService, this.reqresp = reqresp, this.peerManager = peerManager, this.mempools = mempools, this.archiver = archiver, this.epochCache = epochCache, this.proofVerifier = proofVerifier, this.worldStateSynchronizer = worldStateSynchronizer, this.
|
|
85
|
+
super(telemetry, 'LibP2PService'), this.clientType = clientType, this.config = config, this.node = node, this.peerDiscoveryService = peerDiscoveryService, this.reqresp = reqresp, this.peerManager = peerManager, this.mempools = mempools, this.archiver = archiver, this.epochCache = epochCache, this.proofVerifier = proofVerifier, this.worldStateSynchronizer = worldStateSynchronizer, this.jobQueue = new SerialQueue(), this.msgIdSeenValidators = {}, this.protocolVersion = '', this.topicStrings = {};
|
|
86
|
+
// Create child logger with fisherman prefix if in fisherman mode
|
|
87
|
+
this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
|
|
86
88
|
this.instrumentation = new P2PInstrumentation(telemetry, 'LibP2PService');
|
|
87
89
|
this.msgIdSeenValidators[TopicType.tx] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
88
90
|
this.msgIdSeenValidators[TopicType.block_proposal] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
@@ -93,7 +95,8 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
93
95
|
this.topicStrings[TopicType.tx] = createTopicString(TopicType.tx, this.protocolVersion);
|
|
94
96
|
this.topicStrings[TopicType.block_proposal] = createTopicString(TopicType.block_proposal, this.protocolVersion);
|
|
95
97
|
this.topicStrings[TopicType.block_attestation] = createTopicString(TopicType.block_attestation, this.protocolVersion);
|
|
96
|
-
|
|
98
|
+
// Use FishermanAttestationValidator in fisherman mode to validate attestation payloads against proposals
|
|
99
|
+
this.attestationValidator = config.fishermanMode ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry) : new AttestationValidator(epochCache);
|
|
97
100
|
this.blockProposalValidator = new BlockProposalValidator(epochCache, {
|
|
98
101
|
txsPermitted: !config.disableTransactions
|
|
99
102
|
});
|
|
@@ -673,7 +676,7 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
673
676
|
await this.mempools.attestationPool?.addBlockProposal(block);
|
|
674
677
|
const attestations = await this.blockReceivedCallback(block, sender);
|
|
675
678
|
// TODO: fix up this pattern - the abstraction is not nice
|
|
676
|
-
// The attestation can be undefined if no handler is registered / the validator deems the block invalid
|
|
679
|
+
// The attestation can be undefined if no handler is registered / the validator deems the block invalid / in fisherman mode
|
|
677
680
|
if (attestations?.length) {
|
|
678
681
|
for (const attestation of attestations){
|
|
679
682
|
this.logger.verbose(`Broadcasting attestation for slot ${attestation.slotNumber.toNumber()}`, {
|
|
@@ -767,17 +770,18 @@ import { P2PInstrumentation } from './instrumentation.js';
|
|
|
767
770
|
}), new TxProofValidator(this.proofVerifier));
|
|
768
771
|
}
|
|
769
772
|
async validateRequestedTx(tx, peerId, txValidator, requested) {
|
|
773
|
+
const penalize = (severity)=>this.peerManager.penalizePeer(peerId, severity);
|
|
770
774
|
if (!await tx.validateTxHash()) {
|
|
771
|
-
|
|
775
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
772
776
|
throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
|
|
773
777
|
}
|
|
774
778
|
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
775
|
-
|
|
779
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
776
780
|
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
777
781
|
}
|
|
778
782
|
const { result } = await txValidator.validateTx(tx);
|
|
779
783
|
if (result === 'invalid') {
|
|
780
|
-
|
|
784
|
+
penalize(PeerErrorSeverity.LowToleranceError);
|
|
781
785
|
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
782
786
|
}
|
|
783
787
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/p2p",
|
|
3
|
-
"version": "3.0.0-nightly.
|
|
3
|
+
"version": "3.0.0-nightly.20251114",
|
|
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": "3.0.0-nightly.
|
|
71
|
-
"@aztec/epoch-cache": "3.0.0-nightly.
|
|
72
|
-
"@aztec/ethereum": "3.0.0-nightly.
|
|
73
|
-
"@aztec/foundation": "3.0.0-nightly.
|
|
74
|
-
"@aztec/kv-store": "3.0.0-nightly.
|
|
75
|
-
"@aztec/noir-contracts.js": "3.0.0-nightly.
|
|
76
|
-
"@aztec/noir-protocol-circuits-types": "3.0.0-nightly.
|
|
77
|
-
"@aztec/protocol-contracts": "3.0.0-nightly.
|
|
78
|
-
"@aztec/simulator": "3.0.0-nightly.
|
|
79
|
-
"@aztec/stdlib": "3.0.0-nightly.
|
|
80
|
-
"@aztec/telemetry-client": "3.0.0-nightly.
|
|
70
|
+
"@aztec/constants": "3.0.0-nightly.20251114",
|
|
71
|
+
"@aztec/epoch-cache": "3.0.0-nightly.20251114",
|
|
72
|
+
"@aztec/ethereum": "3.0.0-nightly.20251114",
|
|
73
|
+
"@aztec/foundation": "3.0.0-nightly.20251114",
|
|
74
|
+
"@aztec/kv-store": "3.0.0-nightly.20251114",
|
|
75
|
+
"@aztec/noir-contracts.js": "3.0.0-nightly.20251114",
|
|
76
|
+
"@aztec/noir-protocol-circuits-types": "3.0.0-nightly.20251114",
|
|
77
|
+
"@aztec/protocol-contracts": "3.0.0-nightly.20251114",
|
|
78
|
+
"@aztec/simulator": "3.0.0-nightly.20251114",
|
|
79
|
+
"@aztec/stdlib": "3.0.0-nightly.20251114",
|
|
80
|
+
"@aztec/telemetry-client": "3.0.0-nightly.20251114",
|
|
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": "3.0.0-nightly.
|
|
108
|
-
"@aztec/world-state": "3.0.0-nightly.
|
|
107
|
+
"@aztec/archiver": "3.0.0-nightly.20251114",
|
|
108
|
+
"@aztec/world-state": "3.0.0-nightly.20251114",
|
|
109
109
|
"@jest/globals": "^30.0.0",
|
|
110
110
|
"@types/jest": "^30.0.0",
|
|
111
111
|
"@types/node": "^22.15.17",
|
package/src/config.ts
CHANGED
|
@@ -164,6 +164,9 @@ export interface P2PConfig extends P2PReqRespConfig, ChainConfig, TxCollectionCo
|
|
|
164
164
|
|
|
165
165
|
/** Whether to delete transactions from the pool after a reorg instead of moving them back to pending. */
|
|
166
166
|
txPoolDeleteTxsAfterReorg: boolean;
|
|
167
|
+
|
|
168
|
+
/** Whether to run in fisherman mode: validates all proposals and attestations but does not broadcast attestations or participate in consensus */
|
|
169
|
+
fishermanMode: boolean;
|
|
167
170
|
}
|
|
168
171
|
|
|
169
172
|
export const DEFAULT_P2P_PORT = 40400;
|
|
@@ -420,6 +423,12 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
|
420
423
|
description: 'Whether to delete transactions from the pool after a reorg instead of moving them back to pending.',
|
|
421
424
|
...booleanConfigHelper(false),
|
|
422
425
|
},
|
|
426
|
+
fishermanMode: {
|
|
427
|
+
env: 'FISHERMAN_MODE',
|
|
428
|
+
description:
|
|
429
|
+
'Whether to run in fisherman mode: validates all proposals and attestations but does not broadcast attestations or participate in consensus.',
|
|
430
|
+
...booleanConfigHelper(false),
|
|
431
|
+
},
|
|
423
432
|
...p2pReqRespConfigMappings,
|
|
424
433
|
...chainConfigMappings,
|
|
425
434
|
...txCollectionConfigMappings,
|
|
@@ -4,8 +4,8 @@ import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
|
4
4
|
import { type BlockAttestation, type P2PValidator, PeerErrorSeverity } from '@aztec/stdlib/p2p';
|
|
5
5
|
|
|
6
6
|
export class AttestationValidator implements P2PValidator<BlockAttestation> {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
protected epochCache: EpochCacheInterface;
|
|
8
|
+
protected logger: Logger;
|
|
9
9
|
|
|
10
10
|
constructor(epochCache: EpochCacheInterface) {
|
|
11
11
|
this.epochCache = epochCache;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
+
import { type BlockAttestation, PeerErrorSeverity } from '@aztec/stdlib/p2p';
|
|
3
|
+
import { Attributes, Metrics, type TelemetryClient, ValueType } from '@aztec/telemetry-client';
|
|
4
|
+
|
|
5
|
+
import type { AttestationPool } from '../../mem_pools/attestation_pool/attestation_pool.js';
|
|
6
|
+
import { AttestationValidator } from './attestation_validator.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* FishermanAttestationValidator extends the base AttestationValidator to add
|
|
10
|
+
* additional validation for fisherman nodes: verifying that attestations sign
|
|
11
|
+
* the same payload as the original proposal.
|
|
12
|
+
* Invalid attestations are rejected (not propagated), but peer penalization is
|
|
13
|
+
* handled by LibP2PService based on the fishermanMode config to ensure a better
|
|
14
|
+
* view of the network.
|
|
15
|
+
*/
|
|
16
|
+
export class FishermanAttestationValidator extends AttestationValidator {
|
|
17
|
+
private invalidAttestationCounter;
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
epochCache: EpochCacheInterface,
|
|
21
|
+
private attestationPool: AttestationPool,
|
|
22
|
+
telemetryClient: TelemetryClient,
|
|
23
|
+
) {
|
|
24
|
+
super(epochCache);
|
|
25
|
+
this.logger = this.logger.createChild('[FISHERMAN]');
|
|
26
|
+
|
|
27
|
+
const meter = telemetryClient.getMeter('FishermanAttestationValidator');
|
|
28
|
+
this.invalidAttestationCounter = meter.createUpDownCounter(Metrics.VALIDATOR_INVALID_ATTESTATION_RECEIVED_COUNT, {
|
|
29
|
+
description: 'The number of invalid attestations received',
|
|
30
|
+
valueType: ValueType.INT,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
override async validate(message: BlockAttestation): Promise<PeerErrorSeverity | undefined> {
|
|
35
|
+
// First run the standard validation
|
|
36
|
+
const baseValidationResult = await super.validate(message);
|
|
37
|
+
if (baseValidationResult !== undefined) {
|
|
38
|
+
// Track base validation failures (invalid signature, wrong committee, etc.)
|
|
39
|
+
this.invalidAttestationCounter.add(1, {
|
|
40
|
+
[Attributes.ERROR_TYPE]: 'base_validation_failed',
|
|
41
|
+
});
|
|
42
|
+
return baseValidationResult;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// fisherman validation: verify attestation payload matches proposal payload
|
|
46
|
+
const slotNumberBigInt = message.payload.header.slotNumber.toBigInt();
|
|
47
|
+
const attester = message.getSender();
|
|
48
|
+
const proposer = message.getProposer();
|
|
49
|
+
|
|
50
|
+
if (!attester || !proposer) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const proposalId = message.archive.toString();
|
|
55
|
+
const proposal = await this.attestationPool.getBlockProposal(proposalId);
|
|
56
|
+
|
|
57
|
+
if (proposal) {
|
|
58
|
+
// Compare the attestation payload with the proposal payload
|
|
59
|
+
if (!message.payload.equals(proposal.payload)) {
|
|
60
|
+
this.logger.error(
|
|
61
|
+
`Attestation payload mismatch for slot ${slotNumberBigInt}! ` +
|
|
62
|
+
`Attester ${attester.toString()} signed different data than the proposal.`,
|
|
63
|
+
{
|
|
64
|
+
slot: slotNumberBigInt.toString(),
|
|
65
|
+
attester: attester.toString(),
|
|
66
|
+
proposer: proposer.toString(),
|
|
67
|
+
proposalArchive: proposal.archive.toString(),
|
|
68
|
+
attestationArchive: message.archive.toString(),
|
|
69
|
+
proposalHeader: proposal.payload.header.hash().toString(),
|
|
70
|
+
attestationHeader: message.payload.header.hash().toString(),
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// Track invalid attestation metric
|
|
75
|
+
this.invalidAttestationCounter.add(1, {
|
|
76
|
+
[Attributes.ERROR_TYPE]: 'payload_mismatch',
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Return error to reject the message, but LibP2PService won't penalize in fisherman mode
|
|
80
|
+
return PeerErrorSeverity.LowToleranceError;
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
// We might receive attestations before proposals in some cases
|
|
84
|
+
this.logger.debug(
|
|
85
|
+
`Received attestation for slot ${slotNumberBigInt} but proposal not found yet. ` + `Proposal ID: ${proposalId}`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -51,7 +51,11 @@ import { createLibp2p } from 'libp2p';
|
|
|
51
51
|
|
|
52
52
|
import type { P2PConfig } from '../../config.js';
|
|
53
53
|
import type { MemPools } from '../../mem_pools/interface.js';
|
|
54
|
-
import {
|
|
54
|
+
import {
|
|
55
|
+
AttestationValidator,
|
|
56
|
+
BlockProposalValidator,
|
|
57
|
+
FishermanAttestationValidator,
|
|
58
|
+
} from '../../msg_validators/index.js';
|
|
55
59
|
import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
|
|
56
60
|
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
57
61
|
import { type MessageValidator, createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
|
|
@@ -140,6 +144,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
140
144
|
|
|
141
145
|
private instrumentation: P2PInstrumentation;
|
|
142
146
|
|
|
147
|
+
protected logger: Logger;
|
|
148
|
+
|
|
143
149
|
constructor(
|
|
144
150
|
private clientType: T,
|
|
145
151
|
private config: P2PConfig,
|
|
@@ -153,10 +159,13 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
153
159
|
private proofVerifier: ClientProtocolCircuitVerifier,
|
|
154
160
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
155
161
|
telemetry: TelemetryClient,
|
|
156
|
-
|
|
162
|
+
logger: Logger = createLogger('p2p:libp2p_service'),
|
|
157
163
|
) {
|
|
158
164
|
super(telemetry, 'LibP2PService');
|
|
159
165
|
|
|
166
|
+
// Create child logger with fisherman prefix if in fisherman mode
|
|
167
|
+
this.logger = config.fishermanMode ? logger.createChild('[FISHERMAN]') : logger;
|
|
168
|
+
|
|
160
169
|
this.instrumentation = new P2PInstrumentation(telemetry, 'LibP2PService');
|
|
161
170
|
|
|
162
171
|
this.msgIdSeenValidators[TopicType.tx] = new MessageSeenValidator(config.seenMessageCacheSize);
|
|
@@ -174,7 +183,10 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
174
183
|
this.protocolVersion,
|
|
175
184
|
);
|
|
176
185
|
|
|
177
|
-
|
|
186
|
+
// Use FishermanAttestationValidator in fisherman mode to validate attestation payloads against proposals
|
|
187
|
+
this.attestationValidator = config.fishermanMode
|
|
188
|
+
? new FishermanAttestationValidator(epochCache, mempools.attestationPool!, telemetry)
|
|
189
|
+
: new AttestationValidator(epochCache);
|
|
178
190
|
this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
|
|
179
191
|
|
|
180
192
|
this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
|
|
@@ -896,7 +908,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
896
908
|
const attestations = await this.blockReceivedCallback(block, sender);
|
|
897
909
|
|
|
898
910
|
// TODO: fix up this pattern - the abstraction is not nice
|
|
899
|
-
// The attestation can be undefined if no handler is registered / the validator deems the block invalid
|
|
911
|
+
// The attestation can be undefined if no handler is registered / the validator deems the block invalid / in fisherman mode
|
|
900
912
|
if (attestations?.length) {
|
|
901
913
|
for (const attestation of attestations) {
|
|
902
914
|
this.logger.verbose(`Broadcasting attestation for slot ${attestation.slotNumber.toNumber()}`, {
|
|
@@ -1021,19 +1033,21 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
|
|
|
1021
1033
|
}
|
|
1022
1034
|
|
|
1023
1035
|
private async validateRequestedTx(tx: Tx, peerId: PeerId, txValidator: TxValidator, requested?: Set<`0x${string}`>) {
|
|
1036
|
+
const penalize = (severity: PeerErrorSeverity) => this.peerManager.penalizePeer(peerId, severity);
|
|
1037
|
+
|
|
1024
1038
|
if (!(await tx.validateTxHash())) {
|
|
1025
|
-
|
|
1039
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1026
1040
|
throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
|
|
1027
1041
|
}
|
|
1028
1042
|
|
|
1029
1043
|
if (requested && !requested.has(tx.getTxHash().toString())) {
|
|
1030
|
-
|
|
1044
|
+
penalize(PeerErrorSeverity.MidToleranceError);
|
|
1031
1045
|
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
|
|
1032
1046
|
}
|
|
1033
1047
|
|
|
1034
1048
|
const { result } = await txValidator.validateTx(tx);
|
|
1035
1049
|
if (result === 'invalid') {
|
|
1036
|
-
|
|
1050
|
+
penalize(PeerErrorSeverity.LowToleranceError);
|
|
1037
1051
|
throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
|
|
1038
1052
|
}
|
|
1039
1053
|
}
|