From 6fefa6e81f217a88d90afd55fb457be3978ac74d Mon Sep 17 00:00:00 2001 From: jeff <113397187+cyberhorsey@users.noreply.github.com> Date: Fri, 16 Feb 2024 08:01:34 -0800 Subject: [PATCH] feat(prover): additional startup info for guardian prover (#552) Co-authored-by: David --- cmd/flags/prover.go | 12 ++++++ prover/config.go | 15 +++++++ prover/config_test.go | 8 ++++ .../guardian_prover_sender/guardian_prover.go | 43 ++++++++++++++----- prover/guardian_prover_sender/interface.go | 10 ++++- prover/prover.go | 20 ++++++++- prover/prover_test.go | 2 + 7 files changed, 96 insertions(+), 14 deletions(-) diff --git a/cmd/flags/prover.go b/cmd/flags/prover.go index aadf1b43d..3a9abd766 100644 --- a/cmd/flags/prover.go +++ b/cmd/flags/prover.go @@ -190,6 +190,16 @@ var ( Value: false, Category: proverCategory, } + L1NodeVersion = &cli.StringFlag{ + Name: "prover.l1NodeVersion", + Usage: "Version or tag or the L1 Node Version used as an L1 RPC Url by this guardian prover", + Category: proverCategory, + } + L2NodeVersion = &cli.StringFlag{ + Name: "prover.l2NodeVersion", + Usage: "Version or tag or the L2 Node Version used as an L2 RPC Url by this guardian prover", + Category: proverCategory, + } ) // ProverFlags All prover flags. @@ -227,4 +237,6 @@ var ProverFlags = MergeFlags(CommonFlags, []cli.Flag{ DatabaseCacheSize, ProverAssignmentHookAddress, Allowance, + L1NodeVersion, + L2NodeVersion, }) diff --git a/prover/config.go b/prover/config.go index f0917f6e6..cdc4306f1 100644 --- a/prover/config.go +++ b/prover/config.go @@ -2,6 +2,7 @@ package prover import ( "crypto/ecdsa" + "errors" "fmt" "math/big" "net/url" @@ -57,6 +58,8 @@ type Config struct { Allowance *big.Int GuardianProverHealthCheckServerEndpoint *url.URL RaikoHostEndpoint string + L1NodeVersion string + L2NodeVersion string } // NewConfigFromCliContext creates a new config instance from command line flags. @@ -114,9 +117,19 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) { if err := c.Set(flags.ProveUnassignedBlocks.Name, "true"); err != nil { return nil, err } + if err := c.Set(flags.ContesterMode.Name, "true"); err != nil { return nil, err } + + // l1 and l2 node version flags are required only if guardian prover + if !c.IsSet(flags.L1NodeVersion.Name) { + return nil, errors.New("L1NodeVersion is required if guardian prover is set") + } + + if !c.IsSet(flags.L2NodeVersion.Name) { + return nil, errors.New("L2NodeVersion is required if guardian prover is set") + } } if !c.IsSet(flags.GuardianProver.Name) && !c.IsSet(flags.RaikoHostEndpoint.Name) { @@ -165,5 +178,7 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) { DatabasePath: c.String(flags.DatabasePath.Name), DatabaseCacheSize: c.Uint64(flags.DatabaseCacheSize.Name), Allowance: allowance, + L1NodeVersion: c.String(flags.L1NodeVersion.Name), + L2NodeVersion: c.String(flags.L2NodeVersion.Name), }, nil } diff --git a/prover/config_test.go b/prover/config_test.go index 1c1732d8b..d8af0a843 100644 --- a/prover/config_test.go +++ b/prover/config_test.go @@ -15,8 +15,10 @@ import ( var ( l1WsEndpoint = os.Getenv("L1_NODE_WS_ENDPOINT") l1HttpEndpoint = os.Getenv("L1_NODE_HTTP_ENDPOINT") + l1NodeVersion = "1.0.0" l2WsEndpoint = os.Getenv("L2_EXECUTION_ENGINE_WS_ENDPOINT") l2HttpEndpoint = os.Getenv("L2_EXECUTION_ENGINE_HTTP_ENDPOINT") + l2NodeVersion = "0.1.0" taikoL1 = os.Getenv("TAIKO_L1_ADDRESS") taikoL2 = os.Getenv("TAIKO_L2_ADDRESS") allowance = "10000000000000000000000000000000000000000000000000" @@ -50,6 +52,8 @@ func (s *ProverTestSuite) TestNewConfigFromCliContextGuardianProver() { s.Equal(uint64(minTierFee), c.MinPseZkevmTierFee.Uint64()) s.Equal(uint64(3), c.ProveBlockTxReplacementMultiplier) s.Equal(uint64(256), c.ProveBlockMaxTxGasTipCap.Uint64()) + s.Equal(c.L1NodeVersion, l1NodeVersion) + s.Equal(c.L2NodeVersion, l2NodeVersion) s.Nil(new(Prover).InitFromCli(context.Background(), ctx)) s.True(c.ProveUnassignedBlocks) s.Equal("dbPath", c.DatabasePath) @@ -88,6 +92,8 @@ func (s *ProverTestSuite) TestNewConfigFromCliContextGuardianProver() { "--" + flags.DatabaseCacheSize.Name, "128", "--" + flags.MaxProposedIn.Name, "100", "--" + flags.Allowance.Name, allowance, + "--" + flags.L1NodeVersion.Name, l1NodeVersion, + "--" + flags.L2NodeVersion.Name, l2NodeVersion, })) } @@ -129,6 +135,8 @@ func (s *ProverTestSuite) SetupApp() *cli.App { &cli.StringFlag{Name: flags.ProverAssignmentHookAddress.Name}, &cli.StringFlag{Name: flags.Allowance.Name}, &cli.StringFlag{Name: flags.ContesterMode.Name}, + &cli.StringFlag{Name: flags.L1NodeVersion.Name}, + &cli.StringFlag{Name: flags.L2NodeVersion.Name}, } app.Action = func(ctx *cli.Context) error { _, err := NewConfigFromCliContext(ctx) diff --git a/prover/guardian_prover_sender/guardian_prover.go b/prover/guardian_prover_sender/guardian_prover.go index bff8b34db..b3df0a21b 100644 --- a/prover/guardian_prover_sender/guardian_prover.go +++ b/prover/guardian_prover_sender/guardian_prover.go @@ -24,6 +24,8 @@ import ( type healthCheckReq struct { ProverAddress string `json:"prover"` HeartBeatSignature []byte `json:"heartBeatSignature"` + LatestL1Block uint64 `json:"latestL1Block"` + LatestL2Block uint64 `json:"latestL2Block"` } // signedBlockReq is the request body sent to the health check server when a block is signed. @@ -36,10 +38,12 @@ type signedBlockReq struct { // startupReq is the request body send to the health check server when the guardian prover starts up. type startupReq struct { - ProverAddress string `json:"prover"` - Version string `json:"version"` - Revision string `json:"revision"` - Signature []byte `json:"signature"` + ProverAddress string `json:"prover"` + GuardianVersion string `json:"guardianVersion"` + L1NodeVersion string `json:"l1NodeVersion"` + L2NodeVersion string `json:"l2NodeVersion"` + Revision string `json:"revision"` + Signature []byte `json:"signature"` } // GuardianProverBlockSender is responsible for signing and sending known blocks to the health check server. @@ -118,7 +122,13 @@ func (s *GuardianProverBlockSender) SignAndSendBlock(ctx context.Context, blockI ) } -func (s *GuardianProverBlockSender) SendStartup(ctx context.Context, revision string, version string) error { +func (s *GuardianProverBlockSender) SendStartup( + ctx context.Context, + revision string, + version string, + l1NodeVersion string, + l2NodeVersion string, +) error { if s.healthCheckServerEndpoint == nil { log.Info("No health check server endpoint set, returning early") return nil @@ -128,17 +138,22 @@ func (s *GuardianProverBlockSender) SendStartup(ctx context.Context, revision st crypto.Keccak256Hash( s.proverAddress.Bytes(), []byte(revision), - []byte(version)).Bytes(), + []byte(version), + []byte(l1NodeVersion), + []byte(l2NodeVersion), + ).Bytes(), s.privateKey) if err != nil { return err } req := &startupReq{ - Revision: revision, - Version: version, - ProverAddress: s.proverAddress.Hex(), - Signature: sig, + Revision: revision, + GuardianVersion: version, + L1NodeVersion: l1NodeVersion, + L2NodeVersion: l2NodeVersion, + ProverAddress: s.proverAddress.Hex(), + Signature: sig, } if err := s.post(ctx, "startup", req); err != nil { @@ -242,7 +257,11 @@ func (s *GuardianProverBlockSender) Close() error { } // SendHeartbeat sends a heartbeat to the health check server. -func (s *GuardianProverBlockSender) SendHeartbeat(ctx context.Context) error { +func (s *GuardianProverBlockSender) SendHeartbeat( + ctx context.Context, + latestL1Block uint64, + latestL2Block uint64, +) error { sig, err := crypto.Sign(crypto.Keccak256Hash([]byte("HEART_BEAT")).Bytes(), s.privateKey) if err != nil { return err @@ -251,6 +270,8 @@ func (s *GuardianProverBlockSender) SendHeartbeat(ctx context.Context) error { req := &healthCheckReq{ HeartBeatSignature: sig, ProverAddress: s.proverAddress.Hex(), + LatestL1Block: latestL1Block, + LatestL2Block: latestL2Block, } if err := s.post(ctx, "healthCheck", req); err != nil { diff --git a/prover/guardian_prover_sender/interface.go b/prover/guardian_prover_sender/interface.go index aa4d4503d..6776b5b7d 100644 --- a/prover/guardian_prover_sender/interface.go +++ b/prover/guardian_prover_sender/interface.go @@ -7,11 +7,17 @@ import ( type BlockSigner interface { SignAndSendBlock(ctx context.Context, blockID *big.Int) error - SendStartup(ctx context.Context, revision string, version string) error + SendStartup( + ctx context.Context, + revision string, + version string, + l1NodeVersion string, + l2NodeVersion string, + ) error } type Heartbeater interface { - SendHeartbeat(ctx context.Context) error + SendHeartbeat(ctx context.Context, latestL1Block uint64, latestL2Block uint64) error } // BlockSenderHeartbeater defines an interface that communicates with a central Guardian Prover server, diff --git a/prover/prover.go b/prover/prover.go index 9ab0e7e1b..d9337eb66 100644 --- a/prover/prover.go +++ b/prover/prover.go @@ -405,6 +405,8 @@ func (p *Prover) Start() error { p.ctx, version.CommitVersion(), version.CommitVersion(), + p.cfg.L1NodeVersion, + p.cfg.L2NodeVersion, ); err != nil { log.Crit("Failed to send guardian prover startup", "error", err) } @@ -1321,7 +1323,23 @@ func (p *Prover) heartbeatInterval(ctx context.Context) { case <-p.ctx.Done(): return case <-t.C: - if err := p.guardianProverSender.SendHeartbeat(ctx); err != nil { + latestL1Block, err := p.rpc.L1.BlockNumber(ctx) + if err != nil { + log.Error("guardian prover error getting latestL1Block", err) + continue + } + + latestL2Block, err := p.rpc.L2.BlockNumber(ctx) + if err != nil { + log.Error("guardian prover error getting latestL2Block", err) + continue + } + + if err := p.guardianProverSender.SendHeartbeat( + ctx, + latestL1Block, + latestL2Block, + ); err != nil { log.Error("Failed to send guardian prover heartbeat", "error", err) } } diff --git a/prover/prover_test.go b/prover/prover_test.go index cd34fe19a..abdce4723 100644 --- a/prover/prover_test.go +++ b/prover/prover_test.go @@ -502,6 +502,8 @@ func (s *ProverTestSuite) initProver( Allowance: allowance, RPCTimeout: 3 * time.Second, BackOffMaxRetrys: 3, + L1NodeVersion: "1.0.0", + L2NodeVersion: "0.1.0", })) p.srv = testutils.NewTestProverServer( &s.ClientTestSuite,