@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,12 +1,16 @@
|
|
|
1
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
2
3
|
import { computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
|
|
3
4
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
4
5
|
import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
|
|
5
6
|
import { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
6
7
|
import { TxArchive } from './archive/index.js';
|
|
7
|
-
import {
|
|
8
|
+
import { DeletedPool } from './deleted_pool.js';
|
|
9
|
+
import { EvictionManager, FeePayerBalanceEvictionRule, FeePayerBalancePreAddRule, InsufficientFeePerGasEvictionRule, InvalidTxsAfterMiningRule, InvalidTxsAfterReorgRule, LowPriorityEvictionRule, LowPriorityPreAddRule, NullifierConflictRule, TxPoolRejectionCode } from './eviction/index.js';
|
|
10
|
+
import { TxPoolV2Instrumentation } from './instrumentation.js';
|
|
8
11
|
import { DEFAULT_TX_POOL_V2_CONFIG } from './interfaces.js';
|
|
9
|
-
import { buildTxMetaData, checkNullifierConflict
|
|
12
|
+
import { buildTxMetaData, checkNullifierConflict } from './tx_metadata.js';
|
|
13
|
+
import { TxPoolIndices } from './tx_pool_indices.js';
|
|
10
14
|
/**
|
|
11
15
|
* Implementation of TxPoolV2 logic.
|
|
12
16
|
*
|
|
@@ -18,33 +22,35 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
18
22
|
// === Dependencies ===
|
|
19
23
|
#l2BlockSource;
|
|
20
24
|
#worldStateSynchronizer;
|
|
21
|
-
#
|
|
25
|
+
#createTxValidator;
|
|
26
|
+
#checkAllowedSetupCalls;
|
|
22
27
|
// === In-Memory Indices ===
|
|
23
|
-
|
|
24
|
-
/** Nullifier to txHash index (pending txs only) */ #nullifierToTxHash = new Map();
|
|
25
|
-
/** Fee payer to txHashes index (pending txs only) */ #feePayerToTxHashes = new Map();
|
|
26
|
-
/**
|
|
27
|
-
* Pending txHashes grouped by priority fee.
|
|
28
|
-
* Outer map: priorityFee -> Set of txHashes at that fee level.
|
|
29
|
-
*/ #pendingByPriority = new Map();
|
|
30
|
-
/** Protected transactions: txHash -> slotNumber. Includes txs we have and txs we expect to receive. */ #protectedTransactions = new Map();
|
|
28
|
+
#indices = new TxPoolIndices();
|
|
31
29
|
// === Config & Services ===
|
|
32
30
|
#config;
|
|
33
31
|
#archive;
|
|
32
|
+
#deletedPool;
|
|
34
33
|
#evictionManager;
|
|
34
|
+
#dateProvider;
|
|
35
|
+
#instrumentation;
|
|
36
|
+
#evictedTxHashes = new Set();
|
|
35
37
|
#log;
|
|
36
38
|
#callbacks;
|
|
37
|
-
constructor(store, archiveStore, deps, callbacks, config = {}, log){
|
|
39
|
+
constructor(store, archiveStore, deps, callbacks, telemetry, config = {}, dateProvider, log){
|
|
38
40
|
this.#store = store;
|
|
39
41
|
this.#txsDB = store.openMap('txs');
|
|
40
42
|
this.#l2BlockSource = deps.l2BlockSource;
|
|
41
43
|
this.#worldStateSynchronizer = deps.worldStateSynchronizer;
|
|
42
|
-
this.#
|
|
44
|
+
this.#createTxValidator = deps.createTxValidator;
|
|
45
|
+
this.#checkAllowedSetupCalls = deps.checkAllowedSetupCalls;
|
|
43
46
|
this.#config = {
|
|
44
47
|
...DEFAULT_TX_POOL_V2_CONFIG,
|
|
45
48
|
...config
|
|
46
49
|
};
|
|
47
50
|
this.#archive = new TxArchive(archiveStore, this.#config.archivedTxLimit, log);
|
|
51
|
+
this.#deletedPool = new DeletedPool(store, this.#txsDB, log);
|
|
52
|
+
this.#dateProvider = dateProvider;
|
|
53
|
+
this.#instrumentation = new TxPoolV2Instrumentation(telemetry, ()=>this.#indices.getTotalMetadataBytes());
|
|
48
54
|
this.#log = log;
|
|
49
55
|
this.#callbacks = callbacks;
|
|
50
56
|
// Setup eviction manager with rules
|
|
@@ -57,6 +63,7 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
57
63
|
}));
|
|
58
64
|
// Post-event eviction rules (run after events to check ALL pending txs)
|
|
59
65
|
this.#evictionManager.registerRule(new InvalidTxsAfterMiningRule());
|
|
66
|
+
this.#evictionManager.registerRule(new InsufficientFeePerGasEvictionRule(deps.blockMinFeesProvider));
|
|
60
67
|
this.#evictionManager.registerRule(new InvalidTxsAfterReorgRule(deps.worldStateSynchronizer));
|
|
61
68
|
this.#evictionManager.registerRule(new FeePayerBalanceEvictionRule(deps.worldStateSynchronizer));
|
|
62
69
|
// LowPriorityEvictionRule handles cases where txs become pending via prepareForSlot (unprotect)
|
|
@@ -75,20 +82,32 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
75
82
|
* Note: Protected status is lost on restart. All non-mined txs are rebuilt as pending
|
|
76
83
|
* by running pre-add rules to resolve nullifier conflicts, balance checks, and pool size limits.
|
|
77
84
|
*/ async hydrateFromDatabase() {
|
|
78
|
-
// Step
|
|
85
|
+
// Step 0: Hydrate deleted pool state
|
|
86
|
+
await this.#deletedPool.hydrateFromDatabase();
|
|
87
|
+
// Step 1: Load all transactions from DB (excluding soft-deleted)
|
|
79
88
|
const { loaded, errors: deserializationErrors } = await this.#loadAllTxsFromDb();
|
|
80
89
|
// Step 2: Check mined status for each tx
|
|
81
90
|
await this.#markMinedStatusBatch(loaded.map((l)=>l.meta));
|
|
82
91
|
// Step 3: Partition by mined status
|
|
83
|
-
const
|
|
92
|
+
const mined = [];
|
|
93
|
+
const nonMined = [];
|
|
94
|
+
for (const entry of loaded){
|
|
95
|
+
if (entry.meta.minedL2BlockId !== undefined) {
|
|
96
|
+
mined.push(entry.meta);
|
|
97
|
+
} else {
|
|
98
|
+
nonMined.push(entry);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
84
101
|
// Step 4: Validate non-mined transactions
|
|
85
|
-
const { valid, invalid } = await this.#
|
|
102
|
+
const { valid, invalid } = await this.#revalidateMetadata(nonMined.map((e)=>e.meta), 'on startup');
|
|
86
103
|
// Step 5: Populate mined indices (these don't need conflict resolution)
|
|
87
|
-
|
|
104
|
+
for (const meta of mined){
|
|
105
|
+
this.#indices.addMined(meta);
|
|
106
|
+
}
|
|
88
107
|
// Step 6: Rebuild pending pool by running pre-add rules for each tx
|
|
89
108
|
// This resolves nullifier conflicts, fee payer balance issues, and pool size limits
|
|
90
109
|
const { rejected } = await this.#rebuildPendingPool(valid);
|
|
91
|
-
// Step 7: Delete invalid and rejected txs from DB
|
|
110
|
+
// Step 7: Delete invalid and rejected txs from DB only (indices were never populated for these)
|
|
92
111
|
const toDelete = [
|
|
93
112
|
...deserializationErrors,
|
|
94
113
|
...invalid,
|
|
@@ -102,104 +121,158 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
102
121
|
await this.#txsDB.delete(txHashStr);
|
|
103
122
|
}
|
|
104
123
|
});
|
|
105
|
-
this.#log.info(`Deleted ${toDelete.length} invalid/rejected transactions on startup
|
|
124
|
+
this.#log.info(`Deleted ${toDelete.length} invalid/rejected transactions on startup`, {
|
|
125
|
+
txHashes: toDelete
|
|
126
|
+
});
|
|
106
127
|
}
|
|
107
128
|
async addPendingTxs(txs, opts) {
|
|
108
129
|
const accepted = [];
|
|
109
130
|
const ignored = [];
|
|
110
131
|
const rejected = [];
|
|
111
|
-
const
|
|
132
|
+
const errors = new Map();
|
|
112
133
|
const acceptedPending = new Set();
|
|
134
|
+
// Phase 1: Pre-compute all throwable I/O outside the transaction.
|
|
135
|
+
// If any pre-computation throws, the entire call fails before mutations happen.
|
|
136
|
+
const precomputed = new Map();
|
|
137
|
+
const validator = await this.#createTxValidator();
|
|
138
|
+
for (const tx of txs){
|
|
139
|
+
const txHash = tx.getTxHash();
|
|
140
|
+
const txHashStr = txHash.toString();
|
|
141
|
+
const meta = await buildTxMetaData(tx);
|
|
142
|
+
const minedBlockId = await this.#getMinedBlockId(txHash);
|
|
143
|
+
// Validate non-mined txs (mined and pre-protected txs bypass validation inside the transaction)
|
|
144
|
+
let isValid = true;
|
|
145
|
+
if (!minedBlockId) {
|
|
146
|
+
isValid = await this.#validateMeta(meta, validator);
|
|
147
|
+
}
|
|
148
|
+
precomputed.set(txHashStr, {
|
|
149
|
+
meta,
|
|
150
|
+
minedBlockId,
|
|
151
|
+
isValid
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
// Phase 2: Apply mutations inside the transaction using only pre-computed results,
|
|
155
|
+
// in-memory reads, and buffered DB writes. Nothing here can throw an unhandled exception.
|
|
113
156
|
const poolAccess = this.#createPreAddPoolAccess();
|
|
157
|
+
const preAddContext = opts.feeComparisonOnly !== undefined ? {
|
|
158
|
+
feeComparisonOnly: opts.feeComparisonOnly,
|
|
159
|
+
priceBumpPercentage: this.#config.priceBumpPercentage
|
|
160
|
+
} : undefined;
|
|
114
161
|
await this.#store.transactionAsync(async ()=>{
|
|
115
162
|
for (const tx of txs){
|
|
116
163
|
const txHash = tx.getTxHash();
|
|
117
164
|
const txHashStr = txHash.toString();
|
|
118
165
|
// Skip duplicates
|
|
119
|
-
if (this.#
|
|
166
|
+
if (this.#indices.has(txHashStr)) {
|
|
120
167
|
ignored.push(txHash);
|
|
121
168
|
continue;
|
|
122
169
|
}
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
const preProtectedSlot = this.#protectedTransactions.get(txHashStr);
|
|
170
|
+
const { meta, minedBlockId, isValid } = precomputed.get(txHashStr);
|
|
171
|
+
const preProtectedSlot = this.#indices.getProtectionSlot(txHashStr);
|
|
126
172
|
if (minedBlockId) {
|
|
127
173
|
// Already mined - add directly (protection already set if pre-protected)
|
|
128
|
-
await this.#
|
|
174
|
+
await this.#addTx(tx, {
|
|
175
|
+
mined: minedBlockId
|
|
176
|
+
}, opts, meta);
|
|
129
177
|
accepted.push(txHash);
|
|
130
|
-
newlyAdded.push(tx);
|
|
131
178
|
} else if (preProtectedSlot !== undefined) {
|
|
132
179
|
// Pre-protected and not mined - add as protected (bypass validation)
|
|
133
|
-
await this.#
|
|
180
|
+
await this.#addTx(tx, {
|
|
181
|
+
protected: preProtectedSlot
|
|
182
|
+
}, opts, meta);
|
|
134
183
|
accepted.push(txHash);
|
|
135
|
-
|
|
184
|
+
} else if (!isValid) {
|
|
185
|
+
// Failed pre-computed validation
|
|
186
|
+
rejected.push(txHash);
|
|
136
187
|
} else {
|
|
137
|
-
// Regular pending tx -
|
|
138
|
-
const result = await this.#tryAddRegularPendingTx(tx, poolAccess, acceptedPending, ignored);
|
|
188
|
+
// Regular pending tx - run pre-add rules using pre-computed metadata
|
|
189
|
+
const result = await this.#tryAddRegularPendingTx(tx, meta, opts, poolAccess, acceptedPending, ignored, errors, preAddContext);
|
|
139
190
|
if (result.status === 'accepted') {
|
|
140
191
|
acceptedPending.add(txHashStr);
|
|
141
|
-
newlyAdded.push(tx);
|
|
142
|
-
} else if (result.status === 'rejected') {
|
|
143
|
-
rejected.push(txHash);
|
|
144
192
|
} else {
|
|
145
193
|
ignored.push(txHash);
|
|
146
194
|
}
|
|
147
195
|
}
|
|
148
196
|
}
|
|
197
|
+
// Run post-add eviction rules for pending txs (inside transaction for atomicity)
|
|
198
|
+
if (acceptedPending.size > 0) {
|
|
199
|
+
const feePayers = Array.from(acceptedPending).map((txHash)=>this.#indices.getMetadata(txHash).feePayer);
|
|
200
|
+
const uniqueFeePayers = new Set(feePayers);
|
|
201
|
+
await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [
|
|
202
|
+
...uniqueFeePayers
|
|
203
|
+
]);
|
|
204
|
+
}
|
|
149
205
|
});
|
|
150
206
|
// Build final accepted list for pending txs (excludes intra-batch evictions)
|
|
151
207
|
for (const txHashStr of acceptedPending){
|
|
152
208
|
accepted.push(TxHash.fromString(txHashStr));
|
|
153
209
|
}
|
|
154
|
-
//
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
const uniqueFeePayers = new Set(feePayers);
|
|
158
|
-
await this.#evictionManager.evictAfterNewTxs(Array.from(acceptedPending), [
|
|
159
|
-
...uniqueFeePayers
|
|
160
|
-
]);
|
|
210
|
+
// Record metrics
|
|
211
|
+
if (ignored.length > 0) {
|
|
212
|
+
this.#instrumentation.recordIgnored(ignored.length);
|
|
161
213
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
this.#callbacks.onTxsAdded(newlyAdded, opts);
|
|
214
|
+
if (rejected.length > 0) {
|
|
215
|
+
this.#instrumentation.recordRejected(rejected.length);
|
|
165
216
|
}
|
|
166
217
|
return {
|
|
167
218
|
accepted,
|
|
168
219
|
ignored,
|
|
169
|
-
rejected
|
|
220
|
+
rejected,
|
|
221
|
+
...errors.size > 0 ? {
|
|
222
|
+
errors
|
|
223
|
+
} : {}
|
|
170
224
|
};
|
|
171
225
|
}
|
|
172
|
-
/**
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const validationResult = await this.#pendingTxValidator.validateTx(tx);
|
|
177
|
-
if (validationResult.result !== 'valid') {
|
|
178
|
-
this.#log.info(`Rejecting tx ${txHashStr}: ${validationResult.reason?.join(', ')}`);
|
|
179
|
-
return {
|
|
180
|
-
status: 'rejected'
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
// Build metadata and run pre-add rules
|
|
184
|
-
const meta = await buildTxMetaData(tx);
|
|
185
|
-
const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
|
|
226
|
+
/** Adds a validated pending tx, running pre-add rules and evicting conflicts. */ async #tryAddRegularPendingTx(tx, precomputedMeta, opts, poolAccess, acceptedPending, ignored, errors, preAddContext) {
|
|
227
|
+
const txHashStr = tx.getTxHash().toString();
|
|
228
|
+
// Run pre-add rules
|
|
229
|
+
const preAddResult = await this.#evictionManager.runPreAddRules(precomputedMeta, poolAccess, preAddContext);
|
|
186
230
|
if (preAddResult.shouldIgnore) {
|
|
187
|
-
this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason}`);
|
|
231
|
+
this.#log.debug(`Ignoring tx ${txHashStr}: ${preAddResult.reason?.message ?? 'unknown reason'}`);
|
|
232
|
+
if (preAddResult.reason && preAddResult.reason.code !== TxPoolRejectionCode.INTERNAL_ERROR) {
|
|
233
|
+
errors.set(txHashStr, preAddResult.reason);
|
|
234
|
+
}
|
|
188
235
|
return {
|
|
189
236
|
status: 'ignored'
|
|
190
237
|
};
|
|
191
238
|
}
|
|
192
|
-
// Evict conflicts
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
239
|
+
// Evict conflicts, grouped by rule name for metrics
|
|
240
|
+
if (preAddResult.evictions && preAddResult.evictions.length > 0) {
|
|
241
|
+
const byReason = new Map();
|
|
242
|
+
for (const { txHash: evictHash, reason } of preAddResult.evictions){
|
|
243
|
+
const group = byReason.get(reason);
|
|
244
|
+
if (group) {
|
|
245
|
+
group.push(evictHash);
|
|
246
|
+
} else {
|
|
247
|
+
byReason.set(reason, [
|
|
248
|
+
evictHash
|
|
249
|
+
]);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
for (const [reason, hashes] of byReason){
|
|
253
|
+
await this.#evictTxs(hashes, reason);
|
|
199
254
|
}
|
|
255
|
+
for (const evictHashStr of preAddResult.txHashesToEvict){
|
|
256
|
+
this.#log.debug(`Evicted tx ${evictHashStr} due to higher-fee tx ${txHashStr}`, {
|
|
257
|
+
evictedTxHash: evictHashStr,
|
|
258
|
+
replacementTxHash: txHashStr
|
|
259
|
+
});
|
|
260
|
+
if (acceptedPending.has(evictHashStr)) {
|
|
261
|
+
// Evicted tx was from this batch - mark as ignored in result
|
|
262
|
+
acceptedPending.delete(evictHashStr);
|
|
263
|
+
ignored.push(TxHash.fromString(evictHashStr));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// Randomly drop the transaction for testing purposes (report as accepted so it propagates)
|
|
268
|
+
if (this.#config.dropTransactionsProbability > 0 && Math.random() < this.#config.dropTransactionsProbability) {
|
|
269
|
+
this.#log.debug(`Dropping tx ${txHashStr} (simulated drop for testing)`);
|
|
270
|
+
return {
|
|
271
|
+
status: 'accepted'
|
|
272
|
+
};
|
|
200
273
|
}
|
|
201
274
|
// Add the transaction
|
|
202
|
-
await this.#
|
|
275
|
+
await this.#addTx(tx, 'pending', opts, precomputedMeta);
|
|
203
276
|
return {
|
|
204
277
|
status: 'accepted'
|
|
205
278
|
};
|
|
@@ -207,89 +280,125 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
207
280
|
async canAddPendingTx(tx) {
|
|
208
281
|
const txHashStr = tx.getTxHash().toString();
|
|
209
282
|
// Check if already in pool
|
|
210
|
-
if (this.#
|
|
283
|
+
if (this.#indices.has(txHashStr)) {
|
|
284
|
+
this.#log.verbose(`canAddPendingTx: tx ${txHashStr} already in pool`);
|
|
211
285
|
return 'ignored';
|
|
212
286
|
}
|
|
213
|
-
//
|
|
214
|
-
const validationResult = await this.#pendingTxValidator.validateTx(tx);
|
|
215
|
-
if (validationResult.result !== 'valid') {
|
|
216
|
-
return 'rejected';
|
|
217
|
-
}
|
|
218
|
-
// Build metadata and use pre-add rules
|
|
287
|
+
// Build metadata and check pre-add rules
|
|
219
288
|
const meta = await buildTxMetaData(tx);
|
|
220
289
|
const poolAccess = this.#createPreAddPoolAccess();
|
|
221
290
|
const preAddResult = await this.#evictionManager.runPreAddRules(meta, poolAccess);
|
|
222
|
-
|
|
291
|
+
if (preAddResult.shouldIgnore) {
|
|
292
|
+
this.#log.verbose(`canAddPendingTx: tx ${txHashStr} ignored by pre-add rule`, {
|
|
293
|
+
reason: preAddResult.reason?.message ?? 'no reason provided'
|
|
294
|
+
});
|
|
295
|
+
return 'ignored';
|
|
296
|
+
}
|
|
297
|
+
return 'accepted';
|
|
223
298
|
}
|
|
224
299
|
async addProtectedTxs(txs, block, opts) {
|
|
225
300
|
const slotNumber = block.globalVariables.slotNumber;
|
|
226
|
-
|
|
301
|
+
// Precompute setup-call allow-list flags outside the store transaction
|
|
302
|
+
const allowedFlags = await Promise.all(txs.map((tx)=>this.#checkAllowedSetupCalls(tx)));
|
|
227
303
|
await this.#store.transactionAsync(async ()=>{
|
|
228
|
-
for
|
|
304
|
+
for(let i = 0; i < txs.length; i++){
|
|
305
|
+
const tx = txs[i];
|
|
229
306
|
const txHash = tx.getTxHash();
|
|
230
307
|
const txHashStr = txHash.toString();
|
|
231
|
-
const isNew = !this.#
|
|
308
|
+
const isNew = !this.#indices.has(txHashStr);
|
|
232
309
|
const minedBlockId = await this.#getMinedBlockId(txHash);
|
|
233
310
|
if (isNew) {
|
|
234
|
-
|
|
311
|
+
const meta = await buildTxMetaData(tx, allowedFlags[i]);
|
|
312
|
+
// New tx - add as mined or protected (callback emitted by #addTx)
|
|
235
313
|
if (minedBlockId) {
|
|
236
|
-
await this.#
|
|
237
|
-
|
|
314
|
+
await this.#addTx(tx, {
|
|
315
|
+
mined: minedBlockId
|
|
316
|
+
}, opts, meta);
|
|
317
|
+
this.#indices.setProtection(txHashStr, slotNumber);
|
|
238
318
|
} else {
|
|
239
|
-
await this.#
|
|
319
|
+
await this.#addTx(tx, {
|
|
320
|
+
protected: slotNumber
|
|
321
|
+
}, opts, meta);
|
|
240
322
|
}
|
|
241
|
-
newlyAdded.push(tx);
|
|
242
323
|
} else {
|
|
243
324
|
// Existing tx - update protection and mined status
|
|
244
|
-
this.#updateProtection(txHashStr, slotNumber);
|
|
325
|
+
this.#indices.updateProtection(txHashStr, slotNumber);
|
|
245
326
|
if (minedBlockId) {
|
|
246
|
-
this.#
|
|
327
|
+
const meta = this.#indices.getMetadata(txHashStr);
|
|
328
|
+
this.#indices.markAsMined(meta, minedBlockId);
|
|
247
329
|
}
|
|
248
330
|
}
|
|
249
331
|
}
|
|
250
332
|
});
|
|
251
|
-
if (newlyAdded.length > 0) {
|
|
252
|
-
this.#callbacks.onTxsAdded(newlyAdded, opts);
|
|
253
|
-
}
|
|
254
333
|
}
|
|
255
|
-
protectTxs(txHashes, block) {
|
|
334
|
+
async protectTxs(txHashes, block) {
|
|
256
335
|
const slotNumber = block.globalVariables.slotNumber;
|
|
257
336
|
const missing = [];
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
337
|
+
let softDeletedHits = 0;
|
|
338
|
+
let missingPreviouslyEvicted = 0;
|
|
339
|
+
await this.#store.transactionAsync(async ()=>{
|
|
340
|
+
for (const txHash of txHashes){
|
|
341
|
+
const txHashStr = txHash.toString();
|
|
342
|
+
if (this.#indices.has(txHashStr)) {
|
|
343
|
+
// Update protection for existing tx
|
|
344
|
+
this.#indices.updateProtection(txHashStr, slotNumber);
|
|
345
|
+
} else if (this.#deletedPool.isSoftDeleted(txHashStr)) {
|
|
346
|
+
// Resurrect soft-deleted tx as protected
|
|
347
|
+
const buffer = await this.#txsDB.getAsync(txHashStr);
|
|
348
|
+
if (buffer) {
|
|
349
|
+
const tx = Tx.fromBuffer(buffer);
|
|
350
|
+
await this.#addTx(tx, {
|
|
351
|
+
protected: slotNumber
|
|
352
|
+
});
|
|
353
|
+
softDeletedHits++;
|
|
354
|
+
} else {
|
|
355
|
+
// Data missing despite soft-delete flag — treat as truly missing
|
|
356
|
+
this.#indices.setProtection(txHashStr, slotNumber);
|
|
357
|
+
missing.push(txHash);
|
|
358
|
+
}
|
|
359
|
+
} else {
|
|
360
|
+
// Truly missing — pre-record protection for tx we don't have yet
|
|
361
|
+
this.#indices.setProtection(txHashStr, slotNumber);
|
|
362
|
+
missing.push(txHash);
|
|
363
|
+
if (this.#evictedTxHashes.has(txHashStr)) {
|
|
364
|
+
missingPreviouslyEvicted++;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
267
367
|
}
|
|
368
|
+
});
|
|
369
|
+
// Record metrics
|
|
370
|
+
if (softDeletedHits > 0) {
|
|
371
|
+
this.#instrumentation.recordSoftDeletedHits(softDeletedHits);
|
|
372
|
+
}
|
|
373
|
+
if (missing.length > 0) {
|
|
374
|
+
this.#log.debug(`protectTxs missing tx hashes: ${missing.map((h)=>h.toString()).join(', ')}`);
|
|
375
|
+
this.#instrumentation.recordMissingOnProtect(missing.length);
|
|
376
|
+
}
|
|
377
|
+
if (missingPreviouslyEvicted > 0) {
|
|
378
|
+
this.#instrumentation.recordMissingPreviouslyEvicted(missingPreviouslyEvicted);
|
|
268
379
|
}
|
|
380
|
+
this.#log.info(`Protected ${txHashes.length} txs, missing: ${missing.length}, soft-deleted hits: ${softDeletedHits}`);
|
|
269
381
|
return missing;
|
|
270
382
|
}
|
|
271
383
|
async addMinedTxs(txs, block, opts) {
|
|
272
384
|
// Step 1: Build block ID
|
|
273
385
|
const blockId = await this.#buildBlockId(block);
|
|
274
|
-
const newlyAdded = [];
|
|
275
386
|
await this.#store.transactionAsync(async ()=>{
|
|
276
387
|
for (const tx of txs){
|
|
277
388
|
const txHashStr = tx.getTxHash().toString();
|
|
278
|
-
const existingMeta = this.#
|
|
389
|
+
const existingMeta = this.#indices.getMetadata(txHashStr);
|
|
279
390
|
if (existingMeta) {
|
|
280
|
-
//
|
|
281
|
-
this.#markAsMined(existingMeta, blockId);
|
|
391
|
+
// Mark existing tx as mined
|
|
392
|
+
this.#indices.markAsMined(existingMeta, blockId);
|
|
282
393
|
} else {
|
|
283
|
-
//
|
|
284
|
-
await this.#
|
|
285
|
-
|
|
394
|
+
// Add new mined tx (callback emitted by #addTx)
|
|
395
|
+
await this.#addTx(tx, {
|
|
396
|
+
mined: blockId
|
|
397
|
+
}, opts);
|
|
286
398
|
}
|
|
399
|
+
await this.#deletedPool.clearIfMinedHigher(txHashStr, blockId.number);
|
|
287
400
|
}
|
|
288
401
|
});
|
|
289
|
-
// Step 3: Emit events for newly added txs
|
|
290
|
-
if (newlyAdded.length > 0) {
|
|
291
|
-
this.#callbacks.onTxsAdded(newlyAdded, opts);
|
|
292
|
-
}
|
|
293
402
|
}
|
|
294
403
|
async handleMinedBlock(block) {
|
|
295
404
|
// Step 1: Build block ID
|
|
@@ -301,102 +410,141 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
301
410
|
const feePayers = [];
|
|
302
411
|
const found = [];
|
|
303
412
|
for (const txHash of txHashes){
|
|
304
|
-
const meta = this.#
|
|
413
|
+
const meta = this.#indices.getMetadata(txHash.toString());
|
|
305
414
|
if (meta) {
|
|
306
415
|
feePayers.push(meta.feePayer);
|
|
307
416
|
found.push(meta);
|
|
308
417
|
}
|
|
309
418
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
419
|
+
await this.#store.transactionAsync(async ()=>{
|
|
420
|
+
// Step 4: Mark txs as mined (only those we have in the pool)
|
|
421
|
+
for (const meta of found){
|
|
422
|
+
this.#indices.markAsMined(meta, blockId);
|
|
423
|
+
await this.#deletedPool.clearIfMinedHigher(meta.txHash, blockId.number);
|
|
424
|
+
}
|
|
425
|
+
// Step 5: Run post-event eviction rules (inside transaction for atomicity)
|
|
426
|
+
await this.#evictionManager.evictAfterNewBlock(block.header, nullifiers, feePayers);
|
|
427
|
+
});
|
|
428
|
+
if (found.length > 0) {
|
|
429
|
+
this.#callbacks.onTxsMined(found.map((m)=>m.txHash));
|
|
430
|
+
}
|
|
315
431
|
this.#log.info(`Marked ${found.length} txs as mined in block ${blockId.number}`);
|
|
316
432
|
}
|
|
317
433
|
async prepareForSlot(slotNumber) {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
434
|
+
await this.#store.transactionAsync(async ()=>{
|
|
435
|
+
// Step 0: Clean up slot-deleted txs from previous slots
|
|
436
|
+
await this.#deletedPool.cleanupSlotDeleted(slotNumber);
|
|
437
|
+
// Step 1: Find expired protected txs
|
|
438
|
+
const expiredProtected = this.#indices.findExpiredProtectedTxs(slotNumber);
|
|
439
|
+
// Step 2: Clear protection for all expired entries (including those without metadata)
|
|
440
|
+
this.#indices.clearProtection(expiredProtected);
|
|
441
|
+
// Step 3: Filter to only txs that have metadata and are not mined
|
|
442
|
+
const txsToRestore = this.#indices.filterRestorable(expiredProtected);
|
|
443
|
+
if (txsToRestore.length === 0) {
|
|
444
|
+
this.#log.debug(`Preparing for slot ${slotNumber}, no txs to unprotect`);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
this.#log.info(`Preparing for slot ${slotNumber}: unprotecting ${txsToRestore.length} txs`);
|
|
448
|
+
// Step 4: Validate for pending pool
|
|
449
|
+
const { valid, invalid } = await this.#revalidateMetadata(txsToRestore, 'during prepareForSlot');
|
|
450
|
+
// Step 5: Resolve nullifier conflicts and add winners to pending indices
|
|
451
|
+
const { added, toEvict } = this.#applyNullifierConflictResolution(valid);
|
|
452
|
+
// Step 6: Delete invalid txs and evict conflict losers
|
|
453
|
+
await this.#deleteTxsBatch(invalid);
|
|
454
|
+
await this.#evictTxs(toEvict, 'NullifierConflict');
|
|
455
|
+
// Step 7: Run eviction rules (enforce pool size limit)
|
|
456
|
+
if (added.length > 0) {
|
|
457
|
+
const feePayers = added.map((meta)=>meta.feePayer);
|
|
458
|
+
const uniqueFeePayers = new Set(feePayers);
|
|
459
|
+
await this.#evictionManager.evictAfterNewTxs(added.map((m)=>m.txHash), [
|
|
460
|
+
...uniqueFeePayers
|
|
461
|
+
]);
|
|
462
|
+
}
|
|
463
|
+
});
|
|
345
464
|
}
|
|
346
|
-
async handlePrunedBlocks(latestBlock) {
|
|
465
|
+
async handlePrunedBlocks(latestBlock, options) {
|
|
347
466
|
// Step 1: Find transactions mined after the prune point
|
|
348
|
-
const txsToUnmine = this.#findTxsMinedAfter(latestBlock.number);
|
|
467
|
+
const txsToUnmine = this.#indices.findTxsMinedAfter(latestBlock.number);
|
|
349
468
|
if (txsToUnmine.length === 0) {
|
|
350
469
|
this.#log.debug(`No transactions to un-mine for prune to block ${latestBlock.number}`);
|
|
351
470
|
return;
|
|
352
471
|
}
|
|
353
472
|
this.#log.info(`Handling prune to block ${latestBlock.number}: un-mining ${txsToUnmine.length} txs`);
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
473
|
+
await this.#store.transactionAsync(async ()=>{
|
|
474
|
+
// Step 2: Mark ALL un-mined txs with their original mined block number
|
|
475
|
+
// This ensures they get soft-deleted if removed later, and only hard-deleted
|
|
476
|
+
// when their original mined block is finalized
|
|
477
|
+
await this.#deletedPool.markFromPrunedBlock(txsToUnmine.map((m)=>({
|
|
478
|
+
txHash: m.txHash,
|
|
479
|
+
minedAtBlock: BlockNumber(m.minedL2BlockId.number)
|
|
480
|
+
})));
|
|
481
|
+
// Step 3: Unmine - clear mined status from metadata
|
|
482
|
+
for (const meta of txsToUnmine){
|
|
483
|
+
this.#indices.markAsUnmined(meta);
|
|
484
|
+
}
|
|
485
|
+
// If deleteAllTxs is set (epoch prune), delete all un-mined txs and return early
|
|
486
|
+
if (options?.deleteAllTxs) {
|
|
487
|
+
const allTxHashes = txsToUnmine.map((m)=>m.txHash);
|
|
488
|
+
await this.#deleteTxsBatch(allTxHashes);
|
|
489
|
+
this.#log.info(`Handled prune to block ${latestBlock.number} with deleteAllTxs: deleted ${allTxHashes.length} txs`);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
// Step 4: Filter out protected txs (they'll be handled by prepareForSlot)
|
|
493
|
+
const unprotectedTxs = this.#indices.filterUnprotected(txsToUnmine);
|
|
494
|
+
// Step 5: Validate for pending pool
|
|
495
|
+
const { valid, invalid } = await this.#revalidateMetadata(unprotectedTxs, 'during handlePrunedBlocks');
|
|
496
|
+
// Step 6: Resolve nullifier conflicts and add winners to pending indices
|
|
497
|
+
const { toEvict } = this.#applyNullifierConflictResolution(valid);
|
|
498
|
+
// Step 7: Delete invalid txs and evict conflict losers
|
|
499
|
+
await this.#deleteTxsBatch(invalid);
|
|
500
|
+
await this.#evictTxs(toEvict, 'NullifierConflict');
|
|
501
|
+
this.#log.info(`Handled prune to block ${latestBlock.number}: ${valid.length} txs restored to pending, ${invalid.length} invalid, ${toEvict.length} evicted due to nullifier conflicts`, {
|
|
502
|
+
txHashesRestored: valid.map((m)=>m.txHash),
|
|
503
|
+
txHashesInvalid: invalid,
|
|
504
|
+
txHashesEvicted: toEvict
|
|
505
|
+
});
|
|
506
|
+
// Step 8: Run eviction rules for ALL pending txs (not just restored ones)
|
|
507
|
+
// This handles cases like existing pending txs with invalid fee payer balances
|
|
508
|
+
await this.#evictionManager.evictAfterChainPrune(latestBlock.number);
|
|
509
|
+
});
|
|
370
510
|
}
|
|
371
511
|
async handleFailedExecution(txHashes) {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
512
|
+
await this.#store.transactionAsync(async ()=>{
|
|
513
|
+
await this.#deleteTxsBatch(txHashes.map((h)=>h.toString()));
|
|
514
|
+
});
|
|
515
|
+
this.#log.info(`Deleted ${txHashes.length} failed txs`, {
|
|
516
|
+
txHashes: txHashes.map((h)=>h.toString())
|
|
517
|
+
});
|
|
375
518
|
}
|
|
376
519
|
async handleFinalizedBlock(block) {
|
|
377
520
|
const blockNumber = block.globalVariables.blockNumber;
|
|
378
|
-
// Step 1: Find txs
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
txsToArchive.push(Tx.fromBuffer(buffer));
|
|
521
|
+
// Step 1: Find mined txs at or before finalized block
|
|
522
|
+
const minedTxsToFinalize = this.#indices.findTxsMinedAtOrBefore(blockNumber);
|
|
523
|
+
await this.#store.transactionAsync(async ()=>{
|
|
524
|
+
// Step 2: Collect mined txs for archiving (before deletion)
|
|
525
|
+
const txsToArchive = [];
|
|
526
|
+
if (this.#archive.isEnabled()) {
|
|
527
|
+
for (const txHashStr of minedTxsToFinalize){
|
|
528
|
+
const buffer = await this.#txsDB.getAsync(txHashStr);
|
|
529
|
+
if (buffer) {
|
|
530
|
+
txsToArchive.push(Tx.fromBuffer(buffer));
|
|
531
|
+
}
|
|
390
532
|
}
|
|
391
533
|
}
|
|
534
|
+
// Step 3: Delete mined txs from active pool
|
|
535
|
+
await this.#deleteTxsBatch(minedTxsToFinalize);
|
|
536
|
+
// Step 4: Finalize soft-deleted txs
|
|
537
|
+
await this.#deletedPool.finalizeBlock(blockNumber);
|
|
538
|
+
// Step 5: Archive mined txs
|
|
539
|
+
if (txsToArchive.length > 0) {
|
|
540
|
+
await this.#archive.archiveTxs(txsToArchive);
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
if (minedTxsToFinalize.length > 0) {
|
|
544
|
+
this.#log.info(`Finalized ${minedTxsToFinalize.length} mined txs from blocks up to ${blockNumber}`, {
|
|
545
|
+
txHashes: minedTxsToFinalize
|
|
546
|
+
});
|
|
392
547
|
}
|
|
393
|
-
// Step 3: Delete from active pool
|
|
394
|
-
await this.#deleteTxsBatch(txsToFinalize);
|
|
395
|
-
// Step 4: Archive
|
|
396
|
-
if (txsToArchive.length > 0) {
|
|
397
|
-
await this.#archive.archiveTxs(txsToArchive);
|
|
398
|
-
}
|
|
399
|
-
this.#log.info(`Finalized ${txsToFinalize.length} txs from blocks up to ${blockNumber}`);
|
|
400
548
|
}
|
|
401
549
|
// === Query Methods ===
|
|
402
550
|
async getTxByHash(txHash) {
|
|
@@ -412,42 +560,46 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
412
560
|
return results;
|
|
413
561
|
}
|
|
414
562
|
hasTxs(txHashes) {
|
|
415
|
-
return txHashes.map((h)=>
|
|
563
|
+
return txHashes.map((h)=>{
|
|
564
|
+
const hashStr = h.toString();
|
|
565
|
+
return this.#indices.has(hashStr) || this.#deletedPool.isSoftDeleted(hashStr);
|
|
566
|
+
});
|
|
416
567
|
}
|
|
417
568
|
getTxStatus(txHash) {
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
569
|
+
const txHashStr = txHash.toString();
|
|
570
|
+
const meta = this.#indices.getMetadata(txHashStr);
|
|
571
|
+
if (meta) {
|
|
572
|
+
return this.#indices.getTxState(meta);
|
|
421
573
|
}
|
|
422
|
-
|
|
574
|
+
// Check if soft-deleted
|
|
575
|
+
if (this.#deletedPool.isSoftDeleted(txHashStr)) {
|
|
576
|
+
return 'deleted';
|
|
577
|
+
}
|
|
578
|
+
return undefined;
|
|
423
579
|
}
|
|
424
580
|
getPendingTxHashes() {
|
|
425
581
|
return [
|
|
426
|
-
...this.#iteratePendingByPriority('desc')
|
|
582
|
+
...this.#indices.iteratePendingByPriority('desc')
|
|
583
|
+
].map((hash)=>TxHash.fromString(hash));
|
|
584
|
+
}
|
|
585
|
+
getEligiblePendingTxHashes() {
|
|
586
|
+
const maxReceivedAt = this.#dateProvider.now() - this.#config.minTxPoolAgeMs;
|
|
587
|
+
return [
|
|
588
|
+
...this.#indices.iterateEligiblePendingByPriority('desc', maxReceivedAt)
|
|
427
589
|
].map((hash)=>TxHash.fromString(hash));
|
|
428
590
|
}
|
|
429
591
|
getPendingTxCount() {
|
|
430
|
-
|
|
431
|
-
for (const hashes of this.#pendingByPriority.values()){
|
|
432
|
-
count += hashes.size;
|
|
433
|
-
}
|
|
434
|
-
return count;
|
|
592
|
+
return this.#indices.getPendingTxCount();
|
|
435
593
|
}
|
|
436
594
|
getMinedTxHashes() {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
TxHash.fromString(txHash),
|
|
442
|
-
meta.minedL2BlockId
|
|
443
|
-
]);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
return result;
|
|
595
|
+
return this.#indices.getMinedTxs().map(([hash, blockId])=>[
|
|
596
|
+
TxHash.fromString(hash),
|
|
597
|
+
blockId
|
|
598
|
+
]);
|
|
447
599
|
}
|
|
448
600
|
getMinedTxCount() {
|
|
449
601
|
let count = 0;
|
|
450
|
-
for (const meta of this.#
|
|
602
|
+
for (const [, meta] of this.#indices.iterateMetadata()){
|
|
451
603
|
if (meta.minedL2BlockId !== undefined) {
|
|
452
604
|
count++;
|
|
453
605
|
}
|
|
@@ -455,26 +607,16 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
455
607
|
return count;
|
|
456
608
|
}
|
|
457
609
|
isEmpty() {
|
|
458
|
-
return this.#
|
|
610
|
+
return this.#indices.isEmpty();
|
|
459
611
|
}
|
|
460
612
|
getTxCount() {
|
|
461
|
-
return this.#
|
|
613
|
+
return this.#indices.getTxCount();
|
|
462
614
|
}
|
|
463
615
|
getArchivedTxByHash(txHash) {
|
|
464
616
|
return this.#archive.getTxByHash(txHash);
|
|
465
617
|
}
|
|
466
618
|
getLowestPriorityPending(limit) {
|
|
467
|
-
|
|
468
|
-
return [];
|
|
469
|
-
}
|
|
470
|
-
const result = [];
|
|
471
|
-
for (const hash of this.#iteratePendingByPriority('asc')){
|
|
472
|
-
result.push(TxHash.fromString(hash));
|
|
473
|
-
if (result.length >= limit) {
|
|
474
|
-
break;
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
return result;
|
|
619
|
+
return this.#indices.getLowestPriorityPending(limit).map((h)=>TxHash.fromString(h));
|
|
478
620
|
}
|
|
479
621
|
// === Configuration ===
|
|
480
622
|
updateConfig(config) {
|
|
@@ -485,138 +627,122 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
485
627
|
this.#config.archivedTxLimit = config.archivedTxLimit;
|
|
486
628
|
this.#archive.updateLimit(config.archivedTxLimit);
|
|
487
629
|
}
|
|
630
|
+
if (config.minTxPoolAgeMs !== undefined) {
|
|
631
|
+
this.#config.minTxPoolAgeMs = config.minTxPoolAgeMs;
|
|
632
|
+
}
|
|
488
633
|
// Update eviction rules with new config
|
|
489
634
|
this.#evictionManager.updateConfig(config);
|
|
490
635
|
}
|
|
491
636
|
// === Pool Read Access ===
|
|
492
637
|
getPoolReadAccess() {
|
|
493
638
|
return {
|
|
494
|
-
getMetadata: (txHash)=>this.#
|
|
495
|
-
getTxHashByNullifier: (nullifier)=>this.#
|
|
496
|
-
getTxHashesByFeePayer: (feePayer)=>this.#
|
|
497
|
-
getPendingTxCount: ()=>this.getPendingTxCount()
|
|
639
|
+
getMetadata: (txHash)=>this.#indices.getMetadata(txHash),
|
|
640
|
+
getTxHashByNullifier: (nullifier)=>this.#indices.getTxHashByNullifier(nullifier),
|
|
641
|
+
getTxHashesByFeePayer: (feePayer)=>this.#indices.getTxHashesByFeePayer(feePayer),
|
|
642
|
+
getPendingTxCount: ()=>this.#indices.getPendingTxCount()
|
|
498
643
|
};
|
|
499
644
|
}
|
|
500
645
|
// === Metrics ===
|
|
501
646
|
countTxs() {
|
|
502
|
-
let pending = 0;
|
|
503
|
-
let protected_ = 0;
|
|
504
|
-
let mined = 0;
|
|
505
|
-
for (const meta of this.#metadata.values()){
|
|
506
|
-
const state = this.#getTxState(meta);
|
|
507
|
-
if (state === 'pending') {
|
|
508
|
-
pending++;
|
|
509
|
-
} else if (state === 'protected') {
|
|
510
|
-
protected_++;
|
|
511
|
-
} else if (state === 'mined') {
|
|
512
|
-
mined++;
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
647
|
return {
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
mined
|
|
648
|
+
...this.#indices.countTxs(),
|
|
649
|
+
softDeleted: this.#deletedPool.getSoftDeletedCount()
|
|
519
650
|
};
|
|
520
651
|
}
|
|
521
652
|
// ============================================================================
|
|
522
|
-
// PRIVATE
|
|
653
|
+
// PRIVATE HELPERS - Transaction Management
|
|
523
654
|
// ============================================================================
|
|
524
655
|
/**
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
656
|
+
* Adds a new transaction to the pool with the specified state.
|
|
657
|
+
* Emits onTxsAdded callback immediately after DB write.
|
|
658
|
+
*/ async #addTx(tx, state, opts = {}, precomputedMeta) {
|
|
659
|
+
const txHashStr = tx.getTxHash().toString();
|
|
660
|
+
const meta = precomputedMeta ?? await buildTxMetaData(tx);
|
|
661
|
+
meta.receivedAt = this.#dateProvider.now();
|
|
662
|
+
await this.#txsDB.set(txHashStr, tx.toBuffer());
|
|
663
|
+
await this.#deletedPool.clearSoftDeleted(txHashStr);
|
|
664
|
+
this.#callbacks.onTxsAdded([
|
|
665
|
+
tx
|
|
666
|
+
], opts);
|
|
667
|
+
if (state === 'pending') {
|
|
668
|
+
this.#indices.addPending(meta);
|
|
669
|
+
} else if ('protected' in state) {
|
|
670
|
+
this.#indices.addProtected(meta, state.protected);
|
|
535
671
|
} else {
|
|
536
|
-
|
|
672
|
+
meta.minedL2BlockId = state.mined;
|
|
673
|
+
this.#indices.addMined(meta);
|
|
537
674
|
}
|
|
675
|
+
const stateStr = typeof state === 'string' ? state : Object.keys(state)[0];
|
|
676
|
+
this.#log.debug(`Added tx ${txHashStr} as ${stateStr}`, {
|
|
677
|
+
eventName: 'tx-added-to-pool',
|
|
678
|
+
txHash: txHashStr,
|
|
679
|
+
state: stateStr,
|
|
680
|
+
source: opts.source
|
|
681
|
+
});
|
|
682
|
+
return meta;
|
|
538
683
|
}
|
|
539
684
|
/**
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
*/
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
...hashesAtFee
|
|
553
|
-
].sort(hashCompareFn);
|
|
554
|
-
for (const hash of sortedHashes){
|
|
555
|
-
yield hash;
|
|
556
|
-
}
|
|
557
|
-
}
|
|
685
|
+
* Deletes a transaction from both indices and DB.
|
|
686
|
+
* Emits onTxsRemoved callback immediately after DB delete.
|
|
687
|
+
*/ /**
|
|
688
|
+
* Deletes a transaction from the pool.
|
|
689
|
+
* Delegates to DeletedPool which decides soft vs hard delete based on whether
|
|
690
|
+
* the tx is from a pruned block.
|
|
691
|
+
*/ async #deleteTx(txHashStr) {
|
|
692
|
+
this.#indices.remove(txHashStr);
|
|
693
|
+
this.#callbacks.onTxsRemoved([
|
|
694
|
+
txHashStr
|
|
695
|
+
]);
|
|
696
|
+
await this.#deletedPool.deleteTx(txHashStr);
|
|
558
697
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
// --- Finding & Filtering Steps ---
|
|
563
|
-
/** Finds all transactions mined in blocks after the given block number */ #findTxsMinedAfter(blockNumber) {
|
|
564
|
-
const result = [];
|
|
565
|
-
for (const meta of this.#metadata.values()){
|
|
566
|
-
if (meta.minedL2BlockId !== undefined && meta.minedL2BlockId.number > blockNumber) {
|
|
567
|
-
result.push(meta);
|
|
568
|
-
}
|
|
698
|
+
/** Deletes a batch of transactions, emitting callbacks individually for each. */ async #deleteTxsBatch(txHashes) {
|
|
699
|
+
for (const txHashStr of txHashes){
|
|
700
|
+
await this.#deleteTx(txHashStr);
|
|
569
701
|
}
|
|
570
|
-
return result;
|
|
571
702
|
}
|
|
572
|
-
/**
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
if (meta.minedL2BlockId !== undefined && meta.minedL2BlockId.number <= blockNumber) {
|
|
576
|
-
result.push(txHashStr);
|
|
577
|
-
}
|
|
703
|
+
/** Evicts transactions: records eviction metric with reason, caches hashes, then deletes. */ async #evictTxs(txHashes, reason) {
|
|
704
|
+
if (txHashes.length === 0) {
|
|
705
|
+
return;
|
|
578
706
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
}
|
|
707
|
+
this.#instrumentation.recordEvictions(txHashes.length, reason);
|
|
708
|
+
for (const txHashStr of txHashes){
|
|
709
|
+
this.#log.debug(`Evicting tx ${txHashStr}`, {
|
|
710
|
+
txHash: txHashStr,
|
|
711
|
+
reason
|
|
712
|
+
});
|
|
713
|
+
this.#addToEvictedCache(txHashStr);
|
|
587
714
|
}
|
|
588
|
-
|
|
715
|
+
await this.#deleteTxsBatch(txHashes);
|
|
589
716
|
}
|
|
590
|
-
/**
|
|
591
|
-
|
|
717
|
+
/** Adds a tx hash to the bounded evicted cache, evicting the oldest entry if at capacity. */ #addToEvictedCache(txHashStr) {
|
|
718
|
+
if (this.#evictedTxHashes.size >= this.#config.evictedTxCacheSize) {
|
|
719
|
+
// FIFO eviction: remove the first (oldest) entry
|
|
720
|
+
const oldest = this.#evictedTxHashes.values().next().value;
|
|
721
|
+
this.#evictedTxHashes.delete(oldest);
|
|
722
|
+
}
|
|
723
|
+
this.#evictedTxHashes.add(txHashStr);
|
|
592
724
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
725
|
+
// ============================================================================
|
|
726
|
+
// PRIVATE HELPERS - Validation & Conflict Resolution
|
|
727
|
+
// ============================================================================
|
|
728
|
+
/** Validates transaction metadata, returning true if valid */ async #validateMeta(meta, validator, context) {
|
|
729
|
+
const txValidator = validator ?? await this.#createTxValidator();
|
|
730
|
+
const result = await txValidator.validateTx(meta);
|
|
731
|
+
if (result.result !== 'valid') {
|
|
732
|
+
const contextStr = context ? ` ${context}` : '';
|
|
733
|
+
this.#log.info(`Tx ${meta.txHash}${contextStr} failed validation: ${result.reason?.join(', ')}`);
|
|
734
|
+
return false;
|
|
600
735
|
}
|
|
601
|
-
return
|
|
736
|
+
return true;
|
|
602
737
|
}
|
|
603
|
-
|
|
604
|
-
/** Validates transactions for pending pool, returning valid and invalid groups */ async #validateForPending(txs) {
|
|
738
|
+
/** Validates metadata directly */ async #revalidateMetadata(metas, context) {
|
|
605
739
|
const valid = [];
|
|
606
740
|
const invalid = [];
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
if (
|
|
610
|
-
this.#log.warn(`Tx ${meta.txHash} not found in DB during validation`);
|
|
611
|
-
invalid.push(meta.txHash);
|
|
612
|
-
continue;
|
|
613
|
-
}
|
|
614
|
-
const tx = Tx.fromBuffer(buffer);
|
|
615
|
-
const result = await this.#pendingTxValidator.validateTx(tx);
|
|
616
|
-
if (result.result === 'valid') {
|
|
741
|
+
const validator = await this.#createTxValidator();
|
|
742
|
+
for (const meta of metas){
|
|
743
|
+
if (await this.#validateMeta(meta, validator, context)) {
|
|
617
744
|
valid.push(meta);
|
|
618
745
|
} else {
|
|
619
|
-
this.#log.info(`Tx ${meta.txHash} failed validation: ${result.reason?.join(', ')}`);
|
|
620
746
|
invalid.push(meta.txHash);
|
|
621
747
|
}
|
|
622
748
|
}
|
|
@@ -633,7 +759,7 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
633
759
|
const added = [];
|
|
634
760
|
const toEvict = [];
|
|
635
761
|
for (const meta of txs){
|
|
636
|
-
const conflict = checkNullifierConflict(meta, (nullifier)=>this.#
|
|
762
|
+
const conflict = checkNullifierConflict(meta, (nullifier)=>this.#indices.getTxHashByNullifier(nullifier), (txHash)=>this.#indices.getMetadata(txHash));
|
|
637
763
|
if (conflict.shouldIgnore) {
|
|
638
764
|
// Lower priority than existing - don't add, mark for deletion
|
|
639
765
|
toEvict.push(meta.txHash);
|
|
@@ -642,13 +768,13 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
642
768
|
toEvict.push(...conflict.txHashesToEvict);
|
|
643
769
|
// Remove evicted from indices immediately for subsequent checks
|
|
644
770
|
for (const evictHash of conflict.txHashesToEvict){
|
|
645
|
-
const evictMeta = this.#
|
|
771
|
+
const evictMeta = this.#indices.getMetadata(evictHash);
|
|
646
772
|
if (evictMeta) {
|
|
647
|
-
this.#removeFromPendingIndices(evictMeta);
|
|
773
|
+
this.#indices.removeFromPendingIndices(evictMeta);
|
|
648
774
|
}
|
|
649
775
|
}
|
|
650
776
|
// Add to pending indices immediately so subsequent txs in the batch see this tx
|
|
651
|
-
this.#addToPendingIndices(meta);
|
|
777
|
+
this.#indices.addToPendingIndices(meta);
|
|
652
778
|
added.push(meta);
|
|
653
779
|
}
|
|
654
780
|
}
|
|
@@ -657,32 +783,10 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
657
783
|
toEvict
|
|
658
784
|
};
|
|
659
785
|
}
|
|
660
|
-
//
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
}
|
|
665
|
-
return txs;
|
|
666
|
-
}
|
|
667
|
-
/** Removes protection from tx hashes and clears them from the protected map */ #clearProtection(txHashes) {
|
|
668
|
-
for (const txHashStr of txHashes){
|
|
669
|
-
this.#protectedTransactions.delete(txHashStr);
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
// --- Batch Operation Steps ---
|
|
673
|
-
/** Deletes a batch of transactions permanently */ async #deleteTxsBatch(txHashes) {
|
|
674
|
-
if (txHashes.length === 0) {
|
|
675
|
-
return;
|
|
676
|
-
}
|
|
677
|
-
await this.#store.transactionAsync(async ()=>{
|
|
678
|
-
for (const txHashStr of txHashes){
|
|
679
|
-
await this.#deleteTx(txHashStr);
|
|
680
|
-
}
|
|
681
|
-
});
|
|
682
|
-
this.#callbacks.onTxsRemoved(txHashes);
|
|
683
|
-
}
|
|
684
|
-
// --- Block & Tx Info Steps ---
|
|
685
|
-
/** Builds a block ID from a block header */ async #buildBlockId(block) {
|
|
786
|
+
// ============================================================================
|
|
787
|
+
// PRIVATE HELPERS - Block & Hydration
|
|
788
|
+
// ============================================================================
|
|
789
|
+
async #buildBlockId(block) {
|
|
686
790
|
return {
|
|
687
791
|
number: block.globalVariables.blockNumber,
|
|
688
792
|
hash: (await block.hash()).toString()
|
|
@@ -698,43 +802,18 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
698
802
|
hash: txEffect.l2BlockHash.toString()
|
|
699
803
|
};
|
|
700
804
|
}
|
|
701
|
-
/** Marks a batch of transactions as mined */ #markTxsAsMined(metas, blockId) {
|
|
702
|
-
for (const meta of metas){
|
|
703
|
-
this.#markAsMined(meta, blockId);
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
// --- Add Transaction Steps ---
|
|
707
|
-
/** Persists a transaction to the database */ async #persistTx(txHashStr, tx) {
|
|
708
|
-
await this.#txsDB.set(txHashStr, tx.toBuffer());
|
|
709
|
-
}
|
|
710
|
-
/** Adds a new transaction as protected, returning its metadata */ async #addNewProtectedTx(tx, slotNumber) {
|
|
711
|
-
const txHashStr = tx.getTxHash().toString();
|
|
712
|
-
const meta = await buildTxMetaData(tx);
|
|
713
|
-
this.#protectedTransactions.set(txHashStr, slotNumber);
|
|
714
|
-
await this.#persistTx(txHashStr, tx);
|
|
715
|
-
this.#metadata.set(txHashStr, meta);
|
|
716
|
-
// Don't add to pending indices since it's protected
|
|
717
|
-
this.#log.verbose(`Added protected tx ${txHashStr} for slot ${slotNumber}`);
|
|
718
|
-
return meta;
|
|
719
|
-
}
|
|
720
|
-
/** Adds a new transaction as mined, returning its metadata */ async #addNewMinedTx(tx, blockId) {
|
|
721
|
-
const txHashStr = tx.getTxHash().toString();
|
|
722
|
-
const meta = await buildTxMetaData(tx);
|
|
723
|
-
meta.minedL2BlockId = blockId;
|
|
724
|
-
await this.#persistTx(txHashStr, tx);
|
|
725
|
-
this.#metadata.set(txHashStr, meta);
|
|
726
|
-
// Don't add to pending indices since it's mined
|
|
727
|
-
this.#log.verbose(`Added mined tx ${txHashStr} from block ${blockId.number}`);
|
|
728
|
-
return meta;
|
|
729
|
-
}
|
|
730
|
-
// --- Hydration Steps ---
|
|
731
805
|
/** Loads all transactions from the database, returning loaded txs and deserialization errors */ async #loadAllTxsFromDb() {
|
|
732
806
|
const loaded = [];
|
|
733
807
|
const errors = [];
|
|
734
808
|
for await (const [txHashStr, buffer] of this.#txsDB.entriesAsync()){
|
|
809
|
+
// Skip soft-deleted transactions - they stay in DB but not in indices
|
|
810
|
+
if (this.#deletedPool.isSoftDeleted(txHashStr)) {
|
|
811
|
+
continue;
|
|
812
|
+
}
|
|
735
813
|
try {
|
|
736
814
|
const tx = Tx.fromBuffer(buffer);
|
|
737
|
-
const
|
|
815
|
+
const allowedSetupCalls = await this.#checkAllowedSetupCalls(tx);
|
|
816
|
+
const meta = await buildTxMetaData(tx, allowedSetupCalls);
|
|
738
817
|
loaded.push({
|
|
739
818
|
tx,
|
|
740
819
|
meta
|
|
@@ -768,43 +847,6 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
768
847
|
}
|
|
769
848
|
}
|
|
770
849
|
}
|
|
771
|
-
/** Partitions transactions by mined status */ #partitionByMinedStatus(txs) {
|
|
772
|
-
const mined = [];
|
|
773
|
-
const nonMined = [];
|
|
774
|
-
for (const entry of txs){
|
|
775
|
-
if (entry.meta.minedL2BlockId !== undefined) {
|
|
776
|
-
mined.push(entry.meta);
|
|
777
|
-
} else {
|
|
778
|
-
nonMined.push(entry);
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
return {
|
|
782
|
-
mined,
|
|
783
|
-
nonMined
|
|
784
|
-
};
|
|
785
|
-
}
|
|
786
|
-
/** Validates non-mined transactions, returning valid metadata and invalid hashes */ async #validateNonMinedTxs(txs) {
|
|
787
|
-
const valid = [];
|
|
788
|
-
const invalid = [];
|
|
789
|
-
for (const { tx, meta } of txs){
|
|
790
|
-
const result = await this.#pendingTxValidator.validateTx(tx);
|
|
791
|
-
if (result.result === 'valid') {
|
|
792
|
-
valid.push(meta);
|
|
793
|
-
} else {
|
|
794
|
-
this.#log.info(`Removing invalid tx ${meta.txHash} on startup: ${result.reason?.join(', ')}`);
|
|
795
|
-
invalid.push(meta.txHash);
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
return {
|
|
799
|
-
valid,
|
|
800
|
-
invalid
|
|
801
|
-
};
|
|
802
|
-
}
|
|
803
|
-
/** Populates metadata index for mined transactions */ #populateMinedIndices(metas) {
|
|
804
|
-
for (const meta of metas){
|
|
805
|
-
this.#metadata.set(meta.txHash, meta);
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
850
|
/**
|
|
809
851
|
* Rebuilds the pending pool by processing each tx through pre-add rules.
|
|
810
852
|
* Starts with an empty pending pool and adds txs one by one, resolving conflicts.
|
|
@@ -819,22 +861,22 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
819
861
|
if (preAddResult.shouldIgnore) {
|
|
820
862
|
// Transaction rejected - mark for deletion from DB
|
|
821
863
|
rejected.push(meta.txHash);
|
|
822
|
-
this.#log.debug(`Rejected tx ${meta.txHash} during rebuild: ${preAddResult.reason}`);
|
|
864
|
+
this.#log.debug(`Rejected tx ${meta.txHash} during rebuild: ${preAddResult.reason?.message ?? 'unknown reason'}`);
|
|
823
865
|
continue;
|
|
824
866
|
}
|
|
825
867
|
// Evict any conflicting txs identified by pre-add rules
|
|
826
868
|
for (const evictHashStr of preAddResult.txHashesToEvict){
|
|
827
|
-
const evictMeta = this.#
|
|
869
|
+
const evictMeta = this.#indices.getMetadata(evictHashStr);
|
|
828
870
|
if (evictMeta) {
|
|
829
|
-
this.#removeFromPendingIndices(evictMeta);
|
|
830
|
-
this.#
|
|
871
|
+
this.#indices.removeFromPendingIndices(evictMeta);
|
|
872
|
+
this.#indices.remove(evictHashStr);
|
|
831
873
|
rejected.push(evictHashStr);
|
|
832
874
|
accepted.delete(evictHashStr);
|
|
833
875
|
this.#log.debug(`Evicted tx ${evictHashStr} during rebuild due to conflict with ${meta.txHash}`);
|
|
834
876
|
}
|
|
835
877
|
}
|
|
836
|
-
// Add to
|
|
837
|
-
this.#
|
|
878
|
+
// Add to indices
|
|
879
|
+
this.#indices.addPending(meta);
|
|
838
880
|
accepted.add(meta.txHash);
|
|
839
881
|
}
|
|
840
882
|
this.#log.info(`Rebuilt pending pool: ${accepted.size} accepted, ${rejected.length} rejected`);
|
|
@@ -845,197 +887,38 @@ import { buildTxMetaData, checkNullifierConflict, compareFee, compareTxHash } fr
|
|
|
845
887
|
rejected
|
|
846
888
|
};
|
|
847
889
|
}
|
|
848
|
-
// --- Add Pending Tx Steps ---
|
|
849
|
-
/** Checks if a tx is a duplicate (already in pool) */ #isDuplicateTx(txHashStr) {
|
|
850
|
-
return this.#metadata.has(txHashStr);
|
|
851
|
-
}
|
|
852
|
-
/** Adds a new pending tx to the pool, returning its metadata */ async #addNewPendingTx(tx) {
|
|
853
|
-
const txHashStr = tx.getTxHash().toString();
|
|
854
|
-
const meta = await buildTxMetaData(tx);
|
|
855
|
-
await this.#persistTx(txHashStr, tx);
|
|
856
|
-
this.#addToIndices(meta);
|
|
857
|
-
this.#log.verbose(`Added tx ${txHashStr} to pool`, {
|
|
858
|
-
eventName: 'tx-added-to-pool',
|
|
859
|
-
state: this.#getTxState(meta)
|
|
860
|
-
});
|
|
861
|
-
return meta;
|
|
862
|
-
}
|
|
863
|
-
// ============================================================================
|
|
864
|
-
// HELPER FUNCTIONS - Index Management
|
|
865
|
-
// ============================================================================
|
|
866
|
-
#addToIndices(meta) {
|
|
867
|
-
this.#metadata.set(meta.txHash, meta);
|
|
868
|
-
if (this.#getTxState(meta) === 'pending') {
|
|
869
|
-
this.#addToPendingIndices(meta);
|
|
870
|
-
}
|
|
871
|
-
// Protected and mined txs don't go into pending indices
|
|
872
|
-
}
|
|
873
|
-
#addToPendingIndices(meta) {
|
|
874
|
-
// Add to nullifier index
|
|
875
|
-
for (const nullifier of meta.nullifiers){
|
|
876
|
-
this.#nullifierToTxHash.set(nullifier, meta.txHash);
|
|
877
|
-
}
|
|
878
|
-
// Add to fee payer index
|
|
879
|
-
let feePayerSet = this.#feePayerToTxHashes.get(meta.feePayer);
|
|
880
|
-
if (!feePayerSet) {
|
|
881
|
-
feePayerSet = new Set();
|
|
882
|
-
this.#feePayerToTxHashes.set(meta.feePayer, feePayerSet);
|
|
883
|
-
}
|
|
884
|
-
feePayerSet.add(meta.txHash);
|
|
885
|
-
// Add to priority bucket
|
|
886
|
-
let prioritySet = this.#pendingByPriority.get(meta.priorityFee);
|
|
887
|
-
if (!prioritySet) {
|
|
888
|
-
prioritySet = new Set();
|
|
889
|
-
this.#pendingByPriority.set(meta.priorityFee, prioritySet);
|
|
890
|
-
}
|
|
891
|
-
prioritySet.add(meta.txHash);
|
|
892
|
-
}
|
|
893
|
-
#removeFromPendingIndices(meta) {
|
|
894
|
-
// Remove from nullifier index
|
|
895
|
-
for (const nullifier of meta.nullifiers){
|
|
896
|
-
this.#nullifierToTxHash.delete(nullifier);
|
|
897
|
-
}
|
|
898
|
-
// Remove from fee payer index
|
|
899
|
-
const feePayerSet = this.#feePayerToTxHashes.get(meta.feePayer);
|
|
900
|
-
if (feePayerSet) {
|
|
901
|
-
feePayerSet.delete(meta.txHash);
|
|
902
|
-
if (feePayerSet.size === 0) {
|
|
903
|
-
this.#feePayerToTxHashes.delete(meta.feePayer);
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
// Remove from priority map
|
|
907
|
-
const hashSet = this.#pendingByPriority.get(meta.priorityFee);
|
|
908
|
-
if (hashSet) {
|
|
909
|
-
hashSet.delete(meta.txHash);
|
|
910
|
-
if (hashSet.size === 0) {
|
|
911
|
-
this.#pendingByPriority.delete(meta.priorityFee);
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
#updateProtection(txHashStr, slotNumber) {
|
|
916
|
-
const currentSlot = this.#protectedTransactions.get(txHashStr);
|
|
917
|
-
// Only update if not already protected at an equal or later slot
|
|
918
|
-
if (currentSlot !== undefined && currentSlot >= slotNumber) {
|
|
919
|
-
return;
|
|
920
|
-
}
|
|
921
|
-
// Remove from pending indices if transitioning from pending to protected
|
|
922
|
-
if (currentSlot === undefined) {
|
|
923
|
-
const meta = this.#metadata.get(txHashStr);
|
|
924
|
-
if (meta) {
|
|
925
|
-
this.#removeFromPendingIndices(meta);
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
this.#protectedTransactions.set(txHashStr, slotNumber);
|
|
929
|
-
}
|
|
930
|
-
#markAsMined(meta, blockId) {
|
|
931
|
-
meta.minedL2BlockId = blockId;
|
|
932
|
-
// Safe to call unconditionally - removeFromPendingIndices is idempotent
|
|
933
|
-
this.#removeFromPendingIndices(meta);
|
|
934
|
-
}
|
|
935
|
-
async #deleteTx(txHashStr) {
|
|
936
|
-
const meta = this.#metadata.get(txHashStr);
|
|
937
|
-
if (!meta) {
|
|
938
|
-
return;
|
|
939
|
-
}
|
|
940
|
-
// Remove from all indices
|
|
941
|
-
this.#metadata.delete(txHashStr);
|
|
942
|
-
this.#protectedTransactions.delete(txHashStr);
|
|
943
|
-
this.#removeFromPendingIndices(meta);
|
|
944
|
-
// Remove from persistence
|
|
945
|
-
await this.#txsDB.delete(txHashStr);
|
|
946
|
-
}
|
|
947
890
|
// ============================================================================
|
|
948
|
-
//
|
|
891
|
+
// PRIVATE HELPERS - Pool Access Adapters
|
|
949
892
|
// ============================================================================
|
|
950
|
-
|
|
951
|
-
const txHashes = this.#feePayerToTxHashes.get(feePayer);
|
|
952
|
-
if (!txHashes) {
|
|
953
|
-
return [];
|
|
954
|
-
}
|
|
955
|
-
const result = [];
|
|
956
|
-
for (const txHashStr of txHashes){
|
|
957
|
-
const meta = this.#metadata.get(txHashStr);
|
|
958
|
-
if (meta && this.#getTxState(meta) === 'pending') {
|
|
959
|
-
result.push(meta);
|
|
960
|
-
}
|
|
961
|
-
}
|
|
962
|
-
return result;
|
|
963
|
-
}
|
|
964
|
-
/**
|
|
965
|
-
* Creates a PoolOperations adapter for use with the eviction manager.
|
|
966
|
-
*/ #createPoolOperations() {
|
|
893
|
+
#createPoolOperations() {
|
|
967
894
|
return {
|
|
968
|
-
getPendingTxs: ()=>
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
result.push(meta);
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
return result;
|
|
979
|
-
},
|
|
980
|
-
getPendingFeePayers: ()=>{
|
|
981
|
-
return Array.from(this.#feePayerToTxHashes.keys());
|
|
982
|
-
},
|
|
983
|
-
getFeePayerPendingTxs: (feePayer)=>{
|
|
984
|
-
return this.#getFeePayerPendingTxs(feePayer);
|
|
985
|
-
},
|
|
986
|
-
getPendingTxCount: ()=>{
|
|
987
|
-
return this.getPendingTxCount();
|
|
988
|
-
},
|
|
989
|
-
getLowestPriorityPending: (limit)=>{
|
|
990
|
-
return this.getLowestPriorityPending(limit).map((h)=>h.toString());
|
|
991
|
-
},
|
|
992
|
-
deleteTxs: async (txHashes)=>{
|
|
993
|
-
await this.#store.transactionAsync(async ()=>{
|
|
994
|
-
for (const txHashStr of txHashes){
|
|
995
|
-
await this.#deleteTx(txHashStr);
|
|
996
|
-
}
|
|
997
|
-
});
|
|
998
|
-
this.#callbacks.onTxsRemoved(txHashes);
|
|
999
|
-
}
|
|
895
|
+
getPendingTxs: ()=>this.#indices.getPendingTxs(),
|
|
896
|
+
getPendingFeePayers: ()=>this.#indices.getPendingFeePayers(),
|
|
897
|
+
getFeePayerPendingTxs: (feePayer)=>this.#indices.getFeePayerPendingTxs(feePayer),
|
|
898
|
+
getPendingTxCount: ()=>this.#indices.getPendingTxCount(),
|
|
899
|
+
getLowestPriorityPending: (limit)=>this.#indices.getLowestPriorityPending(limit),
|
|
900
|
+
deleteTxs: (txHashes, reason)=>this.#evictTxs(txHashes, reason ?? 'unknown')
|
|
1000
901
|
};
|
|
1001
902
|
}
|
|
1002
|
-
|
|
1003
|
-
* Creates a PreAddPoolAccess adapter for use with pre-add eviction rules.
|
|
1004
|
-
* All methods work with strings and TxMetaData for efficiency.
|
|
1005
|
-
*/ #createPreAddPoolAccess() {
|
|
903
|
+
#createPreAddPoolAccess() {
|
|
1006
904
|
return {
|
|
1007
905
|
getMetadata: (txHashStr)=>{
|
|
1008
|
-
const meta = this.#
|
|
1009
|
-
if (!meta || this.#getTxState(meta) !== 'pending') {
|
|
906
|
+
const meta = this.#indices.getMetadata(txHashStr);
|
|
907
|
+
if (!meta || this.#indices.getTxState(meta) !== 'pending') {
|
|
1010
908
|
return undefined;
|
|
1011
909
|
}
|
|
1012
910
|
return meta;
|
|
1013
911
|
},
|
|
1014
|
-
getTxHashByNullifier: (nullifier)=>
|
|
1015
|
-
return this.#nullifierToTxHash.get(nullifier);
|
|
1016
|
-
},
|
|
912
|
+
getTxHashByNullifier: (nullifier)=>this.#indices.getTxHashByNullifier(nullifier),
|
|
1017
913
|
getFeePayerBalance: async (feePayer)=>{
|
|
1018
914
|
const db = this.#worldStateSynchronizer.getCommitted();
|
|
1019
915
|
const publicStateSource = new DatabasePublicStateSource(db);
|
|
1020
916
|
const balance = await publicStateSource.storageRead(ProtocolContractAddress.FeeJuice, await computeFeePayerBalanceStorageSlot(AztecAddress.fromString(feePayer)));
|
|
1021
917
|
return balance.toBigInt();
|
|
1022
918
|
},
|
|
1023
|
-
getFeePayerPendingTxs: (feePayer)=>
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
getPendingTxCount: ()=>{
|
|
1027
|
-
return this.getPendingTxCount();
|
|
1028
|
-
},
|
|
1029
|
-
getLowestPriorityPendingTx: ()=>{
|
|
1030
|
-
// Iterate in ascending order to find the lowest priority
|
|
1031
|
-
for (const txHashStr of this.#iteratePendingByPriority('asc')){
|
|
1032
|
-
const meta = this.#metadata.get(txHashStr);
|
|
1033
|
-
if (meta) {
|
|
1034
|
-
return meta;
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
return undefined;
|
|
1038
|
-
}
|
|
919
|
+
getFeePayerPendingTxs: (feePayer)=>this.#indices.getFeePayerPendingTxs(feePayer),
|
|
920
|
+
getPendingTxCount: ()=>this.#indices.getPendingTxCount(),
|
|
921
|
+
getLowestPriorityPendingTx: ()=>this.#indices.getLowestPriorityPendingTx()
|
|
1039
922
|
};
|
|
1040
923
|
}
|
|
1041
924
|
}
|