@xyo-network/xl1-protocol-sdk 1.29.8 → 1.30.1
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/dist/neutral/index.mjs +157 -38
- package/dist/neutral/index.mjs.map +1 -1
- package/dist/neutral/simple/block/SimpleBlockViewer.d.ts +2 -3
- package/dist/neutral/simple/block/SimpleBlockViewer.d.ts.map +1 -1
- package/dist/neutral/simple/mempool/SimpleMempoolRunner.d.ts +14 -0
- package/dist/neutral/simple/mempool/SimpleMempoolRunner.d.ts.map +1 -1
- package/dist/neutral/simple/mempool/SimpleMempoolViewer.d.ts +28 -0
- package/dist/neutral/simple/mempool/SimpleMempoolViewer.d.ts.map +1 -1
- package/dist/neutral/test/index.mjs +25 -56
- package/dist/neutral/test/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/neutral/index.mjs
CHANGED
|
@@ -4051,7 +4051,6 @@ import {
|
|
|
4051
4051
|
asSignedHydratedBlockWithStorageMeta,
|
|
4052
4052
|
asXL1BlockNumber as asXL1BlockNumber8,
|
|
4053
4053
|
BlockViewerMoniker as BlockViewerMoniker2,
|
|
4054
|
-
DataLakeViewerMoniker,
|
|
4055
4054
|
FinalizationViewerMoniker
|
|
4056
4055
|
} from "@xyo-network/xl1-protocol-lib";
|
|
4057
4056
|
|
|
@@ -4092,10 +4091,9 @@ var MIN_HEAD_POLL_INTERVAL_MS = 5e3;
|
|
|
4092
4091
|
var SimpleBlockViewer = class extends AbstractCreatableProvider {
|
|
4093
4092
|
moniker = SimpleBlockViewer.defaultMoniker;
|
|
4094
4093
|
_store;
|
|
4095
|
-
dataLakeViewer;
|
|
4096
4094
|
finalizationViewer;
|
|
4097
4095
|
payloadCache = new LruCacheMap({ max: 1e4 });
|
|
4098
|
-
|
|
4096
|
+
signedHydratedBlockWithHashMetaCache = new LruCacheMap({ max: 2e3, ttl: 1e3 * 60 * 60 });
|
|
4099
4097
|
_headPollHash;
|
|
4100
4098
|
_headPollInProgress = false;
|
|
4101
4099
|
_headPollTimer = null;
|
|
@@ -4131,17 +4129,16 @@ var SimpleBlockViewer = class extends AbstractCreatableProvider {
|
|
|
4131
4129
|
}
|
|
4132
4130
|
async blockByHash(hash) {
|
|
4133
4131
|
return await this.spanAsync("blockByHash", async () => {
|
|
4134
|
-
const cachedBlock = this.
|
|
4132
|
+
const cachedBlock = this.signedHydratedBlockWithHashMetaCache.get(hash);
|
|
4135
4133
|
if (cachedBlock) {
|
|
4136
4134
|
return cachedBlock;
|
|
4137
4135
|
}
|
|
4138
4136
|
const cache = this.hydratedBlockCache;
|
|
4139
4137
|
const block = await cache.get(hash);
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
this.signedHydratedBlockWithDataLakePayloadsCache.set(hash, result);
|
|
4138
|
+
if (block) {
|
|
4139
|
+
this.signedHydratedBlockWithHashMetaCache.set(hash, block);
|
|
4143
4140
|
}
|
|
4144
|
-
return
|
|
4141
|
+
return block ?? null;
|
|
4145
4142
|
}, { ...this.context, timeBudgetLimit: 100 });
|
|
4146
4143
|
}
|
|
4147
4144
|
async blockByNumber(blockNumber) {
|
|
@@ -4194,13 +4191,11 @@ var SimpleBlockViewer = class extends AbstractCreatableProvider {
|
|
|
4194
4191
|
}
|
|
4195
4192
|
async createHandler() {
|
|
4196
4193
|
await super.createHandler();
|
|
4197
|
-
this.dataLakeViewer = await this.locator.tryGetInstance(DataLakeViewerMoniker);
|
|
4198
4194
|
this.finalizationViewer = await this.locator.getInstance(FinalizationViewerMoniker);
|
|
4199
4195
|
this._store = { chainMap: this.params.finalizedArchivist };
|
|
4200
4196
|
}
|
|
4201
4197
|
async currentBlock() {
|
|
4202
|
-
|
|
4203
|
-
return result;
|
|
4198
|
+
return await this.finalizationViewer.head();
|
|
4204
4199
|
}
|
|
4205
4200
|
async currentBlockHash() {
|
|
4206
4201
|
return await this.finalizationViewer.headHash();
|
|
@@ -4218,7 +4213,7 @@ var SimpleBlockViewer = class extends AbstractCreatableProvider {
|
|
|
4218
4213
|
const cachedHashes = new Set(cachedPayloads.map((p) => p._hash));
|
|
4219
4214
|
remainingHashes = remainingHashes.filter((h) => !cachedHashes.has(h));
|
|
4220
4215
|
const finalizedPayloads = remainingHashes.length > 0 ? await this.finalizedArchivist.get(remainingHashes) : [];
|
|
4221
|
-
const
|
|
4216
|
+
const resultPayloads = [...cachedPayloads, ...finalizedPayloads.filter(exists4)];
|
|
4222
4217
|
resultPayloads.map((payload) => {
|
|
4223
4218
|
this.payloadCache.set(payload._hash, payload);
|
|
4224
4219
|
});
|
|
@@ -4257,9 +4252,7 @@ var SimpleBlockViewer = class extends AbstractCreatableProvider {
|
|
|
4257
4252
|
await super.stopHandler();
|
|
4258
4253
|
}
|
|
4259
4254
|
async blockByNumberWithContext(chainContext, blockNumber) {
|
|
4260
|
-
|
|
4261
|
-
const [result] = block ? await addDataLakePayloads(block, this.dataLakeViewer) : [null, []];
|
|
4262
|
-
return result;
|
|
4255
|
+
return asSignedHydratedBlockWithHashMeta(await hydratedBlockByNumber(chainContext, blockNumber)) ?? null;
|
|
4263
4256
|
}
|
|
4264
4257
|
async pollHead(emitOnChange) {
|
|
4265
4258
|
if (this._headPollInProgress) return;
|
|
@@ -4629,14 +4622,14 @@ RestDataLakeRunner = __decorateClass([
|
|
|
4629
4622
|
|
|
4630
4623
|
// src/simple/datalake/RestDataLakeViewer.ts
|
|
4631
4624
|
import {
|
|
4632
|
-
DataLakeViewerMoniker
|
|
4625
|
+
DataLakeViewerMoniker
|
|
4633
4626
|
} from "@xyo-network/xl1-protocol-lib";
|
|
4634
4627
|
var RestDataLakeViewer = class extends AbstractRestDataLake {
|
|
4635
4628
|
moniker = RestDataLakeViewer.defaultMoniker;
|
|
4636
4629
|
};
|
|
4637
|
-
__publicField(RestDataLakeViewer, "defaultMoniker",
|
|
4630
|
+
__publicField(RestDataLakeViewer, "defaultMoniker", DataLakeViewerMoniker);
|
|
4638
4631
|
__publicField(RestDataLakeViewer, "dependencies", []);
|
|
4639
|
-
__publicField(RestDataLakeViewer, "monikers", [
|
|
4632
|
+
__publicField(RestDataLakeViewer, "monikers", [DataLakeViewerMoniker]);
|
|
4640
4633
|
RestDataLakeViewer = __decorateClass([
|
|
4641
4634
|
creatableProvider()
|
|
4642
4635
|
], RestDataLakeViewer);
|
|
@@ -4714,14 +4707,14 @@ SimpleDataLakeRunner = __decorateClass([
|
|
|
4714
4707
|
|
|
4715
4708
|
// src/simple/datalake/SimpleDataLakeViewer.ts
|
|
4716
4709
|
import {
|
|
4717
|
-
DataLakeViewerMoniker as
|
|
4710
|
+
DataLakeViewerMoniker as DataLakeViewerMoniker2
|
|
4718
4711
|
} from "@xyo-network/xl1-protocol-lib";
|
|
4719
4712
|
var SimpleDataLakeViewer = class extends AbstractSimpleDataLake {
|
|
4720
4713
|
moniker = SimpleDataLakeViewer.defaultMoniker;
|
|
4721
4714
|
};
|
|
4722
|
-
__publicField(SimpleDataLakeViewer, "defaultMoniker",
|
|
4715
|
+
__publicField(SimpleDataLakeViewer, "defaultMoniker", DataLakeViewerMoniker2);
|
|
4723
4716
|
__publicField(SimpleDataLakeViewer, "dependencies", []);
|
|
4724
|
-
__publicField(SimpleDataLakeViewer, "monikers", [
|
|
4717
|
+
__publicField(SimpleDataLakeViewer, "monikers", [DataLakeViewerMoniker2]);
|
|
4725
4718
|
SimpleDataLakeViewer = __decorateClass([
|
|
4726
4719
|
creatableProvider()
|
|
4727
4720
|
], SimpleDataLakeViewer);
|
|
@@ -4980,18 +4973,26 @@ import {
|
|
|
4980
4973
|
isSignedHydratedBlockWithHashMeta,
|
|
4981
4974
|
isSignedHydratedTransactionWithHashMeta,
|
|
4982
4975
|
MempoolRunnerMoniker,
|
|
4976
|
+
MempoolViewerMoniker,
|
|
4983
4977
|
TransactionRejectionSchema,
|
|
4984
4978
|
TransactionValidationViewerMoniker
|
|
4985
4979
|
} from "@xyo-network/xl1-protocol-lib";
|
|
4986
4980
|
import { Mutex } from "async-mutex";
|
|
4987
4981
|
var DEFAULT_SYNC_INTERVAL = 3e4;
|
|
4988
4982
|
var DEFAULT_SYNC_LIMIT = 100;
|
|
4983
|
+
var ENFORCE_CAP_BATCH_SIZE = 1e3;
|
|
4984
|
+
function isDemotionAware(viewer) {
|
|
4985
|
+
if (!viewer) return false;
|
|
4986
|
+
const candidate = viewer;
|
|
4987
|
+
return typeof candidate.forget === "function" && typeof candidate.getEvictionPriorityOrder === "function";
|
|
4988
|
+
}
|
|
4989
4989
|
var SimpleMempoolRunner = class extends AbstractCreatableProvider {
|
|
4990
4990
|
moniker = SimpleMempoolRunner.defaultMoniker;
|
|
4991
4991
|
_blockValidationViewer;
|
|
4992
4992
|
_chainContractViewer;
|
|
4993
4993
|
_deadLetterQueueRunner;
|
|
4994
4994
|
_finalizationViewer;
|
|
4995
|
+
_mempoolViewer;
|
|
4995
4996
|
_transactionValidationViewer;
|
|
4996
4997
|
_syncMutex = new Mutex();
|
|
4997
4998
|
_syncTimerId = null;
|
|
@@ -5010,6 +5011,9 @@ var SimpleMempoolRunner = class extends AbstractCreatableProvider {
|
|
|
5010
5011
|
get maxExpAhead() {
|
|
5011
5012
|
return this.params.maxExpAhead ?? DEFAULT_MAX_EXP_AHEAD;
|
|
5012
5013
|
}
|
|
5014
|
+
get maxPendingTransactions() {
|
|
5015
|
+
return this.params.maxPendingTransactions ?? 0;
|
|
5016
|
+
}
|
|
5013
5017
|
get pendingBlocksArchivist() {
|
|
5014
5018
|
return this.params.pendingBlocksArchivist;
|
|
5015
5019
|
}
|
|
@@ -5042,6 +5046,7 @@ var SimpleMempoolRunner = class extends AbstractCreatableProvider {
|
|
|
5042
5046
|
this._finalizationViewer = await this.locator.getInstance(FinalizationViewerMoniker4);
|
|
5043
5047
|
this._transactionValidationViewer = await this.locator.getInstance(TransactionValidationViewerMoniker);
|
|
5044
5048
|
this._deadLetterQueueRunner = await this.locator.tryGetInstance(DeadLetterQueueRunnerMoniker);
|
|
5049
|
+
this._mempoolViewer = await this.locator.tryGetInstance(MempoolViewerMoniker);
|
|
5045
5050
|
}
|
|
5046
5051
|
async prunePendingBlocks({
|
|
5047
5052
|
batchSize = 10,
|
|
@@ -5156,6 +5161,7 @@ var SimpleMempoolRunner = class extends AbstractCreatableProvider {
|
|
|
5156
5161
|
pruned += pruneHashes.length;
|
|
5157
5162
|
total += batch.length;
|
|
5158
5163
|
await this.pendingTransactionsArchivist.delete(pruneHashes);
|
|
5164
|
+
this.forgetBundleHashes(pruneHashes);
|
|
5159
5165
|
const pruneSet = new Set(pruneHashes);
|
|
5160
5166
|
const lastSurvivor = batch.findLast((p) => !pruneSet.has(p._hash));
|
|
5161
5167
|
cursor = lastSurvivor?._sequence ?? cursor;
|
|
@@ -5165,8 +5171,7 @@ var SimpleMempoolRunner = class extends AbstractCreatableProvider {
|
|
|
5165
5171
|
order: "desc"
|
|
5166
5172
|
});
|
|
5167
5173
|
}
|
|
5168
|
-
this.
|
|
5169
|
-
return [pruned, total];
|
|
5174
|
+
return this.finalizePruneTransactionsResult(pruned, total);
|
|
5170
5175
|
}
|
|
5171
5176
|
async submitBlocks(blocks) {
|
|
5172
5177
|
const bundles = await Promise.all(blocks.map(async ([bw, payloads]) => {
|
|
@@ -5212,6 +5217,7 @@ var SimpleMempoolRunner = class extends AbstractCreatableProvider {
|
|
|
5212
5217
|
}
|
|
5213
5218
|
const bundles = hashedTransactions.map((tx) => hydratedTransactionToPayloadBundle(tx));
|
|
5214
5219
|
const inserted = await this.pendingTransactionsArchivist.insert(bundles);
|
|
5220
|
+
await this.enforceCap();
|
|
5215
5221
|
return inserted.map((p) => p._hash);
|
|
5216
5222
|
}
|
|
5217
5223
|
async startHandler() {
|
|
@@ -5230,6 +5236,50 @@ var SimpleMempoolRunner = class extends AbstractCreatableProvider {
|
|
|
5230
5236
|
this._syncTimerId = null;
|
|
5231
5237
|
}
|
|
5232
5238
|
}
|
|
5239
|
+
async collectAllPendingTransactionBundles() {
|
|
5240
|
+
const all = [];
|
|
5241
|
+
let cursor;
|
|
5242
|
+
while (true) {
|
|
5243
|
+
const batch = await this.pendingTransactionsArchivist.next({
|
|
5244
|
+
limit: ENFORCE_CAP_BATCH_SIZE,
|
|
5245
|
+
cursor,
|
|
5246
|
+
order: "asc"
|
|
5247
|
+
});
|
|
5248
|
+
if (batch.length === 0) break;
|
|
5249
|
+
all.push(...batch);
|
|
5250
|
+
cursor = batch.at(-1)?._sequence;
|
|
5251
|
+
if (batch.length < ENFORCE_CAP_BATCH_SIZE) break;
|
|
5252
|
+
}
|
|
5253
|
+
return all;
|
|
5254
|
+
}
|
|
5255
|
+
async enforceCap() {
|
|
5256
|
+
const cap = this.maxPendingTransactions;
|
|
5257
|
+
if (cap <= 0) return;
|
|
5258
|
+
const all = await this.collectAllPendingTransactionBundles();
|
|
5259
|
+
if (all.length <= cap) return;
|
|
5260
|
+
const excess = all.length - cap;
|
|
5261
|
+
const bundleHashesOldestFirst = all.map((p) => p._hash);
|
|
5262
|
+
const orderedForEviction = this.orderForEviction(bundleHashesOldestFirst);
|
|
5263
|
+
const toEvict = orderedForEviction.slice(0, excess);
|
|
5264
|
+
await this.pendingTransactionsArchivist.delete(toEvict);
|
|
5265
|
+
this.forgetBundleHashes(toEvict);
|
|
5266
|
+
this.logger?.debug(`enforceCap evicted ${toEvict.length} bundles (pool=${all.length}, cap=${cap})`);
|
|
5267
|
+
}
|
|
5268
|
+
async finalizePruneTransactionsResult(pruned, total) {
|
|
5269
|
+
this.logger?.debug(`prunePendingTransactions completed: pruned=${pruned}, totalChecked=${total}`);
|
|
5270
|
+
await this.enforceCap();
|
|
5271
|
+
return [pruned, total];
|
|
5272
|
+
}
|
|
5273
|
+
forgetBundleHashes(bundleHashes) {
|
|
5274
|
+
if (bundleHashes.length === 0) return;
|
|
5275
|
+
if (isDemotionAware(this._mempoolViewer)) this._mempoolViewer.forget(bundleHashes);
|
|
5276
|
+
}
|
|
5277
|
+
orderForEviction(bundleHashesOldestFirst) {
|
|
5278
|
+
if (isDemotionAware(this._mempoolViewer)) {
|
|
5279
|
+
return this._mempoolViewer.getEvictionPriorityOrder(bundleHashesOldestFirst);
|
|
5280
|
+
}
|
|
5281
|
+
return bundleHashesOldestFirst;
|
|
5282
|
+
}
|
|
5233
5283
|
async routeRejectedTransaction(transaction, errors) {
|
|
5234
5284
|
if (!this._deadLetterQueueRunner) return;
|
|
5235
5285
|
const rejectionErrors = errors.map((e) => ({
|
|
@@ -5342,13 +5392,22 @@ import {
|
|
|
5342
5392
|
} from "@xylabs/sdk-js";
|
|
5343
5393
|
import { isHashMeta as isHashMeta2, isPayloadBundle as isPayloadBundle2 } from "@xyo-network/sdk-js";
|
|
5344
5394
|
import {
|
|
5345
|
-
MempoolViewerMoniker,
|
|
5395
|
+
MempoolViewerMoniker as MempoolViewerMoniker2,
|
|
5346
5396
|
WindowedBlockViewerMoniker
|
|
5347
5397
|
} from "@xyo-network/xl1-protocol-lib";
|
|
5348
5398
|
var DEFAULT_MEMPOOL_SELECTION_RATIO = 0.66;
|
|
5399
|
+
var DEFAULT_DEMOTION_THRESHOLD = 3;
|
|
5400
|
+
var DEFAULT_HANDOUT_STATS_TTL_BLOCKS = 1e3;
|
|
5349
5401
|
var SimpleMempoolViewer = class extends AbstractCreatableProvider {
|
|
5350
5402
|
moniker = SimpleMempoolViewer.defaultMoniker;
|
|
5403
|
+
_handoutStats = /* @__PURE__ */ new Map();
|
|
5351
5404
|
_windowedBlockViewer;
|
|
5405
|
+
get demotionThreshold() {
|
|
5406
|
+
return this.params.demotionThreshold ?? DEFAULT_DEMOTION_THRESHOLD;
|
|
5407
|
+
}
|
|
5408
|
+
get handoutStatsTtlBlocks() {
|
|
5409
|
+
return this.params.handoutStatsTtlBlocks ?? DEFAULT_HANDOUT_STATS_TTL_BLOCKS;
|
|
5410
|
+
}
|
|
5352
5411
|
get pendingBlocksArchivist() {
|
|
5353
5412
|
return this.params.pendingBlocksArchivist;
|
|
5354
5413
|
}
|
|
@@ -5362,6 +5421,32 @@ var SimpleMempoolViewer = class extends AbstractCreatableProvider {
|
|
|
5362
5421
|
await super.createHandler();
|
|
5363
5422
|
this._windowedBlockViewer = await this.locator.getInstance(WindowedBlockViewerMoniker);
|
|
5364
5423
|
}
|
|
5424
|
+
/** Drop handout stats for the given bundle hashes. Called when a bundle has been evicted or otherwise removed from the pool. */
|
|
5425
|
+
forget(bundleHashes) {
|
|
5426
|
+
for (const hash of bundleHashes) this._handoutStats.delete(hash);
|
|
5427
|
+
}
|
|
5428
|
+
/** Return the subset of the given bundle hashes that are currently considered demoted. */
|
|
5429
|
+
getDemotedBundleHashes(bundleHashes) {
|
|
5430
|
+
return bundleHashes.filter((hash) => this.isDemoted(hash));
|
|
5431
|
+
}
|
|
5432
|
+
/**
|
|
5433
|
+
* Return the bundle hashes in the order they should be evicted under size pressure.
|
|
5434
|
+
* Demoted entries come first, sorted by handouts descending; the remainder is left as-is
|
|
5435
|
+
* so the caller can append by FIFO sequence order.
|
|
5436
|
+
*/
|
|
5437
|
+
getEvictionPriorityOrder(bundleHashes) {
|
|
5438
|
+
const demoted = [];
|
|
5439
|
+
const nonDemoted = [];
|
|
5440
|
+
for (const hash of bundleHashes) {
|
|
5441
|
+
if (this.isDemoted(hash)) demoted.push(hash);
|
|
5442
|
+
else nonDemoted.push(hash);
|
|
5443
|
+
}
|
|
5444
|
+
demoted.sort((a, b) => (this._handoutStats.get(b)?.handouts ?? 0) - (this._handoutStats.get(a)?.handouts ?? 0));
|
|
5445
|
+
return [...demoted, ...nonDemoted];
|
|
5446
|
+
}
|
|
5447
|
+
getHandoutStats(bundleHash) {
|
|
5448
|
+
return this._handoutStats.get(bundleHash);
|
|
5449
|
+
}
|
|
5365
5450
|
async pendingBlocks({ cursor: providedCursor } = {}) {
|
|
5366
5451
|
let cursor = void 0;
|
|
5367
5452
|
if (isHash2(providedCursor)) {
|
|
@@ -5404,6 +5489,7 @@ var SimpleMempoolViewer = class extends AbstractCreatableProvider {
|
|
|
5404
5489
|
})
|
|
5405
5490
|
)).filter(exists9);
|
|
5406
5491
|
const currentBlock = await this.windowedBlockViewer.currentBlock();
|
|
5492
|
+
const currentBlockNumber = currentBlock[0].block;
|
|
5407
5493
|
const evaluated = await Promise.all(
|
|
5408
5494
|
hydratedWithBundle.map(async ({ bundle: bundle3, tx }) => ({
|
|
5409
5495
|
bundle: bundle3,
|
|
@@ -5417,25 +5503,43 @@ var SimpleMempoolViewer = class extends AbstractCreatableProvider {
|
|
|
5417
5503
|
await Promise.all(
|
|
5418
5504
|
deletionCandidates.map(async ({ bundle: bundle3, tx }) => {
|
|
5419
5505
|
await this.deleteBundledTransaction(bundle3);
|
|
5506
|
+
this._handoutStats.delete(bundle3._hash);
|
|
5420
5507
|
this.logger?.debug(`Purged completed/expired bundled transaction: ${bundle3._hash}/${tx[0]._hash}`);
|
|
5421
5508
|
})
|
|
5422
5509
|
);
|
|
5423
|
-
|
|
5424
|
-
|
|
5510
|
+
this.gcHandoutStats(currentBlockNumber);
|
|
5511
|
+
const inclusionCandidates = (await Promise.all(validTransactions.map(async ({ bundle: bundle3, tx }) => {
|
|
5512
|
+
if (await this.isInclusionCandidate(tx, currentBlock, false)) return { bundle: bundle3, tx };
|
|
5425
5513
|
}))).filter(exists9);
|
|
5426
5514
|
const selectionRatio = this.params.mempoolSelectionRatio ?? DEFAULT_MEMPOOL_SELECTION_RATIO;
|
|
5427
|
-
const
|
|
5428
|
-
const
|
|
5429
|
-
const
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5515
|
+
const nonDemoted = inclusionCandidates.filter(({ bundle: bundle3 }) => !this.isDemoted(bundle3._hash));
|
|
5516
|
+
const demoted = inclusionCandidates.filter(({ bundle: bundle3 }) => this.isDemoted(bundle3._hash));
|
|
5517
|
+
const primary = this.selectWithRatio(nonDemoted, limit, selectionRatio);
|
|
5518
|
+
const topupNeeded = limit - primary.length;
|
|
5519
|
+
const topup = topupNeeded > 0 ? this.selectWithRatio(demoted, topupNeeded, selectionRatio) : [];
|
|
5520
|
+
let combined = [...primary, ...topup];
|
|
5521
|
+
if (combined.length === 0 && inclusionCandidates.length > 0) {
|
|
5522
|
+
combined = deduplicateWithBundleBySigner(inclusionCandidates).slice(0, 1);
|
|
5523
|
+
}
|
|
5524
|
+
for (const { bundle: bundle3 } of combined) {
|
|
5525
|
+
this.recordHandout(bundle3._hash, currentBlockNumber);
|
|
5526
|
+
}
|
|
5527
|
+
this.logger?.debug(`Inclusion candidates: ${inclusionCandidates.length} (nonDemoted=${nonDemoted.length}, demoted=${demoted.length}); returning ${combined.length}`);
|
|
5528
|
+
return combined.map(({ tx }) => tx);
|
|
5529
|
+
}
|
|
5530
|
+
isDemoted(bundleHash) {
|
|
5531
|
+
const stats = this._handoutStats.get(bundleHash);
|
|
5532
|
+
return stats !== void 0 && stats.handouts >= this.demotionThreshold;
|
|
5435
5533
|
}
|
|
5436
5534
|
async deleteBundledTransaction(bundle3) {
|
|
5437
5535
|
await this.pendingTransactionsArchivist.delete([bundle3._hash]);
|
|
5438
5536
|
}
|
|
5537
|
+
gcHandoutStats(currentBlockNumber) {
|
|
5538
|
+
const ttl = this.handoutStatsTtlBlocks;
|
|
5539
|
+
for (const [hash, stats] of this._handoutStats) {
|
|
5540
|
+
if (currentBlockNumber - stats.firstHandoutAt > ttl) this._handoutStats.delete(hash);
|
|
5541
|
+
}
|
|
5542
|
+
}
|
|
5439
5543
|
/**
|
|
5440
5544
|
* Evaluates a transaction to determine if it should be purged from the mempool.
|
|
5441
5545
|
* @param tx The transaction to evaluate
|
|
@@ -5468,16 +5572,31 @@ var SimpleMempoolViewer = class extends AbstractCreatableProvider {
|
|
|
5468
5572
|
if (checkForDeletable && await this.isDeletable(tx, currentBlock)) return false;
|
|
5469
5573
|
return true;
|
|
5470
5574
|
}
|
|
5575
|
+
recordHandout(bundleHash, currentBlockNumber) {
|
|
5576
|
+
const existing = this._handoutStats.get(bundleHash);
|
|
5577
|
+
if (existing) {
|
|
5578
|
+
existing.handouts += 1;
|
|
5579
|
+
} else {
|
|
5580
|
+
this._handoutStats.set(bundleHash, { handouts: 1, firstHandoutAt: currentBlockNumber });
|
|
5581
|
+
}
|
|
5582
|
+
}
|
|
5583
|
+
selectWithRatio(group, take, selectionRatio) {
|
|
5584
|
+
if (take <= 0 || group.length === 0) return [];
|
|
5585
|
+
const maxByRatio = Math.ceil(group.length * selectionRatio);
|
|
5586
|
+
const effectiveLimit = Math.min(take, maxByRatio);
|
|
5587
|
+
const randomSelected = group.filter(() => Math.random() < selectionRatio);
|
|
5588
|
+
return deduplicateWithBundleBySigner(randomSelected).slice(0, effectiveLimit);
|
|
5589
|
+
}
|
|
5471
5590
|
};
|
|
5472
|
-
__publicField(SimpleMempoolViewer, "defaultMoniker",
|
|
5591
|
+
__publicField(SimpleMempoolViewer, "defaultMoniker", MempoolViewerMoniker2);
|
|
5473
5592
|
__publicField(SimpleMempoolViewer, "dependencies", [WindowedBlockViewerMoniker]);
|
|
5474
|
-
__publicField(SimpleMempoolViewer, "monikers", [
|
|
5593
|
+
__publicField(SimpleMempoolViewer, "monikers", [MempoolViewerMoniker2]);
|
|
5475
5594
|
SimpleMempoolViewer = __decorateClass([
|
|
5476
5595
|
creatableProvider()
|
|
5477
5596
|
], SimpleMempoolViewer);
|
|
5478
|
-
function
|
|
5597
|
+
function deduplicateWithBundleBySigner(items) {
|
|
5479
5598
|
const seen = /* @__PURE__ */ new Set();
|
|
5480
|
-
return
|
|
5599
|
+
return items.filter(({ tx }) => {
|
|
5481
5600
|
const key = tx[0].addresses.toSorted().join(",");
|
|
5482
5601
|
if (seen.has(key)) return false;
|
|
5483
5602
|
seen.add(key);
|