@lodestar/beacon-node 1.47.0 → 1.48.0-dev.042c96183c
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/blocks/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/blocks/index.js +8 -11
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js +14 -0
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/config/index.d.ts.map +1 -1
- package/lib/api/impl/config/index.js +4 -1
- package/lib/api/impl/config/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +44 -39
- package/lib/api/impl/validator/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 +5 -1
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.js +1 -0
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/metrics.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/metrics.js +12 -1
- package/lib/chain/archiveStore/historicalState/metrics.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/types.d.ts +2 -0
- package/lib/chain/archiveStore/historicalState/types.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/types.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/worker.js +4 -1
- package/lib/chain/archiveStore/historicalState/worker.js.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +9 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.js +68 -38
- package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts +5 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +12 -18
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/index.d.ts +8 -4
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +89 -23
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/types.d.ts +8 -0
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/types.js.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.js +26 -11
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +5 -2
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/writeBlockInputToDb.d.ts.map +1 -1
- package/lib/chain/blocks/writeBlockInputToDb.js +9 -16
- package/lib/chain/blocks/writeBlockInputToDb.js.map +1 -1
- package/lib/chain/chain.d.ts +12 -6
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +131 -76
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +1 -1
- package/lib/chain/emitter.js +1 -1
- package/lib/chain/errors/blockError.d.ts +19 -7
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +2 -2
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/dataColumnSidecarError.d.ts +15 -2
- package/lib/chain/errors/dataColumnSidecarError.d.ts.map +1 -1
- package/lib/chain/errors/dataColumnSidecarError.js.map +1 -1
- package/lib/chain/errors/executionPayloadBid.d.ts +9 -0
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +2 -0
- package/lib/chain/errors/executionPayloadBid.js.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.d.ts +10 -11
- package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.js +0 -2
- package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/errors/gossipValidation.d.ts +2 -1
- package/lib/chain/errors/gossipValidation.d.ts.map +1 -1
- package/lib/chain/errors/gossipValidation.js +1 -0
- package/lib/chain/errors/gossipValidation.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +2 -0
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +6 -6
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/lightClient/index.d.ts +3 -3
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +21 -23
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/lightClient/proofs.d.ts +2 -1
- package/lib/chain/lightClient/proofs.d.ts.map +1 -1
- package/lib/chain/lightClient/proofs.js +5 -1
- package/lib/chain/lightClient/proofs.js.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts +5 -0
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +40 -15
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js +3 -25
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +4 -2
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +57 -72
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +1 -0
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/interface.js +1 -0
- package/lib/chain/regen/interface.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +74 -63
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.js +38 -13
- package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.d.ts +15 -3
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +199 -28
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +10 -29
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +5 -6
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts +7 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +22 -5
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/db/beacon.d.ts +14 -5
- package/lib/db/beacon.d.ts.map +1 -1
- package/lib/db/beacon.js +17 -3
- package/lib/db/beacon.js.map +1 -1
- package/lib/db/dataColumnStore.d.ts +39 -0
- package/lib/db/dataColumnStore.d.ts.map +1 -0
- package/lib/db/dataColumnStore.js +81 -0
- package/lib/db/dataColumnStore.js.map +1 -0
- package/lib/db/flatFileStore/atomicWrite.d.ts +8 -0
- package/lib/db/flatFileStore/atomicWrite.d.ts.map +1 -0
- package/lib/db/flatFileStore/atomicWrite.js +61 -0
- package/lib/db/flatFileStore/atomicWrite.js.map +1 -0
- package/lib/db/flatFileStore/dcolFormat.d.ts +90 -0
- package/lib/db/flatFileStore/dcolFormat.d.ts.map +1 -0
- package/lib/db/flatFileStore/dcolFormat.js +286 -0
- package/lib/db/flatFileStore/dcolFormat.js.map +1 -0
- package/lib/db/flatFileStore/errors.d.ts +82 -0
- package/lib/db/flatFileStore/errors.d.ts.map +1 -0
- package/lib/db/flatFileStore/errors.js +32 -0
- package/lib/db/flatFileStore/errors.js.map +1 -0
- package/lib/db/flatFileStore/flatFileStore.d.ts +41 -0
- package/lib/db/flatFileStore/flatFileStore.d.ts.map +1 -0
- package/lib/db/flatFileStore/flatFileStore.js +251 -0
- package/lib/db/flatFileStore/flatFileStore.js.map +1 -0
- package/lib/db/flatFileStore/index.d.ts +4 -0
- package/lib/db/flatFileStore/index.d.ts.map +1 -0
- package/lib/db/flatFileStore/index.js +2 -0
- package/lib/db/flatFileStore/index.js.map +1 -0
- package/lib/db/flatFileStore/interface.d.ts +25 -0
- package/lib/db/flatFileStore/interface.d.ts.map +1 -0
- package/lib/db/flatFileStore/interface.js +2 -0
- package/lib/db/flatFileStore/interface.js.map +1 -0
- package/lib/db/flatFileStore/metrics.d.ts +24 -0
- package/lib/db/flatFileStore/metrics.d.ts.map +1 -0
- package/lib/db/flatFileStore/metrics.js +25 -0
- package/lib/db/flatFileStore/metrics.js.map +1 -0
- package/lib/db/flatFileStore/path.d.ts +9 -0
- package/lib/db/flatFileStore/path.d.ts.map +1 -0
- package/lib/db/flatFileStore/path.js +21 -0
- package/lib/db/flatFileStore/path.js.map +1 -0
- package/lib/db/flatFileStore/slotIndex.d.ts +14 -0
- package/lib/db/flatFileStore/slotIndex.d.ts.map +1 -0
- package/lib/db/flatFileStore/slotIndex.js +46 -0
- package/lib/db/flatFileStore/slotIndex.js.map +1 -0
- package/lib/db/flatFileStore/snappy.d.ts +3 -0
- package/lib/db/flatFileStore/snappy.d.ts.map +1 -0
- package/lib/db/flatFileStore/snappy.js +12 -0
- package/lib/db/flatFileStore/snappy.js.map +1 -0
- package/lib/db/index.d.ts +1 -0
- package/lib/db/index.d.ts.map +1 -1
- package/lib/db/interface.d.ts +8 -1
- package/lib/db/interface.d.ts.map +1 -1
- package/lib/db/repositories/blockArchive.d.ts +8 -1
- package/lib/db/repositories/blockArchive.d.ts.map +1 -1
- package/lib/db/repositories/blockArchive.js +65 -28
- package/lib/db/repositories/blockArchive.js.map +1 -1
- package/lib/db/repositories/blockArchiveIndex.d.ts +1 -2
- package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
- package/lib/db/repositories/blockArchiveIndex.js +3 -7
- package/lib/db/repositories/blockArchiveIndex.js.map +1 -1
- package/lib/execution/builder/apiClient.d.ts +6 -0
- package/lib/execution/builder/apiClient.d.ts.map +1 -1
- package/lib/execution/builder/apiClient.js +19 -1
- package/lib/execution/builder/apiClient.js.map +1 -1
- package/lib/execution/builder/validateBid.d.ts +1 -0
- package/lib/execution/builder/validateBid.d.ts.map +1 -1
- package/lib/execution/builder/validateBid.js +17 -6
- package/lib/execution/builder/validateBid.js.map +1 -1
- package/lib/execution/engine/mock.d.ts.map +1 -1
- package/lib/execution/engine/mock.js +4 -1
- package/lib/execution/engine/mock.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +32 -4
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +78 -8
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/monitoring/clientStats.js +1 -1
- package/lib/monitoring/clientStats.js.map +1 -1
- package/lib/network/gossip/encoding.d.ts.map +1 -1
- package/lib/network/gossip/encoding.js +0 -7
- package/lib/network/gossip/encoding.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +2 -1
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +4 -20
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +7 -6
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +388 -285
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/gossipQueues/indexed.d.ts.map +1 -1
- package/lib/network/processor/gossipQueues/indexed.js +0 -1
- package/lib/network/processor/gossipQueues/indexed.js.map +1 -1
- package/lib/network/processor/index.d.ts +49 -3
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +270 -122
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +112 -91
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js +2 -0
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js.map +1 -1
- package/lib/network/reqresp/protocols.d.ts.map +1 -1
- package/lib/network/reqresp/protocols.js +6 -22
- package/lib/network/reqresp/protocols.js.map +1 -1
- package/lib/network/reqresp/rateLimit.js +2 -1
- package/lib/network/reqresp/rateLimit.js.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts +2 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js +14 -9
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
- package/lib/node/nodejs.d.ts +2 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +4 -2
- package/lib/node/nodejs.js.map +1 -1
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +9 -2
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +25 -2
- package/lib/sync/range/range.js.map +1 -1
- package/lib/util/sszBytes.d.ts +6 -0
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +1 -1
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +19 -20
- package/src/api/impl/beacon/blocks/index.ts +12 -14
- package/src/api/impl/beacon/state/utils.ts +15 -0
- package/src/api/impl/config/index.ts +4 -1
- package/src/api/impl/validator/index.ts +49 -43
- package/src/chain/archiveStore/archiveStore.ts +12 -1
- package/src/chain/archiveStore/historicalState/historicalStateRegen.ts +1 -0
- package/src/chain/archiveStore/historicalState/metrics.ts +14 -1
- package/src/chain/archiveStore/historicalState/types.ts +2 -0
- package/src/chain/archiveStore/historicalState/worker.ts +4 -1
- package/src/chain/archiveStore/utils/archiveBlocks.ts +73 -42
- package/src/chain/blocks/importBlock.ts +25 -20
- package/src/chain/blocks/index.ts +126 -29
- package/src/chain/blocks/types.ts +9 -0
- package/src/chain/blocks/utils/chainSegment.ts +26 -12
- package/src/chain/blocks/verifyBlock.ts +5 -2
- package/src/chain/blocks/writeBlockInputToDb.ts +10 -17
- package/src/chain/chain.ts +155 -85
- package/src/chain/emitter.ts +1 -1
- package/src/chain/errors/blockError.ts +22 -10
- package/src/chain/errors/dataColumnSidecarError.ts +24 -8
- package/src/chain/errors/executionPayloadBid.ts +8 -0
- package/src/chain/errors/executionPayloadEnvelope.ts +14 -11
- package/src/chain/errors/gossipValidation.ts +1 -0
- package/src/chain/forkChoice/index.ts +2 -0
- package/src/chain/interface.ts +6 -6
- package/src/chain/lightClient/index.ts +32 -36
- package/src/chain/lightClient/proofs.ts +10 -0
- package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
- package/src/chain/prepareNextSlot.ts +47 -18
- package/src/chain/produceBlock/computeNewStateRoot.ts +3 -38
- package/src/chain/produceBlock/produceBlockBody.ts +62 -79
- package/src/chain/regen/interface.ts +1 -0
- package/src/chain/validation/block.ts +77 -79
- package/src/chain/validation/dataColumnSidecar.ts +47 -14
- package/src/chain/validation/executionPayloadBid.ts +230 -32
- package/src/chain/validation/executionPayloadEnvelope.ts +10 -37
- package/src/chain/validation/payloadAttestationMessage.ts +8 -9
- package/src/chain/validatorMonitor.ts +24 -7
- package/src/db/beacon.ts +33 -6
- package/src/db/dataColumnStore.ts +113 -0
- package/src/db/flatFileStore/atomicWrite.ts +65 -0
- package/src/db/flatFileStore/dcolFormat.ts +389 -0
- package/src/db/flatFileStore/errors.ts +53 -0
- package/src/db/flatFileStore/flatFileStore.ts +310 -0
- package/src/db/flatFileStore/index.ts +3 -0
- package/src/db/flatFileStore/interface.ts +21 -0
- package/src/db/flatFileStore/metrics.ts +48 -0
- package/src/db/flatFileStore/path.ts +32 -0
- package/src/db/flatFileStore/slotIndex.ts +56 -0
- package/src/db/flatFileStore/snappy.ts +14 -0
- package/src/db/index.ts +1 -0
- package/src/db/interface.ts +9 -1
- package/src/db/repositories/blockArchive.ts +89 -30
- package/src/db/repositories/blockArchiveIndex.ts +4 -9
- package/src/execution/builder/apiClient.ts +21 -1
- package/src/execution/builder/validateBid.ts +26 -7
- package/src/execution/engine/mock.ts +4 -1
- package/src/metrics/metrics/lodestar.ts +83 -9
- package/src/monitoring/clientStats.ts +1 -1
- package/src/network/gossip/encoding.ts +0 -7
- package/src/network/gossip/topic.ts +3 -25
- package/src/network/network.ts +9 -6
- package/src/network/processor/gossipHandlers.ts +500 -355
- package/src/network/processor/gossipQueues/indexed.ts +0 -1
- package/src/network/processor/index.ts +312 -176
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +139 -105
- package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +2 -0
- package/src/network/reqresp/protocols.ts +7 -24
- package/src/network/reqresp/rateLimit.ts +2 -1
- package/src/network/reqresp/utils/dataColumnResponseValidation.ts +15 -7
- package/src/node/nodejs.ts +6 -1
- package/src/sync/range/chain.ts +9 -2
- package/src/sync/range/range.ts +24 -2
- package/src/util/sszBytes.ts +1 -1
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
computeStartSlotAtEpoch,
|
|
12
12
|
getBlockHeaderProposerSignatureSetByHeaderSlot,
|
|
13
13
|
} from "@lodestar/state-transition";
|
|
14
|
-
import {DataColumnSidecar, Root, Slot, SubnetID, ValidatorIndex, fulu, gloas, ssz} from "@lodestar/types";
|
|
14
|
+
import {DataColumnSidecar, Root, RootHex, Slot, SubnetID, ValidatorIndex, fulu, gloas, ssz} from "@lodestar/types";
|
|
15
15
|
import {byteArrayEquals, toRootHex, verifyMerkleBranch} from "@lodestar/utils";
|
|
16
16
|
import {BeaconMetrics} from "../../metrics/metrics/beacon.js";
|
|
17
17
|
import {Metrics} from "../../metrics/metrics.js";
|
|
@@ -39,12 +39,14 @@ export async function validateGossipFuluDataColumnSidecar(
|
|
|
39
39
|
const blockRootHex = toRootHex(ssz.phase0.BeaconBlockHeader.hashTreeRoot(blockHeader));
|
|
40
40
|
|
|
41
41
|
// 1) [REJECT] The sidecar is valid as verified by verify_data_column_sidecar
|
|
42
|
-
verifyFuluDataColumnSidecar(chain.config, dataColumnSidecar);
|
|
42
|
+
verifyFuluDataColumnSidecar(chain.config, dataColumnSidecar, blockRootHex);
|
|
43
43
|
|
|
44
44
|
// 2) [REJECT] The sidecar is for the correct subnet -- i.e. compute_subnet_for_data_column_sidecar(sidecar.index) == subnet_id
|
|
45
45
|
if (computeSubnetForDataColumnSidecar(chain.config, dataColumnSidecar) !== gossipSubnet) {
|
|
46
46
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
47
47
|
code: DataColumnSidecarErrorCode.INVALID_SUBNET,
|
|
48
|
+
slot: blockHeader.slot,
|
|
49
|
+
root: blockRootHex,
|
|
48
50
|
columnIndex: dataColumnSidecar.index,
|
|
49
51
|
gossipSubnet: gossipSubnet,
|
|
50
52
|
});
|
|
@@ -100,8 +102,9 @@ export async function validateGossipFuluDataColumnSidecar(
|
|
|
100
102
|
if (parentBlock.slot >= blockHeader.slot) {
|
|
101
103
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
102
104
|
code: DataColumnSidecarErrorCode.NOT_LATER_THAN_PARENT,
|
|
103
|
-
parentSlot: parentBlock.slot,
|
|
104
105
|
slot: blockHeader.slot,
|
|
106
|
+
root: blockRootHex,
|
|
107
|
+
parentSlot: parentBlock.slot,
|
|
105
108
|
});
|
|
106
109
|
}
|
|
107
110
|
|
|
@@ -140,6 +143,8 @@ export async function validateGossipFuluDataColumnSidecar(
|
|
|
140
143
|
if (proposerIndex !== expectedProposerIndex) {
|
|
141
144
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
142
145
|
code: DataColumnSidecarErrorCode.INCORRECT_PROPOSER,
|
|
146
|
+
slot: blockHeader.slot,
|
|
147
|
+
root: blockRootHex,
|
|
143
148
|
actualProposerIndex: proposerIndex,
|
|
144
149
|
expectedProposerIndex,
|
|
145
150
|
});
|
|
@@ -161,9 +166,9 @@ export async function validateGossipFuluDataColumnSidecar(
|
|
|
161
166
|
) {
|
|
162
167
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
163
168
|
code: DataColumnSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID,
|
|
164
|
-
blockRoot: blockRootHex,
|
|
165
|
-
index: dataColumnSidecar.index,
|
|
166
169
|
slot: blockHeader.slot,
|
|
170
|
+
root: blockRootHex,
|
|
171
|
+
index: dataColumnSidecar.index,
|
|
167
172
|
});
|
|
168
173
|
}
|
|
169
174
|
|
|
@@ -185,7 +190,8 @@ export async function validateGossipFuluDataColumnSidecar(
|
|
|
185
190
|
if (!valid) {
|
|
186
191
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
187
192
|
code: DataColumnSidecarErrorCode.INCLUSION_PROOF_INVALID,
|
|
188
|
-
slot:
|
|
193
|
+
slot: blockHeader.slot,
|
|
194
|
+
root: blockRootHex,
|
|
189
195
|
columnIndex: dataColumnSidecar.index,
|
|
190
196
|
});
|
|
191
197
|
}
|
|
@@ -204,6 +210,7 @@ export async function validateGossipFuluDataColumnSidecar(
|
|
|
204
210
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
205
211
|
code: DataColumnSidecarErrorCode.INVALID_KZG_PROOF,
|
|
206
212
|
slot: blockHeader.slot,
|
|
213
|
+
root: blockRootHex,
|
|
207
214
|
columnIndex: dataColumnSidecar.index,
|
|
208
215
|
});
|
|
209
216
|
} finally {
|
|
@@ -240,6 +247,7 @@ export async function validateGossipGloasDataColumnSidecar(
|
|
|
240
247
|
if (block.slot !== dataColumnSidecar.slot) {
|
|
241
248
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
242
249
|
code: DataColumnSidecarErrorCode.INCORRECT_SIDECAR_SLOT,
|
|
250
|
+
root: blockRootHex,
|
|
243
251
|
columnIndex: dataColumnSidecar.index,
|
|
244
252
|
expected: block.slot,
|
|
245
253
|
actual: dataColumnSidecar.slot,
|
|
@@ -248,12 +256,14 @@ export async function validateGossipGloasDataColumnSidecar(
|
|
|
248
256
|
|
|
249
257
|
// [REJECT] The sidecar must pass verify_data_column_sidecar against the block commitments
|
|
250
258
|
const kzgCommitments = payloadInput.getBlobKzgCommitments();
|
|
251
|
-
verifyGloasDataColumnSidecar(dataColumnSidecar, kzgCommitments);
|
|
259
|
+
verifyGloasDataColumnSidecar(dataColumnSidecar, kzgCommitments, blockRootHex);
|
|
252
260
|
|
|
253
261
|
// [REJECT] The sidecar must be on the correct subnet
|
|
254
262
|
if (computeSubnetForDataColumnSidecar(chain.config, dataColumnSidecar) !== gossipSubnet) {
|
|
255
263
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
256
264
|
code: DataColumnSidecarErrorCode.INVALID_SUBNET,
|
|
265
|
+
slot: dataColumnSidecar.slot,
|
|
266
|
+
root: blockRootHex,
|
|
257
267
|
columnIndex: dataColumnSidecar.index,
|
|
258
268
|
gossipSubnet,
|
|
259
269
|
});
|
|
@@ -272,6 +282,7 @@ export async function validateGossipGloasDataColumnSidecar(
|
|
|
272
282
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
273
283
|
code: DataColumnSidecarErrorCode.INVALID_KZG_PROOF,
|
|
274
284
|
slot: dataColumnSidecar.slot,
|
|
285
|
+
root: blockRootHex,
|
|
275
286
|
columnIndex: dataColumnSidecar.index,
|
|
276
287
|
});
|
|
277
288
|
} finally {
|
|
@@ -283,11 +294,17 @@ export async function validateGossipGloasDataColumnSidecar(
|
|
|
283
294
|
* SPEC FUNCTION
|
|
284
295
|
* https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.4/specs/fulu/p2p-interface.md#verify_data_column_sidecar
|
|
285
296
|
*/
|
|
286
|
-
function verifyFuluDataColumnSidecar(
|
|
297
|
+
function verifyFuluDataColumnSidecar(
|
|
298
|
+
config: ChainForkConfig,
|
|
299
|
+
dataColumnSidecar: fulu.DataColumnSidecar,
|
|
300
|
+
blockRootHex: RootHex
|
|
301
|
+
): void {
|
|
302
|
+
const slot = dataColumnSidecar.signedBlockHeader.message.slot;
|
|
287
303
|
if (dataColumnSidecar.index >= NUMBER_OF_COLUMNS) {
|
|
288
304
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
289
305
|
code: DataColumnSidecarErrorCode.INVALID_INDEX,
|
|
290
|
-
slot
|
|
306
|
+
slot,
|
|
307
|
+
root: blockRootHex,
|
|
291
308
|
columnIndex: dataColumnSidecar.index,
|
|
292
309
|
});
|
|
293
310
|
}
|
|
@@ -295,18 +312,20 @@ function verifyFuluDataColumnSidecar(config: ChainForkConfig, dataColumnSidecar:
|
|
|
295
312
|
if (dataColumnSidecar.kzgCommitments.length === 0) {
|
|
296
313
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
297
314
|
code: DataColumnSidecarErrorCode.NO_COMMITMENTS,
|
|
298
|
-
slot
|
|
315
|
+
slot,
|
|
316
|
+
root: blockRootHex,
|
|
299
317
|
columnIndex: dataColumnSidecar.index,
|
|
300
318
|
});
|
|
301
319
|
}
|
|
302
320
|
|
|
303
|
-
const epoch = computeEpochAtSlot(
|
|
321
|
+
const epoch = computeEpochAtSlot(slot);
|
|
304
322
|
const maxBlobsPerBlock = config.getMaxBlobsPerBlock(epoch);
|
|
305
323
|
|
|
306
324
|
if (dataColumnSidecar.kzgCommitments.length > maxBlobsPerBlock) {
|
|
307
325
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
308
326
|
code: DataColumnSidecarErrorCode.TOO_MANY_KZG_COMMITMENTS,
|
|
309
|
-
slot
|
|
327
|
+
slot,
|
|
328
|
+
root: blockRootHex,
|
|
310
329
|
columnIndex: dataColumnSidecar.index,
|
|
311
330
|
count: dataColumnSidecar.kzgCommitments.length,
|
|
312
331
|
limit: maxBlobsPerBlock,
|
|
@@ -319,6 +338,8 @@ function verifyFuluDataColumnSidecar(config: ChainForkConfig, dataColumnSidecar:
|
|
|
319
338
|
) {
|
|
320
339
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
321
340
|
code: DataColumnSidecarErrorCode.MISMATCHED_LENGTHS,
|
|
341
|
+
slot,
|
|
342
|
+
root: blockRootHex,
|
|
322
343
|
columnLength: dataColumnSidecar.column.length,
|
|
323
344
|
commitmentsLength: dataColumnSidecar.kzgCommitments.length,
|
|
324
345
|
proofsLength: dataColumnSidecar.kzgProofs.length,
|
|
@@ -330,12 +351,17 @@ function verifyFuluDataColumnSidecar(config: ChainForkConfig, dataColumnSidecar:
|
|
|
330
351
|
* SPEC FUNCTION
|
|
331
352
|
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.3/specs/gloas/p2p-interface.md#modified-verify_data_column_sidecar
|
|
332
353
|
*/
|
|
333
|
-
function verifyGloasDataColumnSidecar(
|
|
354
|
+
function verifyGloasDataColumnSidecar(
|
|
355
|
+
dataColumnSidecar: gloas.DataColumnSidecar,
|
|
356
|
+
kzgCommitments: Uint8Array[],
|
|
357
|
+
blockRootHex: RootHex
|
|
358
|
+
): void {
|
|
334
359
|
const slot = getDataColumnSidecarSlot(dataColumnSidecar);
|
|
335
360
|
if (dataColumnSidecar.index >= NUMBER_OF_COLUMNS) {
|
|
336
361
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
337
362
|
code: DataColumnSidecarErrorCode.INVALID_INDEX,
|
|
338
363
|
slot,
|
|
364
|
+
root: blockRootHex,
|
|
339
365
|
columnIndex: dataColumnSidecar.index,
|
|
340
366
|
});
|
|
341
367
|
}
|
|
@@ -344,6 +370,7 @@ function verifyGloasDataColumnSidecar(dataColumnSidecar: gloas.DataColumnSidecar
|
|
|
344
370
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
345
371
|
code: DataColumnSidecarErrorCode.NO_COMMITMENTS,
|
|
346
372
|
slot,
|
|
373
|
+
root: blockRootHex,
|
|
347
374
|
columnIndex: dataColumnSidecar.index,
|
|
348
375
|
});
|
|
349
376
|
}
|
|
@@ -354,6 +381,8 @@ function verifyGloasDataColumnSidecar(dataColumnSidecar: gloas.DataColumnSidecar
|
|
|
354
381
|
) {
|
|
355
382
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
356
383
|
code: DataColumnSidecarErrorCode.MISMATCHED_LENGTHS,
|
|
384
|
+
slot,
|
|
385
|
+
root: blockRootHex,
|
|
357
386
|
columnLength: dataColumnSidecar.column.length,
|
|
358
387
|
commitmentsLength: kzgCommitments.length,
|
|
359
388
|
proofsLength: dataColumnSidecar.kzgProofs.length,
|
|
@@ -465,8 +494,8 @@ export async function validateFuluBlockDataColumnSidecars(
|
|
|
465
494
|
) {
|
|
466
495
|
throw new DataColumnSidecarValidationError({
|
|
467
496
|
code: DataColumnSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID,
|
|
468
|
-
blockRoot: rootHex,
|
|
469
497
|
slot: blockSlot,
|
|
498
|
+
root: rootHex,
|
|
470
499
|
index: dataColumnSidecars[0].index,
|
|
471
500
|
});
|
|
472
501
|
}
|
|
@@ -499,6 +528,7 @@ export async function validateFuluBlockDataColumnSidecars(
|
|
|
499
528
|
{
|
|
500
529
|
code: DataColumnSidecarErrorCode.INVALID_INDEX,
|
|
501
530
|
slot: blockSlot,
|
|
531
|
+
root: toRootHex(blockRoot),
|
|
502
532
|
columnIndex: columnSidecar.index,
|
|
503
533
|
},
|
|
504
534
|
"DataColumnSidecar has invalid index"
|
|
@@ -543,6 +573,7 @@ export async function validateFuluBlockDataColumnSidecars(
|
|
|
543
573
|
{
|
|
544
574
|
code: DataColumnSidecarErrorCode.INCLUSION_PROOF_INVALID,
|
|
545
575
|
slot: blockSlot,
|
|
576
|
+
root: toRootHex(blockRoot),
|
|
546
577
|
columnIndex: columnSidecar.index,
|
|
547
578
|
},
|
|
548
579
|
"DataColumnSidecar has invalid inclusion proof"
|
|
@@ -623,6 +654,7 @@ export async function validateGloasBlockDataColumnSidecars(
|
|
|
623
654
|
if (columnSidecar.slot !== blockSlot) {
|
|
624
655
|
throw new DataColumnSidecarValidationError({
|
|
625
656
|
code: DataColumnSidecarErrorCode.INCORRECT_SIDECAR_SLOT,
|
|
657
|
+
root: toRootHex(blockRoot),
|
|
626
658
|
columnIndex: columnSidecar.index,
|
|
627
659
|
expected: blockSlot,
|
|
628
660
|
actual: columnSidecar.slot,
|
|
@@ -644,6 +676,7 @@ export async function validateGloasBlockDataColumnSidecars(
|
|
|
644
676
|
{
|
|
645
677
|
code: DataColumnSidecarErrorCode.INVALID_INDEX,
|
|
646
678
|
slot: blockSlot,
|
|
679
|
+
root: toRootHex(blockRoot),
|
|
647
680
|
columnIndex: columnSidecar.index,
|
|
648
681
|
},
|
|
649
682
|
"DataColumnSidecar has invalid index"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {ProtoBlock} from "@lodestar/fork-choice";
|
|
2
2
|
import {PAYLOAD_BUILDER_VERSION} from "@lodestar/params";
|
|
3
3
|
import {
|
|
4
4
|
computeEpochAtSlot,
|
|
@@ -46,11 +46,12 @@ function getMinBidValue(currentHighestBid: number): number {
|
|
|
46
46
|
/**
|
|
47
47
|
* Check whether a bid builds on one of the paths compatible with the local head branch.
|
|
48
48
|
*
|
|
49
|
-
* Building directly on the parent is allowed for proposer-boost reorgs
|
|
49
|
+
* Building directly on the parent is allowed for proposer-boost reorgs, including at epoch
|
|
50
|
+
* boundaries when the head is weak enough that a reorg onto the strong parent is predicted.
|
|
50
51
|
* Otherwise the bid must build on the local head's full or empty payload variant, as selected for its slot.
|
|
51
52
|
*/
|
|
52
53
|
function isBidCompatibleWithHead(
|
|
53
|
-
|
|
54
|
+
chain: IBeaconChain,
|
|
54
55
|
head: ProtoBlock,
|
|
55
56
|
bidSlot: Slot,
|
|
56
57
|
bidParentBlockRoot: RootHex,
|
|
@@ -60,9 +61,13 @@ function isBidCompatibleWithHead(
|
|
|
60
61
|
const buildsOnParentPayload = bidParentBlockHash === head.parentBlockHash;
|
|
61
62
|
|
|
62
63
|
if (buildsOnParentBlock && buildsOnParentPayload) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
if (!isStartSlotOfEpoch(bidSlot)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
// Epoch-boundary reorgs are allowed, but only propagate the bid if its parent matches the block
|
|
68
|
+
// we predict a proposer would reorg onto — predictProposerHead returns the strong parent only
|
|
69
|
+
// when the head is weak.
|
|
70
|
+
return chain.predictProposerHead().blockRoot === bidParentBlockRoot;
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
if (bidParentBlockRoot !== head.blockRoot) {
|
|
@@ -71,18 +76,179 @@ function isBidCompatibleWithHead(
|
|
|
71
76
|
|
|
72
77
|
const buildsOnHeadPayload = bidParentBlockHash === head.executionPayloadBlockHash;
|
|
73
78
|
|
|
74
|
-
if (forkChoice.shouldBuildOnFull(head, bidSlot)) {
|
|
79
|
+
if (chain.forkChoice.shouldBuildOnFull(head, bidSlot)) {
|
|
75
80
|
return buildsOnHeadPayload;
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
return buildsOnParentPayload;
|
|
79
84
|
}
|
|
80
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Validation for bids submitted via the API by the operator's own builder.
|
|
88
|
+
*
|
|
89
|
+
* Only non-transient checks are applied: slot later than parent, zero execution payment, blob
|
|
90
|
+
* commitment count, builder eligibility, version and balance coverage, prev_randao, and signature.
|
|
91
|
+
* Transient gossip rules (head compatibility, first bid per tuple, value increment, proposer
|
|
92
|
+
* preferences) are not applied, since those only limit forwarding of peers' messages and the
|
|
93
|
+
* builder may legitimately bid on a branch this node does not consider head.
|
|
94
|
+
* The parent-payload builder-exit rule is omitted because this endpoint only accepts bids from
|
|
95
|
+
* the operator's own builder.
|
|
96
|
+
*
|
|
97
|
+
* Throws on any failed check. Also throws if the bid's parent block is unknown or its state is
|
|
98
|
+
* unavailable, since the checks cannot be evaluated against the parent branch.
|
|
99
|
+
*/
|
|
81
100
|
export async function validateApiExecutionPayloadBid(
|
|
82
101
|
chain: IBeaconChain,
|
|
83
102
|
signedExecutionPayloadBid: gloas.SignedExecutionPayloadBid
|
|
84
|
-
): Promise<
|
|
85
|
-
|
|
103
|
+
): Promise<void> {
|
|
104
|
+
const bid = signedExecutionPayloadBid.message;
|
|
105
|
+
const bidParentBlockRoot = toRootHex(bid.parentBlockRoot);
|
|
106
|
+
|
|
107
|
+
// [REJECT] `bid.execution_payment` is zero.
|
|
108
|
+
if (bid.executionPayment !== 0n) {
|
|
109
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
110
|
+
code: ExecutionPayloadBidErrorCode.NON_ZERO_EXECUTION_PAYMENT,
|
|
111
|
+
builderIndex: bid.builderIndex,
|
|
112
|
+
executionPayment: bid.executionPayment,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// [REJECT] The bid's block hash is not equal to its parent block hash -- i.e.
|
|
117
|
+
// `bid.block_hash != bid.parent_block_hash`.
|
|
118
|
+
if (byteArrayEquals(bid.blockHash, bid.parentBlockHash)) {
|
|
119
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
120
|
+
code: ExecutionPayloadBidErrorCode.BLOCK_HASH_EQUALS_PARENT_BLOCK_HASH,
|
|
121
|
+
blockHash: toRootHex(bid.blockHash),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
|
|
126
|
+
// consensus layer -- i.e. validate that
|
|
127
|
+
// `len(bid.blob_kzg_commitments) <= get_blob_parameters(compute_epoch_at_slot(bid.slot)).max_blobs_per_block`.
|
|
128
|
+
const blobKzgCommitmentsLen = bid.blobKzgCommitments.length;
|
|
129
|
+
const maxBlobsPerBlock = chain.config.getMaxBlobsPerBlock(computeEpochAtSlot(bid.slot));
|
|
130
|
+
if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
|
|
131
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
132
|
+
code: ExecutionPayloadBidErrorCode.TOO_MANY_KZG_COMMITMENTS,
|
|
133
|
+
blobKzgCommitmentsLen,
|
|
134
|
+
commitmentLimit: maxBlobsPerBlock,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// [IGNORE] `bid.slot` is the current slot, or the next slot (`bid.slot - 1` is current), allowing for `MAXIMUM_GOSSIP_CLOCK_DISPARITY`.
|
|
139
|
+
if (
|
|
140
|
+
!chain.clock.isCurrentSlotGivenGossipDisparity(bid.slot) &&
|
|
141
|
+
!chain.clock.isCurrentSlotGivenGossipDisparity(bid.slot - 1)
|
|
142
|
+
) {
|
|
143
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
144
|
+
code: ExecutionPayloadBidErrorCode.INVALID_SLOT,
|
|
145
|
+
builderIndex: bid.builderIndex,
|
|
146
|
+
slot: bid.slot,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// [IGNORE] `bid.parent_block_root` is the hash tree root of a known beacon block in fork choice.
|
|
151
|
+
// Moved earlier than the spec ordering so we can derive the proposer dependent root for the
|
|
152
|
+
// proposer-preferences lookup below from a known fork-choice block.
|
|
153
|
+
const parentBlock = chain.forkChoice.getBlockHexDefaultStatus(bidParentBlockRoot);
|
|
154
|
+
if (parentBlock === null) {
|
|
155
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
156
|
+
code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
157
|
+
parentBlockRoot: bidParentBlockRoot,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// [REJECT] The bid is for a higher slot than its parent block -- i.e.
|
|
162
|
+
// validate that `bid.slot` is greater than the slot of the block with root
|
|
163
|
+
// `bid.parent_block_root`.
|
|
164
|
+
if (bid.slot <= parentBlock.slot) {
|
|
165
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
166
|
+
code: ExecutionPayloadBidErrorCode.NOT_LATER_THAN_PARENT,
|
|
167
|
+
parentSlot: parentBlock.slot,
|
|
168
|
+
slot: bid.slot,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const state = await chain.regen
|
|
173
|
+
.getBlockSlotState(parentBlock, bid.slot, {dontTransferCache: true}, RegenCaller.validateApiExecutionPayloadBid)
|
|
174
|
+
.catch(() => {
|
|
175
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
176
|
+
code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
177
|
+
parentBlockRoot: bidParentBlockRoot,
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
if (!isStatePostGloas(state)) {
|
|
182
|
+
throw new Error(`Expected gloas+ state for execution payload bid validation, got fork=${state.forkName}`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// [REJECT] `bid.builder_index` is within bounds -- i.e. `bid.builder_index < len(state.builders)`.
|
|
186
|
+
// `state.getBuilder` returns a lazy SSZ `getReadonly` view that is not bounds-checked eagerly; an
|
|
187
|
+
// out-of-range index only throws (`LeafNode has no right node`) on deferred field access (e.g. inside
|
|
188
|
+
// `isActiveBuilder`), escaping a try/catch around `getBuilder`. Check the length explicitly instead.
|
|
189
|
+
if (bid.builderIndex >= state.getBuildersLength()) {
|
|
190
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
191
|
+
code: ExecutionPayloadBidErrorCode.BUILDER_NOT_ELIGIBLE,
|
|
192
|
+
builderIndex: bid.builderIndex,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// [REJECT] `bid.builder_index` is a valid/active builder index -- i.e.
|
|
197
|
+
// `is_active_builder(state, bid.builder_index)` returns `True`.
|
|
198
|
+
const builder = state.getBuilder(bid.builderIndex);
|
|
199
|
+
if (!isActiveBuilder(builder, state.finalizedCheckpoint.epoch)) {
|
|
200
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
201
|
+
code: ExecutionPayloadBidErrorCode.BUILDER_NOT_ELIGIBLE,
|
|
202
|
+
builderIndex: bid.builderIndex,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// [REJECT] The builder version is `PAYLOAD_BUILDER_VERSION` -- i.e.
|
|
207
|
+
// `state.builders[bid.builder_index].version == PAYLOAD_BUILDER_VERSION`.
|
|
208
|
+
if (builder.version !== PAYLOAD_BUILDER_VERSION) {
|
|
209
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
210
|
+
code: ExecutionPayloadBidErrorCode.INVALID_BUILDER_VERSION,
|
|
211
|
+
builderIndex: bid.builderIndex,
|
|
212
|
+
version: builder.version,
|
|
213
|
+
expectedVersion: PAYLOAD_BUILDER_VERSION,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// [IGNORE] `bid.value` is less or equal than the builder's excess balance --
|
|
218
|
+
// i.e. `can_builder_cover_bid(state, builder_index, amount)` returns `True`.
|
|
219
|
+
if (!state.canBuilderCoverBid(bid.builderIndex, bid.value)) {
|
|
220
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
221
|
+
code: ExecutionPayloadBidErrorCode.BID_TOO_HIGH,
|
|
222
|
+
bidValue: bid.value,
|
|
223
|
+
builderBalance: builder.balance,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// [REJECT] `bid.prev_randao` is the correct RANDAO mix -- i.e. validate that
|
|
228
|
+
// `bid.prev_randao == get_randao_mix(parent_state, get_current_epoch(parent_state))`.
|
|
229
|
+
const randaoMix = state.getRandaoMix(computeEpochAtSlot(state.slot));
|
|
230
|
+
if (!byteArrayEquals(bid.prevRandao, randaoMix)) {
|
|
231
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
232
|
+
code: ExecutionPayloadBidErrorCode.INVALID_PREV_RANDAO,
|
|
233
|
+
builderIndex: bid.builderIndex,
|
|
234
|
+
bidPrevRandao: toHex(bid.prevRandao),
|
|
235
|
+
expectedPrevRandao: toHex(randaoMix),
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`.
|
|
240
|
+
const signatureSet = createSingleSignatureSetFromComponents(
|
|
241
|
+
builder.pubkey,
|
|
242
|
+
getExecutionPayloadBidSigningRoot(chain.config, bid),
|
|
243
|
+
signedExecutionPayloadBid.signature
|
|
244
|
+
);
|
|
245
|
+
if (!(await chain.bls.verifySignatureSets([signatureSet]))) {
|
|
246
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
247
|
+
code: ExecutionPayloadBidErrorCode.INVALID_SIGNATURE,
|
|
248
|
+
builderIndex: bid.builderIndex,
|
|
249
|
+
slot: bid.slot,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
86
252
|
}
|
|
87
253
|
|
|
88
254
|
export async function validateGossipExecutionPayloadBid(
|
|
@@ -100,6 +266,37 @@ async function validateExecutionPayloadBid(
|
|
|
100
266
|
const bidParentBlockRoot = toRootHex(bid.parentBlockRoot);
|
|
101
267
|
const bidParentBlockHash = toRootHex(bid.parentBlockHash);
|
|
102
268
|
|
|
269
|
+
// [REJECT] `bid.execution_payment` is zero.
|
|
270
|
+
if (bid.executionPayment !== 0n) {
|
|
271
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
272
|
+
code: ExecutionPayloadBidErrorCode.NON_ZERO_EXECUTION_PAYMENT,
|
|
273
|
+
builderIndex: bid.builderIndex,
|
|
274
|
+
executionPayment: bid.executionPayment,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// [REJECT] The bid's block hash is not equal to its parent block hash -- i.e.
|
|
279
|
+
// `bid.block_hash != bid.parent_block_hash`.
|
|
280
|
+
if (byteArrayEquals(bid.blockHash, bid.parentBlockHash)) {
|
|
281
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
282
|
+
code: ExecutionPayloadBidErrorCode.BLOCK_HASH_EQUALS_PARENT_BLOCK_HASH,
|
|
283
|
+
blockHash: toRootHex(bid.blockHash),
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
|
|
288
|
+
// consensus layer -- i.e. validate that
|
|
289
|
+
// `len(bid.blob_kzg_commitments) <= get_blob_parameters(compute_epoch_at_slot(bid.slot)).max_blobs_per_block`.
|
|
290
|
+
const blobKzgCommitmentsLen = bid.blobKzgCommitments.length;
|
|
291
|
+
const maxBlobsPerBlock = chain.config.getMaxBlobsPerBlock(computeEpochAtSlot(bid.slot));
|
|
292
|
+
if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
|
|
293
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
294
|
+
code: ExecutionPayloadBidErrorCode.TOO_MANY_KZG_COMMITMENTS,
|
|
295
|
+
blobKzgCommitmentsLen,
|
|
296
|
+
commitmentLimit: maxBlobsPerBlock,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
103
300
|
// [IGNORE] `bid.slot` is the current slot, or the next slot (`bid.slot - 1` is current), allowing for `MAXIMUM_GOSSIP_CLOCK_DISPARITY`.
|
|
104
301
|
if (
|
|
105
302
|
!chain.clock.isCurrentSlotGivenGossipDisparity(bid.slot) &&
|
|
@@ -114,7 +311,7 @@ async function validateExecutionPayloadBid(
|
|
|
114
311
|
|
|
115
312
|
// [IGNORE] The bid is compatible with the current head branch.
|
|
116
313
|
const head = chain.forkChoice.getHead();
|
|
117
|
-
if (!isBidCompatibleWithHead(chain
|
|
314
|
+
if (!isBidCompatibleWithHead(chain, head, bid.slot, bidParentBlockRoot, bidParentBlockHash)) {
|
|
118
315
|
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
119
316
|
code: ExecutionPayloadBidErrorCode.INCOMPATIBLE_WITH_HEAD,
|
|
120
317
|
slot: bid.slot,
|
|
@@ -245,15 +442,6 @@ async function validateExecutionPayloadBid(
|
|
|
245
442
|
});
|
|
246
443
|
}
|
|
247
444
|
|
|
248
|
-
// [REJECT] `bid.execution_payment` is zero.
|
|
249
|
-
if (bid.executionPayment !== 0n) {
|
|
250
|
-
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
251
|
-
code: ExecutionPayloadBidErrorCode.NON_ZERO_EXECUTION_PAYMENT,
|
|
252
|
-
builderIndex: bid.builderIndex,
|
|
253
|
-
executionPayment: bid.executionPayment,
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
|
|
257
445
|
// [IGNORE] `bid.fee_recipient == proposer_preferences.fee_recipient`.
|
|
258
446
|
if (!byteArrayEquals(bid.feeRecipient, proposerPreferences.message.feeRecipient)) {
|
|
259
447
|
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
@@ -294,19 +482,6 @@ async function validateExecutionPayloadBid(
|
|
|
294
482
|
});
|
|
295
483
|
}
|
|
296
484
|
|
|
297
|
-
// [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
|
|
298
|
-
// consensus layer -- i.e. validate that
|
|
299
|
-
// `len(bid.blob_kzg_commitments) <= get_blob_parameters(compute_epoch_at_slot(bid.slot)).max_blobs_per_block`.
|
|
300
|
-
const blobKzgCommitmentsLen = bid.blobKzgCommitments.length;
|
|
301
|
-
const maxBlobsPerBlock = chain.config.getMaxBlobsPerBlock(computeEpochAtSlot(bid.slot));
|
|
302
|
-
if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
|
|
303
|
-
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
304
|
-
code: ExecutionPayloadBidErrorCode.TOO_MANY_KZG_COMMITMENTS,
|
|
305
|
-
blobKzgCommitmentsLen,
|
|
306
|
-
commitmentLimit: maxBlobsPerBlock,
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
|
|
310
485
|
// [IGNORE] this bid is the highest value bid seen for the tuple
|
|
311
486
|
// `(bid.slot, bid.parent_block_hash, bid.parent_block_root)`.
|
|
312
487
|
// As a DoS prevention measure, the bid must also exceed the current highest bid by a minimum
|
|
@@ -342,6 +517,29 @@ async function validateExecutionPayloadBid(
|
|
|
342
517
|
});
|
|
343
518
|
}
|
|
344
519
|
|
|
520
|
+
// [IGNORE] The parent's payload does not try to exit the builder
|
|
521
|
+
if (byteArrayEquals(bid.parentBlockHash, state.latestExecutionPayloadBid.blockHash)) {
|
|
522
|
+
const requests = await chain.getParentExecutionRequests(parentBlock.slot, parentBlock.blockRoot).catch(() => {
|
|
523
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
524
|
+
code: ExecutionPayloadBidErrorCode.UNKNOWN_PARENT_BLOCK_HASH,
|
|
525
|
+
parentBlockHash: bidParentBlockHash,
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
if (
|
|
529
|
+
requests.builderExits.some(
|
|
530
|
+
(request) =>
|
|
531
|
+
byteArrayEquals(request.pubkey, builder.pubkey) &&
|
|
532
|
+
byteArrayEquals(request.sourceAddress, builder.executionAddress)
|
|
533
|
+
)
|
|
534
|
+
) {
|
|
535
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
536
|
+
code: ExecutionPayloadBidErrorCode.BUILDER_MAY_EXIT,
|
|
537
|
+
builderIndex: bid.builderIndex,
|
|
538
|
+
parentBlockRoot: bidParentBlockRoot,
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
345
543
|
// [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`.
|
|
346
544
|
const signatureSet = createSingleSignatureSetFromComponents(
|
|
347
545
|
builder.pubkey,
|
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
import {PayloadStatus} from "@lodestar/fork-choice";
|
|
2
|
-
import {
|
|
3
|
-
MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD,
|
|
4
|
-
MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD,
|
|
5
|
-
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD,
|
|
6
|
-
MAX_WITHDRAWALS_PER_PAYLOAD,
|
|
7
|
-
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
|
|
8
|
-
} from "@lodestar/params";
|
|
9
2
|
import {
|
|
10
3
|
computeStartSlotAtEpoch,
|
|
11
4
|
getExecutionPayloadEnvelopeSignatureSet,
|
|
@@ -89,6 +82,8 @@ async function validateExecutionPayloadEnvelope(
|
|
|
89
82
|
if (block.slot !== payload.slotNumber) {
|
|
90
83
|
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
91
84
|
code: ExecutionPayloadEnvelopeErrorCode.SLOT_MISMATCH,
|
|
85
|
+
slot: payload.slotNumber,
|
|
86
|
+
root: blockRootHex,
|
|
92
87
|
envelopeSlot: payload.slotNumber,
|
|
93
88
|
blockSlot: block.slot,
|
|
94
89
|
});
|
|
@@ -98,6 +93,8 @@ async function validateExecutionPayloadEnvelope(
|
|
|
98
93
|
if (envelope.builderIndex !== payloadInput.getBuilderIndex()) {
|
|
99
94
|
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
100
95
|
code: ExecutionPayloadEnvelopeErrorCode.BUILDER_INDEX_MISMATCH,
|
|
96
|
+
slot: payload.slotNumber,
|
|
97
|
+
root: blockRootHex,
|
|
101
98
|
envelopeBuilderIndex: envelope.builderIndex,
|
|
102
99
|
bidBuilderIndex: payloadInput.getBuilderIndex(),
|
|
103
100
|
});
|
|
@@ -107,6 +104,8 @@ async function validateExecutionPayloadEnvelope(
|
|
|
107
104
|
if (toRootHex(payload.blockHash) !== payloadInput.getBlockHashHex()) {
|
|
108
105
|
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
109
106
|
code: ExecutionPayloadEnvelopeErrorCode.BLOCK_HASH_MISMATCH,
|
|
107
|
+
slot: payload.slotNumber,
|
|
108
|
+
root: blockRootHex,
|
|
110
109
|
envelopeBlockHash: toRootHex(payload.blockHash),
|
|
111
110
|
bidBlockHash: payloadInput.getBlockHashHex(),
|
|
112
111
|
});
|
|
@@ -117,41 +116,13 @@ async function validateExecutionPayloadEnvelope(
|
|
|
117
116
|
if (!byteArrayEquals(requestsRoot, payloadInput.getBid().executionRequestsRoot)) {
|
|
118
117
|
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
119
118
|
code: ExecutionPayloadEnvelopeErrorCode.EXECUTION_REQUESTS_ROOT_MISMATCH,
|
|
119
|
+
slot: payload.slotNumber,
|
|
120
|
+
root: blockRootHex,
|
|
120
121
|
envelopeRequestsRoot: toRootHex(requestsRoot),
|
|
121
122
|
bidRequestsRoot: toRootHex(payloadInput.getBid().executionRequestsRoot),
|
|
122
123
|
});
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
// [REJECT] The counts of `execution_requests` are within their respective limits.
|
|
126
|
-
// New in Gloas:EIP7688 — progressive lists are unbounded at the type level, so bounds
|
|
127
|
-
// are enforced here in gossip validation.
|
|
128
|
-
const {executionRequests} = envelope;
|
|
129
|
-
const requestCountLimits: [string, number, number][] = [
|
|
130
|
-
["withdrawals", executionRequests.withdrawals.length, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD],
|
|
131
|
-
["consolidations", executionRequests.consolidations.length, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD],
|
|
132
|
-
["builderDeposits", executionRequests.builderDeposits.length, MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD],
|
|
133
|
-
["builderExits", executionRequests.builderExits.length, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD],
|
|
134
|
-
];
|
|
135
|
-
for (const [name, count, limit] of requestCountLimits) {
|
|
136
|
-
if (count > limit) {
|
|
137
|
-
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
138
|
-
code: ExecutionPayloadEnvelopeErrorCode.EXECUTION_REQUESTS_COUNT_EXCEEDED,
|
|
139
|
-
name,
|
|
140
|
-
count,
|
|
141
|
-
limit,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// [REJECT] The number of withdrawals is within the limit.
|
|
147
|
-
if (payload.withdrawals.length > MAX_WITHDRAWALS_PER_PAYLOAD) {
|
|
148
|
-
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
149
|
-
code: ExecutionPayloadEnvelopeErrorCode.WITHDRAWALS_COUNT_EXCEEDED,
|
|
150
|
-
count: payload.withdrawals.length,
|
|
151
|
-
limit: MAX_WITHDRAWALS_PER_PAYLOAD,
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
|
|
155
126
|
// Get the block state to verify the builder's signature.
|
|
156
127
|
const blockState = await chain.regen
|
|
157
128
|
.getState(block.stateRoot, RegenCaller.validateGossipPayloadEnvelope)
|
|
@@ -178,6 +149,8 @@ async function validateExecutionPayloadEnvelope(
|
|
|
178
149
|
if (!(await chain.bls.verifySignatureSets([signatureSet], {verifyOnMainThread: true}))) {
|
|
179
150
|
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
180
151
|
code: ExecutionPayloadEnvelopeErrorCode.INVALID_SIGNATURE,
|
|
152
|
+
slot: payload.slotNumber,
|
|
153
|
+
root: blockRootHex,
|
|
181
154
|
});
|
|
182
155
|
}
|
|
183
156
|
}
|
|
@@ -7,7 +7,6 @@ import {RootHex, gloas, ssz} from "@lodestar/types";
|
|
|
7
7
|
import {toRootHex} from "@lodestar/utils";
|
|
8
8
|
import {GossipAction, PayloadAttestationError, PayloadAttestationErrorCode} from "../errors/index.js";
|
|
9
9
|
import {IBeaconChain} from "../index.js";
|
|
10
|
-
import {RegenCaller} from "../regen/index.js";
|
|
11
10
|
|
|
12
11
|
export type PayloadAttestationValidationResult = {
|
|
13
12
|
attDataRootHex: RootHex;
|
|
@@ -82,15 +81,15 @@ async function validatePayloadAttestationMessage(
|
|
|
82
81
|
// TODO GLOAS: implement this. Technically if we cannot get proto block from fork choice,
|
|
83
82
|
// it is possible that the block didn't pass the validation
|
|
84
83
|
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
});
|
|
84
|
+
// block.slot === data.slot is enforced above, so use the block's post-state directly to avoid
|
|
85
|
+
// getting through regen queue
|
|
86
|
+
const state = chain.regen.getStateSync(block.stateRoot);
|
|
87
|
+
if (state == null) {
|
|
88
|
+
throw new PayloadAttestationError(GossipAction.IGNORE, {
|
|
89
|
+
code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
90
|
+
blockRoot: toRootHex(data.beaconBlockRoot),
|
|
93
91
|
});
|
|
92
|
+
}
|
|
94
93
|
|
|
95
94
|
if (!isStatePostGloas(state)) {
|
|
96
95
|
throw new Error(`Expected gloas+ state for payload attestation validation, got fork=${state.forkName}`);
|