@aztec/p2p 0.0.1-commit.aada20e3 → 0.0.1-commit.b2a5d0dd1
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/README.md +129 -3
- package/dest/client/factory.d.ts +12 -11
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +55 -16
- package/dest/client/interface.d.ts +54 -34
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +41 -52
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +179 -226
- package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +24 -11
- package/dest/config.d.ts +133 -92
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +109 -40
- package/dest/errors/p2p-service.error.d.ts +9 -0
- package/dest/errors/p2p-service.error.d.ts.map +1 -0
- package/dest/errors/p2p-service.error.js +10 -0
- package/dest/errors/tx-pool.error.d.ts +8 -0
- package/dest/errors/tx-pool.error.d.ts.map +1 -0
- package/dest/errors/tx-pool.error.js +9 -0
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +106 -88
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.js +448 -3
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +2 -2
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +353 -87
- package/dest/mem_pools/attestation_pool/index.d.ts +2 -3
- package/dest/mem_pools/attestation_pool/index.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/index.js +1 -2
- package/dest/mem_pools/attestation_pool/mocks.d.ts +2 -2
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +2 -2
- package/dest/mem_pools/index.d.ts +3 -3
- package/dest/mem_pools/index.d.ts.map +1 -1
- package/dest/mem_pools/index.js +1 -1
- package/dest/mem_pools/instrumentation.d.ts +4 -2
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +16 -14
- package/dest/mem_pools/interface.d.ts +5 -5
- package/dest/mem_pools/interface.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +104 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/deleted_pool.js +251 -0
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +3 -3
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +18 -9
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +7 -3
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +3 -3
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +12 -4
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +3 -2
- package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/index.js +2 -1
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +62 -0
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +54 -5
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +8 -0
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +7 -5
- package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +9 -7
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +14 -6
- package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +4 -4
- 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 +16 -4
- package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +3 -3
- 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 +3 -3
- package/dest/mem_pools/tx_pool_v2/index.d.ts +3 -2
- package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/index.js +2 -1
- package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts +15 -0
- package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/instrumentation.js +43 -0
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +37 -12
- package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/interfaces.js +5 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +81 -15
- package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_metadata.js +147 -18
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +108 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +337 -0
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +12 -5
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +23 -6
- package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +14 -5
- 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 +477 -594
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +5 -2
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +20 -11
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +5 -3
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +2 -2
- package/dest/msg_validators/clock_tolerance.d.ts +12 -1
- package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
- package/dest/msg_validators/clock_tolerance.js +54 -3
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +7 -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 +7 -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 +15 -8
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/proposal_validator/proposal_validator.js +67 -47
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +4 -4
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +3 -3
- package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -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 +24 -20
- 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/archive_cache.js +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts +16 -3
- package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.js +1 -1
- package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
- package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
- package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/data_validator.js +35 -2
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +13 -3
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.js +4 -4
- package/dest/msg_validators/tx_validator/factory.d.ts +133 -6
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/factory.js +247 -60
- 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/gas_validator.d.ts +99 -3
- package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/gas_validator.js +137 -53
- package/dest/msg_validators/tx_validator/index.d.ts +3 -1
- package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/index.js +2 -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/nullifier_cache.d.ts +14 -0
- package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
- package/dest/msg_validators/tx_validator/phases_validator.d.ts +22 -2
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +72 -24
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +20 -4
- package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/timestamp_validator.js +6 -6
- package/dest/services/data_store.d.ts +1 -1
- package/dest/services/data_store.d.ts.map +1 -1
- package/dest/services/data_store.js +5 -5
- package/dest/services/dummy_service.d.ts +17 -6
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +16 -5
- package/dest/services/encoding.d.ts +7 -3
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +18 -11
- package/dest/services/gossipsub/index.d.ts +3 -0
- package/dest/services/gossipsub/index.d.ts.map +1 -0
- package/dest/services/gossipsub/index.js +2 -0
- package/dest/services/gossipsub/scoring.d.ts +21 -3
- package/dest/services/gossipsub/scoring.d.ts.map +1 -1
- package/dest/services/gossipsub/scoring.js +24 -7
- package/dest/services/gossipsub/topic_score_params.d.ts +184 -0
- package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -0
- package/dest/services/gossipsub/topic_score_params.js +363 -0
- package/dest/services/libp2p/instrumentation.d.ts +3 -1
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
- package/dest/services/libp2p/instrumentation.js +14 -0
- package/dest/services/libp2p/libp2p_service.d.ts +95 -51
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +566 -442
- package/dest/services/peer-manager/metrics.d.ts +3 -1
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/metrics.js +6 -0
- package/dest/services/peer-manager/peer_manager.d.ts +6 -2
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +39 -11
- package/dest/services/peer-manager/peer_scoring.d.ts +7 -2
- package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_scoring.js +57 -12
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +14 -10
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +89 -112
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts +4 -7
- package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +11 -13
- package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/missing_txs.js +31 -46
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +19 -11
- package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
- package/dest/services/reqresp/batch-tx-requester/peer_collection.js +52 -15
- package/dest/services/reqresp/batch-tx-requester/tx_validator.js +2 -2
- package/dest/services/reqresp/config.d.ts +3 -3
- package/dest/services/reqresp/config.d.ts.map +1 -1
- package/dest/services/reqresp/interface.d.ts +23 -9
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/interface.js +23 -10
- package/dest/services/reqresp/metrics.d.ts +1 -1
- package/dest/services/reqresp/metrics.d.ts.map +1 -1
- package/dest/services/reqresp/metrics.js +0 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +7 -5
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +16 -11
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +21 -10
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +27 -11
- package/dest/services/reqresp/protocols/index.d.ts +1 -2
- package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/index.js +0 -1
- package/dest/services/reqresp/protocols/tx.d.ts +7 -1
- package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/tx.js +21 -3
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limits.js +0 -10
- package/dest/services/reqresp/reqresp.d.ts +4 -2
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +40 -15
- package/dest/services/service.d.ts +43 -4
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/config.d.ts +22 -4
- package/dest/services/tx_collection/config.d.ts.map +1 -1
- package/dest/services/tx_collection/config.js +49 -3
- package/dest/services/tx_collection/fast_tx_collection.d.ts +6 -8
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +88 -88
- package/dest/services/tx_collection/file_store_tx_collection.d.ts +53 -0
- package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -0
- package/dest/services/tx_collection/file_store_tx_collection.js +167 -0
- package/dest/services/tx_collection/file_store_tx_source.d.ts +38 -0
- package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -0
- package/dest/services/tx_collection/file_store_tx_source.js +100 -0
- package/dest/services/tx_collection/index.d.ts +3 -2
- package/dest/services/tx_collection/index.d.ts.map +1 -1
- package/dest/services/tx_collection/index.js +1 -0
- package/dest/services/tx_collection/instrumentation.d.ts +1 -1
- package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
- package/dest/services/tx_collection/instrumentation.js +2 -1
- package/dest/services/tx_collection/proposal_tx_collector.d.ts +15 -15
- package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
- package/dest/services/tx_collection/proposal_tx_collector.js +6 -6
- package/dest/services/tx_collection/request_tracker.d.ts +53 -0
- package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
- package/dest/services/tx_collection/request_tracker.js +84 -0
- package/dest/services/tx_collection/slow_tx_collection.d.ts +7 -3
- package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/slow_tx_collection.js +60 -26
- package/dest/services/tx_collection/tx_collection.d.ts +23 -13
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.js +75 -3
- package/dest/services/tx_collection/tx_collection_sink.d.ts +18 -8
- package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection_sink.js +26 -29
- package/dest/services/tx_collection/tx_source.d.ts +13 -7
- package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_source.js +26 -7
- package/dest/services/tx_file_store/config.d.ts +1 -3
- package/dest/services/tx_file_store/config.d.ts.map +1 -1
- package/dest/services/tx_file_store/config.js +0 -4
- package/dest/services/tx_file_store/tx_file_store.d.ts +4 -3
- package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
- package/dest/services/tx_file_store/tx_file_store.js +9 -6
- package/dest/services/tx_provider.d.ts +4 -4
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider.js +9 -8
- package/dest/test-helpers/make-test-p2p-clients.d.ts +7 -8
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +4 -2
- package/dest/test-helpers/mock-pubsub.d.ts +40 -6
- package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
- package/dest/test-helpers/mock-pubsub.js +139 -13
- package/dest/test-helpers/reqresp-nodes.d.ts +2 -3
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +8 -5
- package/dest/test-helpers/testbench-utils.d.ts +43 -38
- package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
- package/dest/test-helpers/testbench-utils.js +150 -61
- package/dest/testbench/p2p_client_testbench_worker.d.ts +2 -2
- package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +85 -28
- package/dest/testbench/worker_client_manager.d.ts +10 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +55 -3
- package/dest/util.d.ts +3 -3
- package/dest/util.d.ts.map +1 -1
- package/package.json +14 -14
- package/src/client/factory.ts +110 -29
- package/src/client/interface.ts +65 -35
- package/src/client/p2p_client.ts +216 -272
- package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +36 -15
- package/src/config.ts +172 -46
- package/src/errors/p2p-service.error.ts +11 -0
- package/src/errors/tx-pool.error.ts +12 -0
- package/src/index.ts +1 -1
- package/src/mem_pools/attestation_pool/attestation_pool.ts +501 -91
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +442 -102
- package/src/mem_pools/attestation_pool/index.ts +9 -2
- package/src/mem_pools/attestation_pool/mocks.ts +2 -1
- package/src/mem_pools/index.ts +2 -2
- package/src/mem_pools/instrumentation.ts +17 -13
- package/src/mem_pools/interface.ts +4 -4
- package/src/mem_pools/tx_pool_v2/README.md +112 -17
- package/src/mem_pools/tx_pool_v2/deleted_pool.ts +321 -0
- package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +21 -8
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +7 -3
- package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +18 -4
- package/src/mem_pools/tx_pool_v2/eviction/index.ts +5 -0
- package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +65 -0
- package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +59 -4
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +5 -5
- package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +8 -8
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +14 -9
- package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +33 -6
- package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +4 -3
- package/src/mem_pools/tx_pool_v2/index.ts +2 -1
- package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
- package/src/mem_pools/tx_pool_v2/interfaces.ts +37 -12
- package/src/mem_pools/tx_pool_v2/tx_metadata.ts +215 -26
- package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +430 -0
- package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +37 -8
- package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +520 -678
- package/src/msg_validators/attestation_validator/README.md +49 -0
- package/src/msg_validators/attestation_validator/attestation_validator.ts +21 -9
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +6 -3
- package/src/msg_validators/clock_tolerance.ts +72 -3
- package/src/msg_validators/proposal_validator/README.md +123 -0
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +17 -4
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +23 -7
- package/src/msg_validators/proposal_validator/proposal_validator.ts +79 -49
- package/src/msg_validators/tx_validator/README.md +127 -0
- package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +5 -5
- package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
- package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
- package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
- package/src/msg_validators/tx_validator/block_header_validator.ts +15 -3
- package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
- package/src/msg_validators/tx_validator/data_validator.ts +42 -1
- package/src/msg_validators/tx_validator/double_spend_validator.ts +11 -6
- package/src/msg_validators/tx_validator/factory.ts +396 -78
- package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
- package/src/msg_validators/tx_validator/gas_validator.ts +199 -54
- package/src/msg_validators/tx_validator/index.ts +2 -0
- package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
- package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
- package/src/msg_validators/tx_validator/phases_validator.ts +82 -27
- package/src/msg_validators/tx_validator/timestamp_validator.ts +23 -18
- package/src/services/data_store.ts +5 -13
- package/src/services/dummy_service.ts +25 -7
- package/src/services/encoding.ts +18 -10
- package/src/services/gossipsub/README.md +641 -0
- package/src/services/gossipsub/index.ts +2 -0
- package/src/services/gossipsub/scoring.ts +29 -5
- package/src/services/gossipsub/topic_score_params.ts +519 -0
- package/src/services/libp2p/instrumentation.ts +14 -0
- package/src/services/libp2p/libp2p_service.ts +593 -477
- package/src/services/peer-manager/metrics.ts +7 -0
- package/src/services/peer-manager/peer_manager.ts +45 -11
- package/src/services/peer-manager/peer_scoring.ts +52 -5
- package/src/services/reqresp/README.md +229 -0
- package/src/services/reqresp/batch-tx-requester/README.md +53 -14
- package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +89 -122
- package/src/services/reqresp/batch-tx-requester/interface.ts +3 -6
- package/src/services/reqresp/batch-tx-requester/missing_txs.ts +30 -71
- package/src/services/reqresp/batch-tx-requester/peer_collection.ts +68 -24
- package/src/services/reqresp/batch-tx-requester/tx_validator.ts +2 -2
- package/src/services/reqresp/config.ts +2 -2
- package/src/services/reqresp/interface.ts +45 -10
- package/src/services/reqresp/metrics.ts +0 -1
- package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +23 -14
- package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +38 -15
- package/src/services/reqresp/protocols/index.ts +0 -1
- package/src/services/reqresp/protocols/tx.ts +23 -3
- package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
- package/src/services/reqresp/rate-limiter/rate_limits.ts +0 -10
- package/src/services/reqresp/reqresp.ts +53 -16
- package/src/services/service.ts +57 -3
- package/src/services/tx_collection/config.ts +74 -6
- package/src/services/tx_collection/fast_tx_collection.ts +94 -97
- package/src/services/tx_collection/file_store_tx_collection.ts +202 -0
- package/src/services/tx_collection/file_store_tx_source.ts +129 -0
- package/src/services/tx_collection/index.ts +2 -1
- package/src/services/tx_collection/instrumentation.ts +7 -1
- package/src/services/tx_collection/proposal_tx_collector.ts +21 -27
- package/src/services/tx_collection/request_tracker.ts +127 -0
- package/src/services/tx_collection/slow_tx_collection.ts +66 -33
- package/src/services/tx_collection/tx_collection.ts +114 -19
- package/src/services/tx_collection/tx_collection_sink.ts +30 -34
- package/src/services/tx_collection/tx_source.ts +28 -8
- package/src/services/tx_file_store/config.ts +0 -6
- package/src/services/tx_file_store/tx_file_store.ts +10 -8
- package/src/services/tx_provider.ts +10 -9
- package/src/test-helpers/make-test-p2p-clients.ts +6 -6
- package/src/test-helpers/mock-pubsub.ts +180 -14
- package/src/test-helpers/reqresp-nodes.ts +9 -9
- package/src/test-helpers/testbench-utils.ts +157 -74
- package/src/testbench/p2p_client_testbench_worker.ts +94 -31
- package/src/testbench/worker_client_manager.ts +68 -6
- package/src/util.ts +8 -2
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +0 -40
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +0 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +0 -218
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +0 -31
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +0 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +0 -180
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -122
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
- package/dest/mem_pools/tx_pool/index.d.ts +0 -3
- package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/index.js +0 -2
- package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
- package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/priority.js +0 -15
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -400
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -23
- 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 -212
- package/dest/services/reqresp/protocols/block.d.ts +0 -9
- package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
- package/dest/services/reqresp/protocols/block.js +0 -32
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +0 -320
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +0 -264
- package/src/mem_pools/tx_pool/README.md +0 -270
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
- package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
- package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
- package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -162
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
- package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
- package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
- package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
- package/src/mem_pools/tx_pool/index.ts +0 -2
- package/src/mem_pools/tx_pool/priority.ts +0 -20
- package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -319
- package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -230
- package/src/services/reqresp/protocols/block.ts +0 -37
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
1
|
+
import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import type { Logger } from '@aztec/foundation/log';
|
|
3
|
+
import type { DateProvider } from '@aztec/foundation/timer';
|
|
3
4
|
import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
|
|
4
5
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
5
6
|
import { computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
|
|
@@ -8,20 +9,27 @@ import type { L2Block, L2BlockId, L2BlockSource } from '@aztec/stdlib/block';
|
|
|
8
9
|
import type { WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
9
10
|
import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
|
|
10
11
|
import { BlockHeader, Tx, TxHash, type TxValidator } from '@aztec/stdlib/tx';
|
|
12
|
+
import type { TelemetryClient } from '@aztec/telemetry-client';
|
|
11
13
|
|
|
12
14
|
import { TxArchive } from './archive/index.js';
|
|
15
|
+
import { DeletedPool } from './deleted_pool.js';
|
|
13
16
|
import {
|
|
14
17
|
EvictionManager,
|
|
15
18
|
FeePayerBalanceEvictionRule,
|
|
16
19
|
FeePayerBalancePreAddRule,
|
|
20
|
+
InsufficientFeePerGasEvictionRule,
|
|
17
21
|
InvalidTxsAfterMiningRule,
|
|
18
22
|
InvalidTxsAfterReorgRule,
|
|
19
23
|
LowPriorityEvictionRule,
|
|
20
24
|
LowPriorityPreAddRule,
|
|
21
25
|
NullifierConflictRule,
|
|
22
26
|
type PoolOperations,
|
|
27
|
+
type PreAddContext,
|
|
23
28
|
type PreAddPoolAccess,
|
|
29
|
+
TxPoolRejectionCode,
|
|
30
|
+
type TxPoolRejectionError,
|
|
24
31
|
} from './eviction/index.js';
|
|
32
|
+
import { TxPoolV2Instrumentation } from './instrumentation.js';
|
|
25
33
|
import {
|
|
26
34
|
type AddTxsResult,
|
|
27
35
|
DEFAULT_TX_POOL_V2_CONFIG,
|
|
@@ -29,14 +37,8 @@ import {
|
|
|
29
37
|
type TxPoolV2Config,
|
|
30
38
|
type TxPoolV2Dependencies,
|
|
31
39
|
} from './interfaces.js';
|
|
32
|
-
import {
|
|
33
|
-
|
|
34
|
-
type TxState,
|
|
35
|
-
buildTxMetaData,
|
|
36
|
-
checkNullifierConflict,
|
|
37
|
-
compareFee,
|
|
38
|
-
compareTxHash,
|
|
39
|
-
} from './tx_metadata.js';
|
|
40
|
+
import { type TxMetaData, type TxState, buildTxMetaData, checkNullifierConflict } from './tx_metadata.js';
|
|
41
|
+
import { TxPoolIndices } from './tx_pool_indices.js';
|
|
40
42
|
|
|
41
43
|
/**
|
|
42
44
|
* Callbacks for the implementation to notify the outer class about events and metrics.
|
|
@@ -44,6 +46,7 @@ import {
|
|
|
44
46
|
export interface TxPoolV2Callbacks {
|
|
45
47
|
onTxsAdded: (txs: Tx[], opts: { source?: string }) => void;
|
|
46
48
|
onTxsRemoved: (txHashes: string[] | bigint[]) => void;
|
|
49
|
+
onTxsMined: (txHashes: string[]) => void;
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
/**
|
|
@@ -59,27 +62,20 @@ export class TxPoolV2Impl {
|
|
|
59
62
|
// === Dependencies ===
|
|
60
63
|
#l2BlockSource: L2BlockSource;
|
|
61
64
|
#worldStateSynchronizer: WorldStateSynchronizer;
|
|
62
|
-
#
|
|
65
|
+
#createTxValidator: TxPoolV2Dependencies['createTxValidator'];
|
|
66
|
+
#checkAllowedSetupCalls: TxPoolV2Dependencies['checkAllowedSetupCalls'];
|
|
63
67
|
|
|
64
68
|
// === In-Memory Indices ===
|
|
65
|
-
|
|
66
|
-
#metadata: Map<string, TxMetaData> = new Map();
|
|
67
|
-
/** Nullifier to txHash index (pending txs only) */
|
|
68
|
-
#nullifierToTxHash: Map<string, string> = new Map();
|
|
69
|
-
/** Fee payer to txHashes index (pending txs only) */
|
|
70
|
-
#feePayerToTxHashes: Map<string, Set<string>> = new Map();
|
|
71
|
-
/**
|
|
72
|
-
* Pending txHashes grouped by priority fee.
|
|
73
|
-
* Outer map: priorityFee -> Set of txHashes at that fee level.
|
|
74
|
-
*/
|
|
75
|
-
#pendingByPriority: Map<bigint, Set<string>> = new Map();
|
|
76
|
-
/** Protected transactions: txHash -> slotNumber. Includes txs we have and txs we expect to receive. */
|
|
77
|
-
#protectedTransactions: Map<string, SlotNumber> = new Map();
|
|
69
|
+
#indices: TxPoolIndices = new TxPoolIndices();
|
|
78
70
|
|
|
79
71
|
// === Config & Services ===
|
|
80
72
|
#config: TxPoolV2Config;
|
|
81
73
|
#archive: TxArchive;
|
|
74
|
+
#deletedPool: DeletedPool;
|
|
82
75
|
#evictionManager: EvictionManager;
|
|
76
|
+
#dateProvider: DateProvider;
|
|
77
|
+
#instrumentation: TxPoolV2Instrumentation;
|
|
78
|
+
#evictedTxHashes: Set<string> = new Set();
|
|
83
79
|
#log: Logger;
|
|
84
80
|
#callbacks: TxPoolV2Callbacks;
|
|
85
81
|
|
|
@@ -88,7 +84,9 @@ export class TxPoolV2Impl {
|
|
|
88
84
|
archiveStore: AztecAsyncKVStore,
|
|
89
85
|
deps: TxPoolV2Dependencies,
|
|
90
86
|
callbacks: TxPoolV2Callbacks,
|
|
87
|
+
telemetry: TelemetryClient,
|
|
91
88
|
config: Partial<TxPoolV2Config> = {},
|
|
89
|
+
dateProvider: DateProvider,
|
|
92
90
|
log: Logger,
|
|
93
91
|
) {
|
|
94
92
|
this.#store = store;
|
|
@@ -96,10 +94,14 @@ export class TxPoolV2Impl {
|
|
|
96
94
|
|
|
97
95
|
this.#l2BlockSource = deps.l2BlockSource;
|
|
98
96
|
this.#worldStateSynchronizer = deps.worldStateSynchronizer;
|
|
99
|
-
this.#
|
|
97
|
+
this.#createTxValidator = deps.createTxValidator;
|
|
98
|
+
this.#checkAllowedSetupCalls = deps.checkAllowedSetupCalls;
|
|
100
99
|
|
|
101
100
|
this.#config = { ...DEFAULT_TX_POOL_V2_CONFIG, ...config };
|
|
102
101
|
this.#archive = new TxArchive(archiveStore, this.#config.archivedTxLimit, log);
|
|
102
|
+
this.#deletedPool = new DeletedPool(store, this.#txsDB, log);
|
|
103
|
+
this.#dateProvider = dateProvider;
|
|
104
|
+
this.#instrumentation = new TxPoolV2Instrumentation(telemetry, () => this.#indices.getTotalMetadataBytes());
|
|
103
105
|
this.#log = log;
|
|
104
106
|
this.#callbacks = callbacks;
|
|
105
107
|
|
|
@@ -115,6 +117,7 @@ export class TxPoolV2Impl {
|
|
|
115
117
|
|
|
116
118
|
// Post-event eviction rules (run after events to check ALL pending txs)
|
|
117
119
|
this.#evictionManager.registerRule(new InvalidTxsAfterMiningRule());
|
|
120
|
+
this.#evictionManager.registerRule(new InsufficientFeePerGasEvictionRule(deps.blockMinFeesProvider));
|
|
118
121
|
this.#evictionManager.registerRule(new InvalidTxsAfterReorgRule(deps.worldStateSynchronizer));
|
|
119
122
|
this.#evictionManager.registerRule(new FeePayerBalanceEvictionRule(deps.worldStateSynchronizer));
|
|
120
123
|
// LowPriorityEvictionRule handles cases where txs become pending via prepareForSlot (unprotect)
|
|
@@ -134,26 +137,42 @@ export class TxPoolV2Impl {
|
|
|
134
137
|
* by running pre-add rules to resolve nullifier conflicts, balance checks, and pool size limits.
|
|
135
138
|
*/
|
|
136
139
|
async hydrateFromDatabase(): Promise<void> {
|
|
137
|
-
// Step
|
|
140
|
+
// Step 0: Hydrate deleted pool state
|
|
141
|
+
await this.#deletedPool.hydrateFromDatabase();
|
|
142
|
+
|
|
143
|
+
// Step 1: Load all transactions from DB (excluding soft-deleted)
|
|
138
144
|
const { loaded, errors: deserializationErrors } = await this.#loadAllTxsFromDb();
|
|
139
145
|
|
|
140
146
|
// Step 2: Check mined status for each tx
|
|
141
147
|
await this.#markMinedStatusBatch(loaded.map(l => l.meta));
|
|
142
148
|
|
|
143
149
|
// Step 3: Partition by mined status
|
|
144
|
-
const
|
|
150
|
+
const mined: TxMetaData[] = [];
|
|
151
|
+
const nonMined: { tx: Tx; meta: TxMetaData }[] = [];
|
|
152
|
+
for (const entry of loaded) {
|
|
153
|
+
if (entry.meta.minedL2BlockId !== undefined) {
|
|
154
|
+
mined.push(entry.meta);
|
|
155
|
+
} else {
|
|
156
|
+
nonMined.push(entry);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
145
159
|
|
|
146
160
|
// Step 4: Validate non-mined transactions
|
|
147
|
-
const { valid, invalid } = await this.#
|
|
161
|
+
const { valid, invalid } = await this.#revalidateMetadata(
|
|
162
|
+
nonMined.map(e => e.meta),
|
|
163
|
+
'on startup',
|
|
164
|
+
);
|
|
148
165
|
|
|
149
166
|
// Step 5: Populate mined indices (these don't need conflict resolution)
|
|
150
|
-
|
|
167
|
+
for (const meta of mined) {
|
|
168
|
+
this.#indices.addMined(meta);
|
|
169
|
+
}
|
|
151
170
|
|
|
152
171
|
// Step 6: Rebuild pending pool by running pre-add rules for each tx
|
|
153
172
|
// This resolves nullifier conflicts, fee payer balance issues, and pool size limits
|
|
154
173
|
const { rejected } = await this.#rebuildPendingPool(valid);
|
|
155
174
|
|
|
156
|
-
// Step 7: Delete invalid and rejected txs from DB
|
|
175
|
+
// Step 7: Delete invalid and rejected txs from DB only (indices were never populated for these)
|
|
157
176
|
const toDelete = [...deserializationErrors, ...invalid, ...rejected];
|
|
158
177
|
if (toDelete.length === 0) {
|
|
159
178
|
return;
|
|
@@ -163,17 +182,45 @@ export class TxPoolV2Impl {
|
|
|
163
182
|
await this.#txsDB.delete(txHashStr);
|
|
164
183
|
}
|
|
165
184
|
});
|
|
166
|
-
this.#log.info(`Deleted ${toDelete.length} invalid/rejected transactions on startup
|
|
185
|
+
this.#log.info(`Deleted ${toDelete.length} invalid/rejected transactions on startup`, { txHashes: toDelete });
|
|
167
186
|
}
|
|
168
187
|
|
|
169
|
-
async addPendingTxs(txs: Tx[], opts: { source?: string }): Promise<AddTxsResult> {
|
|
188
|
+
async addPendingTxs(txs: Tx[], opts: { source?: string; feeComparisonOnly?: boolean }): Promise<AddTxsResult> {
|
|
170
189
|
const accepted: TxHash[] = [];
|
|
171
190
|
const ignored: TxHash[] = [];
|
|
172
191
|
const rejected: TxHash[] = [];
|
|
173
|
-
const
|
|
192
|
+
const errors = new Map<string, TxPoolRejectionError>();
|
|
174
193
|
const acceptedPending = new Set<string>();
|
|
175
194
|
|
|
195
|
+
// Phase 1: Pre-compute all throwable I/O outside the transaction.
|
|
196
|
+
// If any pre-computation throws, the entire call fails before mutations happen.
|
|
197
|
+
const precomputed = new Map<string, { meta: TxMetaData; minedBlockId: L2BlockId | undefined; isValid: boolean }>();
|
|
198
|
+
|
|
199
|
+
const validator = await this.#createTxValidator();
|
|
200
|
+
|
|
201
|
+
for (const tx of txs) {
|
|
202
|
+
const txHash = tx.getTxHash();
|
|
203
|
+
const txHashStr = txHash.toString();
|
|
204
|
+
|
|
205
|
+
const meta = await buildTxMetaData(tx);
|
|
206
|
+
const minedBlockId = await this.#getMinedBlockId(txHash);
|
|
207
|
+
|
|
208
|
+
// Validate non-mined txs (mined and pre-protected txs bypass validation inside the transaction)
|
|
209
|
+
let isValid = true;
|
|
210
|
+
if (!minedBlockId) {
|
|
211
|
+
isValid = await this.#validateMeta(meta, validator);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
precomputed.set(txHashStr, { meta, minedBlockId, isValid });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Phase 2: Apply mutations inside the transaction using only pre-computed results,
|
|
218
|
+
// in-memory reads, and buffered DB writes. Nothing here can throw an unhandled exception.
|
|
176
219
|
const poolAccess = this.#createPreAddPoolAccess();
|
|
220
|
+
const preAddContext: PreAddContext | undefined =
|
|
221
|
+
opts.feeComparisonOnly !== undefined
|
|
222
|
+
? { feeComparisonOnly: opts.feeComparisonOnly, priceBumpPercentage: this.#config.priceBumpPercentage }
|
|
223
|
+
: undefined;
|
|
177
224
|
|
|
178
225
|
await this.#store.transactionAsync(async () => {
|
|
179
226
|
for (const tx of txs) {
|
|
@@ -181,38 +228,51 @@ export class TxPoolV2Impl {
|
|
|
181
228
|
const txHashStr = txHash.toString();
|
|
182
229
|
|
|
183
230
|
// Skip duplicates
|
|
184
|
-
if (this.#
|
|
231
|
+
if (this.#indices.has(txHashStr)) {
|
|
185
232
|
ignored.push(txHash);
|
|
186
233
|
continue;
|
|
187
234
|
}
|
|
188
235
|
|
|
189
|
-
|
|
190
|
-
const
|
|
191
|
-
const preProtectedSlot = this.#protectedTransactions.get(txHashStr);
|
|
236
|
+
const { meta, minedBlockId, isValid } = precomputed.get(txHashStr)!;
|
|
237
|
+
const preProtectedSlot = this.#indices.getProtectionSlot(txHashStr);
|
|
192
238
|
|
|
193
239
|
if (minedBlockId) {
|
|
194
240
|
// Already mined - add directly (protection already set if pre-protected)
|
|
195
|
-
await this.#
|
|
241
|
+
await this.#addTx(tx, { mined: minedBlockId }, opts, meta);
|
|
196
242
|
accepted.push(txHash);
|
|
197
|
-
newlyAdded.push(tx);
|
|
198
243
|
} else if (preProtectedSlot !== undefined) {
|
|
199
244
|
// Pre-protected and not mined - add as protected (bypass validation)
|
|
200
|
-
await this.#
|
|
245
|
+
await this.#addTx(tx, { protected: preProtectedSlot }, opts, meta);
|
|
201
246
|
accepted.push(txHash);
|
|
202
|
-
|
|
247
|
+
} else if (!isValid) {
|
|
248
|
+
// Failed pre-computed validation
|
|
249
|
+
rejected.push(txHash);
|
|
203
250
|
} else {
|
|
204
|
-
// Regular pending tx -
|
|
205
|
-
const result = await this.#tryAddRegularPendingTx(
|
|
251
|
+
// Regular pending tx - run pre-add rules using pre-computed metadata
|
|
252
|
+
const result = await this.#tryAddRegularPendingTx(
|
|
253
|
+
tx,
|
|
254
|
+
meta,
|
|
255
|
+
opts,
|
|
256
|
+
poolAccess,
|
|
257
|
+
acceptedPending,
|
|
258
|
+
ignored,
|
|
259
|
+
errors,
|
|
260
|
+
preAddContext,
|
|
261
|
+
);
|
|
206
262
|
if (result.status === 'accepted') {
|
|
207
263
|
acceptedPending.add(txHashStr);
|
|
208
|
-
newlyAdded.push(tx);
|
|
209
|
-
} else if (result.status === 'rejected') {
|
|
210
|
-
rejected.push(txHash);
|
|
211
264
|
} else {
|
|
212
265
|
ignored.push(txHash);
|
|
213
266
|
}
|
|
214
267
|
}
|
|
215
268
|
}
|
|
269
|
+
|
|
270
|
+
// Run post-add eviction rules for pending txs (inside transaction for atomicity)
|
|
271
|
+
if (acceptedPending.size > 0) {
|
|
272
|
+
const feePayers = Array.from(acceptedPending).map(txHash => this.#indices.getMetadata(txHash)!.feePayer);
|
|
273
|
+
const uniqueFeePayers = new Set<string>(feePayers);
|
|
274
|
+
await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [...uniqueFeePayers]);
|
|
275
|
+
}
|
|
216
276
|
});
|
|
217
277
|
|
|
218
278
|
// Build final accepted list for pending txs (excludes intra-batch evictions)
|
|
@@ -220,164 +280,211 @@ export class TxPoolV2Impl {
|
|
|
220
280
|
accepted.push(TxHash.fromString(txHashStr));
|
|
221
281
|
}
|
|
222
282
|
|
|
223
|
-
//
|
|
224
|
-
if (
|
|
225
|
-
|
|
226
|
-
const uniqueFeePayers = new Set<string>(feePayers);
|
|
227
|
-
await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [...uniqueFeePayers]);
|
|
283
|
+
// Record metrics
|
|
284
|
+
if (ignored.length > 0) {
|
|
285
|
+
this.#instrumentation.recordIgnored(ignored.length);
|
|
228
286
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (newlyAdded.length > 0) {
|
|
232
|
-
this.#callbacks.onTxsAdded(newlyAdded, opts);
|
|
287
|
+
if (rejected.length > 0) {
|
|
288
|
+
this.#instrumentation.recordRejected(rejected.length);
|
|
233
289
|
}
|
|
234
290
|
|
|
235
|
-
return { accepted, ignored, rejected };
|
|
291
|
+
return { accepted, ignored, rejected, ...(errors.size > 0 ? { errors } : {}) };
|
|
236
292
|
}
|
|
237
293
|
|
|
238
|
-
/**
|
|
294
|
+
/** Adds a validated pending tx, running pre-add rules and evicting conflicts. */
|
|
239
295
|
async #tryAddRegularPendingTx(
|
|
240
296
|
tx: Tx,
|
|
297
|
+
precomputedMeta: TxMetaData,
|
|
298
|
+
opts: { source?: string },
|
|
241
299
|
poolAccess: PreAddPoolAccess,
|
|
242
300
|
acceptedPending: Set<string>,
|
|
243
301
|
ignored: TxHash[],
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
302
|
+
errors: Map<string, TxPoolRejectionError>,
|
|
303
|
+
preAddContext?: PreAddContext,
|
|
304
|
+
): Promise<{ status: 'accepted' | 'ignored' }> {
|
|
305
|
+
const txHashStr = tx.getTxHash().toString();
|
|
247
306
|
|
|
248
|
-
//
|
|
249
|
-
const
|
|
250
|
-
if (validationResult.result !== 'valid') {
|
|
251
|
-
this.#log.info(`Rejecting tx ${txHashStr}: ${validationResult.reason?.join(', ')}`);
|
|
252
|
-
return { status: 'rejected' };
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// Build metadata and run pre-add rules
|
|
256
|
-
const meta = await buildTxMetaData(tx);
|
|
257
|
-
const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
|
|
307
|
+
// Run pre-add rules
|
|
308
|
+
const preAddResult = await this.#evictionManager.runPreAddRules(precomputedMeta, poolAccess, preAddContext);
|
|
258
309
|
|
|
259
310
|
if (preAddResult.shouldIgnore) {
|
|
260
|
-
this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason}`);
|
|
311
|
+
this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason?.message ?? 'unknown reason'}`);
|
|
312
|
+
if (preAddResult.reason && preAddResult.reason.code !== TxPoolRejectionCode.INTERNAL_ERROR) {
|
|
313
|
+
errors.set(txHashStr, preAddResult.reason);
|
|
314
|
+
}
|
|
261
315
|
return { status: 'ignored' };
|
|
262
316
|
}
|
|
263
317
|
|
|
264
|
-
// Evict conflicts
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
318
|
+
// Evict conflicts, grouped by rule name for metrics
|
|
319
|
+
if (preAddResult.evictions && preAddResult.evictions.length > 0) {
|
|
320
|
+
const byReason = new Map<string, string[]>();
|
|
321
|
+
for (const { txHash: evictHash, reason } of preAddResult.evictions) {
|
|
322
|
+
const group = byReason.get(reason);
|
|
323
|
+
if (group) {
|
|
324
|
+
group.push(evictHash);
|
|
325
|
+
} else {
|
|
326
|
+
byReason.set(reason, [evictHash]);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
for (const [reason, hashes] of byReason) {
|
|
330
|
+
await this.#evictTxs(hashes, reason);
|
|
271
331
|
}
|
|
332
|
+
for (const evictHashStr of preAddResult.txHashesToEvict) {
|
|
333
|
+
this.#log.debug(`Evicted tx ${evictHashStr} due to higher-fee tx ${txHashStr}`, {
|
|
334
|
+
evictedTxHash: evictHashStr,
|
|
335
|
+
replacementTxHash: txHashStr,
|
|
336
|
+
});
|
|
337
|
+
if (acceptedPending.has(evictHashStr)) {
|
|
338
|
+
// Evicted tx was from this batch - mark as ignored in result
|
|
339
|
+
acceptedPending.delete(evictHashStr);
|
|
340
|
+
ignored.push(TxHash.fromString(evictHashStr));
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Randomly drop the transaction for testing purposes (report as accepted so it propagates)
|
|
346
|
+
if (this.#config.dropTransactionsProbability > 0 && Math.random() < this.#config.dropTransactionsProbability) {
|
|
347
|
+
this.#log.debug(`Dropping tx ${txHashStr} (simulated drop for testing)`);
|
|
348
|
+
return { status: 'accepted' };
|
|
272
349
|
}
|
|
273
350
|
|
|
274
351
|
// Add the transaction
|
|
275
|
-
await this.#
|
|
352
|
+
await this.#addTx(tx, 'pending', opts, precomputedMeta);
|
|
276
353
|
return { status: 'accepted' };
|
|
277
354
|
}
|
|
278
355
|
|
|
279
|
-
async canAddPendingTx(tx: Tx): Promise<'accepted' | 'ignored'
|
|
356
|
+
async canAddPendingTx(tx: Tx): Promise<'accepted' | 'ignored'> {
|
|
280
357
|
const txHashStr = tx.getTxHash().toString();
|
|
281
358
|
|
|
282
359
|
// Check if already in pool
|
|
283
|
-
if (this.#
|
|
360
|
+
if (this.#indices.has(txHashStr)) {
|
|
361
|
+
this.#log.verbose(`canAddPendingTx: tx ${txHashStr} already in pool`);
|
|
284
362
|
return 'ignored';
|
|
285
363
|
}
|
|
286
364
|
|
|
287
|
-
//
|
|
288
|
-
const validationResult = await this.#pendingTxValidator.validateTx(tx);
|
|
289
|
-
if (validationResult.result !== 'valid') {
|
|
290
|
-
return 'rejected';
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// Build metadata and use pre-add rules
|
|
365
|
+
// Build metadata and check pre-add rules
|
|
294
366
|
const meta = await buildTxMetaData(tx);
|
|
295
367
|
const poolAccess = this.#createPreAddPoolAccess();
|
|
296
368
|
const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
|
|
297
369
|
|
|
298
|
-
|
|
370
|
+
if (preAddResult.shouldIgnore) {
|
|
371
|
+
this.#log.verbose(`canAddPendingTx: tx ${txHashStr} ignored by pre-add rule`, {
|
|
372
|
+
reason: preAddResult.reason?.message ?? 'no reason provided',
|
|
373
|
+
});
|
|
374
|
+
return 'ignored';
|
|
375
|
+
}
|
|
376
|
+
return 'accepted';
|
|
299
377
|
}
|
|
300
378
|
|
|
301
379
|
async addProtectedTxs(txs: Tx[], block: BlockHeader, opts: { source?: string }): Promise<void> {
|
|
302
380
|
const slotNumber = block.globalVariables.slotNumber;
|
|
303
|
-
|
|
381
|
+
|
|
382
|
+
// Precompute setup-call allow-list flags outside the store transaction
|
|
383
|
+
const allowedFlags = await Promise.all(txs.map(tx => this.#checkAllowedSetupCalls(tx)));
|
|
304
384
|
|
|
305
385
|
await this.#store.transactionAsync(async () => {
|
|
306
|
-
for (
|
|
386
|
+
for (let i = 0; i < txs.length; i++) {
|
|
387
|
+
const tx = txs[i];
|
|
307
388
|
const txHash = tx.getTxHash();
|
|
308
389
|
const txHashStr = txHash.toString();
|
|
309
|
-
const isNew = !this.#
|
|
390
|
+
const isNew = !this.#indices.has(txHashStr);
|
|
310
391
|
const minedBlockId = await this.#getMinedBlockId(txHash);
|
|
311
392
|
|
|
312
393
|
if (isNew) {
|
|
313
|
-
|
|
394
|
+
const meta = await buildTxMetaData(tx, allowedFlags[i]);
|
|
395
|
+
// New tx - add as mined or protected (callback emitted by #addTx)
|
|
314
396
|
if (minedBlockId) {
|
|
315
|
-
await this.#
|
|
316
|
-
this.#
|
|
397
|
+
await this.#addTx(tx, { mined: minedBlockId }, opts, meta);
|
|
398
|
+
this.#indices.setProtection(txHashStr, slotNumber);
|
|
317
399
|
} else {
|
|
318
|
-
await this.#
|
|
400
|
+
await this.#addTx(tx, { protected: slotNumber }, opts, meta);
|
|
319
401
|
}
|
|
320
|
-
newlyAdded.push(tx);
|
|
321
402
|
} else {
|
|
322
403
|
// Existing tx - update protection and mined status
|
|
323
|
-
this.#updateProtection(txHashStr, slotNumber);
|
|
404
|
+
this.#indices.updateProtection(txHashStr, slotNumber);
|
|
324
405
|
if (minedBlockId) {
|
|
325
|
-
this.#
|
|
406
|
+
const meta = this.#indices.getMetadata(txHashStr)!;
|
|
407
|
+
this.#indices.markAsMined(meta, minedBlockId);
|
|
326
408
|
}
|
|
327
409
|
}
|
|
328
410
|
}
|
|
329
411
|
});
|
|
330
|
-
|
|
331
|
-
if (newlyAdded.length > 0) {
|
|
332
|
-
this.#callbacks.onTxsAdded(newlyAdded, opts);
|
|
333
|
-
}
|
|
334
412
|
}
|
|
335
413
|
|
|
336
|
-
protectTxs(txHashes: TxHash[], block: BlockHeader): TxHash[] {
|
|
414
|
+
async protectTxs(txHashes: TxHash[], block: BlockHeader): Promise<TxHash[]> {
|
|
337
415
|
const slotNumber = block.globalVariables.slotNumber;
|
|
338
416
|
const missing: TxHash[] = [];
|
|
417
|
+
let softDeletedHits = 0;
|
|
418
|
+
let missingPreviouslyEvicted = 0;
|
|
339
419
|
|
|
340
|
-
|
|
341
|
-
const
|
|
420
|
+
await this.#store.transactionAsync(async () => {
|
|
421
|
+
for (const txHash of txHashes) {
|
|
422
|
+
const txHashStr = txHash.toString();
|
|
342
423
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
424
|
+
if (this.#indices.has(txHashStr)) {
|
|
425
|
+
// Update protection for existing tx
|
|
426
|
+
this.#indices.updateProtection(txHashStr, slotNumber);
|
|
427
|
+
} else if (this.#deletedPool.isSoftDeleted(txHashStr)) {
|
|
428
|
+
// Resurrect soft-deleted tx as protected
|
|
429
|
+
const buffer = await this.#txsDB.getAsync(txHashStr);
|
|
430
|
+
if (buffer) {
|
|
431
|
+
const tx = Tx.fromBuffer(buffer);
|
|
432
|
+
await this.#addTx(tx, { protected: slotNumber });
|
|
433
|
+
softDeletedHits++;
|
|
434
|
+
} else {
|
|
435
|
+
// Data missing despite soft-delete flag — treat as truly missing
|
|
436
|
+
this.#indices.setProtection(txHashStr, slotNumber);
|
|
437
|
+
missing.push(txHash);
|
|
438
|
+
}
|
|
439
|
+
} else {
|
|
440
|
+
// Truly missing — pre-record protection for tx we don't have yet
|
|
441
|
+
this.#indices.setProtection(txHashStr, slotNumber);
|
|
442
|
+
missing.push(txHash);
|
|
443
|
+
if (this.#evictedTxHashes.has(txHashStr)) {
|
|
444
|
+
missingPreviouslyEvicted++;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
350
447
|
}
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
// Record metrics
|
|
451
|
+
if (softDeletedHits > 0) {
|
|
452
|
+
this.#instrumentation.recordSoftDeletedHits(softDeletedHits);
|
|
453
|
+
}
|
|
454
|
+
if (missing.length > 0) {
|
|
455
|
+
this.#log.debug(`protectTxs missing tx hashes: ${missing.map(h => h.toString()).join(', ')}`);
|
|
456
|
+
this.#instrumentation.recordMissingOnProtect(missing.length);
|
|
457
|
+
}
|
|
458
|
+
if (missingPreviouslyEvicted > 0) {
|
|
459
|
+
this.#instrumentation.recordMissingPreviouslyEvicted(missingPreviouslyEvicted);
|
|
351
460
|
}
|
|
352
461
|
|
|
462
|
+
this.#log.info(
|
|
463
|
+
`Protected ${txHashes.length} txs, missing: ${missing.length}, soft-deleted hits: ${softDeletedHits}`,
|
|
464
|
+
);
|
|
465
|
+
|
|
353
466
|
return missing;
|
|
354
467
|
}
|
|
355
468
|
|
|
356
469
|
async addMinedTxs(txs: Tx[], block: BlockHeader, opts: { source?: string }): Promise<void> {
|
|
357
470
|
// Step 1: Build block ID
|
|
358
471
|
const blockId = await this.#buildBlockId(block);
|
|
359
|
-
const newlyAdded: Tx[] = [];
|
|
360
472
|
|
|
361
473
|
await this.#store.transactionAsync(async () => {
|
|
362
474
|
for (const tx of txs) {
|
|
363
475
|
const txHashStr = tx.getTxHash().toString();
|
|
364
|
-
const existingMeta = this.#
|
|
476
|
+
const existingMeta = this.#indices.getMetadata(txHashStr);
|
|
365
477
|
|
|
366
478
|
if (existingMeta) {
|
|
367
|
-
//
|
|
368
|
-
this.#markAsMined(existingMeta, blockId);
|
|
479
|
+
// Mark existing tx as mined
|
|
480
|
+
this.#indices.markAsMined(existingMeta, blockId);
|
|
369
481
|
} else {
|
|
370
|
-
//
|
|
371
|
-
await this.#
|
|
372
|
-
newlyAdded.push(tx);
|
|
482
|
+
// Add new mined tx (callback emitted by #addTx)
|
|
483
|
+
await this.#addTx(tx, { mined: blockId }, opts);
|
|
373
484
|
}
|
|
485
|
+
await this.#deletedPool.clearIfMinedHigher(txHashStr, blockId.number);
|
|
374
486
|
}
|
|
375
487
|
});
|
|
376
|
-
|
|
377
|
-
// Step 3: Emit events for newly added txs
|
|
378
|
-
if (newlyAdded.length > 0) {
|
|
379
|
-
this.#callbacks.onTxsAdded(newlyAdded, opts);
|
|
380
|
-
}
|
|
381
488
|
}
|
|
382
489
|
|
|
383
490
|
async handleMinedBlock(block: L2Block): Promise<void> {
|
|
@@ -392,61 +499,76 @@ export class TxPoolV2Impl {
|
|
|
392
499
|
const feePayers: string[] = [];
|
|
393
500
|
const found: TxMetaData[] = [];
|
|
394
501
|
for (const txHash of txHashes) {
|
|
395
|
-
const meta = this.#
|
|
502
|
+
const meta = this.#indices.getMetadata(txHash.toString());
|
|
396
503
|
if (meta) {
|
|
397
504
|
feePayers.push(meta.feePayer);
|
|
398
505
|
found.push(meta);
|
|
399
506
|
}
|
|
400
507
|
}
|
|
401
508
|
|
|
402
|
-
|
|
403
|
-
|
|
509
|
+
await this.#store.transactionAsync(async () => {
|
|
510
|
+
// Step 4: Mark txs as mined (only those we have in the pool)
|
|
511
|
+
for (const meta of found) {
|
|
512
|
+
this.#indices.markAsMined(meta, blockId);
|
|
513
|
+
await this.#deletedPool.clearIfMinedHigher(meta.txHash, blockId.number);
|
|
514
|
+
}
|
|
404
515
|
|
|
405
|
-
|
|
406
|
-
|
|
516
|
+
// Step 5: Run post-event eviction rules (inside transaction for atomicity)
|
|
517
|
+
await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
if (found.length > 0) {
|
|
521
|
+
this.#callbacks.onTxsMined(found.map(m => m.txHash));
|
|
522
|
+
}
|
|
407
523
|
|
|
408
|
-
this.#callbacks.onTxsRemoved(txHashes.map(h => h.toBigInt()));
|
|
409
524
|
this.#log.info(`Marked ${found.length} txs as mined in block ${blockId.number}`);
|
|
410
525
|
}
|
|
411
526
|
|
|
412
527
|
async prepareForSlot(slotNumber: SlotNumber): Promise<void> {
|
|
413
|
-
|
|
414
|
-
|
|
528
|
+
await this.#store.transactionAsync(async () => {
|
|
529
|
+
// Step 0: Clean up slot-deleted txs from previous slots
|
|
530
|
+
await this.#deletedPool.cleanupSlotDeleted(slotNumber);
|
|
415
531
|
|
|
416
|
-
|
|
417
|
-
|
|
532
|
+
// Step 1: Find expired protected txs
|
|
533
|
+
const expiredProtected = this.#indices.findExpiredProtectedTxs(slotNumber);
|
|
418
534
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
535
|
+
// Step 2: Clear protection for all expired entries (including those without metadata)
|
|
536
|
+
this.#indices.clearProtection(expiredProtected);
|
|
537
|
+
|
|
538
|
+
// Step 3: Filter to only txs that have metadata and are not mined
|
|
539
|
+
const txsToRestore = this.#indices.filterRestorable(expiredProtected);
|
|
540
|
+
if (txsToRestore.length === 0) {
|
|
541
|
+
this.#log.debug(`Preparing for slot ${slotNumber}, no txs to unprotect`);
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
424
544
|
|
|
425
|
-
|
|
545
|
+
this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
|
|
426
546
|
|
|
427
|
-
|
|
428
|
-
|
|
547
|
+
// Step 4: Validate for pending pool
|
|
548
|
+
const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, 'during prepareForSlot');
|
|
429
549
|
|
|
430
|
-
|
|
431
|
-
|
|
550
|
+
// Step 5: Resolve nullifier conflicts and add winners to pending indices
|
|
551
|
+
const { added, toEvict } = this.#applyNullifierConflictResolution(valid);
|
|
432
552
|
|
|
433
|
-
|
|
434
|
-
|
|
553
|
+
// Step 6: Delete invalid txs and evict conflict losers
|
|
554
|
+
await this.#deleteTxsBatch(invalid);
|
|
555
|
+
await this.#evictTxs(toEvict, 'NullifierConflict');
|
|
435
556
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
557
|
+
// Step 7: Run eviction rules (enforce pool size limit)
|
|
558
|
+
if (added.length > 0) {
|
|
559
|
+
const feePayers = added.map(meta => meta.feePayer);
|
|
560
|
+
const uniqueFeePayers = new Set<string>(feePayers);
|
|
561
|
+
await this.#evictionManager.evictAfterNewTxs(
|
|
562
|
+
added.map(m => m.txHash),
|
|
563
|
+
[...uniqueFeePayers],
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
});
|
|
445
567
|
}
|
|
446
568
|
|
|
447
|
-
async handlePrunedBlocks(latestBlock: L2BlockId): Promise<void> {
|
|
569
|
+
async handlePrunedBlocks(latestBlock: L2BlockId, options?: { deleteAllTxs?: boolean }): Promise<void> {
|
|
448
570
|
// Step 1: Find transactions mined after the prune point
|
|
449
|
-
const txsToUnmine = this.#findTxsMinedAfter(latestBlock.number);
|
|
571
|
+
const txsToUnmine = this.#indices.findTxsMinedAfter(latestBlock.number);
|
|
450
572
|
if (txsToUnmine.length === 0) {
|
|
451
573
|
this.#log.debug(`No transactions to un-mine for prune to block ${latestBlock.number}`);
|
|
452
574
|
return;
|
|
@@ -454,62 +576,99 @@ export class TxPoolV2Impl {
|
|
|
454
576
|
|
|
455
577
|
this.#log.info(`Handling prune to block ${latestBlock.number}: un-mining ${txsToUnmine.length} txs`);
|
|
456
578
|
|
|
457
|
-
|
|
458
|
-
|
|
579
|
+
await this.#store.transactionAsync(async () => {
|
|
580
|
+
// Step 2: Mark ALL un-mined txs with their original mined block number
|
|
581
|
+
// This ensures they get soft-deleted if removed later, and only hard-deleted
|
|
582
|
+
// when their original mined block is finalized
|
|
583
|
+
await this.#deletedPool.markFromPrunedBlock(
|
|
584
|
+
txsToUnmine.map(m => ({
|
|
585
|
+
txHash: m.txHash,
|
|
586
|
+
minedAtBlock: BlockNumber(m.minedL2BlockId!.number),
|
|
587
|
+
})),
|
|
588
|
+
);
|
|
459
589
|
|
|
460
|
-
|
|
461
|
-
|
|
590
|
+
// Step 3: Unmine - clear mined status from metadata
|
|
591
|
+
for (const meta of txsToUnmine) {
|
|
592
|
+
this.#indices.markAsUnmined(meta);
|
|
593
|
+
}
|
|
462
594
|
|
|
463
|
-
|
|
464
|
-
|
|
595
|
+
// If deleteAllTxs is set (epoch prune), delete all un-mined txs and return early
|
|
596
|
+
if (options?.deleteAllTxs) {
|
|
597
|
+
const allTxHashes = txsToUnmine.map(m => m.txHash);
|
|
598
|
+
await this.#deleteTxsBatch(allTxHashes);
|
|
599
|
+
this.#log.info(
|
|
600
|
+
`Handled prune to block ${latestBlock.number} with deleteAllTxs: deleted ${allTxHashes.length} txs`,
|
|
601
|
+
);
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
465
604
|
|
|
466
|
-
|
|
467
|
-
|
|
605
|
+
// Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
|
|
606
|
+
const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
|
|
468
607
|
|
|
469
|
-
|
|
470
|
-
|
|
608
|
+
// Step 5: Validate for pending pool
|
|
609
|
+
const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
|
|
471
610
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
611
|
+
// Step 6: Resolve nullifier conflicts and add winners to pending indices
|
|
612
|
+
const { toEvict } = this.#applyNullifierConflictResolution(valid);
|
|
613
|
+
|
|
614
|
+
// Step 7: Delete invalid txs and evict conflict losers
|
|
615
|
+
await this.#deleteTxsBatch(invalid);
|
|
616
|
+
await this.#evictTxs(toEvict, 'NullifierConflict');
|
|
617
|
+
|
|
618
|
+
this.#log.info(
|
|
619
|
+
`Handled prune to block ${latestBlock.number}: ${valid.length} txs restored to pending, ${invalid.length} invalid, ${toEvict.length} evicted due to nullifier conflicts`,
|
|
620
|
+
{ txHashesRestored: valid.map(m => m.txHash), txHashesInvalid: invalid, txHashesEvicted: toEvict },
|
|
621
|
+
);
|
|
622
|
+
|
|
623
|
+
// Step 8: Run eviction rules for ALL pending txs (not just restored ones)
|
|
624
|
+
// This handles cases like existing pending txs with invalid fee payer balances
|
|
625
|
+
await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
|
|
626
|
+
});
|
|
475
627
|
}
|
|
476
628
|
|
|
477
629
|
async handleFailedExecution(txHashes: TxHash[]): Promise<void> {
|
|
478
|
-
|
|
479
|
-
|
|
630
|
+
await this.#store.transactionAsync(async () => {
|
|
631
|
+
await this.#deleteTxsBatch(txHashes.map(h => h.toString()));
|
|
632
|
+
});
|
|
480
633
|
|
|
481
|
-
this.#log.info(`Deleted ${txHashes.length} failed txs
|
|
634
|
+
this.#log.info(`Deleted ${txHashes.length} failed txs`, { txHashes: txHashes.map(h => h.toString()) });
|
|
482
635
|
}
|
|
483
636
|
|
|
484
637
|
async handleFinalizedBlock(block: BlockHeader): Promise<void> {
|
|
485
638
|
const blockNumber = block.globalVariables.blockNumber;
|
|
486
639
|
|
|
487
|
-
// Step 1: Find txs
|
|
488
|
-
const
|
|
489
|
-
if (txsToFinalize.length === 0) {
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
640
|
+
// Step 1: Find mined txs at or before finalized block
|
|
641
|
+
const minedTxsToFinalize = this.#indices.findTxsMinedAtOrBefore(blockNumber);
|
|
492
642
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
|
|
643
|
+
await this.#store.transactionAsync(async () => {
|
|
644
|
+
// Step 2: Collect mined txs for archiving (before deletion)
|
|
645
|
+
const txsToArchive: Tx[] = [];
|
|
646
|
+
if (this.#archive.isEnabled()) {
|
|
647
|
+
for (const txHashStr of minedTxsToFinalize) {
|
|
648
|
+
const buffer = await this.#txsDB.getAsync(txHashStr);
|
|
649
|
+
if (buffer) {
|
|
650
|
+
txsToArchive.push(Tx.fromBuffer(buffer));
|
|
651
|
+
}
|
|
500
652
|
}
|
|
501
653
|
}
|
|
502
|
-
}
|
|
503
654
|
|
|
504
|
-
|
|
505
|
-
|
|
655
|
+
// Step 3: Delete mined txs from active pool
|
|
656
|
+
await this.#deleteTxsBatch(minedTxsToFinalize);
|
|
506
657
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
658
|
+
// Step 4: Finalize soft-deleted txs
|
|
659
|
+
await this.#deletedPool.finalizeBlock(blockNumber);
|
|
660
|
+
|
|
661
|
+
// Step 5: Archive mined txs
|
|
662
|
+
if (txsToArchive.length > 0) {
|
|
663
|
+
await this.#archive.archiveTxs(txsToArchive);
|
|
664
|
+
}
|
|
665
|
+
});
|
|
511
666
|
|
|
512
|
-
|
|
667
|
+
if (minedTxsToFinalize.length > 0) {
|
|
668
|
+
this.#log.info(`Finalized ${minedTxsToFinalize.length} mined txs from blocks up to ${blockNumber}`, {
|
|
669
|
+
txHashes: minedTxsToFinalize,
|
|
670
|
+
});
|
|
671
|
+
}
|
|
513
672
|
}
|
|
514
673
|
|
|
515
674
|
// === Query Methods ===
|
|
@@ -529,42 +688,47 @@ export class TxPoolV2Impl {
|
|
|
529
688
|
}
|
|
530
689
|
|
|
531
690
|
hasTxs(txHashes: TxHash[]): boolean[] {
|
|
532
|
-
return txHashes.map(h =>
|
|
691
|
+
return txHashes.map(h => {
|
|
692
|
+
const hashStr = h.toString();
|
|
693
|
+
return this.#indices.has(hashStr) || this.#deletedPool.isSoftDeleted(hashStr);
|
|
694
|
+
});
|
|
533
695
|
}
|
|
534
696
|
|
|
535
697
|
getTxStatus(txHash: TxHash): TxState | undefined {
|
|
536
|
-
const
|
|
537
|
-
|
|
538
|
-
|
|
698
|
+
const txHashStr = txHash.toString();
|
|
699
|
+
const meta = this.#indices.getMetadata(txHashStr);
|
|
700
|
+
if (meta) {
|
|
701
|
+
return this.#indices.getTxState(meta);
|
|
702
|
+
}
|
|
703
|
+
// Check if soft-deleted
|
|
704
|
+
if (this.#deletedPool.isSoftDeleted(txHashStr)) {
|
|
705
|
+
return 'deleted';
|
|
539
706
|
}
|
|
540
|
-
return
|
|
707
|
+
return undefined;
|
|
541
708
|
}
|
|
542
709
|
|
|
543
710
|
getPendingTxHashes(): TxHash[] {
|
|
544
|
-
return [...this.#iteratePendingByPriority('desc')].map(hash => TxHash.fromString(hash));
|
|
711
|
+
return [...this.#indices.iteratePendingByPriority('desc')].map(hash => TxHash.fromString(hash));
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
getEligiblePendingTxHashes(): TxHash[] {
|
|
715
|
+
const maxReceivedAt = this.#dateProvider.now() - this.#config.minTxPoolAgeMs;
|
|
716
|
+
return [...this.#indices.iterateEligiblePendingByPriority('desc', maxReceivedAt)].map(hash =>
|
|
717
|
+
TxHash.fromString(hash),
|
|
718
|
+
);
|
|
545
719
|
}
|
|
546
720
|
|
|
547
721
|
getPendingTxCount(): number {
|
|
548
|
-
|
|
549
|
-
for (const hashes of this.#pendingByPriority.values()) {
|
|
550
|
-
count += hashes.size;
|
|
551
|
-
}
|
|
552
|
-
return count;
|
|
722
|
+
return this.#indices.getPendingTxCount();
|
|
553
723
|
}
|
|
554
724
|
|
|
555
725
|
getMinedTxHashes(): [TxHash, L2BlockId][] {
|
|
556
|
-
|
|
557
|
-
for (const [txHash, meta] of this.#metadata) {
|
|
558
|
-
if (meta.minedL2BlockId !== undefined) {
|
|
559
|
-
result.push([TxHash.fromString(txHash), meta.minedL2BlockId]);
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
return result;
|
|
726
|
+
return this.#indices.getMinedTxs().map(([hash, blockId]) => [TxHash.fromString(hash), blockId]);
|
|
563
727
|
}
|
|
564
728
|
|
|
565
729
|
getMinedTxCount(): number {
|
|
566
730
|
let count = 0;
|
|
567
|
-
for (const meta of this.#
|
|
731
|
+
for (const [, meta] of this.#indices.iterateMetadata()) {
|
|
568
732
|
if (meta.minedL2BlockId !== undefined) {
|
|
569
733
|
count++;
|
|
570
734
|
}
|
|
@@ -573,11 +737,11 @@ export class TxPoolV2Impl {
|
|
|
573
737
|
}
|
|
574
738
|
|
|
575
739
|
isEmpty(): boolean {
|
|
576
|
-
return this.#
|
|
740
|
+
return this.#indices.isEmpty();
|
|
577
741
|
}
|
|
578
742
|
|
|
579
743
|
getTxCount(): number {
|
|
580
|
-
return this.#
|
|
744
|
+
return this.#indices.getTxCount();
|
|
581
745
|
}
|
|
582
746
|
|
|
583
747
|
getArchivedTxByHash(txHash: TxHash): Promise<Tx | undefined> {
|
|
@@ -585,18 +749,7 @@ export class TxPoolV2Impl {
|
|
|
585
749
|
}
|
|
586
750
|
|
|
587
751
|
getLowestPriorityPending(limit: number): TxHash[] {
|
|
588
|
-
|
|
589
|
-
return [];
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
const result: TxHash[] = [];
|
|
593
|
-
for (const hash of this.#iteratePendingByPriority('asc')) {
|
|
594
|
-
result.push(TxHash.fromString(hash));
|
|
595
|
-
if (result.length >= limit) {
|
|
596
|
-
break;
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
return result;
|
|
752
|
+
return this.#indices.getLowestPriorityPending(limit).map(h => TxHash.fromString(h));
|
|
600
753
|
}
|
|
601
754
|
|
|
602
755
|
// === Configuration ===
|
|
@@ -609,6 +762,9 @@ export class TxPoolV2Impl {
|
|
|
609
762
|
this.#config.archivedTxLimit = config.archivedTxLimit;
|
|
610
763
|
this.#archive.updateLimit(config.archivedTxLimit);
|
|
611
764
|
}
|
|
765
|
+
if (config.minTxPoolAgeMs !== undefined) {
|
|
766
|
+
this.#config.minTxPoolAgeMs = config.minTxPoolAgeMs;
|
|
767
|
+
}
|
|
612
768
|
// Update eviction rules with new config
|
|
613
769
|
this.#evictionManager.updateConfig(config);
|
|
614
770
|
}
|
|
@@ -617,159 +773,146 @@ export class TxPoolV2Impl {
|
|
|
617
773
|
|
|
618
774
|
getPoolReadAccess(): PoolReadAccess {
|
|
619
775
|
return {
|
|
620
|
-
getMetadata: (txHash: string) => this.#
|
|
621
|
-
getTxHashByNullifier: (nullifier: string) => this.#
|
|
622
|
-
getTxHashesByFeePayer: (feePayer: string) => this.#
|
|
623
|
-
getPendingTxCount: () => this.getPendingTxCount(),
|
|
776
|
+
getMetadata: (txHash: string) => this.#indices.getMetadata(txHash),
|
|
777
|
+
getTxHashByNullifier: (nullifier: string) => this.#indices.getTxHashByNullifier(nullifier),
|
|
778
|
+
getTxHashesByFeePayer: (feePayer: string) => this.#indices.getTxHashesByFeePayer(feePayer),
|
|
779
|
+
getPendingTxCount: () => this.#indices.getPendingTxCount(),
|
|
624
780
|
};
|
|
625
781
|
}
|
|
626
782
|
|
|
627
783
|
// === Metrics ===
|
|
628
784
|
|
|
629
|
-
countTxs(): {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
} else if (state === 'mined') {
|
|
641
|
-
mined++;
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
return { pending, protected: protected_, mined };
|
|
785
|
+
countTxs(): {
|
|
786
|
+
pending: number;
|
|
787
|
+
protected: number;
|
|
788
|
+
mined: number;
|
|
789
|
+
softDeleted: number;
|
|
790
|
+
totalMetadataBytes: number;
|
|
791
|
+
} {
|
|
792
|
+
return {
|
|
793
|
+
...this.#indices.countTxs(),
|
|
794
|
+
softDeleted: this.#deletedPool.getSoftDeletedCount(),
|
|
795
|
+
};
|
|
646
796
|
}
|
|
647
797
|
|
|
648
798
|
// ============================================================================
|
|
649
|
-
// PRIVATE
|
|
799
|
+
// PRIVATE HELPERS - Transaction Management
|
|
650
800
|
// ============================================================================
|
|
651
801
|
|
|
652
802
|
/**
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
* - 'mined' if it has a minedL2BlockId
|
|
656
|
-
* - 'protected' if it's in the protectedTransactions map (but not mined)
|
|
657
|
-
* - 'pending' otherwise
|
|
803
|
+
* Adds a new transaction to the pool with the specified state.
|
|
804
|
+
* Emits onTxsAdded callback immediately after DB write.
|
|
658
805
|
*/
|
|
659
|
-
#
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
806
|
+
async #addTx(
|
|
807
|
+
tx: Tx,
|
|
808
|
+
state: 'pending' | { protected: SlotNumber } | { mined: L2BlockId },
|
|
809
|
+
opts: { source?: string } = {},
|
|
810
|
+
precomputedMeta?: TxMetaData,
|
|
811
|
+
): Promise<TxMetaData> {
|
|
812
|
+
const txHashStr = tx.getTxHash().toString();
|
|
813
|
+
const meta = precomputedMeta ?? (await buildTxMetaData(tx));
|
|
814
|
+
meta.receivedAt = this.#dateProvider.now();
|
|
815
|
+
|
|
816
|
+
await this.#txsDB.set(txHashStr, tx.toBuffer());
|
|
817
|
+
await this.#deletedPool.clearSoftDeleted(txHashStr);
|
|
818
|
+
this.#callbacks.onTxsAdded([tx], opts);
|
|
819
|
+
|
|
820
|
+
if (state === 'pending') {
|
|
821
|
+
this.#indices.addPending(meta);
|
|
822
|
+
} else if ('protected' in state) {
|
|
823
|
+
this.#indices.addProtected(meta, state.protected);
|
|
664
824
|
} else {
|
|
665
|
-
|
|
825
|
+
meta.minedL2BlockId = state.mined;
|
|
826
|
+
this.#indices.addMined(meta);
|
|
666
827
|
}
|
|
828
|
+
|
|
829
|
+
const stateStr = typeof state === 'string' ? state : Object.keys(state)[0];
|
|
830
|
+
this.#log.debug(`Added tx ${txHashStr} as ${stateStr}`, {
|
|
831
|
+
eventName: 'tx-added-to-pool',
|
|
832
|
+
txHash: txHashStr,
|
|
833
|
+
state: stateStr,
|
|
834
|
+
source: opts.source,
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
return meta;
|
|
667
838
|
}
|
|
668
839
|
|
|
669
840
|
/**
|
|
670
|
-
*
|
|
671
|
-
*
|
|
841
|
+
* Deletes a transaction from both indices and DB.
|
|
842
|
+
* Emits onTxsRemoved callback immediately after DB delete.
|
|
672
843
|
*/
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
for (const fee of sortedFees) {
|
|
683
|
-
const hashesAtFee = this.#pendingByPriority.get(fee)!;
|
|
684
|
-
const sortedHashes = [...hashesAtFee].sort(hashCompareFn);
|
|
685
|
-
for (const hash of sortedHashes) {
|
|
686
|
-
yield hash;
|
|
687
|
-
}
|
|
688
|
-
}
|
|
844
|
+
/**
|
|
845
|
+
* Deletes a transaction from the pool.
|
|
846
|
+
* Delegates to DeletedPool which decides soft vs hard delete based on whether
|
|
847
|
+
* the tx is from a pruned block.
|
|
848
|
+
*/
|
|
849
|
+
async #deleteTx(txHashStr: string): Promise<void> {
|
|
850
|
+
this.#indices.remove(txHashStr);
|
|
851
|
+
this.#callbacks.onTxsRemoved([txHashStr]);
|
|
852
|
+
await this.#deletedPool.deleteTx(txHashStr);
|
|
689
853
|
}
|
|
690
854
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
// --- Finding & Filtering Steps ---
|
|
696
|
-
|
|
697
|
-
/** Finds all transactions mined in blocks after the given block number */
|
|
698
|
-
#findTxsMinedAfter(blockNumber: number): TxMetaData[] {
|
|
699
|
-
const result: TxMetaData[] = [];
|
|
700
|
-
for (const meta of this.#metadata.values()) {
|
|
701
|
-
if (meta.minedL2BlockId !== undefined && meta.minedL2BlockId.number > blockNumber) {
|
|
702
|
-
result.push(meta);
|
|
703
|
-
}
|
|
855
|
+
/** Deletes a batch of transactions, emitting callbacks individually for each. */
|
|
856
|
+
async #deleteTxsBatch(txHashes: string[]): Promise<void> {
|
|
857
|
+
for (const txHashStr of txHashes) {
|
|
858
|
+
await this.#deleteTx(txHashStr);
|
|
704
859
|
}
|
|
705
|
-
return result;
|
|
706
860
|
}
|
|
707
861
|
|
|
708
|
-
/**
|
|
709
|
-
#
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
862
|
+
/** Evicts transactions: records eviction metric with reason, caches hashes, then deletes. */
|
|
863
|
+
async #evictTxs(txHashes: string[], reason: string): Promise<void> {
|
|
864
|
+
if (txHashes.length === 0) {
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
this.#instrumentation.recordEvictions(txHashes.length, reason);
|
|
868
|
+
for (const txHashStr of txHashes) {
|
|
869
|
+
this.#log.debug(`Evicting tx ${txHashStr}`, { txHash: txHashStr, reason });
|
|
870
|
+
this.#addToEvictedCache(txHashStr);
|
|
715
871
|
}
|
|
716
|
-
|
|
872
|
+
await this.#deleteTxsBatch(txHashes);
|
|
717
873
|
}
|
|
718
874
|
|
|
719
|
-
/**
|
|
720
|
-
#
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
}
|
|
875
|
+
/** Adds a tx hash to the bounded evicted cache, evicting the oldest entry if at capacity. */
|
|
876
|
+
#addToEvictedCache(txHashStr: string): void {
|
|
877
|
+
if (this.#evictedTxHashes.size >= this.#config.evictedTxCacheSize) {
|
|
878
|
+
// FIFO eviction: remove the first (oldest) entry
|
|
879
|
+
const oldest = this.#evictedTxHashes.values().next().value!;
|
|
880
|
+
this.#evictedTxHashes.delete(oldest);
|
|
726
881
|
}
|
|
727
|
-
|
|
882
|
+
this.#evictedTxHashes.add(txHashStr);
|
|
728
883
|
}
|
|
729
884
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
}
|
|
885
|
+
// ============================================================================
|
|
886
|
+
// PRIVATE HELPERS - Validation & Conflict Resolution
|
|
887
|
+
// ============================================================================
|
|
734
888
|
|
|
735
|
-
/**
|
|
736
|
-
#
|
|
737
|
-
const
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
889
|
+
/** Validates transaction metadata, returning true if valid */
|
|
890
|
+
async #validateMeta(meta: TxMetaData, validator?: TxValidator<TxMetaData>, context?: string): Promise<boolean> {
|
|
891
|
+
const txValidator = validator ?? (await this.#createTxValidator());
|
|
892
|
+
const result = await txValidator.validateTx(meta);
|
|
893
|
+
if (result.result !== 'valid') {
|
|
894
|
+
const contextStr = context ? ` ${context}` : '';
|
|
895
|
+
this.#log.info(`Tx ${meta.txHash}${contextStr} failed validation: ${result.reason?.join(', ')}`);
|
|
896
|
+
return false;
|
|
743
897
|
}
|
|
744
|
-
return
|
|
898
|
+
return true;
|
|
745
899
|
}
|
|
746
900
|
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
901
|
+
/** Validates metadata directly */
|
|
902
|
+
async #revalidateMetadata(
|
|
903
|
+
metas: TxMetaData[],
|
|
904
|
+
context?: string,
|
|
905
|
+
): Promise<{ valid: TxMetaData[]; invalid: string[] }> {
|
|
751
906
|
const valid: TxMetaData[] = [];
|
|
752
907
|
const invalid: string[] = [];
|
|
753
|
-
|
|
754
|
-
for (const meta of
|
|
755
|
-
|
|
756
|
-
if (!buffer) {
|
|
757
|
-
this.#log.warn(`Tx ${meta.txHash} not found in DB during validation`);
|
|
758
|
-
invalid.push(meta.txHash);
|
|
759
|
-
continue;
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
const tx = Tx.fromBuffer(buffer);
|
|
763
|
-
const result = await this.#pendingTxValidator.validateTx(tx);
|
|
764
|
-
|
|
765
|
-
if (result.result === 'valid') {
|
|
908
|
+
const validator = await this.#createTxValidator();
|
|
909
|
+
for (const meta of metas) {
|
|
910
|
+
if (await this.#validateMeta(meta, validator, context)) {
|
|
766
911
|
valid.push(meta);
|
|
767
912
|
} else {
|
|
768
|
-
this.#log.info(`Tx ${meta.txHash} failed validation: ${result.reason?.join(', ')}`);
|
|
769
913
|
invalid.push(meta.txHash);
|
|
770
914
|
}
|
|
771
915
|
}
|
|
772
|
-
|
|
773
916
|
return { valid, invalid };
|
|
774
917
|
}
|
|
775
918
|
|
|
@@ -785,8 +928,8 @@ export class TxPoolV2Impl {
|
|
|
785
928
|
for (const meta of txs) {
|
|
786
929
|
const conflict = checkNullifierConflict(
|
|
787
930
|
meta,
|
|
788
|
-
nullifier => this.#
|
|
789
|
-
txHash => this.#
|
|
931
|
+
nullifier => this.#indices.getTxHashByNullifier(nullifier),
|
|
932
|
+
txHash => this.#indices.getMetadata(txHash),
|
|
790
933
|
);
|
|
791
934
|
if (conflict.shouldIgnore) {
|
|
792
935
|
// Lower priority than existing - don't add, mark for deletion
|
|
@@ -796,13 +939,13 @@ export class TxPoolV2Impl {
|
|
|
796
939
|
toEvict.push(...conflict.txHashesToEvict);
|
|
797
940
|
// Remove evicted from indices immediately for subsequent checks
|
|
798
941
|
for (const evictHash of conflict.txHashesToEvict) {
|
|
799
|
-
const evictMeta = this.#
|
|
942
|
+
const evictMeta = this.#indices.getMetadata(evictHash);
|
|
800
943
|
if (evictMeta) {
|
|
801
|
-
this.#removeFromPendingIndices(evictMeta);
|
|
944
|
+
this.#indices.removeFromPendingIndices(evictMeta);
|
|
802
945
|
}
|
|
803
946
|
}
|
|
804
947
|
// Add to pending indices immediately so subsequent txs in the batch see this tx
|
|
805
|
-
this.#addToPendingIndices(meta);
|
|
948
|
+
this.#indices.addToPendingIndices(meta);
|
|
806
949
|
added.push(meta);
|
|
807
950
|
}
|
|
808
951
|
}
|
|
@@ -810,43 +953,10 @@ export class TxPoolV2Impl {
|
|
|
810
953
|
return { added, toEvict };
|
|
811
954
|
}
|
|
812
955
|
|
|
813
|
-
//
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
#unmineTxs(txs: TxMetaData[]): TxMetaData[] {
|
|
817
|
-
for (const meta of txs) {
|
|
818
|
-
meta.minedL2BlockId = undefined;
|
|
819
|
-
}
|
|
820
|
-
return txs;
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
/** Removes protection from tx hashes and clears them from the protected map */
|
|
824
|
-
#clearProtection(txHashes: string[]): void {
|
|
825
|
-
for (const txHashStr of txHashes) {
|
|
826
|
-
this.#protectedTransactions.delete(txHashStr);
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
// --- Batch Operation Steps ---
|
|
831
|
-
|
|
832
|
-
/** Deletes a batch of transactions permanently */
|
|
833
|
-
async #deleteTxsBatch(txHashes: string[]): Promise<void> {
|
|
834
|
-
if (txHashes.length === 0) {
|
|
835
|
-
return;
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
await this.#store.transactionAsync(async () => {
|
|
839
|
-
for (const txHashStr of txHashes) {
|
|
840
|
-
await this.#deleteTx(txHashStr);
|
|
841
|
-
}
|
|
842
|
-
});
|
|
843
|
-
|
|
844
|
-
this.#callbacks.onTxsRemoved(txHashes);
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
// --- Block & Tx Info Steps ---
|
|
956
|
+
// ============================================================================
|
|
957
|
+
// PRIVATE HELPERS - Block & Hydration
|
|
958
|
+
// ============================================================================
|
|
848
959
|
|
|
849
|
-
/** Builds a block ID from a block header */
|
|
850
960
|
async #buildBlockId(block: BlockHeader): Promise<L2BlockId> {
|
|
851
961
|
return {
|
|
852
962
|
number: block.globalVariables.blockNumber,
|
|
@@ -866,50 +976,6 @@ export class TxPoolV2Impl {
|
|
|
866
976
|
};
|
|
867
977
|
}
|
|
868
978
|
|
|
869
|
-
/** Marks a batch of transactions as mined */
|
|
870
|
-
#markTxsAsMined(metas: TxMetaData[], blockId: L2BlockId): void {
|
|
871
|
-
for (const meta of metas) {
|
|
872
|
-
this.#markAsMined(meta, blockId);
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
// --- Add Transaction Steps ---
|
|
877
|
-
|
|
878
|
-
/** Persists a transaction to the database */
|
|
879
|
-
async #persistTx(txHashStr: string, tx: Tx): Promise<void> {
|
|
880
|
-
await this.#txsDB.set(txHashStr, tx.toBuffer());
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
/** Adds a new transaction as protected, returning its metadata */
|
|
884
|
-
async #addNewProtectedTx(tx: Tx, slotNumber: SlotNumber): Promise<TxMetaData> {
|
|
885
|
-
const txHashStr = tx.getTxHash().toString();
|
|
886
|
-
const meta = await buildTxMetaData(tx);
|
|
887
|
-
|
|
888
|
-
this.#protectedTransactions.set(txHashStr, slotNumber);
|
|
889
|
-
await this.#persistTx(txHashStr, tx);
|
|
890
|
-
this.#metadata.set(txHashStr, meta);
|
|
891
|
-
// Don't add to pending indices since it's protected
|
|
892
|
-
|
|
893
|
-
this.#log.verbose(`Added protected tx ${txHashStr} for slot ${slotNumber}`);
|
|
894
|
-
return meta;
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
/** Adds a new transaction as mined, returning its metadata */
|
|
898
|
-
async #addNewMinedTx(tx: Tx, blockId: L2BlockId): Promise<TxMetaData> {
|
|
899
|
-
const txHashStr = tx.getTxHash().toString();
|
|
900
|
-
const meta = await buildTxMetaData(tx);
|
|
901
|
-
meta.minedL2BlockId = blockId;
|
|
902
|
-
|
|
903
|
-
await this.#persistTx(txHashStr, tx);
|
|
904
|
-
this.#metadata.set(txHashStr, meta);
|
|
905
|
-
// Don't add to pending indices since it's mined
|
|
906
|
-
|
|
907
|
-
this.#log.verbose(`Added mined tx ${txHashStr} from block ${blockId.number}`);
|
|
908
|
-
return meta;
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
// --- Hydration Steps ---
|
|
912
|
-
|
|
913
979
|
/** Loads all transactions from the database, returning loaded txs and deserialization errors */
|
|
914
980
|
async #loadAllTxsFromDb(): Promise<{
|
|
915
981
|
loaded: { tx: Tx; meta: TxMetaData }[];
|
|
@@ -919,9 +985,15 @@ export class TxPoolV2Impl {
|
|
|
919
985
|
const errors: string[] = [];
|
|
920
986
|
|
|
921
987
|
for await (const [txHashStr, buffer] of this.#txsDB.entriesAsync()) {
|
|
988
|
+
// Skip soft-deleted transactions - they stay in DB but not in indices
|
|
989
|
+
if (this.#deletedPool.isSoftDeleted(txHashStr)) {
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
|
|
922
993
|
try {
|
|
923
994
|
const tx = Tx.fromBuffer(buffer);
|
|
924
|
-
const
|
|
995
|
+
const allowedSetupCalls = await this.#checkAllowedSetupCalls(tx);
|
|
996
|
+
const meta = await buildTxMetaData(tx, allowedSetupCalls);
|
|
925
997
|
loaded.push({ tx, meta });
|
|
926
998
|
} catch (err) {
|
|
927
999
|
this.#log.warn(`Failed to deserialize tx ${txHashStr}, deleting`, { err });
|
|
@@ -949,50 +1021,6 @@ export class TxPoolV2Impl {
|
|
|
949
1021
|
}
|
|
950
1022
|
}
|
|
951
1023
|
|
|
952
|
-
/** Partitions transactions by mined status */
|
|
953
|
-
#partitionByMinedStatus(txs: { tx: Tx; meta: TxMetaData }[]): {
|
|
954
|
-
mined: TxMetaData[];
|
|
955
|
-
nonMined: { tx: Tx; meta: TxMetaData }[];
|
|
956
|
-
} {
|
|
957
|
-
const mined: TxMetaData[] = [];
|
|
958
|
-
const nonMined: { tx: Tx; meta: TxMetaData }[] = [];
|
|
959
|
-
|
|
960
|
-
for (const entry of txs) {
|
|
961
|
-
if (entry.meta.minedL2BlockId !== undefined) {
|
|
962
|
-
mined.push(entry.meta);
|
|
963
|
-
} else {
|
|
964
|
-
nonMined.push(entry);
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
return { mined, nonMined };
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
/** Validates non-mined transactions, returning valid metadata and invalid hashes */
|
|
972
|
-
async #validateNonMinedTxs(txs: { tx: Tx; meta: TxMetaData }[]): Promise<{ valid: TxMetaData[]; invalid: string[] }> {
|
|
973
|
-
const valid: TxMetaData[] = [];
|
|
974
|
-
const invalid: string[] = [];
|
|
975
|
-
|
|
976
|
-
for (const { tx, meta } of txs) {
|
|
977
|
-
const result = await this.#pendingTxValidator.validateTx(tx);
|
|
978
|
-
if (result.result === 'valid') {
|
|
979
|
-
valid.push(meta);
|
|
980
|
-
} else {
|
|
981
|
-
this.#log.info(`Removing invalid tx ${meta.txHash} on startup: ${result.reason?.join(', ')}`);
|
|
982
|
-
invalid.push(meta.txHash);
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
return { valid, invalid };
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
/** Populates metadata index for mined transactions */
|
|
990
|
-
#populateMinedIndices(metas: TxMetaData[]): void {
|
|
991
|
-
for (const meta of metas) {
|
|
992
|
-
this.#metadata.set(meta.txHash, meta);
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
|
|
996
1024
|
/**
|
|
997
1025
|
* Rebuilds the pending pool by processing each tx through pre-add rules.
|
|
998
1026
|
* Starts with an empty pending pool and adds txs one by one, resolving conflicts.
|
|
@@ -1010,24 +1038,26 @@ export class TxPoolV2Impl {
|
|
|
1010
1038
|
if (preAddResult.shouldIgnore) {
|
|
1011
1039
|
// Transaction rejected - mark for deletion from DB
|
|
1012
1040
|
rejected.push(meta.txHash);
|
|
1013
|
-
this.#log.debug(
|
|
1041
|
+
this.#log.debug(
|
|
1042
|
+
`Rejected tx ${meta.txHash} during rebuild: ${preAddResult.reason?.message ?? 'unknown reason'}`,
|
|
1043
|
+
);
|
|
1014
1044
|
continue;
|
|
1015
1045
|
}
|
|
1016
1046
|
|
|
1017
1047
|
// Evict any conflicting txs identified by pre-add rules
|
|
1018
1048
|
for (const evictHashStr of preAddResult.txHashesToEvict) {
|
|
1019
|
-
const evictMeta = this.#
|
|
1049
|
+
const evictMeta = this.#indices.getMetadata(evictHashStr);
|
|
1020
1050
|
if (evictMeta) {
|
|
1021
|
-
this.#removeFromPendingIndices(evictMeta);
|
|
1022
|
-
this.#
|
|
1051
|
+
this.#indices.removeFromPendingIndices(evictMeta);
|
|
1052
|
+
this.#indices.remove(evictHashStr);
|
|
1023
1053
|
rejected.push(evictHashStr);
|
|
1024
1054
|
accepted.delete(evictHashStr);
|
|
1025
1055
|
this.#log.debug(`Evicted tx ${evictHashStr} during rebuild due to conflict with ${meta.txHash}`);
|
|
1026
1056
|
}
|
|
1027
1057
|
}
|
|
1028
1058
|
|
|
1029
|
-
// Add to
|
|
1030
|
-
this.#
|
|
1059
|
+
// Add to indices
|
|
1060
|
+
this.#indices.addPending(meta);
|
|
1031
1061
|
accepted.add(meta.txHash);
|
|
1032
1062
|
}
|
|
1033
1063
|
|
|
@@ -1035,207 +1065,32 @@ export class TxPoolV2Impl {
|
|
|
1035
1065
|
return { accepted: [...accepted], rejected };
|
|
1036
1066
|
}
|
|
1037
1067
|
|
|
1038
|
-
// --- Add Pending Tx Steps ---
|
|
1039
|
-
|
|
1040
|
-
/** Checks if a tx is a duplicate (already in pool) */
|
|
1041
|
-
#isDuplicateTx(txHashStr: string): boolean {
|
|
1042
|
-
return this.#metadata.has(txHashStr);
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
/** Adds a new pending tx to the pool, returning its metadata */
|
|
1046
|
-
async #addNewPendingTx(tx: Tx): Promise<TxMetaData> {
|
|
1047
|
-
const txHashStr = tx.getTxHash().toString();
|
|
1048
|
-
const meta = await buildTxMetaData(tx);
|
|
1049
|
-
|
|
1050
|
-
await this.#persistTx(txHashStr, tx);
|
|
1051
|
-
this.#addToIndices(meta);
|
|
1052
|
-
|
|
1053
|
-
this.#log.verbose(`Added tx ${txHashStr} to pool`, {
|
|
1054
|
-
eventName: 'tx-added-to-pool',
|
|
1055
|
-
state: this.#getTxState(meta),
|
|
1056
|
-
});
|
|
1057
|
-
|
|
1058
|
-
return meta;
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
1068
|
// ============================================================================
|
|
1062
|
-
//
|
|
1069
|
+
// PRIVATE HELPERS - Pool Access Adapters
|
|
1063
1070
|
// ============================================================================
|
|
1064
1071
|
|
|
1065
|
-
#addToIndices(meta: TxMetaData): void {
|
|
1066
|
-
this.#metadata.set(meta.txHash, meta);
|
|
1067
|
-
|
|
1068
|
-
if (this.#getTxState(meta) === 'pending') {
|
|
1069
|
-
this.#addToPendingIndices(meta);
|
|
1070
|
-
}
|
|
1071
|
-
// Protected and mined txs don't go into pending indices
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
#addToPendingIndices(meta: TxMetaData): void {
|
|
1075
|
-
// Add to nullifier index
|
|
1076
|
-
for (const nullifier of meta.nullifiers) {
|
|
1077
|
-
this.#nullifierToTxHash.set(nullifier, meta.txHash);
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
// Add to fee payer index
|
|
1081
|
-
let feePayerSet = this.#feePayerToTxHashes.get(meta.feePayer);
|
|
1082
|
-
if (!feePayerSet) {
|
|
1083
|
-
feePayerSet = new Set();
|
|
1084
|
-
this.#feePayerToTxHashes.set(meta.feePayer, feePayerSet);
|
|
1085
|
-
}
|
|
1086
|
-
feePayerSet.add(meta.txHash);
|
|
1087
|
-
|
|
1088
|
-
// Add to priority bucket
|
|
1089
|
-
let prioritySet = this.#pendingByPriority.get(meta.priorityFee);
|
|
1090
|
-
if (!prioritySet) {
|
|
1091
|
-
prioritySet = new Set();
|
|
1092
|
-
this.#pendingByPriority.set(meta.priorityFee, prioritySet);
|
|
1093
|
-
}
|
|
1094
|
-
prioritySet.add(meta.txHash);
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
#removeFromPendingIndices(meta: TxMetaData): void {
|
|
1098
|
-
// Remove from nullifier index
|
|
1099
|
-
for (const nullifier of meta.nullifiers) {
|
|
1100
|
-
this.#nullifierToTxHash.delete(nullifier);
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
// Remove from fee payer index
|
|
1104
|
-
const feePayerSet = this.#feePayerToTxHashes.get(meta.feePayer);
|
|
1105
|
-
if (feePayerSet) {
|
|
1106
|
-
feePayerSet.delete(meta.txHash);
|
|
1107
|
-
if (feePayerSet.size === 0) {
|
|
1108
|
-
this.#feePayerToTxHashes.delete(meta.feePayer);
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
1111
|
-
|
|
1112
|
-
// Remove from priority map
|
|
1113
|
-
const hashSet = this.#pendingByPriority.get(meta.priorityFee);
|
|
1114
|
-
if (hashSet) {
|
|
1115
|
-
hashSet.delete(meta.txHash);
|
|
1116
|
-
if (hashSet.size === 0) {
|
|
1117
|
-
this.#pendingByPriority.delete(meta.priorityFee);
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
#updateProtection(txHashStr: string, slotNumber: SlotNumber): void {
|
|
1123
|
-
const currentSlot = this.#protectedTransactions.get(txHashStr);
|
|
1124
|
-
|
|
1125
|
-
// Only update if not already protected at an equal or later slot
|
|
1126
|
-
if (currentSlot !== undefined && currentSlot >= slotNumber) {
|
|
1127
|
-
return;
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
// Remove from pending indices if transitioning from pending to protected
|
|
1131
|
-
if (currentSlot === undefined) {
|
|
1132
|
-
const meta = this.#metadata.get(txHashStr);
|
|
1133
|
-
if (meta) {
|
|
1134
|
-
this.#removeFromPendingIndices(meta);
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
|
-
this.#protectedTransactions.set(txHashStr, slotNumber);
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
#markAsMined(meta: TxMetaData, blockId: L2BlockId): void {
|
|
1142
|
-
meta.minedL2BlockId = blockId;
|
|
1143
|
-
// Safe to call unconditionally - removeFromPendingIndices is idempotent
|
|
1144
|
-
this.#removeFromPendingIndices(meta);
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
async #deleteTx(txHashStr: string): Promise<void> {
|
|
1148
|
-
const meta = this.#metadata.get(txHashStr);
|
|
1149
|
-
if (!meta) {
|
|
1150
|
-
return;
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
// Remove from all indices
|
|
1154
|
-
this.#metadata.delete(txHashStr);
|
|
1155
|
-
this.#protectedTransactions.delete(txHashStr);
|
|
1156
|
-
this.#removeFromPendingIndices(meta);
|
|
1157
|
-
|
|
1158
|
-
// Remove from persistence
|
|
1159
|
-
await this.#txsDB.delete(txHashStr);
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
// ============================================================================
|
|
1163
|
-
// HELPER FUNCTIONS - Adapters
|
|
1164
|
-
// ============================================================================
|
|
1165
|
-
|
|
1166
|
-
/** Gets all pending transactions for a given fee payer. */
|
|
1167
|
-
#getFeePayerPendingTxs(feePayer: string): TxMetaData[] {
|
|
1168
|
-
const txHashes = this.#feePayerToTxHashes.get(feePayer);
|
|
1169
|
-
if (!txHashes) {
|
|
1170
|
-
return [];
|
|
1171
|
-
}
|
|
1172
|
-
const result: TxMetaData[] = [];
|
|
1173
|
-
for (const txHashStr of txHashes) {
|
|
1174
|
-
const meta = this.#metadata.get(txHashStr);
|
|
1175
|
-
if (meta && this.#getTxState(meta) === 'pending') {
|
|
1176
|
-
result.push(meta);
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
return result;
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
/**
|
|
1183
|
-
* Creates a PoolOperations adapter for use with the eviction manager.
|
|
1184
|
-
*/
|
|
1185
1072
|
#createPoolOperations(): PoolOperations {
|
|
1186
1073
|
return {
|
|
1187
|
-
getPendingTxs: ()
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
result.push(meta);
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
}
|
|
1197
|
-
return result;
|
|
1198
|
-
},
|
|
1199
|
-
getPendingFeePayers: (): string[] => {
|
|
1200
|
-
return Array.from(this.#feePayerToTxHashes.keys());
|
|
1201
|
-
},
|
|
1202
|
-
getFeePayerPendingTxs: (feePayer: string): TxMetaData[] => {
|
|
1203
|
-
return this.#getFeePayerPendingTxs(feePayer);
|
|
1204
|
-
},
|
|
1205
|
-
getPendingTxCount: (): number => {
|
|
1206
|
-
return this.getPendingTxCount();
|
|
1207
|
-
},
|
|
1208
|
-
getLowestPriorityPending: (limit: number): string[] => {
|
|
1209
|
-
return this.getLowestPriorityPending(limit).map(h => h.toString());
|
|
1210
|
-
},
|
|
1211
|
-
deleteTxs: async (txHashes: string[]): Promise<void> => {
|
|
1212
|
-
await this.#store.transactionAsync(async () => {
|
|
1213
|
-
for (const txHashStr of txHashes) {
|
|
1214
|
-
await this.#deleteTx(txHashStr);
|
|
1215
|
-
}
|
|
1216
|
-
});
|
|
1217
|
-
this.#callbacks.onTxsRemoved(txHashes);
|
|
1218
|
-
},
|
|
1074
|
+
getPendingTxs: () => this.#indices.getPendingTxs(),
|
|
1075
|
+
getPendingFeePayers: () => this.#indices.getPendingFeePayers(),
|
|
1076
|
+
getFeePayerPendingTxs: (feePayer: string) => this.#indices.getFeePayerPendingTxs(feePayer),
|
|
1077
|
+
getPendingTxCount: () => this.#indices.getPendingTxCount(),
|
|
1078
|
+
getLowestPriorityPending: (limit: number) => this.#indices.getLowestPriorityPending(limit),
|
|
1079
|
+
deleteTxs: (txHashes: string[], reason?: string) => this.#evictTxs(txHashes, reason ?? 'unknown'),
|
|
1219
1080
|
};
|
|
1220
1081
|
}
|
|
1221
1082
|
|
|
1222
|
-
/**
|
|
1223
|
-
* Creates a PreAddPoolAccess adapter for use with pre-add eviction rules.
|
|
1224
|
-
* All methods work with strings and TxMetaData for efficiency.
|
|
1225
|
-
*/
|
|
1226
1083
|
#createPreAddPoolAccess(): PreAddPoolAccess {
|
|
1227
1084
|
return {
|
|
1228
|
-
getMetadata: (txHashStr: string)
|
|
1229
|
-
const meta = this.#
|
|
1230
|
-
if (!meta || this.#getTxState(meta) !== 'pending') {
|
|
1085
|
+
getMetadata: (txHashStr: string) => {
|
|
1086
|
+
const meta = this.#indices.getMetadata(txHashStr);
|
|
1087
|
+
if (!meta || this.#indices.getTxState(meta) !== 'pending') {
|
|
1231
1088
|
return undefined;
|
|
1232
1089
|
}
|
|
1233
1090
|
return meta;
|
|
1234
1091
|
},
|
|
1235
|
-
getTxHashByNullifier: (nullifier: string)
|
|
1236
|
-
|
|
1237
|
-
},
|
|
1238
|
-
getFeePayerBalance: async (feePayer: string): Promise<bigint> => {
|
|
1092
|
+
getTxHashByNullifier: (nullifier: string) => this.#indices.getTxHashByNullifier(nullifier),
|
|
1093
|
+
getFeePayerBalance: async (feePayer: string) => {
|
|
1239
1094
|
const db = this.#worldStateSynchronizer.getCommitted();
|
|
1240
1095
|
const publicStateSource = new DatabasePublicStateSource(db);
|
|
1241
1096
|
const balance = await publicStateSource.storageRead(
|
|
@@ -1244,22 +1099,9 @@ export class TxPoolV2Impl {
|
|
|
1244
1099
|
);
|
|
1245
1100
|
return balance.toBigInt();
|
|
1246
1101
|
},
|
|
1247
|
-
getFeePayerPendingTxs: (feePayer: string)
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
getPendingTxCount: (): number => {
|
|
1251
|
-
return this.getPendingTxCount();
|
|
1252
|
-
},
|
|
1253
|
-
getLowestPriorityPendingTx: (): TxMetaData | undefined => {
|
|
1254
|
-
// Iterate in ascending order to find the lowest priority
|
|
1255
|
-
for (const txHashStr of this.#iteratePendingByPriority('asc')) {
|
|
1256
|
-
const meta = this.#metadata.get(txHashStr);
|
|
1257
|
-
if (meta) {
|
|
1258
|
-
return meta;
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
return undefined;
|
|
1262
|
-
},
|
|
1102
|
+
getFeePayerPendingTxs: (feePayer: string) => this.#indices.getFeePayerPendingTxs(feePayer),
|
|
1103
|
+
getPendingTxCount: () => this.#indices.getPendingTxCount(),
|
|
1104
|
+
getLowestPriorityPendingTx: () => this.#indices.getLowestPriorityPendingTx(),
|
|
1263
1105
|
};
|
|
1264
1106
|
}
|
|
1265
1107
|
}
|