mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
all: integrate blsync into geth cmd
This commit is contained in:
parent
ca0feab9d3
commit
b3289536f1
11 changed files with 181 additions and 233 deletions
|
|
@ -40,6 +40,7 @@ type LightClient struct {
|
||||||
store *store
|
store *store
|
||||||
|
|
||||||
chainHeadFeed event.Feed
|
chainHeadFeed event.Feed
|
||||||
|
quitCh chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bootstrap retrieves a light client bootstrap and authenticates it against the
|
// Bootstrap retrieves a light client bootstrap and authenticates it against the
|
||||||
|
|
@ -68,6 +69,7 @@ func Bootstrap(ctx context.Context, server string, root common.Hash) (*LightClie
|
||||||
optimistic: &bs.Header.Header,
|
optimistic: &bs.Header.Header,
|
||||||
finalized: &bs.Header.Header,
|
finalized: &bs.Header.Header,
|
||||||
},
|
},
|
||||||
|
quitCh: make(chan struct{}),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,22 +92,25 @@ func (c *LightClient) Finalized() *types.Header {
|
||||||
|
|
||||||
// Start executes the main active loop of the light client which drives the
|
// Start executes the main active loop of the light client which drives the
|
||||||
// underlying light client store.
|
// underlying light client store.
|
||||||
func (c *LightClient) Start() {
|
func (c *LightClient) Start() error {
|
||||||
log.Info("beacon light client starting")
|
|
||||||
var (
|
var (
|
||||||
ticker = time.NewTicker(params.SlotLength * time.Second)
|
ticker = time.NewTicker(params.SlotLength * time.Second)
|
||||||
lastFinality = time.Now()
|
lastFinality = time.Now()
|
||||||
)
|
)
|
||||||
for ; ; <-ticker.C {
|
for {
|
||||||
|
select {
|
||||||
|
case <-c.quitCh:
|
||||||
|
return nil
|
||||||
|
case <-ticker.C:
|
||||||
if c.store.next == nil {
|
if c.store.next == nil {
|
||||||
log.Debug("fetching committee update", "period", c.store.finalizedPeriod())
|
log.Debug("Fetching committee update", "period", c.store.finalizedPeriod())
|
||||||
updates, err := c.beacon.GetRangeUpdate(c.store.finalizedPeriod(), 1)
|
updates, err := c.beacon.GetRangeUpdate(c.store.finalizedPeriod(), 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("failed to fetch next committee", "err", err)
|
log.Error("Failed to fetch next committee", "err", err)
|
||||||
} else {
|
} else {
|
||||||
for _, update := range updates {
|
for _, update := range updates {
|
||||||
if err := c.store.Insert(update); err != nil {
|
if err := c.store.Insert(update); err != nil {
|
||||||
log.Error("failed to insert committee update", "err", err)
|
log.Error("Failed to insert committee update", "err", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -117,38 +122,42 @@ func (c *LightClient) Start() {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if time.Since(lastFinality) > time.Minute*5 {
|
if time.Since(lastFinality) > time.Minute*5 {
|
||||||
log.Trace("fetching finality update")
|
|
||||||
lastFinality = time.Now()
|
lastFinality = time.Now()
|
||||||
update, err = c.beacon.GetFinalityUpdate()
|
update, err = c.beacon.GetFinalityUpdate()
|
||||||
} else {
|
} else {
|
||||||
log.Trace("fetching optimistic update")
|
|
||||||
update, err = c.beacon.GetOptimisticUpdate()
|
update, err = c.beacon.GetOptimisticUpdate()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("failed to retrieve update", "err", err)
|
log.Error("Failed to retrieve update", "err", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Trace("got update", "slot", update.AttestedHeader.Slot, "root", update.AttestedHeader.Hash(), "sigslot", update.SignatureSlot, "period", update.AttestedHeader.SyncPeriod(), "hasFinalized", update.FinalizedHeader != nil, "hasNext", update.NextSyncCommittee != nil)
|
log.Trace("New beacon update", "slot", update.AttestedHeader.Slot, "root", update.AttestedHeader.Hash(), "sigslot", update.SignatureSlot, "period", update.AttestedHeader.SyncPeriod(), "hasFinalized", update.FinalizedHeader != nil, "hasNext", update.NextSyncCommittee != nil)
|
||||||
if err := c.store.Insert(update); err != nil {
|
if err := c.store.Insert(update); err != nil {
|
||||||
log.Error("failed to insert update", "err", err)
|
log.Error("Failed to insert update", "err", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
head := update.AttestedHeader
|
head := update.AttestedHeader
|
||||||
log.Info("beacon head updated", "slot", head.Slot, "root", head.Hash(), "finalized", c.Finalized().Hash(), "signers", update.SyncAggregate.SignerCount())
|
log.Info("Beacon head updated", "slot", head.Slot, "root", head.Hash(), "finalized", c.Finalized().Hash(), "signers", update.SyncAggregate.SignerCount())
|
||||||
|
|
||||||
// Fetch full execution payload from beacon provider and send to head feed.
|
// Fetch full execution payload from beacon provider and send to head feed.
|
||||||
data, err := c.getExecutableData(head.Hash())
|
data, err := c.fetchExecutableData(head.Hash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("failed to insert update", "err", err)
|
log.Error("Failed to insert update", "err", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.chainHeadFeed.Send(ChainHeadEvent{Data: data})
|
c.chainHeadFeed.Send(ChainHeadEvent{Data: data})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// getExecutableData retrieves the full beacon block associated with the beacon
|
func (c *LightClient) Stop() error {
|
||||||
|
close(c.quitCh)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchExecutableData retrieves the full beacon block associated with the beacon
|
||||||
// block root and returns the inner execution payload.
|
// block root and returns the inner execution payload.
|
||||||
func (c *LightClient) getExecutableData(head common.Hash) (*engine.ExecutableData, error) {
|
func (c *LightClient) fetchExecutableData(head common.Hash) (*engine.ExecutableData, error) {
|
||||||
block, err := c.beacon.GetBlock(head)
|
block, err := c.beacon.GetBlock(head)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get execution payload: %w", err)
|
return nil, fmt.Errorf("failed to get execution payload: %w", err)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/beacon/params"
|
"github.com/ethereum/go-ethereum/beacon/params"
|
||||||
"github.com/ethereum/go-ethereum/beacon/types"
|
"github.com/ethereum/go-ethereum/beacon/types"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -71,7 +70,6 @@ func (s *store) validate(update *types.LightClientUpdate) error {
|
||||||
)
|
)
|
||||||
// Verify update does not skip a sync committee.
|
// Verify update does not skip a sync committee.
|
||||||
if updatePeriod != storedPeriod && (s.next == nil || updatePeriod != storedPeriod+1) {
|
if updatePeriod != storedPeriod && (s.next == nil || updatePeriod != storedPeriod+1) {
|
||||||
log.Error("update not from current or next sync committee", "stored", storedPeriod, "update", updatePeriod)
|
|
||||||
return errWrongPeriod
|
return errWrongPeriod
|
||||||
}
|
}
|
||||||
if !(update.AttestedHeader.Slot > s.finalized.Slot || update.NextSyncCommittee != nil) {
|
if !(update.AttestedHeader.Slot > s.finalized.Slot || update.NextSyncCommittee != nil) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2024 The go-ethereum Authors
|
// copyright 2023 the go-ethereum authors
|
||||||
// This file is part of the go-ethereum library.
|
// This file is part of the go-ethereum library.
|
||||||
//
|
//
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
|
|
||||||
|
|
@ -1,185 +0,0 @@
|
||||||
// Copyright 2023 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/beacon/engine"
|
|
||||||
"github.com/ethereum/go-ethereum/beacon/light"
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/internal/flags"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/node"
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
|
||||||
"github.com/mattn/go-colorable"
|
|
||||||
"github.com/mattn/go-isatty"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var app = &cli.App{
|
|
||||||
Usage: "go-ethereum beacon light sync tool",
|
|
||||||
Action: run,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
EngineApiFlag = &cli.StringFlag{
|
|
||||||
Name: "engine",
|
|
||||||
Usage: "url to execution client engine api",
|
|
||||||
}
|
|
||||||
JwtSecretFlag = &cli.StringFlag{
|
|
||||||
Name: "jwtsecret",
|
|
||||||
Usage: "path to jwt secret used to communicate with execution client",
|
|
||||||
}
|
|
||||||
LightClientServerFlag = &cli.StringFlag{
|
|
||||||
Name: "server",
|
|
||||||
Usage: "server which provides the beacon light client apis",
|
|
||||||
}
|
|
||||||
TrustedBlockRootFlag = &cli.StringFlag{
|
|
||||||
Name: "trusted-root",
|
|
||||||
Usage: "root of trusted block within the weak-subjectivity window",
|
|
||||||
}
|
|
||||||
VerbosityFlag = &cli.IntFlag{
|
|
||||||
Name: "verbosity",
|
|
||||||
Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail",
|
|
||||||
Value: 3,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
app.Flags = flags.Merge([]cli.Flag{
|
|
||||||
EngineApiFlag,
|
|
||||||
JwtSecretFlag,
|
|
||||||
LightClientServerFlag,
|
|
||||||
TrustedBlockRootFlag,
|
|
||||||
VerbosityFlag,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run(ctx *cli.Context) error {
|
|
||||||
// Setup logger.
|
|
||||||
var (
|
|
||||||
usecolor = (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
|
||||||
output = io.Writer(os.Stdout)
|
|
||||||
verbosity = log.FromLegacyLevel(ctx.Int(VerbosityFlag.Name))
|
|
||||||
)
|
|
||||||
if usecolor {
|
|
||||||
output = colorable.NewColorable(os.Stdout)
|
|
||||||
}
|
|
||||||
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(output, verbosity, usecolor)))
|
|
||||||
|
|
||||||
// Start light client.
|
|
||||||
var (
|
|
||||||
root = ctx.String(TrustedBlockRootFlag.Name)
|
|
||||||
engine = makeRPCClient(ctx)
|
|
||||||
server = ctx.String(LightClientServerFlag.Name)
|
|
||||||
)
|
|
||||||
chain, err := light.Bootstrap(context.Background(), server, common.HexToHash(root))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to bootstrap: %v", err)
|
|
||||||
}
|
|
||||||
go chain.Start()
|
|
||||||
|
|
||||||
headCh := make(chan light.ChainHeadEvent)
|
|
||||||
chain.SubscribeChainHeadEvent(headCh)
|
|
||||||
|
|
||||||
// Send new head events to engine api.
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case head := <-headCh:
|
|
||||||
if err := sendUpdate(engine, head.Data, chain.Finalized().Hash()); err != nil {
|
|
||||||
log.Error("unable to send update to execution client", "err", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendUpdate passes the execution payload to execution client and affirms it
|
|
||||||
// with a forck choice updated.
|
|
||||||
func sendUpdate(engine *rpc.Client, ep *engine.ExecutableData, finalized common.Hash) error {
|
|
||||||
if _, err := callNewPayloadV2(engine, ep); err != nil {
|
|
||||||
return fmt.Errorf("failed to send new payload: %w", err)
|
|
||||||
}
|
|
||||||
if _, err := callForkchoiceUpdatedV1(engine, ep.BlockHash, finalized); err != nil {
|
|
||||||
return fmt.Errorf("failed to send forkchoice updated: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeRPCClient(ctx *cli.Context) *rpc.Client {
|
|
||||||
if !ctx.IsSet(EngineApiFlag.Name) {
|
|
||||||
log.Warn("No engine API target specified, performing a dry run")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if !ctx.IsSet(JwtSecretFlag.Name) {
|
|
||||||
exit(fmt.Errorf("JWT secret parameter missing")) // TODO use default if datadir is specified
|
|
||||||
}
|
|
||||||
engineApiUrl, jwtFileName := ctx.String(EngineApiFlag.Name), ctx.String(JwtSecretFlag.Name)
|
|
||||||
var jwtSecret [32]byte
|
|
||||||
if jwt, err := os.ReadFile(jwtFileName); err != nil {
|
|
||||||
utils.Fatalf("Error loading or generating JWT secret: %v", err)
|
|
||||||
} else {
|
|
||||||
copy(jwtSecret[:], common.FromHex(string(jwt)))
|
|
||||||
}
|
|
||||||
auth := node.NewJWTAuth(jwtSecret)
|
|
||||||
cl, err := rpc.DialOptions(context.Background(), engineApiUrl, rpc.WithHTTPAuth(auth))
|
|
||||||
if err != nil {
|
|
||||||
utils.Fatalf("Could not create RPC client: %v", err)
|
|
||||||
}
|
|
||||||
return cl
|
|
||||||
}
|
|
||||||
|
|
||||||
func callNewPayloadV2(client *rpc.Client, ep *engine.ExecutableData) (string, error) {
|
|
||||||
var resp engine.PayloadStatusV1
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
err := client.CallContext(ctx, &resp, "engine_newPayloadV2", ep)
|
|
||||||
cancel()
|
|
||||||
return resp.Status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func callForkchoiceUpdatedV1(client *rpc.Client, headHash, finalizedHash common.Hash) (string, error) {
|
|
||||||
var resp engine.ForkChoiceResponse
|
|
||||||
update := engine.ForkchoiceStateV1{
|
|
||||||
HeadBlockHash: headHash,
|
|
||||||
SafeBlockHash: common.Hash{},
|
|
||||||
FinalizedBlockHash: common.Hash{},
|
|
||||||
}
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
err := client.CallContext(ctx, &resp, "engine_forkchoiceUpdatedV1", update, nil)
|
|
||||||
cancel()
|
|
||||||
return resp.PayloadStatus.Status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func exit(err interface{}) {
|
|
||||||
if err == nil {
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
@ -221,6 +221,9 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
||||||
}
|
}
|
||||||
catalyst.RegisterSimulatedBeaconAPIs(stack, simBeacon)
|
catalyst.RegisterSimulatedBeaconAPIs(stack, simBeacon)
|
||||||
stack.RegisterLifecycle(simBeacon)
|
stack.RegisterLifecycle(simBeacon)
|
||||||
|
} else if ctx.IsSet(utils.BeaconAPIFlag.Name) && ctx.IsSet(utils.BeaconTrustedBlockRootFlag.Name) {
|
||||||
|
blsync := catalyst.NewBlsync(eth)
|
||||||
|
stack.RegisterLifecycle(blsync)
|
||||||
} else {
|
} else {
|
||||||
err := catalyst.Register(stack, eth)
|
err := catalyst.Register(stack, eth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,8 @@ var (
|
||||||
configFileFlag,
|
configFileFlag,
|
||||||
utils.LogDebugFlag,
|
utils.LogDebugFlag,
|
||||||
utils.LogBacktraceAtFlag,
|
utils.LogBacktraceAtFlag,
|
||||||
|
utils.BeaconAPIFlag,
|
||||||
|
utils.BeaconTrustedBlockRootFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabaseFlags)
|
}, utils.NetworkFlags, utils.DatabaseFlags)
|
||||||
|
|
||||||
rpcFlags = []cli.Flag{
|
rpcFlags = []cli.Flag{
|
||||||
|
|
|
||||||
|
|
@ -908,6 +908,18 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
|
||||||
Value: metrics.DefaultConfig.InfluxDBOrganization,
|
Value: metrics.DefaultConfig.InfluxDBOrganization,
|
||||||
Category: flags.MetricsCategory,
|
Category: flags.MetricsCategory,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Beacon light client flags.
|
||||||
|
BeaconAPIFlag = &cli.StringFlag{
|
||||||
|
Name: "beacon.api",
|
||||||
|
Usage: "server which provides the beacon light client apis",
|
||||||
|
Category: flags.BeaconCategory,
|
||||||
|
}
|
||||||
|
BeaconTrustedBlockRootFlag = &cli.StringFlag{
|
||||||
|
Name: "beacon.wss",
|
||||||
|
Usage: "root of trusted block within the weak-subjectivity window",
|
||||||
|
Category: flags.BeaconCategory,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -1842,6 +1854,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
if err := kzg4844.UseCKZG(ctx.String(CryptoKZGFlag.Name) == "ckzg"); err != nil {
|
if err := kzg4844.UseCKZG(ctx.String(CryptoKZGFlag.Name) == "ckzg"); err != nil {
|
||||||
Fatalf("Failed to set KZG library implementation to %s: %v", ctx.String(CryptoKZGFlag.Name), err)
|
Fatalf("Failed to set KZG library implementation to %s: %v", ctx.String(CryptoKZGFlag.Name), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx.IsSet(BeaconAPIFlag.Name) && !ctx.IsSet(BeaconTrustedBlockRootFlag.Name)) || (!ctx.IsSet(BeaconAPIFlag.Name) && ctx.IsSet(BeaconTrustedBlockRootFlag.Name)) {
|
||||||
|
Fatalf("Must set both beacon api flag and beacon trusted block root flag to use beacon light client")
|
||||||
|
}
|
||||||
|
cfg.BeaconAPI = ctx.String(BeaconAPIFlag.Name)
|
||||||
|
cfg.BeaconTrustedBlockRoot = ctx.String(BeaconTrustedBlockRootFlag.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDNSDiscoveryDefaults configures DNS discovery with the given URL if
|
// SetDNSDiscoveryDefaults configures DNS discovery with the given URL if
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
package eth
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
@ -25,6 +26,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
|
|
@ -71,6 +73,7 @@ type Ethereum struct {
|
||||||
txPool *txpool.TxPool
|
txPool *txpool.TxPool
|
||||||
|
|
||||||
blockchain *core.BlockChain
|
blockchain *core.BlockChain
|
||||||
|
beacon *light.LightClient
|
||||||
handler *handler
|
handler *handler
|
||||||
ethDialCandidates enode.Iterator
|
ethDialCandidates enode.Iterator
|
||||||
snapDialCandidates enode.Iterator
|
snapDialCandidates enode.Iterator
|
||||||
|
|
@ -273,6 +276,14 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.BeaconAPI != "" && config.BeaconTrustedBlockRoot != "" {
|
||||||
|
beacon, err := light.Bootstrap(context.Background(), config.BeaconAPI, common.HexToHash(config.BeaconTrustedBlockRoot))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
eth.beacon = beacon
|
||||||
|
}
|
||||||
|
|
||||||
// Start the RPC service
|
// Start the RPC service
|
||||||
eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, networkID)
|
eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, networkID)
|
||||||
|
|
||||||
|
|
@ -476,6 +487,7 @@ func (s *Ethereum) Miner() *miner.Miner { return s.miner }
|
||||||
|
|
||||||
func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager }
|
func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager }
|
||||||
func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain }
|
func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain }
|
||||||
|
func (s *Ethereum) Beacon() *light.LightClient { return s.beacon }
|
||||||
func (s *Ethereum) TxPool() *txpool.TxPool { return s.txPool }
|
func (s *Ethereum) TxPool() *txpool.TxPool { return s.txPool }
|
||||||
func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux }
|
func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux }
|
||||||
func (s *Ethereum) Engine() consensus.Engine { return s.engine }
|
func (s *Ethereum) Engine() consensus.Engine { return s.engine }
|
||||||
|
|
|
||||||
86
eth/catalyst/blsync.go
Normal file
86
eth/catalyst/blsync.go
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
// Copyright 2024 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package catalyst
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/light"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Blsync tracks the head of the beacon chain through the beacon light client
|
||||||
|
// and drives the local node via ConsensusAPI.
|
||||||
|
type Blsync struct {
|
||||||
|
eth *eth.Ethereum
|
||||||
|
engine *ConsensusAPI
|
||||||
|
client *light.LightClient
|
||||||
|
headCh chan light.ChainHeadEvent
|
||||||
|
headSub event.Subscription
|
||||||
|
|
||||||
|
quitCh chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBlsync creates a new beacon light syncer.
|
||||||
|
func NewBlsync(eth *eth.Ethereum) *Blsync {
|
||||||
|
engine := newConsensusAPIWithoutHeartbeat(eth)
|
||||||
|
return &Blsync{
|
||||||
|
eth: eth,
|
||||||
|
engine: engine,
|
||||||
|
client: eth.Beacon(),
|
||||||
|
headCh: make(chan light.ChainHeadEvent, 128),
|
||||||
|
quitCh: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start starts underlying beacon light client and the sync logic for driving
|
||||||
|
// the local node.
|
||||||
|
func (b *Blsync) Start() error {
|
||||||
|
log.Info("Blsync started")
|
||||||
|
b.headSub = b.client.SubscribeChainHeadEvent(b.headCh)
|
||||||
|
go b.client.Start()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-b.quitCh:
|
||||||
|
return nil
|
||||||
|
case head := <-b.headCh:
|
||||||
|
if _, err := b.engine.NewPayloadV2(*head.Data); err != nil {
|
||||||
|
log.Error("failed to send new payload", "err", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
update := engine.ForkchoiceStateV1{
|
||||||
|
HeadBlockHash: head.Data.BlockHash,
|
||||||
|
SafeBlockHash: common.Hash{},
|
||||||
|
FinalizedBlockHash: common.Hash{},
|
||||||
|
}
|
||||||
|
if _, err := b.engine.ForkchoiceUpdatedV1(update, nil); err != nil {
|
||||||
|
log.Error("failed to send forkchoice updated", "err", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop signals to the light client and syncer to exit.
|
||||||
|
func (b *Blsync) Stop() error {
|
||||||
|
b.client.Stop()
|
||||||
|
close(b.quitCh)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -113,6 +113,10 @@ type Config struct {
|
||||||
LightNoPrune bool `toml:",omitempty"` // Whether to disable light chain pruning
|
LightNoPrune bool `toml:",omitempty"` // Whether to disable light chain pruning
|
||||||
LightNoSyncServe bool `toml:",omitempty"` // Whether to serve light clients before syncing
|
LightNoSyncServe bool `toml:",omitempty"` // Whether to serve light clients before syncing
|
||||||
|
|
||||||
|
// Beacon light client options
|
||||||
|
BeaconAPI string
|
||||||
|
BeaconTrustedBlockRoot string
|
||||||
|
|
||||||
// Database options
|
// Database options
|
||||||
SkipBcVersionCheck bool `toml:"-"`
|
SkipBcVersionCheck bool `toml:"-"`
|
||||||
DatabaseHandles int `toml:"-"`
|
DatabaseHandles int `toml:"-"`
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import "github.com/urfave/cli/v2"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
EthCategory = "ETHEREUM"
|
EthCategory = "ETHEREUM"
|
||||||
|
BeaconCategory = "BEACON"
|
||||||
LightCategory = "LIGHT CLIENT"
|
LightCategory = "LIGHT CLIENT"
|
||||||
DevCategory = "DEVELOPER CHAIN"
|
DevCategory = "DEVELOPER CHAIN"
|
||||||
StateCategory = "STATE HISTORY MANAGEMENT"
|
StateCategory = "STATE HISTORY MANAGEMENT"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue