Skip to content

Commit

Permalink
changes based on pr-18181
Browse files Browse the repository at this point in the history
  • Loading branch information
YoGhurt111 committed Sep 27, 2024
1 parent 0834514 commit d505ebe
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 36 deletions.
111 changes: 111 additions & 0 deletions packages/taiko-client/pkg/rpc/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,117 @@ func GetBlockProofStatus(
}, nil
}

// BatchGetBlockProofStatus checks whether the batch of L2 block still need new proofs or new contests.
// Here are the possible status:
// 1. No proof on chain at all.
// 2. A valid proof has been submitted.
// 3. An invalid proof has been submitted, and there is no valid contest.
// 4. An invalid proof has been submitted, and there is a valid contest.
func BatchGetBlockProofStatus(
ctx context.Context,
cli *Client,
ids []*big.Int,
proverAddress common.Address,
proverSetAddress common.Address,
) ([]*BlockProofStatus, error) {
ctxWithTimeout, cancel := CtxWithTimeoutOrDefault(ctx, defaultTimeout)
defer cancel()

var (
parentHashes = make([][32]byte, len(ids))
parents = make([]*types.Header, len(ids))
blockIDs = make([]uint64, len(ids))
result = make([]*BlockProofStatus, len(ids))
)
// Get the local L2 parent header.
for i, id := range ids {
parent, err := cli.L2.HeaderByNumber(ctxWithTimeout, new(big.Int).Sub(id, common.Big1))
if err != nil {
return nil, err
}
parentHashes[i] = parent.ParentHash
parents[i] = parent
blockIDs[i] = id.Uint64()
}

// Get the transition state from TaikoL1 contract.
transitions, err := cli.TaikoL1.GetTransitions(
&bind.CallOpts{Context: ctxWithTimeout},
blockIDs,
parentHashes,
)
if err != nil {
return nil, err
}
for i, transition := range transitions {
// no proof on chain
if transition.StateRoot == (common.Hash{}) {
result[i] = &BlockProofStatus{IsSubmitted: false, ParentHeader: parents[i]}
continue
}

header, err := cli.WaitL2Header(ctxWithTimeout, ids[i])
if err != nil {
return nil, err
}
if header.Hash() != transition.BlockHash ||
(transition.StateRoot != (common.Hash{}) && transition.StateRoot != header.Root) {
log.Info(
"Different block hash or state root detected, try submitting a contest",
"localBlockHash", header.Hash(),
"protocolTransitionBlockHash", common.BytesToHash(transition.BlockHash[:]),
"localStateRoot", header.Root,
"protocolTransitionStateRoot", common.BytesToHash(transition.StateRoot[:]),
)
result[i] = &BlockProofStatus{
IsSubmitted: true,
Invalid: true,
CurrentTransitionState: &transitions[i],
ParentHeader: parents[i],
}
continue
}

if proverAddress == transition.Prover ||
(proverSetAddress != ZeroAddress && transition.Prover == proverSetAddress) {
log.Info(
"📬 Block's proof has already been submitted by current prover",
"blockID", ids[i],
"parent", parents[i].Hash().Hex(),
"hash", common.Bytes2Hex(transition.BlockHash[:]),
"stateRoot", common.Bytes2Hex(transition.StateRoot[:]),
"timestamp", transition.Timestamp,
"contester", transition.Contester,
)
result[i] = &BlockProofStatus{
IsSubmitted: true,
Invalid: transition.Contester != ZeroAddress,
ParentHeader: parents[i],
CurrentTransitionState: &transitions[i],
}
continue
}
log.Info(
"📬 Block's proof has already been submitted by another prover",
"blockID", ids[i],
"prover", transition.Prover,
"parent", parents[i].Hash().Hex(),
"hash", common.Bytes2Hex(transition.BlockHash[:]),
"stateRoot", common.Bytes2Hex(transition.StateRoot[:]),
"timestamp", transition.Timestamp,
"contester", transition.Contester,
)

result[i] = &BlockProofStatus{
IsSubmitted: true,
Invalid: transition.Contester != ZeroAddress,
ParentHeader: parents[i],
CurrentTransitionState: &transitions[i],
}
}
return result, 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, client *EthClient, headNum *big.Int) error {
Expand Down
13 changes: 11 additions & 2 deletions packages/taiko-client/prover/proof_producer/optimistic_producer.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,18 @@ func (o *OptimisticProofProducer) Aggregate(
"items", items,
)
if len(items) == 0 {
return nil, errInvalidLength
return nil, ErrInvalidLength
}
return o.DummyProofProducer.RequestBatchProofs(items, o.Tier())
blockIDs := make([]*big.Int, len(items))
for i, item := range items {
blockIDs[i] = item.Meta.GetBlockID()
}
batchProof, err := o.DummyProofProducer.RequestBatchProofs(items, o.Tier())
if err != nil {
return nil, err
}
batchProof.BlockIDs = blockIDs
return batchProof, nil
}

// RequestCancel implements the ProofProducer interface to cancel the proof generating progress.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
var (
errProofGenerating = errors.New("proof is generating")
errEmptyProof = errors.New("proof is empty")
errInvalidLength = errors.New("invalid items length")
ErrInvalidLength = errors.New("invalid items length")
)

// ProofRequestBody represents a request body to generate a proof.
Expand Down Expand Up @@ -62,6 +62,7 @@ type BatchProofs struct {
Proofs []*ProofWithHeader
BatchProof []byte
Tier uint16
BlockIDs []*big.Int
}

type ProofProducer interface {
Expand Down
3 changes: 2 additions & 1 deletion packages/taiko-client/prover/proof_producer/sgx_producer.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func (s *SGXProofProducer) Aggregate(
"items", items,
)
if len(items) == 0 {
return nil, errInvalidLength
return nil, ErrInvalidLength
}

blockIDs := make([]*big.Int, len(items))
Expand All @@ -163,6 +163,7 @@ func (s *SGXProofProducer) Aggregate(
Proofs: items,
BatchProof: batchProof,
Tier: s.Tier(),
BlockIDs: blockIDs,
}, nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ func (pb *ProofBuffer) Write(item *producer.ProofWithHeader) (int, error) {

// Read returns the content with given length in the buffer.
func (pb *ProofBuffer) Read(length int) ([]*producer.ProofWithHeader, error) {

if length > len(pb.buffer) {
return nil, errNotEnoughProof
}
Expand Down
51 changes: 32 additions & 19 deletions packages/taiko-client/prover/proof_submitter/proof_submitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"math/big"
"time"

"github.com/ethereum/go-ethereum/accounts/abi/bind"

"github.com/cenkalti/backoff/v4"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -337,33 +339,44 @@ func (s *ProofSubmitter) BatchSubmitProofs(ctx context.Context, batchProof *proo
invalidProofs []*proofProducer.ProofWithHeader
latestProvenBlockID *big.Int
)
for _, proof := range batchProof.Proofs {
// Check if the proof has already been submitted.
proofStatus, err := rpc.GetBlockProofStatus(
ctx,
s.rpc,
proof.BlockID,
proof.Opts.ProverAddress,
s.proverSetAddress,
if len(batchProof.Proofs) == 0 {
return proofProducer.ErrInvalidLength
}
// Check if the proof has already been submitted.
proofStatus, err := rpc.BatchGetBlockProofStatus(
ctx,
s.rpc,
batchProof.BlockIDs,
batchProof.Proofs[0].Opts.ProverAddress,
s.proverSetAddress,
)
if err != nil {
return err
}
stateVars, err := s.rpc.GetProtocolStateVariables(&bind.CallOpts{Context: ctx})
if err != nil {
log.Warn(
"Failed to fetch state variables",
"error", err,
)
return err
}
for i, proof := range batchProof.Proofs {
// Check if this proof is still needed to be submitted.
ok, err := s.sender.ValidateProof(ctx, proof, new(big.Int).SetUint64(stateVars.B.LastVerifiedBlockId))
if err != nil {
return err
}
if proofStatus.IsSubmitted && !proofStatus.Invalid {
if !ok {
log.Error("a valid proof for block is already submitted", "blockId", proof.BlockID)
invalidProofs = append(invalidProofs, proof)
break
continue
}

// Check if this proof is still needed to be submitted.
ok, err := s.sender.ValidateProof(ctx, proof)
if err != nil {
return err
}
if !ok {
if proofStatus[i].IsSubmitted && !proofStatus[i].Invalid {
log.Error("a valid proof for block is already submitted", "blockId", proof.BlockID)
invalidProofs = append(invalidProofs, proof)
break
continue
}

// Get the corresponding L2 block.
Expand All @@ -374,13 +387,13 @@ func (s *ProofSubmitter) BatchSubmitProofs(ctx context.Context, batchProof *proo
"error", err,
)
invalidProofs = append(invalidProofs, proof)
break
continue
}

if block.Transactions().Len() == 0 {
log.Error("invalid block without anchor transaction, blockID", "blockId", proof.BlockID)
invalidProofs = append(invalidProofs, proof)
break
continue
}

// Validate TaikoL2.anchor transaction inside the L2 block.
Expand Down
32 changes: 20 additions & 12 deletions packages/taiko-client/prover/proof_submitter/transaction/sender.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (s *Sender) Send(
}

// Check if this proof is still needed to be submitted.
ok, err := s.ValidateProof(ctx, proofWithHeader)
ok, err := s.ValidateProof(ctx, proofWithHeader, nil)
if err != nil || !ok {
return err
}
Expand Down Expand Up @@ -157,7 +157,11 @@ func (s *Sender) SendBatchProof(

// ValidateProof checks if the proof's corresponding L1 block is still in the canonical chain and if the
// latest verified head is not ahead of this block proof.
func (s *Sender) ValidateProof(ctx context.Context, proofWithHeader *producer.ProofWithHeader) (bool, error) {
func (s *Sender) ValidateProof(
ctx context.Context,
proofWithHeader *producer.ProofWithHeader,
latestVerifiedID *big.Int,
) (bool, error) {
// 1. Check if the corresponding L1 block is still in the canonical chain.
l1Header, err := s.rpc.L1.HeaderByNumber(ctx, proofWithHeader.Meta.GetRawBlockHeight())
if err != nil {
Expand All @@ -180,18 +184,22 @@ func (s *Sender) ValidateProof(ctx context.Context, proofWithHeader *producer.Pr
return false, nil
}

var verifiedID = latestVerifiedID
// 2. Check if latest verified head is ahead of this block proof.
stateVars, err := s.rpc.GetProtocolStateVariables(&bind.CallOpts{Context: ctx})
if err != nil {
log.Warn(
"Failed to fetch state variables",
"blockID", proofWithHeader.BlockID,
"error", err,
)
return false, err
if verifiedID == nil {
stateVars, err := s.rpc.GetProtocolStateVariables(&bind.CallOpts{Context: ctx})
if err != nil {
log.Warn(
"Failed to fetch state variables",
"blockID", proofWithHeader.BlockID,
"error", err,
)
return false, err
}
verifiedID = new(big.Int).SetUint64(stateVars.B.LastVerifiedBlockId)
}
latestVerifiedID := stateVars.B.LastVerifiedBlockId
if new(big.Int).SetUint64(latestVerifiedID).Cmp(proofWithHeader.BlockID) >= 0 {

if verifiedID.Cmp(proofWithHeader.BlockID) >= 0 {
log.Info(
"Block is already verified, skip current proof submission",
"blockID", proofWithHeader.BlockID.Uint64(),
Expand Down

0 comments on commit d505ebe

Please sign in to comment.