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

Commit

Permalink
feat(prover): add --prover.minEthBalance and `--prover.minTaikoToke…
Browse files Browse the repository at this point in the history
…nBalance` flags (#641)
  • Loading branch information
davidtaikocha authored Mar 17, 2024
1 parent 9cbe4b8 commit 1a7128b
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 8 deletions.
14 changes: 14 additions & 0 deletions cmd/flags/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ var (
Category: proverCategory,
Value: false,
}
MinEthBalance = &cli.Uint64Flag{
Name: "prover.minEthBalance",
Usage: "Minimum ETH balance (in wei) a prover wants to keep",
Category: proverCategory,
Value: 0,
}
MinTaikoTokenBalance = &cli.Uint64Flag{
Name: "prover.minTaikoTokenBalance",
Usage: "Minimum Taiko token balance a prover wants to keep",
Category: proverCategory,
Value: 0,
}
// Tier fee related.
MinOptimisticTierFee = &cli.Uint64Flag{
Name: "minTierFee.optimistic",
Expand Down Expand Up @@ -192,6 +204,8 @@ var ProverFlags = MergeFlags(CommonFlags, []cli.Flag{
MinOptimisticTierFee,
MinSgxTierFee,
MinSgxAndZkVMTierFee,
MinEthBalance,
MinTaikoTokenBalance,
StartingBlockID,
Dummy,
GuardianProver,
Expand Down
2 changes: 2 additions & 0 deletions internal/testutils/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ func (s *ClientTestSuite) NewTestProverServer(
MinOptimisticTierFee: common.Big1,
MinSgxTierFee: common.Big1,
MinSgxAndZkVMTierFee: common.Big1,
MinEthBalance: common.Big1,
MinTaikoTokenBalance: common.Big1,
MaxExpiry: 24 * time.Hour,
TaikoL1Address: common.HexToAddress(os.Getenv("TAIKO_L1_ADDRESS")),
AssignmentHookAddress: common.HexToAddress(os.Getenv("ASSIGNMENT_HOOK_ADDRESS")),
Expand Down
4 changes: 4 additions & 0 deletions prover/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ type Config struct {
MinOptimisticTierFee *big.Int
MinSgxTierFee *big.Int
MinSgxAndZkVMTierFee *big.Int
MinEthBalance *big.Int
MinTaikoTokenBalance *big.Int
MaxExpiry time.Duration
MaxProposedIn uint64
MaxBlockSlippage uint64
Expand Down Expand Up @@ -171,6 +173,8 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) {
MinOptimisticTierFee: new(big.Int).SetUint64(c.Uint64(flags.MinOptimisticTierFee.Name)),
MinSgxTierFee: new(big.Int).SetUint64(c.Uint64(flags.MinSgxTierFee.Name)),
MinSgxAndZkVMTierFee: new(big.Int).SetUint64(c.Uint64(flags.MinSgxAndZkVMTierFee.Name)),
MinEthBalance: new(big.Int).SetUint64(c.Uint64(flags.MinEthBalance.Name)),
MinTaikoTokenBalance: new(big.Int).SetUint64(c.Uint64(flags.MinTaikoTokenBalance.Name)),
MaxExpiry: c.Duration(flags.MaxExpiry.Name),
MaxBlockSlippage: c.Uint64(flags.MaxAcceptableBlockSlippage.Name),
MaxProposedIn: c.Uint64(flags.MaxProposedIn.Name),
Expand Down
2 changes: 2 additions & 0 deletions prover/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ func InitFromConfig(ctx context.Context, p *Prover, cfg *Config) (err error) {
ProverPrivateKey: p.cfg.L1ProverPrivKey,
MinOptimisticTierFee: p.cfg.MinOptimisticTierFee,
MinSgxTierFee: p.cfg.MinSgxTierFee,
MinEthBalance: p.cfg.MinEthBalance,
MinTaikoTokenBalance: p.cfg.MinTaikoTokenBalance,
MaxExpiry: p.cfg.MaxExpiry,
MaxBlockSlippage: p.cfg.MaxBlockSlippage,
TaikoL1Address: p.cfg.TaikoL1Address,
Expand Down
86 changes: 78 additions & 8 deletions prover/server/api.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package server

import (
"context"
"math/big"
"net/http"
"time"

"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"
Expand All @@ -14,6 +16,10 @@ import (
"github.com/taikoxyz/taiko-client/pkg/rpc"
)

const (
rpcTimeout = 1 * time.Minute
)

// @title Taiko Prover Server API
// @version 1.0
// @termsOfService http://swagger.io/terms/
Expand Down Expand Up @@ -100,34 +106,44 @@ func (s *ProverServer) CreateAssignment(c echo.Context) error {
"currentUsedCapacity", len(s.proofSubmissionCh),
)

// 1. Check if the request body is valid.
if req.TxListHash == (common.Hash{}) {
log.Info("Invalid txList hash")
return echo.NewHTTPError(http.StatusUnprocessableEntity, "invalid txList hash")
}

if req.FeeToken != (common.Address{}) {
return echo.NewHTTPError(http.StatusUnprocessableEntity, "only receive ETH")
}

ok, err := rpc.CheckProverBalance(
// 2. Check if the prover has the required minimum on-chain ETH and Taiko token balance.
ok, err := s.checkMinEthAndToken(c.Request().Context())
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, err)
}

if !ok {
return echo.NewHTTPError(http.StatusUnprocessableEntity, "insufficient prover balance")
}

// 3. Check if the prover's token balance is enough to cover the bonds.
if ok, err = rpc.CheckProverBalance(
c.Request().Context(),
s.rpc,
s.proverAddress,
s.assignmentHookAddress,
s.livenessBond,
)
if err != nil {
); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, err)
}

if !ok {
log.Warn(
"Insufficient prover balance, please get more tokens or wait for verification of the blocks you proved",
"Insufficient prover token balance, please get more tokens or wait for verification of the blocks you proved",
"prover", s.proverAddress,
)
return echo.NewHTTPError(http.StatusUnprocessableEntity, "insufficient prover balance")
}

// 4. Check if the proof fee meets prover's minimum requirement for each tier.
for _, tier := range req.TierFees {
if tier.Tier == encoding.TierGuardianID {
continue
Expand Down Expand Up @@ -157,6 +173,7 @@ func (s *ProverServer) CreateAssignment(c echo.Context) error {
}
}

// 5. Check if the expiry is too long.
if req.Expiry > uint64(time.Now().Add(s.maxExpiry).Unix()) {
log.Warn(
"Expiry too long",
Expand All @@ -167,18 +184,18 @@ func (s *ProverServer) CreateAssignment(c echo.Context) error {
return echo.NewHTTPError(http.StatusUnprocessableEntity, "expiry too long")
}

// Check if the prover has any capacity now.
// 6. Check if the prover has any capacity now.
if s.proofSubmissionCh != nil && len(s.proofSubmissionCh) == cap(s.proofSubmissionCh) {
log.Warn("Prover does not have capacity", "capacity", cap(s.proofSubmissionCh))
return echo.NewHTTPError(http.StatusUnprocessableEntity, "prover does not have capacity")
}

// 7. Encode and sign the prover assignment payload.
l1Head, err := s.rpc.L1.BlockNumber(c.Request().Context())
if err != nil {
log.Error("Failed to get L1 block head", "error", err)
return echo.NewHTTPError(http.StatusUnprocessableEntity, err)
}

encoded, err := encoding.EncodeProverAssignmentPayload(
s.protocolConfigs.ChainId,
s.taikoL1Address,
Expand All @@ -200,10 +217,63 @@ func (s *ProverServer) CreateAssignment(c echo.Context) error {
return echo.NewHTTPError(http.StatusInternalServerError, err)
}

// 8. Return the signed payload.
return c.JSON(http.StatusOK, &ProposeBlockResponse{
SignedPayload: signed,
Prover: s.proverAddress,
MaxBlockID: l1Head + s.maxSlippage,
MaxProposedIn: s.maxProposedIn,
})
}

// checkMinEthAndToken checks if the prover has the required minimum on-chain ETH and Taiko token balance.
func (s *ProverServer) checkMinEthAndToken(ctx context.Context) (bool, error) {
ctx, cancel := context.WithTimeout(ctx, rpcTimeout)
defer cancel()

// 1. Check prover's ETH balance.
ethBalance, err := s.rpc.L1.BalanceAt(ctx, s.proverAddress, nil)
if err != nil {
return false, err
}

log.Info(
"Prover's ETH balance",
"balance", ethBalance,
"address", s.proverAddress.Hex(),
)

if ethBalance.Cmp(s.minEthBalance) <= 0 {
log.Warn(
"Prover does not have required minimum on-chain ETH balance",
"providedProver", s.proverAddress.Hex(),
"ethBalance", ethBalance,
"minEthBalance", s.minEthBalance,
)
return false, nil
}

// 2. Check prover's Taiko token balance.
balance, err := s.rpc.TaikoToken.BalanceOf(&bind.CallOpts{Context: ctx}, s.proverAddress)
if err != nil {
return false, err
}

log.Info(
"Prover's Taiko token balance",
"balance", balance.String(),
"address", s.proverAddress.Hex(),
)

if balance.Cmp(s.minTaikoTokenBalance) <= 0 {
log.Warn(
"Prover does not have required on-chain Taiko token balance",
"providedProver", s.proverAddress.Hex(),
"taikoTokenBalance", balance,
"minTaikoTokenBalance", s.minTaikoTokenBalance,
)
return false, nil
}

return true, nil
}
6 changes: 6 additions & 0 deletions prover/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ type ProverServer struct {
minOptimisticTierFee *big.Int
minSgxTierFee *big.Int
minSgxAndZkVMTierFee *big.Int
minEthBalance *big.Int
minTaikoTokenBalance *big.Int
maxExpiry time.Duration
maxSlippage uint64
maxProposedIn uint64
Expand All @@ -54,6 +56,8 @@ type NewProverServerOpts struct {
MinOptimisticTierFee *big.Int
MinSgxTierFee *big.Int
MinSgxAndZkVMTierFee *big.Int
MinEthBalance *big.Int
MinTaikoTokenBalance *big.Int
MaxExpiry time.Duration
MaxBlockSlippage uint64
MaxProposedIn uint64
Expand All @@ -74,6 +78,8 @@ func New(opts *NewProverServerOpts) (*ProverServer, error) {
minOptimisticTierFee: opts.MinOptimisticTierFee,
minSgxTierFee: opts.MinSgxTierFee,
minSgxAndZkVMTierFee: opts.MinSgxAndZkVMTierFee,
minEthBalance: opts.MinEthBalance,
minTaikoTokenBalance: opts.MinTaikoTokenBalance,
maxExpiry: opts.MaxExpiry,
maxProposedIn: opts.MaxProposedIn,
maxSlippage: opts.MaxBlockSlippage,
Expand Down
2 changes: 2 additions & 0 deletions prover/server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ func (s *ProverServerTestSuite) SetupTest() {
MinOptimisticTierFee: common.Big1,
MinSgxTierFee: common.Big1,
MinSgxAndZkVMTierFee: common.Big1,
MinEthBalance: common.Big1,
MinTaikoTokenBalance: common.Big1,
MaxExpiry: time.Hour,
ProofSubmissionCh: make(chan<- proofProducer.ProofRequestBody, 1024),
TaikoL1Address: common.HexToAddress(os.Getenv("TAIKO_L1_ADDRESS")),
Expand Down

0 comments on commit 1a7128b

Please sign in to comment.