Skip to content

Commit

Permalink
Merge branch 'main' into add-swagger-chores
Browse files Browse the repository at this point in the history
  • Loading branch information
dionysuzx authored May 14, 2024
2 parents 91c1c92 + d669263 commit d20b367
Show file tree
Hide file tree
Showing 13 changed files with 250 additions and 128 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type AssignmentExpiredEventHandler struct {
proofSubmissionCh chan<- *proofProducer.ProofRequestBody
proofContestCh chan<- *proofProducer.ContestRequestBody
contesterMode bool
// Guardian prover related.
isGuardian bool
}

// NewAssignmentExpiredEventHandler creates a new AssignmentExpiredEventHandler instance.
Expand All @@ -28,8 +30,9 @@ func NewAssignmentExpiredEventHandler(
proofSubmissionCh chan *proofProducer.ProofRequestBody,
proofContestCh chan *proofProducer.ContestRequestBody,
contesterMode bool,
isGuardian bool,
) *AssignmentExpiredEventHandler {
return &AssignmentExpiredEventHandler{rpc, proverAddress, proofSubmissionCh, proofContestCh, contesterMode}
return &AssignmentExpiredEventHandler{rpc, proverAddress, proofSubmissionCh, proofContestCh, contesterMode, isGuardian}
}

// Handle implements the AssignmentExpiredHandler interface.
Expand Down Expand Up @@ -63,7 +66,7 @@ func (h *AssignmentExpiredEventHandler) Handle(

// If there is no contester, we submit a contest to protocol.
go func() {
if proofStatus.CurrentTransitionState.Contester == rpc.ZeroAddress {
if proofStatus.CurrentTransitionState.Contester == rpc.ZeroAddress && !h.isGuardian {
h.proofContestCh <- &proofProducer.ContestRequestBody{
BlockID: e.BlockId,
ProposedIn: new(big.Int).SetUint64(e.Raw.BlockNumber),
Expand Down
82 changes: 25 additions & 57 deletions packages/taiko-client/prover/event_handler/block_proposed.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package handler

import (
"context"
"crypto/rand"
"errors"
"fmt"
"math/big"
Expand All @@ -24,9 +23,8 @@ import (
)

var (
errL1Reorged = errors.New("L1 reorged")
proofExpirationDelay = 6 * 12 * time.Second // 6 ethereum blocks
submissionDelayRandomBumpRange float64 = 20
errL1Reorged = errors.New("L1 reorged")
proofExpirationDelay = 6 * 12 * time.Second // 6 ethereum blocks
)

// BlockProposedEventHandler is responsible for handling the BlockProposed event as a prover.
Expand All @@ -44,8 +42,7 @@ type BlockProposedEventHandler struct {
contesterMode bool
proveUnassignedBlocks bool
// Guardian prover related.
isGuardian bool
submissionDelay time.Duration
isGuardian bool
}

// NewBlockProposedEventHandlerOps is the options for creating a new BlockProposedEventHandler.
Expand All @@ -62,7 +59,6 @@ type NewBlockProposedEventHandlerOps struct {
BackOffMaxRetrys uint64
ContesterMode bool
ProveUnassignedBlocks bool
SubmissionDelay time.Duration
}

// NewBlockProposedEventHandler creates a new BlockProposedEventHandler instance.
Expand All @@ -81,7 +77,6 @@ func NewBlockProposedEventHandler(opts *NewBlockProposedEventHandlerOps) *BlockP
opts.ContesterMode,
opts.ProveUnassignedBlocks,
false,
opts.SubmissionDelay,
}
}

Expand Down Expand Up @@ -223,29 +218,6 @@ func (h *BlockProposedEventHandler) checkL1Reorg(
return nil
}

// getRandomBumpedSubmissionDelay returns a random bumped submission delay.
func (h *BlockProposedEventHandler) getRandomBumpedSubmissionDelay(expiredAt time.Time) (time.Duration, error) {
if h.submissionDelay == 0 {
return h.submissionDelay, nil
}

randomBump, err := rand.Int(
rand.Reader,
new(big.Int).SetUint64(uint64(h.submissionDelay.Seconds()*submissionDelayRandomBumpRange/100)),
)
if err != nil {
return 0, err
}

delay := time.Duration(h.submissionDelay.Seconds()+float64(randomBump.Uint64())) * time.Second

if time.Since(expiredAt) >= delay {
return 0, nil
}

return delay - time.Since(expiredAt), nil
}

// checkExpirationAndSubmitProof checks whether the proposed block's proving window is expired,
// and submits a new proof if necessary.
func (h *BlockProposedEventHandler) checkExpirationAndSubmitProof(
Expand Down Expand Up @@ -295,28 +267,33 @@ func (h *BlockProposedEventHandler) checkExpirationAndSubmitProof(
return nil
}

// If the current proof has not been contested, we should contest it at first.
if proofStatus.CurrentTransitionState.Contester == rpc.ZeroAddress {
h.proofContestCh <- &proofProducer.ContestRequestBody{
BlockID: e.BlockId,
ProposedIn: new(big.Int).SetUint64(e.Raw.BlockNumber),
ParentHash: proofStatus.ParentHeader.Hash(),
Meta: &e.Meta,
Tier: e.Meta.MinTier,
}
if h.isGuardian {
// In guardian prover, we submit a proof directly.
h.proofSubmissionCh <- &proofProducer.ProofRequestBody{Tier: encoding.TierGuardianMinorityID, Event: e}
} else {
// The invalid proof submitted to protocol is contested by another prover,
// we need to submit a proof with a higher tier.
h.proofSubmissionCh <- &proofProducer.ProofRequestBody{
Tier: proofStatus.CurrentTransitionState.Tier + 1,
Event: e,
// If the current proof has not been contested, we should contest it at first.
if proofStatus.CurrentTransitionState.Contester == rpc.ZeroAddress {
h.proofContestCh <- &proofProducer.ContestRequestBody{
BlockID: e.BlockId,
ProposedIn: new(big.Int).SetUint64(e.Raw.BlockNumber),
ParentHash: proofStatus.ParentHeader.Hash(),
Meta: &e.Meta,
Tier: e.Meta.MinTier,
}
} else {
// The invalid proof submitted to protocol is contested by another prover,
// we need to submit a proof with a higher tier.
h.proofSubmissionCh <- &proofProducer.ProofRequestBody{
Tier: proofStatus.CurrentTransitionState.Tier + 1,
Event: e,
}
}
}

return nil
}

windowExpired, expiredAt, timeToExpire, err := isProvingWindowExpired(e, h.sharedState.GetTiers())
windowExpired, _, timeToExpire, err := IsProvingWindowExpired(&e.Meta, h.sharedState.GetTiers())
if err != nil {
return fmt.Errorf("failed to check if the proving window is expired: %w", err)
}
Expand All @@ -339,7 +316,7 @@ func (h *BlockProposedEventHandler) checkExpirationAndSubmitProof(
"timeToExpire", timeToExpire,
)
time.AfterFunc(
// Add another 60 seconds, to ensure one more L1 block will be mined before the proof submission
// Add another 72 seconds, to ensure one more L1 block will be mined before the proof submission
timeToExpire+proofExpirationDelay,
func() { h.assignmentExpiredCh <- e },
)
Expand All @@ -352,12 +329,6 @@ func (h *BlockProposedEventHandler) checkExpirationAndSubmitProof(
// try to submit a proof for this proposed block.
tier := e.Meta.MinTier

// Get a random bumped submission delay, if necessary.
submissionDelay, err := h.getRandomBumpedSubmissionDelay(expiredAt)
if err != nil {
return err
}

if h.isGuardian {
tier = encoding.TierGuardianMinorityID
}
Expand All @@ -367,15 +338,12 @@ func (h *BlockProposedEventHandler) checkExpirationAndSubmitProof(
"blockID", e.BlockId,
"assignProver", e.AssignedProver,
"minTier", e.Meta.MinTier,
"submissionDelay", submissionDelay,
"tier", tier,
)

metrics.ProverProofsAssigned.Add(1)

time.AfterFunc(submissionDelay, func() {
h.proofSubmissionCh <- &proofProducer.ProofRequestBody{Tier: tier, Event: e}
})
h.proofSubmissionCh <- &proofProducer.ProofRequestBody{Tier: tier, Event: e}

return nil
}
Expand Down
33 changes: 0 additions & 33 deletions packages/taiko-client/prover/event_handler/block_proposed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,36 +31,3 @@ func (s *EventHandlerTestSuite) TestBlockProposedHandle() {
err := handler.Handle(context.Background(), e, func() {})
s.Nil(err)
}

func (s *EventHandlerTestSuite) TestGetRandomBumpedSubmissionDelay() {
opts := &NewBlockProposedEventHandlerOps{
SharedState: &state.SharedState{},
ProverAddress: common.Address{},
GenesisHeightL1: 0,
RPC: s.RPCClient,
ProofGenerationCh: make(chan *proofProducer.ProofWithHeader),
AssignmentExpiredCh: make(chan *bindings.TaikoL1ClientBlockProposed),
ProofSubmissionCh: make(chan *proofProducer.ProofRequestBody),
ProofContestCh: make(chan *proofProducer.ContestRequestBody),
BackOffRetryInterval: 1 * time.Minute,
BackOffMaxRetrys: 5,
ContesterMode: true,
ProveUnassignedBlocks: true,
}
handler1 := NewBlockProposedEventHandler(opts)

delay, err := handler1.getRandomBumpedSubmissionDelay(time.Now())
s.Nil(err)
s.Zero(delay)

opts.SubmissionDelay = 1 * time.Hour
handler2 := NewBlockProposedEventHandler(opts)
delay, err = handler2.getRandomBumpedSubmissionDelay(time.Now())
s.Nil(err)
s.NotZero(delay)
s.Greater(delay.Seconds(), opts.SubmissionDelay.Seconds())
s.Less(
delay.Seconds(),
opts.SubmissionDelay.Seconds()*(1+(submissionDelayRandomBumpRange/100)),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (h *TransitionContestedEventHandler) Handle(
return err
}

blockProposedEvent, err := getBlockProposedEventFromBlockID(
blockProposedEvent, err := GetBlockProposedEventFromBlockID(
ctx,
h.rpc,
e.BlockId,
Expand Down
55 changes: 42 additions & 13 deletions packages/taiko-client/prover/event_handler/transition_proved.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"math/big"

"github.com/taikoxyz/taiko-mono/packages/taiko-client/bindings/encoding"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"

Expand All @@ -15,18 +17,28 @@ import (

// TransitionProvedEventHandler is responsible for handling the TransitionProved event.
type TransitionProvedEventHandler struct {
rpc *rpc.Client
proofContestCh chan<- *proofProducer.ContestRequestBody
contesterMode bool
rpc *rpc.Client
proofContestCh chan<- *proofProducer.ContestRequestBody
proofSubmissionCh chan<- *proofProducer.ProofRequestBody
contesterMode bool
isGuardian bool
}

// NewTransitionProvedEventHandler creates a new TransitionProvedEventHandler instance.
func NewTransitionProvedEventHandler(
rpc *rpc.Client,
proofContestCh chan *proofProducer.ContestRequestBody,
proofSubmissionCh chan *proofProducer.ProofRequestBody,
contesterMode bool,
isGuardian bool,
) *TransitionProvedEventHandler {
return &TransitionProvedEventHandler{rpc, proofContestCh, contesterMode}
return &TransitionProvedEventHandler{
rpc,
proofContestCh,
proofSubmissionCh,
contesterMode,
isGuardian,
}
}

// Handle implements the TransitionProvedHandler interface.
Expand Down Expand Up @@ -78,15 +90,32 @@ func (h *TransitionProvedEventHandler) Handle(
"blockHash", common.Bytes2Hex(e.Tran.BlockHash[:]),
"stateRoot", common.Bytes2Hex(e.Tran.StateRoot[:]),
)

go func() {
h.proofContestCh <- &proofProducer.ContestRequestBody{
BlockID: e.BlockId,
ProposedIn: new(big.Int).SetUint64(blockInfo.ProposedIn),
ParentHash: e.Tran.ParentHash,
Meta: meta,
Tier: e.Tier,
if h.isGuardian {
blockProposedEvent, err := GetBlockProposedEventFromBlockID(
ctx,
h.rpc,
e.BlockId,
new(big.Int).SetUint64(blockInfo.ProposedIn),
)
if err != nil {
return err
}
}()
go func() {
h.proofSubmissionCh <- &proofProducer.ProofRequestBody{
Tier: encoding.TierGuardianMinorityID,
Event: blockProposedEvent,
}
}()
} else {
go func() {
h.proofContestCh <- &proofProducer.ContestRequestBody{
BlockID: e.BlockId,
ProposedIn: new(big.Int).SetUint64(blockInfo.ProposedIn),
ParentHash: e.Tran.ParentHash,
Meta: meta,
Tier: e.Tier,
}
}()
}
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ func (s *EventHandlerTestSuite) TestTransitionProvedHandle() {
handler := NewTransitionProvedEventHandler(
s.RPCClient,
make(chan *proofProducer.ContestRequestBody),
make(chan *proofProducer.ProofRequestBody),
true,
false,
)
e := s.ProposeAndInsertValidBlock(s.proposer, s.blobSyncer)
err := handler.Handle(context.Background(), &bindings.TaikoL1ClientTransitionProved{
Expand Down
22 changes: 11 additions & 11 deletions packages/taiko-client/prover/event_handler/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,22 @@ func isValidProof(
l2Header.Root == stateRoot, nil
}

// getProvingWindow returns the provingWindow of the given proposed block.
// getProvingWindow returns the provingWindow of the given tier.
func getProvingWindow(
e *bindings.TaikoL1ClientBlockProposed,
tier uint16,
tiers []*rpc.TierProviderTierWithID,
) (time.Duration, error) {
for _, t := range tiers {
if e.Meta.MinTier == t.ID {
if tier == t.ID {
return time.Duration(t.ProvingWindow) * time.Minute, nil
}
}

return 0, errTierNotFound
}

// getBlockProposedEventFromBlockID fetches the BlockProposed event by the given block id.
func getBlockProposedEventFromBlockID(
// GetBlockProposedEventFromBlockID fetches the BlockProposed event by the given block id.
func GetBlockProposedEventFromBlockID(
ctx context.Context,
rpc *rpc.Client,
id *big.Int,
Expand Down Expand Up @@ -120,28 +120,28 @@ func getMetadataFromBlockID(
id *big.Int,
proposedIn *big.Int,
) (*bindings.TaikoDataBlockMetadata, error) {
e, err := getBlockProposedEventFromBlockID(ctx, rpc, id, proposedIn)
e, err := GetBlockProposedEventFromBlockID(ctx, rpc, id, proposedIn)
if err != nil {
return nil, err
}
return &e.Meta, nil
}

// isProvingWindowExpired returns true as the first return parameter if the assigned prover
// IsProvingWindowExpired returns true as the first return parameter if the assigned prover
// proving window of the given proposed block is expired, and the second return parameter is the time
// remaining til proving window is expired.
func isProvingWindowExpired(
e *bindings.TaikoL1ClientBlockProposed,
func IsProvingWindowExpired(
metadata *bindings.TaikoDataBlockMetadata,
tiers []*rpc.TierProviderTierWithID,
) (bool, time.Time, time.Duration, error) {
provingWindow, err := getProvingWindow(e, tiers)
provingWindow, err := getProvingWindow(metadata.MinTier, tiers)
if err != nil {
return false, time.Time{}, 0, fmt.Errorf("failed to get proving window: %w", err)
}

var (
now = uint64(time.Now().Unix())
expiredAt = e.Meta.Timestamp + uint64(provingWindow.Seconds())
expiredAt = metadata.Timestamp + uint64(provingWindow.Seconds())
)

return now > expiredAt, time.Unix(int64(expiredAt), 0), time.Duration(expiredAt-now) * time.Second, nil
Expand Down
Loading

0 comments on commit d20b367

Please sign in to comment.