diff --git a/beacon-chain/core/transition/BUILD.bazel b/beacon-chain/core/transition/BUILD.bazel index 458b73191..347d857dc 100644 --- a/beacon-chain/core/transition/BUILD.bazel +++ b/beacon-chain/core/transition/BUILD.bazel @@ -43,6 +43,7 @@ go_library( "//consensus-types/blocks:go_default_library", "//consensus-types/interfaces:go_default_library", "//consensus-types/primitives:go_default_library", + "//container/trie:go_default_library", "//crypto/bls:go_default_library", "//crypto/hash:go_default_library", "//encoding/bytesutil:go_default_library", diff --git a/beacon-chain/core/transition/state.go b/beacon-chain/core/transition/state.go index 7ebdb3b03..d24a62b60 100644 --- a/beacon-chain/core/transition/state.go +++ b/beacon-chain/core/transition/state.go @@ -10,6 +10,7 @@ import ( state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native" "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stateutil" "github.com/prysmaticlabs/prysm/v3/config/params" + "github.com/prysmaticlabs/prysm/v3/container/trie" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" ) @@ -75,6 +76,43 @@ func GenesisBeaconState(ctx context.Context, deposits []*ethpb.Deposit, genesisT return OptimizedGenesisBeaconState(genesisTime, st, st.Eth1Data()) } +// PreminedGenesisBeaconState works almost exactly like GenesisBeaconState, except that it assumes that genesis deposits +// are not represented in the deposit contract and are only found in the genesis state validator registry. In order +// to ensure the deposit root and count match the empty deposit contract deployed in a testnet genesis block, the root +// of an empty deposit trie is computed and used as Eth1Data.deposit_root, and the deposit count is set to 0. +func PreminedGenesisBeaconState(ctx context.Context, deposits []*ethpb.Deposit, genesisTime uint64, eth1Data *ethpb.Eth1Data) (state.BeaconState, error) { + st, err := EmptyGenesisState() + if err != nil { + return nil, err + } + + // Process initial deposits. + st, err = helpers.UpdateGenesisEth1Data(st, deposits, eth1Data) + if err != nil { + return nil, err + } + st, err = b.ProcessPreGenesisDeposits(ctx, st, deposits) + if err != nil { + return nil, errors.Wrap(err, "could not process validator deposits") + } + + t, err := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth) + if err != nil { + return nil, err + } + dr, err := t.HashTreeRoot() + if err != nil { + return nil, err + } + if err := st.SetEth1Data(ðpb.Eth1Data{DepositRoot: dr[:], BlockHash: eth1Data.BlockHash}); err != nil { + return nil, err + } + if err := st.SetEth1DepositIndex(0); err != nil { + return nil, err + } + return OptimizedGenesisBeaconState(genesisTime, st, st.Eth1Data()) +} + // OptimizedGenesisBeaconState is used to create a state that has already processed deposits. This is to efficiently // create a mainnet state at chainstart. func OptimizedGenesisBeaconState(genesisTime uint64, preState state.BeaconState, eth1Data *ethpb.Eth1Data) (state.BeaconState, error) { diff --git a/beacon-chain/execution/service.go b/beacon-chain/execution/service.go index 06fa05cb0..70a61be79 100644 --- a/beacon-chain/execution/service.go +++ b/beacon-chain/execution/service.go @@ -718,6 +718,9 @@ func (s *Service) determineEarliestVotingBlock(ctx context.Context, followBlock return 0, errors.Errorf("invalid genesis time provided. %d > %d", followBackDist, votingTime) } earliestValidTime := votingTime - followBackDist + if earliestValidTime < genesisTime { + return 0, nil + } hdr, err := s.BlockByTimestamp(ctx, earliestValidTime) if err != nil { return 0, err diff --git a/beacon-chain/execution/testing/genesis.go b/beacon-chain/execution/testing/genesis.go index dc52eb2c3..ff350f6ae 100644 --- a/beacon-chain/execution/testing/genesis.go +++ b/beacon-chain/execution/testing/genesis.go @@ -1,6 +1,7 @@ package testing import ( + "fmt" "math" "math/big" @@ -16,7 +17,7 @@ import ( const defaultMinerAddress = "0x878705ba3f8bc32fcf7f4caa1a35e72af65cf766" const defaultTestChainId int64 = 1337 const defaultCoinbase = "0x0000000000000000000000000000000000000000" -const defaultDifficulty = "0x20000" +const defaultDifficulty = "1" const defaultMixhash = "0x0000000000000000000000000000000000000000000000000000000000000000" const defaultParenthash = "0x0000000000000000000000000000000000000000000000000000000000000000" const defaultMinerBalance = "100000000000000000000000000000" @@ -78,6 +79,10 @@ const DefaultCliqueSigner = "0x0000000000000000000000000000000000000000000000000 // like in an e2e test. The parameters are minimal but the full value is returned unmarshaled so that it can be // customized as desired. func GethTestnetGenesis(genesisTime uint64, cfg *clparams.BeaconChainConfig) core.Genesis { + ttd, ok := big.NewInt(0).SetString(clparams.BeaconConfig().TerminalTotalDifficulty, 10) + if !ok { + panic(fmt.Sprintf("unable to parse TerminalTotalDifficulty as an integer = %s", clparams.BeaconConfig().TerminalTotalDifficulty)) + } cc := ¶ms.ChainConfig{ ChainID: big.NewInt(defaultTestChainId), HomesteadBlock: bigz, @@ -95,16 +100,24 @@ func GethTestnetGenesis(genesisTime uint64, cfg *clparams.BeaconChainConfig) cor ArrowGlacierBlock: bigz, GrayGlacierBlock: bigz, MergeNetsplitBlock: bigz, - TerminalTotalDifficulty: bigz, + TerminalTotalDifficulty: ttd, TerminalTotalDifficultyPassed: false, + Clique: ¶ms.CliqueConfig{ + Period: cfg.SecondsPerETH1Block, + Epoch: 20000, + }, } da := defaultDepositContractAllocation(cfg.DepositContractAddress) ma := minerAllocation() + extra, err := hexutil.Decode(DefaultCliqueSigner) + if err != nil { + panic(fmt.Sprintf("unable to decode DefaultCliqueSigner, with error %v", err.Error())) + } return core.Genesis{ Config: cc, Nonce: 0, // overridden for authorized signer votes in clique, so we should leave it empty? Timestamp: genesisTime, - ExtraData: []byte(DefaultCliqueSigner), + ExtraData: extra, GasLimit: math.MaxUint64 >> 1, // shift 1 back from the max, just in case Difficulty: common.HexToHash(defaultDifficulty).Big(), Mixhash: common.HexToHash(defaultMixhash), diff --git a/cmd/config.go b/cmd/config.go index 0e2ba87e2..afd3372ec 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -10,7 +10,6 @@ import ( type Flags struct { // Configuration related flags. MinimalConfig bool // MinimalConfig as defined in the spec. - E2EConfig bool // E2EConfig made specifically for testing, do not use except in E2E. MaxRPCPageSize int // MaxRPCPageSize is used for a cap of page sizes in RPC requests. } diff --git a/config/params/loader.go b/config/params/loader.go index bd4e7cf4c..5df155701 100644 --- a/config/params/loader.go +++ b/config/params/loader.go @@ -25,11 +25,7 @@ func isMinimal(lines []string) bool { return false } -func UnmarshalConfigFile(path string, conf *BeaconChainConfig) (*BeaconChainConfig, error) { - yamlFile, err := os.ReadFile(path) // #nosec G304 - if err != nil { - return nil, errors.Wrap(err, "Failed to read chain config file.") - } +func UnmarshalConfig(yamlFile []byte, conf *BeaconChainConfig) (*BeaconChainConfig, error) { // To track if config name is defined inside config file. hasConfigName := false // Convert 0x hex inputs to fixed bytes arrays @@ -72,6 +68,14 @@ func UnmarshalConfigFile(path string, conf *BeaconChainConfig) (*BeaconChainConf return conf, nil } +func UnmarshalConfigFile(path string, conf *BeaconChainConfig) (*BeaconChainConfig, error) { + yamlFile, err := os.ReadFile(path) // #nosec G304 + if err != nil { + return nil, errors.Wrap(err, "Failed to read chain config file.") + } + return UnmarshalConfig(yamlFile, conf) +} + // LoadChainConfigFile load, convert hex values into valid param yaml format, // unmarshal , and apply beacon chain config file. func LoadChainConfigFile(path string, conf *BeaconChainConfig) error { @@ -201,6 +205,7 @@ func ConfigToYaml(cfg *BeaconChainConfig) []byte { fmt.Sprintf("TERMINAL_TOTAL_DIFFICULTY: %s", cfg.TerminalTotalDifficulty), fmt.Sprintf("TERMINAL_BLOCK_HASH: %#x", cfg.TerminalBlockHash), fmt.Sprintf("TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: %d", cfg.TerminalBlockHashActivationEpoch), + fmt.Sprintf("DEPOSIT_CONTRACT_ADDRESS: %s", cfg.DepositContractAddress), } yamlFile := []byte(strings.Join(lines, "\n")) diff --git a/config/params/loader_test.go b/config/params/loader_test.go index 4ceb25659..941eebfcc 100644 --- a/config/params/loader_test.go +++ b/config/params/loader_test.go @@ -22,99 +22,115 @@ import ( // These are variables that we don't use in Prysm. (i.e. future hardfork, light client... etc) var placeholderFields = []string{"UPDATE_TIMEOUT", "EIP4844_FORK_EPOCH", "EIP4844_FORK_VERSION"} +func assertEqualConfigs(t *testing.T, name string, fields []string, expected, actual *params.BeaconChainConfig) { + // Misc params. + assert.Equal(t, expected.MaxCommitteesPerSlot, actual.MaxCommitteesPerSlot, "%s: MaxCommitteesPerSlot", name) + assert.Equal(t, expected.TargetCommitteeSize, actual.TargetCommitteeSize, "%s: TargetCommitteeSize", name) + assert.Equal(t, expected.MaxValidatorsPerCommittee, actual.MaxValidatorsPerCommittee, "%s: MaxValidatorsPerCommittee", name) + assert.Equal(t, expected.MinPerEpochChurnLimit, actual.MinPerEpochChurnLimit, "%s: MinPerEpochChurnLimit", name) + assert.Equal(t, expected.ChurnLimitQuotient, actual.ChurnLimitQuotient, "%s: ChurnLimitQuotient", name) + assert.Equal(t, expected.ShuffleRoundCount, actual.ShuffleRoundCount, "%s: ShuffleRoundCount", name) + assert.Equal(t, expected.MinGenesisActiveValidatorCount, actual.MinGenesisActiveValidatorCount, "%s: MinGenesisActiveValidatorCount", name) + assert.Equal(t, expected.MinGenesisTime, actual.MinGenesisTime, "%s: MinGenesisTime", name) + assert.Equal(t, expected.HysteresisQuotient, actual.HysteresisQuotient, "%s: HysteresisQuotient", name) + assert.Equal(t, expected.HysteresisDownwardMultiplier, actual.HysteresisDownwardMultiplier, "%s: HysteresisDownwardMultiplier", name) + assert.Equal(t, expected.HysteresisUpwardMultiplier, actual.HysteresisUpwardMultiplier, "%s: HysteresisUpwardMultiplier", name) + + // Fork Choice params. + assert.Equal(t, expected.SafeSlotsToUpdateJustified, actual.SafeSlotsToUpdateJustified, "%s: SafeSlotsToUpdateJustified", name) + + // Validator params. + assert.Equal(t, expected.Eth1FollowDistance, actual.Eth1FollowDistance, "%s: Eth1FollowDistance", name) + assert.Equal(t, expected.TargetAggregatorsPerCommittee, actual.TargetAggregatorsPerCommittee, "%s: TargetAggregatorsPerCommittee", name) + assert.Equal(t, expected.RandomSubnetsPerValidator, actual.RandomSubnetsPerValidator, "%s: RandomSubnetsPerValidator", name) + assert.Equal(t, expected.EpochsPerRandomSubnetSubscription, actual.EpochsPerRandomSubnetSubscription, "%s: EpochsPerRandomSubnetSubscription", name) + assert.Equal(t, expected.SecondsPerETH1Block, actual.SecondsPerETH1Block, "%s: SecondsPerETH1Block", name) + + // Deposit contract. + assert.Equal(t, expected.DepositChainID, actual.DepositChainID, "%s: DepositChainID", name) + assert.Equal(t, expected.DepositNetworkID, actual.DepositNetworkID, "%s: DepositNetworkID", name) + assert.Equal(t, expected.DepositContractAddress, actual.DepositContractAddress, "%s: DepositContractAddress", name) + + // Gwei values. + assert.Equal(t, expected.MinDepositAmount, actual.MinDepositAmount, "%s: MinDepositAmount", name) + assert.Equal(t, expected.MaxEffectiveBalance, actual.MaxEffectiveBalance, "%s: MaxEffectiveBalance", name) + assert.Equal(t, expected.EjectionBalance, actual.EjectionBalance, "%s: EjectionBalance", name) + assert.Equal(t, expected.EffectiveBalanceIncrement, actual.EffectiveBalanceIncrement, "%s: EffectiveBalanceIncrement", name) + + // Initial values. + assert.DeepEqual(t, expected.GenesisForkVersion, actual.GenesisForkVersion, "%s: GenesisForkVersion", name) + assert.DeepEqual(t, expected.BLSWithdrawalPrefixByte, actual.BLSWithdrawalPrefixByte, "%s: BLSWithdrawalPrefixByte", name) + assert.DeepEqual(t, expected.ETH1AddressWithdrawalPrefixByte, actual.ETH1AddressWithdrawalPrefixByte, "%s: ETH1AddressWithdrawalPrefixByte", name) + + // Time parameters. + assert.Equal(t, expected.GenesisDelay, actual.GenesisDelay, "%s: GenesisDelay", name) + assert.Equal(t, expected.SecondsPerSlot, actual.SecondsPerSlot, "%s: SecondsPerSlot", name) + assert.Equal(t, expected.MinAttestationInclusionDelay, actual.MinAttestationInclusionDelay, "%s: MinAttestationInclusionDelay", name) + assert.Equal(t, expected.SlotsPerEpoch, actual.SlotsPerEpoch, "%s: SlotsPerEpoch", name) + assert.Equal(t, expected.MinSeedLookahead, actual.MinSeedLookahead, "%s: MinSeedLookahead", name) + assert.Equal(t, expected.MaxSeedLookahead, actual.MaxSeedLookahead, "%s: MaxSeedLookahead", name) + assert.Equal(t, expected.EpochsPerEth1VotingPeriod, actual.EpochsPerEth1VotingPeriod, "%s: EpochsPerEth1VotingPeriod", name) + assert.Equal(t, expected.SlotsPerHistoricalRoot, actual.SlotsPerHistoricalRoot, "%s: SlotsPerHistoricalRoot", name) + assert.Equal(t, expected.MinValidatorWithdrawabilityDelay, actual.MinValidatorWithdrawabilityDelay, "%s: MinValidatorWithdrawabilityDelay", name) + assert.Equal(t, expected.ShardCommitteePeriod, actual.ShardCommitteePeriod, "%s: ShardCommitteePeriod", name) + assert.Equal(t, expected.MinEpochsToInactivityPenalty, actual.MinEpochsToInactivityPenalty, "%s: MinEpochsToInactivityPenalty", name) + + // State vector lengths. + assert.Equal(t, expected.EpochsPerHistoricalVector, actual.EpochsPerHistoricalVector, "%s: EpochsPerHistoricalVector", name) + assert.Equal(t, expected.EpochsPerSlashingsVector, actual.EpochsPerSlashingsVector, "%s: EpochsPerSlashingsVector", name) + assert.Equal(t, expected.HistoricalRootsLimit, actual.HistoricalRootsLimit, "%s: HistoricalRootsLimit", name) + assert.Equal(t, expected.ValidatorRegistryLimit, actual.ValidatorRegistryLimit, "%s: ValidatorRegistryLimit", name) + + // Reward and penalty quotients. + assert.Equal(t, expected.BaseRewardFactor, actual.BaseRewardFactor, "%s: BaseRewardFactor", name) + assert.Equal(t, expected.WhistleBlowerRewardQuotient, actual.WhistleBlowerRewardQuotient, "%s: WhistleBlowerRewardQuotient", name) + assert.Equal(t, expected.ProposerRewardQuotient, actual.ProposerRewardQuotient, "%s: ProposerRewardQuotient", name) + assert.Equal(t, expected.InactivityPenaltyQuotient, actual.InactivityPenaltyQuotient, "%s: InactivityPenaltyQuotient", name) + assert.Equal(t, expected.InactivityPenaltyQuotientAltair, actual.InactivityPenaltyQuotientAltair, "%s: InactivityPenaltyQuotientAltair", name) + assert.Equal(t, expected.MinSlashingPenaltyQuotient, actual.MinSlashingPenaltyQuotient, "%s: MinSlashingPenaltyQuotient", name) + assert.Equal(t, expected.MinSlashingPenaltyQuotientAltair, actual.MinSlashingPenaltyQuotientAltair, "%s: MinSlashingPenaltyQuotientAltair", name) + assert.Equal(t, expected.ProportionalSlashingMultiplier, actual.ProportionalSlashingMultiplier, "%s: ProportionalSlashingMultiplier", name) + assert.Equal(t, expected.ProportionalSlashingMultiplierAltair, actual.ProportionalSlashingMultiplierAltair, "%s: ProportionalSlashingMultiplierAltair", name) + + // Max operations per block. + assert.Equal(t, expected.MaxProposerSlashings, actual.MaxProposerSlashings, "%s: MaxProposerSlashings", name) + assert.Equal(t, expected.MaxAttesterSlashings, actual.MaxAttesterSlashings, "%s: MaxAttesterSlashings", name) + assert.Equal(t, expected.MaxAttestations, actual.MaxAttestations, "%s: MaxAttestations", name) + assert.Equal(t, expected.MaxDeposits, actual.MaxDeposits, "%s: MaxDeposits", name) + assert.Equal(t, expected.MaxVoluntaryExits, actual.MaxVoluntaryExits, "%s: MaxVoluntaryExits", name) + + // Signature domains. + assert.Equal(t, expected.DomainBeaconProposer, actual.DomainBeaconProposer, "%s: DomainBeaconProposer", name) + assert.Equal(t, expected.DomainBeaconAttester, actual.DomainBeaconAttester, "%s: DomainBeaconAttester", name) + assert.Equal(t, expected.DomainRandao, actual.DomainRandao, "%s: DomainRandao", name) + assert.Equal(t, expected.DomainDeposit, actual.DomainDeposit, "%s: DomainDeposit", name) + 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) + + assertYamlFieldsMatch(t, name, fields, expected, actual) +} + +func TestModifiedE2E(t *testing.T) { + c := params.E2ETestConfig().Copy() + c.DepositContractAddress = "0x4242424242424242424242424242424242424242" + c.TerminalTotalDifficulty = "0" + c.AltairForkEpoch = 0 + c.BellatrixForkEpoch = 0 + y := params.ConfigToYaml(c) + cfg, err := params.UnmarshalConfig(y, nil) + require.NoError(t, err) + assertEqualConfigs(t, "modified-e2e", []string{}, c, cfg) +} + func TestLoadConfigFile(t *testing.T) { - // TODO(11750) - t.Skip("needs https://github.com/prysmaticlabs/prysm/issues/11750") - // See https://media.githubusercontent.com/media/ethereum/consensus-spec-tests/master/tests/minimal/config/phase0.yaml - assertVals := func(name string, fields []string, expected, actual *params.BeaconChainConfig) { - // Misc params. - assert.Equal(t, expected.MaxCommitteesPerSlot, actual.MaxCommitteesPerSlot, "%s: MaxCommitteesPerSlot", name) - assert.Equal(t, expected.TargetCommitteeSize, actual.TargetCommitteeSize, "%s: TargetCommitteeSize", name) - assert.Equal(t, expected.MaxValidatorsPerCommittee, actual.MaxValidatorsPerCommittee, "%s: MaxValidatorsPerCommittee", name) - assert.Equal(t, expected.MinPerEpochChurnLimit, actual.MinPerEpochChurnLimit, "%s: MinPerEpochChurnLimit", name) - assert.Equal(t, expected.ChurnLimitQuotient, actual.ChurnLimitQuotient, "%s: ChurnLimitQuotient", name) - assert.Equal(t, expected.ShuffleRoundCount, actual.ShuffleRoundCount, "%s: ShuffleRoundCount", name) - assert.Equal(t, expected.MinGenesisActiveValidatorCount, actual.MinGenesisActiveValidatorCount, "%s: MinGenesisActiveValidatorCount", name) - assert.Equal(t, expected.MinGenesisTime, actual.MinGenesisTime, "%s: MinGenesisTime", name) - assert.Equal(t, expected.HysteresisQuotient, actual.HysteresisQuotient, "%s: HysteresisQuotient", name) - assert.Equal(t, expected.HysteresisDownwardMultiplier, actual.HysteresisDownwardMultiplier, "%s: HysteresisDownwardMultiplier", name) - assert.Equal(t, expected.HysteresisUpwardMultiplier, actual.HysteresisUpwardMultiplier, "%s: HysteresisUpwardMultiplier", name) - - // Fork Choice params. - assert.Equal(t, expected.SafeSlotsToUpdateJustified, actual.SafeSlotsToUpdateJustified, "%s: SafeSlotsToUpdateJustified", name) - - // Validator params. - assert.Equal(t, expected.Eth1FollowDistance, actual.Eth1FollowDistance, "%s: Eth1FollowDistance", name) - assert.Equal(t, expected.TargetAggregatorsPerCommittee, actual.TargetAggregatorsPerCommittee, "%s: TargetAggregatorsPerCommittee", name) - assert.Equal(t, expected.RandomSubnetsPerValidator, actual.RandomSubnetsPerValidator, "%s: RandomSubnetsPerValidator", name) - assert.Equal(t, expected.EpochsPerRandomSubnetSubscription, actual.EpochsPerRandomSubnetSubscription, "%s: EpochsPerRandomSubnetSubscription", name) - assert.Equal(t, expected.SecondsPerETH1Block, actual.SecondsPerETH1Block, "%s: SecondsPerETH1Block", name) - - // Deposit contract. - assert.Equal(t, expected.DepositChainID, actual.DepositChainID, "%s: DepositChainID", name) - assert.Equal(t, expected.DepositNetworkID, actual.DepositNetworkID, "%s: DepositNetworkID", name) - assert.Equal(t, expected.DepositContractAddress, actual.DepositContractAddress, "%s: DepositContractAddress", name) - - // Gwei values. - assert.Equal(t, expected.MinDepositAmount, actual.MinDepositAmount, "%s: MinDepositAmount", name) - assert.Equal(t, expected.MaxEffectiveBalance, actual.MaxEffectiveBalance, "%s: MaxEffectiveBalance", name) - assert.Equal(t, expected.EjectionBalance, actual.EjectionBalance, "%s: EjectionBalance", name) - assert.Equal(t, expected.EffectiveBalanceIncrement, actual.EffectiveBalanceIncrement, "%s: EffectiveBalanceIncrement", name) - - // Initial values. - assert.DeepEqual(t, expected.GenesisForkVersion, actual.GenesisForkVersion, "%s: GenesisForkVersion", name) - assert.DeepEqual(t, expected.BLSWithdrawalPrefixByte, actual.BLSWithdrawalPrefixByte, "%s: BLSWithdrawalPrefixByte", name) - assert.DeepEqual(t, expected.ETH1AddressWithdrawalPrefixByte, actual.ETH1AddressWithdrawalPrefixByte, "%s: ETH1AddressWithdrawalPrefixByte", name) - - // Time parameters. - assert.Equal(t, expected.GenesisDelay, actual.GenesisDelay, "%s: GenesisDelay", name) - assert.Equal(t, expected.SecondsPerSlot, actual.SecondsPerSlot, "%s: SecondsPerSlot", name) - assert.Equal(t, expected.MinAttestationInclusionDelay, actual.MinAttestationInclusionDelay, "%s: MinAttestationInclusionDelay", name) - assert.Equal(t, expected.SlotsPerEpoch, actual.SlotsPerEpoch, "%s: SlotsPerEpoch", name) - assert.Equal(t, expected.MinSeedLookahead, actual.MinSeedLookahead, "%s: MinSeedLookahead", name) - assert.Equal(t, expected.MaxSeedLookahead, actual.MaxSeedLookahead, "%s: MaxSeedLookahead", name) - assert.Equal(t, expected.EpochsPerEth1VotingPeriod, actual.EpochsPerEth1VotingPeriod, "%s: EpochsPerEth1VotingPeriod", name) - assert.Equal(t, expected.SlotsPerHistoricalRoot, actual.SlotsPerHistoricalRoot, "%s: SlotsPerHistoricalRoot", name) - assert.Equal(t, expected.MinValidatorWithdrawabilityDelay, actual.MinValidatorWithdrawabilityDelay, "%s: MinValidatorWithdrawabilityDelay", name) - assert.Equal(t, expected.ShardCommitteePeriod, actual.ShardCommitteePeriod, "%s: ShardCommitteePeriod", name) - assert.Equal(t, expected.MinEpochsToInactivityPenalty, actual.MinEpochsToInactivityPenalty, "%s: MinEpochsToInactivityPenalty", name) - - // State vector lengths. - assert.Equal(t, expected.EpochsPerHistoricalVector, actual.EpochsPerHistoricalVector, "%s: EpochsPerHistoricalVector", name) - assert.Equal(t, expected.EpochsPerSlashingsVector, actual.EpochsPerSlashingsVector, "%s: EpochsPerSlashingsVector", name) - assert.Equal(t, expected.HistoricalRootsLimit, actual.HistoricalRootsLimit, "%s: HistoricalRootsLimit", name) - assert.Equal(t, expected.ValidatorRegistryLimit, actual.ValidatorRegistryLimit, "%s: ValidatorRegistryLimit", name) - - // Reward and penalty quotients. - assert.Equal(t, expected.BaseRewardFactor, actual.BaseRewardFactor, "%s: BaseRewardFactor", name) - assert.Equal(t, expected.WhistleBlowerRewardQuotient, actual.WhistleBlowerRewardQuotient, "%s: WhistleBlowerRewardQuotient", name) - assert.Equal(t, expected.ProposerRewardQuotient, actual.ProposerRewardQuotient, "%s: ProposerRewardQuotient", name) - assert.Equal(t, expected.InactivityPenaltyQuotient, actual.InactivityPenaltyQuotient, "%s: InactivityPenaltyQuotient", name) - assert.Equal(t, expected.InactivityPenaltyQuotientAltair, actual.InactivityPenaltyQuotientAltair, "%s: InactivityPenaltyQuotientAltair", name) - assert.Equal(t, expected.MinSlashingPenaltyQuotient, actual.MinSlashingPenaltyQuotient, "%s: MinSlashingPenaltyQuotient", name) - assert.Equal(t, expected.MinSlashingPenaltyQuotientAltair, actual.MinSlashingPenaltyQuotientAltair, "%s: MinSlashingPenaltyQuotientAltair", name) - assert.Equal(t, expected.ProportionalSlashingMultiplier, actual.ProportionalSlashingMultiplier, "%s: ProportionalSlashingMultiplier", name) - assert.Equal(t, expected.ProportionalSlashingMultiplierAltair, actual.ProportionalSlashingMultiplierAltair, "%s: ProportionalSlashingMultiplierAltair", name) - - // Max operations per block. - assert.Equal(t, expected.MaxProposerSlashings, actual.MaxProposerSlashings, "%s: MaxProposerSlashings", name) - assert.Equal(t, expected.MaxAttesterSlashings, actual.MaxAttesterSlashings, "%s: MaxAttesterSlashings", name) - assert.Equal(t, expected.MaxAttestations, actual.MaxAttestations, "%s: MaxAttestations", name) - assert.Equal(t, expected.MaxDeposits, actual.MaxDeposits, "%s: MaxDeposits", name) - assert.Equal(t, expected.MaxVoluntaryExits, actual.MaxVoluntaryExits, "%s: MaxVoluntaryExits", name) - - // Signature domains. - assert.Equal(t, expected.DomainBeaconProposer, actual.DomainBeaconProposer, "%s: DomainBeaconProposer", name) - assert.Equal(t, expected.DomainBeaconAttester, actual.DomainBeaconAttester, "%s: DomainBeaconAttester", name) - assert.Equal(t, expected.DomainRandao, actual.DomainRandao, "%s: DomainRandao", name) - assert.Equal(t, expected.DomainDeposit, actual.DomainDeposit, "%s: DomainDeposit", name) - 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) - - assertYamlFieldsMatch(t, name, fields, expected, actual) - } - t.Run("mainnet", func(t *testing.T) { mn := params.MainnetConfig().Copy() mainnetPresetsFiles := presetsFilePath(t, "mainnet") @@ -130,7 +146,7 @@ func TestLoadConfigFile(t *testing.T) { mnf, err := params.UnmarshalConfigFile(mainnetConfigFile, nil) require.NoError(t, err) fields := fieldsFromYamls(t, append(mainnetPresetsFiles, mainnetConfigFile)) - assertVals("mainnet", fields, mn, mnf) + assertEqualConfigs(t, "mainnet", fields, mn, mnf) }) t.Run("minimal", func(t *testing.T) { @@ -148,7 +164,7 @@ func TestLoadConfigFile(t *testing.T) { minf, err := params.UnmarshalConfigFile(minimalConfigFile, nil) require.NoError(t, err) fields := fieldsFromYamls(t, append(minimalPresetsFiles, minimalConfigFile)) - assertVals("minimal", fields, min, minf) + assertEqualConfigs(t, "minimal", fields, min, minf) }) t.Run("e2e", func(t *testing.T) { @@ -158,7 +174,7 @@ func TestLoadConfigFile(t *testing.T) { e2ef, err := params.UnmarshalConfigFile(configFile, nil) require.NoError(t, err) fields := fieldsFromYamls(t, []string{configFile}) - assertVals("e2e", fields, e2e, e2ef) + assertEqualConfigs(t, "e2e", fields, e2e, e2ef) }) } diff --git a/config/params/testdata/e2e_config.yaml b/config/params/testdata/e2e_config.yaml index dff0fb41d..6bd26fe53 100644 --- a/config/params/testdata/e2e_config.yaml +++ b/config/params/testdata/e2e_config.yaml @@ -7,8 +7,8 @@ PRESET_BASE: 'minimal' # Transition # --------------------------------------------------------------- -# TBD, 2**256-2**10 is a placeholder, e2e is 616 -TERMINAL_TOTAL_DIFFICULTY: 616 +# TBD, 2**256-2**10 is a placeholder, e2e is 480 +TERMINAL_TOTAL_DIFFICULTY: 480 # By default, don't use these params #TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000 #TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551615 @@ -83,7 +83,7 @@ PROPOSER_SCORE_BOOST: 40 DEPOSIT_CHAIN_ID: 1337 # Override for e2e tests DEPOSIT_NETWORK_ID: 1337 # Override for e2e tests # Configured on a per testnet basis -DEPOSIT_CONTRACT_ADDRESS: 0x1234567890123456789012345678901234567890 +DEPOSIT_CONTRACT_ADDRESS: 0x4242424242424242424242424242424242424242 # Updated penalty values # --------------------------------------------------------------- diff --git a/config/params/testnet_config_test.go b/config/params/testnet_config_test.go index 4d8d8a651..707868830 100644 --- a/config/params/testnet_config_test.go +++ b/config/params/testnet_config_test.go @@ -20,14 +20,12 @@ func testnetConfigFilePath(t *testing.T, network string) string { } func TestE2EConfigParity(t *testing.T) { - // TODO(11750) - t.Skip("needs https://github.com/prysmaticlabs/prysm/issues/11750") params.SetupTestConfigCleanup(t) testDir := bazel.TestTmpDir() yamlDir := filepath.Join(testDir, "config.yaml") testCfg := params.E2EMainnetTestConfig() - yamlObj := params.E2EMainnetConfigYaml() + yamlObj := params.ConfigToYaml(params.E2EMainnetTestConfig()) assert.NoError(t, file.WriteFile(yamlDir, yamlObj)) require.NoError(t, params.LoadChainConfigFile(yamlDir, params.MainnetConfig().Copy())) diff --git a/config/params/testnet_e2e_config.go b/config/params/testnet_e2e_config.go index 3ab82140d..f46276b37 100644 --- a/config/params/testnet_e2e_config.go +++ b/config/params/testnet_e2e_config.go @@ -1,8 +1,8 @@ package params const ( - altairE2EForkEpoch = 0 - bellatrixE2EForkEpoch = 0 + altairE2EForkEpoch = 6 + bellatrixE2EForkEpoch = 8 ) // E2ETestConfig retrieves the configurations made specifically for E2E testing. @@ -36,7 +36,7 @@ func E2ETestConfig() *BeaconChainConfig { e2eConfig.BellatrixForkEpoch = bellatrixE2EForkEpoch // Terminal Total Difficulty. - e2eConfig.TerminalTotalDifficulty = "0" + e2eConfig.TerminalTotalDifficulty = "480" // Prysm constants. e2eConfig.ConfigName = EndToEndName @@ -74,7 +74,7 @@ func E2EMainnetTestConfig() *BeaconChainConfig { e2eConfig.BellatrixForkEpoch = bellatrixE2EForkEpoch // Terminal Total Difficulty. - e2eConfig.TerminalTotalDifficulty = "0" + e2eConfig.TerminalTotalDifficulty = "480" // Prysm constants. e2eConfig.ConfigName = EndToEndMainnetName @@ -86,13 +86,3 @@ func E2EMainnetTestConfig() *BeaconChainConfig { e2eConfig.InitializeForkSchedule() return e2eConfig } - -// E2EMainnetConfigYaml returns the e2e config in yaml format. -func E2EMainnetConfigYaml() []byte { - return ConfigToYaml(E2EMainnetTestConfig()) -} - -// E2ETestConfigYaml returns the e2e config in yaml format. -func E2ETestConfigYaml() []byte { - return ConfigToYaml(E2ETestConfig()) -} diff --git a/runtime/interop/BUILD.bazel b/runtime/interop/BUILD.bazel index 00ab4ed82..c4139a78b 100644 --- a/runtime/interop/BUILD.bazel +++ b/runtime/interop/BUILD.bazel @@ -6,6 +6,7 @@ go_library( "generate_genesis_state.go", "generate_genesis_state_bellatrix.go", "generate_keys.go", + "premined_genesis_state.go", ], importpath = "github.com/prysmaticlabs/prysm/v3/runtime/interop", visibility = ["//visibility:public"], diff --git a/runtime/interop/premined_genesis_state.go b/runtime/interop/premined_genesis_state.go new file mode 100644 index 000000000..cffee5787 --- /dev/null +++ b/runtime/interop/premined_genesis_state.go @@ -0,0 +1,63 @@ +package interop + +import ( + "context" + "time" + + "github.com/pkg/errors" + coreState "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition" + statenative "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native" + "github.com/prysmaticlabs/prysm/v3/config/params" + "github.com/prysmaticlabs/prysm/v3/container/trie" + ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" +) + +// GeneratePreminedGenesisState deterministically given a genesis time and number of validators. +// If a genesis time of 0 is supplied it is set to the current time. +func GeneratePreminedGenesisState(ctx context.Context, genesisTime, numValidators uint64, e1d *ethpb.Eth1Data) (*ethpb.BeaconState, []*ethpb.Deposit, error) { + privKeys, pubKeys, err := DeterministicallyGenerateKeys(0 /*startIndex*/, numValidators) + if err != nil { + return nil, nil, errors.Wrapf(err, "could not deterministically generate keys for %d validators", numValidators) + } + depositDataItems, depositDataRoots, err := DepositDataFromKeys(privKeys, pubKeys) + if err != nil { + return nil, nil, errors.Wrap(err, "could not generate deposit data from keys") + } + return GeneratePreminedGenesisStateFromDepositData(ctx, genesisTime, depositDataItems, depositDataRoots, e1d) +} + +// GeneratePreminedGenesisStateFromDepositData creates a genesis state given a list of +// deposit data items and their corresponding roots. +func GeneratePreminedGenesisStateFromDepositData( + ctx context.Context, genesisTime uint64, depositData []*ethpb.Deposit_Data, depositDataRoots [][]byte, e1d *ethpb.Eth1Data, +) (*ethpb.BeaconState, []*ethpb.Deposit, error) { + t, err := trie.GenerateTrieFromItems(depositDataRoots, params.BeaconConfig().DepositContractTreeDepth) + if err != nil { + return nil, nil, errors.Wrap(err, "could not generate Merkle trie for deposit proofs") + } + deposits, err := GenerateDepositsFromData(depositData, t) + if err != nil { + return nil, nil, errors.Wrap(err, "could not generate deposits from the deposit data provided") + } + root, err := t.HashTreeRoot() + if err != nil { + return nil, nil, errors.Wrap(err, "could not hash tree root of deposit trie") + } + if genesisTime == 0 { + genesisTime = uint64(time.Now().Unix()) + } + beaconState, err := coreState.PreminedGenesisBeaconState(ctx, deposits, genesisTime, ðpb.Eth1Data{ + DepositRoot: root[:], + DepositCount: uint64(len(deposits)), + BlockHash: e1d.BlockHash, + }) + if err != nil { + return nil, nil, errors.Wrap(err, "could not generate genesis state") + } + + pbState, err := statenative.ProtobufBeaconStatePhase0(beaconState.ToProtoUnsafe()) + if err != nil { + return nil, nil, err + } + return pbState, deposits, nil +} diff --git a/runtime/tos/tos.go b/runtime/tos/tos.go index cbb02ccd6..9b1494843 100644 --- a/runtime/tos/tos.go +++ b/runtime/tos/tos.go @@ -37,10 +37,6 @@ var ( // VerifyTosAcceptedOrPrompt check if Tos was accepted before or asks to accept. func VerifyTosAcceptedOrPrompt(ctx *cli.Context) error { - if ctx.Bool(cmd.E2EConfigFlag.Name) { - return nil - } - if file.FileExists(filepath.Join(ctx.String(cmd.DataDirFlag.Name), acceptTosFilename)) { return nil } diff --git a/testing/endtoend/BUILD.bazel b/testing/endtoend/BUILD.bazel index 1c728cf02..73acb7280 100644 --- a/testing/endtoend/BUILD.bazel +++ b/testing/endtoend/BUILD.bazel @@ -42,6 +42,7 @@ test_suite( ) common_deps = [ + "//runtime/version:go_default_library", "//api/client/beacon:go_default_library", "//beacon-chain/blockchain/testing:go_default_library", "//beacon-chain/core/transition:go_default_library", diff --git a/testing/endtoend/components/BUILD.bazel b/testing/endtoend/components/BUILD.bazel index a46113e70..27513ef41 100644 --- a/testing/endtoend/components/BUILD.bazel +++ b/testing/endtoend/components/BUILD.bazel @@ -20,7 +20,6 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/v3/testing/endtoend/components", visibility = ["//testing/endtoend:__subpackages__"], deps = [ - "//beacon-chain/core/blocks:go_default_library", "//beacon-chain/state:go_default_library", "//beacon-chain/state/state-native:go_default_library", "//cmd:go_default_library", @@ -38,12 +37,14 @@ go_library( "//proto/engine/v1:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "//runtime/interop:go_default_library", + "//runtime/version:go_default_library", "//testing/endtoend/helpers:go_default_library", "//testing/endtoend/params:go_default_library", "//testing/endtoend/types:go_default_library", "//validator/keymanager:go_default_library", "@com_github_ethereum_go_ethereum//common:go_default_library", "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", + "@com_github_ethereum_go_ethereum//core/types:go_default_library", "@com_github_google_uuid//:go_default_library", "@com_github_pkg_errors//:go_default_library", "@com_github_sirupsen_logrus//:go_default_library", diff --git a/testing/endtoend/components/beacon_node.go b/testing/endtoend/components/beacon_node.go index 960d3f92c..c74354ffb 100644 --- a/testing/endtoend/components/beacon_node.go +++ b/testing/endtoend/components/beacon_node.go @@ -13,8 +13,8 @@ import ( "syscall" "github.com/bazelbuild/rules_go/go/tools/bazel" + "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/v3/beacon-chain/state" state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native" cmdshared "github.com/prysmaticlabs/prysm/v3/cmd" @@ -29,6 +29,7 @@ import ( enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v3/runtime/interop" + "github.com/prysmaticlabs/prysm/v3/runtime/version" "github.com/prysmaticlabs/prysm/v3/testing/endtoend/helpers" e2e "github.com/prysmaticlabs/prysm/v3/testing/endtoend/params" e2etypes "github.com/prysmaticlabs/prysm/v3/testing/endtoend/types" @@ -182,7 +183,6 @@ func (node *BeaconNode) generateGenesis(ctx context.Context) (state.BeaconState, return nil, errors.New("Cannot construct bellatrix block, e2e.TestParams.Eth1GenesisBlock == nil") } gb := e2e.TestParams.Eth1GenesisBlock - // so the DepositRoot in the BeaconState should be set to the HTR of an empty deposit trie. t, err := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth) if err != nil { @@ -197,54 +197,15 @@ func (node *BeaconNode) generateGenesis(ctx context.Context) (state.BeaconState, DepositCount: 0, BlockHash: gb.Hash().Bytes(), } - - payload := &enginev1.ExecutionPayload{ - ParentHash: gb.ParentHash().Bytes(), - FeeRecipient: gb.Coinbase().Bytes(), - StateRoot: gb.Root().Bytes(), - ReceiptsRoot: gb.ReceiptHash().Bytes(), - LogsBloom: gb.Bloom().Bytes(), - PrevRandao: params.BeaconConfig().ZeroHash[:], - BlockNumber: gb.NumberU64(), - GasLimit: gb.GasLimit(), - GasUsed: gb.GasUsed(), - Timestamp: gb.Time(), - ExtraData: gb.Extra()[:32], - BaseFeePerGas: bytesutil.PadTo(bytesutil.ReverseByteOrder(gb.BaseFee().Bytes()), fieldparams.RootLength), - BlockHash: gb.Hash().Bytes(), - Transactions: make([][]byte, 0), + v := e2etypes.GenesisFork() + switch v { + case version.Bellatrix: + return generateGenesisBellatrix(ctx, gb, e1d) + case version.Phase0: + return generateGenesisPhase0(ctx, e1d) + default: + return nil, fmt.Errorf("unsupported genesis fork version %s", version.String(v)) } - genesis, _, err := interop.GenerateGenesisStateBellatrix(ctx, e2e.TestParams.CLGenesisTime, params.BeaconConfig().MinGenesisActiveValidatorCount, payload, e1d) - if err != nil { - return nil, err - } - lbhr, err := genesis.LatestBlockHeader.HashTreeRoot() - if err != nil { - return nil, err - } - si, err := state_native.InitializeFromProtoUnsafeBellatrix(genesis) - if err != nil { - return nil, err - } - genb, err := blocks.NewGenesisBlockForState(ctx, si) - if err != nil { - return nil, err - } - gbr, err := genb.Block().HashTreeRoot() - if err != nil { - return nil, err - } - log.WithField("el_block_time", gb.Time()). - WithField("cl_genesis_time", genesis.GenesisTime). - WithField("state_root", fmt.Sprintf("%#x", genb.Block().StateRoot())). - WithField("latest_block_header_root", fmt.Sprintf("%#x", lbhr)). - WithField("latest_block_header_state_root", fmt.Sprintf("%#x", genesis.LatestBlockHeader.StateRoot)). - WithField("latest_block_header_parent_root", fmt.Sprintf("%#x", genesis.LatestBlockHeader.ParentRoot)). - WithField("latest_block_header_body_root", fmt.Sprintf("%#x", genesis.LatestBlockHeader.BodyRoot)). - WithField("derived_block_root", fmt.Sprintf("%#x", gbr)). - WithField("el_block_root", fmt.Sprintf("%#x", genesis.Eth1Data.BlockHash)). - Info("genesis eth1 data") - return si, nil } func (node *BeaconNode) saveGenesis(ctx context.Context) (string, error) { @@ -279,6 +240,17 @@ func (node *BeaconNode) saveGenesis(ctx context.Context) (string, error) { return genesisPath, file.WriteFile(genesisPath, genesisBytes) } +func (node *BeaconNode) saveConfig() (string, error) { + cfg := params.BeaconConfig().Copy() + cfgBytes := params.ConfigToYaml(cfg) + cfgDir := path.Join(e2e.TestParams.TestPath, fmt.Sprintf("config/%d", node.index)) + if err := file.MkdirAll(cfgDir); err != nil { + return "", err + } + cfgPath := path.Join(cfgDir, "beacon-config.yaml") + return cfgPath, file.WriteFile(cfgPath, cfgBytes) +} + // Start starts a fresh beacon node, connecting to all passed in beacon nodes. func (node *BeaconNode) Start(ctx context.Context) error { binaryPath, found := bazel.FindBinary("cmd/beacon-chain", "beacon-chain") @@ -309,6 +281,10 @@ func (node *BeaconNode) Start(ctx context.Context) error { if err != nil { return err } + cfgPath, err := node.saveConfig() + if err != nil { + return err + } args := []string{ fmt.Sprintf("--%s=%s", genesis.StatePath.Name, genesisPath), fmt.Sprintf("--%s=%s/eth2-beacon-node-%d", cmdshared.DataDirFlag.Name, e2e.TestParams.TestPath, index), @@ -329,8 +305,8 @@ func (node *BeaconNode) Start(ctx context.Context) error { fmt.Sprintf("--%s=%s", cmdshared.BootstrapNode.Name, enr), fmt.Sprintf("--%s=%s", cmdshared.VerbosityFlag.Name, "debug"), fmt.Sprintf("--%s=%d", flags.BlockBatchLimitBurstFactor.Name, 8), + fmt.Sprintf("--%s=%s", cmdshared.ChainConfigFileFlag.Name, cfgPath), "--" + cmdshared.ForceClearDB.Name, - "--" + cmdshared.E2EConfigFlag.Name, "--" + cmdshared.AcceptTosFlag.Name, "--" + flags.EnableDebugRPCEndpoints.Name, } @@ -413,3 +389,35 @@ func (node *BeaconNode) Stop() error { func (node *BeaconNode) UnderlyingProcess() *os.Process { return node.cmd.Process } + +func generateGenesisPhase0(ctx context.Context, e1d *ethpb.Eth1Data) (state.BeaconState, error) { + g, _, err := interop.GeneratePreminedGenesisState(ctx, e2e.TestParams.CLGenesisTime, params.BeaconConfig().MinGenesisActiveValidatorCount, e1d) + if err != nil { + return nil, err + } + return state_native.InitializeFromProtoUnsafePhase0(g) +} + +func generateGenesisBellatrix(ctx context.Context, gb *types.Block, e1d *ethpb.Eth1Data) (state.BeaconState, error) { + payload := &enginev1.ExecutionPayload{ + ParentHash: gb.ParentHash().Bytes(), + FeeRecipient: gb.Coinbase().Bytes(), + StateRoot: gb.Root().Bytes(), + ReceiptsRoot: gb.ReceiptHash().Bytes(), + LogsBloom: gb.Bloom().Bytes(), + PrevRandao: params.BeaconConfig().ZeroHash[:], + BlockNumber: gb.NumberU64(), + GasLimit: gb.GasLimit(), + GasUsed: gb.GasUsed(), + Timestamp: gb.Time(), + ExtraData: gb.Extra()[:32], + BaseFeePerGas: bytesutil.PadTo(bytesutil.ReverseByteOrder(gb.BaseFee().Bytes()), fieldparams.RootLength), + BlockHash: gb.Hash().Bytes(), + Transactions: make([][]byte, 0), + } + g, _, err := interop.GenerateGenesisStateBellatrix(ctx, e2e.TestParams.CLGenesisTime, params.BeaconConfig().MinGenesisActiveValidatorCount, payload, e1d) + if err != nil { + return nil, err + } + return state_native.InitializeFromProtoUnsafeBellatrix(g) +} diff --git a/testing/endtoend/components/lighthouse_beacon.go b/testing/endtoend/components/lighthouse_beacon.go index df317c903..09e351907 100644 --- a/testing/endtoend/components/lighthouse_beacon.go +++ b/testing/endtoend/components/lighthouse_beacon.go @@ -260,7 +260,7 @@ func (node *LighthouseBeaconNode) Stop() error { func (node *LighthouseBeaconNode) createTestnetDir(index int) (string, error) { testNetDir := e2e.TestParams.TestPath + fmt.Sprintf("/lighthouse-testnet-%d", index) configPath := filepath.Join(testNetDir, "config.yaml") - rawYaml := params.E2EMainnetConfigYaml() + rawYaml := params.ConfigToYaml(params.BeaconConfig()) // Add in deposit contract in yaml depContractStr := fmt.Sprintf("\nDEPOSIT_CONTRACT_ADDRESS: %s", params.BeaconConfig().DepositContractAddress) rawYaml = append(rawYaml, []byte(depContractStr)...) diff --git a/testing/endtoend/components/validator.go b/testing/endtoend/components/validator.go index 974f1932d..5ae0a58f1 100644 --- a/testing/endtoend/components/validator.go +++ b/testing/endtoend/components/validator.go @@ -164,6 +164,17 @@ func NewValidatorNode(config *e2etypes.E2EConfig, validatorNum, index, offset in } } +func (node *ValidatorNode) saveConfig() (string, error) { + cfg := params.BeaconConfig().Copy() + cfgBytes := params.ConfigToYaml(cfg) + cfgDir := path.Join(e2e.TestParams.TestPath, fmt.Sprintf("config/%d", node.index)) + if err := file.MkdirAll(cfgDir); err != nil { + return "", err + } + cfgPath := path.Join(cfgDir, "validator-config.yaml") + return cfgPath, file.WriteFile(cfgPath, cfgBytes) +} + // Start starts a validator client. func (v *ValidatorNode) Start(ctx context.Context) error { validatorHexPubKeys := make([]string, 0) @@ -206,6 +217,10 @@ func (v *ValidatorNode) Start(ctx context.Context) error { if err != nil { return err } + cfgPath, err := v.saveConfig() + if err != nil { + return err + } args := []string{ fmt.Sprintf("--%s=%s/eth2-val-%d", cmdshared.DataDirFlag.Name, e2e.TestParams.TestPath, index), fmt.Sprintf("--%s=%s", cmdshared.LogFileName.Name, file.Name()), @@ -217,8 +232,8 @@ func (v *ValidatorNode) Start(ctx context.Context) error { fmt.Sprintf("--%s=%s", flags.GrpcHeadersFlag.Name, "dummy=value,foo=bar"), // Sending random headers shouldn't break anything. fmt.Sprintf("--%s=%s", cmdshared.VerbosityFlag.Name, "debug"), fmt.Sprintf("--%s=%s", flags.ProposerSettingsFlag.Name, proposerSettingsPathPath), + fmt.Sprintf("--%s=%s", cmdshared.ChainConfigFileFlag.Name, cfgPath), "--" + cmdshared.ForceClearDB.Name, - "--" + cmdshared.E2EConfigFlag.Name, "--" + cmdshared.AcceptTosFlag.Name, } @@ -314,40 +329,26 @@ func (v *ValidatorNode) UnderlyingProcess() *os.Process { return v.cmd.Process } -func createProposerSettingsPath(pubkeys []string, validatorIndex int) (string, error) { - testNetDir := e2e.TestParams.TestPath + fmt.Sprintf("/proposer-settings/validator_%d", validatorIndex) +func createProposerSettingsPath(pubkeys []string, nodeIdx int) (string, error) { + testNetDir := e2e.TestParams.TestPath + fmt.Sprintf("/proposer-settings/validator_%d", nodeIdx) configPath := filepath.Join(testNetDir, "config.json") if len(pubkeys) == 0 { return "", errors.New("number of validators must be greater than 0") } var proposerSettingsPayload validator_service_config.ProposerSettingsPayload - if len(pubkeys) == 1 { - proposerSettingsPayload = validator_service_config.ProposerSettingsPayload{ - DefaultConfig: &validator_service_config.ProposerOptionPayload{ - FeeRecipient: DefaultFeeRecipientAddress, - }, - } - } else { - config := make(map[string]*validator_service_config.ProposerOptionPayload) + config := make(map[string]*validator_service_config.ProposerOptionPayload) - for i, pubkey := range pubkeys { - // Create an account - byteval, err := hexutil.Decode(pubkey) - if err != nil { - return "", err - } - deterministicFeeRecipient := common.HexToAddress(hexutil.Encode(byteval[:fieldparams.FeeRecipientLength])).Hex() - config[pubkeys[i]] = &validator_service_config.ProposerOptionPayload{ - FeeRecipient: deterministicFeeRecipient, - } - } - proposerSettingsPayload = validator_service_config.ProposerSettingsPayload{ - ProposerConfig: config, - DefaultConfig: &validator_service_config.ProposerOptionPayload{ - FeeRecipient: DefaultFeeRecipientAddress, - }, + for i, pubkey := range pubkeys { + config[pubkeys[i]] = &validator_service_config.ProposerOptionPayload{ + FeeRecipient: FeeRecipientFromPubkey(pubkey), } } + proposerSettingsPayload = validator_service_config.ProposerSettingsPayload{ + ProposerConfig: config, + DefaultConfig: &validator_service_config.ProposerOptionPayload{ + FeeRecipient: DefaultFeeRecipientAddress, + }, + } jsonBytes, err := json.Marshal(proposerSettingsPayload) if err != nil { return "", err @@ -360,3 +361,10 @@ func createProposerSettingsPath(pubkeys []string, validatorIndex int) (string, e } return configPath, nil } + +// FeeRecipientFromPubkey slices, from the beginning of the hex-encoded pubkey string, the 2 character 0x preamble +// plus enough hex chars to fill out the fee_recipient byte value. +func FeeRecipientFromPubkey(key string) string { + // pubkey[:(2+fieldparams.FeeRecipientLength*2)] slicing 2 (for the 0x preamble) + 2 hex chars for each byte + return common.HexToAddress(key[:(2 + fieldparams.FeeRecipientLength*2)]).Hex() +} diff --git a/testing/endtoend/components/web3remotesigner.go b/testing/endtoend/components/web3remotesigner.go index 448339c6f..5b328c128 100644 --- a/testing/endtoend/components/web3remotesigner.go +++ b/testing/endtoend/components/web3remotesigner.go @@ -70,7 +70,7 @@ func (w *Web3RemoteSigner) Start(ctx context.Context) error { return err } - testDir, err := w.createTestnetDir() + testDir, err := createTestnetDir() if err != nil { return err } @@ -256,10 +256,14 @@ func writeKeystoreKeys(ctx context.Context, keystorePath string, numKeys uint64) return nil } -func (w *Web3RemoteSigner) createTestnetDir() (string, error) { +func (w *Web3RemoteSigner) UnderlyingProcess() *os.Process { + return w.cmd.Process +} + +func createTestnetDir() (string, error) { testNetDir := e2e.TestParams.TestPath + "/web3signer-testnet" configPath := filepath.Join(testNetDir, "config.yaml") - rawYaml := params.E2ETestConfigYaml() + rawYaml := params.ConfigToYaml(params.BeaconConfig()) // Add in deposit contract in yaml depContractStr := fmt.Sprintf("\nDEPOSIT_CONTRACT_ADDRESS: %s", params.BeaconConfig().DepositContractAddress) rawYaml = append(rawYaml, []byte(depContractStr)...) @@ -273,7 +277,3 @@ func (w *Web3RemoteSigner) createTestnetDir() (string, error) { return configPath, nil } - -func (w *Web3RemoteSigner) UnderlyingProcess() *os.Process { - return w.cmd.Process -} diff --git a/testing/endtoend/endtoend_setup_test.go b/testing/endtoend/endtoend_setup_test.go index dd4c7835b..67d97d6f0 100644 --- a/testing/endtoend/endtoend_setup_test.go +++ b/testing/endtoend/endtoend_setup_test.go @@ -14,9 +14,9 @@ import ( "github.com/prysmaticlabs/prysm/v3/testing/require" ) -func e2eMinimal(t *testing.T, cfgo ...types.E2EConfigOpt) *testRunner { +func e2eMinimal(t *testing.T, v int, cfgo ...types.E2EConfigOpt) *testRunner { params.SetupTestConfigCleanup(t) - params.OverrideBeaconConfig(params.E2ETestConfig().Copy()) + require.NoError(t, params.SetActive(types.StartAt(v, params.E2ETestConfig()))) require.NoError(t, e2eParams.Init(t, e2eParams.StandardBeaconCount)) // Run for 12 epochs if not in long-running to confirm long-running has no issues. @@ -87,9 +87,9 @@ func e2eMinimal(t *testing.T, cfgo ...types.E2EConfigOpt) *testRunner { return newTestRunner(t, testConfig) } -func e2eMainnet(t *testing.T, usePrysmSh, useMultiClient bool, cfgo ...types.E2EConfigOpt) *testRunner { +func e2eMainnet(t *testing.T, usePrysmSh, useMultiClient bool, cfg *params.BeaconChainConfig, cfgo ...types.E2EConfigOpt) *testRunner { params.SetupTestConfigCleanup(t) - params.OverrideBeaconConfig(params.E2EMainnetTestConfig()) + require.NoError(t, params.SetActive(cfg)) if useMultiClient { require.NoError(t, e2eParams.InitMultiClient(t, e2eParams.StandardBeaconCount, e2eParams.StandardLighthouseNodeCount)) } else { @@ -153,6 +153,7 @@ func e2eMainnet(t *testing.T, usePrysmSh, useMultiClient bool, cfgo ...types.E2E for _, o := range cfgo { o(testConfig) } + // In the event we use the cross-client e2e option, we add in an additional // evaluator for multiclient runs to verify the beacon api conformance. if testConfig.UseValidatorCrossClient { diff --git a/testing/endtoend/evaluators/BUILD.bazel b/testing/endtoend/evaluators/BUILD.bazel index ace2076d8..171ee35c5 100644 --- a/testing/endtoend/evaluators/BUILD.bazel +++ b/testing/endtoend/evaluators/BUILD.bazel @@ -31,7 +31,6 @@ go_library( "//consensus-types/interfaces:go_default_library", "//consensus-types/primitives:go_default_library", "//container/slice:go_default_library", - "//crypto/bls:go_default_library", "//encoding/bytesutil:go_default_library", "//math:go_default_library", "//network/forks:go_default_library", diff --git a/testing/endtoend/evaluators/fee_recipient.go b/testing/endtoend/evaluators/fee_recipient.go index 539767eb2..fc997d94e 100644 --- a/testing/endtoend/evaluators/fee_recipient.go +++ b/testing/endtoend/evaluators/fee_recipient.go @@ -1,6 +1,7 @@ package evaluators import ( + "bytes" "context" "fmt" @@ -9,9 +10,7 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" "github.com/pkg/errors" - fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams" "github.com/prysmaticlabs/prysm/v3/config/params" - "github.com/prysmaticlabs/prysm/v3/crypto/bls" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v3/runtime/interop" "github.com/prysmaticlabs/prysm/v3/testing/endtoend/components" @@ -19,6 +18,7 @@ import ( e2e "github.com/prysmaticlabs/prysm/v3/testing/endtoend/params" "github.com/prysmaticlabs/prysm/v3/testing/endtoend/policies" "github.com/prysmaticlabs/prysm/v3/testing/endtoend/types" + log "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/protobuf/types/known/emptypb" ) @@ -29,6 +29,39 @@ var FeeRecipientIsPresent = types.Evaluator{ Evaluation: feeRecipientIsPresent, } +func lhKeyMap() (map[string]bool, error) { + if e2e.TestParams.LighthouseBeaconNodeCount == 0 { + return nil, nil + } + pry, lh := e2e.TestParams.BeaconNodeCount, e2e.TestParams.LighthouseBeaconNodeCount + valPerNode := int(params.BeaconConfig().MinGenesisActiveValidatorCount) / (pry + lh) + lhOff := valPerNode * pry + _, keys, err := interop.DeterministicallyGenerateKeys(uint64(lhOff), uint64(valPerNode*lh)) + if err != nil { + return nil, err + } + + km := make(map[string]bool) + for _, k := range keys { + km[hexutil.Encode(k.Marshal())] = true + } + return km, nil +} + +func valKeyMap() (map[string]bool, error) { + nvals := params.BeaconConfig().MinGenesisActiveValidatorCount + // matches validator start in validator component + validators used for deposits + _, pubs, err := interop.DeterministicallyGenerateKeys(0, nvals+e2e.DepositCount) + if err != nil { + return nil, err + } + km := make(map[string]bool) + for _, k := range pubs { + km[hexutil.Encode(k.Marshal())] = true + } + return km, nil +} + func feeRecipientIsPresent(_ types.EvaluationContext, conns ...*grpc.ClientConn) error { conn := conns[0] client := ethpb.NewBeaconChainClient(conn) @@ -47,97 +80,98 @@ func feeRecipientIsPresent(_ types.EvaluationContext, conns ...*grpc.ClientConn) return err } defer rpcclient.Close() - web3 := ethclient.NewClient(rpcclient) - ctx := context.Background() - validatorNum := int(params.BeaconConfig().MinGenesisActiveValidatorCount) - _, pubs, err := interop.DeterministicallyGenerateKeys(uint64(0), uint64(validatorNum+int(e2e.DepositCount))) // matches validator start in validator component + validators used for deposits + valkeys, err := valKeyMap() if err != nil { return err } - lighthouseKeys := []bls.PublicKey{} - if e2e.TestParams.LighthouseBeaconNodeCount != 0 { - totalNodecount := e2e.TestParams.BeaconNodeCount + e2e.TestParams.LighthouseBeaconNodeCount - valPerNode := validatorNum / totalNodecount - lighthouseOffset := valPerNode * e2e.TestParams.BeaconNodeCount - - _, lighthouseKeys, err = interop.DeterministicallyGenerateKeys(uint64(lighthouseOffset), uint64(valPerNode*e2e.TestParams.LighthouseBeaconNodeCount)) - if err != nil { - return err - } + lhkeys, err := lhKeyMap() + if err != nil { + return err } for _, ctr := range blks.BlockContainers { - if fr := ctr.GetBellatrixBlock(); fr != nil { - var account common.Address - - fr := ctr.GetBellatrixBlock().Block.Body.ExecutionPayload.FeeRecipient - if len(fr) != 0 && hexutil.Encode(fr) != params.BeaconConfig().EthBurnAddressHex { - account = common.BytesToAddress(fr) - } else { + if ctr.GetBellatrixBlock() != nil { + bb := ctr.GetBellatrixBlock().Block + payload := bb.Body.ExecutionPayload + // If the beacon chain has transitioned to Bellatrix, but the EL hasn't hit TTD, we could see a few slots + // of blocks with empty payloads. + if bytes.Equal(payload.BlockHash, make([]byte, 32)) { + continue + } + if len(payload.FeeRecipient) == 0 || hexutil.Encode(payload.FeeRecipient) == params.BeaconConfig().EthBurnAddressHex { + log.WithField("proposer_index", bb.ProposerIndex).WithField("slot", bb.Slot).Error("fee recipient eval bug") return errors.New("fee recipient is not set") } - validatorRequest := ðpb.GetValidatorRequest{ + + fr := common.BytesToAddress(payload.FeeRecipient) + gvr := ðpb.GetValidatorRequest{ QueryFilter: ðpb.GetValidatorRequest_Index{ Index: ctr.GetBellatrixBlock().Block.ProposerIndex, }, } - validator, err := client.GetValidator(context.Background(), validatorRequest) + validator, err := client.GetValidator(context.Background(), gvr) if err != nil { return errors.Wrap(err, "failed to get validators") } - publickey := validator.GetPublicKey() - isDeterministicKey := false - isLighthouseKey := false + pk := hexutil.Encode(validator.GetPublicKey()) - // If lighthouse keys are present, we skip the check. - for _, pub := range lighthouseKeys { - if hexutil.Encode(publickey) == hexutil.Encode(pub.Marshal()) { - isLighthouseKey = true - break - } - } - if isLighthouseKey { + if _, ok := lhkeys[pk]; ok { + // Don't check lighthouse keys. continue } - for _, pub := range pubs { - if hexutil.Encode(publickey) == hexutil.Encode(pub.Marshal()) { - isDeterministicKey = true - break - } - } - // calculate deterministic fee recipient using first 20 bytes of public key - deterministicFeeRecipient := common.HexToAddress(hexutil.Encode(publickey[:fieldparams.FeeRecipientLength])).Hex() - if isDeterministicKey && deterministicFeeRecipient != account.Hex() { - return fmt.Errorf("publickey %s, fee recipient %s does not match the proposer settings fee recipient %s", - hexutil.Encode(publickey), account.Hex(), deterministicFeeRecipient) - } - if !isDeterministicKey && components.DefaultFeeRecipientAddress != account.Hex() { - return fmt.Errorf("publickey %s, fee recipient %s does not match the default fee recipient %s", - hexutil.Encode(publickey), account.Hex(), components.DefaultFeeRecipientAddress) - } - currentBlock, err := web3.BlockByHash(ctx, common.BytesToHash(ctr.GetBellatrixBlock().GetBlock().GetBody().GetExecutionPayload().BlockHash)) - if err != nil { - return err + + // In e2e we generate deterministic keys by validator index, and then use a slice of their public key bytes + // as the fee recipient, so that this will also be deterministic, so this test can statelessly verify it. + // These should be the only keys we see. + // Otherwise something has changed in e2e and this test needs to be updated. + _, knownKey := valkeys[pk] + if !knownKey { + log.WithField("pubkey", pk). + WithField("slot", bb.Slot). + WithField("proposer_index", bb.ProposerIndex). + WithField("fee_recipient", fr.Hex()). + Warn("unknown key observed, not a deterministically generated key") + return errors.New("unknown key observed, not a deterministically generated key") } - accountBalance, err := web3.BalanceAt(ctx, account, currentBlock.Number()) - if err != nil { - return err + if components.FeeRecipientFromPubkey(pk) != fr.Hex() { + return fmt.Errorf("publickey %s, fee recipient %s does not match the proposer settings fee recipient %s", + pk, fr.Hex(), components.FeeRecipientFromPubkey(pk)) } - previousBlock, err := web3.BlockByHash(ctx, common.BytesToHash(ctr.GetBellatrixBlock().GetBlock().GetBody().GetExecutionPayload().ParentHash)) - if err != nil { + + if err := checkRecipientBalance(rpcclient, common.BytesToHash(payload.BlockHash), common.BytesToHash(payload.ParentHash), fr); err != nil { return err } - prevAccountBalance, err := web3.BalanceAt(ctx, account, previousBlock.Number()) - if err != nil { - return err - } - if currentBlock.GasUsed() > 0 && accountBalance.Uint64() <= prevAccountBalance.Uint64() { - return errors.Errorf("account balance didn't change after applying fee recipient for account: %s", account.Hex()) - } } } return nil } + +func checkRecipientBalance(c *rpc.Client, block, parent common.Hash, account common.Address) error { + web3 := ethclient.NewClient(c) + ctx := context.Background() + b, err := web3.BlockByHash(ctx, block) + if err != nil { + return err + } + + bal, err := web3.BalanceAt(ctx, account, b.Number()) + if err != nil { + return err + } + pBlock, err := web3.BlockByHash(ctx, parent) + if err != nil { + return err + } + pBal, err := web3.BalanceAt(ctx, account, pBlock.Number()) + if err != nil { + return err + } + if b.GasUsed() > 0 && bal.Uint64() <= pBal.Uint64() { + return errors.Errorf("account balance didn't change after applying fee recipient for account: %s", account.Hex()) + } + + return nil +} diff --git a/testing/endtoend/evaluators/operations.go b/testing/endtoend/evaluators/operations.go index 7dc7ea6f1..4af6fca64 100644 --- a/testing/endtoend/evaluators/operations.go +++ b/testing/endtoend/evaluators/operations.go @@ -7,8 +7,6 @@ import ( "math" "strings" - log "github.com/sirupsen/logrus" - "github.com/pkg/errors" corehelpers "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing" @@ -256,7 +254,6 @@ func getAllValidators(c ethpb.BeaconChainClient) ([]*ethpb.Validator, error) { vals = append(vals, v.Validator) } pageToken = validators.NextPageToken - log.WithField("len", len(vals)).WithField("pageToken", pageToken).Info("getAllValidators") } return vals, nil } @@ -425,6 +422,7 @@ func validatorsVoteWithTheMajority(_ e2etypes.EvaluationContext, conns ...*grpc. default: return errors.New("block neither phase0,altair or bellatrix") } + seenVotes[slot] = vote // We treat epoch 1 differently from other epoch for two reasons: // - this evaluator is not executed for epoch 0 so we have to calculate the first slot differently @@ -445,6 +443,14 @@ func validatorsVoteWithTheMajority(_ e2etypes.EvaluationContext, conns ...*grpc. } if !bytes.Equal(vote, expectedEth1DataVote) { + for i := types.Slot(0); i < slot; i++ { + v, ok := seenVotes[i] + if ok { + fmt.Printf("vote at slot=%d = %#x\n", i, v) + } else { + fmt.Printf("did not see slot=%d\n", i) + } + } return fmt.Errorf("incorrect eth1data vote for slot %d; expected: %#x vs voted: %#x", slot, expectedEth1DataVote, vote) } @@ -452,4 +458,5 @@ func validatorsVoteWithTheMajority(_ e2etypes.EvaluationContext, conns ...*grpc. return nil } +var seenVotes = make(map[types.Slot][]byte) var expectedEth1DataVote []byte diff --git a/testing/endtoend/fork.go b/testing/endtoend/fork.go new file mode 100644 index 000000000..6ee3d8a56 --- /dev/null +++ b/testing/endtoend/fork.go @@ -0,0 +1 @@ +package endtoend diff --git a/testing/endtoend/mainnet_e2e_test.go b/testing/endtoend/mainnet_e2e_test.go index b39c2fd8b..a59ec3695 100644 --- a/testing/endtoend/mainnet_e2e_test.go +++ b/testing/endtoend/mainnet_e2e_test.go @@ -2,9 +2,14 @@ package endtoend import ( "testing" + + "github.com/prysmaticlabs/prysm/v3/config/params" + "github.com/prysmaticlabs/prysm/v3/runtime/version" + "github.com/prysmaticlabs/prysm/v3/testing/endtoend/types" ) // Run mainnet e2e config with the current release validator against latest beacon node. func TestEndToEnd_MainnetConfig_ValidatorAtCurrentRelease(t *testing.T) { - e2eMainnet(t, true, false).run() + r := e2eMainnet(t, true, false, types.StartAt(version.Phase0, params.E2EMainnetTestConfig())) + r.run() } diff --git a/testing/endtoend/mainnet_scenario_e2e_test.go b/testing/endtoend/mainnet_scenario_e2e_test.go index 1ecbd6913..b61ecee1d 100644 --- a/testing/endtoend/mainnet_scenario_e2e_test.go +++ b/testing/endtoend/mainnet_scenario_e2e_test.go @@ -3,15 +3,16 @@ package endtoend import ( "testing" + "github.com/prysmaticlabs/prysm/v3/config/params" "github.com/prysmaticlabs/prysm/v3/testing/endtoend/types" ) func TestEndToEnd_MainnetConfig_MultiClient(t *testing.T) { - e2eMainnet(t, false /*usePrysmSh*/, true /*useMultiClient*/, types.WithValidatorCrossClient()).run() + e2eMainnet(t, false, true, params.E2EMainnetTestConfig().Copy(), types.WithValidatorCrossClient()).run() } func TestEndToEnd_MultiScenarioRun_Multiclient(t *testing.T) { - runner := e2eMainnet(t, false /*usePrysmSh*/, true /*useMultiClient*/, types.WithEpochs(22)) + runner := e2eMainnet(t, false, true, params.E2EMainnetTestConfig().Copy(), types.WithEpochs(22)) runner.config.Evaluators = scenarioEvalsMulti() runner.config.EvalInterceptor = runner.multiScenarioMulticlient runner.scenarioRunner() diff --git a/testing/endtoend/minimal_e2e_test.go b/testing/endtoend/minimal_e2e_test.go index 854286450..0dc8712f4 100644 --- a/testing/endtoend/minimal_e2e_test.go +++ b/testing/endtoend/minimal_e2e_test.go @@ -3,9 +3,11 @@ package endtoend import ( "testing" + "github.com/prysmaticlabs/prysm/v3/runtime/version" "github.com/prysmaticlabs/prysm/v3/testing/endtoend/types" ) func TestEndToEnd_MinimalConfig(t *testing.T) { - e2eMinimal(t, types.WithCheckpointSync()).run() + r := e2eMinimal(t, version.Phase0, types.WithCheckpointSync()) + r.run() } diff --git a/testing/endtoend/minimal_scenario_e2e_test.go b/testing/endtoend/minimal_scenario_e2e_test.go index f36e19655..d5e69b28b 100644 --- a/testing/endtoend/minimal_scenario_e2e_test.go +++ b/testing/endtoend/minimal_scenario_e2e_test.go @@ -3,11 +3,12 @@ package endtoend import ( "testing" + "github.com/prysmaticlabs/prysm/v3/runtime/version" "github.com/prysmaticlabs/prysm/v3/testing/endtoend/types" ) func TestEndToEnd_MultiScenarioRun(t *testing.T) { - runner := e2eMinimal(t, types.WithEpochs(22)) + runner := e2eMinimal(t, version.Phase0, types.WithEpochs(22)) runner.config.Evaluators = scenarioEvals() runner.config.EvalInterceptor = runner.multiScenario @@ -15,16 +16,16 @@ func TestEndToEnd_MultiScenarioRun(t *testing.T) { } func TestEndToEnd_MinimalConfig_Web3Signer(t *testing.T) { - e2eMinimal(t, types.WithRemoteSigner()).run() + e2eMinimal(t, version.Phase0, types.WithRemoteSigner()).run() } func TestEndToEnd_MinimalConfig_ValidatorRESTApi(t *testing.T) { - e2eMinimal(t, types.WithCheckpointSync(), types.WithValidatorRESTApi()).run() + e2eMinimal(t, version.Phase0, types.WithCheckpointSync(), types.WithValidatorRESTApi()).run() } func TestEndToEnd_ScenarioRun_EEOffline(t *testing.T) { t.Skip("TODO(#10242) Prysm is current unable to handle an offline e2e") - runner := e2eMinimal(t) + runner := e2eMinimal(t, version.Phase0) runner.config.Evaluators = scenarioEvals() runner.config.EvalInterceptor = runner.eeOffline diff --git a/testing/endtoend/types/BUILD.bazel b/testing/endtoend/types/BUILD.bazel index b139a73fe..81cfd4bd4 100644 --- a/testing/endtoend/types/BUILD.bazel +++ b/testing/endtoend/types/BUILD.bazel @@ -5,12 +5,15 @@ go_library( testonly = True, srcs = [ "empty.go", + "fork.go", "types.go", ], importpath = "github.com/prysmaticlabs/prysm/v3/testing/endtoend/types", visibility = ["//testing/endtoend:__subpackages__"], deps = [ + "//config/params:go_default_library", "//consensus-types/primitives:go_default_library", + "//runtime/version:go_default_library", "@org_golang_google_grpc//:go_default_library", ], ) diff --git a/testing/endtoend/types/fork.go b/testing/endtoend/types/fork.go new file mode 100644 index 000000000..e617126b7 --- /dev/null +++ b/testing/endtoend/types/fork.go @@ -0,0 +1,26 @@ +package types + +import ( + "fmt" + + "github.com/prysmaticlabs/prysm/v3/config/params" + "github.com/prysmaticlabs/prysm/v3/runtime/version" +) + +func StartAt(v int, c *params.BeaconChainConfig) *params.BeaconChainConfig { + c = c.Copy() + if v >= version.Altair { + c.AltairForkEpoch = 0 + } + if v >= version.Bellatrix { + c.BellatrixForkEpoch = 0 + } + if v >= version.Capella { + c.CapellaForkEpoch = 0 + } + // Time TTD to line up roughly with the bellatrix fork epoch. + // E2E sets EL block production rate equal to SecondsPerETH1Block to keep the math simple. + ttd := uint64(c.BellatrixForkEpoch) * uint64(c.SlotsPerEpoch) * c.SecondsPerSlot + c.TerminalTotalDifficulty = fmt.Sprintf("%d", ttd) + return c +} diff --git a/testing/endtoend/types/types.go b/testing/endtoend/types/types.go index c3ba6eb99..f1edd9c01 100644 --- a/testing/endtoend/types/types.go +++ b/testing/endtoend/types/types.go @@ -6,7 +6,9 @@ import ( "context" "os" + "github.com/prysmaticlabs/prysm/v3/config/params" types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v3/runtime/version" "google.golang.org/grpc" ) @@ -65,6 +67,20 @@ type E2EConfig struct { ExtraEpochs uint64 } +func GenesisFork() int { + cfg := params.BeaconConfig() + if cfg.CapellaForkEpoch == 0 { + return version.Capella + } + if cfg.BellatrixForkEpoch == 0 { + return version.Bellatrix + } + if cfg.AltairForkEpoch == 0 { + return version.Altair + } + return version.Phase0 +} + // Evaluator defines the structure of the evaluators used to // conduct the current beacon state during the E2E. type Evaluator struct {