@aztec/p2p 0.83.1 → 0.84.0
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/services/peer-manager/peer_manager.d.ts +1 -1
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +14 -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/services/peer-manager/peer_manager.ts +19 -11
- 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
|
}
|
|
@@ -22,7 +22,7 @@ export declare class PeerManager {
|
|
|
22
22
|
private trustedPeers;
|
|
23
23
|
private trustedPeersInitialized;
|
|
24
24
|
private metrics;
|
|
25
|
-
private
|
|
25
|
+
private handlers;
|
|
26
26
|
constructor(libP2PNode: PubSubLibp2p, peerDiscoveryService: PeerDiscoveryService, config: P2PConfig, telemetryClient: TelemetryClient, logger: import("@aztec/foundation/log").Logger, peerScoring: PeerScoring, reqresp: ReqResp);
|
|
27
27
|
/**
|
|
28
28
|
* Initializes the trusted peers.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peer_manager.d.ts","sourceRoot":"","sources":["../../../src/services/peer-manager/peer_manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,eAAe,EAAa,MAAM,yBAAyB,CAAC;AAG1E,OAAO,KAAK,EAAc,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAI5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,aAAa,EAAuB,MAAM,iCAAiC,CAAC;AACrF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAoBrE,qBAAa,WAAW;
|
|
1
|
+
{"version":3,"file":"peer_manager.d.ts","sourceRoot":"","sources":["../../../src/services/peer-manager/peer_manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,eAAe,EAAa,MAAM,yBAAyB,CAAC;AAG1E,OAAO,KAAK,EAAc,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAI5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,aAAa,EAAuB,MAAM,iCAAiC,CAAC;AACrF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAoBrE,qBAAa,WAAW;IAgBpB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,oBAAoB;IAC5B,OAAO,CAAC,MAAM;IAEd,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,OAAO;IArBjB,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,8BAA8B,CAAa;IACnD,OAAO,CAAC,aAAa,CAAwC;IAC7D,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,uBAAuB,CAAkB;IAEjD,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,QAAQ,CAIF;gBAGJ,UAAU,EAAE,YAAY,EACxB,oBAAoB,EAAE,oBAAoB,EAC1C,MAAM,EAAE,SAAS,EACzB,eAAe,EAAE,eAAe,EACxB,MAAM,wCAAmC,EACzC,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,OAAO;IAwB1B;;;;OAIG;IACG,sBAAsB;IAU5B,IAAI,MAAM,6CAET;IAGM,SAAS;IAShB;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;IAU9B;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAShC;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IASnC;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IAQrB;;;OAGG;IACI,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAM3C;;;;;;OAMG;IACI,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa;IAQrD,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB;IAIvD,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAIpC,QAAQ,CAAC,cAAc,UAAQ,GAAG,QAAQ,EAAE;IAiCnD;;OAEG;IACH,OAAO,CAAC,QAAQ;IAiEhB,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,mBAAmB;IAwB3B;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAwBvB;;;;;;;;OAQG;IACH,OAAO,CAAC,mBAAmB;YAuBb,wBAAwB;YAcxB,cAAc;IAQ5B;;;OAGG;YACW,oBAAoB;YA8DpB,QAAQ;IA2BtB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,gBAAgB;IAsBxB;;;OAGG;IACU,IAAI;CAYlB"}
|
|
@@ -31,7 +31,7 @@ export class PeerManager {
|
|
|
31
31
|
trustedPeers;
|
|
32
32
|
trustedPeersInitialized;
|
|
33
33
|
metrics;
|
|
34
|
-
|
|
34
|
+
handlers;
|
|
35
35
|
constructor(libP2PNode, peerDiscoveryService, config, telemetryClient, logger = createLogger('p2p:peer-manager'), peerScoring, reqresp){
|
|
36
36
|
this.libP2PNode = libP2PNode;
|
|
37
37
|
this.peerDiscoveryService = peerDiscoveryService;
|
|
@@ -45,15 +45,20 @@ export class PeerManager {
|
|
|
45
45
|
this.timedOutPeers = new Map();
|
|
46
46
|
this.trustedPeers = new Set();
|
|
47
47
|
this.trustedPeersInitialized = false;
|
|
48
|
+
this.handlers = {};
|
|
48
49
|
this.metrics = new PeerManagerMetrics(telemetryClient, 'PeerManager');
|
|
50
|
+
// Handle Discovered peers
|
|
51
|
+
this.handlers = {
|
|
52
|
+
handleConnectedPeerEvent: this.handleConnectedPeerEvent.bind(this),
|
|
53
|
+
handleDisconnectedPeerEvent: this.handleDisconnectedPeerEvent.bind(this),
|
|
54
|
+
handleDiscoveredPeer: (enr)=>this.handleDiscoveredPeer(enr).catch((e)=>this.logger.error('Error handling discovered peer', e))
|
|
55
|
+
};
|
|
49
56
|
// Handle new established connections
|
|
50
|
-
this.libP2PNode.addEventListener(PeerEvent.CONNECTED, this.handleConnectedPeerEvent
|
|
57
|
+
this.libP2PNode.addEventListener(PeerEvent.CONNECTED, this.handlers.handleConnectedPeerEvent);
|
|
51
58
|
// Handle lost connections
|
|
52
|
-
this.libP2PNode.addEventListener(PeerEvent.DISCONNECTED, this.handleDisconnectedPeerEvent
|
|
53
|
-
// Handle Discovered peers
|
|
54
|
-
this.discoveredPeerHandler = (enr)=>this.handleDiscoveredPeer(enr).catch((e)=>this.logger.error('Error handling discovered peer', e));
|
|
59
|
+
this.libP2PNode.addEventListener(PeerEvent.DISCONNECTED, this.handlers.handleDisconnectedPeerEvent);
|
|
55
60
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
56
|
-
this.peerDiscoveryService.on(PeerEvent.DISCOVERED, this.
|
|
61
|
+
this.peerDiscoveryService.on(PeerEvent.DISCOVERED, this.handlers.handleDiscoveredPeer);
|
|
57
62
|
// Display peer counts every 60 seconds
|
|
58
63
|
this.displayPeerCountsPeerHeartbeat = Math.floor(60_000 / this.config.peerCheckIntervalMS);
|
|
59
64
|
}
|
|
@@ -447,11 +452,11 @@ export class PeerManager {
|
|
|
447
452
|
* Removing all event listeners.
|
|
448
453
|
*/ async stop() {
|
|
449
454
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
450
|
-
this.peerDiscoveryService.off(PeerEvent.DISCOVERED, this.
|
|
455
|
+
this.peerDiscoveryService.off(PeerEvent.DISCOVERED, this.handlers.handleDiscoveredPeer);
|
|
451
456
|
// Send goodbyes to all peers
|
|
452
457
|
await Promise.all(this.libP2PNode.getPeers().map((peer)=>this.goodbyeAndDisconnectPeer(peer, GoodByeReason.SHUTDOWN)));
|
|
453
|
-
this.libP2PNode.removeEventListener(PeerEvent.CONNECTED, this.handleConnectedPeerEvent);
|
|
454
|
-
this.libP2PNode.removeEventListener(PeerEvent.DISCONNECTED, this.handleDisconnectedPeerEvent);
|
|
458
|
+
this.libP2PNode.removeEventListener(PeerEvent.CONNECTED, this.handlers.handleConnectedPeerEvent);
|
|
459
|
+
this.libP2PNode.removeEventListener(PeerEvent.DISCONNECTED, this.handlers.handleDisconnectedPeerEvent);
|
|
455
460
|
}
|
|
456
461
|
}
|
|
457
462
|
_ts_decorate([
|
|
@@ -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.
|
|
3
|
+
"version": "0.84.0",
|
|
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.
|
|
69
|
-
"@aztec/epoch-cache": "0.
|
|
70
|
-
"@aztec/foundation": "0.
|
|
71
|
-
"@aztec/kv-store": "0.
|
|
72
|
-
"@aztec/noir-
|
|
73
|
-
"@aztec/protocol-
|
|
74
|
-
"@aztec/
|
|
75
|
-
"@aztec/
|
|
68
|
+
"@aztec/constants": "0.84.0",
|
|
69
|
+
"@aztec/epoch-cache": "0.84.0",
|
|
70
|
+
"@aztec/foundation": "0.84.0",
|
|
71
|
+
"@aztec/kv-store": "0.84.0",
|
|
72
|
+
"@aztec/noir-contracts.js": "0.84.0",
|
|
73
|
+
"@aztec/noir-protocol-circuits-types": "0.84.0",
|
|
74
|
+
"@aztec/protocol-contracts": "0.84.0",
|
|
75
|
+
"@aztec/simulator": "0.84.0",
|
|
76
|
+
"@aztec/stdlib": "0.84.0",
|
|
77
|
+
"@aztec/telemetry-client": "0.84.0",
|
|
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.
|
|
106
|
+
"@aztec/archiver": "0.84.0",
|
|
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';
|