Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Capella State Detection #11862

Merged
merged 16 commits into from
Jan 13, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion beacon-chain/core/blocks/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func NewGenesisBlock(stateRoot []byte) *ethpb.SignedBeaconBlock {
return block
}

var ErrUnrecognizedState = errors.New("uknonwn underlying type for state.BeaconState value")
var ErrUnrecognizedState = errors.New("unknown underlying type for state.BeaconState value")

func NewGenesisBlockForState(ctx context.Context, st state.BeaconState) (interfaces.SignedBeaconBlock, error) {
root, err := st.HashTreeRoot(ctx)
Expand Down Expand Up @@ -113,6 +113,38 @@ func NewGenesisBlockForState(ctx context.Context, st state.BeaconState) (interfa
},
Signature: params.BeaconConfig().EmptySignature[:],
})
case *ethpb.BeaconStateCapella:
return blocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlockCapella{
Block: &ethpb.BeaconBlockCapella{
ParentRoot: params.BeaconConfig().ZeroHash[:],
StateRoot: root[:],
Body: &ethpb.BeaconBlockBodyCapella{
RandaoReveal: make([]byte, 96),
Eth1Data: &ethpb.Eth1Data{
DepositRoot: make([]byte, 32),
BlockHash: make([]byte, 32),
},
Graffiti: make([]byte, 32),
SyncAggregate: &ethpb.SyncAggregate{
SyncCommitteeBits: make([]byte, fieldparams.SyncCommitteeLength/8),
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
},
ExecutionPayload: &enginev1.ExecutionPayloadCapella{
ParentHash: make([]byte, 32),
FeeRecipient: make([]byte, 20),
StateRoot: make([]byte, 32),
ReceiptsRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
PrevRandao: make([]byte, 32),
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
Transactions: make([][]byte, 0),
Withdrawals: make([]*enginev1.Withdrawal, 0),
},
},
},
Signature: params.BeaconConfig().EmptySignature[:],
})
default:
return nil, ErrUnrecognizedState
}
Expand Down
35 changes: 34 additions & 1 deletion beacon-chain/db/kv/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package kv

import (
"context"
"encoding/hex"
"os"
"testing"

"github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db/iface"
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v3/testing/assert"
"github.com/prysmaticlabs/prysm/v3/testing/require"
"github.com/prysmaticlabs/prysm/v3/testing/util"
Expand Down Expand Up @@ -48,6 +50,37 @@ func testGenesisDataSaved(t *testing.T, db iface.Database) {
require.Equal(t, gbHTR, headHTR, "head block does not match genesis block")
}

func TestLoadCapellaFromFile(t *testing.T) {
cfg, err := params.ByName(params.MainnetName)
require.NoError(t, err)
// This state fixture is from a hive testnet, `0a` is the suffix they are using in their fork versions.
suffix, err := hex.DecodeString("0a")
require.NoError(t, err)
require.Equal(t, 1, len(suffix))
reversioned := cfg.Copy()
params.FillTestVersions(reversioned, suffix[0])
reversioned.CapellaForkEpoch = 0
require.Equal(t, [4]byte{3, 0, 0, 10}, bytesutil.ToBytes4(reversioned.CapellaForkVersion))
reversioned.ConfigName = "capella-genesis-test"
undo, err := params.SetActiveWithUndo(reversioned)
require.NoError(t, err)
defer func() {
require.NoError(t, undo())
}()

fp := "testdata/capella_genesis.ssz"
rfp, err := bazel.Runfile(fp)
if err == nil {
fp = rfp
}
sb, err := os.ReadFile(fp)
require.NoError(t, err)

db := setupDB(t)
require.NoError(t, db.LoadGenesis(context.Background(), sb))
testGenesisDataSaved(t, db)
}

func TestLoadGenesisFromFile(t *testing.T) {
// for this test to work, we need the active config to have these properties:
// - fork version schedule that matches mainnnet.genesis.ssz
Expand All @@ -57,7 +90,7 @@ func TestLoadGenesisFromFile(t *testing.T) {
// uses the mainnet fork schedule. construct the differently named mainnet config and set it active.
// finally, revert all this at the end of the test.

// first get the real mainnet out of the way by overwriting it schedule.
// first get the real mainnet out of the way by overwriting its schedule.
cfg, err := params.ByName(params.MainnetName)
require.NoError(t, err)
cfg = cfg.Copy()
Expand Down
Binary file added beacon-chain/db/kv/testdata/capella_genesis.ssz
Binary file not shown.
8 changes: 2 additions & 6 deletions config/params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,22 +221,18 @@ func (b *BeaconChainConfig) InitializeForkSchedule() {

func configForkSchedule(b *BeaconChainConfig) map[[fieldparams.VersionLength]byte]types.Epoch {
fvs := map[[fieldparams.VersionLength]byte]types.Epoch{}
// Set Genesis fork data.
fvs[bytesutil.ToBytes4(b.GenesisForkVersion)] = b.GenesisEpoch
// Set Altair fork data.
fvs[bytesutil.ToBytes4(b.AltairForkVersion)] = b.AltairForkEpoch
// Set Bellatrix fork data.
fvs[bytesutil.ToBytes4(b.BellatrixForkVersion)] = b.BellatrixForkEpoch
fvs[bytesutil.ToBytes4(b.CapellaForkVersion)] = b.CapellaForkEpoch
return fvs
}

func configForkNames(b *BeaconChainConfig) map[[fieldparams.VersionLength]byte]string {
fvn := map[[fieldparams.VersionLength]byte]string{}
// Set Genesis fork data.
fvn[bytesutil.ToBytes4(b.GenesisForkVersion)] = "phase0"
// Set Altair fork data.
fvn[bytesutil.ToBytes4(b.AltairForkVersion)] = "altair"
// Set Bellatrix fork data.
fvn[bytesutil.ToBytes4(b.BellatrixForkVersion)] = "bellatrix"
fvn[bytesutil.ToBytes4(b.CapellaForkVersion)] = "capella"
return fvn
}
3 changes: 2 additions & 1 deletion config/params/interop.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ func InteropConfig() *BeaconChainConfig {
c.GenesisForkVersion = []byte{0, 0, 0, 235}
c.AltairForkVersion = []byte{1, 0, 0, 235}
c.BellatrixForkVersion = []byte{2, 0, 0, 235}
c.ShardingForkVersion = []byte{3, 0, 0, 235}
c.CapellaForkVersion = []byte{3, 0, 0, 235}
c.ShardingForkVersion = []byte{4, 0, 0, 235}

c.InitializeForkSchedule()
return c
Expand Down
1 change: 1 addition & 0 deletions config/params/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ func ConfigToYaml(cfg *BeaconChainConfig) []byte {
fmt.Sprintf("DEPOSIT_NETWORK_ID: %d", cfg.DepositNetworkID),
fmt.Sprintf("ALTAIR_FORK_EPOCH: %d", cfg.AltairForkEpoch),
fmt.Sprintf("ALTAIR_FORK_VERSION: %#x", cfg.AltairForkVersion),
fmt.Sprintf("CAPELLA_FORK_VERSION: %#x", cfg.CapellaForkVersion),
fmt.Sprintf("BELLATRIX_FORK_EPOCH: %d", cfg.BellatrixForkEpoch),
fmt.Sprintf("BELLATRIX_FORK_VERSION: %#x", cfg.BellatrixForkVersion),
fmt.Sprintf("SHARDING_FORK_EPOCH: %d", cfg.ShardingForkEpoch),
Expand Down
9 changes: 6 additions & 3 deletions config/params/mainnet_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,21 +273,24 @@ func MainnetTestConfig() *BeaconChainConfig {
return mn
}

// FillTestVersions replaces the byte in the last position of each fork version
// so that
// FillTestVersions replaces the fork schedule in the given BeaconChainConfig with test values, using the given
// byte argument as the high byte (common across forks).
func FillTestVersions(c *BeaconChainConfig, b byte) {
c.GenesisForkVersion = make([]byte, fieldparams.VersionLength)
c.AltairForkVersion = make([]byte, fieldparams.VersionLength)
c.BellatrixForkVersion = make([]byte, fieldparams.VersionLength)
c.CapellaForkVersion = make([]byte, fieldparams.VersionLength)
c.ShardingForkVersion = make([]byte, fieldparams.VersionLength)

c.GenesisForkVersion[fieldparams.VersionLength-1] = b
c.AltairForkVersion[fieldparams.VersionLength-1] = b
c.BellatrixForkVersion[fieldparams.VersionLength-1] = b
c.CapellaForkVersion[fieldparams.VersionLength-1] = b
c.ShardingForkVersion[fieldparams.VersionLength-1] = b

c.GenesisForkVersion[0] = 0
c.AltairForkVersion[0] = 1
c.BellatrixForkVersion[0] = 2
c.ShardingForkVersion[0] = 3
c.CapellaForkVersion[0] = 3
c.ShardingForkVersion[0] = 4
}
6 changes: 4 additions & 2 deletions config/params/testnet_e2e_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ func E2ETestConfig() *BeaconChainConfig {
e2eConfig.GenesisForkVersion = []byte{0, 0, 0, 253}
e2eConfig.AltairForkVersion = []byte{1, 0, 0, 253}
e2eConfig.BellatrixForkVersion = []byte{2, 0, 0, 253}
e2eConfig.ShardingForkVersion = []byte{3, 0, 0, 253}
e2eConfig.CapellaForkVersion = []byte{3, 0, 0, 253}
e2eConfig.ShardingForkVersion = []byte{4, 0, 0, 253}

e2eConfig.InitializeForkSchedule()
return e2eConfig
Expand Down Expand Up @@ -81,7 +82,8 @@ func E2EMainnetTestConfig() *BeaconChainConfig {
e2eConfig.GenesisForkVersion = []byte{0, 0, 0, 254}
e2eConfig.AltairForkVersion = []byte{1, 0, 0, 254}
e2eConfig.BellatrixForkVersion = []byte{2, 0, 0, 254}
e2eConfig.ShardingForkVersion = []byte{3, 0, 0, 254}
e2eConfig.CapellaForkVersion = []byte{3, 0, 0, 254}
e2eConfig.ShardingForkVersion = []byte{4, 0, 0, 254}

e2eConfig.InitializeForkSchedule()
return e2eConfig
Expand Down
1 change: 1 addition & 0 deletions config/params/testnet_ropsten_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func RopstenConfig() *BeaconChainConfig {
cfg.AltairForkVersion = []byte{0x80, 0x00, 0x00, 0x70}
cfg.BellatrixForkEpoch = 750
cfg.BellatrixForkVersion = []byte{0x80, 0x00, 0x00, 0x71}
cfg.CapellaForkVersion = []byte{0x80, 0x00, 0x00, 0x72}
cfg.TerminalTotalDifficulty = "50000000000000000"
cfg.DepositContractAddress = "0x6f22fFbC56eFF051aECF839396DD1eD9aD6BBA9D"
cfg.InitializeForkSchedule()
Expand Down
2 changes: 2 additions & 0 deletions encoding/ssz/detect/configfork.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ func FromForkVersion(cv [fieldparams.VersionLength]byte) (*VersionedUnmarshaler,
fork = version.Altair
case bytesutil.ToBytes4(cfg.BellatrixForkVersion):
fork = version.Bellatrix
case bytesutil.ToBytes4(cfg.CapellaForkVersion):
fork = version.Capella
default:
return nil, errors.Wrapf(ErrForkNotFound, "version=%#x", cv)
}
Expand Down
22 changes: 14 additions & 8 deletions encoding/ssz/detect/configfork_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func TestSlotFromBlock(t *testing.T) {
}

func TestByState(t *testing.T) {
undo, err := hackBellatrixMaxuint()
undo, err := hackCapellaMaxuint()
require.NoError(t, err)
defer func() {
require.NoError(t, undo())
Expand All @@ -58,6 +58,8 @@ func TestByState(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)
cases := []struct {
name string
version int
Expand All @@ -82,6 +84,12 @@ func TestByState(t *testing.T) {
slot: bellaSlot,
forkversion: bytesutil.ToBytes4(bc.BellatrixForkVersion),
},
{
name: "capella",
version: version.Capella,
slot: capellaSlot,
forkversion: bytesutil.ToBytes4(bc.CapellaForkVersion),
},
}
for _, c := range cases {
st, err := stateForVersion(c.version)
Expand Down Expand Up @@ -119,7 +127,7 @@ func stateForVersion(v int) (state.BeaconState, error) {

func TestUnmarshalState(t *testing.T) {
ctx := context.Background()
undo, err := hackBellatrixMaxuint()
undo, err := hackCapellaMaxuint()
require.NoError(t, err)
defer func() {
require.NoError(t, undo())
Expand Down Expand Up @@ -176,24 +184,23 @@ func TestUnmarshalState(t *testing.T) {
}
}

func hackBellatrixMaxuint() (func() error, error) {
func hackCapellaMaxuint() (func() error, error) {
// 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.
bc := params.MainnetConfig().Copy()
bc.BellatrixForkEpoch = math.MaxUint32
bc.CapellaForkEpoch = math.MaxUint32
undo, err := params.SetActiveWithUndo(bc)
return undo, err
}

func TestUnmarshalBlock(t *testing.T) {
undo, err := hackBellatrixMaxuint()
undo, err := hackCapellaMaxuint()
require.NoError(t, err)
defer func() {
require.NoError(t, undo())
}()
require.Equal(t, types.Epoch(math.MaxUint32), params.BeaconConfig().BellatrixForkEpoch)
genv := bytesutil.ToBytes4(params.BeaconConfig().GenesisForkVersion)
altairv := bytesutil.ToBytes4(params.BeaconConfig().AltairForkVersion)
bellav := bytesutil.ToBytes4(params.BeaconConfig().BellatrixForkVersion)
Expand Down Expand Up @@ -280,12 +287,11 @@ func TestUnmarshalBlock(t *testing.T) {
}

func TestUnmarshalBlindedBlock(t *testing.T) {
undo, err := hackBellatrixMaxuint()
undo, err := hackCapellaMaxuint()
require.NoError(t, err)
defer func() {
require.NoError(t, undo())
}()
require.Equal(t, types.Epoch(math.MaxUint32), params.BeaconConfig().BellatrixForkEpoch)
genv := bytesutil.ToBytes4(params.BeaconConfig().GenesisForkVersion)
altairv := bytesutil.ToBytes4(params.BeaconConfig().AltairForkVersion)
bellav := bytesutil.ToBytes4(params.BeaconConfig().BellatrixForkVersion)
Expand Down