diff --git a/encoding/ssz/detect/configfork.go b/encoding/ssz/detect/configfork.go index edd2c866e..79f48fea4 100644 --- a/encoding/ssz/detect/configfork.go +++ b/encoding/ssz/detect/configfork.go @@ -68,6 +68,8 @@ func FromForkVersion(cv [fieldparams.VersionLength]byte) (*VersionedUnmarshaler, fork = version.Bellatrix case bytesutil.ToBytes4(cfg.CapellaForkVersion): fork = version.Capella + case bytesutil.ToBytes4(cfg.DenebForkVersion): + fork = version.Deneb default: return nil, errors.Wrapf(ErrForkNotFound, "version=%#x", cv) } @@ -123,6 +125,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.Deneb: + st := ðpb.BeaconStateDeneb{} + err = st.UnmarshalSSZ(marshaled) + if err != nil { + return nil, errors.Wrapf(err, "failed to unmarshal state, detected fork=%s", forkName) + } + s, err = state_native.InitializeFromProtoUnsafeDeneb(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) } @@ -169,6 +181,8 @@ func (cf *VersionedUnmarshaler) UnmarshalBeaconBlock(marshaled []byte) (interfac blk = ðpb.SignedBeaconBlockBellatrix{} case version.Capella: blk = ðpb.SignedBeaconBlockCapella{} + case version.Deneb: + blk = ðpb.SignedBeaconBlockDeneb{} default: forkName := version.String(cf.Fork) return nil, fmt.Errorf("unable to initialize ReadOnlyBeaconBlock for fork version=%s at slot=%d", forkName, slot) @@ -202,6 +216,8 @@ func (cf *VersionedUnmarshaler) UnmarshalBlindedBeaconBlock(marshaled []byte) (i blk = ðpb.SignedBlindedBeaconBlockBellatrix{} case version.Capella: blk = ðpb.SignedBlindedBeaconBlockCapella{} + case version.Deneb: + blk = ðpb.SignedBlindedBeaconBlockDeneb{} default: forkName := version.String(cf.Fork) return nil, fmt.Errorf("unable to initialize ReadOnlyBeaconBlock for fork version=%s at slot=%d", forkName, slot) diff --git a/encoding/ssz/detect/configfork_test.go b/encoding/ssz/detect/configfork_test.go index b4191a684..6fc0b39a5 100644 --- a/encoding/ssz/detect/configfork_test.go +++ b/encoding/ssz/detect/configfork_test.go @@ -48,7 +48,7 @@ func TestSlotFromBlock(t *testing.T) { } func TestByState(t *testing.T) { - undo, err := hackCapellaMaxuint() + undo, err := hackDenebMaxuint() require.NoError(t, err) defer func() { require.NoError(t, undo()) @@ -60,6 +60,8 @@ func TestByState(t *testing.T) { require.NoError(t, err) capellaSlot, err := slots.EpochStart(bc.CapellaForkEpoch) require.NoError(t, err) + denebSlot, err := slots.EpochStart(bc.DenebForkEpoch) + require.NoError(t, err) cases := []struct { name string version int @@ -90,6 +92,12 @@ func TestByState(t *testing.T) { slot: capellaSlot, forkversion: bytesutil.ToBytes4(bc.CapellaForkVersion), }, + { + name: "deneb", + version: version.Deneb, + slot: denebSlot, + forkversion: bytesutil.ToBytes4(bc.DenebForkVersion), + }, } for _, c := range cases { st, err := stateForVersion(c.version) @@ -120,6 +128,8 @@ func stateForVersion(v int) (state.BeaconState, error) { return util.NewBeaconStateBellatrix() case version.Capella: return util.NewBeaconStateCapella() + case version.Deneb: + return util.NewBeaconStateDeneb() default: return nil, fmt.Errorf("unrecognized version %d", v) } @@ -127,7 +137,7 @@ func stateForVersion(v int) (state.BeaconState, error) { func TestUnmarshalState(t *testing.T) { ctx := context.Background() - undo, err := hackCapellaMaxuint() + undo, err := hackDenebMaxuint() require.NoError(t, err) defer func() { require.NoError(t, undo()) @@ -137,6 +147,10 @@ func TestUnmarshalState(t *testing.T) { require.NoError(t, err) bellaSlot, err := slots.EpochStart(bc.BellatrixForkEpoch) require.NoError(t, err) + capellaSlot, err := slots.EpochStart(bc.CapellaForkEpoch) + require.NoError(t, err) + denebSlot, err := slots.EpochStart(bc.DenebForkEpoch) + require.NoError(t, err) cases := []struct { name string version int @@ -161,6 +175,18 @@ func TestUnmarshalState(t *testing.T) { slot: bellaSlot, forkversion: bytesutil.ToBytes4(bc.BellatrixForkVersion), }, + { + name: "capella", + version: version.Capella, + slot: capellaSlot, + forkversion: bytesutil.ToBytes4(bc.CapellaForkVersion), + }, + { + name: "deneb", + version: version.Deneb, + slot: denebSlot, + forkversion: bytesutil.ToBytes4(bc.DenebForkVersion), + }, } for _, c := range cases { st, err := stateForVersion(c.version) @@ -185,19 +211,19 @@ func TestUnmarshalState(t *testing.T) { } } -func hackCapellaMaxuint() (func() error, error) { - // We monkey patch the config to use a smaller value for the bellatrix fork epoch. +func hackDenebMaxuint() (func() error, error) { + // We monkey patch the config to use a smaller value for the next fork epoch (which is always set to maxint). // Upstream configs use MaxUint64, which leads to a multiplication overflow when converting epoch->slot. // Unfortunately we have unit tests that assert our config matches the upstream config, so we have to choose between // breaking conformance, adding a special case to the conformance unit test, or patch it here. bc := params.MainnetConfig().Copy() - bc.CapellaForkEpoch = math.MaxUint32 + bc.DenebForkEpoch = math.MaxUint32 undo, err := params.SetActiveWithUndo(bc) return undo, err } func TestUnmarshalBlock(t *testing.T) { - undo, err := hackCapellaMaxuint() + undo, err := hackDenebMaxuint() require.NoError(t, err) defer func() { require.NoError(t, undo()) @@ -205,10 +231,16 @@ func TestUnmarshalBlock(t *testing.T) { 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) altairS, err := slots.EpochStart(params.BeaconConfig().AltairForkEpoch) require.NoError(t, err) bellaS, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch) require.NoError(t, err) + capellaS, err := slots.EpochStart(params.BeaconConfig().CapellaForkEpoch) + require.NoError(t, err) + denebS, err := slots.EpochStart(params.BeaconConfig().DenebForkEpoch) + require.NoError(t, err) cases := []struct { b func(*testing.T, primitives.Slot) interfaces.ReadOnlySignedBeaconBlock name string @@ -245,6 +277,24 @@ func TestUnmarshalBlock(t *testing.T) { version: bellav, slot: bellaS, }, + { + name: "first slot of capella", + b: signedTestBlockCapella, + version: capellaV, + slot: capellaS, + }, + { + name: "last slot of capella", + b: signedTestBlockCapella, + version: capellaV, + slot: denebS - 1, + }, + { + name: "first slot of deneb", + b: signedTestBlockDeneb, + version: denebV, + slot: denebS, + }, { name: "bellatrix block in altair slot", b: signedTestBlockBellatrix, @@ -289,7 +339,7 @@ func TestUnmarshalBlock(t *testing.T) { } func TestUnmarshalBlindedBlock(t *testing.T) { - undo, err := hackCapellaMaxuint() + undo, err := hackDenebMaxuint() require.NoError(t, err) defer func() { require.NoError(t, undo()) @@ -297,10 +347,16 @@ func TestUnmarshalBlindedBlock(t *testing.T) { 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) altairS, err := slots.EpochStart(params.BeaconConfig().AltairForkEpoch) require.NoError(t, err) bellaS, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch) require.NoError(t, err) + capellaS, err := slots.EpochStart(params.BeaconConfig().CapellaForkEpoch) + require.NoError(t, err) + denebS, err := slots.EpochStart(params.BeaconConfig().DenebForkEpoch) + require.NoError(t, err) cases := []struct { b func(*testing.T, primitives.Slot) interfaces.ReadOnlySignedBeaconBlock name string @@ -344,6 +400,24 @@ func TestUnmarshalBlindedBlock(t *testing.T) { slot: bellaS - 1, err: errBlockForkMismatch, }, + { + name: "first slot of capella", + b: signedTestBlindedBlockCapella, + version: capellaV, + slot: capellaS, + }, + { + name: "last slot of capella", + b: signedTestBlindedBlockCapella, + version: capellaV, + slot: denebS - 1, + }, + { + name: "first slot of deneb", + b: signedTestBlindedBlockDeneb, + version: denebV, + slot: denebS, + }, { name: "genesis block in altair slot", b: signedTestBlockGenesis, @@ -411,3 +485,35 @@ func signedTestBlindedBlockBellatrix(t *testing.T, slot primitives.Slot) interfa require.NoError(t, err) return s } + +func signedTestBlockCapella(t *testing.T, slot primitives.Slot) interfaces.ReadOnlySignedBeaconBlock { + b := util.NewBeaconBlockCapella() + b.Block.Slot = slot + s, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + return s +} + +func signedTestBlindedBlockCapella(t *testing.T, slot primitives.Slot) interfaces.ReadOnlySignedBeaconBlock { + b := util.NewBlindedBeaconBlockCapella() + b.Block.Slot = slot + s, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + return s +} + +func signedTestBlockDeneb(t *testing.T, slot primitives.Slot) interfaces.ReadOnlySignedBeaconBlock { + b := util.NewBeaconBlockDeneb() + b.Block.Slot = slot + s, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + return s +} + +func signedTestBlindedBlockDeneb(t *testing.T, slot primitives.Slot) interfaces.ReadOnlySignedBeaconBlock { + b := util.NewBlindedBeaconBlockDeneb() + b.Block.Slot = slot + s, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + return s +}