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

Commit

Permalink
feat(prover): introduce evidence.Assembler
Browse files Browse the repository at this point in the history
  • Loading branch information
davidtaikocha committed Oct 10, 2023
1 parent 468e5f4 commit 6ff40bb
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 182 deletions.
1 change: 1 addition & 0 deletions prover/proof_producer/dummy_producer.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func (o *DummyProofProducer) RequestProof(
Proof: bytes.Repeat([]byte{0xff}, 100),
Degree: CircuitsIdx,
Opts: opts,
Tier: tier,
}

return nil
Expand Down
98 changes: 98 additions & 0 deletions prover/proof_submitter/evidence/assembler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package evidence

import (
"context"
"encoding/binary"
"fmt"

"github.com/ethereum/go-ethereum/log"
"github.com/taikoxyz/taiko-client/bindings/encoding"
"github.com/taikoxyz/taiko-client/pkg/rpc"
anchorTxValidator "github.com/taikoxyz/taiko-client/prover/anchor_tx_validator"
proofProducer "github.com/taikoxyz/taiko-client/prover/proof_producer"
)

// Assembler is responsible for assembling evidence for the given L2 block proof.
type Assembler struct {
rpc *rpc.Client
anchorTxValidator *anchorTxValidator.AnchorTxValidator
graffiti [32]byte
}

// NewAssembler creates a new EvidenceAssembler instance.
func NewAssembler(cli *rpc.Client, anchorTxValidator *anchorTxValidator.AnchorTxValidator, graffiti string) *Assembler {
return &Assembler{
rpc: cli,
anchorTxValidator: anchorTxValidator,
graffiti: rpc.StringToBytes32(graffiti),
}
}

// assembleEvidence assembles the evidence for the given L2 block proof.
func (a *Assembler) AssembleEvidence(
ctx context.Context,
proofWithHeader *proofProducer.ProofWithHeader,
) (*encoding.BlockEvidence, error) {
var (
blockID = proofWithHeader.BlockID
header = proofWithHeader.Header
proof = proofWithHeader.Proof
)

log.Info(
"Assemble new evidence",
"blockID", blockID,
"parentHash", proofWithHeader.Header.ParentHash,
"hash", proofWithHeader.Header.Hash(),
"signalRoot", proofWithHeader.Opts.SignalRoot,
"tier", proofWithHeader.Tier,
)

// Get the corresponding L2 block.
block, err := a.rpc.L2.BlockByHash(ctx, header.Hash())
if err != nil {
return nil, fmt.Errorf("failed to get L2 block with given hash %s: %w", header.Hash(), err)
}

if block.Transactions().Len() == 0 {
return nil, fmt.Errorf("invalid block without anchor transaction, blockID %s", blockID)
}

// Validate TaikoL2.anchor transaction inside the L2 block.
anchorTx := block.Transactions()[0]
if err := a.anchorTxValidator.ValidateAnchorTx(ctx, anchorTx); err != nil {
return nil, fmt.Errorf("invalid anchor transaction: %w", err)
}

// Get and validate this anchor transaction's receipt.
if _, err = a.anchorTxValidator.GetAndValidateAnchorTxReceipt(ctx, anchorTx); err != nil {
return nil, fmt.Errorf("failed to fetch anchor transaction receipt: %w", err)
}

evidence := &encoding.BlockEvidence{
MetaHash: proofWithHeader.Opts.MetaHash,
ParentHash: proofWithHeader.Opts.ParentHash,
BlockHash: proofWithHeader.Opts.BlockHash,
SignalRoot: proofWithHeader.Opts.SignalRoot,
Graffiti: a.graffiti,
Tier: proofWithHeader.Tier,
Proof: proof,
}

if proofWithHeader.Tier == encoding.TierPseZkevmID {
circuitsIdx, err := proofProducer.DegreeToCircuitsIdx(proofWithHeader.Degree)
if err != nil {
return nil, err
}
evidence.Proof = append(uint16ToBytes(circuitsIdx), evidence.Proof...)
}

return evidence, nil
}

// uint16ToBytes converts an uint16 to bytes.
func uint16ToBytes(i uint16) []byte {
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, i)
return b
}
101 changes: 15 additions & 86 deletions prover/proof_submitter/proof_submitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package submitter
import (
"context"
"crypto/ecdsa"
"encoding/binary"
"errors"
"fmt"
"math/big"
Expand All @@ -21,6 +20,7 @@ import (
"github.com/taikoxyz/taiko-client/pkg/rpc"
anchorTxValidator "github.com/taikoxyz/taiko-client/prover/anchor_tx_validator"
proofProducer "github.com/taikoxyz/taiko-client/prover/proof_producer"
"github.com/taikoxyz/taiko-client/prover/proof_submitter/evidence"
)

var _ Submitter = (*ProofSubmitter)(nil)
Expand All @@ -31,16 +31,14 @@ type ProofSubmitter struct {
rpc *rpc.Client
proofProducer proofProducer.ProofProducer
resultCh chan *proofProducer.ProofWithHeader
anchorTxValidator *anchorTxValidator.AnchorTxValidator
evidenceAssembler *evidence.Assembler
txSender *TxSender
proverPrivKey *ecdsa.PrivateKey
proverAddress common.Address
taikoL2Address common.Address
l1SignalService common.Address
l2SignalService common.Address
graffiti [32]byte
submissionMaxRetry uint64
retryInterval time.Duration
waitReceiptTimeout time.Duration
proveBlockTxGasLimit *uint64
txReplacementTipMultiplier uint64
proveBlockMaxTxGasTipCap *big.Int
Expand Down Expand Up @@ -77,20 +75,23 @@ func New(
return nil, err
}

maxRetry := &submissionMaxRetry
if proofProducer.Tier() == encoding.TierGuardianID {
maxRetry = nil
}

return &ProofSubmitter{
rpc: rpcClient,
proofProducer: proofProducer,
resultCh: resultCh,
anchorTxValidator: anchorValidator,
evidenceAssembler: evidence.NewAssembler(rpcClient, anchorValidator, graffiti),
txSender: NewTxSender(rpcClient, retryInterval, maxRetry, waitReceiptTimeout),
proverPrivKey: proverPrivKey,
proverAddress: crypto.PubkeyToAddress(proverPrivKey.PublicKey),
l1SignalService: l1SignalService,
l2SignalService: l2SignalService,
taikoL2Address: taikoL2Address,
graffiti: rpc.StringToBytes32(graffiti),
submissionMaxRetry: submissionMaxRetry,
retryInterval: retryInterval,
waitReceiptTimeout: waitReceiptTimeout,
proveBlockTxGasLimit: proveBlockTxGasLimit,
txReplacementTipMultiplier: txReplacementTipMultiplier,
proveBlockMaxTxGasTipCap: proveBlockMaxTxGasTipCap,
Expand Down Expand Up @@ -175,63 +176,14 @@ func (s *ProofSubmitter) SubmitProof(
"proposer", proofWithHeader.Meta.Coinbase,
"hash", proofWithHeader.Header.Hash(),
"proof", common.Bytes2Hex(proofWithHeader.Proof),
"tier", s.proofProducer.Tier(),
"graffiti", common.Bytes2Hex(s.graffiti[:]),
"tier", proofWithHeader.Tier,
)

metrics.ProverReceivedProofCounter.Inc(1)

var (
blockID = proofWithHeader.BlockID
header = proofWithHeader.Header
proof = proofWithHeader.Proof
)

// Get the corresponding L2 block.
block, err := s.rpc.L2.BlockByHash(ctx, header.Hash())
evidence, err := s.evidenceAssembler.AssembleEvidence(ctx, proofWithHeader)
if err != nil {
return fmt.Errorf("failed to get L2 block with given hash %s: %w", header.Hash(), err)
}

log.Debug(
"L2 block to prove",
"blockID", blockID,
"hash", block.Hash(),
"root", header.Root.String(),
"transactions", len(block.Transactions()),
)

if block.Transactions().Len() == 0 {
return fmt.Errorf("invalid block without anchor transaction, blockID %s", blockID)
}

// Validate TaikoL2.anchor transaction inside the L2 block.
anchorTx := block.Transactions()[0]
if err := s.anchorTxValidator.ValidateAnchorTx(ctx, anchorTx); err != nil {
return fmt.Errorf("invalid anchor transaction: %w", err)
}

// Get and validate this anchor transaction's receipt.
if _, err = s.anchorTxValidator.GetAndValidateAnchorTxReceipt(ctx, anchorTx); err != nil {
return fmt.Errorf("failed to fetch anchor transaction receipt: %w", err)
}

evidence := &encoding.BlockEvidence{
MetaHash: proofWithHeader.Opts.MetaHash,
ParentHash: proofWithHeader.Opts.ParentHash,
BlockHash: proofWithHeader.Opts.BlockHash,
SignalRoot: proofWithHeader.Opts.SignalRoot,
Graffiti: s.graffiti,
Tier: s.proofProducer.Tier(),
Proof: proof,
}

if s.proofProducer.Tier() == encoding.TierPseZkevmID {
circuitsIdx, err := proofProducer.DegreeToCircuitsIdx(proofWithHeader.Degree)
if err != nil {
return err
}
evidence.Proof = append(uint16ToBytes(circuitsIdx), evidence.Proof...)
return fmt.Errorf("failed to assemble evidence: %w", err)
}

input, err := encoding.EncodeEvidence(evidence)
Expand Down Expand Up @@ -268,26 +220,10 @@ func (s *ProofSubmitter) SubmitProof(
}
}

return s.rpc.TaikoL1.ProveBlock(txOpts, blockID.Uint64(), input)
return s.rpc.TaikoL1.ProveBlock(txOpts, proofWithHeader.BlockID.Uint64(), input)
}

maxRetry := &s.submissionMaxRetry
if s.proofProducer.Tier() == encoding.TierGuardianID {
maxRetry = nil
}

if err := sendTxWithBackoff(
ctx,
s.rpc,
blockID,
proofWithHeader.Opts.EventL1Hash,
block.Header().Time,
proofWithHeader.Meta,
sendTx,
s.retryInterval,
maxRetry,
s.waitReceiptTimeout,
); err != nil {
if err := s.txSender.Send(ctx, proofWithHeader, sendTx); err != nil {
if errors.Is(err, errUnretryable) {
return nil
}
Expand All @@ -310,10 +246,3 @@ func (s *ProofSubmitter) Producer() proofProducer.ProofProducer {
func (s *ProofSubmitter) Tier() uint16 {
return s.proofProducer.Tier()
}

// uint16ToBytes converts an uint16 to bytes.
func uint16ToBytes(i uint16) []byte {
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, i)
return b
}
1 change: 1 addition & 0 deletions prover/proof_submitter/proof_submitter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ func (s *ProofSubmitterTestSuite) TestProofSubmitterSubmitProofMetadataNotFound(
BlockID: common.Big256,
Meta: &bindings.TaikoDataBlockMetadata{},
Header: &types.Header{},
Opts: &proofProducer.ProofRequestOptions{},
Proof: bytes.Repeat([]byte{0xff}, 100),
},
),
Expand Down
Loading

0 comments on commit 6ff40bb

Please sign in to comment.