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

feat(prover): support SGX prover with raiko-host #473

Merged
merged 5 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cmd/flags/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ var (
Required: true,
Category: proverCategory,
}
RaikoHostEndpoint = &cli.StringFlag{
Name: "raiko.hostEndpoint",
Usage: "RPC endpoint of a Raiko host service",
Required: true,
Category: proverCategory,
}
L1ProverPrivKey = &cli.StringFlag{
Name: "l1.proverPrivKey",
Usage: "Private key of L1 prover, who will send TaikoL1.proveBlock transactions",
Expand Down Expand Up @@ -189,6 +195,7 @@ var ProverFlags = MergeFlags(CommonFlags, []cli.Flag{
L2HTTPEndpoint,
ZkEvmRpcdEndpoint,
ZkEvmRpcdParamsPath,
RaikoHostEndpoint,
L1ProverPrivKey,
MinOptimisticTierFee,
MinSgxTierFee,
Expand Down
2 changes: 2 additions & 0 deletions prover/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ type Config struct {
DatabasePath string
DatabaseCacheSize uint64
Allowance *big.Int
RaikoHostEndpoint string
}

// NewConfigFromCliContext creates a new config instance from command line flags.
Expand Down Expand Up @@ -128,6 +129,7 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) {
L1ProverPrivKey: l1ProverPrivKey,
ZKEvmRpcdEndpoint: c.String(flags.ZkEvmRpcdEndpoint.Name),
ZkEvmRpcdParamsPath: c.String(flags.ZkEvmRpcdParamsPath.Name),
RaikoHostEndpoint: c.String(flags.RaikoHostEndpoint.Name),
StartingBlockID: startingBlockID,
Dummy: c.Bool(flags.Dummy.Name),
GuardianProverAddress: common.HexToAddress(c.String(flags.GuardianProver.Name)),
Expand Down
175 changes: 170 additions & 5 deletions prover/proof_producer/sgx_producer.go
Original file line number Diff line number Diff line change
@@ -1,36 +1,201 @@
package producer

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"math/big"
"net/http"
"time"

"github.com/cenkalti/backoff/v4"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/taikoxyz/taiko-client/bindings"
"github.com/taikoxyz/taiko-client/bindings/encoding"
"github.com/taikoxyz/taiko-client/metrics"
)

// SGXProofProducer generates a SGX proof for the given block.
type SGXProofProducer struct{ *DummyProofProducer }
type SGXProofProducer struct {
RaikoHostEndpoint string // a proverd RPC endpoint
L1Endpoint string // a L1 node RPC endpoint
L2Endpoint string // a L2 execution engine's RPC endpoint
*DummyProofProducer
}

// SGXRequestProofBody represents the JSON body for requesting the proof.
type SGXRequestProofBody struct {
JsonRPC string `json:"jsonrpc"`
ID *big.Int `json:"id"`
Method string `json:"method"`
Params []*SGXRequestProofBodyParam `json:"params"`
}

// SGXRequestProofBody represents the JSON body of RequestProofBody's `param` field.
type SGXRequestProofBodyParam struct {
Type string `json:"type"`
Block *big.Int `json:"block"`
L2RPC string `json:"l2Rpc"`
L1RPC string `json:"l1Rpc"`
Prover string `json:"prover"`
Graffiti string `json:"graffiti"`
}

// SGXRequestProofBodyResponse represents the JSON body of the response of the proof requests.
type SGXRequestProofBodyResponse struct {
JsonRPC string `json:"jsonrpc"`
ID *big.Int `json:"id"`
Result *RaikoHostOutput `json:"result"`
Error *struct {
Code *big.Int `json:"code"`
Message string `json:"message"`
} `json:"error,omitempty"`
}

// RaikoHostOutput represents the JSON body of SGXRequestProofBodyResponse's `result` field.
type RaikoHostOutput struct {
Type string `json:"type"`
Proof string `json:"proof"`
}

// NewSGXProducer creates a new `SGXProofProducer` instance.
func NewSGXProducer(
raikoHostEndpoint string,
l1Endpoint string,
l2Endpoint string,
) (*SGXProofProducer, error) {
return &SGXProofProducer{
RaikoHostEndpoint: raikoHostEndpoint,
L1Endpoint: l1Endpoint,
L2Endpoint: l2Endpoint,
}, nil
}

// RequestProof implements the ProofProducer interface.
func (s *SGXProofProducer) RequestProof(
func (p *SGXProofProducer) RequestProof(
ctx context.Context,
opts *ProofRequestOptions,
blockID *big.Int,
meta *bindings.TaikoDataBlockMetadata,
header *types.Header,
resultCh chan *ProofWithHeader,
) error {
log.Warn(
"SGX proof producer is unimplemented, will return a dummy proof instead",
log.Info(
"Request proof from raiko-host service",
"blockID", blockID,
"coinbase", meta.Coinbase,
"height", header.Number,
"hash", header.Hash(),
)

return s.DummyProofProducer.RequestProof(ctx, opts, blockID, meta, header, s.Tier(), resultCh)
if p.DummyProofProducer != nil {
return p.DummyProofProducer.RequestProof(ctx, opts, blockID, meta, header, p.Tier(), resultCh)
}

proof, err := p.callProverDaemon(ctx, opts)
if err != nil {
return err
}

resultCh <- &ProofWithHeader{
BlockID: blockID,
Header: header,
Meta: meta,
Proof: proof,
Degree: 0,
Opts: opts,
Tier: p.Tier(),
}

return nil
}

// callProverDaemon keeps polling the proverd service to get the requested proof.
func (p *SGXProofProducer) callProverDaemon(ctx context.Context, opts *ProofRequestOptions) ([]byte, error) {
var (
proof []byte
start = time.Now()
)
if err := backoff.Retry(func() error {
if ctx.Err() != nil {
return nil
}
output, err := p.requestProof(opts)
if err != nil {
log.Error("Failed to request proof", "height", opts.BlockID, "err", err, "endpoint", p.RaikoHostEndpoint)
return err
}

if output == nil {
log.Info("Proof generating", "height", opts.BlockID, "time", time.Since(start))
return errProofGenerating
}

log.Debug("Proof generation output", "output", output)

proof = common.Hex2Bytes(output.Proof)
log.Info("Proof generated", "height", opts.BlockID, "time", time.Since(start))
return nil
}, backoff.NewConstantBackOff(proofPollingInterval)); err != nil {
return nil, err
}

metrics.ProverPseProofGenerationTime.Update(int64(time.Since(start).Seconds()))

return proof, nil
}

// requestProof sends a RPC request to proverd to try to get the requested proof.
func (p *SGXProofProducer) requestProof(opts *ProofRequestOptions) (*RaikoHostOutput, error) {
reqBody := SGXRequestProofBody{
JsonRPC: "2.0",
ID: common.Big1,
Method: "proof",
Params: []*SGXRequestProofBodyParam{{
Type: "Sgx",
Block: opts.BlockID,
L2RPC: p.L2Endpoint,
L1RPC: p.L1Endpoint,
Prover: opts.ProverAddress.Hex()[2:],
Graffiti: opts.Graffiti,
}},
}

jsonValue, err := json.Marshal(reqBody)
if err != nil {
return nil, err
}

res, err := http.Post(p.RaikoHostEndpoint, "application/json", bytes.NewBuffer(jsonValue))
if err != nil {
return nil, err
}

defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to request proof, id: %d, statusCode: %d", opts.BlockID, res.StatusCode)
}

resBytes, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}

var output SGXRequestProofBodyResponse
if err := json.Unmarshal(resBytes, &output); err != nil {
return nil, err
}

if output.Error != nil {
return nil, errors.New(output.Error.Message)
}

return output.Result, nil
}

// Tier implements the ProofProducer interface.
Expand Down
9 changes: 8 additions & 1 deletion prover/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,14 @@ func InitFromConfig(ctx context.Context, p *Prover, cfg *Config) (err error) {
case encoding.TierOptimisticID:
producer = &proofProducer.OptimisticProofProducer{DummyProofProducer: new(proofProducer.DummyProofProducer)}
case encoding.TierSgxID:
producer = &proofProducer.SGXProofProducer{DummyProofProducer: new(proofProducer.DummyProofProducer)}
sgxProducer, err := proofProducer.NewSGXProducer(cfg.RaikoHostEndpoint, cfg.L1HttpEndpoint, cfg.L2HttpEndpoint)
if err != nil {
return err
}
if p.cfg.Dummy {
sgxProducer.DummyProofProducer = new(proofProducer.DummyProofProducer)
}
producer = sgxProducer
case encoding.TierSgxAndPseZkevmID:
zkEvmRpcdProducer, err := proofProducer.NewZkevmRpcdProducer(
cfg.ZKEvmRpcdEndpoint,
Expand Down
Loading