@lodestar/beacon-node 1.50.0-dev.f2d839a25c → 1.50.0-dev.f2fb26d453
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/lib/api/impl/beacon/pool/index.js +4 -4
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts +1 -0
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +6 -2
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.d.ts +4 -1
- package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.js +4 -3
- package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +4 -0
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/chain.js +3 -3
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/initState.d.ts +2 -9
- package/lib/chain/initState.d.ts.map +1 -1
- package/lib/chain/initState.js +5 -38
- package/lib/chain/initState.js.map +1 -1
- package/lib/chain/opPools/opPool.d.ts +5 -4
- package/lib/chain/opPools/opPool.d.ts.map +1 -1
- package/lib/chain/opPools/opPool.js +62 -18
- package/lib/chain/opPools/opPool.js.map +1 -1
- package/lib/chain/opPools/utils.d.ts +4 -1
- package/lib/chain/opPools/utils.d.ts.map +1 -1
- package/lib/chain/opPools/utils.js +11 -1
- package/lib/chain/opPools/utils.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.d.ts +4 -4
- package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
- package/lib/chain/validation/attesterSlashing.js +3 -0
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/proposerSlashing.d.ts +3 -3
- package/lib/chain/validation/proposerSlashing.d.ts.map +1 -1
- package/lib/chain/validation/proposerSlashing.js +3 -0
- package/lib/chain/validation/proposerSlashing.js.map +1 -1
- package/lib/db/beacon.d.ts.map +1 -1
- package/lib/db/beacon.js +2 -0
- package/lib/db/beacon.js.map +1 -1
- package/lib/db/repositories/proposerSlashing.d.ts +1 -0
- package/lib/db/repositories/proposerSlashing.d.ts.map +1 -1
- package/lib/db/repositories/proposerSlashing.js +5 -1
- package/lib/db/repositories/proposerSlashing.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/network/metadata.d.ts +1 -1
- package/lib/network/metadata.d.ts.map +1 -1
- package/lib/network/metadata.js +17 -17
- package/lib/network/metadata.js.map +1 -1
- package/lib/network/peers/datastore.d.ts +9 -9
- package/lib/network/peers/datastore.d.ts.map +1 -1
- package/lib/network/peers/datastore.js +36 -36
- package/lib/network/peers/datastore.js.map +1 -1
- package/lib/network/processor/gossipHandlers.js +4 -4
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +41 -26
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +9 -5
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +83 -42
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/util/execution.d.ts +2 -0
- package/lib/util/execution.d.ts.map +1 -1
- package/lib/util/execution.js +1 -1
- package/lib/util/execution.js.map +1 -1
- package/package.json +15 -15
- package/src/api/impl/beacon/pool/index.ts +4 -4
- package/src/chain/archiveStore/archiveStore.ts +9 -3
- package/src/chain/archiveStore/utils/pruneHistory.ts +6 -4
- package/src/chain/blocks/importBlock.ts +4 -0
- package/src/chain/chain.ts +3 -3
- package/src/chain/initState.ts +8 -60
- package/src/chain/opPools/opPool.ts +91 -18
- package/src/chain/opPools/utils.ts +31 -3
- package/src/chain/validation/attesterSlashing.ts +7 -4
- package/src/chain/validation/proposerSlashing.ts +7 -4
- package/src/db/beacon.ts +2 -0
- package/src/db/repositories/proposerSlashing.ts +6 -1
- package/src/index.ts +1 -1
- package/src/network/metadata.ts +17 -17
- package/src/network/peers/datastore.ts +36 -36
- package/src/network/processor/gossipHandlers.ts +4 -4
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +42 -28
- package/src/sync/unknownBlock.ts +94 -46
- package/src/util/execution.ts +1 -1
package/src/sync/unknownBlock.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {ChainEvent, ChainEventData, IBeaconChain} from "../chain/index.js";
|
|
|
15
15
|
import {validateGloasBlockDataColumnSidecars} from "../chain/validation/dataColumnSidecar.js";
|
|
16
16
|
import {validateGossipExecutionPayloadEnvelope} from "../chain/validation/executionPayloadEnvelope.js";
|
|
17
17
|
import {Metrics} from "../metrics/index.js";
|
|
18
|
-
import {INetwork, NetworkEvent, NetworkEventData, prettyPrintPeerIdStr} from "../network/index.js";
|
|
18
|
+
import {INetwork, NetworkEvent, NetworkEventData, PeerAction, prettyPrintPeerIdStr} from "../network/index.js";
|
|
19
19
|
import {PeerSyncMeta} from "../network/peers/peersData.js";
|
|
20
20
|
import {MAX_PEERS_PER_ROOT} from "../network/processor/constants.js";
|
|
21
21
|
import {ClockEvent} from "../util/clock.js";
|
|
@@ -442,6 +442,11 @@ export class BlockInputSync {
|
|
|
442
442
|
};
|
|
443
443
|
|
|
444
444
|
private addByRootHex = (rootHex: RootHex, peerIdStr?: PeerIdStr): boolean => {
|
|
445
|
+
if (this.knownBadBlocks.has(rootHex)) {
|
|
446
|
+
this.logger.debug("Ignoring known bad block root", {root: rootHex, peerIdStr: peerIdStr ?? "unknown peer"});
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
|
|
445
450
|
let pendingBlock = this.pendingBlocks.get(rootHex);
|
|
446
451
|
let added = false;
|
|
447
452
|
if (!pendingBlock) {
|
|
@@ -477,6 +482,11 @@ export class BlockInputSync {
|
|
|
477
482
|
};
|
|
478
483
|
|
|
479
484
|
private addByBlockInput = (blockInput: IBlockInput, peerIdStr?: string): void => {
|
|
485
|
+
if (this.knownBadBlocks.has(blockInput.blockRootHex)) {
|
|
486
|
+
this.logger.debug("Ignoring known bad block", {slot: blockInput.slot, root: blockInput.blockRootHex, peerIdStr});
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
|
|
480
490
|
let pendingBlock = this.pendingBlocks.get(blockInput.blockRootHex);
|
|
481
491
|
// if entry is missing or was added via rootHex and now we have more complete information overwrite
|
|
482
492
|
// the existing information with the more complete cache entry
|
|
@@ -513,6 +523,15 @@ export class BlockInputSync {
|
|
|
513
523
|
};
|
|
514
524
|
|
|
515
525
|
private addByPayloadRootHex = (rootHex: RootHex, peerIdStr?: PeerIdStr, slot?: Slot): boolean => {
|
|
526
|
+
if (this.knownBadBlocks.has(rootHex)) {
|
|
527
|
+
this.logger.debug("Ignoring payload for known bad block root", {
|
|
528
|
+
slot: slot ?? "unknown",
|
|
529
|
+
root: rootHex,
|
|
530
|
+
peerIdStr,
|
|
531
|
+
});
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
|
|
516
535
|
let pendingPayload = this.pendingPayloads.get(rootHex);
|
|
517
536
|
let added = false;
|
|
518
537
|
if (!pendingPayload) {
|
|
@@ -581,6 +600,15 @@ export class BlockInputSync {
|
|
|
581
600
|
peerIdStr?: PeerIdStr,
|
|
582
601
|
envelope?: gloas.SignedExecutionPayloadEnvelope
|
|
583
602
|
): void => {
|
|
603
|
+
if (this.knownBadBlocks.has(payloadInput.blockRootHex)) {
|
|
604
|
+
this.logger.debug("Ignoring payload input for known bad block root", {
|
|
605
|
+
slot: payloadInput.slot,
|
|
606
|
+
root: payloadInput.blockRootHex,
|
|
607
|
+
peerIdStr,
|
|
608
|
+
});
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
|
|
584
612
|
const pendingPayload = this.toPendingPayloadInput(
|
|
585
613
|
payloadInput,
|
|
586
614
|
this.pendingPayloads.get(payloadInput.blockRootHex),
|
|
@@ -654,6 +682,7 @@ export class BlockInputSync {
|
|
|
654
682
|
return {kind: "ready"};
|
|
655
683
|
}
|
|
656
684
|
|
|
685
|
+
// The parent's payload is known but does not match `parentBlockHashHex`
|
|
657
686
|
if (this.chain.forkChoice.hasPayloadHexUnsafe(parentRootHex)) {
|
|
658
687
|
return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
|
|
659
688
|
}
|
|
@@ -1032,7 +1061,8 @@ export class BlockInputSync {
|
|
|
1032
1061
|
}
|
|
1033
1062
|
} else if (blockSlot <= finalizedSlot) {
|
|
1034
1063
|
// the common ancestor of the downloading chain and canonical chain should be at least the finalized slot and
|
|
1035
|
-
// we should found it through forkchoice. If not,
|
|
1064
|
+
// we should found it through forkchoice. If not, drop the chain without penalizing peers because pending entries are
|
|
1065
|
+
// block retained on failed download, so finalization can pass the block while it is still pending
|
|
1036
1066
|
// 0 - 1 - ... - n - finalizedSlot
|
|
1037
1067
|
// \
|
|
1038
1068
|
// parent 1 - parent 2 - ... - unknownParent block
|
|
@@ -1040,7 +1070,7 @@ export class BlockInputSync {
|
|
|
1040
1070
|
...logCtx2,
|
|
1041
1071
|
finalizedSlot,
|
|
1042
1072
|
});
|
|
1043
|
-
this.
|
|
1073
|
+
this.removeAllDescendants(block, DroppedItemReason.belowFinalized);
|
|
1044
1074
|
} else {
|
|
1045
1075
|
this.onUnknownBlockRoot({rootHex: pending.blockInput.parentRootHex, source: BlockInputSource.byRoot});
|
|
1046
1076
|
}
|
|
@@ -1172,15 +1202,18 @@ export class BlockInputSync {
|
|
|
1172
1202
|
break;
|
|
1173
1203
|
|
|
1174
1204
|
case BlockErrorCode.EXECUTION_ENGINE_INVALID:
|
|
1175
|
-
//
|
|
1205
|
+
// Ban but do not downscore: optimistic-sync peers may forward and serve blocks whose payload is later
|
|
1206
|
+
// rejected by the execution engine. Per the spec, an INVALID execution payload SHOULD NOT cause a peer
|
|
1207
|
+
// to be down-scored or disconnected, only consensus-layer invalidity MAY.
|
|
1208
|
+
// https://github.com/ethereum/consensus-specs/blob/master/specs/bellatrix/p2p-interface.md#the-reqresp-domain
|
|
1176
1209
|
this.logger.debug("Execution engine rejected block from unknown parent sync", errorData, res.err);
|
|
1177
|
-
this.
|
|
1210
|
+
this.removeAndBanAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
|
|
1178
1211
|
break;
|
|
1179
1212
|
|
|
1180
1213
|
default:
|
|
1181
1214
|
// Block is not correct with respect to our chain. Log error loudly
|
|
1182
1215
|
this.logger.debug("Error processing block from unknown parent sync", errorData, res.err);
|
|
1183
|
-
this.
|
|
1216
|
+
this.removeAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
|
|
1184
1217
|
}
|
|
1185
1218
|
}
|
|
1186
1219
|
|
|
@@ -1478,11 +1511,11 @@ export class BlockInputSync {
|
|
|
1478
1511
|
}
|
|
1479
1512
|
|
|
1480
1513
|
const {peerId, client: peerClient} = peerMeta;
|
|
1481
|
-
cacheItem.peerIdStrings.add(peerId);
|
|
1482
1514
|
|
|
1483
1515
|
try {
|
|
1484
1516
|
if (!envelope) {
|
|
1485
1517
|
envelope = await this.fetchExecutionPayloadEnvelope(peerId, blockRoot, rootHex);
|
|
1518
|
+
cacheItem.peerIdStrings.add(peerId);
|
|
1486
1519
|
const slotWasUnknown = typeof slot !== "number";
|
|
1487
1520
|
slot = envelope.message.payload.slotNumber;
|
|
1488
1521
|
if (slotWasUnknown) {
|
|
@@ -1524,6 +1557,8 @@ export class BlockInputSync {
|
|
|
1524
1557
|
const missing = pendingPayload.payloadInput.getMissingSampledColumnMeta().missing;
|
|
1525
1558
|
if (missing.length > 0) {
|
|
1526
1559
|
const columnSidecars = await this.fetchPayloadColumns(peerMeta, pendingPayload.payloadInput, missing);
|
|
1560
|
+
// toPendingPayloadInput copied cacheItem's set, so add to the object that is carried forward
|
|
1561
|
+
pendingPayload.peerIdStrings.add(peerId);
|
|
1527
1562
|
const seenTimestampSec = Date.now() / 1000;
|
|
1528
1563
|
for (const columnSidecar of columnSidecars) {
|
|
1529
1564
|
if (pendingPayload.payloadInput.hasColumn(columnSidecar.index)) {
|
|
@@ -1716,8 +1751,6 @@ export class BlockInputSync {
|
|
|
1716
1751
|
}
|
|
1717
1752
|
const {peerId, client: peerClient} = peerMeta;
|
|
1718
1753
|
|
|
1719
|
-
cacheItem.peerIdStrings.add(peerId);
|
|
1720
|
-
|
|
1721
1754
|
try {
|
|
1722
1755
|
const downloadResult = await downloadByRoot({
|
|
1723
1756
|
config: this.config,
|
|
@@ -1728,6 +1761,7 @@ export class BlockInputSync {
|
|
|
1728
1761
|
cacheItem,
|
|
1729
1762
|
});
|
|
1730
1763
|
cacheItem = downloadResult.result;
|
|
1764
|
+
cacheItem.peerIdStrings.add(peerId);
|
|
1731
1765
|
if (slot === undefined) {
|
|
1732
1766
|
slot = cacheItem.blockInput.slot;
|
|
1733
1767
|
// we were not able to observe the time into slot when starting the fetch, do it now
|
|
@@ -1843,40 +1877,6 @@ export class BlockInputSync {
|
|
|
1843
1877
|
throw Error(message);
|
|
1844
1878
|
}
|
|
1845
1879
|
|
|
1846
|
-
/**
|
|
1847
|
-
* Gets all descendant blocks of `block` recursively from `pendingBlocks`.
|
|
1848
|
-
* Assumes that if a parent block does not exist or is not processable, all descendant blocks are bad too.
|
|
1849
|
-
* Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
|
|
1850
|
-
* referenced more than one bad block.
|
|
1851
|
-
*/
|
|
1852
|
-
private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem, headReason: DroppedItemReason): void {
|
|
1853
|
-
// Get all blocks that are a descendant of this one
|
|
1854
|
-
const badPendingBlocks = this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent);
|
|
1855
|
-
// just console log and do not penalize on pending/bad blocks for debugging
|
|
1856
|
-
// console.log("removeAndDownscoreAllDescendants", {block});
|
|
1857
|
-
|
|
1858
|
-
for (const block of badPendingBlocks) {
|
|
1859
|
-
//
|
|
1860
|
-
// TODO(fulu): why is this commented out here?
|
|
1861
|
-
//
|
|
1862
|
-
// this.knownBadBlocks.add(block.blockRootHex);
|
|
1863
|
-
// for (const peerIdStr of block.peerIdStrings) {
|
|
1864
|
-
// // TODO: Refactor peerRpcScores to work with peerIdStr only
|
|
1865
|
-
// this.network.reportPeer(peerIdStr, PeerAction.LowToleranceError, "BadBlockByRoot");
|
|
1866
|
-
// }
|
|
1867
|
-
this.logger.debug("ignored Banning unknown block", {
|
|
1868
|
-
slot: getBlockInputSyncCacheItemSlot(block),
|
|
1869
|
-
root: getBlockInputSyncCacheItemRootHex(block),
|
|
1870
|
-
peerIdStrings: Array.from(block.peerIdStrings)
|
|
1871
|
-
.map((id) => prettyPrintPeerIdStr(id))
|
|
1872
|
-
.join(","),
|
|
1873
|
-
});
|
|
1874
|
-
}
|
|
1875
|
-
|
|
1876
|
-
// Prune knownBadBlocks
|
|
1877
|
-
pruneSetToMax(this.knownBadBlocks, MAX_KNOWN_BAD_BLOCKS);
|
|
1878
|
-
}
|
|
1879
|
-
|
|
1880
1880
|
// Once a parent payload is invalid, every descendant waiting on that payload lineage becomes unrecoverable too.
|
|
1881
1881
|
private removePendingPayloadAndDescendants(rootHex: RootHex, headReason: DroppedItemReason): void {
|
|
1882
1882
|
// Keep PayloadEnvelopeInput resident in the seen cache. importBlock() owns that object and
|
|
@@ -1903,13 +1903,61 @@ export class BlockInputSync {
|
|
|
1903
1903
|
}
|
|
1904
1904
|
}
|
|
1905
1905
|
|
|
1906
|
+
/**
|
|
1907
|
+
* Same as `removeAndBanAllDescendants`, and downscores every peer that referenced or served a banned item, once per
|
|
1908
|
+
* peer. Only call for consensus-layer invalidity, never for an INVALID execution payload:
|
|
1909
|
+
* https://github.com/ethereum/consensus-specs/blob/master/specs/bellatrix/p2p-interface.md#the-reqresp-domain
|
|
1910
|
+
*/
|
|
1911
|
+
private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem, headReason: DroppedItemReason): void {
|
|
1912
|
+
const peersToReport = new Set<PeerIdStr>();
|
|
1913
|
+
for (const bannedBlock of this.removeAndBanAllDescendants(block, headReason)) {
|
|
1914
|
+
for (const peerIdStr of bannedBlock.peerIdStrings) {
|
|
1915
|
+
peersToReport.add(peerIdStr);
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
for (const peerIdStr of peersToReport) {
|
|
1920
|
+
this.network.reportPeer(peerIdStr, PeerAction.LowToleranceError, headReason);
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
/**
|
|
1925
|
+
* Removes `block` and all its pending descendants and bans their roots in `knownBadBlocks`. Only call when the chain
|
|
1926
|
+
* is provably bad: a banned root is never searched for again. Returns the banned items.
|
|
1927
|
+
*/
|
|
1928
|
+
private removeAndBanAllDescendants(
|
|
1929
|
+
block: BlockInputSyncCacheItem,
|
|
1930
|
+
headReason: DroppedItemReason
|
|
1931
|
+
): BlockInputSyncCacheItem[] {
|
|
1932
|
+
const bannedBlocks: BlockInputSyncCacheItem[] = [];
|
|
1933
|
+
for (const badBlock of this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent)) {
|
|
1934
|
+
const rootHex = getBlockInputSyncCacheItemRootHex(badBlock);
|
|
1935
|
+
// a gossip import may race a failing sync path, never ban a root fork choice has imported
|
|
1936
|
+
if (this.chain.forkChoice.hasBlockHex(rootHex)) {
|
|
1937
|
+
continue;
|
|
1938
|
+
}
|
|
1939
|
+
this.knownBadBlocks.add(rootHex);
|
|
1940
|
+
bannedBlocks.push(badBlock);
|
|
1941
|
+
this.logger.debug("Banning unknown block", {
|
|
1942
|
+
slot: getBlockInputSyncCacheItemSlot(badBlock),
|
|
1943
|
+
root: rootHex,
|
|
1944
|
+
reason: headReason,
|
|
1945
|
+
peerIdStrings: Array.from(badBlock.peerIdStrings)
|
|
1946
|
+
.map((id) => prettyPrintPeerIdStr(id))
|
|
1947
|
+
.join(","),
|
|
1948
|
+
});
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
pruneSetToMax(this.knownBadBlocks, MAX_KNOWN_BAD_BLOCKS);
|
|
1952
|
+
return bannedBlocks;
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1906
1955
|
private removeAllDescendants(
|
|
1907
1956
|
block: BlockInputSyncCacheItem,
|
|
1908
1957
|
headReason: DroppedItemReason,
|
|
1909
1958
|
descendantReason: DroppedItemReason = DroppedItemReason.invalidParent
|
|
1910
1959
|
): BlockInputSyncCacheItem[] {
|
|
1911
1960
|
const rootHex = getBlockInputSyncCacheItemRootHex(block);
|
|
1912
|
-
const slot = getBlockInputSyncCacheItemSlot(block);
|
|
1913
1961
|
// Get all blocks that are a descendant of this one (index 0 is the head item itself)
|
|
1914
1962
|
const badPendingBlocks = [block, ...getAllDescendantBlocks(rootHex, this.pendingBlocks)];
|
|
1915
1963
|
|
|
@@ -1926,8 +1974,8 @@ export class BlockInputSync {
|
|
|
1926
1974
|
// Keep PayloadEnvelopeInput resident in the seen cache for consistency with the
|
|
1927
1975
|
// importBlock()-owned lifecycle.
|
|
1928
1976
|
this.logger.debug("Removing bad/unknown/incomplete BlockInputSyncCacheItem", {
|
|
1929
|
-
slot,
|
|
1930
|
-
|
|
1977
|
+
slot: getBlockInputSyncCacheItemSlot(block),
|
|
1978
|
+
root: rootHex,
|
|
1931
1979
|
});
|
|
1932
1980
|
}
|
|
1933
1981
|
|
package/src/util/execution.ts
CHANGED
|
@@ -260,7 +260,7 @@ export async function getDataColumnSidecarsFromExecution(
|
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
/** engine_getPayloadBodiesByHashV2: every EL must accept requests of up to 32 hashes, larger ones may fail with -38004 */
|
|
263
|
-
const MAX_BODIES_PER_REQUEST = 32;
|
|
263
|
+
export const MAX_BODIES_PER_REQUEST = 32;
|
|
264
264
|
|
|
265
265
|
type SlotEnvelopeBytes = {slot: Slot; envelopeBytes: Uint8Array};
|
|
266
266
|
|