Skip to content

Commit

Permalink
feat(prover): add --expectedReward flag (taikoxyz#248)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidtaikocha authored May 29, 2023
1 parent 65cfee6 commit 30451a7
Show file tree
Hide file tree
Showing 15 changed files with 174 additions and 133 deletions.
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:
with:
repository: taikoxyz/taiko-mono
path: ${{ env.TAIKO_MONO_DIR }}
ref: alpha-3

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
Expand Down
5 changes: 5 additions & 0 deletions bindings/encoding/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import (
"github.com/ethereum/go-ethereum/core/types"
)

var (
OracleProverAddress = common.HexToAddress("0x0000000000000000000000000000000000000000")
SystemProverAddress = common.HexToAddress("0x0000000000000000000000000000000000000001")
)

type BlockHeader struct {
ParentHash [32]byte
OmmersHash [32]byte
Expand Down
7 changes: 7 additions & 0 deletions cmd/flags/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ var (
Category: proverCategory,
Value: "",
}
ExpectedReward = &cli.Uint64Flag{
Name: "expectedReward",
Usage: "The expected prover reward for each block",
Category: proverCategory,
Value: 100_000_000,
}
)

// All prover flags.
Expand All @@ -98,4 +104,5 @@ var ProverFlags = MergeFlags(CommonFlags, []cli.Flag{
OracleProverPrivateKey,
SystemProverPrivateKey,
Graffiti,
ExpectedReward,
})
68 changes: 68 additions & 0 deletions pkg/rpc/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import (
"context"
"fmt"
"math/big"
"strings"
"time"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
"github.com/taikoxyz/taiko-client/bindings"
"github.com/taikoxyz/taiko-client/bindings/encoding"
)

// GetProtocolStateVariables gets the protocol states from TaikoL1 contract.
Expand Down Expand Up @@ -108,6 +111,71 @@ func GetReceiptsByBlock(ctx context.Context, cli *rpc.Client, block *types.Block
return receipts, nil
}

// NeedNewProof checks whether the L2 block still needs a new proof.
func NeedNewProof(
ctx context.Context,
cli *Client,
id *big.Int,
proverAddress common.Address,
realProofSkipSize *big.Int,
) (bool, error) {
if realProofSkipSize != nil && id.Uint64()%realProofSkipSize.Uint64() != 0 {
log.Info(
"Skipping valid block proof",
"blockID", id.Uint64(),
"skipSize", realProofSkipSize.Uint64(),
)

return false, nil
}

var parent *types.Header
if id.Cmp(common.Big1) == 0 {
header, err := cli.L2.HeaderByNumber(ctx, common.Big0)
if err != nil {
return false, err
}

parent = header
} else {
parentL1Origin, err := cli.WaitL1Origin(ctx, new(big.Int).Sub(id, common.Big1))
if err != nil {
return false, err
}

if parent, err = cli.L2.HeaderByHash(ctx, parentL1Origin.L2BlockHash); err != nil {
return false, err
}
}

fc, err := cli.TaikoL1.GetForkChoice(nil, id, parent.Hash(), uint32(parent.GasUsed))
if err != nil {
if !strings.Contains(encoding.TryParsingCustomError(err).Error(), "L1_FORK_CHOICE_NOT_FOUND") {
return false, encoding.TryParsingCustomError(err)
}

return true, nil
}

if fc.Prover == encoding.OracleProverAddress || fc.Prover == encoding.SystemProverAddress {
return true, nil
}

if proverAddress == fc.Prover {
log.Info("📬 Block's proof has already been submitted by current prover", "blockID", id)
return false, nil
}

log.Info(
"📬 Block's proof has already been submitted by another prover",
"blockID", id,
"prover", fc.Prover,
"provenAt", fc.ProvenAt,
)

return false, nil
}

// SetHead makes a `debug_setHead` RPC call to set the chain's head, should only be used
// for testing purpose.
func SetHead(ctx context.Context, rpc *rpc.Client, headNum *big.Int) error {
Expand Down
2 changes: 2 additions & 0 deletions prover/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type Config struct {
Graffiti string
RandomDummyProofDelayLowerBound *time.Duration
RandomDummyProofDelayUpperBound *time.Duration
ExpectedReward uint64
}

// NewConfigFromCliContext creates a new config instance from command line flags.
Expand Down Expand Up @@ -134,5 +135,6 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) {
Graffiti: c.String(flags.Graffiti.Name),
RandomDummyProofDelayLowerBound: randomDummyProofDelayLowerBound,
RandomDummyProofDelayUpperBound: randomDummyProofDelayUpperBound,
ExpectedReward: c.Uint64(flags.ExpectedReward.Name),
}, nil
}
6 changes: 0 additions & 6 deletions prover/proof_producer/dummy_producer.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ type DummyProofProducer struct {
RandomDummyProofDelayUpperBound *time.Duration
}

func (d *DummyProofProducer) CalcProofTimeTargetDelay(
header *types.Header,
) time.Duration {
return time.Duration(0)
}

// RequestProof implements the ProofProducer interface.
func (d *DummyProofProducer) RequestProof(
ctx context.Context,
Expand Down
2 changes: 0 additions & 2 deletions prover/proof_producer/proof_producer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"
"math/big"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -55,7 +54,6 @@ type ProofProducer interface {
resultCh chan *ProofWithHeader,
) error
Cancel(ctx context.Context, blockID *big.Int) error
CalcProofTimeTargetDelay(header *types.Header) time.Duration
}

func DegreeToCircuitsIdx(degree uint64) (uint16, error) {
Expand Down
11 changes: 2 additions & 9 deletions prover/proof_producer/special_proof_producer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"math/big"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -61,12 +60,6 @@ func NewSpecialProofProducer(
}, nil
}

func (p *SpecialProofProducer) CalcProofTimeTargetDelay(
header *types.Header,
) time.Duration {
return time.Duration(0)
}

// RequestProof implements the ProofProducer interface.
func (p *SpecialProofProducer) RequestProof(
ctx context.Context,
Expand Down Expand Up @@ -119,9 +112,9 @@ func (p *SpecialProofProducer) RequestProof(
// whether a proof can be overwritten or not.
var prover common.Address
if p.isSystemProver {
prover = common.HexToAddress("0x0000000000000000000000000000000000000001")
prover = encoding.SystemProverAddress
} else {
prover = common.HexToAddress("0x0000000000000000000000000000000000000000")
prover = encoding.OracleProverAddress
}
// signature should be done with proof set to nil, verifierID set to 0,
// and prover set to 0 address.
Expand Down
48 changes: 14 additions & 34 deletions prover/proof_producer/zkevm_rpcd_producer.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,36 +95,18 @@ func NewZkevmRpcdProducer(
l1Endpoint string,
l2Endpoint string,
retry bool,
proofTimeTarget uint64,
protocolConfig *bindings.TaikoDataConfig,
) (*ZkevmRpcdProducer, error) {
return &ZkevmRpcdProducer{
RpcdEndpoint: rpcdEndpoint,
Param: param,
L1Endpoint: l1Endpoint,
L2Endpoint: l2Endpoint,
Retry: retry,
ProofTimeTarget: proofTimeTarget,
ProtocolConfig: protocolConfig,
RpcdEndpoint: rpcdEndpoint,
Param: param,
L1Endpoint: l1Endpoint,
L2Endpoint: l2Endpoint,
Retry: retry,
ProtocolConfig: protocolConfig,
}, nil
}

func (p *ZkevmRpcdProducer) CalcProofTimeTargetDelay(
header *types.Header,
) time.Duration {
// if > 0, delay has not yet elapsed; proof should be delayed.
// if <= 0, delay has already elapsed; proof does not need delay.
delay := ((p.ProofTimeTarget + header.Time) - uint64(time.Now().Unix()))

log.Debug("Proof submission delay", "delay", delay)

if delay > 0 {
return time.Duration(delay * uint64(time.Second))
} else {
return time.Duration(0)
}
}

// RequestProof implements the ProofProducer interface.
func (p *ZkevmRpcdProducer) RequestProof(
ctx context.Context,
Expand Down Expand Up @@ -156,16 +138,14 @@ func (p *ZkevmRpcdProducer) RequestProof(
return err
}

time.AfterFunc(p.CalcProofTimeTargetDelay(header), func() {
resultCh <- &ProofWithHeader{
BlockID: blockID,
Header: header,
Meta: meta,
ZkProof: proof,
Degree: degree,
Opts: opts,
}
})
resultCh <- &ProofWithHeader{
BlockID: blockID,
Header: header,
Meta: meta,
ZkProof: proof,
Degree: degree,
Opts: opts,
}

return nil
}
Expand Down
5 changes: 0 additions & 5 deletions prover/proof_producer/zkevm_rpcd_producer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,12 @@ import (
)

func TestNewZkevmRpcdProducer(t *testing.T) {
var proofTimeTarget uint64 = 3

dummyZkevmRpcdProducer, err := NewZkevmRpcdProducer(
"http://localhost:18545",
"",
"",
"",
false,
proofTimeTarget,
&bindings.TaikoDataConfig{},
)
require.Nil(t, err)
Expand Down Expand Up @@ -49,7 +46,6 @@ func TestNewZkevmRpcdProducer(t *testing.T) {
Nonce: types.BlockNonce{},
}

timeBefore := time.Now()
require.Nil(t, dummyZkevmRpcdProducer.RequestProof(
context.Background(),
&ProofRequestOptions{},
Expand All @@ -60,7 +56,6 @@ func TestNewZkevmRpcdProducer(t *testing.T) {
))

res := <-resCh
require.True(t, time.Now().After(timeBefore.Add(time.Duration(proofTimeTarget)*time.Second)))
require.Equal(t, res.BlockID, blockID)
require.Equal(t, res.Header, header)
require.NotEmpty(t, res.ZkProof)
Expand Down
43 changes: 41 additions & 2 deletions prover/proof_submitter/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
"fmt"
"math/big"
"strings"
"time"

"github.com/cenkalti/backoff/v4"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
Expand All @@ -19,13 +21,15 @@ import (

var (
errUnretryable = errors.New("unretryable")
errNeedWaiting = errors.New("need waiting before the proof submission")
)

// isSubmitProofTxErrorRetryable checks whether the error returned by a proof submission transaction
// is retryable.
func isSubmitProofTxErrorRetryable(err error, blockID *big.Int) bool {
if strings.HasPrefix(err.Error(), "L1_NOT_SPECIAL_PROVER") ||
!strings.HasPrefix(err.Error(), "L1_") {
!strings.HasPrefix(err.Error(), "L1_") ||
errors.Is(err, errNeedWaiting) {
return true
}

Expand Down Expand Up @@ -64,6 +68,8 @@ func sendTxWithBackoff(
ctx context.Context,
cli *rpc.Client,
blockID *big.Int,
proposedAt uint64,
expectedReward uint64,
sendTxFunc func() (*types.Transaction, error),
) error {
var isUnretryableError bool
Expand All @@ -72,6 +78,39 @@ func sendTxWithBackoff(
return nil
}

// Check the expected reward.
if expectedReward != 0 {
// Check if this proof is still needed at first.
needNewProof, err := rpc.NeedNewProof(ctx, cli, blockID, common.Address{}, nil)
if err != nil {
log.Warn(
"Failed to check if the generated proof is needed",
"blockID", blockID, "error", err,
)
return err
}

if needNewProof {
proofTime := uint64(time.Now().Unix()) - (proposedAt)
reward, err := cli.TaikoL1.GetProofReward(nil, proofTime)
if err != nil {
log.Warn("Failed to get proof reward", "blockID", blockID, "proofTime", proofTime, "error", err)
return err
}

log.Info(
"Current proof reward",
"currentReward", reward,
"expectedReward", expectedReward,
"needWaiting", reward < expectedReward,
)

if reward < expectedReward {
return errNeedWaiting
}
}
}

tx, err := sendTxFunc()
if err != nil {
err = encoding.TryParsingCustomError(err)
Expand All @@ -90,7 +129,7 @@ func sendTxWithBackoff(
}

return nil
}, backoff.NewExponentialBackOff()); err != nil {
}, backoff.NewConstantBackOff(12*time.Second)); err != nil {
return fmt.Errorf("failed to send TaikoL1.proveBlock transaction: %w", err)
}

Expand Down
Loading

0 comments on commit 30451a7

Please sign in to comment.