diff --git a/cmd/lightclient/lightclient/lightclient.go b/cmd/lightclient/lightclient/lightclient.go index 6ab68d6cd9b..f1224d61f93 100644 --- a/cmd/lightclient/lightclient/lightclient.go +++ b/cmd/lightclient/lightclient/lightclient.go @@ -20,10 +20,12 @@ import ( lru "github.com/hashicorp/golang-lru" "github.com/ledgerwatch/erigon-lib/gointerfaces/remote" + "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cl/rpc/consensusrpc" "github.com/ledgerwatch/erigon/cl/utils" + "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/log/v3" ) @@ -39,13 +41,13 @@ type LightClient struct { verbose bool highestSeen uint64 // Highest ETH1 block seen recentHashesCache *lru.Cache + db kv.RwDB sentinel consensusrpc.SentinelClient execution remote.ETHBACKENDServer store *LightClientStore - lastValidated *cltypes.LightClientUpdate } -func NewLightClient(ctx context.Context, genesisConfig *clparams.GenesisConfig, beaconConfig *clparams.BeaconChainConfig, +func NewLightClient(ctx context.Context, db kv.RwDB, genesisConfig *clparams.GenesisConfig, beaconConfig *clparams.BeaconChainConfig, execution remote.ETHBACKENDServer, sentinel consensusrpc.SentinelClient, highestSeen uint64, verbose bool) (*LightClient, error) { recentHashesCache, err := lru.New(maxRecentHashes) @@ -59,6 +61,7 @@ func NewLightClient(ctx context.Context, genesisConfig *clparams.GenesisConfig, execution: execution, verbose: verbose, highestSeen: highestSeen, + db: db, }, err } @@ -67,6 +70,12 @@ func (l *LightClient) Start() { log.Error("No trusted setup") return } + tx, err := l.db.BeginRw(l.ctx) + if err != nil { + log.Error("Could not open MDBX transaction", "err", err) + return + } + defer tx.Rollback() logPeers := time.NewTicker(time.Minute) go l.chainTip.StartLoop() for { @@ -126,18 +135,42 @@ func (l *LightClient) Start() { } // log new validated segment if len(updates) > 0 { - l.lastValidated = updates[len(updates)-1] + lastValidated := updates[len(updates)-1] + // Save to Database + if lastValidated.HasNextSyncCommittee() { + if err := rawdb.WriteLightClientUpdate(tx, lastValidated); err != nil { + log.Warn("Could not write lightclient update to db", "err", err) + } + // Process it as a full LightClientUpdate + } else if lastValidated.IsFinalityUpdate() { + if err := rawdb.WriteLightClientFinalityUpdate(tx, &cltypes.LightClientFinalityUpdate{ + AttestedHeader: lastValidated.AttestedHeader, + FinalizedHeader: lastValidated.FinalizedHeader, + FinalityBranch: lastValidated.FinalityBranch, + SyncAggregate: lastValidated.SyncAggregate, + SignatureSlot: lastValidated.SignatureSlot, + }); err != nil { + log.Warn("Could not write finality lightclient update to db", "err", err) + } + } else if err := rawdb.WriteLightClientOptimisticUpdate(tx, &cltypes.LightClientOptimisticUpdate{ + AttestedHeader: lastValidated.AttestedHeader, + SyncAggregate: lastValidated.SyncAggregate, + SignatureSlot: lastValidated.SignatureSlot, + }); err != nil { + log.Warn("Could not write optimistic lightclient update to db", "err", err) + } + if l.verbose { log.Info("[LightClient] Validated Chain Segments", "elapsed", time.Since(start), "from", updates[0].AttestedHeader.Slot-1, - "to", l.lastValidated.AttestedHeader.Slot) + "to", lastValidated.AttestedHeader.Slot) } prev, curr := l.chainTip.GetLastBlocks() if prev == nil { continue } // Skip if we went out of sync and weird network stuff happen - if prev.Slot != l.lastValidated.AttestedHeader.Slot { + if prev.Slot != lastValidated.AttestedHeader.Slot { continue } // Validate update against block N-1 @@ -146,7 +179,7 @@ func (l *LightClient) Start() { log.Warn("[LightClient] Could not retrive body root of block N-1", "err", err) continue } - if !bytes.Equal(prevRoot[:], l.lastValidated.AttestedHeader.BodyRoot[:]) { + if !bytes.Equal(prevRoot[:], lastValidated.AttestedHeader.BodyRoot[:]) { log.Warn("[LightClient] Could validate block N-1") continue } diff --git a/cmd/lightclient/main.go b/cmd/lightclient/main.go index 2c1f643d67a..74d796691c6 100644 --- a/cmd/lightclient/main.go +++ b/cmd/lightclient/main.go @@ -18,6 +18,7 @@ import ( "fmt" "os" + "github.com/ledgerwatch/erigon-lib/kv/memdb" "github.com/ledgerwatch/log/v3" "github.com/urfave/cli/v2" @@ -50,6 +51,7 @@ func runLightClientNode(cliCtx *cli.Context) error { log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(lcCfg.LogLvl), log.StderrHandler)) log.Info("[LightClient]", "chain", cliCtx.String(flags.LightClientChain.Name)) log.Info("[LightClient] Running lightclient", "cfg", lcCfg) + db := memdb.New() sentinel, err := service.StartSentinelService(&sentinel.SentinelConfig{ IpAddr: lcCfg.Addr, Port: int(lcCfg.Port), @@ -58,7 +60,7 @@ func runLightClientNode(cliCtx *cli.Context) error { NetworkConfig: lcCfg.NetworkCfg, BeaconConfig: lcCfg.BeaconCfg, NoDiscovery: lcCfg.NoDiscovery, - }, &service.ServerConfig{Network: lcCfg.ServerProtocol, Addr: lcCfg.ServerAddr}, nil) + }, db, &service.ServerConfig{Network: lcCfg.ServerProtocol, Addr: lcCfg.ServerAddr}, nil) if err != nil { log.Error("Could not start sentinel", "err", err) } @@ -71,7 +73,7 @@ func runLightClientNode(cliCtx *cli.Context) error { return err } log.Info("Finalized Checkpoint", "Epoch", bs.FinalizedCheckpoint.Epoch) - lc, err := lightclient.NewLightClient(ctx, lcCfg.GenesisCfg, lcCfg.BeaconCfg, nil, sentinel, 0, true) + lc, err := lightclient.NewLightClient(ctx, db, lcCfg.GenesisCfg, lcCfg.BeaconCfg, nil, sentinel, 0, true) if err != nil { log.Error("Could not make Lightclient", "err", err) } diff --git a/cmd/sentinel/main.go b/cmd/sentinel/main.go index cc29efb522c..9b80467113d 100644 --- a/cmd/sentinel/main.go +++ b/cmd/sentinel/main.go @@ -87,7 +87,7 @@ func runSentinelNode(cliCtx *cli.Context) error { NetworkConfig: lcCfg.NetworkCfg, BeaconConfig: lcCfg.BeaconCfg, NoDiscovery: lcCfg.NoDiscovery, - }, &service.ServerConfig{Network: lcCfg.ServerProtocol, Addr: lcCfg.ServerAddr}, nil) + }, nil, &service.ServerConfig{Network: lcCfg.ServerProtocol, Addr: lcCfg.ServerAddr}, nil) if err != nil { log.Error("Could not start sentinel", "err", err) return err diff --git a/cmd/sentinel/sentinel/sentinel.go b/cmd/sentinel/sentinel/sentinel.go index 99c2142f9d5..62f71d2eccf 100644 --- a/cmd/sentinel/sentinel/sentinel.go +++ b/cmd/sentinel/sentinel/sentinel.go @@ -20,6 +20,7 @@ import ( "net" "strings" + "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cl/fork" "github.com/ledgerwatch/erigon/cmd/sentinel/sentinel/communication" @@ -46,6 +47,7 @@ type Sentinel struct { cfg *SentinelConfig peers *peers.Peers MetadataV2 *cltypes.MetadataV2 + db kv.RoDB discoverConfig discover.Config pubsub *pubsub.PubSub @@ -160,10 +162,12 @@ func (s *Sentinel) pubsubOptions() []pubsub.Option { func New( ctx context.Context, cfg *SentinelConfig, + db kv.RoDB, ) (*Sentinel, error) { s := &Sentinel{ ctx: ctx, cfg: cfg, + db: db, } // Setup discovery diff --git a/cmd/sentinel/sentinel/service/start.go b/cmd/sentinel/sentinel/service/start.go index 03cbfc80e0b..069ba51bb51 100644 --- a/cmd/sentinel/sentinel/service/start.go +++ b/cmd/sentinel/sentinel/service/start.go @@ -6,6 +6,7 @@ import ( "net" "time" + "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon/cl/rpc/consensusrpc" "github.com/ledgerwatch/erigon/cmd/sentinel/sentinel" "github.com/ledgerwatch/log/v3" @@ -19,9 +20,9 @@ type ServerConfig struct { Addr string } -func StartSentinelService(cfg *sentinel.SentinelConfig, srvCfg *ServerConfig, creds credentials.TransportCredentials) (consensusrpc.SentinelClient, error) { +func StartSentinelService(cfg *sentinel.SentinelConfig, db kv.RoDB, srvCfg *ServerConfig, creds credentials.TransportCredentials) (consensusrpc.SentinelClient, error) { ctx := context.Background() - sent, err := sentinel.New(context.Background(), cfg) + sent, err := sentinel.New(context.Background(), cfg, db) if err != nil { return nil, err } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index f936c781219..e61ea337d98 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -32,6 +32,7 @@ import ( libcommon "github.com/ledgerwatch/erigon-lib/common/cmp" "github.com/ledgerwatch/erigon-lib/common/dbg" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/common" "github.com/ledgerwatch/erigon/common/dbutils" "github.com/ledgerwatch/erigon/core/types" @@ -1869,3 +1870,45 @@ func ReadVerkleNode(tx kv.RwTx, root common.Hash) (verkle.VerkleNode, error) { } return verkle.ParseNode(encoded, 0, root[:]) } + +func WriteLightClientUpdate(tx kv.RwTx, update *cltypes.LightClientUpdate) error { + key := make([]byte, 4) + binary.BigEndian.PutUint32(key, uint32(update.SignatureSlot/8192)) + + encoded, err := update.MarshalSSZ() + if err != nil { + return err + } + return tx.Put(kv.LightClientUpdates, key, encoded) +} + +func WriteLightClientFinalityUpdate(tx kv.RwTx, update *cltypes.LightClientFinalityUpdate) error { + encoded, err := update.MarshalSSZ() + if err != nil { + return err + } + return tx.Put(kv.LightClient, kv.LightClientFinalityUpdate, encoded) +} + +func WriteLightClientOptimisticUpdate(tx kv.RwTx, update *cltypes.LightClientOptimisticUpdate) error { + encoded, err := update.MarshalSSZ() + if err != nil { + return err + } + return tx.Put(kv.LightClient, kv.LightClientOptimisticUpdate, encoded) +} + +func ReadLightClientUpdate(tx kv.RwTx, period uint32) (*cltypes.LightClientUpdate, error) { + key := make([]byte, 4) + binary.BigEndian.PutUint32(key, period) + + encoded, err := tx.GetOne(kv.LightClientUpdates, key) + if err != nil { + return nil, err + } + update := &cltypes.LightClientUpdate{} + if err = update.UnmarshalSSZ(encoded); err != nil { + return nil, err + } + return update, nil +} diff --git a/eth/backend.go b/eth/backend.go index 877d831617f..cb078d69a07 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -42,6 +42,7 @@ import ( prototypes "github.com/ledgerwatch/erigon-lib/gointerfaces/types" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/kvcache" + "github.com/ledgerwatch/erigon-lib/kv/memdb" "github.com/ledgerwatch/erigon-lib/kv/remotedbserver" libstate "github.com/ledgerwatch/erigon-lib/state" txpool2 "github.com/ledgerwatch/erigon-lib/txpool" @@ -509,12 +510,12 @@ func New(stack *node.Node, config *ethconfig.Config, logger log.Logger) (*Ethere GenesisConfig: genesisCfg, NetworkConfig: networkCfg, BeaconConfig: beaconCfg, - }, &service.ServerConfig{Network: "tcp", Addr: fmt.Sprintf("%s:%d", config.SentinelAddr, config.SentinelPort)}, creds) + }, chainKv, &service.ServerConfig{Network: "tcp", Addr: fmt.Sprintf("%s:%d", config.SentinelAddr, config.SentinelPort)}, creds) if err != nil { return nil, err } - lc, err := lightclient.NewLightClient(ctx, genesisCfg, beaconCfg, ethBackendRPC, client, currentBlockNumber, false) + lc, err := lightclient.NewLightClient(ctx, memdb.New(), genesisCfg, beaconCfg, ethBackendRPC, client, currentBlockNumber, false) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index 16ca16e7be2..9e6ecf41feb 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ledgerwatch/erigon go 1.18 require ( - github.com/ledgerwatch/erigon-lib v0.0.0-20221114105902-10e842853bb4 + github.com/ledgerwatch/erigon-lib v0.0.0-20221115124415-2e09a741f07b github.com/ledgerwatch/erigon-snapshot v1.1.1-0.20221026024915-f6abfe5c120e github.com/ledgerwatch/log/v3 v3.6.0 github.com/ledgerwatch/secp256k1 v1.0.0 diff --git a/go.sum b/go.sum index 6b4b4074952..0a22f890353 100644 --- a/go.sum +++ b/go.sum @@ -558,8 +558,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758 h1:0D5M2HQSGD3PYPwICLl+/9oulQauOuETfgFvhBDffs0= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/ledgerwatch/erigon-lib v0.0.0-20221114105902-10e842853bb4 h1:lUsHWLgwyCV+9G5/g6pML/bwWFwWsEz72PuqrUfm6kw= -github.com/ledgerwatch/erigon-lib v0.0.0-20221114105902-10e842853bb4/go.mod h1:NJybmPjoS9/TbvwTn3bJww3lrxxc7i8Ny+zq2EmDIpg= +github.com/ledgerwatch/erigon-lib v0.0.0-20221115124415-2e09a741f07b h1:LN3EjK0/Iw4o0b9trWFei96GVNeGmGMXJdYdB7m1N2U= +github.com/ledgerwatch/erigon-lib v0.0.0-20221115124415-2e09a741f07b/go.mod h1:NJybmPjoS9/TbvwTn3bJww3lrxxc7i8Ny+zq2EmDIpg= github.com/ledgerwatch/erigon-snapshot v1.1.1-0.20221026024915-f6abfe5c120e h1:VRfm6Ylg0WTnjzFs7mU5qOyZGZTPhnlpwtMPrcD7n+U= github.com/ledgerwatch/erigon-snapshot v1.1.1-0.20221026024915-f6abfe5c120e/go.mod h1:3AuPxZc85jkehh/HA9h8gabv5MSi3kb/ddtzBsTVJFo= github.com/ledgerwatch/log/v3 v3.6.0 h1:JBUSK1epPyutUrz7KYDTcJtQLEHnehECRpKbM1ugy5M=