mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-10 03:31:20 +00:00
cf0bd633f0
* fork/version detection and unmarshaling support * Update config/params/config.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update proto/detect/configfork.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * PR feedback * move ssz initialization into the detect package * clarify comment * VersionForEpoch is much simpler/clearer in reverse * simpler VersionForEpoch; build AllConfigs in init * use fieldparams for Version * Update proto/detect/configfork_test.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * remove custom ForkName type, use runtime/version * pr cleanup * random fix from bad gh ui suggestion; privatize * privatize fieldSpec methods; + unit tests * Update proto/detect/configfork.go Co-authored-by: Potuz <potuz@prysmaticlabs.com> * fix bad github ui suggestion * ensure unique versions for simpler config match * fmt & adding unit test for ByState() * table-driven unit test for ByState * TestUnmarshalState * OrderedSchedule -> network/forks per PR feedback * goimports * lint fixes * move proto/detect -> ssz/encoding/detect * use typeUndefined in String * backport config tests from e2e PR * fix config parity test; make debugging it easier * lint * fix fork schedule initialization * cleanup * fix build * fix big ole derp * anything for you, deep source * goimportsss * InitializeForkSchedule in LoadChainConfigFile * PR feedback Co-authored-by: kasey <kasey@users.noreply.github.com> Co-authored-by: Radosław Kapka <rkapka@wp.pl> Co-authored-by: Potuz <potuz@prysmaticlabs.com>
402 lines
11 KiB
Go
402 lines
11 KiB
Go
package detect
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"math"
|
|
"testing"
|
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
|
"github.com/prysmaticlabs/prysm/config/params"
|
|
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
|
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
|
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
|
"github.com/prysmaticlabs/prysm/runtime/version"
|
|
"github.com/prysmaticlabs/prysm/testing/util"
|
|
"github.com/prysmaticlabs/prysm/time/slots"
|
|
|
|
types "github.com/prysmaticlabs/eth2-types"
|
|
v1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
|
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
|
"github.com/prysmaticlabs/prysm/testing/require"
|
|
)
|
|
|
|
func TestSlotFromBlock(t *testing.T) {
|
|
b := testBlockGenesis()
|
|
var slot types.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 := testBlockAltair()
|
|
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 := testBlockBellatrix()
|
|
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) {
|
|
bc, cleanup := hackBellatrixMaxuint()
|
|
defer cleanup()
|
|
altairSlot, err := slots.EpochStart(bc.AltairForkEpoch)
|
|
bellaSlot, err := slots.EpochStart(bc.BellatrixForkEpoch)
|
|
require.NoError(t, err)
|
|
cases := []struct {
|
|
name string
|
|
version int
|
|
slot types.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),
|
|
},
|
|
}
|
|
for _, c := range cases {
|
|
st, err := stateForVersion(c.version)
|
|
require.NoError(t, err)
|
|
require.NoError(t, st.SetFork(ðpb.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)
|
|
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()
|
|
default:
|
|
return nil, fmt.Errorf("unrecognoized version %d", v)
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalState(t *testing.T) {
|
|
ctx := context.Background()
|
|
bc, cleanup := hackBellatrixMaxuint()
|
|
defer cleanup()
|
|
altairSlot, err := slots.EpochStart(bc.AltairForkEpoch)
|
|
bellaSlot, err := slots.EpochStart(bc.BellatrixForkEpoch)
|
|
require.NoError(t, err)
|
|
cases := []struct {
|
|
name string
|
|
version int
|
|
slot types.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),
|
|
},
|
|
}
|
|
for _, c := range cases {
|
|
st, err := stateForVersion(c.version)
|
|
require.NoError(t, err)
|
|
require.NoError(t, st.SetFork(ðpb.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 hackBellatrixMaxuint() (*params.BeaconChainConfig, func()) {
|
|
// We monkey patch the config to use a smaller value for the bellatrix fork epoch.
|
|
// 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.
|
|
previous := params.BeaconConfig()
|
|
bc := params.MainnetConfig().Copy()
|
|
bc.BellatrixForkEpoch = math.MaxUint32
|
|
bc.InitializeForkSchedule()
|
|
params.OverrideBeaconConfig(bc)
|
|
// override the param used for mainnet with the patched version
|
|
params.KnownConfigs[params.Mainnet] = func() *params.BeaconChainConfig {
|
|
return bc
|
|
}
|
|
return bc, func() {
|
|
// put the previous BeaconChainConfig back in place at the end of the test
|
|
params.OverrideBeaconConfig(previous)
|
|
// restore the normal MainnetConfig func in the KnownConfigs mapping
|
|
params.KnownConfigs[params.Mainnet] = params.MainnetConfig
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalBlock(t *testing.T) {
|
|
bc, cleanup := hackBellatrixMaxuint()
|
|
defer cleanup()
|
|
require.Equal(t, types.Epoch(math.MaxUint32), params.KnownConfigs[params.Mainnet]().BellatrixForkEpoch)
|
|
genv := bytesutil.ToBytes4(bc.GenesisForkVersion)
|
|
altairv := bytesutil.ToBytes4(bc.AltairForkVersion)
|
|
bellav := bytesutil.ToBytes4(bc.BellatrixForkVersion)
|
|
altairS, err := slots.EpochStart(bc.AltairForkEpoch)
|
|
bellaS, err := slots.EpochStart(bc.BellatrixForkEpoch)
|
|
require.NoError(t, err)
|
|
cases := []struct {
|
|
b func(*testing.T, types.Slot) block.SignedBeaconBlock
|
|
name string
|
|
version [4]byte
|
|
slot types.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: "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 signedTestBlockGenesis(t *testing.T, slot types.Slot) block.SignedBeaconBlock {
|
|
b := testBlockGenesis()
|
|
b.Block.Slot = slot
|
|
s, err := wrapper.WrappedSignedBeaconBlock(b)
|
|
require.NoError(t, err)
|
|
return s
|
|
}
|
|
|
|
func testBlockGenesis() *ethpb.SignedBeaconBlock {
|
|
return ðpb.SignedBeaconBlock{
|
|
Block: ðpb.BeaconBlock{
|
|
ProposerIndex: types.ValidatorIndex(0),
|
|
ParentRoot: make([]byte, 32),
|
|
StateRoot: make([]byte, 32),
|
|
Body: ðpb.BeaconBlockBody{
|
|
RandaoReveal: make([]byte, 96),
|
|
Graffiti: make([]byte, 32),
|
|
ProposerSlashings: []*ethpb.ProposerSlashing{},
|
|
AttesterSlashings: []*ethpb.AttesterSlashing{},
|
|
Attestations: []*ethpb.Attestation{},
|
|
Deposits: []*ethpb.Deposit{},
|
|
VoluntaryExits: []*ethpb.SignedVoluntaryExit{},
|
|
Eth1Data: ðpb.Eth1Data{
|
|
DepositRoot: make([]byte, 32),
|
|
DepositCount: 0,
|
|
BlockHash: make([]byte, 32),
|
|
},
|
|
},
|
|
},
|
|
Signature: make([]byte, 96),
|
|
}
|
|
}
|
|
|
|
func signedTestBlockAltair(t *testing.T, slot types.Slot) block.SignedBeaconBlock {
|
|
b := testBlockAltair()
|
|
b.Block.Slot = slot
|
|
s, err := wrapper.WrappedSignedBeaconBlock(b)
|
|
require.NoError(t, err)
|
|
return s
|
|
}
|
|
|
|
func testBlockAltair() *ethpb.SignedBeaconBlockAltair {
|
|
return ðpb.SignedBeaconBlockAltair{
|
|
Block: ðpb.BeaconBlockAltair{
|
|
ProposerIndex: types.ValidatorIndex(0),
|
|
ParentRoot: make([]byte, 32),
|
|
StateRoot: make([]byte, 32),
|
|
Body: ðpb.BeaconBlockBodyAltair{
|
|
RandaoReveal: make([]byte, 96),
|
|
Eth1Data: ðpb.Eth1Data{
|
|
DepositRoot: make([]byte, 32),
|
|
DepositCount: 0,
|
|
BlockHash: make([]byte, 32),
|
|
},
|
|
Graffiti: make([]byte, 32),
|
|
ProposerSlashings: []*ethpb.ProposerSlashing{},
|
|
AttesterSlashings: []*ethpb.AttesterSlashing{},
|
|
Attestations: []*ethpb.Attestation{},
|
|
Deposits: []*ethpb.Deposit{},
|
|
VoluntaryExits: []*ethpb.SignedVoluntaryExit{},
|
|
SyncAggregate: ðpb.SyncAggregate{
|
|
SyncCommitteeBits: make([]byte, 64),
|
|
SyncCommitteeSignature: make([]byte, 96),
|
|
},
|
|
},
|
|
},
|
|
Signature: make([]byte, 96),
|
|
}
|
|
}
|
|
|
|
func signedTestBlockBellatrix(t *testing.T, slot types.Slot) block.SignedBeaconBlock {
|
|
b := testBlockBellatrix()
|
|
b.Block.Slot = slot
|
|
s, err := wrapper.WrappedSignedBeaconBlock(b)
|
|
require.NoError(t, err)
|
|
return s
|
|
}
|
|
|
|
func testBlockBellatrix() *ethpb.SignedBeaconBlockBellatrix {
|
|
return ðpb.SignedBeaconBlockBellatrix{
|
|
Block: ðpb.BeaconBlockBellatrix{
|
|
ProposerIndex: types.ValidatorIndex(0),
|
|
ParentRoot: make([]byte, 32),
|
|
StateRoot: make([]byte, 32),
|
|
Body: ðpb.BeaconBlockBodyBellatrix{
|
|
RandaoReveal: make([]byte, 96),
|
|
Eth1Data: ðpb.Eth1Data{
|
|
DepositRoot: make([]byte, 32),
|
|
DepositCount: 0,
|
|
BlockHash: make([]byte, 32),
|
|
},
|
|
Graffiti: make([]byte, 32),
|
|
ProposerSlashings: []*ethpb.ProposerSlashing{},
|
|
AttesterSlashings: []*ethpb.AttesterSlashing{},
|
|
Attestations: []*ethpb.Attestation{},
|
|
Deposits: []*ethpb.Deposit{},
|
|
VoluntaryExits: []*ethpb.SignedVoluntaryExit{},
|
|
SyncAggregate: ðpb.SyncAggregate{
|
|
SyncCommitteeBits: make([]byte, 64),
|
|
SyncCommitteeSignature: make([]byte, 96),
|
|
},
|
|
ExecutionPayload: &v1.ExecutionPayload{
|
|
ParentHash: make([]byte, 32),
|
|
FeeRecipient: make([]byte, 20),
|
|
StateRoot: make([]byte, 32),
|
|
ReceiptsRoot: make([]byte, 32),
|
|
LogsBloom: make([]byte, 256),
|
|
BlockNumber: 0,
|
|
GasLimit: 0,
|
|
GasUsed: 0,
|
|
Timestamp: 0,
|
|
ExtraData: make([]byte, 32),
|
|
BaseFeePerGas: make([]byte, 32),
|
|
BlockHash: make([]byte, 32),
|
|
Transactions: make([][]byte, 0),
|
|
PrevRandao: make([]byte, 32),
|
|
},
|
|
},
|
|
},
|
|
Signature: make([]byte, 96),
|
|
}
|
|
}
|