Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
This commit is contained in:
Bastin
2025-11-06 23:47:35 +01:00
committed by GitHub
parent 7794a77ae6
commit de0825f880
7 changed files with 507 additions and 62 deletions

View File

@@ -2804,7 +2804,7 @@ func TestProcessLightClientUpdate(t *testing.T) {
require.NoError(t, s.cfg.BeaconDB.SaveState(ctx, headState, [32]byte{1, 2}))
require.NoError(t, s.cfg.BeaconDB.SaveHeadBlockRoot(ctx, [32]byte{1, 2}))
for testVersion := version.Altair; testVersion <= version.Electra; testVersion++ {
for _, testVersion := range version.All()[1:] {
t.Run(version.String(testVersion), func(t *testing.T) {
l := util.NewTestLightClient(t, testVersion)

View File

@@ -181,6 +181,13 @@ func decodeLightClientBootstrap(enc []byte) (interfaces.LightClientBootstrap, []
}
m = bootstrap
syncCommitteeHash = enc[len(ElectraKey) : len(ElectraKey)+32]
case hasFuluKey(enc):
bootstrap := &ethpb.LightClientBootstrapElectra{}
if err := bootstrap.UnmarshalSSZ(enc[len(fuluKey)+32:]); err != nil {
return nil, nil, errors.Wrap(err, "could not unmarshal Electra light client bootstrap")
}
m = bootstrap
syncCommitteeHash = enc[len(fuluKey) : len(fuluKey)+32]
default:
return nil, nil, errors.New("decoding of saved light client bootstrap is unsupported")
}
@@ -296,6 +303,12 @@ func decodeLightClientUpdate(enc []byte) (interfaces.LightClientUpdate, error) {
return nil, errors.Wrap(err, "could not unmarshal Electra light client update")
}
m = update
case hasFuluKey(enc):
update := &ethpb.LightClientUpdateElectra{}
if err := update.UnmarshalSSZ(enc[len(fuluKey):]); err != nil {
return nil, errors.Wrap(err, "could not unmarshal Fulu light client update")
}
m = update
default:
return nil, errors.New("decoding of saved light client update is unsupported")
}
@@ -304,6 +317,8 @@ func decodeLightClientUpdate(enc []byte) (interfaces.LightClientUpdate, error) {
func keyForLightClientUpdate(v int) ([]byte, error) {
switch v {
case version.Fulu:
return fuluKey, nil
case version.Electra:
return ElectraKey, nil
case version.Deneb:

View File

@@ -215,8 +215,7 @@ func TestStore_LightClientUpdate_CanSaveRetrieve(t *testing.T) {
db := setupDB(t)
ctx := t.Context()
for testVersion := version.Altair; testVersion <= version.Electra; testVersion++ {
for _, testVersion := range version.All()[1:] {
t.Run(version.String(testVersion), func(t *testing.T) {
update, err := createUpdate(t, testVersion)
require.NoError(t, err)
@@ -572,8 +571,7 @@ func TestStore_LightClientBootstrap_CanSaveRetrieve(t *testing.T) {
require.NoError(t, err)
require.IsNil(t, retrievedBootstrap)
})
for testVersion := version.Altair; testVersion <= version.Electra; testVersion++ {
for _, testVersion := range version.All()[1:] {
t.Run(version.String(testVersion), func(t *testing.T) {
bootstrap, err := createDefaultLightClientBootstrap(primitives.Slot(uint64(params.BeaconConfig().VersionToForkEpochMap()[testVersion]) * uint64(params.BeaconConfig().SlotsPerEpoch)))
require.NoError(t, err)

View File

@@ -29,58 +29,22 @@ func TestLightClient_NewLightClientOptimisticUpdateFromBeaconState(t *testing.T)
cfg.CapellaForkEpoch = 3
cfg.DenebForkEpoch = 4
cfg.ElectraForkEpoch = 5
cfg.FuluForkEpoch = 6
params.OverrideBeaconConfig(cfg)
t.Run("Altair", func(t *testing.T) {
l := util.NewTestLightClient(t, version.Altair)
for _, testVersion := range version.All()[1:] {
t.Run(version.String(testVersion), func(t *testing.T) {
l := util.NewTestLightClient(t, testVersion)
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader())
})
t.Run("Capella", func(t *testing.T) {
l := util.NewTestLightClient(t, version.Capella)
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader())
})
t.Run("Deneb", func(t *testing.T) {
l := util.NewTestLightClient(t, version.Deneb)
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader())
})
t.Run("Electra", func(t *testing.T) {
l := util.NewTestLightClient(t, version.Electra)
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader())
})
l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader())
})
}
}
func TestLightClient_NewLightClientFinalityUpdateFromBeaconState(t *testing.T) {
@@ -91,6 +55,7 @@ func TestLightClient_NewLightClientFinalityUpdateFromBeaconState(t *testing.T) {
cfg.CapellaForkEpoch = 3
cfg.DenebForkEpoch = 4
cfg.ElectraForkEpoch = 5
cfg.FuluForkEpoch = 6
params.OverrideBeaconConfig(cfg)
t.Run("Altair", func(t *testing.T) {
@@ -538,6 +503,157 @@ func TestLightClient_NewLightClientFinalityUpdateFromBeaconState(t *testing.T) {
require.DeepSSZEqual(t, execution, updateExecution.Proto(), "Finalized Block Execution is not equal")
})
})
t.Run("Fulu", func(t *testing.T) {
t.Run("FinalizedBlock Not Nil", func(t *testing.T) {
l := util.NewTestLightClient(t, version.Fulu)
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader())
//zeroHash := params.BeaconConfig().ZeroHash[:]
finalizedBlockHeader, err := l.FinalizedBlock.Header()
require.NoError(t, err)
require.NotNil(t, update.FinalizedHeader(), "Finalized header is nil")
updateFinalizedHeaderBeacon := update.FinalizedHeader().Beacon()
require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal")
require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal")
fb, err := update.FinalityBranchElectra()
require.NoError(t, err)
proof, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.NoError(t, err)
for i, leaf := range fb {
require.DeepSSZEqual(t, proof[i], leaf[:], "Leaf is not equal")
}
// Check Execution BlockHash
payloadInterface, err := l.FinalizedBlock.Block().Body().Execution()
require.NoError(t, err)
transactionsRoot, err := payloadInterface.TransactionsRoot()
if errors.Is(err, consensustypes.ErrUnsupportedField) {
transactions, err := payloadInterface.Transactions()
require.NoError(t, err)
transactionsRootArray, err := ssz.TransactionsRoot(transactions)
require.NoError(t, err)
transactionsRoot = transactionsRootArray[:]
} else {
require.NoError(t, err)
}
withdrawalsRoot, err := payloadInterface.WithdrawalsRoot()
if errors.Is(err, consensustypes.ErrUnsupportedField) {
withdrawals, err := payloadInterface.Withdrawals()
require.NoError(t, err)
withdrawalsRootArray, err := ssz.WithdrawalSliceRoot(withdrawals, fieldparams.MaxWithdrawalsPerPayload)
require.NoError(t, err)
withdrawalsRoot = withdrawalsRootArray[:]
} else {
require.NoError(t, err)
}
execution := &v11.ExecutionPayloadHeaderDeneb{
ParentHash: payloadInterface.ParentHash(),
FeeRecipient: payloadInterface.FeeRecipient(),
StateRoot: payloadInterface.StateRoot(),
ReceiptsRoot: payloadInterface.ReceiptsRoot(),
LogsBloom: payloadInterface.LogsBloom(),
PrevRandao: payloadInterface.PrevRandao(),
BlockNumber: payloadInterface.BlockNumber(),
GasLimit: payloadInterface.GasLimit(),
GasUsed: payloadInterface.GasUsed(),
Timestamp: payloadInterface.Timestamp(),
ExtraData: payloadInterface.ExtraData(),
BaseFeePerGas: payloadInterface.BaseFeePerGas(),
BlockHash: payloadInterface.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
}
updateExecution, err := update.FinalizedHeader().Execution()
require.NoError(t, err)
require.DeepSSZEqual(t, execution, updateExecution.Proto(), "Finalized Block Execution is not equal")
})
t.Run("FinalizedBlock In Previous Fork", func(t *testing.T) {
l := util.NewTestLightClient(t, version.Fulu, util.WithFinalizedCheckpointInPrevFork())
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot(), "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate())
l.CheckAttestedHeader(update.AttestedHeader())
finalizedBlockHeader, err := l.FinalizedBlock.Header()
require.NoError(t, err)
require.NotNil(t, update.FinalizedHeader(), "Finalized header is nil")
updateFinalizedHeaderBeacon := update.FinalizedHeader().Beacon()
require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal")
require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal")
fb, err := update.FinalityBranchElectra()
require.NoError(t, err)
proof, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.NoError(t, err)
for i, leaf := range fb {
require.DeepSSZEqual(t, proof[i], leaf[:], "Leaf is not equal")
}
// Check Execution BlockHash
payloadInterface, err := l.FinalizedBlock.Block().Body().Execution()
require.NoError(t, err)
transactionsRoot, err := payloadInterface.TransactionsRoot()
if errors.Is(err, consensustypes.ErrUnsupportedField) {
transactions, err := payloadInterface.Transactions()
require.NoError(t, err)
transactionsRootArray, err := ssz.TransactionsRoot(transactions)
require.NoError(t, err)
transactionsRoot = transactionsRootArray[:]
} else {
require.NoError(t, err)
}
withdrawalsRoot, err := payloadInterface.WithdrawalsRoot()
if errors.Is(err, consensustypes.ErrUnsupportedField) {
withdrawals, err := payloadInterface.Withdrawals()
require.NoError(t, err)
withdrawalsRootArray, err := ssz.WithdrawalSliceRoot(withdrawals, fieldparams.MaxWithdrawalsPerPayload)
require.NoError(t, err)
withdrawalsRoot = withdrawalsRootArray[:]
} else {
require.NoError(t, err)
}
execution := &v11.ExecutionPayloadHeaderDeneb{
ParentHash: payloadInterface.ParentHash(),
FeeRecipient: payloadInterface.FeeRecipient(),
StateRoot: payloadInterface.StateRoot(),
ReceiptsRoot: payloadInterface.ReceiptsRoot(),
LogsBloom: payloadInterface.LogsBloom(),
PrevRandao: payloadInterface.PrevRandao(),
BlockNumber: payloadInterface.BlockNumber(),
GasLimit: payloadInterface.GasLimit(),
GasUsed: payloadInterface.GasUsed(),
Timestamp: payloadInterface.Timestamp(),
ExtraData: payloadInterface.ExtraData(),
BaseFeePerGas: payloadInterface.BaseFeePerGas(),
BlockHash: payloadInterface.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
}
updateExecution, err := update.FinalizedHeader().Execution()
require.NoError(t, err)
require.DeepSSZEqual(t, execution, updateExecution.Proto(), "Finalized Block Execution is not equal")
})
})
}
func TestLightClient_BlockToLightClientHeader(t *testing.T) {
@@ -983,6 +1099,138 @@ func TestLightClient_BlockToLightClientHeader(t *testing.T) {
})
})
t.Run("Fulu", func(t *testing.T) {
t.Run("Non-Blinded Beacon Block", func(t *testing.T) {
l := util.NewTestLightClient(t, version.Fulu)
header, err := lightClient.BlockToLightClientHeader(l.Ctx, version.Fulu, l.Block)
require.NoError(t, err)
require.NotNil(t, header, "header is nil")
parentRoot := l.Block.Block().ParentRoot()
stateRoot := l.Block.Block().StateRoot()
bodyRoot, err := l.Block.Block().Body().HashTreeRoot()
require.NoError(t, err)
payload, err := l.Block.Block().Body().Execution()
require.NoError(t, err)
transactionsRoot, err := lightClient.ComputeTransactionsRoot(payload)
require.NoError(t, err)
withdrawalsRoot, err := lightClient.ComputeWithdrawalsRoot(payload)
require.NoError(t, err)
blobGasUsed, err := payload.BlobGasUsed()
require.NoError(t, err)
excessBlobGas, err := payload.ExcessBlobGas()
require.NoError(t, err)
executionHeader := &v11.ExecutionPayloadHeaderDeneb{
ParentHash: payload.ParentHash(),
FeeRecipient: payload.FeeRecipient(),
StateRoot: payload.StateRoot(),
ReceiptsRoot: payload.ReceiptsRoot(),
LogsBloom: payload.LogsBloom(),
PrevRandao: payload.PrevRandao(),
BlockNumber: payload.BlockNumber(),
GasLimit: payload.GasLimit(),
GasUsed: payload.GasUsed(),
Timestamp: payload.Timestamp(),
ExtraData: payload.ExtraData(),
BaseFeePerGas: payload.BaseFeePerGas(),
BlockHash: payload.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
BlobGasUsed: blobGasUsed,
ExcessBlobGas: excessBlobGas,
}
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block())
require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), header.Beacon().Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon().ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon().ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon().StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon().BodyRoot, "Body root is not equal")
headerExecution, err := header.Execution()
require.NoError(t, err)
require.DeepSSZEqual(t, executionHeader, headerExecution.Proto(), "Execution headers are not equal")
headerExecutionBranch, err := header.ExecutionBranch()
require.NoError(t, err)
require.DeepSSZEqual(t, executionPayloadProof, convertArrayToSlice(headerExecutionBranch), "Execution payload proofs are not equal")
})
t.Run("Blinded Beacon Block", func(t *testing.T) {
l := util.NewTestLightClient(t, version.Fulu, util.WithBlinded())
header, err := lightClient.BlockToLightClientHeader(l.Ctx, version.Fulu, l.Block)
require.NoError(t, err)
require.NotNil(t, header, "header is nil")
parentRoot := l.Block.Block().ParentRoot()
stateRoot := l.Block.Block().StateRoot()
bodyRoot, err := l.Block.Block().Body().HashTreeRoot()
require.NoError(t, err)
payload, err := l.Block.Block().Body().Execution()
require.NoError(t, err)
transactionsRoot, err := payload.TransactionsRoot()
require.NoError(t, err)
withdrawalsRoot, err := payload.WithdrawalsRoot()
require.NoError(t, err)
blobGasUsed, err := payload.BlobGasUsed()
require.NoError(t, err)
excessBlobGas, err := payload.ExcessBlobGas()
require.NoError(t, err)
executionHeader := &v11.ExecutionPayloadHeaderDeneb{
ParentHash: payload.ParentHash(),
FeeRecipient: payload.FeeRecipient(),
StateRoot: payload.StateRoot(),
ReceiptsRoot: payload.ReceiptsRoot(),
LogsBloom: payload.LogsBloom(),
PrevRandao: payload.PrevRandao(),
BlockNumber: payload.BlockNumber(),
GasLimit: payload.GasLimit(),
GasUsed: payload.GasUsed(),
Timestamp: payload.Timestamp(),
ExtraData: payload.ExtraData(),
BaseFeePerGas: payload.BaseFeePerGas(),
BlockHash: payload.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
BlobGasUsed: blobGasUsed,
ExcessBlobGas: excessBlobGas,
}
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block())
require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), header.Beacon().Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon().ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon().ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon().StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon().BodyRoot, "Body root is not equal")
headerExecution, err := header.Execution()
require.NoError(t, err)
require.DeepSSZEqual(t, executionHeader, headerExecution.Proto(), "Execution headers are not equal")
headerExecutionBranch, err := header.ExecutionBranch()
require.NoError(t, err)
require.DeepSSZEqual(t, executionPayloadProof, convertArrayToSlice(headerExecutionBranch), "Execution payload proofs are not equal")
})
})
t.Run("Capella fork with Altair block", func(t *testing.T) {
l := util.NewTestLightClient(t, version.Altair)

View File

@@ -46,7 +46,7 @@ func TestLightClientHandler_GetLightClientBootstrap(t *testing.T) {
cfg.FuluForkEpoch = 5
params.OverrideBeaconConfig(cfg)
for testVersion := version.Altair; testVersion <= version.Electra; testVersion++ {
for _, testVersion := range version.All()[1:] {
t.Run(version.String(testVersion), func(t *testing.T) {
l := util.NewTestLightClient(t, testVersion)
@@ -131,7 +131,7 @@ func TestLightClientHandler_GetLightClientBootstrap(t *testing.T) {
resp = &pb.LightClientBootstrapCapella{}
case version.Deneb:
resp = &pb.LightClientBootstrapDeneb{}
case version.Electra:
case version.Electra, version.Fulu:
resp = &pb.LightClientBootstrapElectra{}
default:
t.Fatalf("Unsupported version %s", version.String(testVersion))
@@ -173,10 +173,11 @@ func TestLightClientHandler_GetLightClientByRange(t *testing.T) {
config.CapellaForkEpoch = 2
config.DenebForkEpoch = 3
config.ElectraForkEpoch = 4
config.FuluForkEpoch = 5
params.OverrideBeaconConfig(config)
t.Run("can save retrieve", func(t *testing.T) {
for testVersion := version.Altair; testVersion <= version.Electra; testVersion++ {
for _, testVersion := range version.All()[1:] {
t.Run(version.String(testVersion), func(t *testing.T) {
slot := primitives.Slot(params.BeaconConfig().VersionToForkEpochMap()[testVersion] * primitives.Epoch(config.SlotsPerEpoch)).Add(1)
@@ -252,7 +253,7 @@ func TestLightClientHandler_GetLightClientByRange(t *testing.T) {
resp = &pb.LightClientUpdateCapella{}
case version.Deneb:
resp = &pb.LightClientUpdateDeneb{}
case version.Electra:
case version.Electra, version.Fulu:
resp = &pb.LightClientUpdateElectra{}
default:
t.Fatalf("Unsupported version %s", version.String(testVersion))
@@ -313,7 +314,7 @@ func TestLightClientHandler_GetLightClientByRange(t *testing.T) {
resp = &pb.LightClientUpdateCapella{}
case version.Deneb:
resp = &pb.LightClientUpdateDeneb{}
case version.Electra:
case version.Electra, version.Fulu:
resp = &pb.LightClientUpdateElectra{}
default:
t.Fatalf("Unsupported version %s", version.String(testVersion))
@@ -730,7 +731,7 @@ func TestLightClientHandler_GetLightClientFinalityUpdate(t *testing.T) {
require.Equal(t, http.StatusNotFound, writer.Code)
})
for testVersion := 1; testVersion < 6; testVersion++ {
for _, testVersion := range version.All()[1:] {
t.Run(version.String(testVersion), func(t *testing.T) {
ctx := t.Context()
@@ -793,7 +794,7 @@ func TestLightClientHandler_GetLightClientFinalityUpdate(t *testing.T) {
resp = &pb.LightClientFinalityUpdateCapella{}
case version.Deneb:
resp = &pb.LightClientFinalityUpdateDeneb{}
case version.Electra:
case version.Electra, version.Fulu:
resp = &pb.LightClientFinalityUpdateElectra{}
default:
t.Fatalf("Unsupported version %s", version.String(testVersion))
@@ -825,7 +826,7 @@ func TestLightClientHandler_GetLightClientOptimisticUpdate(t *testing.T) {
require.Equal(t, http.StatusNotFound, writer.Code)
})
for testVersion := 1; testVersion < 6; testVersion++ {
for _, testVersion := range version.All()[1:] {
t.Run(version.String(testVersion), func(t *testing.T) {
ctx := t.Context()
l := util.NewTestLightClient(t, testVersion)
@@ -886,7 +887,7 @@ func TestLightClientHandler_GetLightClientOptimisticUpdate(t *testing.T) {
resp = &pb.LightClientOptimisticUpdateCapella{}
case version.Deneb:
resp = &pb.LightClientOptimisticUpdateDeneb{}
case version.Electra:
case version.Electra, version.Fulu:
resp = &pb.LightClientOptimisticUpdateDeneb{}
default:
t.Fatalf("Unsupported version %s", version.String(testVersion))

View File

@@ -0,0 +1,3 @@
### Added
- add fulu support to light client processing.

View File

@@ -62,6 +62,8 @@ func NewTestLightClient(t *testing.T, forkVersion int, options ...LightClientOpt
return l.setupTestDeneb()
case version.Electra:
return l.setupTestElectra()
case version.Fulu:
return l.setupTestFulu()
default:
l.T.Fatalf("Unsupported version %s", version.String(l.version))
return nil
@@ -955,6 +957,184 @@ func (l *TestLightClient) setupTestElectra() *TestLightClient {
return l
}
func (l *TestLightClient) setupTestFulu() *TestLightClient {
ctx := context.Background()
attestedSlot := primitives.Slot(uint64(params.BeaconConfig().FuluForkEpoch) * uint64(params.BeaconConfig().SlotsPerEpoch)).Add(1)
if l.increaseAttestedSlotBy > 0 {
attestedSlot = attestedSlot.Add(l.increaseAttestedSlotBy)
}
signatureSlot := attestedSlot.Add(1)
if l.increaseSignatureSlotBy > 0 {
signatureSlot = signatureSlot.Add(l.increaseSignatureSlotBy)
}
// Attested State & Block
attestedState, err := NewBeaconStateFulu()
require.NoError(l.T, err)
require.NoError(l.T, attestedState.SetSlot(attestedSlot))
var signedFinalizedBlock interfaces.SignedBeaconBlock
var finalizedState state.BeaconState
// Finalized checkpoint
if !l.noFinalizedCheckpoint {
var finalizedSlot primitives.Slot
if l.finalizedCheckpointInPrevFork {
finalizedSlot = primitives.Slot(uint64(params.BeaconConfig().ElectraForkEpoch) * uint64(params.BeaconConfig().SlotsPerEpoch))
if l.increaseFinalizedSlotBy > 0 {
finalizedSlot = finalizedSlot.Add(l.increaseFinalizedSlotBy)
}
finalizedState, err = NewBeaconStateElectra()
require.NoError(l.T, err)
require.NoError(l.T, finalizedState.SetSlot(finalizedSlot))
finalizedBlock := NewBeaconBlockElectra()
require.NoError(l.T, err)
finalizedBlock.Block.Slot = finalizedSlot
signedFinalizedBlock, err = blocks.NewSignedBeaconBlock(finalizedBlock)
require.NoError(l.T, err)
finalizedHeader, err := signedFinalizedBlock.Header()
require.NoError(l.T, err)
require.NoError(l.T, finalizedState.SetLatestBlockHeader(finalizedHeader.Header))
finalizedStateRoot, err := finalizedState.HashTreeRoot(ctx)
require.NoError(l.T, err)
finalizedBlock.Block.StateRoot = finalizedStateRoot[:]
signedFinalizedBlock, err = blocks.NewSignedBeaconBlock(finalizedBlock)
require.NoError(l.T, err)
} else {
finalizedSlot = primitives.Slot(uint64(params.BeaconConfig().FuluForkEpoch) * uint64(params.BeaconConfig().SlotsPerEpoch))
if l.increaseFinalizedSlotBy > 0 {
finalizedSlot = finalizedSlot.Add(l.increaseFinalizedSlotBy)
}
finalizedState, err = NewBeaconStateFulu()
require.NoError(l.T, err)
require.NoError(l.T, finalizedState.SetSlot(finalizedSlot))
finalizedBlock := NewBeaconBlockFulu()
require.NoError(l.T, err)
finalizedBlock.Block.Slot = finalizedSlot
signedFinalizedBlock, err = blocks.NewSignedBeaconBlock(finalizedBlock)
require.NoError(l.T, err)
finalizedHeader, err := signedFinalizedBlock.Header()
require.NoError(l.T, err)
require.NoError(l.T, finalizedState.SetLatestBlockHeader(finalizedHeader.Header))
finalizedStateRoot, err := finalizedState.HashTreeRoot(ctx)
require.NoError(l.T, err)
finalizedBlock.Block.StateRoot = finalizedStateRoot[:]
signedFinalizedBlock, err = blocks.NewSignedBeaconBlock(finalizedBlock)
require.NoError(l.T, err)
}
// Set the finalized checkpoint
finalizedBlockRoot, err := signedFinalizedBlock.Block().HashTreeRoot()
require.NoError(l.T, err)
finalizedCheckpoint := &ethpb.Checkpoint{
Epoch: slots.ToEpoch(finalizedSlot),
Root: finalizedBlockRoot[:],
}
require.NoError(l.T, attestedState.SetFinalizedCheckpoint(finalizedCheckpoint))
}
// Attested Block
attestedBlock := NewBeaconBlockFulu()
attestedBlock.Block.Slot = attestedSlot
attestedBlock.Block.ParentRoot = l.attestedParentRoot[:]
signedAttestedBlock, err := blocks.NewSignedBeaconBlock(attestedBlock)
require.NoError(l.T, err)
attestedBlockHeader, err := signedAttestedBlock.Header()
require.NoError(l.T, err)
require.NoError(l.T, attestedState.SetLatestBlockHeader(attestedBlockHeader.Header))
attestedStateRoot, err := attestedState.HashTreeRoot(ctx)
require.NoError(l.T, err)
attestedBlock.Block.StateRoot = attestedStateRoot[:]
signedAttestedBlock, err = blocks.NewSignedBeaconBlock(attestedBlock)
require.NoError(l.T, err)
// Signature State & Block
signatureState, err := NewBeaconStateFulu()
require.NoError(l.T, err)
require.NoError(l.T, signatureState.SetSlot(signatureSlot))
var signedSignatureBlock interfaces.SignedBeaconBlock
if l.blinded {
signatureBlock := NewBlindedBeaconBlockFulu()
signatureBlock.Message.Slot = signatureSlot
attestedBlockRoot, err := signedAttestedBlock.Block().HashTreeRoot()
require.NoError(l.T, err)
signatureBlock.Message.ParentRoot = attestedBlockRoot[:]
var trueBitNum uint64
if l.supermajority {
trueBitNum = uint64((float64(params.BeaconConfig().SyncCommitteeSize) * 2.0 / 3.0) + 1 + float64(l.increaseActiveParticipantsBy))
} else {
trueBitNum = params.BeaconConfig().MinSyncCommitteeParticipants
}
for i := uint64(0); i < trueBitNum; i++ {
signatureBlock.Message.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true)
}
signedSignatureBlock, err = blocks.NewSignedBeaconBlock(signatureBlock)
require.NoError(l.T, err)
signatureBlockHeader, err := signedSignatureBlock.Header()
require.NoError(l.T, err)
err = signatureState.SetLatestBlockHeader(signatureBlockHeader.Header)
require.NoError(l.T, err)
stateRoot, err := signatureState.HashTreeRoot(ctx)
require.NoError(l.T, err)
signatureBlock.Message.StateRoot = stateRoot[:]
signedSignatureBlock, err = blocks.NewSignedBeaconBlock(signatureBlock)
require.NoError(l.T, err)
} else {
signatureBlock := NewBeaconBlockFulu()
signatureBlock.Block.Slot = signatureSlot
attestedBlockRoot, err := signedAttestedBlock.Block().HashTreeRoot()
require.NoError(l.T, err)
signatureBlock.Block.ParentRoot = attestedBlockRoot[:]
var trueBitNum uint64
if l.supermajority {
trueBitNum = uint64((float64(params.BeaconConfig().SyncCommitteeSize) * 2.0 / 3.0) + 1 + float64(l.increaseActiveParticipantsBy))
} else {
trueBitNum = params.BeaconConfig().MinSyncCommitteeParticipants
}
for i := uint64(0); i < trueBitNum; i++ {
signatureBlock.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true)
}
signedSignatureBlock, err = blocks.NewSignedBeaconBlock(signatureBlock)
require.NoError(l.T, err)
signatureBlockHeader, err := signedSignatureBlock.Header()
require.NoError(l.T, err)
err = signatureState.SetLatestBlockHeader(signatureBlockHeader.Header)
require.NoError(l.T, err)
signatureStateRoot, err := signatureState.HashTreeRoot(ctx)
require.NoError(l.T, err)
signatureBlock.Block.StateRoot = signatureStateRoot[:]
signedSignatureBlock, err = blocks.NewSignedBeaconBlock(signatureBlock)
require.NoError(l.T, err)
}
l.State = signatureState
l.AttestedState = attestedState
l.AttestedBlock = signedAttestedBlock
l.Block = signedSignatureBlock
l.Ctx = ctx
l.FinalizedBlock = signedFinalizedBlock
l.FinalizedState = finalizedState
return l
}
func (l *TestLightClient) CheckAttestedHeader(header interfaces.LightClientHeader) {
updateAttestedHeaderBeacon := header.Beacon()
testAttestedHeader, err := l.AttestedBlock.Header()