Files
prysm/encoding/ssz/detect/configfork_test.go
Bastin 92bd211e4d upgrade v6 to v7 (#15989)
* upgrade v6 to v7

* changelog

* update-go-ssz
2025-11-06 16:16:23 +00:00

837 lines
23 KiB
Go

package detect
import (
"fmt"
"testing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/runtime/version"
"github.com/OffchainLabs/prysm/v7/testing/require"
"github.com/OffchainLabs/prysm/v7/testing/util"
"github.com/OffchainLabs/prysm/v7/time/slots"
)
func TestSlotFromBlock(t *testing.T) {
b := util.NewBeaconBlock()
var slot primitives.Slot = 3
b.Block.Slot = slot
bb, err := b.MarshalSSZ()
require.NoError(t, err)
sfb, err := slotFromBlock(bb)
require.NoError(t, err)
require.Equal(t, slot, sfb)
ba := util.NewBeaconBlockAltair()
ba.Block.Slot = slot
bab, err := ba.MarshalSSZ()
require.NoError(t, err)
sfba, err := slotFromBlock(bab)
require.NoError(t, err)
require.Equal(t, slot, sfba)
bm := util.NewBeaconBlockBellatrix()
bm.Block.Slot = slot
bmb, err := ba.MarshalSSZ()
require.NoError(t, err)
sfbm, err := slotFromBlock(bmb)
require.NoError(t, err)
require.Equal(t, slot, sfbm)
}
func TestByState(t *testing.T) {
defer util.HackForksMaxuint(t, []int{version.Electra, version.Fulu})()
bc := params.BeaconConfig()
altairSlot, err := slots.EpochStart(bc.AltairForkEpoch)
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)
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
slot primitives.Slot
forkversion [4]byte
}{
{
name: "genesis",
version: version.Phase0,
slot: 0,
forkversion: bytesutil.ToBytes4(bc.GenesisForkVersion),
},
{
name: "altair",
version: version.Altair,
slot: altairSlot,
forkversion: bytesutil.ToBytes4(bc.AltairForkVersion),
},
{
name: "bellatrix",
version: version.Bellatrix,
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),
},
{
name: "electra",
version: version.Electra,
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)
require.NoError(t, err)
fork, err := params.Fork(slots.ToEpoch(c.slot))
require.NoError(t, err)
require.NoError(t, st.SetFork(fork))
require.NoError(t, st.SetSlot(c.slot))
m, err := st.MarshalSSZ()
require.NoError(t, err)
cf, err := FromState(m)
require.NoError(t, err)
require.Equal(t, c.version, cf.Fork)
require.Equal(t, c.forkversion, cf.Version)
require.Equal(t, bc.ConfigName, cf.Config.ConfigName)
}
}
func stateForVersion(v int) (state.BeaconState, error) {
switch v {
case version.Phase0:
return util.NewBeaconState()
case version.Altair:
return util.NewBeaconStateAltair()
case version.Bellatrix:
return util.NewBeaconStateBellatrix()
case version.Capella:
return util.NewBeaconStateCapella()
case version.Deneb:
return util.NewBeaconStateDeneb()
case version.Electra:
return util.NewBeaconStateElectra()
case version.Fulu:
return util.NewBeaconStateFulu()
default:
return nil, fmt.Errorf("unrecognized version %d", v)
}
}
func TestUnmarshalState(t *testing.T) {
ctx := t.Context()
defer util.HackForksMaxuint(t, []int{version.Electra, version.Fulu})()
bc := params.BeaconConfig()
altairSlot, err := slots.EpochStart(bc.AltairForkEpoch)
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)
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
slot primitives.Slot
forkversion [4]byte
}{
{
name: "genesis",
version: version.Phase0,
slot: 0,
forkversion: bytesutil.ToBytes4(bc.GenesisForkVersion),
},
{
name: "altair",
version: version.Altair,
slot: altairSlot,
forkversion: bytesutil.ToBytes4(bc.AltairForkVersion),
},
{
name: "bellatrix",
version: version.Bellatrix,
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),
},
{
name: "electra",
version: version.Electra,
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)
require.NoError(t, err)
require.NoError(t, st.SetFork(&ethpb.Fork{
PreviousVersion: make([]byte, 4),
CurrentVersion: c.forkversion[:],
Epoch: 0,
}))
require.NoError(t, st.SetSlot(c.slot))
m, err := st.MarshalSSZ()
require.NoError(t, err)
cf, err := FromState(m)
require.NoError(t, err)
s, err := cf.UnmarshalBeaconState(m)
require.NoError(t, err)
expected, err := st.HashTreeRoot(ctx)
require.NoError(t, err)
actual, err := s.HashTreeRoot(ctx)
require.NoError(t, err)
require.DeepEqual(t, expected, actual)
}
}
func TestDetectAndUnmarshalBlock(t *testing.T) {
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)
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)
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
slot primitives.Slot
errExists bool
}{
{
name: "genesis - slot 0",
b: signedTestBlockGenesis,
},
{
name: "last slot of phase 0",
b: signedTestBlockGenesis,
slot: altairS - 1,
},
{
name: "first slot of altair",
b: signedTestBlockAltair,
slot: altairS,
},
{
name: "last slot of altair",
b: signedTestBlockAltair,
slot: bellaS - 1,
},
{
name: "first slot of bellatrix",
b: signedTestBlockBellatrix,
slot: bellaS,
},
{
name: "first slot of capella",
b: signedTestBlockCapella,
slot: capellaS,
},
{
name: "last slot of capella",
b: signedTestBlockCapella,
slot: denebS - 1,
},
{
name: "first slot of deneb",
b: signedTestBlockDeneb,
slot: denebS,
},
{
name: "first slot of electra",
b: signedTestBlockElectra,
slot: electraS,
},
{
name: "first slot of fulu",
b: signedTestBlockFulu,
slot: fuluS,
},
{
name: "bellatrix block in altair slot",
b: signedTestBlockBellatrix,
slot: bellaS - 1,
errExists: true,
},
{
name: "genesis block in altair slot",
b: signedTestBlockGenesis,
slot: bellaS - 1,
errExists: true,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
b := c.b(t, c.slot)
marshaled, err := b.MarshalSSZ()
require.NoError(t, err)
cf, err := FromBlock(marshaled)
require.NoError(t, err)
bcf, err := cf.UnmarshalBeaconBlock(marshaled)
if c.errExists {
require.NotNil(t, err)
return
}
require.NoError(t, err)
expected, err := b.Block().HashTreeRoot()
require.NoError(t, err)
actual, err := bcf.Block().HashTreeRoot()
require.NoError(t, err)
require.Equal(t, expected, actual)
})
}
}
func TestUnmarshalBlock(t *testing.T) {
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)
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)
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
version [4]byte
slot primitives.Slot
err error
}{
{
name: "genesis - slot 0",
b: signedTestBlockGenesis,
version: genv,
},
{
name: "last slot of phase 0",
b: signedTestBlockGenesis,
version: genv,
slot: altairS - 1,
},
{
name: "first slot of altair",
b: signedTestBlockAltair,
version: altairv,
slot: altairS,
},
{
name: "last slot of altair",
b: signedTestBlockAltair,
version: altairv,
slot: bellaS - 1,
},
{
name: "first slot of bellatrix",
b: signedTestBlockBellatrix,
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: "first slot of electra",
b: signedTestBlockElectra,
version: electraV,
slot: electraS,
},
{
name: "first slot of fulu",
b: signedTestBlockFulu,
version: fuluV,
slot: fuluS,
},
{
name: "bellatrix block in altair slot",
b: signedTestBlockBellatrix,
version: bellav,
slot: bellaS - 1,
err: errBlockForkMismatch,
},
{
name: "genesis block in altair slot",
b: signedTestBlockGenesis,
version: genv,
slot: bellaS - 1,
err: errBlockForkMismatch,
},
{
name: "altair block in genesis slot",
b: signedTestBlockAltair,
version: altairv,
err: errBlockForkMismatch,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
b := c.b(t, c.slot)
marshaled, err := b.MarshalSSZ()
require.NoError(t, err)
cf, err := FromForkVersion(c.version)
require.NoError(t, err)
bcf, err := cf.UnmarshalBeaconBlock(marshaled)
if c.err != nil {
require.ErrorIs(t, err, c.err)
return
}
require.NoError(t, err)
expected, err := b.Block().HashTreeRoot()
require.NoError(t, err)
actual, err := bcf.Block().HashTreeRoot()
require.NoError(t, err)
require.Equal(t, expected, actual)
})
}
}
func TestUnmarshalBlindedBlock(t *testing.T) {
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)
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)
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
version [4]byte
slot primitives.Slot
err error
}{
{
name: "genesis - slot 0",
b: signedTestBlockGenesis,
version: genv,
},
{
name: "last slot of phase 0",
b: signedTestBlockGenesis,
version: genv,
slot: altairS - 1,
},
{
name: "first slot of altair",
b: signedTestBlockAltair,
version: altairv,
slot: altairS,
},
{
name: "last slot of altair",
b: signedTestBlockAltair,
version: altairv,
slot: bellaS - 1,
},
{
name: "first slot of bellatrix",
b: signedTestBlindedBlockBellatrix,
version: bellav,
slot: bellaS,
},
{
name: "bellatrix block in altair slot",
b: signedTestBlindedBlockBellatrix,
version: bellav,
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: "first slot of electra",
b: signedTestBlindedBlockElectra,
version: electraV,
slot: electraS,
},
{
name: "first slot of fulu",
b: signedTestBlindedBlockFulu,
version: fuluV,
slot: fuluS,
},
{
name: "genesis block in altair slot",
b: signedTestBlockGenesis,
version: genv,
slot: bellaS - 1,
err: errBlockForkMismatch,
},
{
name: "altair block in genesis slot",
b: signedTestBlockAltair,
version: altairv,
err: errBlockForkMismatch,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
b := c.b(t, c.slot)
marshaled, err := b.MarshalSSZ()
require.NoError(t, err)
cf, err := FromForkVersion(c.version)
require.NoError(t, err)
bcf, err := cf.UnmarshalBlindedBeaconBlock(marshaled)
if c.err != nil {
require.ErrorIs(t, err, c.err)
return
}
require.NoError(t, err)
expected, err := b.Block().HashTreeRoot()
require.NoError(t, err)
actual, err := bcf.Block().HashTreeRoot()
require.NoError(t, err)
require.Equal(t, expected, actual)
})
}
}
// ----------------------------------------------------------------------------
// Phase 0
// ----------------------------------------------------------------------------
func signedTestBlockGenesis(t *testing.T, slot primitives.Slot) interfaces.ReadOnlySignedBeaconBlock {
b := util.NewBeaconBlock()
b.Block.Slot = slot
s, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
return s
}
// ----------------------------------------------------------------------------
// Altair
// ----------------------------------------------------------------------------
func signedTestBlockAltair(t *testing.T, slot primitives.Slot) interfaces.ReadOnlySignedBeaconBlock {
b := util.NewBeaconBlockAltair()
b.Block.Slot = slot
s, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
return s
}
// ----------------------------------------------------------------------------
// Bellatrix
// ----------------------------------------------------------------------------
func signedTestBlockBellatrix(t *testing.T, slot primitives.Slot) interfaces.ReadOnlySignedBeaconBlock {
b := util.NewBeaconBlockBellatrix()
b.Block.Slot = slot
s, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
return s
}
func signedTestBlindedBlockBellatrix(t *testing.T, slot primitives.Slot) interfaces.ReadOnlySignedBeaconBlock {
b := util.NewBlindedBeaconBlockBellatrix()
b.Block.Slot = slot
s, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
return s
}
// ----------------------------------------------------------------------------
// Capella
// ----------------------------------------------------------------------------
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
}
// ----------------------------------------------------------------------------
// Deneb
// ----------------------------------------------------------------------------
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.Message.Slot = slot
s, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
return s
}
// ----------------------------------------------------------------------------
// Electra
// ----------------------------------------------------------------------------
func signedTestBlockElectra(t *testing.T, slot primitives.Slot) interfaces.ReadOnlySignedBeaconBlock {
b := util.NewBeaconBlockElectra()
b.Block.Slot = slot
s, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
return s
}
func signedTestBlindedBlockElectra(t *testing.T, slot primitives.Slot) interfaces.ReadOnlySignedBeaconBlock {
b := util.NewBlindedBeaconBlockElectra()
b.Message.Slot = slot
s, err := blocks.NewSignedBeaconBlock(b)
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
}
func TestUnmarshalStateStandalone(t *testing.T) {
ctx := t.Context()
defer util.HackForksMaxuint(t, []int{version.Electra, version.Fulu})()
bc := params.BeaconConfig()
altairSlot, err := slots.EpochStart(bc.AltairForkEpoch)
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)
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
slot primitives.Slot
forkversion [4]byte
}{
{
name: "phase0",
version: version.Phase0,
slot: 0,
forkversion: bytesutil.ToBytes4(bc.GenesisForkVersion),
},
{
name: "altair",
version: version.Altair,
slot: altairSlot,
forkversion: bytesutil.ToBytes4(bc.AltairForkVersion),
},
{
name: "bellatrix",
version: version.Bellatrix,
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),
},
{
name: "electra",
version: version.Electra,
slot: electraSlot,
forkversion: bytesutil.ToBytes4(bc.ElectraForkVersion),
},
{
name: "fulu",
version: version.Fulu,
slot: fuluSlot,
forkversion: bytesutil.ToBytes4(bc.FuluForkVersion),
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
// Create a state for the specific version
originalState, err := stateForVersion(c.version)
require.NoError(t, err)
require.NoError(t, originalState.SetFork(&ethpb.Fork{
PreviousVersion: make([]byte, 4),
CurrentVersion: c.forkversion[:],
Epoch: 0,
}))
require.NoError(t, originalState.SetSlot(c.slot))
marshaled, err := originalState.MarshalSSZ()
require.NoError(t, err)
unmarshaledState, err := UnmarshalState(marshaled)
require.NoError(t, err)
require.NotNil(t, unmarshaledState)
// Verify the unmarshaled state matches the original
expectedRoot, err := originalState.HashTreeRoot(ctx)
require.NoError(t, err)
actualRoot, err := unmarshaledState.HashTreeRoot(ctx)
require.NoError(t, err)
require.DeepEqual(t, expectedRoot, actualRoot)
// Verify basic state properties
require.Equal(t, c.slot, unmarshaledState.Slot())
fork := unmarshaledState.Fork()
require.DeepEqual(t, c.forkversion[:], fork.CurrentVersion)
})
}
t.Run("invalid state data", func(t *testing.T) {
invalidData := []byte("bad")
_, err := UnmarshalState(invalidData)
require.ErrorContains(t, "failed to detect version from state", err)
})
}