diff --git a/beacon-chain/core/blocks/genesis.go b/beacon-chain/core/blocks/genesis.go index 42d5e72d6..d5fb1ff65 100644 --- a/beacon-chain/core/blocks/genesis.go +++ b/beacon-chain/core/blocks/genesis.go @@ -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) @@ -113,6 +113,38 @@ func NewGenesisBlockForState(ctx context.Context, st state.BeaconState) (interfa }, Signature: params.BeaconConfig().EmptySignature[:], }) + case *ethpb.BeaconStateCapella: + return blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockCapella{ + Block: ðpb.BeaconBlockCapella{ + ParentRoot: params.BeaconConfig().ZeroHash[:], + StateRoot: root[:], + Body: ðpb.BeaconBlockBodyCapella{ + RandaoReveal: make([]byte, 96), + Eth1Data: ðpb.Eth1Data{ + DepositRoot: make([]byte, 32), + BlockHash: make([]byte, 32), + }, + Graffiti: make([]byte, 32), + SyncAggregate: ðpb.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 } diff --git a/beacon-chain/db/kv/genesis_test.go b/beacon-chain/db/kv/genesis_test.go index e954166a7..abf7fae95 100644 --- a/beacon-chain/db/kv/genesis_test.go +++ b/beacon-chain/db/kv/genesis_test.go @@ -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" @@ -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 @@ -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() diff --git a/beacon-chain/db/kv/testdata/capella_genesis.ssz b/beacon-chain/db/kv/testdata/capella_genesis.ssz new file mode 100644 index 000000000..8637d910f Binary files /dev/null and b/beacon-chain/db/kv/testdata/capella_genesis.ssz differ diff --git a/beacon-chain/rpc/eth/beacon/BUILD.bazel b/beacon-chain/rpc/eth/beacon/BUILD.bazel index 869291189..2acb8bcde 100644 --- a/beacon-chain/rpc/eth/beacon/BUILD.bazel +++ b/beacon-chain/rpc/eth/beacon/BUILD.bazel @@ -115,6 +115,7 @@ go_test( "//crypto/hash:go_default_library", "//encoding/bytesutil:go_default_library", "//encoding/ssz:go_default_library", + "//network/forks:go_default_library", "//proto/engine/v1:go_default_library", "//proto/eth/service:go_default_library", "//proto/eth/v1:go_default_library", diff --git a/beacon-chain/rpc/eth/beacon/config_test.go b/beacon-chain/rpc/eth/beacon/config_test.go index 23651569d..edc309172 100644 --- a/beacon-chain/rpc/eth/beacon/config_test.go +++ b/beacon-chain/rpc/eth/beacon/config_test.go @@ -9,6 +9,7 @@ import ( "github.com/prysmaticlabs/prysm/v3/config/params" types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v3/encoding/bytesutil" + "github.com/prysmaticlabs/prysm/v3/network/forks" "github.com/prysmaticlabs/prysm/v3/testing/assert" "github.com/prysmaticlabs/prysm/v3/testing/require" "google.golang.org/protobuf/types/known/emptypb" @@ -425,6 +426,6 @@ func TestForkSchedule_CorrectNumberOfForks(t *testing.T) { s := &Server{} resp, err := s.GetForkSchedule(context.Background(), &emptypb.Empty{}) require.NoError(t, err) - // Genesis and Altair. - assert.Equal(t, 3, len(resp.Data)) + os := forks.NewOrderedSchedule(params.BeaconConfig()) + assert.Equal(t, os.Len(), len(resp.Data)) } diff --git a/config/params/config.go b/config/params/config.go index 153e74a6a..7df9e7e26 100644 --- a/config/params/config.go +++ b/config/params/config.go @@ -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 } diff --git a/config/params/interop.go b/config/params/interop.go index 90a9378d8..e3f49e307 100644 --- a/config/params/interop.go +++ b/config/params/interop.go @@ -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 diff --git a/config/params/loader.go b/config/params/loader.go index 5df155701..b75180db8 100644 --- a/config/params/loader.go +++ b/config/params/loader.go @@ -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), diff --git a/config/params/loader_test.go b/config/params/loader_test.go index 941eebfcc..76d0eb42d 100644 --- a/config/params/loader_test.go +++ b/config/params/loader_test.go @@ -107,13 +107,15 @@ func assertEqualConfigs(t *testing.T, name string, fields []string, expected, ac assert.Equal(t, expected.DomainVoluntaryExit, actual.DomainVoluntaryExit, "%s: DomainVoluntaryExit", name) assert.Equal(t, expected.DomainSelectionProof, actual.DomainSelectionProof, "%s: DomainSelectionProof", name) assert.Equal(t, expected.DomainAggregateAndProof, actual.DomainAggregateAndProof, "%s: DomainAggregateAndProof", name) - assert.Equal(t, expected.TerminalTotalDifficulty, actual.TerminalTotalDifficulty, "%s: DomainAggregateAndProof", name) - assert.Equal(t, expected.AltairForkEpoch, actual.AltairForkEpoch, "%s: DomainAggregateAndProof", name) - assert.Equal(t, expected.BellatrixForkEpoch, actual.BellatrixForkEpoch, "%s: DomainAggregateAndProof", name) - assert.Equal(t, expected.SqrRootSlotsPerEpoch, actual.SqrRootSlotsPerEpoch, "%s: DomainAggregateAndProof", name) - assert.DeepEqual(t, expected.GenesisForkVersion, actual.GenesisForkVersion, "%s: DomainAggregateAndProof", name) - assert.DeepEqual(t, expected.AltairForkVersion, actual.AltairForkVersion, "%s: DomainAggregateAndProof", name) - assert.DeepEqual(t, expected.BellatrixForkVersion, actual.BellatrixForkVersion, "%s: DomainAggregateAndProof", name) + assert.Equal(t, expected.TerminalTotalDifficulty, actual.TerminalTotalDifficulty, "%s: TerminalTotalDifficulty", name) + assert.Equal(t, expected.AltairForkEpoch, actual.AltairForkEpoch, "%s: AltairForkEpoch", name) + assert.Equal(t, expected.BellatrixForkEpoch, actual.BellatrixForkEpoch, "%s: BellatrixForkEpoch", name) + assert.Equal(t, expected.CapellaForkEpoch, actual.CapellaForkEpoch, "%s: CapellaForkEpoch", name) + assert.Equal(t, expected.SqrRootSlotsPerEpoch, actual.SqrRootSlotsPerEpoch, "%s: SqrRootSlotsPerEpoch", name) + assert.DeepEqual(t, expected.GenesisForkVersion, actual.GenesisForkVersion, "%s: GenesisForkVersion", name) + assert.DeepEqual(t, expected.AltairForkVersion, actual.AltairForkVersion, "%s: AltairForkVersion", name) + assert.DeepEqual(t, expected.BellatrixForkVersion, actual.BellatrixForkVersion, "%s: BellatrixForkVersion", name) + assert.DeepEqual(t, expected.CapellaForkVersion, actual.CapellaForkVersion, "%s: CapellaForkVersion", name) assertYamlFieldsMatch(t, name, fields, expected, actual) } diff --git a/config/params/mainnet_config.go b/config/params/mainnet_config.go index 3eefff814..e85f846ea 100644 --- a/config/params/mainnet_config.go +++ b/config/params/mainnet_config.go @@ -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 } diff --git a/config/params/testdata/e2e_config.yaml b/config/params/testdata/e2e_config.yaml index 6bd26fe53..36c5c72a2 100644 --- a/config/params/testdata/e2e_config.yaml +++ b/config/params/testdata/e2e_config.yaml @@ -38,8 +38,11 @@ ALTAIR_FORK_EPOCH: 6 # Override for e2e # Bellatrix BELLATRIX_FORK_VERSION: 0x020000fd BELLATRIX_FORK_EPOCH: 8 +# Capella +CAPELLA_FORK_VERSION: 0x030000fd +CAPELLA_FORK_EPOCH: 18446744073709551615 # Sharding -SHARDING_FORK_VERSION: 0x030000fd +SHARDING_FORK_VERSION: 0x040000fd SHARDING_FORK_EPOCH: 18446744073709551615 diff --git a/config/params/testnet_e2e_config.go b/config/params/testnet_e2e_config.go index f46276b37..d8d3d50bd 100644 --- a/config/params/testnet_e2e_config.go +++ b/config/params/testnet_e2e_config.go @@ -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 @@ -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 diff --git a/config/params/testnet_ropsten_config.go b/config/params/testnet_ropsten_config.go index 38d7b2f6f..f897c8995 100644 --- a/config/params/testnet_ropsten_config.go +++ b/config/params/testnet_ropsten_config.go @@ -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() diff --git a/encoding/ssz/detect/configfork.go b/encoding/ssz/detect/configfork.go index ab2a5c0ed..7f907e4e3 100644 --- a/encoding/ssz/detect/configfork.go +++ b/encoding/ssz/detect/configfork.go @@ -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) } diff --git a/encoding/ssz/detect/configfork_test.go b/encoding/ssz/detect/configfork_test.go index 4d5b6774e..02e13f128 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 := hackBellatrixMaxuint() + undo, err := hackCapellaMaxuint() require.NoError(t, err) defer func() { require.NoError(t, undo()) @@ -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 @@ -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) @@ -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()) @@ -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) @@ -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)