diff --git a/beacon/blsync/client.go b/beacon/blsync/client.go
index 39a1c6ea76..3c93754d3d 100644
--- a/beacon/blsync/client.go
+++ b/beacon/blsync/client.go
@@ -17,25 +17,22 @@
package blsync
import (
- "strings"
-
"github.com/ethereum/go-ethereum/beacon/light"
"github.com/ethereum/go-ethereum/beacon/light/api"
"github.com/ethereum/go-ethereum/beacon/light/request"
"github.com/ethereum/go-ethereum/beacon/light/sync"
+ "github.com/ethereum/go-ethereum/beacon/params"
"github.com/ethereum/go-ethereum/beacon/types"
- "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/ethdb/memorydb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
- "github.com/urfave/cli/v2"
)
type Client struct {
urls []string
customHeader map[string]string
- chainConfig *lightClientConfig
+ config *params.ClientConfig
scheduler *request.Scheduler
blockSync *beaconBlockSync
engineRPC *rpc.Client
@@ -44,34 +41,18 @@ type Client struct {
engineClient *engineClient
}
-func NewClient(ctx *cli.Context) *Client {
- if !ctx.IsSet(utils.BeaconApiFlag.Name) {
- utils.Fatalf("Beacon node light client API URL not specified")
- }
- var (
- chainConfig = makeChainConfig(ctx)
- customHeader = make(map[string]string)
- )
- for _, s := range ctx.StringSlice(utils.BeaconApiHeaderFlag.Name) {
- kv := strings.Split(s, ":")
- if len(kv) != 2 {
- utils.Fatalf("Invalid custom API header entry: %s", s)
- }
- customHeader[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
- }
-
+func NewClient(config params.ClientConfig) *Client {
// create data structures
var (
db = memorydb.New()
- threshold = ctx.Int(utils.BeaconThresholdFlag.Name)
- committeeChain = light.NewCommitteeChain(db, chainConfig.ChainConfig, threshold, !ctx.Bool(utils.BeaconNoFilterFlag.Name))
- headTracker = light.NewHeadTracker(committeeChain, threshold)
+ committeeChain = light.NewCommitteeChain(db, &config.ChainConfig, config.Threshold, !config.NoFilter)
+ headTracker = light.NewHeadTracker(committeeChain, config.Threshold)
)
headSync := sync.NewHeadSync(headTracker, committeeChain)
// set up scheduler and sync modules
scheduler := request.NewScheduler()
- checkpointInit := sync.NewCheckpointInit(committeeChain, chainConfig.Checkpoint)
+ checkpointInit := sync.NewCheckpointInit(committeeChain, config.Checkpoint)
forwardSync := sync.NewForwardUpdateSync(committeeChain)
beaconBlockSync := newBeaconBlockSync(headTracker)
scheduler.RegisterTarget(headTracker)
@@ -83,9 +64,9 @@ func NewClient(ctx *cli.Context) *Client {
return &Client{
scheduler: scheduler,
- urls: ctx.StringSlice(utils.BeaconApiFlag.Name),
- customHeader: customHeader,
- chainConfig: &chainConfig,
+ urls: config.Apis,
+ customHeader: config.CustomHeader,
+ config: &config,
blockSync: beaconBlockSync,
}
}
@@ -97,7 +78,7 @@ func (c *Client) SetEngineRPC(engine *rpc.Client) {
func (c *Client) Start() error {
headCh := make(chan types.ChainHeadEvent, 16)
c.chainHeadSub = c.blockSync.SubscribeChainHead(headCh)
- c.engineClient = startEngineClient(c.chainConfig, c.engineRPC, headCh)
+ c.engineClient = startEngineClient(c.config, c.engineRPC, headCh)
c.scheduler.Start()
for _, url := range c.urls {
diff --git a/beacon/blsync/config.go b/beacon/blsync/config.go
deleted file mode 100644
index 828c14f898..0000000000
--- a/beacon/blsync/config.go
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright 2022 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package blsync
-
-import (
- "github.com/ethereum/go-ethereum/beacon/types"
- "github.com/ethereum/go-ethereum/cmd/utils"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/hexutil"
- "github.com/urfave/cli/v2"
-)
-
-// lightClientConfig contains beacon light client configuration
-type lightClientConfig struct {
- *types.ChainConfig
- Checkpoint common.Hash
-}
-
-var (
- MainnetConfig = lightClientConfig{
- ChainConfig: (&types.ChainConfig{
- GenesisValidatorsRoot: common.HexToHash("0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95"),
- GenesisTime: 1606824023,
- }).
- AddFork("GENESIS", 0, []byte{0, 0, 0, 0}).
- AddFork("ALTAIR", 74240, []byte{1, 0, 0, 0}).
- AddFork("BELLATRIX", 144896, []byte{2, 0, 0, 0}).
- AddFork("CAPELLA", 194048, []byte{3, 0, 0, 0}).
- AddFork("DENEB", 269568, []byte{4, 0, 0, 0}),
- Checkpoint: common.HexToHash("0x6509b691f4de4f7b083f2784938fd52f0e131675432b3fd85ea549af9aebd3d0"),
- }
-
- SepoliaConfig = lightClientConfig{
- ChainConfig: (&types.ChainConfig{
- GenesisValidatorsRoot: common.HexToHash("0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078"),
- GenesisTime: 1655733600,
- }).
- AddFork("GENESIS", 0, []byte{144, 0, 0, 105}).
- AddFork("ALTAIR", 50, []byte{144, 0, 0, 112}).
- AddFork("BELLATRIX", 100, []byte{144, 0, 0, 113}).
- AddFork("CAPELLA", 56832, []byte{144, 0, 0, 114}).
- AddFork("DENEB", 132608, []byte{144, 0, 0, 115}),
- Checkpoint: common.HexToHash("0x456e85f5608afab3465a0580bff8572255f6d97af0c5f939e3f7536b5edb2d3f"),
- }
-
- HoleskyConfig = lightClientConfig{
- ChainConfig: (&types.ChainConfig{
- GenesisValidatorsRoot: common.HexToHash("0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1"),
- GenesisTime: 1695902400,
- }).
- AddFork("GENESIS", 0, []byte{1, 1, 112, 0}).
- AddFork("ALTAIR", 0, []byte{2, 1, 112, 0}).
- AddFork("BELLATRIX", 0, []byte{3, 1, 112, 0}).
- AddFork("CAPELLA", 256, []byte{4, 1, 112, 0}).
- AddFork("DENEB", 29696, []byte{5, 1, 112, 0}),
- Checkpoint: common.HexToHash("0x6456a1317f54d4b4f2cb5bc9d153b5af0988fe767ef0609f0236cf29030bcff7"),
- }
-)
-
-func makeChainConfig(ctx *cli.Context) lightClientConfig {
- var config lightClientConfig
- customConfig := ctx.IsSet(utils.BeaconConfigFlag.Name)
- utils.CheckExclusive(ctx, utils.MainnetFlag, utils.SepoliaFlag, utils.HoleskyFlag, utils.BeaconConfigFlag)
- switch {
- case ctx.Bool(utils.MainnetFlag.Name):
- config = MainnetConfig
- case ctx.Bool(utils.SepoliaFlag.Name):
- config = SepoliaConfig
- case ctx.Bool(utils.HoleskyFlag.Name):
- config = HoleskyConfig
- default:
- if !customConfig {
- config = MainnetConfig
- }
- }
- // Genesis root and time should always be specified together with custom chain config
- if customConfig {
- if !ctx.IsSet(utils.BeaconGenesisRootFlag.Name) {
- utils.Fatalf("Custom beacon chain config is specified but genesis root is missing")
- }
- if !ctx.IsSet(utils.BeaconGenesisTimeFlag.Name) {
- utils.Fatalf("Custom beacon chain config is specified but genesis time is missing")
- }
- if !ctx.IsSet(utils.BeaconCheckpointFlag.Name) {
- utils.Fatalf("Custom beacon chain config is specified but checkpoint is missing")
- }
- config.ChainConfig = &types.ChainConfig{
- GenesisTime: ctx.Uint64(utils.BeaconGenesisTimeFlag.Name),
- }
- if c, err := hexutil.Decode(ctx.String(utils.BeaconGenesisRootFlag.Name)); err == nil && len(c) <= 32 {
- copy(config.GenesisValidatorsRoot[:len(c)], c)
- } else {
- utils.Fatalf("Invalid hex string", "beacon.genesis.gvroot", ctx.String(utils.BeaconGenesisRootFlag.Name), "error", err)
- }
- if err := config.ChainConfig.LoadForks(ctx.String(utils.BeaconConfigFlag.Name)); err != nil {
- utils.Fatalf("Could not load beacon chain config file", "file name", ctx.String(utils.BeaconConfigFlag.Name), "error", err)
- }
- } else {
- if ctx.IsSet(utils.BeaconGenesisRootFlag.Name) {
- utils.Fatalf("Genesis root is specified but custom beacon chain config is missing")
- }
- if ctx.IsSet(utils.BeaconGenesisTimeFlag.Name) {
- utils.Fatalf("Genesis time is specified but custom beacon chain config is missing")
- }
- }
- // Checkpoint is required with custom chain config and is optional with pre-defined config
- if ctx.IsSet(utils.BeaconCheckpointFlag.Name) {
- if c, err := hexutil.Decode(ctx.String(utils.BeaconCheckpointFlag.Name)); err == nil && len(c) <= 32 {
- copy(config.Checkpoint[:len(c)], c)
- } else {
- utils.Fatalf("Invalid hex string", "beacon.checkpoint", ctx.String(utils.BeaconCheckpointFlag.Name), "error", err)
- }
- }
- return config
-}
diff --git a/beacon/blsync/engineclient.go b/beacon/blsync/engineclient.go
index fb8f77f32b..c6569fdbde 100644
--- a/beacon/blsync/engineclient.go
+++ b/beacon/blsync/engineclient.go
@@ -23,6 +23,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/beacon/engine"
+ "github.com/ethereum/go-ethereum/beacon/params"
"github.com/ethereum/go-ethereum/beacon/types"
"github.com/ethereum/go-ethereum/common"
ctypes "github.com/ethereum/go-ethereum/core/types"
@@ -31,14 +32,14 @@ import (
)
type engineClient struct {
- config *lightClientConfig
+ config *params.ClientConfig
rpc *rpc.Client
rootCtx context.Context
cancelRoot context.CancelFunc
wg sync.WaitGroup
}
-func startEngineClient(config *lightClientConfig, rpc *rpc.Client, headCh <-chan types.ChainHeadEvent) *engineClient {
+func startEngineClient(config *params.ClientConfig, rpc *rpc.Client, headCh <-chan types.ChainHeadEvent) *engineClient {
ctx, cancel := context.WithCancel(context.Background())
ec := &engineClient{
config: config,
diff --git a/beacon/light/committee_chain.go b/beacon/light/committee_chain.go
index 778cd3028f..4fa87785c0 100644
--- a/beacon/light/committee_chain.go
+++ b/beacon/light/committee_chain.go
@@ -76,24 +76,24 @@ type CommitteeChain struct {
unixNano func() int64 // system clock (simulated clock in tests)
sigVerifier committeeSigVerifier // BLS sig verifier (dummy verifier in tests)
- config *types.ChainConfig
+ config *params.ChainConfig
minimumUpdateScore types.UpdateScore
enforceTime bool // enforceTime specifies whether the age of a signed header should be checked
}
// NewCommitteeChain creates a new CommitteeChain.
-func NewCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool) *CommitteeChain {
+func NewCommitteeChain(db ethdb.KeyValueStore, config *params.ChainConfig, signerThreshold int, enforceTime bool) *CommitteeChain {
return newCommitteeChain(db, config, signerThreshold, enforceTime, blsVerifier{}, &mclock.System{}, func() int64 { return time.Now().UnixNano() })
}
// NewTestCommitteeChain creates a new CommitteeChain for testing.
-func NewTestCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool, clock *mclock.Simulated) *CommitteeChain {
+func NewTestCommitteeChain(db ethdb.KeyValueStore, config *params.ChainConfig, signerThreshold int, enforceTime bool, clock *mclock.Simulated) *CommitteeChain {
return newCommitteeChain(db, config, signerThreshold, enforceTime, dummyVerifier{}, clock, func() int64 { return int64(clock.Now()) })
}
// newCommitteeChain creates a new CommitteeChain with the option of replacing the
// clock source and signature verification for testing purposes.
-func newCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool, sigVerifier committeeSigVerifier, clock mclock.Clock, unixNano func() int64) *CommitteeChain {
+func newCommitteeChain(db ethdb.KeyValueStore, config *params.ChainConfig, signerThreshold int, enforceTime bool, sigVerifier committeeSigVerifier, clock mclock.Clock, unixNano func() int64) *CommitteeChain {
s := &CommitteeChain{
committeeCache: lru.NewCache[uint64, syncCommittee](10),
db: db,
@@ -505,7 +505,7 @@ func (s *CommitteeChain) verifySignedHeader(head types.SignedHeader) (bool, time
if committee == nil {
return false, age, nil
}
- if signingRoot, err := s.config.Forks.SigningRoot(head.Header); err == nil {
+ if signingRoot, err := s.config.Forks.SigningRoot(head.Header.Epoch(), head.Header.Hash()); err == nil {
return s.sigVerifier.verifySignature(committee, signingRoot, &head.Signature), age, nil
}
return false, age, nil
diff --git a/beacon/light/committee_chain_test.go b/beacon/light/committee_chain_test.go
index 57b6d7175c..17ba135905 100644
--- a/beacon/light/committee_chain_test.go
+++ b/beacon/light/committee_chain_test.go
@@ -31,15 +31,15 @@ var (
testGenesis = newTestGenesis()
testGenesis2 = newTestGenesis()
- tfBase = newTestForks(testGenesis, types.Forks{
- &types.Fork{Epoch: 0, Version: []byte{0}},
+ tfBase = newTestForks(testGenesis, params.Forks{
+ ¶ms.Fork{Epoch: 0, Version: []byte{0}},
})
- tfAlternative = newTestForks(testGenesis, types.Forks{
- &types.Fork{Epoch: 0, Version: []byte{0}},
- &types.Fork{Epoch: 0x700, Version: []byte{1}},
+ tfAlternative = newTestForks(testGenesis, params.Forks{
+ ¶ms.Fork{Epoch: 0, Version: []byte{0}},
+ ¶ms.Fork{Epoch: 0x700, Version: []byte{1}},
})
- tfAnotherGenesis = newTestForks(testGenesis2, types.Forks{
- &types.Fork{Epoch: 0, Version: []byte{0}},
+ tfAnotherGenesis = newTestForks(testGenesis2, params.Forks{
+ ¶ms.Fork{Epoch: 0, Version: []byte{0}},
})
tcBase = newTestCommitteeChain(nil, tfBase, true, 0, 10, 400, false)
@@ -226,13 +226,13 @@ type committeeChainTest struct {
t *testing.T
db *memorydb.Database
clock *mclock.Simulated
- config types.ChainConfig
+ config params.ChainConfig
signerThreshold int
enforceTime bool
chain *CommitteeChain
}
-func newCommitteeChainTest(t *testing.T, config types.ChainConfig, signerThreshold int, enforceTime bool) *committeeChainTest {
+func newCommitteeChainTest(t *testing.T, config params.ChainConfig, signerThreshold int, enforceTime bool) *committeeChainTest {
c := &committeeChainTest{
t: t,
db: memorydb.New(),
@@ -298,20 +298,20 @@ func (c *committeeChainTest) verifyRange(tc *testCommitteeChain, begin, end uint
c.verifySignedHeader(tc, float64(end)+1.5, false)
}
-func newTestGenesis() types.ChainConfig {
- var config types.ChainConfig
+func newTestGenesis() params.ChainConfig {
+ var config params.ChainConfig
rand.Read(config.GenesisValidatorsRoot[:])
return config
}
-func newTestForks(config types.ChainConfig, forks types.Forks) types.ChainConfig {
+func newTestForks(config params.ChainConfig, forks params.Forks) params.ChainConfig {
for _, fork := range forks {
config.AddFork(fork.Name, fork.Epoch, fork.Version)
}
return config
}
-func newTestCommitteeChain(parent *testCommitteeChain, config types.ChainConfig, newCommittees bool, begin, end int, signerCount int, finalizedHeader bool) *testCommitteeChain {
+func newTestCommitteeChain(parent *testCommitteeChain, config params.ChainConfig, newCommittees bool, begin, end int, signerCount int, finalizedHeader bool) *testCommitteeChain {
tc := &testCommitteeChain{
config: config,
}
@@ -337,7 +337,7 @@ type testPeriod struct {
type testCommitteeChain struct {
periods []testPeriod
- config types.ChainConfig
+ config params.ChainConfig
}
func (tc *testCommitteeChain) fillCommittees(begin, end int) {
diff --git a/beacon/light/test_helpers.go b/beacon/light/test_helpers.go
index f537d963a6..7bd19ca0ad 100644
--- a/beacon/light/test_helpers.go
+++ b/beacon/light/test_helpers.go
@@ -33,7 +33,7 @@ func GenerateTestCommittee() *types.SerializedSyncCommittee {
return s
}
-func GenerateTestUpdate(config *types.ChainConfig, period uint64, committee, nextCommittee *types.SerializedSyncCommittee, signerCount int, finalizedHeader bool) *types.LightClientUpdate {
+func GenerateTestUpdate(config *params.ChainConfig, period uint64, committee, nextCommittee *types.SerializedSyncCommittee, signerCount int, finalizedHeader bool) *types.LightClientUpdate {
update := new(types.LightClientUpdate)
update.NextSyncCommitteeRoot = nextCommittee.Root()
var attestedHeader types.Header
@@ -48,9 +48,9 @@ func GenerateTestUpdate(config *types.ChainConfig, period uint64, committee, nex
return update
}
-func GenerateTestSignedHeader(header types.Header, config *types.ChainConfig, committee *types.SerializedSyncCommittee, signatureSlot uint64, signerCount int) types.SignedHeader {
+func GenerateTestSignedHeader(header types.Header, config *params.ChainConfig, committee *types.SerializedSyncCommittee, signatureSlot uint64, signerCount int) types.SignedHeader {
bitmask := makeBitmask(signerCount)
- signingRoot, _ := config.Forks.SigningRoot(header)
+ signingRoot, _ := config.Forks.SigningRoot(header.Epoch(), header.Hash())
c, _ := dummyVerifier{}.deserializeSyncCommittee(committee)
return types.SignedHeader{
Header: header,
diff --git a/beacon/types/config.go b/beacon/params/config.go
similarity index 94%
rename from beacon/types/config.go
rename to beacon/params/config.go
index 7706e85f6c..be2a40f171 100644
--- a/beacon/types/config.go
+++ b/beacon/params/config.go
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-package types
+package params
import (
"crypto/sha256"
@@ -39,81 +39,13 @@ const syncCommitteeDomain = 7
var knownForks = []string{"GENESIS", "ALTAIR", "BELLATRIX", "CAPELLA", "DENEB"}
-// Fork describes a single beacon chain fork and also stores the calculated
-// signature domain used after this fork.
-type Fork struct {
- // Name of the fork in the chain config (config.yaml) file
- Name string
-
- // Epoch when given fork version is activated
- Epoch uint64
-
- // Fork version, see https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types
- Version []byte
-
- // index in list of known forks or MaxInt if unknown
- knownIndex int
-
- // calculated by computeDomain, based on fork version and genesis validators root
- domain merkle.Value
-}
-
-// computeDomain returns the signature domain based on the given fork version
-// and genesis validator set root.
-func (f *Fork) computeDomain(genesisValidatorsRoot common.Hash) {
- var (
- hasher = sha256.New()
- forkVersion32 merkle.Value
- forkDataRoot merkle.Value
- )
- copy(forkVersion32[:], f.Version)
- hasher.Write(forkVersion32[:])
- hasher.Write(genesisValidatorsRoot[:])
- hasher.Sum(forkDataRoot[:0])
-
- f.domain[0] = syncCommitteeDomain
- copy(f.domain[4:], forkDataRoot[:28])
-}
-
-// Forks is the list of all beacon chain forks in the chain configuration.
-type Forks []*Fork
-
-// domain returns the signature domain for the given epoch (assumes that domains
-// have already been calculated).
-func (f Forks) domain(epoch uint64) (merkle.Value, error) {
- for i := len(f) - 1; i >= 0; i-- {
- if epoch >= f[i].Epoch {
- return f[i].domain, nil
- }
- }
- return merkle.Value{}, fmt.Errorf("unknown fork for epoch %d", epoch)
-}
-
-// SigningRoot calculates the signing root of the given header.
-func (f Forks) SigningRoot(header Header) (common.Hash, error) {
- domain, err := f.domain(header.Epoch())
- if err != nil {
- return common.Hash{}, err
- }
- var (
- signingRoot common.Hash
- headerHash = header.Hash()
- hasher = sha256.New()
- )
- hasher.Write(headerHash[:])
- hasher.Write(domain[:])
- hasher.Sum(signingRoot[:0])
-
- return signingRoot, nil
-}
-
-func (f Forks) Len() int { return len(f) }
-func (f Forks) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-func (f Forks) Less(i, j int) bool {
- if f[i].Epoch != f[j].Epoch {
- return f[i].Epoch < f[j].Epoch
- }
- return f[i].knownIndex < f[j].knownIndex
+// ClientConfig contains beacon light client configuration.
+type ClientConfig struct {
+ ChainConfig
+ Apis []string
+ CustomHeader map[string]string
+ Threshold int
+ NoFilter bool
}
// ChainConfig contains the beacon chain configuration.
@@ -121,6 +53,7 @@ type ChainConfig struct {
GenesisTime uint64 // Unix timestamp of slot 0
GenesisValidatorsRoot common.Hash // Root hash of the genesis validator set, used for signature domain calculation
Forks Forks
+ Checkpoint common.Hash
}
// ForkAtEpoch returns the latest active fork at the given epoch.
@@ -202,3 +135,79 @@ func (c *ChainConfig) LoadForks(path string) error {
}
return nil
}
+
+// Fork describes a single beacon chain fork and also stores the calculated
+// signature domain used after this fork.
+type Fork struct {
+ // Name of the fork in the chain config (config.yaml) file
+ Name string
+
+ // Epoch when given fork version is activated
+ Epoch uint64
+
+ // Fork version, see https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types
+ Version []byte
+
+ // index in list of known forks or MaxInt if unknown
+ knownIndex int
+
+ // calculated by computeDomain, based on fork version and genesis validators root
+ domain merkle.Value
+}
+
+// computeDomain returns the signature domain based on the given fork version
+// and genesis validator set root.
+func (f *Fork) computeDomain(genesisValidatorsRoot common.Hash) {
+ var (
+ hasher = sha256.New()
+ forkVersion32 merkle.Value
+ forkDataRoot merkle.Value
+ )
+ copy(forkVersion32[:], f.Version)
+ hasher.Write(forkVersion32[:])
+ hasher.Write(genesisValidatorsRoot[:])
+ hasher.Sum(forkDataRoot[:0])
+
+ f.domain[0] = syncCommitteeDomain
+ copy(f.domain[4:], forkDataRoot[:28])
+}
+
+// Forks is the list of all beacon chain forks in the chain configuration.
+type Forks []*Fork
+
+// domain returns the signature domain for the given epoch (assumes that domains
+// have already been calculated).
+func (f Forks) domain(epoch uint64) (merkle.Value, error) {
+ for i := len(f) - 1; i >= 0; i-- {
+ if epoch >= f[i].Epoch {
+ return f[i].domain, nil
+ }
+ }
+ return merkle.Value{}, fmt.Errorf("unknown fork for epoch %d", epoch)
+}
+
+// SigningRoot calculates the signing root of the given header.
+func (f Forks) SigningRoot(epoch uint64, root common.Hash) (common.Hash, error) {
+ domain, err := f.domain(epoch)
+ if err != nil {
+ return common.Hash{}, err
+ }
+ var (
+ signingRoot common.Hash
+ hasher = sha256.New()
+ )
+ hasher.Write(root[:])
+ hasher.Write(domain[:])
+ hasher.Sum(signingRoot[:0])
+
+ return signingRoot, nil
+}
+
+func (f Forks) Len() int { return len(f) }
+func (f Forks) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
+func (f Forks) Less(i, j int) bool {
+ if f[i].Epoch != f[j].Epoch {
+ return f[i].Epoch < f[j].Epoch
+ }
+ return f[i].knownIndex < f[j].knownIndex
+}
diff --git a/beacon/params/networks.go b/beacon/params/networks.go
new file mode 100644
index 0000000000..5b00b27953
--- /dev/null
+++ b/beacon/params/networks.go
@@ -0,0 +1,56 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package params
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+)
+
+var (
+ MainnetLightConfig = (&ChainConfig{
+ GenesisValidatorsRoot: common.HexToHash("0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95"),
+ GenesisTime: 1606824023,
+ Checkpoint: common.HexToHash("0x6509b691f4de4f7b083f2784938fd52f0e131675432b3fd85ea549af9aebd3d0"),
+ }).
+ AddFork("GENESIS", 0, []byte{0, 0, 0, 0}).
+ AddFork("ALTAIR", 74240, []byte{1, 0, 0, 0}).
+ AddFork("BELLATRIX", 144896, []byte{2, 0, 0, 0}).
+ AddFork("CAPELLA", 194048, []byte{3, 0, 0, 0}).
+ AddFork("DENEB", 269568, []byte{4, 0, 0, 0})
+
+ SepoliaLightConfig = (&ChainConfig{
+ GenesisValidatorsRoot: common.HexToHash("0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078"),
+ GenesisTime: 1655733600,
+ Checkpoint: common.HexToHash("0x456e85f5608afab3465a0580bff8572255f6d97af0c5f939e3f7536b5edb2d3f"),
+ }).
+ AddFork("GENESIS", 0, []byte{144, 0, 0, 105}).
+ AddFork("ALTAIR", 50, []byte{144, 0, 0, 112}).
+ AddFork("BELLATRIX", 100, []byte{144, 0, 0, 113}).
+ AddFork("CAPELLA", 56832, []byte{144, 0, 0, 114}).
+ AddFork("DENEB", 132608, []byte{144, 0, 0, 115})
+
+ HoleskyLightConfig = (&ChainConfig{
+ GenesisValidatorsRoot: common.HexToHash("0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1"),
+ GenesisTime: 1695902400,
+ Checkpoint: common.HexToHash("0x6456a1317f54d4b4f2cb5bc9d153b5af0988fe767ef0609f0236cf29030bcff7"),
+ }).
+ AddFork("GENESIS", 0, []byte{1, 1, 112, 0}).
+ AddFork("ALTAIR", 0, []byte{2, 1, 112, 0}).
+ AddFork("BELLATRIX", 0, []byte{3, 1, 112, 0}).
+ AddFork("CAPELLA", 256, []byte{4, 1, 112, 0}).
+ AddFork("DENEB", 29696, []byte{5, 1, 112, 0})
+)
diff --git a/cmd/blsync/main.go b/cmd/blsync/main.go
index 6a35e9d16a..d74e1496cd 100644
--- a/cmd/blsync/main.go
+++ b/cmd/blsync/main.go
@@ -70,7 +70,7 @@ func main() {
func sync(ctx *cli.Context) error {
// set up blsync
- client := blsync.NewClient(ctx)
+ client := blsync.NewClient(utils.MakeBeaconLightConfig(ctx))
client.SetEngineRPC(makeRPCClient(ctx))
client.Start()
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index 842c1c2347..17ed9fb606 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -240,7 +240,7 @@ func makeFullNode(ctx *cli.Context) *node.Node {
// Start blsync mode.
srv := rpc.NewServer()
srv.RegisterName("engine", catalyst.NewConsensusAPI(eth))
- blsyncer := blsync.NewClient(ctx)
+ blsyncer := blsync.NewClient(utils.MakeBeaconLightConfig(ctx))
blsyncer.SetEngineRPC(rpc.DialInProc(srv))
stack.RegisterLifecycle(blsyncer)
} else {
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index c788b85089..4eef66ebc6 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -40,6 +40,7 @@ import (
bparams "github.com/ethereum/go-ethereum/beacon/params"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/fdlimit"
+ "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
@@ -1889,6 +1890,81 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
}
}
+// MakeBeaconLightConfig constructs a beacon light client config based on the
+// related command line flags.
+func MakeBeaconLightConfig(ctx *cli.Context) bparams.ClientConfig {
+ var config bparams.ClientConfig
+ customConfig := ctx.IsSet(BeaconConfigFlag.Name)
+ CheckExclusive(ctx, MainnetFlag, SepoliaFlag, HoleskyFlag, BeaconConfigFlag)
+ switch {
+ case ctx.Bool(MainnetFlag.Name):
+ config.ChainConfig = *bparams.MainnetLightConfig
+ case ctx.Bool(SepoliaFlag.Name):
+ config.ChainConfig = *bparams.SepoliaLightConfig
+ case ctx.Bool(HoleskyFlag.Name):
+ config.ChainConfig = *bparams.HoleskyLightConfig
+ default:
+ if !customConfig {
+ config.ChainConfig = *bparams.MainnetLightConfig
+ }
+ }
+ // Genesis root and time should always be specified together with custom chain config
+ if customConfig {
+ if !ctx.IsSet(BeaconGenesisRootFlag.Name) {
+ Fatalf("Custom beacon chain config is specified but genesis root is missing")
+ }
+ if !ctx.IsSet(BeaconGenesisTimeFlag.Name) {
+ Fatalf("Custom beacon chain config is specified but genesis time is missing")
+ }
+ if !ctx.IsSet(BeaconCheckpointFlag.Name) {
+ Fatalf("Custom beacon chain config is specified but checkpoint is missing")
+ }
+ config.ChainConfig = bparams.ChainConfig{
+ GenesisTime: ctx.Uint64(BeaconGenesisTimeFlag.Name),
+ }
+ if c, err := hexutil.Decode(ctx.String(BeaconGenesisRootFlag.Name)); err == nil && len(c) <= 32 {
+ copy(config.GenesisValidatorsRoot[:len(c)], c)
+ } else {
+ Fatalf("Invalid hex string", "beacon.genesis.gvroot", ctx.String(BeaconGenesisRootFlag.Name), "error", err)
+ }
+ configFile := ctx.String(BeaconConfigFlag.Name)
+ if err := config.ChainConfig.LoadForks(configFile); err != nil {
+ Fatalf("Could not load beacon chain config", "file", configFile, "error", err)
+ }
+ log.Info("Using custom beacon chain config", "file", configFile)
+ } else {
+ if ctx.IsSet(BeaconGenesisRootFlag.Name) {
+ Fatalf("Genesis root is specified but custom beacon chain config is missing")
+ }
+ if ctx.IsSet(BeaconGenesisTimeFlag.Name) {
+ Fatalf("Genesis time is specified but custom beacon chain config is missing")
+ }
+ }
+ // Checkpoint is required with custom chain config and is optional with pre-defined config
+ if ctx.IsSet(BeaconCheckpointFlag.Name) {
+ if c, err := hexutil.Decode(ctx.String(BeaconCheckpointFlag.Name)); err == nil && len(c) <= 32 {
+ copy(config.Checkpoint[:len(c)], c)
+ } else {
+ Fatalf("Invalid hex string", "beacon.checkpoint", ctx.String(BeaconCheckpointFlag.Name), "error", err)
+ }
+ }
+ config.Apis = ctx.StringSlice(BeaconApiFlag.Name)
+ if config.Apis == nil {
+ Fatalf("Beacon node light client API URL not specified")
+ }
+ config.CustomHeader = make(map[string]string)
+ for _, s := range ctx.StringSlice(BeaconApiHeaderFlag.Name) {
+ kv := strings.Split(s, ":")
+ if len(kv) != 2 {
+ Fatalf("Invalid custom API header entry: %s", s)
+ }
+ config.CustomHeader[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
+ }
+ config.Threshold = ctx.Int(BeaconThresholdFlag.Name)
+ config.NoFilter = ctx.Bool(BeaconNoFilterFlag.Name)
+ return config
+}
+
// SetDNSDiscoveryDefaults configures DNS discovery with the given URL if
// no URLs are set.
func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) {