Compare commits

...

3 Commits

Author SHA1 Message Date
Raul Jordan
c245c55dc5 add in interfaces 2022-04-16 01:09:26 -04:00
Leo Lara
7f53700306 Remove feature and flag Pyrmont testnet (#10522)
* Remove feature and flag Pyrmont testnet

* Remove unused parameter

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
2022-04-15 15:30:32 +00:00
Radosław Kapka
3b69f7a196 Simplify Initial Sync (#10523)
* move waitForStateInitialization to Start

* remove channel

* handle error in test

* fix service tests

* use fatal log

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
2022-04-15 13:32:31 +00:00
24 changed files with 168 additions and 122 deletions

View File

@@ -270,6 +270,7 @@ func AttestationsDelta(beaconState state.BeaconState, bal *precompute.Balance, v
// Modified in Altair and Bellatrix.
var inactivityDenominator uint64
bias := cfg.InactivityScoreBias
inactivityDenominator := bias * beaconState.InactivityPenaltyQuotient()
switch beaconState.Version() {
case version.Altair:
inactivityDenominator = bias * cfg.InactivityPenaltyQuotientAltair

View File

@@ -16,12 +16,19 @@ import (
type BeaconState interface {
ReadOnlyBeaconState
WriteOnlyBeaconState
SpecConstantsProvider
Copy() BeaconState
HashTreeRoot(ctx context.Context) ([32]byte, error)
FutureForkStub
StateProver
}
// SpecConstantsProvider defines a struct which can provide varying configuration
// values depending on fork versions, such as the beacon state.
type SpecConstantsProvider interface {
InactivityPenaltyQuotient() (uint64, error)
}
// StateProver defines the ability to create Merkle proofs for beacon state fields.
type StateProver interface {
FinalizedRootProof(ctx context.Context) ([][]byte, error)

View File

@@ -0,0 +1,7 @@
package v1
import "github.com/prysmaticlabs/prysm/config/params"
func (b *BeaconState) InactivityPenaltyQuotient() uint64 {
return params.BeaconConfig().InactivityPenaltyQuotient
}

View File

@@ -0,0 +1,7 @@
package v2
import "github.com/prysmaticlabs/prysm/config/params"
func (b *BeaconState) InactivityPenaltyQuotient() uint64 {
return params.BeaconConfig().InactivityPenaltyQuotientAltair
}

View File

@@ -0,0 +1,7 @@
package v3
import "github.com/prysmaticlabs/prysm/config/params"
func (b *BeaconState) InactivityPenaltyQuotient() uint64 {
return params.BeaconConfig().InactivityPenaltyQuotientBellatrix
}

View File

@@ -0,0 +1,7 @@
package v1
import "github.com/prysmaticlabs/prysm/config/params"
func (b *BeaconState) InactivityPenaltyQuotient() uint64 {
return params.BeaconConfig().InactivityPenaltyQuotient
}

View File

@@ -0,0 +1,7 @@
package v1
import "github.com/prysmaticlabs/prysm/config/params"
func (b *BeaconState) InactivityPenaltyQuotient() uint64 {
return params.BeaconConfig().InactivityPenaltyQuotientAltair
}

View File

@@ -0,0 +1,7 @@
package v1
import "github.com/prysmaticlabs/prysm/config/params"
func (b *BeaconState) InactivityPenaltyQuotient() uint64 {
return params.BeaconConfig().InactivityPenaltyQuotientBellatrix
}

View File

@@ -49,30 +49,29 @@ type Service struct {
synced *abool.AtomicBool
chainStarted *abool.AtomicBool
counter *ratecounter.RateCounter
genesisChan chan time.Time
}
// NewService configures the initial sync service responsible for bringing the node up to the
// latest head of the blockchain.
func NewService(ctx context.Context, cfg *Config) *Service {
ctx, cancel := context.WithCancel(ctx)
s := &Service{
return &Service{
cfg: cfg,
ctx: ctx,
cancel: cancel,
synced: abool.New(),
chainStarted: abool.New(),
counter: ratecounter.NewRateCounter(counterSeconds * time.Second),
genesisChan: make(chan time.Time),
}
go s.waitForStateInitialization()
return s
}
// Start the initial sync service.
func (s *Service) Start() {
// Wait for state initialized event.
genesis := <-s.genesisChan
genesis, err := s.waitForStateInitialization()
if err != nil {
log.WithError(err).Fatal("Failed to wait for state initialization.")
return
}
if genesis.IsZero() {
log.Debug("Exiting Initial Sync Service")
return
@@ -180,9 +179,10 @@ func (s *Service) waitForMinimumPeers() {
}
}
// TODO: Return error
// waitForStateInitialization makes sure that beacon node is ready to be accessed: it is either
// already properly configured or system waits up until state initialized event is triggered.
func (s *Service) waitForStateInitialization() {
func (s *Service) waitForStateInitialization() (time.Time, error) {
// Wait for state to be initialized.
stateChannel := make(chan *feed.Event, 1)
stateSub := s.cfg.StateNotifier.StateFeed().Subscribe(stateChannel)
@@ -198,19 +198,14 @@ func (s *Service) waitForStateInitialization() {
continue
}
log.WithField("starttime", data.StartTime).Debug("Received state initialized event")
s.genesisChan <- data.StartTime
return
return data.StartTime, nil
}
case <-s.ctx.Done():
log.Debug("Context closed, exiting goroutine")
// Send a zero time in the event we are exiting.
s.genesisChan <- time.Time{}
return
return time.Time{}, errors.New("context closed, exiting goroutine")
case err := <-stateSub.Err():
log.WithError(err).Error("Subscription to state notifier failed")
// Send a zero time in the event we are exiting.
s.genesisChan <- time.Time{}
return
return time.Time{}, errors.Wrap(err, "subscription to state notifier failed")
}
}
}

View File

@@ -168,11 +168,7 @@ func TestService_InitStartStop(t *testing.T) {
Chain: mc,
StateNotifier: notifier,
})
time.Sleep(500 * time.Millisecond)
assert.NotNil(t, s)
if tt.methodRuns != nil {
tt.methodRuns(notifier.StateFeed())
}
wg := &sync.WaitGroup{}
wg.Add(1)
@@ -181,6 +177,11 @@ func TestService_InitStartStop(t *testing.T) {
wg.Done()
}()
time.Sleep(500 * time.Millisecond)
if tt.methodRuns != nil {
tt.methodRuns(notifier.StateFeed())
}
go func() {
// Allow to exit from test (on no head loop waiting for head is started).
// In most tests, this is redundant, as Start() already exited.
@@ -207,7 +208,6 @@ func TestService_waitForStateInitialization(t *testing.T) {
synced: abool.New(),
chainStarted: abool.New(),
counter: ratecounter.NewRateCounter(counterSeconds * time.Second),
genesisChan: make(chan time.Time),
}
return s
}
@@ -221,9 +221,8 @@ func TestService_waitForStateInitialization(t *testing.T) {
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
go s.waitForStateInitialization()
currTime := <-s.genesisChan
assert.Equal(t, true, currTime.IsZero())
_, err := s.waitForStateInitialization()
assert.ErrorContains(t, "context closed", err)
wg.Done()
}()
go func() {
@@ -236,8 +235,6 @@ func TestService_waitForStateInitialization(t *testing.T) {
t.Fatalf("Test should have exited by now, timed out")
}
assert.LogsContain(t, hook, "Waiting for state to be initialized")
assert.LogsContain(t, hook, "Context closed, exiting goroutine")
assert.LogsDoNotContain(t, hook, "Subscription to state notifier failed")
})
t.Run("no state and state init event received", func(t *testing.T) {
@@ -251,8 +248,9 @@ func TestService_waitForStateInitialization(t *testing.T) {
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
go s.waitForStateInitialization()
receivedGenesisTime = <-s.genesisChan
var err error
receivedGenesisTime, err = s.waitForStateInitialization()
require.NoError(t, err)
assert.Equal(t, false, receivedGenesisTime.IsZero())
wg.Done()
}()
@@ -281,7 +279,6 @@ func TestService_waitForStateInitialization(t *testing.T) {
assert.LogsContain(t, hook, "Event feed data is not type *statefeed.InitializedData")
assert.LogsContain(t, hook, "Waiting for state to be initialized")
assert.LogsContain(t, hook, "Received state initialized event")
assert.LogsDoNotContain(t, hook, "Context closed, exiting goroutine")
})
t.Run("no state and state init event received and service start", func(t *testing.T) {
@@ -296,7 +293,8 @@ func TestService_waitForStateInitialization(t *testing.T) {
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
s.waitForStateInitialization()
_, err := s.waitForStateInitialization()
require.NoError(t, err)
wg.Done()
}()
@@ -321,7 +319,6 @@ func TestService_waitForStateInitialization(t *testing.T) {
}
assert.LogsContain(t, hook, "Waiting for state to be initialized")
assert.LogsContain(t, hook, "Received state initialized event")
assert.LogsDoNotContain(t, hook, "Context closed, exiting goroutine")
})
}

View File

@@ -28,7 +28,6 @@ var Commands = &cli.Command{
flags.WalletPasswordFileFlag,
flags.DeletePublicKeysFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),
@@ -62,7 +61,6 @@ var Commands = &cli.Command{
flags.GrpcRetriesFlag,
flags.GrpcRetryDelayFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),
@@ -93,7 +91,6 @@ var Commands = &cli.Command{
flags.BackupPublicKeysFlag,
flags.BackupPasswordFile,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),
@@ -121,7 +118,6 @@ var Commands = &cli.Command{
flags.AccountPasswordFileFlag,
flags.ImportPrivateKeyFileFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),
@@ -155,7 +151,6 @@ var Commands = &cli.Command{
flags.GrpcRetryDelayFlag,
flags.ExitAllFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),

View File

@@ -22,7 +22,6 @@ var Commands = &cli.Command{
cmd.DataDirFlag,
flags.SlashingProtectionExportDirFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),
@@ -47,7 +46,6 @@ var Commands = &cli.Command{
cmd.DataDirFlag,
flags.SlashingProtectionJSONFileFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),

View File

@@ -34,7 +34,6 @@ var Commands = &cli.Command{
flags.Mnemonic25thWordFileFlag,
flags.SkipMnemonic25thWordCheckFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),
@@ -64,7 +63,6 @@ var Commands = &cli.Command{
flags.RemoteSignerKeyPathFlag,
flags.RemoteSignerCACertPathFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),
@@ -93,7 +91,6 @@ var Commands = &cli.Command{
flags.Mnemonic25thWordFileFlag,
flags.SkipMnemonic25thWordCheckFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),

View File

@@ -35,9 +35,6 @@ const disabledFeatureFlag = "Disabled feature flag"
// Flags is a struct to represent which features the client will perform on runtime.
type Flags struct {
// Testnet Flags.
PyrmontTestnet bool // PyrmontTestnet defines the flag through which we can enable the node to run on the Pyrmont testnet.
// Feature related flags.
RemoteSlasherProtection bool // RemoteSlasherProtection utilizes a beacon node with --slasher mode for validator slashing protection.
WriteSSZStateTransitions bool // WriteSSZStateTransitions to tmp directory.
@@ -121,13 +118,8 @@ func InitWithReset(c *Flags) func() {
}
// configureTestnet sets the config according to specified testnet flag
func configureTestnet(ctx *cli.Context, cfg *Flags) {
if ctx.Bool(PyrmontTestnet.Name) {
log.Warn("Running on Pyrmont Testnet")
params.UsePyrmontConfig()
params.UsePyrmontNetworkConfig()
cfg.PyrmontTestnet = true
} else if ctx.Bool(PraterTestnet.Name) {
func configureTestnet(ctx *cli.Context) {
if ctx.Bool(PraterTestnet.Name) {
log.Warn("Running on the Prater Testnet")
params.UsePraterConfig()
params.UsePraterNetworkConfig()
@@ -145,7 +137,7 @@ func ConfigureBeaconChain(ctx *cli.Context) {
if ctx.Bool(devModeFlag.Name) {
enableDevModeFlags(ctx)
}
configureTestnet(ctx, cfg)
configureTestnet(ctx)
if ctx.Bool(writeSSZStateTransitionsFlag.Name) {
logEnabled(writeSSZStateTransitionsFlag)
@@ -240,7 +232,7 @@ func ConfigureBeaconChain(ctx *cli.Context) {
func ConfigureValidator(ctx *cli.Context) {
complainOnDeprecatedFlags(ctx)
cfg := &Flags{}
configureTestnet(ctx, cfg)
configureTestnet(ctx)
if ctx.Bool(enableExternalSlasherProtectionFlag.Name) {
log.Fatal(
"Remote slashing protection has currently been disabled in Prysm due to safety concerns. " +

View File

@@ -11,41 +11,41 @@ import (
func TestInitFeatureConfig(t *testing.T) {
defer Init(&Flags{})
cfg := &Flags{
PyrmontTestnet: true,
EnablePeerScorer: true,
}
Init(cfg)
c := Get()
assert.Equal(t, true, c.PyrmontTestnet)
assert.Equal(t, true, c.EnablePeerScorer)
// Reset back to false for the follow up tests.
cfg = &Flags{PyrmontTestnet: false}
cfg = &Flags{RemoteSlasherProtection: false}
Init(cfg)
}
func TestInitWithReset(t *testing.T) {
defer Init(&Flags{})
Init(&Flags{
PyrmontTestnet: true,
EnablePeerScorer: true,
})
assert.Equal(t, true, Get().PyrmontTestnet)
assert.Equal(t, true, Get().EnablePeerScorer)
// Overwrite previously set value (value that didn't come by default).
resetCfg := InitWithReset(&Flags{
PyrmontTestnet: false,
EnablePeerScorer: false,
})
assert.Equal(t, false, Get().PyrmontTestnet)
assert.Equal(t, false, Get().EnablePeerScorer)
// Reset must get to previously set configuration (not to default config values).
resetCfg()
assert.Equal(t, true, Get().PyrmontTestnet)
assert.Equal(t, true, Get().EnablePeerScorer)
}
func TestConfigureBeaconConfig(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.Bool(PyrmontTestnet.Name, true, "test")
set.Bool(enablePeerScorer.Name, true, "test")
context := cli.NewContext(&app, set, nil)
ConfigureBeaconChain(context)
c := Get()
assert.Equal(t, true, c.PyrmontTestnet)
assert.Equal(t, true, c.EnablePeerScorer)
}

View File

@@ -70,6 +70,11 @@ var (
Usage: deprecatedUsage,
Hidden: true,
}
deprecatedPyrmontTestnet = &cli.BoolFlag{
Name: "pyrmont",
Usage: deprecatedUsage,
Hidden: true,
}
)
var deprecatedFlags = []cli.Flag{
@@ -84,4 +89,5 @@ var deprecatedFlags = []cli.Flag{
deprecatedDisableNextSlotStateCache,
deprecatedAttestationAggregationStrategy,
deprecatedForceOptMaxCoverAggregationStategy,
deprecatedPyrmontTestnet,
}

View File

@@ -7,11 +7,6 @@ import (
)
var (
// PyrmontTestnet flag for the multiclient Ethereum consensus testnet.
PyrmontTestnet = &cli.BoolFlag{
Name: "pyrmont",
Usage: "This defines the flag through which we can run on the Pyrmont Multiclient Testnet",
}
// PraterTestnet flag for the multiclient Ethereum consensus testnet.
PraterTestnet = &cli.BoolFlag{
Name: "prater",
@@ -156,7 +151,6 @@ var ValidatorFlags = append(deprecatedFlags, []cli.Flag{
writeWalletPasswordOnWebOnboarding,
enableExternalSlasherProtectionFlag,
disableAttestingHistoryDBCache,
PyrmontTestnet,
PraterTestnet,
Mainnet,
dynamicKeyReloadDebounceInterval,
@@ -175,7 +169,6 @@ var BeaconChainFlags = append(deprecatedFlags, []cli.Flag{
devModeFlag,
writeSSZStateTransitionsFlag,
disableGRPCConnectionLogging,
PyrmontTestnet,
PraterTestnet,
Mainnet,
enablePeerScorer,

View File

@@ -13,7 +13,6 @@ go_library(
"network_config.go",
"testnet_e2e_config.go",
"testnet_prater_config.go",
"testnet_pyrmont_config.go",
"testutils.go",
"values.go",
],

View File

@@ -1,43 +0,0 @@
package params
import "math"
// UsePyrmontNetworkConfig uses the Pyrmont specific
// network config.
func UsePyrmontNetworkConfig() {
cfg := BeaconNetworkConfig().Copy()
cfg.ContractDeploymentBlock = 3743587
cfg.BootstrapNodes = []string{
"enr:-Ku4QOA5OGWObY8ep_x35NlGBEj7IuQULTjkgxC_0G1AszqGEA0Wn2RNlyLFx9zGTNB1gdFBA6ZDYxCgIza1uJUUOj4Dh2F0dG5ldHOIAAAAAAAAAACEZXRoMpDVTPWXAAAgCf__________gmlkgnY0gmlwhDQPSjiJc2VjcDI1NmsxoQM6yTQB6XGWYJbI7NZFBjp4Yb9AYKQPBhVrfUclQUobb4N1ZHCCIyg",
"enr:-Ku4QOksdA2tabOGrfOOr6NynThMoio6Ggka2oDPqUuFeWCqcRM2alNb8778O_5bK95p3EFt0cngTUXm2H7o1jkSJ_8Dh2F0dG5ldHOIAAAAAAAAAACEZXRoMpDVTPWXAAAgCf__________gmlkgnY0gmlwhDaa13aJc2VjcDI1NmsxoQKdNQJvnohpf0VO0ZYCAJxGjT0uwJoAHbAiBMujGjK0SoN1ZHCCIyg",
}
OverrideBeaconNetworkConfig(cfg)
}
// UsePyrmontConfig sets the main beacon chain
// config for Pyrmont.
func UsePyrmontConfig() {
beaconConfig = PyrmontConfig()
}
// PyrmontConfig defines the config for the
// Pyrmont testnet.
func PyrmontConfig() *BeaconChainConfig {
cfg := MainnetConfig().Copy()
cfg.MinGenesisTime = 1605700800
cfg.GenesisDelay = 432000
cfg.ConfigName = ConfigNames[Pyrmont]
cfg.GenesisForkVersion = []byte{0x00, 0x00, 0x20, 0x09}
cfg.AltairForkVersion = []byte{0x01, 0x00, 0x20, 0x09}
cfg.AltairForkEpoch = 61650
cfg.BellatrixForkVersion = []byte{0x02, 0x00, 0x20, 0x09}
cfg.BellatrixForkEpoch = math.MaxUint64
cfg.ShardingForkVersion = []byte{0x03, 0x00, 0x20, 0x09}
cfg.ShardingForkEpoch = math.MaxUint64
cfg.SecondsPerETH1Block = 14
cfg.DepositChainID = 5
cfg.DepositNetworkID = 5
cfg.DepositContractAddress = "0x8c5fecdC472E27Bc447696F431E425D02dd46a8c"
cfg.InitializeForkSchedule()
return cfg
}

View File

@@ -12,7 +12,6 @@ const (
Mainnet ConfigName = iota
Minimal
EndToEnd
Pyrmont
Prater
EndToEndMainnet
)
@@ -33,7 +32,6 @@ var ConfigNames = map[ConfigName]string{
Mainnet: "mainnet",
Minimal: "minimal",
EndToEnd: "end-to-end",
Pyrmont: "pyrmont",
Prater: "prater",
EndToEndMainnet: "end-to-end-mainnet",
}
@@ -42,7 +40,6 @@ var ConfigNames = map[ConfigName]string{
var KnownConfigs = map[ConfigName]func() *BeaconChainConfig{
Mainnet: MainnetConfig,
Prater: PraterConfig,
Pyrmont: PyrmontConfig,
Minimal: MinimalSpecConfig,
EndToEnd: E2ETestConfig,
EndToEndMainnet: E2EMainnetTestConfig,

View File

@@ -0,0 +1,72 @@
package consensus_types
import (
ssz "github.com/ferranbt/fastssz"
types "github.com/prysmaticlabs/eth2-types"
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client"
"google.golang.org/protobuf/proto"
)
// SSZItem defines a struct which provides Marshal,
// Unmarshal, and HashTreeRoot SSZ operations.
type SSZItem interface {
ssz.Marshaler
ssz.Unmarshaler
ssz.HashRoot
}
// Container defines the base methods required for a consensus
// data structure used in Prysm, containing utilities for SSZ
// as well as conversion methods to a protobuf representation for use
// with Prysm's gRPC API.
type Container interface {
SSZItem
IsNil() bool
Proto() proto.Message
FromProto(m proto.Message)
}
// SignedBeaconBlock describes the method set of a signed beacon block.
type SignedBeaconBlock interface {
Container
Block() BeaconBlock
Signature() []byte
Copy() SignedBeaconBlock
PbGenericBlock() (*ethpb.GenericSignedBeaconBlock, error)
PbPhase0Block() (*ethpb.SignedBeaconBlock, error)
PbAltairBlock() (*ethpb.SignedBeaconBlockAltair, error)
PbBellatrixBlock() (*ethpb.SignedBeaconBlockBellatrix, error)
PbBlindedBellatrixBlock() (*ethpb.SignedBlindedBeaconBlockBellatrix, error)
Header() (*ethpb.SignedBeaconBlockHeader, error)
}
// BeaconBlock describes an interface which states the methods
// employed by an object that is a beacon block.
type BeaconBlock interface {
Container
Slot() types.Slot
ProposerIndex() types.ValidatorIndex
ParentRoot() []byte
StateRoot() []byte
Body() BeaconBlockBody
AsSignRequestObject() validatorpb.SignRequestObject
}
// BeaconBlockBody describes the method set employed by an object
// that is a beacon block body.
type BeaconBlockBody interface {
Container
RandaoReveal() []byte
Eth1Data() *ethpb.Eth1Data
Graffiti() []byte
ProposerSlashings() []*ethpb.ProposerSlashing
AttesterSlashings() []*ethpb.AttesterSlashing
Attestations() []*ethpb.Attestation
Deposits() []*ethpb.Deposit
VoluntaryExits() []*ethpb.SignedVoluntaryExit
SyncAggregate() (*ethpb.SyncAggregate, error)
ExecutionPayload() (*enginev1.ExecutionPayload, error)
ExecutionPayloadHeader() (*ethpb.ExecutionPayloadHeader, error)
}

View File

@@ -7,7 +7,7 @@ Flags:
-beacon string
gRPC address of the Prysm beacon node (default "127.0.0.1:4000")
-genesis uint
Genesis time. mainnet=1606824023, prater=1616508000, pyrmont=1605722407 (default 1606824023)
Genesis time. mainnet=1606824023, prater=1616508000 (default 1606824023)
```
Usage:

View File

@@ -18,7 +18,7 @@ import (
var (
beacon = flag.String("beacon", "127.0.0.1:4000", "gRPC address of the Prysm beacon node")
genesis = flag.Uint64("genesis", 1606824023, "Genesis time. mainnet=1606824023, prater=1616508000, pyrmont=1605722407")
genesis = flag.Uint64("genesis", 1606824023, "Genesis time. mainnet=1606824023, prater=1616508000")
)
func main() {

View File

@@ -276,9 +276,7 @@ func displayExitInfo(rawExitedKeys [][]byte, trimmedExitedKeys []string) {
urlFormattedPubKeys := make([]string, len(rawExitedKeys))
for i, key := range rawExitedKeys {
var baseUrl string
if params.BeaconConfig().ConfigName == params.ConfigNames[params.Pyrmont] {
baseUrl = "https://pyrmont.beaconcha.in/validator/"
} else if params.BeaconConfig().ConfigName == params.ConfigNames[params.Prater] {
if params.BeaconConfig().ConfigName == params.ConfigNames[params.Prater] {
baseUrl = "https://prater.beaconcha.in/validator/"
} else {
baseUrl = "https://beaconcha.in/validator/"