@aztec/p2p 0.83.0 → 0.83.1-nightly.20250404
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/client/factory.d.ts +2 -1
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +3 -3
- package/dest/client/p2p_client.d.ts +2 -1
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/config.d.ts +16 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +53 -0
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +3 -0
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/allowed_public_setup.js +27 -0
- package/dest/msg_validators/tx_validator/gas_validator.d.ts +10 -0
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/gas_validator.js +76 -0
- package/dest/msg_validators/tx_validator/index.d.ts +4 -0
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +4 -0
- package/dest/msg_validators/tx_validator/phases_validator.d.ts +13 -0
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/phases_validator.js +83 -0
- package/dest/msg_validators/tx_validator/test_utils.d.ts +17 -0
- package/dest/msg_validators/tx_validator/test_utils.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/test_utils.js +22 -0
- package/dest/services/libp2p/libp2p_service.d.ts +6 -3
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +36 -9
- package/dest/test-helpers/reqresp-nodes.d.ts +2 -1
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +2 -2
- package/package.json +12 -10
- package/src/client/factory.ts +4 -3
- package/src/client/p2p_client.ts +2 -1
- package/src/config.ts +64 -1
- package/src/msg_validators/tx_validator/allowed_public_setup.ts +35 -0
- package/src/msg_validators/tx_validator/gas_validator.ts +95 -0
- package/src/msg_validators/tx_validator/index.ts +4 -0
- package/src/msg_validators/tx_validator/phases_validator.ts +104 -0
- package/src/msg_validators/tx_validator/test_utils.ts +43 -0
- package/src/services/libp2p/libp2p_service.ts +42 -7
- package/src/test-helpers/reqresp-nodes.ts +3 -2
|
@@ -8,8 +8,10 @@ import { Fr } from '@aztec/foundation/fields';
|
|
|
8
8
|
import { createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
9
9
|
import { SerialQueue } from '@aztec/foundation/queue';
|
|
10
10
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
11
|
+
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
12
|
+
import { GasFees } from '@aztec/stdlib/gas';
|
|
11
13
|
import { BlockAttestation, BlockProposal, P2PClientType, PeerErrorSeverity, TopicTypeMap, getTopicTypeForClientType, metricsTopicStrToLabels } from '@aztec/stdlib/p2p';
|
|
12
|
-
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
14
|
+
import { DatabasePublicStateSource, MerkleTreeId } from '@aztec/stdlib/trees';
|
|
13
15
|
import { Tx } from '@aztec/stdlib/tx';
|
|
14
16
|
import { Attributes, OtelMetricsAdapter, WithTracer, trackSpan } from '@aztec/telemetry-client';
|
|
15
17
|
import { gossipsub } from '@chainsafe/libp2p-gossipsub';
|
|
@@ -25,7 +27,8 @@ import { mplex } from '@libp2p/mplex';
|
|
|
25
27
|
import { tcp } from '@libp2p/tcp';
|
|
26
28
|
import { createLibp2p } from 'libp2p';
|
|
27
29
|
import { AttestationValidator, BlockProposalValidator } from '../../msg_validators/index.js';
|
|
28
|
-
import {
|
|
30
|
+
import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
|
|
31
|
+
import { DataTxValidator, DoubleSpendTxValidator, GasTxValidator, MetadataTxValidator, PhasesTxValidator, TxProofValidator } from '../../msg_validators/tx_validator/index.js';
|
|
29
32
|
import { GossipSubEvent } from '../../types/index.js';
|
|
30
33
|
import { convertToMultiaddr } from '../../util.js';
|
|
31
34
|
import { AztecDatastore } from '../data_store.js';
|
|
@@ -45,7 +48,7 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
45
48
|
node;
|
|
46
49
|
peerDiscoveryService;
|
|
47
50
|
mempools;
|
|
48
|
-
|
|
51
|
+
archiver;
|
|
49
52
|
proofVerifier;
|
|
50
53
|
worldStateSynchronizer;
|
|
51
54
|
logger;
|
|
@@ -59,14 +62,15 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
59
62
|
reqresp;
|
|
60
63
|
// Trusted peers ids
|
|
61
64
|
trustedPeersIds;
|
|
65
|
+
feesCache;
|
|
62
66
|
/**
|
|
63
67
|
* Callback for when a block is received from a peer.
|
|
64
68
|
* @param block - The block received from the peer.
|
|
65
69
|
* @returns The attestation for the block, if any.
|
|
66
70
|
*/ blockReceivedCallback;
|
|
67
71
|
gossipSubEventHandler;
|
|
68
|
-
constructor(clientType, config, node, peerDiscoveryService, mempools,
|
|
69
|
-
super(telemetry, 'LibP2PService'), this.clientType = clientType, this.config = config, this.node = node, this.peerDiscoveryService = peerDiscoveryService, this.mempools = mempools, this.
|
|
72
|
+
constructor(clientType, config, node, peerDiscoveryService, mempools, archiver, epochCache, proofVerifier, worldStateSynchronizer, telemetry, logger = createLogger('p2p:libp2p_service')){
|
|
73
|
+
super(telemetry, 'LibP2PService'), this.clientType = clientType, this.config = config, this.node = node, this.peerDiscoveryService = peerDiscoveryService, this.mempools = mempools, this.archiver = archiver, this.proofVerifier = proofVerifier, this.worldStateSynchronizer = worldStateSynchronizer, this.logger = logger, this.jobQueue = new SerialQueue(), this.trustedPeersIds = [];
|
|
70
74
|
const peerScoring = new PeerScoring(config);
|
|
71
75
|
this.reqresp = new ReqResp(config, node, peerScoring);
|
|
72
76
|
this.peerManager = new PeerManager(node, peerDiscoveryService, config, telemetry, createLogger(`${logger.module}:peer_manager`), peerScoring, this.reqresp);
|
|
@@ -223,7 +227,7 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
223
227
|
// Create request response protocol handlers
|
|
224
228
|
const txHandler = reqRespTxHandler(this.mempools);
|
|
225
229
|
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
|
|
226
|
-
const blockHandler = reqRespBlockHandler(this.
|
|
230
|
+
const blockHandler = reqRespBlockHandler(this.archiver);
|
|
227
231
|
const requestResponseHandlers = {
|
|
228
232
|
[ReqRespSubProtocol.PING]: pingHandler,
|
|
229
233
|
[ReqRespSubProtocol.STATUS]: statusHandler,
|
|
@@ -509,8 +513,8 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
509
513
|
return true;
|
|
510
514
|
}
|
|
511
515
|
async validatePropagatedTx(tx, peerId) {
|
|
512
|
-
const blockNumber = await this.
|
|
513
|
-
const messageValidators = this.createMessageValidators(blockNumber);
|
|
516
|
+
const blockNumber = await this.archiver.getBlockNumber() + 1;
|
|
517
|
+
const messageValidators = await this.createMessageValidators(blockNumber);
|
|
514
518
|
const outcome = await this.runValidations(tx, messageValidators);
|
|
515
519
|
if (outcome.allPassed) {
|
|
516
520
|
return true;
|
|
@@ -524,6 +528,18 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
524
528
|
this.peerManager.penalizePeer(peerId, severity);
|
|
525
529
|
return false;
|
|
526
530
|
}
|
|
531
|
+
async getGasFees(blockNumber) {
|
|
532
|
+
if (blockNumber === this.feesCache?.blockNumber) {
|
|
533
|
+
return this.feesCache.gasFees;
|
|
534
|
+
}
|
|
535
|
+
const header = await this.archiver.getBlockHeader(blockNumber);
|
|
536
|
+
const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
|
|
537
|
+
this.feesCache = {
|
|
538
|
+
blockNumber,
|
|
539
|
+
gasFees
|
|
540
|
+
};
|
|
541
|
+
return gasFees;
|
|
542
|
+
}
|
|
527
543
|
/**
|
|
528
544
|
* Create message validators for the given block number.
|
|
529
545
|
*
|
|
@@ -532,7 +548,10 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
532
548
|
*
|
|
533
549
|
* @param blockNumber - The block number to create validators for.
|
|
534
550
|
* @returns The message validators.
|
|
535
|
-
*/ createMessageValidators(blockNumber) {
|
|
551
|
+
*/ async createMessageValidators(blockNumber) {
|
|
552
|
+
const merkleTree = this.worldStateSynchronizer.getCommitted();
|
|
553
|
+
const gasFees = await this.getGasFees(blockNumber - 1);
|
|
554
|
+
const allowedInSetup = this.config.txPublicSetupAllowList ?? await getDefaultAllowedSetupFunctions();
|
|
536
555
|
return {
|
|
537
556
|
dataValidator: {
|
|
538
557
|
validator: new DataTxValidator(),
|
|
@@ -555,6 +574,14 @@ import { ReqResp } from '../reqresp/reqresp.js';
|
|
|
555
574
|
}
|
|
556
575
|
}),
|
|
557
576
|
severity: PeerErrorSeverity.HighToleranceError
|
|
577
|
+
},
|
|
578
|
+
gasValidator: {
|
|
579
|
+
validator: new GasTxValidator(new DatabasePublicStateSource(merkleTree), ProtocolContractAddress.FeeJuice, gasFees),
|
|
580
|
+
severity: PeerErrorSeverity.HighToleranceError
|
|
581
|
+
},
|
|
582
|
+
phasesValidator: {
|
|
583
|
+
validator: new PhasesTxValidator(this.archiver, allowedInSetup, blockNumber),
|
|
584
|
+
severity: PeerErrorSeverity.MidToleranceError
|
|
558
585
|
}
|
|
559
586
|
};
|
|
560
587
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { EpochCache } from '@aztec/epoch-cache';
|
|
2
2
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
3
3
|
import { type ChainConfig } from '@aztec/stdlib/config';
|
|
4
|
+
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
4
5
|
import type { ClientProtocolCircuitVerifier, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
5
6
|
import type { P2PClientType } from '@aztec/stdlib/p2p';
|
|
6
7
|
import type { Tx } from '@aztec/stdlib/tx';
|
|
@@ -27,7 +28,7 @@ export declare function createLibp2pNode(boostrapAddrs?: string[], peerId?: Peer
|
|
|
27
28
|
*
|
|
28
29
|
*
|
|
29
30
|
*/
|
|
30
|
-
export declare function createTestLibP2PService<T extends P2PClientType>(clientType: T, boostrapAddrs: string[] | undefined,
|
|
31
|
+
export declare function createTestLibP2PService<T extends P2PClientType>(clientType: T, boostrapAddrs: string[] | undefined, archiver: L2BlockSource & ContractDataSource, worldStateSynchronizer: WorldStateSynchronizer, epochCache: EpochCache, mempools: MemPools<T>, telemetry: TelemetryClient, port?: number, peerId?: PeerId, chainConfig?: ChainConfig): Promise<LibP2PService<T>>;
|
|
31
32
|
/**
|
|
32
33
|
* A p2p / req resp node pairing the req node will always contain the p2p node.
|
|
33
34
|
* they are provided as a pair to allow access the p2p node directly
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reqresp-nodes.d.ts","sourceRoot":"","sources":["../../src/test-helpers/reqresp-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,KAAK,WAAW,EAAoB,MAAM,sBAAsB,CAAC;AAC1E,OAAO,KAAK,EAAE,6BAA6B,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC7G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AAEnF,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAM7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAKhD,OAAO,EAAE,KAAK,MAAM,EAAoC,MAAM,QAAQ,CAAC;AAEvE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAa,MAAM,cAAc,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAE5E,OAAO,EAEL,KAAK,0BAA0B,EAC/B,KAAK,4BAA4B,EAElC,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAGzD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,aAAa,GAAE,MAAM,EAAO,EAC5B,MAAM,CAAC,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,EACb,eAAe,GAAE,OAAe,EAChC,KAAK,GAAE,OAAc,GACpB,OAAO,CAAC,MAAM,CAAC,CAqCjB;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAAC,CAAC,SAAS,aAAa,EACnE,UAAU,EAAE,CAAC,EACb,aAAa,sBAAe,EAC5B,
|
|
1
|
+
{"version":3,"file":"reqresp-nodes.d.ts","sourceRoot":"","sources":["../../src/test-helpers/reqresp-nodes.ts"],"names":[],"mappings":"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"}
|
|
@@ -73,7 +73,7 @@ import { convertToMultiaddr, createLibP2PPeerIdFromPrivateKey } from '../util.js
|
|
|
73
73
|
* P2P functionality is operational, however everything else is default
|
|
74
74
|
*
|
|
75
75
|
*
|
|
76
|
-
*/ export async function createTestLibP2PService(clientType, boostrapAddrs = [],
|
|
76
|
+
*/ export async function createTestLibP2PService(clientType, boostrapAddrs = [], archiver, worldStateSynchronizer, epochCache, mempools, telemetry, port = 0, peerId, chainConfig = emptyChainConfig) {
|
|
77
77
|
peerId = peerId ?? await createSecp256k1PeerId();
|
|
78
78
|
const config = {
|
|
79
79
|
p2pIp: `127.0.0.1`,
|
|
@@ -90,7 +90,7 @@ import { convertToMultiaddr, createLibP2PPeerIdFromPrivateKey } from '../util.js
|
|
|
90
90
|
const proofVerifier = new AlwaysTrueCircuitVerifier();
|
|
91
91
|
// No bootstrap nodes provided as the libp2p service will register them in the constructor
|
|
92
92
|
const p2pNode = await createLibp2pNode([], peerId, port, /*enable gossip */ true, /**start */ false);
|
|
93
|
-
return new LibP2PService(clientType, config, p2pNode, discoveryService, mempools,
|
|
93
|
+
return new LibP2PService(clientType, config, p2pNode, discoveryService, mempools, archiver, epochCache, proofVerifier, worldStateSynchronizer, telemetry);
|
|
94
94
|
}
|
|
95
95
|
// Mock sub protocol handlers
|
|
96
96
|
export const MOCK_SUB_PROTOCOL_HANDLERS = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/p2p",
|
|
3
|
-
"version": "0.83.
|
|
3
|
+
"version": "0.83.1-nightly.20250404",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -65,14 +65,16 @@
|
|
|
65
65
|
]
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@aztec/constants": "0.83.
|
|
69
|
-
"@aztec/epoch-cache": "0.83.
|
|
70
|
-
"@aztec/foundation": "0.83.
|
|
71
|
-
"@aztec/kv-store": "0.83.
|
|
72
|
-
"@aztec/noir-
|
|
73
|
-
"@aztec/protocol-
|
|
74
|
-
"@aztec/
|
|
75
|
-
"@aztec/
|
|
68
|
+
"@aztec/constants": "0.83.1-nightly.20250404",
|
|
69
|
+
"@aztec/epoch-cache": "0.83.1-nightly.20250404",
|
|
70
|
+
"@aztec/foundation": "0.83.1-nightly.20250404",
|
|
71
|
+
"@aztec/kv-store": "0.83.1-nightly.20250404",
|
|
72
|
+
"@aztec/noir-contracts.js": "0.83.1-nightly.20250404",
|
|
73
|
+
"@aztec/noir-protocol-circuits-types": "0.83.1-nightly.20250404",
|
|
74
|
+
"@aztec/protocol-contracts": "0.83.1-nightly.20250404",
|
|
75
|
+
"@aztec/simulator": "0.83.1-nightly.20250404",
|
|
76
|
+
"@aztec/stdlib": "0.83.1-nightly.20250404",
|
|
77
|
+
"@aztec/telemetry-client": "0.83.1-nightly.20250404",
|
|
76
78
|
"@chainsafe/discv5": "9.0.0",
|
|
77
79
|
"@chainsafe/enr": "3.0.0",
|
|
78
80
|
"@chainsafe/libp2p-gossipsub": "13.0.0",
|
|
@@ -101,7 +103,7 @@
|
|
|
101
103
|
"xxhash-wasm": "^1.1.0"
|
|
102
104
|
},
|
|
103
105
|
"devDependencies": {
|
|
104
|
-
"@aztec/archiver": "0.83.
|
|
106
|
+
"@aztec/archiver": "0.83.1-nightly.20250404",
|
|
105
107
|
"@jest/globals": "^29.5.0",
|
|
106
108
|
"@types/jest": "^29.5.0",
|
|
107
109
|
"@types/node": "^18.14.6",
|
package/src/client/factory.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
|
4
4
|
import type { DataStoreConfig } from '@aztec/kv-store/config';
|
|
5
5
|
import { createStore } from '@aztec/kv-store/lmdb-v2';
|
|
6
6
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
7
|
+
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
7
8
|
import type { ClientProtocolCircuitVerifier, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
8
9
|
import { P2PClientType } from '@aztec/stdlib/p2p';
|
|
9
10
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
@@ -29,7 +30,7 @@ type P2PClientDeps<T extends P2PClientType> = {
|
|
|
29
30
|
export const createP2PClient = async <T extends P2PClientType>(
|
|
30
31
|
clientType: T,
|
|
31
32
|
_config: P2PConfig & DataStoreConfig,
|
|
32
|
-
|
|
33
|
+
archiver: L2BlockSource & ContractDataSource,
|
|
33
34
|
proofVerifier: ClientProtocolCircuitVerifier,
|
|
34
35
|
worldStateSynchronizer: WorldStateSynchronizer,
|
|
35
36
|
epochCache: EpochCacheInterface,
|
|
@@ -73,7 +74,7 @@ export const createP2PClient = async <T extends P2PClientType>(
|
|
|
73
74
|
discoveryService,
|
|
74
75
|
peerId,
|
|
75
76
|
mempools,
|
|
76
|
-
|
|
77
|
+
archiver,
|
|
77
78
|
epochCache,
|
|
78
79
|
proofVerifier,
|
|
79
80
|
worldStateSynchronizer,
|
|
@@ -85,5 +86,5 @@ export const createP2PClient = async <T extends P2PClientType>(
|
|
|
85
86
|
logger.verbose('P2P is disabled. Using dummy P2P service');
|
|
86
87
|
p2pService = new DummyP2PService();
|
|
87
88
|
}
|
|
88
|
-
return new P2PClient(clientType, store,
|
|
89
|
+
return new P2PClient(clientType, store, archiver, mempools, p2pService, config, telemetry);
|
|
89
90
|
};
|
package/src/client/p2p_client.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
L2Tips,
|
|
10
10
|
PublishedL2Block,
|
|
11
11
|
} from '@aztec/stdlib/block';
|
|
12
|
+
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
12
13
|
import type { P2PApi, PeerInfo, ProverCoordination } from '@aztec/stdlib/interfaces/server';
|
|
13
14
|
import { BlockAttestation, type BlockProposal, ConsensusPayload, type P2PClientType } from '@aztec/stdlib/p2p';
|
|
14
15
|
import type { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
@@ -211,7 +212,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
211
212
|
constructor(
|
|
212
213
|
_clientType: T,
|
|
213
214
|
store: AztecAsyncKVStore,
|
|
214
|
-
private l2BlockSource: L2BlockSource,
|
|
215
|
+
private l2BlockSource: L2BlockSource & ContractDataSource,
|
|
215
216
|
mempools: MemPools<T>,
|
|
216
217
|
private p2pService: P2PService,
|
|
217
218
|
config: Partial<P2PConfig> = {},
|
package/src/config.ts
CHANGED
|
@@ -6,8 +6,11 @@ import {
|
|
|
6
6
|
numberConfigHelper,
|
|
7
7
|
pickConfigMappings,
|
|
8
8
|
} from '@aztec/foundation/config';
|
|
9
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
9
10
|
import { type DataStoreConfig, dataConfigMappings } from '@aztec/kv-store/config';
|
|
10
|
-
import {
|
|
11
|
+
import { FunctionSelector } from '@aztec/stdlib/abi';
|
|
12
|
+
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
13
|
+
import { type AllowedElement, type ChainConfig, chainConfigMappings } from '@aztec/stdlib/config';
|
|
11
14
|
|
|
12
15
|
import { type P2PReqRespConfig, p2pReqRespConfigMappings } from './services/reqresp/config.js';
|
|
13
16
|
|
|
@@ -169,6 +172,9 @@ export interface P2PConfig extends P2PReqRespConfig, ChainConfig {
|
|
|
169
172
|
* The maximum possible size of the P2P DB in KB. Overwrites the general dataStoreMapSizeKB.
|
|
170
173
|
*/
|
|
171
174
|
p2pStoreMapSizeKb?: number;
|
|
175
|
+
|
|
176
|
+
/** Which calls are allowed in the public setup phase of a tx. */
|
|
177
|
+
txPublicSetupAllowList: AllowedElement[];
|
|
172
178
|
}
|
|
173
179
|
|
|
174
180
|
export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
@@ -341,6 +347,13 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
|
341
347
|
parseEnv: (val: string | undefined) => (val ? +val : undefined),
|
|
342
348
|
description: 'The maximum possible size of the P2P DB in KB. Overwrites the general dataStoreMapSizeKB.',
|
|
343
349
|
},
|
|
350
|
+
txPublicSetupAllowList: {
|
|
351
|
+
env: 'TX_PUBLIC_SETUP_ALLOWLIST',
|
|
352
|
+
parseEnv: (val: string) => parseAllowList(val),
|
|
353
|
+
description: 'The list of functions calls allowed to run in setup',
|
|
354
|
+
printDefault: () =>
|
|
355
|
+
'AuthRegistry, FeeJuice.increase_public_balance, Token.increase_public_balance, FPC.prepare_fee',
|
|
356
|
+
},
|
|
344
357
|
...p2pReqRespConfigMappings,
|
|
345
358
|
...chainConfigMappings,
|
|
346
359
|
};
|
|
@@ -383,3 +396,53 @@ export const bootnodeConfigMappings = pickConfigMappings(
|
|
|
383
396
|
{ ...p2pConfigMappings, ...dataConfigMappings, ...chainConfigMappings },
|
|
384
397
|
bootnodeConfigKeys,
|
|
385
398
|
);
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Parses a string to a list of allowed elements.
|
|
402
|
+
* Each encoded is expected to be of one of the following formats
|
|
403
|
+
* `I:${address}`
|
|
404
|
+
* `I:${address}:${selector}`
|
|
405
|
+
* `C:${classId}`
|
|
406
|
+
* `C:${classId}:${selector}`
|
|
407
|
+
*
|
|
408
|
+
* @param value The string to parse
|
|
409
|
+
* @returns A list of allowed elements
|
|
410
|
+
*/
|
|
411
|
+
export function parseAllowList(value: string): AllowedElement[] {
|
|
412
|
+
const entries: AllowedElement[] = [];
|
|
413
|
+
|
|
414
|
+
if (!value) {
|
|
415
|
+
return entries;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
for (const val of value.split(',')) {
|
|
419
|
+
const [typeString, identifierString, selectorString] = val.split(':');
|
|
420
|
+
const selector = selectorString !== undefined ? FunctionSelector.fromString(selectorString) : undefined;
|
|
421
|
+
|
|
422
|
+
if (typeString === 'I') {
|
|
423
|
+
if (selector) {
|
|
424
|
+
entries.push({
|
|
425
|
+
address: AztecAddress.fromString(identifierString),
|
|
426
|
+
selector,
|
|
427
|
+
});
|
|
428
|
+
} else {
|
|
429
|
+
entries.push({
|
|
430
|
+
address: AztecAddress.fromString(identifierString),
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
} else if (typeString === 'C') {
|
|
434
|
+
if (selector) {
|
|
435
|
+
entries.push({
|
|
436
|
+
classId: Fr.fromHexString(identifierString),
|
|
437
|
+
selector,
|
|
438
|
+
});
|
|
439
|
+
} else {
|
|
440
|
+
entries.push({
|
|
441
|
+
classId: Fr.fromHexString(identifierString),
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return entries;
|
|
448
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { FPCContract } from '@aztec/noir-contracts.js/FPC';
|
|
2
|
+
import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token';
|
|
3
|
+
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
4
|
+
import { getContractClassFromArtifact } from '@aztec/stdlib/contract';
|
|
5
|
+
import type { AllowedElement } from '@aztec/stdlib/interfaces/server';
|
|
6
|
+
|
|
7
|
+
let defaultAllowedSetupFunctions: AllowedElement[] | undefined = undefined;
|
|
8
|
+
export async function getDefaultAllowedSetupFunctions(): Promise<AllowedElement[]> {
|
|
9
|
+
if (defaultAllowedSetupFunctions === undefined) {
|
|
10
|
+
defaultAllowedSetupFunctions = [
|
|
11
|
+
// needed for authwit support
|
|
12
|
+
{
|
|
13
|
+
address: ProtocolContractAddress.AuthRegistry,
|
|
14
|
+
},
|
|
15
|
+
// needed for claiming on the same tx as a spend
|
|
16
|
+
{
|
|
17
|
+
address: ProtocolContractAddress.FeeJuice,
|
|
18
|
+
// We can't restrict the selector because public functions get routed via dispatch.
|
|
19
|
+
// selector: FunctionSelector.fromSignature('_increase_public_balance((Field),u128)'),
|
|
20
|
+
},
|
|
21
|
+
// needed for private transfers via FPC
|
|
22
|
+
{
|
|
23
|
+
classId: (await getContractClassFromArtifact(TokenContractArtifact)).id,
|
|
24
|
+
// We can't restrict the selector because public functions get routed via dispatch.
|
|
25
|
+
// selector: FunctionSelector.fromSignature('_increase_public_balance((Field),u128)'),
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
classId: (await getContractClassFromArtifact(FPCContract.artifact)).id,
|
|
29
|
+
// We can't restrict the selector because public functions get routed via dispatch.
|
|
30
|
+
// selector: FunctionSelector.fromSignature('prepare_fee((Field),Field,(Field),Field)'),
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
return defaultAllowedSetupFunctions;
|
|
35
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
2
|
+
import { computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
|
|
3
|
+
import { getCallRequestsWithCalldataByPhase } from '@aztec/simulator/server';
|
|
4
|
+
import { FunctionSelector } from '@aztec/stdlib/abi';
|
|
5
|
+
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
6
|
+
import type { GasFees } from '@aztec/stdlib/gas';
|
|
7
|
+
import type { PublicStateSource } from '@aztec/stdlib/trees';
|
|
8
|
+
import { type Tx, TxExecutionPhase, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
|
|
9
|
+
|
|
10
|
+
export class GasTxValidator implements TxValidator<Tx> {
|
|
11
|
+
#log = createLogger('sequencer:tx_validator:tx_gas');
|
|
12
|
+
#publicDataSource: PublicStateSource;
|
|
13
|
+
#feeJuiceAddress: AztecAddress;
|
|
14
|
+
#gasFees: GasFees;
|
|
15
|
+
|
|
16
|
+
constructor(publicDataSource: PublicStateSource, feeJuiceAddress: AztecAddress, gasFees: GasFees) {
|
|
17
|
+
this.#publicDataSource = publicDataSource;
|
|
18
|
+
this.#feeJuiceAddress = feeJuiceAddress;
|
|
19
|
+
this.#gasFees = gasFees;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async validateTx(tx: Tx): Promise<TxValidationResult> {
|
|
23
|
+
if (await this.#shouldSkip(tx)) {
|
|
24
|
+
return Promise.resolve({ result: 'skipped', reason: ['Insufficient fee per gas'] });
|
|
25
|
+
}
|
|
26
|
+
return this.#validateTxFee(tx);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Check whether the tx's max fees are valid for the current block, and skip if not.
|
|
31
|
+
* We skip instead of invalidating since the tx may become eligible later.
|
|
32
|
+
* Note that circuits check max fees even if fee payer is unset, so we
|
|
33
|
+
* keep this validation even if the tx does not pay fees.
|
|
34
|
+
*/
|
|
35
|
+
async #shouldSkip(tx: Tx): Promise<boolean> {
|
|
36
|
+
const gasSettings = tx.data.constants.txContext.gasSettings;
|
|
37
|
+
|
|
38
|
+
// Skip the tx if its max fees are not enough for the current block's gas fees.
|
|
39
|
+
const maxFeesPerGas = gasSettings.maxFeesPerGas;
|
|
40
|
+
const notEnoughMaxFees =
|
|
41
|
+
maxFeesPerGas.feePerDaGas.lt(this.#gasFees.feePerDaGas) ||
|
|
42
|
+
maxFeesPerGas.feePerL2Gas.lt(this.#gasFees.feePerL2Gas);
|
|
43
|
+
|
|
44
|
+
if (notEnoughMaxFees) {
|
|
45
|
+
this.#log.warn(`Skipping transaction ${await tx.getTxHash()} due to insufficient fee per gas`, {
|
|
46
|
+
txMaxFeesPerGas: maxFeesPerGas.toInspect(),
|
|
47
|
+
currentGasFees: this.#gasFees.toInspect(),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return notEnoughMaxFees;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async #validateTxFee(tx: Tx): Promise<TxValidationResult> {
|
|
54
|
+
const feePayer = tx.data.feePayer;
|
|
55
|
+
|
|
56
|
+
// Compute the maximum fee that this tx may pay, based on its gasLimits and maxFeePerGas
|
|
57
|
+
const feeLimit = tx.data.constants.txContext.gasSettings.getFeeLimit();
|
|
58
|
+
|
|
59
|
+
// Read current balance of the feePayer
|
|
60
|
+
const initialBalance = await this.#publicDataSource.storageRead(
|
|
61
|
+
this.#feeJuiceAddress,
|
|
62
|
+
await computeFeePayerBalanceStorageSlot(feePayer),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// If there is a claim in this tx that increases the fee payer balance in Fee Juice, add it to balance
|
|
66
|
+
const setupFns = getCallRequestsWithCalldataByPhase(tx, TxExecutionPhase.SETUP);
|
|
67
|
+
const increasePublicBalanceSelector = await FunctionSelector.fromSignature(
|
|
68
|
+
'_increase_public_balance((Field),u128)',
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// Arguments of the claim function call:
|
|
72
|
+
// - args[0]: Amount recipient.
|
|
73
|
+
// - args[1]: Amount being claimed.
|
|
74
|
+
const claimFunctionCall = setupFns.find(
|
|
75
|
+
fn =>
|
|
76
|
+
fn.request.contractAddress.equals(this.#feeJuiceAddress) &&
|
|
77
|
+
fn.request.msgSender.equals(this.#feeJuiceAddress) &&
|
|
78
|
+
fn.calldata.length > 2 &&
|
|
79
|
+
fn.functionSelector.equals(increasePublicBalanceSelector) &&
|
|
80
|
+
fn.args[0].equals(feePayer.toField()) &&
|
|
81
|
+
!fn.request.isStaticCall,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const balance = claimFunctionCall ? initialBalance.add(claimFunctionCall.args[1]) : initialBalance;
|
|
85
|
+
if (balance.lt(feeLimit)) {
|
|
86
|
+
this.#log.warn(`Rejecting transaction due to not enough fee payer balance`, {
|
|
87
|
+
feePayer,
|
|
88
|
+
balance: balance.toBigInt(),
|
|
89
|
+
feeLimit: feeLimit.toBigInt(),
|
|
90
|
+
});
|
|
91
|
+
return { result: 'invalid', reason: ['Insufficient fee payer balance'] };
|
|
92
|
+
}
|
|
93
|
+
return { result: 'valid' };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -4,3 +4,7 @@ export * from './double_spend_validator.js';
|
|
|
4
4
|
export * from './metadata_validator.js';
|
|
5
5
|
export * from './tx_proof_validator.js';
|
|
6
6
|
export * from './block_header_validator.js';
|
|
7
|
+
export * from './gas_validator.js';
|
|
8
|
+
export * from './phases_validator.js';
|
|
9
|
+
export * from './test_utils.js';
|
|
10
|
+
export * from './allowed_public_setup.js';
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
2
|
+
import { PublicContractsDB, getCallRequestsWithCalldataByPhase } from '@aztec/simulator/server';
|
|
3
|
+
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
4
|
+
import type { AllowedElement } from '@aztec/stdlib/interfaces/server';
|
|
5
|
+
import {
|
|
6
|
+
type PublicCallRequestWithCalldata,
|
|
7
|
+
Tx,
|
|
8
|
+
TxExecutionPhase,
|
|
9
|
+
type TxValidationResult,
|
|
10
|
+
type TxValidator,
|
|
11
|
+
} from '@aztec/stdlib/tx';
|
|
12
|
+
|
|
13
|
+
export class PhasesTxValidator implements TxValidator<Tx> {
|
|
14
|
+
#log = createLogger('sequencer:tx_validator:tx_phases');
|
|
15
|
+
private contractsDB: PublicContractsDB;
|
|
16
|
+
|
|
17
|
+
constructor(contracts: ContractDataSource, private setupAllowList: AllowedElement[], private blockNumber: number) {
|
|
18
|
+
this.contractsDB = new PublicContractsDB(contracts);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async validateTx(tx: Tx): Promise<TxValidationResult> {
|
|
22
|
+
try {
|
|
23
|
+
// TODO(@spalladino): We add this just to handle public authwit-check calls during setup
|
|
24
|
+
// which are needed for public FPC flows, but fail if the account contract hasnt been deployed yet,
|
|
25
|
+
// which is what we're trying to do as part of the current txs.
|
|
26
|
+
await this.contractsDB.addNewContracts(tx);
|
|
27
|
+
|
|
28
|
+
if (!tx.data.forPublic) {
|
|
29
|
+
this.#log.debug(
|
|
30
|
+
`Tx ${await Tx.getHash(tx)} does not contain enqueued public functions. Skipping phases validation.`,
|
|
31
|
+
);
|
|
32
|
+
return { result: 'valid' };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const setupFns = getCallRequestsWithCalldataByPhase(tx, TxExecutionPhase.SETUP);
|
|
36
|
+
for (const setupFn of setupFns) {
|
|
37
|
+
if (!(await this.isOnAllowList(setupFn, this.setupAllowList))) {
|
|
38
|
+
this.#log.warn(
|
|
39
|
+
`Rejecting tx ${await Tx.getHash(tx)} because it calls setup function not on allow list: ${
|
|
40
|
+
setupFn.request.contractAddress
|
|
41
|
+
}:${setupFn.functionSelector}`,
|
|
42
|
+
{ allowList: this.setupAllowList },
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
return { result: 'invalid', reason: ['Setup function not on allow list'] };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return { result: 'valid' };
|
|
50
|
+
} finally {
|
|
51
|
+
this.contractsDB.clearContractsForTx();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private async isOnAllowList(
|
|
56
|
+
publicCall: PublicCallRequestWithCalldata,
|
|
57
|
+
allowList: AllowedElement[],
|
|
58
|
+
): Promise<boolean> {
|
|
59
|
+
if (publicCall.isEmpty()) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const contractAddress = publicCall.request.contractAddress;
|
|
64
|
+
const functionSelector = publicCall.functionSelector;
|
|
65
|
+
|
|
66
|
+
// do these checks first since they don't require the contract class
|
|
67
|
+
for (const entry of allowList) {
|
|
68
|
+
if ('address' in entry && !('selector' in entry)) {
|
|
69
|
+
if (contractAddress.equals(entry.address)) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if ('address' in entry && 'selector' in entry) {
|
|
75
|
+
if (contractAddress.equals(entry.address) && entry.selector.equals(functionSelector)) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const contractClass = await this.contractsDB.getContractInstance(contractAddress, this.blockNumber);
|
|
81
|
+
|
|
82
|
+
if (!contractClass) {
|
|
83
|
+
throw new Error(`Contract not found: ${contractAddress}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if ('classId' in entry && !('selector' in entry)) {
|
|
87
|
+
if (contractClass.currentContractClassId.equals(entry.classId)) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if ('classId' in entry && 'selector' in entry) {
|
|
93
|
+
if (
|
|
94
|
+
contractClass.currentContractClassId.equals(entry.classId) &&
|
|
95
|
+
(entry.selector === undefined || entry.selector.equals(functionSelector))
|
|
96
|
+
) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Fr } from '@aztec/foundation/fields';
|
|
2
|
+
import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
3
|
+
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
4
|
+
import { HashedValues, type Tx } from '@aztec/stdlib/tx';
|
|
5
|
+
|
|
6
|
+
export function patchNonRevertibleFn(
|
|
7
|
+
tx: Tx,
|
|
8
|
+
index: number,
|
|
9
|
+
overrides: { address?: AztecAddress; selector: FunctionSelector; args?: Fr[]; msgSender?: AztecAddress },
|
|
10
|
+
): Promise<AztecAddress> {
|
|
11
|
+
return patchFn('nonRevertibleAccumulatedData', tx, index, overrides);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function patchRevertibleFn(
|
|
15
|
+
tx: Tx,
|
|
16
|
+
index: number,
|
|
17
|
+
overrides: { address?: AztecAddress; selector: FunctionSelector; args?: Fr[]; msgSender?: AztecAddress },
|
|
18
|
+
): Promise<AztecAddress> {
|
|
19
|
+
return patchFn('revertibleAccumulatedData', tx, index, overrides);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function patchFn(
|
|
23
|
+
where: 'revertibleAccumulatedData' | 'nonRevertibleAccumulatedData',
|
|
24
|
+
tx: Tx,
|
|
25
|
+
index: number,
|
|
26
|
+
overrides: { address?: AztecAddress; selector: FunctionSelector; args?: Fr[]; msgSender?: AztecAddress },
|
|
27
|
+
): Promise<AztecAddress> {
|
|
28
|
+
const calldataIndex =
|
|
29
|
+
where === 'nonRevertibleAccumulatedData'
|
|
30
|
+
? index
|
|
31
|
+
: index + tx.data.forPublic!.nonRevertibleAccumulatedData.publicCallRequests.length;
|
|
32
|
+
const calldata = [overrides.selector.toField(), ...(overrides.args ?? [])];
|
|
33
|
+
const hashedCalldata = await HashedValues.fromCalldata(calldata);
|
|
34
|
+
tx.publicFunctionCalldata[calldataIndex] = hashedCalldata;
|
|
35
|
+
|
|
36
|
+
const request = tx.data.forPublic![where].publicCallRequests[index];
|
|
37
|
+
request.contractAddress = overrides.address ?? request.contractAddress;
|
|
38
|
+
request.msgSender = overrides.msgSender ?? request.msgSender;
|
|
39
|
+
request.calldataHash = hashedCalldata.hash;
|
|
40
|
+
tx.data.forPublic![where].publicCallRequests[index] = request;
|
|
41
|
+
|
|
42
|
+
return request.contractAddress;
|
|
43
|
+
}
|