@aztec/p2p 0.0.1-commit.033589e → 0.0.1-commit.04852196a
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 -2
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +2 -1
- package/dest/client/p2p_client.d.ts +1 -1
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +0 -24
- package/dest/config.d.ts +12 -2
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +46 -7
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +7 -1
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +8 -6
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +2 -2
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +3 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.js +2 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +17 -9
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +26 -9
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +26 -43
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +2 -1
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +5 -4
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +5 -4
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +12 -9
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +46 -44
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +1 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/allowed_public_setup.js +21 -32
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
- package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
- package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
- package/dest/msg_validators/tx_validator/index.d.ts +2 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +1 -0
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
- package/dest/msg_validators/tx_validator/phases_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +21 -1
- 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 +11 -10
- package/dest/test-helpers/make-test-p2p-clients.d.ts +1 -1
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +2 -1
- package/dest/testbench/worker_client_manager.d.ts +3 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +6 -2
- package/dest/util.d.ts +1 -1
- package/package.json +14 -14
- package/src/client/factory.ts +2 -1
- package/src/client/p2p_client.ts +0 -22
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +1 -1
- package/src/config.ts +59 -4
- package/src/mem_pools/tx_pool_v2/README.md +9 -1
- package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +11 -1
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +15 -6
- package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +2 -1
- package/src/mem_pools/tx_pool_v2/interfaces.ts +3 -0
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +41 -11
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +29 -43
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +3 -1
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +13 -3
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +19 -6
- package/src/msg_validators/proposal_validator/proposal_validator.ts +57 -48
- package/src/msg_validators/tx_validator/allowed_public_setup.ts +16 -35
- package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
- package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
- package/src/msg_validators/tx_validator/index.ts +1 -0
- package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
- package/src/msg_validators/tx_validator/phases_validator.ts +29 -0
- package/src/services/libp2p/libp2p_service.ts +11 -9
- package/src/test-helpers/make-test-p2p-clients.ts +1 -1
- package/src/test-helpers/reqresp-nodes.ts +1 -1
- package/src/testbench/p2p_client_testbench_worker.ts +2 -1
- package/src/testbench/worker_client_manager.ts +13 -5
- package/src/util.ts +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -24
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -378
- package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -373
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { insertIntoSortedArray, removeFromSortedArray } from '@aztec/foundation/array';
|
|
1
2
|
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import type { L2BlockId } from '@aztec/stdlib/block';
|
|
3
4
|
|
|
4
|
-
import { type
|
|
5
|
+
import { type PriorityComparable, type TxMetaData, type TxState, comparePriority } from './tx_metadata.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Manages in-memory indices for the transaction pool.
|
|
@@ -22,8 +23,8 @@ export class TxPoolIndices {
|
|
|
22
23
|
#nullifierToTxHash: Map<string, string> = new Map();
|
|
23
24
|
/** Fee payer to txHashes index (pending txs only) */
|
|
24
25
|
#feePayerToTxHashes: Map<string, Set<string>> = new Map();
|
|
25
|
-
/** Pending
|
|
26
|
-
#pendingByPriority:
|
|
26
|
+
/** Pending transactions sorted ascending by priority fee, ties broken by txHash */
|
|
27
|
+
#pendingByPriority: PriorityComparable[] = [];
|
|
27
28
|
/** Protected transactions: txHash -> slotNumber */
|
|
28
29
|
#protectedTransactions: Map<string, SlotNumber> = new Map();
|
|
29
30
|
|
|
@@ -73,20 +74,14 @@ export class TxPoolIndices {
|
|
|
73
74
|
* @param order - 'desc' for highest priority first, 'asc' for lowest priority first
|
|
74
75
|
*/
|
|
75
76
|
*iteratePendingByPriority(order: 'asc' | 'desc', filter?: (hash: string) => boolean): Generator<string> {
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const sortedHashes = [...hashesAtFee].sort(hashCompareFn);
|
|
85
|
-
for (const hashBigInt of sortedHashes) {
|
|
86
|
-
const hash = txHashFromBigInt(hashBigInt);
|
|
87
|
-
if (filter === undefined || filter(hash)) {
|
|
88
|
-
yield hash;
|
|
89
|
-
}
|
|
77
|
+
const arr = this.#pendingByPriority;
|
|
78
|
+
const start = order === 'asc' ? 0 : arr.length - 1;
|
|
79
|
+
const step = order === 'asc' ? 1 : -1;
|
|
80
|
+
const inBounds = order === 'asc' ? (i: number) => i < arr.length : (i: number) => i >= 0;
|
|
81
|
+
|
|
82
|
+
for (let i = start; inBounds(i); i += step) {
|
|
83
|
+
if (filter === undefined || filter(arr[i].txHash)) {
|
|
84
|
+
yield arr[i].txHash;
|
|
90
85
|
}
|
|
91
86
|
}
|
|
92
87
|
}
|
|
@@ -227,11 +222,7 @@ export class TxPoolIndices {
|
|
|
227
222
|
|
|
228
223
|
/** Gets the count of pending transactions */
|
|
229
224
|
getPendingTxCount(): number {
|
|
230
|
-
|
|
231
|
-
for (const hashes of this.#pendingByPriority.values()) {
|
|
232
|
-
count += hashes.size;
|
|
233
|
-
}
|
|
234
|
-
return count;
|
|
225
|
+
return this.#pendingByPriority.length;
|
|
235
226
|
}
|
|
236
227
|
|
|
237
228
|
/** Gets the lowest priority pending transaction hashes (up to limit) */
|
|
@@ -264,12 +255,10 @@ export class TxPoolIndices {
|
|
|
264
255
|
/** Gets all pending transactions */
|
|
265
256
|
getPendingTxs(): TxMetaData[] {
|
|
266
257
|
const result: TxMetaData[] = [];
|
|
267
|
-
for (const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
result.push(meta);
|
|
272
|
-
}
|
|
258
|
+
for (const entry of this.#pendingByPriority) {
|
|
259
|
+
const meta = this.#metadata.get(entry.txHash);
|
|
260
|
+
if (meta) {
|
|
261
|
+
result.push(meta);
|
|
273
262
|
}
|
|
274
263
|
}
|
|
275
264
|
return result;
|
|
@@ -408,13 +397,12 @@ export class TxPoolIndices {
|
|
|
408
397
|
}
|
|
409
398
|
feePayerSet.add(meta.txHash);
|
|
410
399
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
prioritySet.add(meta.txHashBigInt);
|
|
400
|
+
insertIntoSortedArray(
|
|
401
|
+
this.#pendingByPriority,
|
|
402
|
+
{ txHash: meta.txHash, priorityFee: meta.priorityFee, txHashBigInt: meta.txHashBigInt },
|
|
403
|
+
comparePriority,
|
|
404
|
+
false,
|
|
405
|
+
);
|
|
418
406
|
}
|
|
419
407
|
|
|
420
408
|
#removeFromPendingIndices(meta: TxMetaData): void {
|
|
@@ -432,13 +420,11 @@ export class TxPoolIndices {
|
|
|
432
420
|
}
|
|
433
421
|
}
|
|
434
422
|
|
|
435
|
-
// Remove from priority
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
}
|
|
442
|
-
}
|
|
423
|
+
// Remove from priority array
|
|
424
|
+
removeFromSortedArray(
|
|
425
|
+
this.#pendingByPriority,
|
|
426
|
+
{ txHash: meta.txHash, priorityFee: meta.priorityFee, txHashBigInt: meta.txHashBigInt },
|
|
427
|
+
comparePriority,
|
|
428
|
+
);
|
|
443
429
|
}
|
|
444
430
|
}
|
|
@@ -214,7 +214,9 @@ export class TxPoolV2Impl {
|
|
|
214
214
|
// in-memory reads, and buffered DB writes. Nothing here can throw an unhandled exception.
|
|
215
215
|
const poolAccess = this.#createPreAddPoolAccess();
|
|
216
216
|
const preAddContext: PreAddContext | undefined =
|
|
217
|
-
opts.feeComparisonOnly !== undefined
|
|
217
|
+
opts.feeComparisonOnly !== undefined
|
|
218
|
+
? { feeComparisonOnly: opts.feeComparisonOnly, priceBumpPercentage: this.#config.priceBumpPercentage }
|
|
219
|
+
: undefined;
|
|
218
220
|
|
|
219
221
|
await this.#store.transactionAsync(async () => {
|
|
220
222
|
for (const tx of txs) {
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import type { BlockProposal, P2PValidator } from '@aztec/stdlib/p2p';
|
|
2
|
+
import type { BlockProposal, P2PValidator, ValidationResult } from '@aztec/stdlib/p2p';
|
|
3
3
|
|
|
4
4
|
import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
|
|
5
5
|
|
|
6
|
-
export class BlockProposalValidator
|
|
6
|
+
export class BlockProposalValidator implements P2PValidator<BlockProposal> {
|
|
7
|
+
private proposalValidator: ProposalValidator;
|
|
8
|
+
|
|
7
9
|
constructor(epochCache: EpochCacheInterface, opts: { txsPermitted: boolean; maxTxsPerBlock?: number }) {
|
|
8
|
-
|
|
10
|
+
this.proposalValidator = new ProposalValidator(epochCache, opts, 'p2p:block_proposal_validator');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async validate(proposal: BlockProposal): Promise<ValidationResult> {
|
|
14
|
+
const headerResult = await this.proposalValidator.validate(proposal);
|
|
15
|
+
if (headerResult.result !== 'accept') {
|
|
16
|
+
return headerResult;
|
|
17
|
+
}
|
|
18
|
+
return this.proposalValidator.validateTxs(proposal);
|
|
9
19
|
}
|
|
10
20
|
}
|
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
|
-
import type { CheckpointProposal, P2PValidator } from '@aztec/stdlib/p2p';
|
|
2
|
+
import type { CheckpointProposal, P2PValidator, ValidationResult } from '@aztec/stdlib/p2p';
|
|
3
3
|
|
|
4
4
|
import { ProposalValidator } from '../proposal_validator/proposal_validator.js';
|
|
5
5
|
|
|
6
|
-
export class CheckpointProposalValidator
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
{
|
|
6
|
+
export class CheckpointProposalValidator implements P2PValidator<CheckpointProposal> {
|
|
7
|
+
private proposalValidator: ProposalValidator;
|
|
8
|
+
|
|
10
9
|
constructor(epochCache: EpochCacheInterface, opts: { txsPermitted: boolean; maxTxsPerBlock?: number }) {
|
|
11
|
-
|
|
10
|
+
this.proposalValidator = new ProposalValidator(epochCache, opts, 'p2p:checkpoint_proposal_validator');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async validate(proposal: CheckpointProposal): Promise<ValidationResult> {
|
|
14
|
+
const headerResult = await this.proposalValidator.validate(proposal);
|
|
15
|
+
if (headerResult.result !== 'accept') {
|
|
16
|
+
return headerResult;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const blockProposal = proposal.getBlockProposal();
|
|
20
|
+
if (blockProposal) {
|
|
21
|
+
return this.proposalValidator.validateTxs(blockProposal);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return { result: 'accept' };
|
|
12
25
|
}
|
|
13
26
|
}
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
2
|
import { NoCommitteeError } from '@aztec/ethereum/contracts';
|
|
3
3
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
type BlockProposal,
|
|
6
|
+
type CheckpointProposalCore,
|
|
7
|
+
PeerErrorSeverity,
|
|
8
|
+
type ValidationResult,
|
|
9
|
+
} from '@aztec/stdlib/p2p';
|
|
5
10
|
|
|
6
11
|
import { isWithinClockTolerance } from '../clock_tolerance.js';
|
|
7
12
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
/** Validates header-level and tx-level fields of block and checkpoint proposals. */
|
|
14
|
+
export class ProposalValidator {
|
|
15
|
+
private epochCache: EpochCacheInterface;
|
|
16
|
+
private logger: Logger;
|
|
17
|
+
private txsPermitted: boolean;
|
|
18
|
+
private maxTxsPerBlock?: number;
|
|
13
19
|
|
|
14
20
|
constructor(
|
|
15
21
|
epochCache: EpochCacheInterface,
|
|
@@ -22,7 +28,8 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
|
|
|
22
28
|
this.logger = createLogger(loggerName);
|
|
23
29
|
}
|
|
24
30
|
|
|
25
|
-
|
|
31
|
+
/** Validates header-level fields: slot, signature, and proposer. */
|
|
32
|
+
public async validate(proposal: BlockProposal | CheckpointProposalCore): Promise<ValidationResult> {
|
|
26
33
|
try {
|
|
27
34
|
// Slot check
|
|
28
35
|
const { currentSlot, nextSlot } = this.epochCache.getCurrentAndNextSlot();
|
|
@@ -44,38 +51,6 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
|
|
|
44
51
|
return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
|
|
45
52
|
}
|
|
46
53
|
|
|
47
|
-
// Transactions permitted check
|
|
48
|
-
const embeddedTxCount = proposal.txs?.length ?? 0;
|
|
49
|
-
if (!this.txsPermitted && (proposal.txHashes.length > 0 || embeddedTxCount > 0)) {
|
|
50
|
-
this.logger.warn(
|
|
51
|
-
`Penalizing peer for proposal with ${proposal.txHashes.length} transaction(s) when transactions are not permitted`,
|
|
52
|
-
);
|
|
53
|
-
return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Max txs per block check
|
|
57
|
-
if (this.maxTxsPerBlock !== undefined && proposal.txHashes.length > this.maxTxsPerBlock) {
|
|
58
|
-
this.logger.warn(
|
|
59
|
-
`Penalizing peer for proposal with ${proposal.txHashes.length} transaction(s) when max is ${this.maxTxsPerBlock}`,
|
|
60
|
-
);
|
|
61
|
-
return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Embedded txs must be listed in txHashes
|
|
65
|
-
const hashSet = new Set(proposal.txHashes.map(h => h.toString()));
|
|
66
|
-
const missingTxHashes =
|
|
67
|
-
embeddedTxCount > 0
|
|
68
|
-
? proposal.txs!.filter(tx => !hashSet.has(tx.getTxHash().toString())).map(tx => tx.getTxHash().toString())
|
|
69
|
-
: [];
|
|
70
|
-
if (embeddedTxCount > 0 && missingTxHashes.length > 0) {
|
|
71
|
-
this.logger.warn('Penalizing peer for embedded transaction(s) not included in txHashes', {
|
|
72
|
-
embeddedTxCount,
|
|
73
|
-
txHashesLength: proposal.txHashes.length,
|
|
74
|
-
missingTxHashes,
|
|
75
|
-
});
|
|
76
|
-
return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
54
|
// Proposer check
|
|
80
55
|
const expectedProposer = await this.epochCache.getProposerAttesterAddressInSlot(slotNumber);
|
|
81
56
|
if (expectedProposer !== undefined && !proposer.equals(expectedProposer)) {
|
|
@@ -86,15 +61,6 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
|
|
|
86
61
|
return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
|
|
87
62
|
}
|
|
88
63
|
|
|
89
|
-
// Validate tx hashes for all txs embedded in the proposal
|
|
90
|
-
if (!(await Promise.all(proposal.txs?.map(tx => tx.validateTxHash()) ?? [])).every(v => v)) {
|
|
91
|
-
this.logger.warn(`Penalizing peer for invalid tx hashes in proposal`, {
|
|
92
|
-
proposer,
|
|
93
|
-
slotNumber,
|
|
94
|
-
});
|
|
95
|
-
return { result: 'reject', severity: PeerErrorSeverity.LowToleranceError };
|
|
96
|
-
}
|
|
97
|
-
|
|
98
64
|
return { result: 'accept' };
|
|
99
65
|
} catch (e) {
|
|
100
66
|
if (e instanceof NoCommitteeError) {
|
|
@@ -103,4 +69,47 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
|
|
|
103
69
|
throw e;
|
|
104
70
|
}
|
|
105
71
|
}
|
|
72
|
+
|
|
73
|
+
/** Validates transaction-related fields of a block proposal. */
|
|
74
|
+
public async validateTxs(proposal: BlockProposal): Promise<ValidationResult> {
|
|
75
|
+
// Transactions permitted check
|
|
76
|
+
const embeddedTxCount = proposal.txs?.length ?? 0;
|
|
77
|
+
if (!this.txsPermitted && (proposal.txHashes.length > 0 || embeddedTxCount > 0)) {
|
|
78
|
+
this.logger.warn(
|
|
79
|
+
`Penalizing peer for proposal with ${proposal.txHashes.length} transaction(s) when transactions are not permitted`,
|
|
80
|
+
);
|
|
81
|
+
return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Max txs per block check
|
|
85
|
+
if (this.maxTxsPerBlock !== undefined && proposal.txHashes.length > this.maxTxsPerBlock) {
|
|
86
|
+
this.logger.warn(
|
|
87
|
+
`Penalizing peer for proposal with ${proposal.txHashes.length} transaction(s) when max is ${this.maxTxsPerBlock}`,
|
|
88
|
+
);
|
|
89
|
+
return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Embedded txs must be listed in txHashes
|
|
93
|
+
const hashSet = new Set(proposal.txHashes.map(h => h.toString()));
|
|
94
|
+
const missingTxHashes =
|
|
95
|
+
embeddedTxCount > 0
|
|
96
|
+
? proposal.txs!.filter(tx => !hashSet.has(tx.getTxHash().toString())).map(tx => tx.getTxHash().toString())
|
|
97
|
+
: [];
|
|
98
|
+
if (embeddedTxCount > 0 && missingTxHashes.length > 0) {
|
|
99
|
+
this.logger.warn('Penalizing peer for embedded transaction(s) not included in txHashes', {
|
|
100
|
+
embeddedTxCount,
|
|
101
|
+
txHashesLength: proposal.txHashes.length,
|
|
102
|
+
missingTxHashes,
|
|
103
|
+
});
|
|
104
|
+
return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Validate tx hashes for all txs embedded in the proposal
|
|
108
|
+
if (!(await Promise.all(proposal.txs?.map(tx => tx.validateTxHash()) ?? [])).every(v => v)) {
|
|
109
|
+
this.logger.warn(`Penalizing peer for invalid tx hashes in proposal`);
|
|
110
|
+
return { result: 'reject', severity: PeerErrorSeverity.LowToleranceError };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return { result: 'accept' };
|
|
114
|
+
}
|
|
106
115
|
}
|
|
@@ -1,49 +1,30 @@
|
|
|
1
|
-
import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token';
|
|
2
1
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { AuthRegistryArtifact } from '@aztec/protocol-contracts/auth-registry';
|
|
3
|
+
import { FeeJuiceArtifact } from '@aztec/protocol-contracts/fee-juice';
|
|
5
4
|
import type { AllowedElement } from '@aztec/stdlib/interfaces/server';
|
|
6
5
|
|
|
6
|
+
import { buildAllowedElement } from './allowed_setup_helpers.js';
|
|
7
|
+
|
|
7
8
|
let defaultAllowedSetupFunctions: AllowedElement[] | undefined;
|
|
8
9
|
|
|
9
10
|
/** Returns the default list of functions allowed to run in the setup phase of a transaction. */
|
|
10
11
|
export async function getDefaultAllowedSetupFunctions(): Promise<AllowedElement[]> {
|
|
11
12
|
if (defaultAllowedSetupFunctions === undefined) {
|
|
12
|
-
|
|
13
|
-
const setAuthorizedInternalSelector = await FunctionSelector.fromSignature('_set_authorized((Field),Field,bool)');
|
|
14
|
-
const setAuthorizedSelector = await FunctionSelector.fromSignature('set_authorized(Field,bool)');
|
|
15
|
-
const increaseBalanceSelector = await FunctionSelector.fromSignature('_increase_public_balance((Field),u128)');
|
|
16
|
-
const transferInPublicSelector = await FunctionSelector.fromSignature(
|
|
17
|
-
'transfer_in_public((Field),(Field),u128,Field)',
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
defaultAllowedSetupFunctions = [
|
|
13
|
+
defaultAllowedSetupFunctions = await Promise.all([
|
|
21
14
|
// AuthRegistry: needed for authwit support via private path (set_authorized_private enqueues _set_authorized)
|
|
22
|
-
{
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
},
|
|
15
|
+
buildAllowedElement(AuthRegistryArtifact, { address: ProtocolContractAddress.AuthRegistry }, '_set_authorized', {
|
|
16
|
+
onlySelf: true,
|
|
17
|
+
rejectNullMsgSender: true,
|
|
18
|
+
}),
|
|
26
19
|
// AuthRegistry: needed for authwit support via public path (PublicFeePaymentMethod calls set_authorized directly)
|
|
27
|
-
{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
},
|
|
20
|
+
buildAllowedElement(AuthRegistryArtifact, { address: ProtocolContractAddress.AuthRegistry }, 'set_authorized', {
|
|
21
|
+
rejectNullMsgSender: true,
|
|
22
|
+
}),
|
|
31
23
|
// FeeJuice: needed for claiming on the same tx as a spend (claim_and_end_setup enqueues this)
|
|
32
|
-
{
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// Token: needed for private transfers via FPC (transfer_to_public enqueues this)
|
|
37
|
-
{
|
|
38
|
-
classId: tokenClassId,
|
|
39
|
-
selector: increaseBalanceSelector,
|
|
40
|
-
},
|
|
41
|
-
// Token: needed for public transfers via FPC (fee_entrypoint_public enqueues this)
|
|
42
|
-
{
|
|
43
|
-
classId: tokenClassId,
|
|
44
|
-
selector: transferInPublicSelector,
|
|
45
|
-
},
|
|
46
|
-
];
|
|
24
|
+
buildAllowedElement(FeeJuiceArtifact, { address: ProtocolContractAddress.FeeJuice }, '_increase_public_balance', {
|
|
25
|
+
onlySelf: true,
|
|
26
|
+
}),
|
|
27
|
+
]);
|
|
47
28
|
}
|
|
48
29
|
return defaultAllowedSetupFunctions;
|
|
49
30
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
|
+
import { FunctionSelector, countArgumentsSize, getAllFunctionAbis } from '@aztec/stdlib/abi';
|
|
3
|
+
import type { ContractArtifact } from '@aztec/stdlib/abi';
|
|
4
|
+
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
5
|
+
import type { AllowedElement } from '@aztec/stdlib/interfaces/server';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Builds an AllowedElement from a contract artifact, deriving both the function selector
|
|
9
|
+
* and calldata length from the artifact instead of hardcoding signature strings.
|
|
10
|
+
*/
|
|
11
|
+
export async function buildAllowedElement(
|
|
12
|
+
artifact: ContractArtifact,
|
|
13
|
+
target: { address: AztecAddress } | { classId: Fr },
|
|
14
|
+
functionName: string,
|
|
15
|
+
opts?: { onlySelf?: boolean; rejectNullMsgSender?: boolean },
|
|
16
|
+
): Promise<AllowedElement> {
|
|
17
|
+
const allFunctions = getAllFunctionAbis(artifact);
|
|
18
|
+
const fn = allFunctions.find(f => f.name === functionName);
|
|
19
|
+
if (!fn) {
|
|
20
|
+
throw new Error(`Unknown function ${functionName} in artifact ${artifact.name}`);
|
|
21
|
+
}
|
|
22
|
+
const selector = await FunctionSelector.fromNameAndParameters(fn.name, fn.parameters);
|
|
23
|
+
const calldataLength = 1 + countArgumentsSize(fn);
|
|
24
|
+
return {
|
|
25
|
+
...target,
|
|
26
|
+
selector,
|
|
27
|
+
calldataLength,
|
|
28
|
+
...(opts?.onlySelf ? { onlySelf: true } : {}),
|
|
29
|
+
...(opts?.rejectNullMsgSender ? { rejectNullMsgSender: true } : {}),
|
|
30
|
+
} as AllowedElement;
|
|
31
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { FeeJuiceArtifact } from '@aztec/protocol-contracts/fee-juice';
|
|
1
2
|
import { getCallRequestsWithCalldataByPhase } from '@aztec/simulator/server';
|
|
2
|
-
import { FunctionSelector } from '@aztec/stdlib/abi';
|
|
3
|
+
import { FunctionSelector, getAllFunctionAbis } from '@aztec/stdlib/abi';
|
|
3
4
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
4
5
|
import { type Tx, TxExecutionPhase } from '@aztec/stdlib/tx';
|
|
5
6
|
|
|
@@ -8,7 +9,10 @@ export type FeePayerBalanceDelta = {
|
|
|
8
9
|
claimAmount: bigint;
|
|
9
10
|
};
|
|
10
11
|
|
|
11
|
-
const increasePublicBalanceSelectorPromise =
|
|
12
|
+
const increasePublicBalanceSelectorPromise = (() => {
|
|
13
|
+
const fn = getAllFunctionAbis(FeeJuiceArtifact).find(f => f.name === '_increase_public_balance')!;
|
|
14
|
+
return FunctionSelector.fromNameAndParameters(fn.name, fn.parameters);
|
|
15
|
+
})();
|
|
12
16
|
|
|
13
17
|
export function getTxFeeLimit(tx: Tx): bigint {
|
|
14
18
|
return tx.data.constants.txContext.gasSettings.getFeeLimit().toBigInt();
|
|
@@ -8,6 +8,7 @@ export * from './gas_validator.js';
|
|
|
8
8
|
export * from './phases_validator.js';
|
|
9
9
|
export * from './test_utils.js';
|
|
10
10
|
export * from './allowed_public_setup.js';
|
|
11
|
+
export * from './allowed_setup_helpers.js';
|
|
11
12
|
export * from './archive_cache.js';
|
|
12
13
|
export * from './tx_permitted_validator.js';
|
|
13
14
|
export * from './timestamp_validator.js';
|
|
@@ -28,16 +28,24 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
|
|
|
28
28
|
validateTx(tx: T): Promise<TxValidationResult> {
|
|
29
29
|
const errors = [];
|
|
30
30
|
if (!this.#hasCorrectL1ChainId(tx)) {
|
|
31
|
-
errors.push(
|
|
31
|
+
errors.push(
|
|
32
|
+
`${TX_ERROR_INCORRECT_L1_CHAIN_ID} (tx: ${tx.data.constants.txContext.chainId.toNumber()}, expected: ${this.values.l1ChainId.toNumber()})`,
|
|
33
|
+
);
|
|
32
34
|
}
|
|
33
35
|
if (!this.#hasCorrectRollupVersion(tx)) {
|
|
34
|
-
errors.push(
|
|
36
|
+
errors.push(
|
|
37
|
+
`${TX_ERROR_INCORRECT_ROLLUP_VERSION} (tx: ${tx.data.constants.txContext.version.toNumber()}, expected: ${this.values.rollupVersion.toNumber()})`,
|
|
38
|
+
);
|
|
35
39
|
}
|
|
36
40
|
if (!this.#hasCorrectVkTreeRoot(tx)) {
|
|
37
|
-
errors.push(
|
|
41
|
+
errors.push(
|
|
42
|
+
`${TX_ERROR_INCORRECT_VK_TREE_ROOT} (tx: ${tx.data.constants.vkTreeRoot.toString()}, expected: ${this.values.vkTreeRoot.toString()})`,
|
|
43
|
+
);
|
|
38
44
|
}
|
|
39
45
|
if (!this.#hasCorrectprotocolContractsHash(tx)) {
|
|
40
|
-
errors.push(
|
|
46
|
+
errors.push(
|
|
47
|
+
`${TX_ERROR_INCORRECT_PROTOCOL_CONTRACTS_HASH} (tx: ${tx.data.constants.protocolContractsHash.toString()}, expected: ${this.values.protocolContractsHash.toString()})`,
|
|
48
|
+
);
|
|
41
49
|
}
|
|
42
50
|
return Promise.resolve(errors.length > 0 ? { result: 'invalid', reason: errors } : { result: 'valid' });
|
|
43
51
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { NULL_MSG_SENDER_CONTRACT_ADDRESS } from '@aztec/constants';
|
|
1
2
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
2
3
|
import { PublicContractsDB, getCallRequestsWithCalldataByPhase } from '@aztec/simulator/server';
|
|
4
|
+
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
3
5
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
4
6
|
import type { AllowedElement } from '@aztec/stdlib/interfaces/server';
|
|
5
7
|
import {
|
|
@@ -7,6 +9,9 @@ import {
|
|
|
7
9
|
TX_ERROR_DURING_VALIDATION,
|
|
8
10
|
TX_ERROR_SETUP_FUNCTION_NOT_ALLOWED,
|
|
9
11
|
TX_ERROR_SETUP_FUNCTION_UNKNOWN_CONTRACT,
|
|
12
|
+
TX_ERROR_SETUP_NULL_MSG_SENDER,
|
|
13
|
+
TX_ERROR_SETUP_ONLY_SELF_WRONG_SENDER,
|
|
14
|
+
TX_ERROR_SETUP_WRONG_CALLDATA_LENGTH,
|
|
10
15
|
Tx,
|
|
11
16
|
TxExecutionPhase,
|
|
12
17
|
type TxValidationResult,
|
|
@@ -84,6 +89,18 @@ export class PhasesTxValidator implements TxValidator<Tx> {
|
|
|
84
89
|
for (const entry of allowList) {
|
|
85
90
|
if ('address' in entry) {
|
|
86
91
|
if (contractAddress.equals(entry.address) && entry.selector.equals(functionSelector)) {
|
|
92
|
+
if (entry.calldataLength !== undefined && publicCall.calldata.length !== entry.calldataLength) {
|
|
93
|
+
return TX_ERROR_SETUP_WRONG_CALLDATA_LENGTH;
|
|
94
|
+
}
|
|
95
|
+
if (entry.onlySelf && !publicCall.request.msgSender.equals(contractAddress)) {
|
|
96
|
+
return TX_ERROR_SETUP_ONLY_SELF_WRONG_SENDER;
|
|
97
|
+
}
|
|
98
|
+
if (
|
|
99
|
+
entry.rejectNullMsgSender &&
|
|
100
|
+
publicCall.request.msgSender.equals(AztecAddress.fromBigInt(NULL_MSG_SENDER_CONTRACT_ADDRESS))
|
|
101
|
+
) {
|
|
102
|
+
return TX_ERROR_SETUP_NULL_MSG_SENDER;
|
|
103
|
+
}
|
|
87
104
|
return undefined;
|
|
88
105
|
}
|
|
89
106
|
}
|
|
@@ -105,6 +122,18 @@ export class PhasesTxValidator implements TxValidator<Tx> {
|
|
|
105
122
|
}
|
|
106
123
|
|
|
107
124
|
if (contractClassId.value === entry.classId.toString() && entry.selector.equals(functionSelector)) {
|
|
125
|
+
if (entry.calldataLength !== undefined && publicCall.calldata.length !== entry.calldataLength) {
|
|
126
|
+
return TX_ERROR_SETUP_WRONG_CALLDATA_LENGTH;
|
|
127
|
+
}
|
|
128
|
+
if (entry.onlySelf && !publicCall.request.msgSender.equals(contractAddress)) {
|
|
129
|
+
return TX_ERROR_SETUP_ONLY_SELF_WRONG_SENDER;
|
|
130
|
+
}
|
|
131
|
+
if (
|
|
132
|
+
entry.rejectNullMsgSender &&
|
|
133
|
+
publicCall.request.msgSender.equals(AztecAddress.fromBigInt(NULL_MSG_SENDER_CONTRACT_ADDRESS))
|
|
134
|
+
) {
|
|
135
|
+
return TX_ERROR_SETUP_NULL_MSG_SENDER;
|
|
136
|
+
}
|
|
108
137
|
return undefined;
|
|
109
138
|
}
|
|
110
139
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
2
2
|
import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { maxBy } from '@aztec/foundation/collection';
|
|
3
4
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
5
|
import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
|
|
5
6
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
@@ -19,6 +20,7 @@ import {
|
|
|
19
20
|
P2PMessage,
|
|
20
21
|
type ValidationResult as P2PValidationResult,
|
|
21
22
|
PeerErrorSeverity,
|
|
23
|
+
PeerErrorSeverityByHarshness,
|
|
22
24
|
TopicType,
|
|
23
25
|
createTopicString,
|
|
24
26
|
getTopicsForConfig,
|
|
@@ -222,14 +224,12 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
222
224
|
this.protocolVersion,
|
|
223
225
|
);
|
|
224
226
|
|
|
225
|
-
|
|
227
|
+
const proposalValidatorOpts = {
|
|
226
228
|
txsPermitted: !config.disableTransactions,
|
|
227
|
-
maxTxsPerBlock: config.
|
|
228
|
-
}
|
|
229
|
-
this.
|
|
230
|
-
|
|
231
|
-
maxTxsPerBlock: config.maxTxsPerBlock,
|
|
232
|
-
});
|
|
229
|
+
maxTxsPerBlock: config.validateMaxTxsPerBlock,
|
|
230
|
+
};
|
|
231
|
+
this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
|
|
232
|
+
this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
|
|
233
233
|
this.checkpointAttestationValidator = config.fishermanMode
|
|
234
234
|
? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
|
|
235
235
|
: new CheckpointAttestationValidator(epochCache);
|
|
@@ -1664,8 +1664,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
1664
1664
|
|
|
1665
1665
|
// A promise that resolves when all validations have been run
|
|
1666
1666
|
const allValidations = await Promise.all(validationPromises);
|
|
1667
|
-
const
|
|
1668
|
-
if (
|
|
1667
|
+
const failures = allValidations.filter(x => !x.isValid);
|
|
1668
|
+
if (failures.length > 0) {
|
|
1669
|
+
// Pick the most severe failure (lowest tolerance = harshest penalty)
|
|
1670
|
+
const failed = maxBy(failures, f => PeerErrorSeverityByHarshness.indexOf(f.severity))!;
|
|
1669
1671
|
return {
|
|
1670
1672
|
allPassed: false,
|
|
1671
1673
|
failure: {
|
|
@@ -4,9 +4,9 @@ import { SecretValue } from '@aztec/foundation/config';
|
|
|
4
4
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
5
5
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
6
6
|
import { sleep } from '@aztec/foundation/sleep';
|
|
7
|
-
import type { DataStoreConfig } from '@aztec/kv-store/config';
|
|
8
7
|
import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
|
|
9
8
|
import type { WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
9
|
+
import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
|
|
10
10
|
|
|
11
11
|
import { createP2PClient } from '../client/index.js';
|
|
12
12
|
import type { P2PClient } from '../client/p2p_client.js';
|
|
@@ -2,7 +2,6 @@ import type { EpochCache } from '@aztec/epoch-cache';
|
|
|
2
2
|
import { timesParallel } from '@aztec/foundation/collection';
|
|
3
3
|
import { SecretValue } from '@aztec/foundation/config';
|
|
4
4
|
import { createLogger } from '@aztec/foundation/log';
|
|
5
|
-
import type { DataStoreConfig } from '@aztec/kv-store/config';
|
|
6
5
|
import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
|
|
7
6
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
8
7
|
import { type ChainConfig, emptyChainConfig } from '@aztec/stdlib/config';
|
|
@@ -12,6 +11,7 @@ import type {
|
|
|
12
11
|
IVCProofVerificationResult,
|
|
13
12
|
WorldStateSynchronizer,
|
|
14
13
|
} from '@aztec/stdlib/interfaces/server';
|
|
14
|
+
import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
|
|
15
15
|
import type { Tx } from '@aztec/stdlib/tx';
|
|
16
16
|
import { compressComponentVersions } from '@aztec/stdlib/versioning';
|
|
17
17
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
@@ -12,13 +12,13 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
12
12
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
13
13
|
import { sleep } from '@aztec/foundation/sleep';
|
|
14
14
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
15
|
-
import type { DataStoreConfig } from '@aztec/kv-store/config';
|
|
16
15
|
import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
|
|
17
16
|
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
18
17
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
19
18
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
20
19
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
21
20
|
import type { ClientProtocolCircuitVerifier, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
21
|
+
import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
|
|
22
22
|
import { type BlockProposal, P2PMessage } from '@aztec/stdlib/p2p';
|
|
23
23
|
import { ChonkProof } from '@aztec/stdlib/proofs';
|
|
24
24
|
import { makeAztecAddress, makeBlockHeader, makeBlockProposal, mockTx } from '@aztec/stdlib/testing';
|
|
@@ -340,6 +340,7 @@ process.on('message', async msg => {
|
|
|
340
340
|
const config: P2PConfig = {
|
|
341
341
|
...rawConfig,
|
|
342
342
|
peerIdPrivateKey: rawConfig.peerIdPrivateKey ? new SecretValue(rawConfig.peerIdPrivateKey) : undefined,
|
|
343
|
+
priceBumpPercentage: 10n,
|
|
343
344
|
} as P2PConfig;
|
|
344
345
|
|
|
345
346
|
workerConfig = config;
|