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

Commit

Permalink
feat(prover_selector): check prover's token balance (#406)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidtaikocha authored Sep 24, 2023
1 parent 4ab061f commit 834c0ea
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 39 deletions.
47 changes: 47 additions & 0 deletions pkg/rpc/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,53 @@ func GetProtocolStateVariables(
return &stateVars, nil
}

// CheckProverBalance checks if the prover has the necessary balance either in TaikoL1 token balances
// or, if not, then check allowance, as contract will attempt to burn directly after
// if it doesnt have the available token balance in-contract.
func CheckProverBalance(
ctx context.Context,
rpc *Client,
prover common.Address,
taikoL1Address common.Address,
bond *big.Int,
) (bool, error) {
ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, defaultTimeout)
defer cancel()

depositedBalance, err := rpc.TaikoL1.GetTaikoTokenBalance(&bind.CallOpts{Context: ctxWithTimeout}, prover)
if err != nil {
return false, err
}

if bond.Cmp(depositedBalance) > 0 {
// Check allowance on taiko token contract
allowance, err := rpc.TaikoToken.Allowance(&bind.CallOpts{Context: ctxWithTimeout}, prover, taikoL1Address)
if err != nil {
return false, err
}

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

if bond.Cmp(allowance) > 0 || bond.Cmp(balance) > 0 {
log.Info(
"Assigned prover does not have required on-chain token balance or allowance",
"providedProver", prover.Hex(),
"depositedBalance", depositedBalance.String(),
"taikoTokenBalance", balance,
"allowance", allowance.String(),
"proofBond", bond,
)
return false, nil
}
}

return true, nil
}

// WaitReceipt keeps waiting until the given transaction has an execution
// receipt to know whether it was reverted or not.
func WaitReceipt(
Expand Down
33 changes: 1 addition & 32 deletions proposer/prover_selector/eth_fee_eoa_selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (s *ETHFeeEOASelector) AssignProver(
}

if proverAddress != encoding.OracleProverAddress {
ok, err := s.checkProverBalance(ctx, proverAddress)
ok, err := rpc.CheckProverBalance(ctx, s.rpc, proverAddress, s.taikoL1Address, s.protocolConfigs.ProofBond)
if err != nil {
log.Warn("Failed to check prover balance", "endpoint", endpoint, "error", err)
continue
Expand All @@ -141,37 +141,6 @@ func (s *ETHFeeEOASelector) AssignProver(
return nil, nil, errUnableToFindProver
}

// checkProverBalance checks if the prover has the necessary balance either in TaikoL1 token balances
// or, if not, then check allowance, as contract will attempt to burn directly after
// if it doesnt have the available token balance in-contract.
func (s *ETHFeeEOASelector) checkProverBalance(ctx context.Context, prover common.Address) (bool, error) {
taikoTokenBalance, err := s.rpc.TaikoL1.GetTaikoTokenBalance(&bind.CallOpts{Context: ctx}, prover)
if err != nil {
return false, err
}

if s.protocolConfigs.ProofBond.Cmp(taikoTokenBalance) > 0 {
// Check allowance on taiko token contract
allowance, err := s.rpc.TaikoToken.Allowance(&bind.CallOpts{Context: ctx}, prover, s.taikoL1Address)
if err != nil {
return false, err
}

if s.protocolConfigs.ProofBond.Cmp(allowance) > 0 {
log.Info(
"Assigned prover does not have required on-chain token balance or allowance",
"providedProver", prover.Hex(),
"taikoTokenBalance", taikoTokenBalance.String(),
"allowance", allowance.String(),
"proofBond", s.protocolConfigs.ProofBond,
)
return false, nil
}
}

return true, nil
}

// shuffleProverEndpoints shuffles the current selector's prover endpoints.
func (s *ETHFeeEOASelector) shuffleProverEndpoints() []*url.URL {
rand.Shuffle(len(s.proverEndpoints), func(i, j int) {
Expand Down
7 changes: 0 additions & 7 deletions proposer/prover_selector/eth_fee_eoa_selector_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package selector

import (
"context"
"net/url"
"os"
"testing"
Expand Down Expand Up @@ -43,12 +42,6 @@ func (s *ProverSelectorTestSuite) SetupTest() {
s.Nil(err)
}

func (s *ProverSelectorTestSuite) TestCheckProverBalance() {
ok, err := s.s.checkProverBalance(context.Background(), s.proverAddress)
s.Nil(err)
s.True(ok)
}

func TestProverSelectorTestSuite(t *testing.T) {
suite.Run(t, new(ProverSelectorTestSuite))
}
4 changes: 4 additions & 0 deletions prover/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,10 @@ func InitFromConfig(ctx context.Context, p *Prover, cfg *Config) (err error) {
MinProofFee: p.cfg.MinProofFee,
MaxExpiry: p.cfg.MaxExpiry,
CapacityManager: p.capacityManager,
TaikoL1Address: p.cfg.TaikoL1Address,
Rpc: p.rpc,
Bond: protocolConfigs.ProofBond,
IsOracle: p.cfg.OracleProver,
}
if p.cfg.OracleProver {
proverServerOpts.ProverPrivateKey = p.cfg.OracleProverPrivateKey
Expand Down
17 changes: 17 additions & 0 deletions prover/server/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/labstack/echo/v4"
"github.com/taikoxyz/taiko-client/bindings/encoding"
"github.com/taikoxyz/taiko-client/pkg/rpc"
)

// Status represents the current prover server status.
Expand Down Expand Up @@ -50,6 +51,7 @@ type ProposeBlockResponse struct {
// @Accept json
// @Produce json
// @Success 200 {object} ProposeBlockResponse
// @Failure 422 {string} string "insufficient prover balance"
// @Failure 422 {string} string "proof fee too low"
// @Failure 422 {string} string "expiry too long"
// @Failure 422 {string} string "prover does not have capacity"
Expand All @@ -62,6 +64,21 @@ func (srv *ProverServer) CreateAssignment(c echo.Context) error {

log.Info("Propose block data", "fee", req.Fee, "expiry", req.Expiry)

if !srv.isOracle {
ok, err := rpc.CheckProverBalance(c.Request().Context(), srv.rpc, srv.proverAddress, srv.taikoL1Address, srv.bond)
if 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",
"prover", srv.proverAddress,
)
return echo.NewHTTPError(http.StatusUnprocessableEntity, "insufficient prover balance")
}
}

if req.Fee.Cmp(srv.minProofFee) < 0 {
return echo.NewHTTPError(http.StatusUnprocessableEntity, "proof fee too low")
}
Expand Down
13 changes: 13 additions & 0 deletions prover/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
echo "github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/taikoxyz/taiko-client/pkg/rpc"
capacity "github.com/taikoxyz/taiko-client/prover/capacity_manager"
)

Expand All @@ -35,6 +36,10 @@ type ProverServer struct {
minProofFee *big.Int
maxExpiry time.Duration
capacityManager *capacity.CapacityManager
taikoL1Address common.Address
rpc *rpc.Client
bond *big.Int
isOracle bool
}

// NewProverServerOpts contains all configurations for creating a prover server instance.
Expand All @@ -43,6 +48,10 @@ type NewProverServerOpts struct {
MinProofFee *big.Int
MaxExpiry time.Duration
CapacityManager *capacity.CapacityManager
TaikoL1Address common.Address
Rpc *rpc.Client
Bond *big.Int
IsOracle bool
}

// New creates a new prover server instance.
Expand All @@ -54,6 +63,10 @@ func New(opts *NewProverServerOpts) (*ProverServer, error) {
minProofFee: opts.MinProofFee,
maxExpiry: opts.MaxExpiry,
capacityManager: opts.CapacityManager,
taikoL1Address: opts.TaikoL1Address,
rpc: opts.Rpc,
bond: opts.Bond,
isOracle: opts.IsOracle,
}

srv.echo.HideBanner = true
Expand Down
19 changes: 19 additions & 0 deletions prover/server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
echo "github.com/labstack/echo/v4"
"github.com/phayes/freeport"
"github.com/stretchr/testify/suite"
"github.com/taikoxyz/taiko-client/pkg/rpc"
capacity "github.com/taikoxyz/taiko-client/prover/capacity_manager"
)

Expand All @@ -30,12 +31,30 @@ func (s *ProverServerTestSuite) SetupTest() {
l1ProverPrivKey, err := crypto.ToECDSA(common.Hex2Bytes(os.Getenv("L1_PROVER_PRIVATE_KEY")))
s.Nil(err)

timeout := 5 * time.Second
rpcClient, err := rpc.NewClient(context.Background(), &rpc.ClientConfig{
L1Endpoint: os.Getenv("L1_NODE_WS_ENDPOINT"),
L2Endpoint: os.Getenv("L2_EXECUTION_ENGINE_WS_ENDPOINT"),
TaikoL1Address: common.HexToAddress(os.Getenv("TAIKO_L1_ADDRESS")),
TaikoL2Address: common.HexToAddress(os.Getenv("TAIKO_L2_ADDRESS")),
TaikoTokenAddress: common.HexToAddress(os.Getenv("TAIKO_TOKEN_ADDRESS")),
L2EngineEndpoint: os.Getenv("L2_EXECUTION_ENGINE_AUTH_ENDPOINT"),
JwtSecret: os.Getenv("JWT_SECRET"),
RetryInterval: backoff.DefaultMaxInterval,
Timeout: &timeout,
})
s.Nil(err)

srv := &ProverServer{
echo: echo.New(),
proverPrivateKey: l1ProverPrivKey,
minProofFee: common.Big1,
maxExpiry: 24 * time.Hour,
capacityManager: capacity.New(1024),
taikoL1Address: common.HexToAddress(os.Getenv("TAIKO_L1_ADDRESS")),
rpc: rpcClient,
bond: common.Big0,
isOracle: false,
}

srv.echo.HideBanner = true
Expand Down
8 changes: 8 additions & 0 deletions testutils/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"math/big"
"net/http"
"net/url"
"os"
"time"

"github.com/cenkalti/backoff/v4"
Expand Down Expand Up @@ -192,11 +193,18 @@ func NewTestProverServer(
capacityManager *capacity.CapacityManager,
url *url.URL,
) *server.ProverServer {
protocolConfig, err := s.RpcClient.TaikoL1.GetConfig(nil)
s.Nil(err)

srv, err := server.New(&server.NewProverServerOpts{
ProverPrivateKey: proverPrivKey,
MinProofFee: common.Big1,
MaxExpiry: 24 * time.Hour,
CapacityManager: capacityManager,
TaikoL1Address: common.HexToAddress(os.Getenv("TAIKO_L1_ADDRESS")),
Rpc: s.RpcClient,
Bond: protocolConfig.ProofBond,
IsOracle: true,
})
s.Nil(err)

Expand Down

0 comments on commit 834c0ea

Please sign in to comment.