Skip to content
This repository has been archived by the owner on May 11, 2024. It is now read-only.

Commit

Permalink
feat(prover): improve prover implementation (#616)
Browse files Browse the repository at this point in the history
Co-authored-by: David <[email protected]>
Co-authored-by: jeff <[email protected]>
Co-authored-by: Gavin Yu <[email protected]>
Co-authored-by: yuguo <[email protected]>
  • Loading branch information
5 people committed Mar 9, 2024
1 parent 077ccf2 commit b7af09c
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 147 deletions.
4 changes: 3 additions & 1 deletion prover/guardian.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ var (
// gurdianProverHeartbeatLoop keeps sending heartbeats to the guardian prover health check server
// on an interval.
func (p *Prover) gurdianProverHeartbeatLoop(ctx context.Context) {
// Only guardian provers need to send heartbeat.
p.wg.Add(1)
defer p.wg.Done()

if !p.IsGuardianProver() {
return
}
Expand Down
1 change: 0 additions & 1 deletion prover/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ func (p *Prover) initProofSubmitters(
producer,
p.proofGenerationCh,
p.cfg.TaikoL2Address,
p.cfg.L1ProverPrivKey,
p.cfg.Graffiti,
sender,
txBuilder,
Expand Down
2 changes: 1 addition & 1 deletion prover/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func (s *ProverTestSuite) TestSetApprovalAmount() {
opts, err := bind.NewKeyedTransactorWithChainID(s.p.proverPrivateKey, s.p.rpc.L1.ChainID)
opts, err := bind.NewKeyedTransactorWithChainID(s.p.cfg.L1ProverPrivKey, s.p.rpc.L1.ChainID)
s.Nil(err)

tx, err := s.p.rpc.TaikoToken.Approve(opts, s.p.cfg.AssignmentHookAddress, common.Big0)
Expand Down
3 changes: 0 additions & 3 deletions prover/proof_submitter/proof_contester.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package submitter

import (
"context"
"crypto/ecdsa"
"math/big"
"strings"

Expand Down Expand Up @@ -32,15 +31,13 @@ type ProofContester struct {
func NewProofContester(
ctx context.Context,
rpcClient *rpc.Client,
proverPrivKey *ecdsa.PrivateKey,
txSender *sender.Sender,
graffiti string,
builder *transaction.ProveBlockTxBuilder,
) (*ProofContester, error) {
sender, err := transaction.NewSender(
ctx,
rpcClient,
proverPrivKey,
txSender,
)
if err != nil {
Expand Down
6 changes: 1 addition & 5 deletions prover/proof_submitter/proof_submitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ package submitter

import (
"context"
"crypto/ecdsa"
"errors"
"fmt"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"

"github.com/taikoxyz/taiko-client/bindings"
Expand Down Expand Up @@ -44,7 +42,6 @@ func New(
proofProducer proofProducer.ProofProducer,
resultCh chan *proofProducer.ProofWithHeader,
taikoL2Address common.Address,
proverPrivKey *ecdsa.PrivateKey,
graffiti string,
txSender *sender.Sender,
builder *transaction.ProveBlockTxBuilder,
Expand All @@ -57,7 +54,6 @@ func New(
proofSender, err := transaction.NewSender(
ctx,
rpcClient,
proverPrivKey,
txSender,
)
if err != nil {
Expand All @@ -71,7 +67,7 @@ func New(
anchorValidator: anchorValidator,
txBuilder: builder,
sender: proofSender,
proverAddress: crypto.PubkeyToAddress(proverPrivKey.PublicKey),
proverAddress: txSender.GetOpts().From,
taikoL2Address: taikoL2Address,
graffiti: rpc.StringToBytes32(graffiti),
}, nil
Expand Down
2 changes: 0 additions & 2 deletions prover/proof_submitter/proof_submitter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ func (s *ProofSubmitterTestSuite) SetupTest() {
&producer.OptimisticProofProducer{},
s.proofCh,
common.HexToAddress(os.Getenv("TAIKO_L2_ADDRESS")),
l1ProverPrivKey,
"test",
sender,
builder,
Expand All @@ -65,7 +64,6 @@ func (s *ProofSubmitterTestSuite) SetupTest() {
s.contester, err = NewProofContester(
context.Background(),
s.RPCClient,
l1ProverPrivKey,
sender,
"test",
builder,
Expand Down
2 changes: 0 additions & 2 deletions prover/proof_submitter/transaction/sender.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package transaction

import (
"context"
"crypto/ecdsa"
"math/big"
"strings"

Expand All @@ -25,7 +24,6 @@ type Sender struct {
func NewSender(
ctx context.Context,
cli *rpc.Client,
proverPrivateKey *ecdsa.PrivateKey,
txSender *sender.Sender,
) (*Sender, error) {
return &Sender{
Expand Down
2 changes: 1 addition & 1 deletion prover/proof_submitter/transaction/sender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (s *TransactionTestSuite) SetupTest() {
txSender, err := sender.NewSender(context.Background(), &sender.Config{}, s.RPCClient.L1, l1ProverPrivKey)
s.Nil(err)

s.sender, err = NewSender(context.Background(), s.RPCClient, l1ProverPrivKey, txSender)
s.sender, err = NewSender(context.Background(), s.RPCClient, txSender)
s.Nil(err)

s.builder = NewProveBlockTxBuilder(s.RPCClient, l1ProverPrivKey)
Expand Down
175 changes: 67 additions & 108 deletions prover/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package prover

import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
"math/big"
Expand Down Expand Up @@ -35,8 +34,7 @@ import (
// Prover keeps trying to prove newly proposed blocks.
type Prover struct {
// Configurations
cfg *Config
proverPrivateKey *ecdsa.PrivateKey
cfg *Config

// Clients
rpc *rpc.Client
Expand Down Expand Up @@ -89,7 +87,9 @@ func (p *Prover) InitFromCli(ctx context.Context, c *cli.Context) error {
func InitFromConfig(ctx context.Context, p *Prover, cfg *Config) (err error) {
p.cfg = cfg
p.ctx = ctx
p.proverPrivateKey = cfg.L1ProverPrivKey

// Initialize state which will be shared by event handlers.
p.sharedState = state.New()

// Initialize state which will be shared by event handlers.
p.sharedState = state.New()
Expand Down Expand Up @@ -152,11 +152,11 @@ func InitFromConfig(ctx context.Context, p *Prover, cfg *Config) (err error) {
senderCfg.MaxRetrys = 0
}

txSender, err := sender.NewSender(p.ctx, senderCfg, p.rpc.L1, p.proverPrivateKey)
txSender, err := sender.NewSender(p.ctx, senderCfg, p.rpc.L1, p.cfg.L1ProverPrivKey)
if err != nil {
return err
}
txBuilder := transaction.NewProveBlockTxBuilder(p.rpc, p.proverPrivateKey)
txBuilder := transaction.NewProveBlockTxBuilder(p.rpc, p.cfg.L1ProverPrivKey)

// Proof submitters
if err := p.initProofSubmitters(p.ctx, txSender, txBuilder); err != nil {
Expand All @@ -167,7 +167,6 @@ func InitFromConfig(ctx context.Context, p *Prover, cfg *Config) (err error) {
p.proofContester, err = proofSubmitter.NewProofContester(
p.ctx,
p.rpc,
p.cfg.L1ProverPrivKey,
txSender,
p.cfg.Graffiti,
txBuilder,
Expand Down Expand Up @@ -253,9 +252,7 @@ func (p *Prover) Start() error {
// eventLoop starts the main loop of Taiko prover.
func (p *Prover) eventLoop() {
p.wg.Add(1)
defer func() {
p.wg.Done()
}()
defer p.wg.Done()

// reqProving requests performing a proving operation, won't block
// if we are already proving.
Expand Down Expand Up @@ -297,35 +294,23 @@ func (p *Prover) eventLoop() {
case <-p.ctx.Done():
return
case proofWithHeader := <-p.proofGenerationCh:
p.submitProofOp(p.ctx, proofWithHeader)
p.withRetry(func() error { return p.submitProofOp(proofWithHeader) })
case req := <-p.proofSubmissionCh:
p.requestProofOp(p.ctx, req.Event, req.Tier)
p.withRetry(func() error { return p.requestProofOp(req.Event, req.Tier) })
case req := <-p.proofContestCh:
p.contestProofOp(p.ctx, req)
p.withRetry(func() error { return p.contestProofOp(req) })
case <-p.proveNotify:
if err := p.proveOp(); err != nil {
log.Error("Prove new blocks error", "error", err)
}
case e := <-blockVerifiedCh:
p.blockVerifiedHandler.Handle(e)
case e := <-transitionProvedCh:
go func() {
if err := p.withRetry(func() error { return p.transitionProvedHandler.Handle(p.ctx, e) }); err != nil {
log.Error("Handle TaikoL1.TransitionProved event error", "error", err)
}
}()
p.withRetry(func() error { return p.transitionProvedHandler.Handle(p.ctx, e) })
case e := <-transitionContestedCh:
go func() {
if err := p.withRetry(func() error { return p.transitionContestedHandler.Handle(p.ctx, e) }); err != nil {
log.Error("Handle TaikoL1.TransitionContested event error", "error", err)
}
}()
p.withRetry(func() error { return p.transitionContestedHandler.Handle(p.ctx, e) })
case e := <-p.assignmentExpiredCh:
go func() {
if err := p.withRetry(func() error { return p.assignmentExpiredHandler.Handle(p.ctx, e) }); err != nil {
log.Error("Handle proof window expired event error", "error", err)
}
}()
p.withRetry(func() error { return p.assignmentExpiredHandler.Handle(p.ctx, e) })
case <-blockProposedCh:
reqProving()
case <-forceProvingTicker.C:
Expand Down Expand Up @@ -376,86 +361,53 @@ func (p *Prover) proveOp() error {
}

// contestProofOp performs a proof contest operation.
func (p *Prover) contestProofOp(ctx context.Context, req *proofSubmitter.ContestRequestBody) {
go func() {
if err := backoff.Retry(func() error {
if err := p.proofContester.SubmitContest(
p.ctx,
req.BlockID,
req.ProposedIn,
req.ParentHash,
req.Meta,
req.Tier,
); err != nil {
log.Error("Request new proof contest error", "blockID", req.BlockID, "error", err)
return err
}
func (p *Prover) contestProofOp(req *proofSubmitter.ContestRequestBody) error {
if err := p.proofContester.SubmitContest(
p.ctx,
req.BlockID,
req.ProposedIn,
req.ParentHash,
req.Meta,
req.Tier,
); err != nil {
log.Error("Request new proof contest error", "blockID", req.BlockID, "error", err)
return err
}

return nil
}, backoff.WithMaxRetries(
backoff.NewConstantBackOff(p.cfg.BackOffRetryInterval),
p.cfg.BackOffMaxRetrys,
)); err != nil {
log.Error("Request new proof contest error", "blockID", req.BlockID, "error", err)
}
}()
return nil
}

// requestProofOp requests a new proof generation operation.
func (p *Prover) requestProofOp(ctx context.Context, e *bindings.TaikoL1ClientBlockProposed, minTier uint16) {
go func() {
if p.IsGuardianProver() {
minTier = encoding.TierGuardianID
func (p *Prover) requestProofOp(e *bindings.TaikoL1ClientBlockProposed, minTier uint16) error {
if p.IsGuardianProver() {
minTier = encoding.TierGuardianID
}
if submitter := p.selectSubmitter(minTier); submitter != nil {
if err := submitter.RequestProof(p.ctx, e); err != nil {
log.Error("Request new proof error", "blockID", e.BlockId, "error", err)
return err
}

if err := backoff.Retry(func() error {
if ctx.Err() != nil {
log.Error("Context is done, aborting requestProofOp", "blockID", e.BlockId, "error", ctx.Err())
return nil
}

if proofSubmitter := p.selectSubmitter(minTier); proofSubmitter != nil {
if err := proofSubmitter.RequestProof(ctx, e); err != nil {
log.Error("Request new proof error", "blockID", e.BlockId, "error", err)
return err
}

return nil
}
return nil
}

log.Error("Failed to find proof submitter", "blockID", e.BlockId, "minTier", minTier)
return nil
}, backoff.WithMaxRetries(
backoff.NewConstantBackOff(p.cfg.BackOffRetryInterval),
p.cfg.BackOffMaxRetrys,
)); err != nil {
log.Error("Request new proof error", "blockID", e.BlockId, "error", err)
}
}()
log.Error("Failed to find proof submitter", "blockID", e.BlockId, "minTier", minTier)
return nil
}

// submitProofOp performs a proof submission operation.
func (p *Prover) submitProofOp(ctx context.Context, proofWithHeader *proofProducer.ProofWithHeader) {
go func() {
if err := backoff.Retry(
func() error {
proofSubmitter := p.getSubmitterByTier(proofWithHeader.Tier)
if proofSubmitter == nil {
return nil
}
func (p *Prover) submitProofOp(proofWithHeader *proofProducer.ProofWithHeader) error {
submitter := p.getSubmitterByTier(proofWithHeader.Tier)
if submitter == nil {
return nil
}

if err := proofSubmitter.SubmitProof(p.ctx, proofWithHeader); err != nil {
log.Error("Submit proof error", "error", err)
return err
}
if err := submitter.SubmitProof(p.ctx, proofWithHeader); err != nil {
log.Error("Submit proof error", "error", err)
return err
}

return nil
},
backoff.WithMaxRetries(backoff.NewConstantBackOff(p.cfg.BackOffRetryInterval), p.cfg.BackOffMaxRetrys),
); err != nil {
log.Error("Submit proof error", "error", err)
}
}()
return nil
}

// Name returns the application name.
Expand Down Expand Up @@ -497,19 +449,26 @@ func (p *Prover) IsGuardianProver() bool {

// ProverAddress returns the current prover account address.
func (p *Prover) ProverAddress() common.Address {
return crypto.PubkeyToAddress(p.proverPrivateKey.PublicKey)
return crypto.PubkeyToAddress(p.cfg.L1ProverPrivKey.PublicKey)
}

// withRetry retries the given function with prover backoff policy.
func (p *Prover) withRetry(f func() error) error {
return backoff.Retry(
func() error {
if p.ctx.Err() != nil {
log.Error("Context is done, aborting", "error", p.ctx.Err())
return nil
}
return f()
},
backoff.WithMaxRetries(backoff.NewConstantBackOff(p.cfg.BackOffRetryInterval), p.cfg.BackOffMaxRetrys),
)
func (p *Prover) withRetry(f func() error) {
p.wg.Add(1)
go func() {
defer p.wg.Done()
err := backoff.Retry(
func() error {
if p.ctx.Err() != nil {
log.Error("Context is done, aborting", "error", p.ctx.Err())
return nil
}
return f()
},
backoff.WithMaxRetries(backoff.NewConstantBackOff(p.cfg.BackOffRetryInterval), p.cfg.BackOffMaxRetrys),
)
if err != nil {
log.Error("Operation failed", "error", err)
}
}()
}
Loading

0 comments on commit b7af09c

Please sign in to comment.