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

Commit

Permalink
feat: update proveOp
Browse files Browse the repository at this point in the history
  • Loading branch information
davidtaikocha committed Nov 10, 2023
1 parent 8c250db commit 925273b
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 36 deletions.
59 changes: 42 additions & 17 deletions pkg/rpc/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
)

var (
ZeroAddress = common.HexToAddress("0x0000000000000000000000000000000000000000")
ZeroAddress common.Address
waitReceiptPollingInterval = 3 * time.Second
defaultWaitReceiptTimeout = 1 * time.Minute
)
Expand Down Expand Up @@ -127,32 +127,40 @@ func WaitReceipt(
}
}

// NeedNewProof checks whether the L2 block still needs a new proof.
func NeedNewProof(
// BlockProofStatus represents the proving status of the given L2 block.
type BlockProofStatus struct {
IsSubmitted bool
Invalid bool
CurrentTransitionState *bindings.TaikoDataTransitionState
ParentBlock *types.Header
}

// GetBlockProofStatus checks whether the L2 block still needs a new proof or a new contest.
func GetBlockProofStatus(
ctx context.Context,
cli *Client,
id *big.Int,
proverAddress common.Address,
) (bool, error) {
) (*BlockProofStatus, error) {
ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, defaultTimeout)
defer cancel()

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

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

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

Expand All @@ -163,29 +171,46 @@ func NeedNewProof(
)
if err != nil {
if !strings.Contains(encoding.TryParsingCustomError(err).Error(), "L1_TRANSITION_NOT_FOUND") {
return false, encoding.TryParsingCustomError(err)
return nil, encoding.TryParsingCustomError(err)
}

return true, nil
return &BlockProofStatus{IsSubmitted: false}, nil
}

l1Origin, err := cli.WaitL1Origin(ctxWithTimeout, id)
if err != nil {
return false, err
return nil, err
}

l2SignalService, err := cli.TaikoL2.SignalService(&bind.CallOpts{Context: ctx, BlockNumber: id})
if err != nil {
return nil, err
}

root, err := cli.GetStorageRoot(ctx, cli.L2GethClient, l2SignalService, id)
if err != nil {
return nil, err
}

if l1Origin.L2BlockHash != transition.BlockHash {
if l1Origin.L2BlockHash != transition.BlockHash || transition.SignalRoot != root {
log.Info(
"Different blockhash detected, try submitting a proof",
"local", common.BytesToHash(l1Origin.L2BlockHash[:]),
"protocol", common.BytesToHash(transition.BlockHash[:]),
"Different block hash or signal root detected, try submitting a contest",
"localBlockHash", common.BytesToHash(l1Origin.L2BlockHash[:]),
"protocolTransitionBlockHash", common.BytesToHash(transition.BlockHash[:]),
"localSignalRoot", root,
"protocolTransitionSignalRoot", common.BytesToHash(transition.SignalRoot[:]),
)
return true, nil
return &BlockProofStatus{
IsSubmitted: true,
Invalid: true,
CurrentTransitionState: &transition,
ParentBlock: parent,
}, nil
}

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

log.Info(
Expand All @@ -195,7 +220,7 @@ func NeedNewProof(
"timestamp", transition.Timestamp,
)

return false, nil
return &BlockProofStatus{IsSubmitted: true}, nil
}

type AccountPoolContent map[string]map[string]*types.Transaction
Expand Down
1 change: 0 additions & 1 deletion prover/proof_submitter/proof_submitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ func (s *ProofSubmitter) SubmitProof(

metrics.ProverReceivedProofCounter.Inc(1)

// Validate anchor transaction
// Get the corresponding L2 block.
block, err := s.rpc.L2.BlockByHash(ctx, proofWithHeader.Header.Hash())
if err != nil {
Expand Down
79 changes: 72 additions & 7 deletions prover/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,6 @@ func (p *Prover) onBlockProposed(
// If there are newly generated proofs, we need to submit them as soon as possible.
if len(p.proofGenerationCh) > 0 {
log.Info("onBlockProposed early return", "proofGenerationChannelLength", len(p.proofGenerationCh))

end()
return nil
}
Expand Down Expand Up @@ -458,7 +457,7 @@ func (p *Prover) onBlockProposed(
}

// Check whether the block's proof is still needed.
needNewProof, err := rpc.NeedNewProof(
proofStatus, err := rpc.GetBlockProofStatus(
p.ctx,
p.rpc,
event.BlockId,
Expand All @@ -468,8 +467,22 @@ func (p *Prover) onBlockProposed(
return fmt.Errorf("failed to check whether the L2 block needs a new proof: %w", err)
}

if !needNewProof {
return nil
if proofStatus.IsSubmitted {
// If there is already a proof submitted and there is no need to contest
// it, we skip proving this block here.
if !proofStatus.Invalid || !p.cfg.ContesterMode {
return nil
}

// The proof submitted to protocol is invalid.
return p.handleInvalidProof(
ctx, event.BlockId,
new(big.Int).SetUint64(event.Raw.BlockNumber),
proofStatus.ParentBlock.Hash(),
proofStatus.CurrentTransitionState.Contester,
&event.Meta,
proofStatus.CurrentTransitionState.Tier,
)
}

log.Info(
Expand Down Expand Up @@ -604,6 +617,44 @@ func (p *Prover) onBlockProposed(
return nil
}

// handleInvalidProof handles the case when the proof submitted to protocol is invalid.
func (p *Prover) handleInvalidProof(
ctx context.Context,
blockID *big.Int,
proposedIn *big.Int,
parentHash common.Hash,
contester common.Address,
meta *bindings.TaikoDataBlockMetadata,
tier uint16,
) error {
// The proof submitted to protocol is invalid.
log.Info(
"Invalid proof detected",
"blockID", blockID,
"parent", parentHash,
)

// If there is no contester, we submit a contest to protocol.
if contester == rpc.ZeroAddress {
log.Info(
"Try submitting a contest",
"blockID", blockID,
"parent", parentHash,
)

return p.proofContester.SubmitContest(ctx, blockID, proposedIn, parentHash, meta, tier)
}

log.Info(
"Try submitting a higher tier proof",
"blockID", blockID,
"parent", parentHash,
)

// If there is already a contester, we try submitting a proof with a higher tier here.
return p.requestProofByBlockID(blockID, proposedIn, tier+1, nil)
}

// submitProofOp performs a proof submission operation.
func (p *Prover) submitProofOp(ctx context.Context, proofWithHeader *proofProducer.ProofWithHeader) {
go func() {
Expand Down Expand Up @@ -1004,12 +1055,26 @@ func (p *Prover) onProvingWindowExpired(ctx context.Context, e *bindings.TaikoL1
return nil
}
// Check if we still need to generate a new proof for that block.
needNewProof, err := rpc.NeedNewProof(ctx, p.rpc, e.BlockId, p.proverAddress)
proofStatus, err := rpc.GetBlockProofStatus(ctx, p.rpc, e.BlockId, p.proverAddress)
if err != nil {
return err
}
if !needNewProof {
return nil
if proofStatus.IsSubmitted {
// If there is already a proof submitted and there is no need to contest
// it, we skip proving this block here.
if !proofStatus.Invalid || !p.cfg.ContesterMode {
return nil
}

return p.handleInvalidProof(
ctx,
e.BlockId,
new(big.Int).SetUint64(e.Raw.BlockNumber),
proofStatus.ParentBlock.Hash(),
proofStatus.CurrentTransitionState.Contester,
&e.Meta,
proofStatus.CurrentTransitionState.Tier,
)
}

return p.requestProofByBlockID(e.BlockId, new(big.Int).SetUint64(e.Raw.BlockNumber), e.Meta.MinTier, nil)
Expand Down
30 changes: 19 additions & 11 deletions prover/prover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,19 +259,27 @@ func (s *ProverTestSuite) TestContestWrongBlocks() {
s.Equal(header.Hash(), common.BytesToHash(contestedEvent.Tran.BlockHash[:]))
s.Equal(header.ParentHash, common.BytesToHash(contestedEvent.Tran.ParentHash[:]))

approvedSink := make(chan *bindings.GuardianProverApproved)
approvedSub, err := s.p.rpc.GuardianProver.WatchApproved(nil, approvedSink, []uint64{})
s.Nil(err)
defer func() {
approvedSub.Unsubscribe()
close(approvedSink)
}()

s.Nil(s.p.onTransitionContested(context.Background(), contestedEvent))
s.Nil(s.p.selectSubmitter(encoding.TierGuardianID).SubmitProof(context.Background(), <-s.p.proofGenerationCh))
approvedEvent := <-approvedSink

s.Equal(header.Number.Uint64(), approvedEvent.BlockId)
if contestedEvent.Tier >= encoding.TierSgxAndPseZkevmID {
approvedSink := make(chan *bindings.GuardianProverApproved)
approvedSub, err := s.p.rpc.GuardianProver.WatchApproved(nil, approvedSink, []uint64{})
s.Nil(err)
defer func() {
approvedSub.Unsubscribe()
close(approvedSink)
}()

s.Nil(s.p.selectSubmitter(encoding.TierGuardianID).SubmitProof(context.Background(), <-s.p.proofGenerationCh))
approvedEvent := <-approvedSink

s.Equal(header.Number.Uint64(), approvedEvent.BlockId)
return
}

s.Nil(s.p.selectSubmitter(contestedEvent.Tier+1).SubmitProof(context.Background(), <-s.p.proofGenerationCh))
event = <-sink
s.Equal(header.Number.Uint64(), event.BlockId.Uint64())
}

func (s *ProverTestSuite) TestProveExpiredUnassignedBlock() {
Expand Down

0 comments on commit 925273b

Please sign in to comment.