Add Fulu fork boilerplate (#14771)

* Prepare for future fork boilerplate.

* Implement the Fulu fork boilerplate.

* `Upgraded state to <fork> log`: Move from debug to info.

Rationale:
This log is the only one notifying the user a new fork happened.
A new fork is always a little bit stressful for a node operator.
Having at least one log indicating the client switched fork is something useful.

* Update testing/util/helpers.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Fix Radek's comment.

* Fix Radek's comment.

* Update beacon-chain/state/state-native/state_trie.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update beacon-chain/state/state-native/state_trie.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Fix Radek's comment.

* Fix Radek's comment.

* Fix Radek's comment.

* Remove Electra struct type aliasing.

---------

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
This commit is contained in:
Manu NALEPA
2025-01-07 21:09:12 +01:00
committed by GitHub
parent a21f544219
commit c48d40907c
99 changed files with 10951 additions and 1507 deletions

View File

@@ -88,6 +88,8 @@ func FromForkVersion(cv [fieldparams.VersionLength]byte) (*VersionedUnmarshaler,
fork = version.Deneb
case bytesutil.ToBytes4(cfg.ElectraForkVersion):
fork = version.Electra
case bytesutil.ToBytes4(cfg.FuluForkVersion):
fork = version.Fulu
default:
return nil, errors.Wrapf(ErrForkNotFound, "version=%#x", cv)
}
@@ -163,6 +165,16 @@ func (cf *VersionedUnmarshaler) UnmarshalBeaconState(marshaled []byte) (s state.
if err != nil {
return nil, errors.Wrapf(err, "failed to init state trie from state, detected fork=%s", forkName)
}
case version.Fulu:
st := &ethpb.BeaconStateFulu{}
err = st.UnmarshalSSZ(marshaled)
if err != nil {
return nil, errors.Wrapf(err, "failed to unmarshal state, detected fork=%s", forkName)
}
s, err = state_native.InitializeFromProtoUnsafeFulu(st)
if err != nil {
return nil, errors.Wrapf(err, "failed to init state trie from state, detected fork=%s", forkName)
}
default:
return nil, fmt.Errorf("unable to initialize BeaconState for fork version=%s", forkName)
}
@@ -213,6 +225,8 @@ func (cf *VersionedUnmarshaler) UnmarshalBeaconBlock(marshaled []byte) (interfac
blk = &ethpb.SignedBeaconBlockDeneb{}
case version.Electra:
blk = &ethpb.SignedBeaconBlockElectra{}
case version.Fulu:
blk = &ethpb.SignedBeaconBlockFulu{}
default:
forkName := version.String(cf.Fork)
return nil, fmt.Errorf("unable to initialize ReadOnlyBeaconBlock for fork version=%s at slot=%d", forkName, slot)
@@ -250,6 +264,8 @@ func (cf *VersionedUnmarshaler) UnmarshalBlindedBeaconBlock(marshaled []byte) (i
blk = &ethpb.SignedBlindedBeaconBlockDeneb{}
case version.Electra:
blk = &ethpb.SignedBlindedBeaconBlockElectra{}
case version.Fulu:
blk = &ethpb.SignedBlindedBeaconBlockFulu{}
default:
forkName := version.String(cf.Fork)
return nil, fmt.Errorf("unable to initialize ReadOnlyBeaconBlock for fork version=%s at slot=%d", forkName, slot)

View File

@@ -46,8 +46,8 @@ func TestSlotFromBlock(t *testing.T) {
}
func TestByState(t *testing.T) {
undo := util.HackElectraMaxuint(t)
defer undo()
defer util.HackForksMaxuint(t, []int{version.Electra, version.Fulu})()
bc := params.BeaconConfig()
altairSlot, err := slots.EpochStart(bc.AltairForkEpoch)
require.NoError(t, err)
@@ -59,6 +59,8 @@ func TestByState(t *testing.T) {
require.NoError(t, err)
electraSlot, err := slots.EpochStart(bc.ElectraForkEpoch)
require.NoError(t, err)
fuluSlot, err := slots.EpochStart(bc.FuluForkEpoch)
require.NoError(t, err)
cases := []struct {
name string
version int
@@ -101,6 +103,12 @@ func TestByState(t *testing.T) {
slot: electraSlot,
forkversion: bytesutil.ToBytes4(bc.ElectraForkVersion),
},
{
name: "fulu",
version: version.Fulu,
slot: fuluSlot,
forkversion: bytesutil.ToBytes4(bc.FuluForkVersion),
},
}
for _, c := range cases {
st, err := stateForVersion(c.version)
@@ -135,6 +143,8 @@ func stateForVersion(v int) (state.BeaconState, error) {
return util.NewBeaconStateDeneb()
case version.Electra:
return util.NewBeaconStateElectra()
case version.Fulu:
return util.NewBeaconStateFulu()
default:
return nil, fmt.Errorf("unrecognized version %d", v)
}
@@ -142,8 +152,8 @@ func stateForVersion(v int) (state.BeaconState, error) {
func TestUnmarshalState(t *testing.T) {
ctx := context.Background()
undo := util.HackElectraMaxuint(t)
defer undo()
defer util.HackForksMaxuint(t, []int{version.Electra, version.Fulu})()
bc := params.BeaconConfig()
altairSlot, err := slots.EpochStart(bc.AltairForkEpoch)
require.NoError(t, err)
@@ -155,6 +165,8 @@ func TestUnmarshalState(t *testing.T) {
require.NoError(t, err)
electraSlot, err := slots.EpochStart(bc.ElectraForkEpoch)
require.NoError(t, err)
fuluSlot, err := slots.EpochStart(bc.FuluForkEpoch)
require.NoError(t, err)
cases := []struct {
name string
version int
@@ -197,6 +209,12 @@ func TestUnmarshalState(t *testing.T) {
slot: electraSlot,
forkversion: bytesutil.ToBytes4(bc.ElectraForkVersion),
},
{
name: "fulu",
version: version.Fulu,
slot: fuluSlot,
forkversion: bytesutil.ToBytes4(bc.FuluForkVersion),
},
}
for _, c := range cases {
st, err := stateForVersion(c.version)
@@ -222,8 +240,8 @@ func TestUnmarshalState(t *testing.T) {
}
func TestDetectAndUnmarshalBlock(t *testing.T) {
undo := util.HackElectraMaxuint(t)
defer undo()
defer util.HackForksMaxuint(t, []int{version.Electra, version.Fulu})()
altairS, err := slots.EpochStart(params.BeaconConfig().AltairForkEpoch)
require.NoError(t, err)
bellaS, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch)
@@ -234,6 +252,8 @@ func TestDetectAndUnmarshalBlock(t *testing.T) {
require.NoError(t, err)
electraS, err := slots.EpochStart(params.BeaconConfig().ElectraForkEpoch)
require.NoError(t, err)
fuluS, err := slots.EpochStart(params.BeaconConfig().FuluForkEpoch)
require.NoError(t, err)
cases := []struct {
b func(*testing.T, primitives.Slot) interfaces.ReadOnlySignedBeaconBlock
name string
@@ -284,6 +304,11 @@ func TestDetectAndUnmarshalBlock(t *testing.T) {
b: signedTestBlockElectra,
slot: electraS,
},
{
name: "first slot of fulu",
b: signedTestBlockFulu,
slot: fuluS,
},
{
name: "bellatrix block in altair slot",
b: signedTestBlockBellatrix,
@@ -320,14 +345,15 @@ func TestDetectAndUnmarshalBlock(t *testing.T) {
}
func TestUnmarshalBlock(t *testing.T) {
undo := util.HackElectraMaxuint(t)
defer undo()
defer util.HackForksMaxuint(t, []int{version.Electra, version.Fulu})()
genv := bytesutil.ToBytes4(params.BeaconConfig().GenesisForkVersion)
altairv := bytesutil.ToBytes4(params.BeaconConfig().AltairForkVersion)
bellav := bytesutil.ToBytes4(params.BeaconConfig().BellatrixForkVersion)
capellaV := bytesutil.ToBytes4(params.BeaconConfig().CapellaForkVersion)
denebV := bytesutil.ToBytes4(params.BeaconConfig().DenebForkVersion)
electraV := bytesutil.ToBytes4(params.BeaconConfig().ElectraForkVersion)
fuluV := bytesutil.ToBytes4(params.BeaconConfig().FuluForkVersion)
altairS, err := slots.EpochStart(params.BeaconConfig().AltairForkEpoch)
require.NoError(t, err)
bellaS, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch)
@@ -338,6 +364,8 @@ func TestUnmarshalBlock(t *testing.T) {
require.NoError(t, err)
electraS, err := slots.EpochStart(params.BeaconConfig().ElectraForkEpoch)
require.NoError(t, err)
fuluS, err := slots.EpochStart(params.BeaconConfig().FuluForkEpoch)
require.NoError(t, err)
cases := []struct {
b func(*testing.T, primitives.Slot) interfaces.ReadOnlySignedBeaconBlock
name string
@@ -398,6 +426,12 @@ func TestUnmarshalBlock(t *testing.T) {
version: electraV,
slot: electraS,
},
{
name: "first slot of fulu",
b: signedTestBlockFulu,
version: fuluV,
slot: fuluS,
},
{
name: "bellatrix block in altair slot",
b: signedTestBlockBellatrix,
@@ -442,14 +476,15 @@ func TestUnmarshalBlock(t *testing.T) {
}
func TestUnmarshalBlindedBlock(t *testing.T) {
undo := util.HackElectraMaxuint(t)
defer undo()
defer util.HackForksMaxuint(t, []int{version.Electra, version.Fulu})()
genv := bytesutil.ToBytes4(params.BeaconConfig().GenesisForkVersion)
altairv := bytesutil.ToBytes4(params.BeaconConfig().AltairForkVersion)
bellav := bytesutil.ToBytes4(params.BeaconConfig().BellatrixForkVersion)
capellaV := bytesutil.ToBytes4(params.BeaconConfig().CapellaForkVersion)
denebV := bytesutil.ToBytes4(params.BeaconConfig().DenebForkVersion)
electraV := bytesutil.ToBytes4(params.BeaconConfig().ElectraForkVersion)
fuluV := bytesutil.ToBytes4(params.BeaconConfig().FuluForkVersion)
altairS, err := slots.EpochStart(params.BeaconConfig().AltairForkEpoch)
require.NoError(t, err)
bellaS, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch)
@@ -460,6 +495,8 @@ func TestUnmarshalBlindedBlock(t *testing.T) {
require.NoError(t, err)
electraS, err := slots.EpochStart(params.BeaconConfig().ElectraForkEpoch)
require.NoError(t, err)
fuluS, err := slots.EpochStart(params.BeaconConfig().FuluForkEpoch)
require.NoError(t, err)
cases := []struct {
b func(*testing.T, primitives.Slot) interfaces.ReadOnlySignedBeaconBlock
name string
@@ -527,6 +564,12 @@ func TestUnmarshalBlindedBlock(t *testing.T) {
version: electraV,
slot: electraS,
},
{
name: "first slot of fulu",
b: signedTestBlindedBlockFulu,
version: fuluV,
slot: fuluS,
},
{
name: "genesis block in altair slot",
b: signedTestBlockGenesis,
@@ -666,3 +709,23 @@ func signedTestBlindedBlockElectra(t *testing.T, slot primitives.Slot) interface
require.NoError(t, err)
return s
}
// ----------------------------------------------------------------------------
// Fulu
// ----------------------------------------------------------------------------
func signedTestBlockFulu(t *testing.T, slot primitives.Slot) interfaces.ReadOnlySignedBeaconBlock {
b := util.NewBeaconBlockFulu()
b.Block.Slot = slot
s, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
return s
}
func signedTestBlindedBlockFulu(t *testing.T, slot primitives.Slot) interfaces.ReadOnlySignedBeaconBlock {
b := util.NewBlindedBeaconBlockFulu()
b.Message.Slot = slot
s, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
return s
}