Skip to content

Commit

Permalink
wip: proposer server
Browse files Browse the repository at this point in the history
  • Loading branch information
cyberhorsey committed Jul 1, 2024
1 parent d4eca52 commit 7951c8a
Show file tree
Hide file tree
Showing 11 changed files with 497 additions and 13 deletions.
8 changes: 8 additions & 0 deletions packages/taiko-client/cmd/flags/proposer.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,13 @@ var (
Category: proposerCategory,
EnvVars: []string{"PRECONFIRMATION_RPC"},
}
ProposerHTTPServerPort = &cli.Uint64Flag{
Name: "proposer.port",
Usage: "Port to expose for http server",
Category: proverCategory,
Value: 9871,
EnvVars: []string{"PROPOSER_PORT"},
}
)

// ProposerFlags All proposer flags.
Expand Down Expand Up @@ -173,4 +180,5 @@ var ProposerFlags = MergeFlags(CommonFlags, []cli.Flag{
BlobAllowed,
L1BlockBuilderTip,
PreconfirmationRPC,
ProposerHTTPServerPort,
}, TxmgrFlags)
2 changes: 2 additions & 0 deletions packages/taiko-client/proposer/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type Config struct {
TxmgrConfigs *txmgr.CLIConfig
L1BlockBuilderTip *big.Int
PreconfirmationRPC string
HTTPServerPort uint64
}

// NewConfigFromCliContext initializes a Config instance from
Expand Down Expand Up @@ -136,5 +137,6 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) {
l1ProposerPrivKey,
c,
),
HTTPServerPort: c.Uint64(flags.ProposerHTTPServerPort.Name),
}, nil
}
4 changes: 4 additions & 0 deletions packages/taiko-client/proposer/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var (
tierFee = 100.0
proposeInterval = "10s"
rpcTimeout = "5s"
httpPort = "9344"
)

func (s *ProposerTestSuite) TestNewConfigFromCliContext() {
Expand Down Expand Up @@ -55,6 +56,7 @@ func (s *ProposerTestSuite) TestNewConfigFromCliContext() {
s.Equal(uint64(15), c.TierFeePriceBump.Uint64())
s.Equal(uint64(5), c.MaxTierFeePriceBumps)
s.Equal(true, c.IncludeParentMetaHash)
s.Equal(uint64(9344), c.HTTPServerPort)

for i, e := range strings.Split(proverEndpoints, ",") {
s.Equal(c.ProverEndpoints[i].String(), e)
Expand Down Expand Up @@ -83,6 +85,7 @@ func (s *ProposerTestSuite) TestNewConfigFromCliContext() {
"--" + flags.TierFeePriceBump.Name, "15",
"--" + flags.MaxTierFeePriceBumps.Name, "5",
"--" + flags.ProposeBlockIncludeParentMetaHash.Name, "true",
"--" + flags.ProposerHTTPServerPort.Name, httpPort,
}))
}

Expand Down Expand Up @@ -143,6 +146,7 @@ func (s *ProposerTestSuite) SetupApp() *cli.App {
&cli.Uint64Flag{Name: flags.TierFeePriceBump.Name},
&cli.Uint64Flag{Name: flags.MaxTierFeePriceBumps.Name},
&cli.BoolFlag{Name: flags.ProposeBlockIncludeParentMetaHash.Name},
&cli.StringFlag{Name: flags.ProposerHTTPServerPort.Name},
}
app.Flags = append(app.Flags, flags.TxmgrFlags...)
app.Action = func(ctx *cli.Context) error {
Expand Down
53 changes: 40 additions & 13 deletions packages/taiko-client/proposer/proposer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package proposer
import (
"bytes"
"context"
"errors"
"fmt"
"math/big"
"math/rand"
"net/http"
"sync"
"time"

Expand All @@ -25,6 +27,7 @@ import (
"github.com/taikoxyz/taiko-mono/packages/taiko-client/internal/utils"
"github.com/taikoxyz/taiko-mono/packages/taiko-client/pkg/rpc"
selector "github.com/taikoxyz/taiko-mono/packages/taiko-client/proposer/prover_selector"
"github.com/taikoxyz/taiko-mono/packages/taiko-client/proposer/server"
builder "github.com/taikoxyz/taiko-mono/packages/taiko-client/proposer/transaction_builder"
)

Expand Down Expand Up @@ -53,6 +56,9 @@ type Proposer struct {
// Protocol configurations
protocolConfigs *bindings.TaikoDataConfig

// Proposer API for block builders
server *server.ProposerServer

lastProposedAt time.Time

txmgr *txmgr.SimpleTxManager
Expand Down Expand Up @@ -112,18 +118,21 @@ func (p *Proposer) InitFromConfig(ctx context.Context, cfg *Config, txMgr *txmgr
}
}

if p.proverSelector, err = selector.NewETHFeeEOASelector(
&protocolConfigs,
p.rpc,
p.proposerAddress,
cfg.TaikoL1Address,
cfg.ProverSetAddress,
p.tierFees,
cfg.TierFeePriceBump,
cfg.ProverEndpoints,
cfg.MaxTierFeePriceBumps,
); err != nil {
return err
// prover selector is optional
if cfg.ProverSetAddress.Hex() != rpc.ZeroAddress.Hex() {
if p.proverSelector, err = selector.NewETHFeeEOASelector(
&protocolConfigs,
p.rpc,
p.proposerAddress,
cfg.TaikoL1Address,
cfg.ProverSetAddress,
p.tierFees,
cfg.TierFeePriceBump,
cfg.ProverEndpoints,
cfg.MaxTierFeePriceBumps,
); err != nil {
return err
}
}

if cfg.BlobAllowed {
Expand Down Expand Up @@ -154,13 +163,27 @@ func (p *Proposer) InitFromConfig(ctx context.Context, cfg *Config, txMgr *txmgr
)
}

// Prover server
if p.server, err = server.New(&server.NewProposerServerOpts{
RPC: p.rpc,
ProtocolConfigs: &protocolConfigs,
}); err != nil {
return err
}

return nil
}

// Start starts the proposer's main loop.
func (p *Proposer) Start() error {
p.wg.Add(1)
go p.eventLoop()

go func() {
if err := p.server.Start(fmt.Sprintf(":%v", p.HTTPServerPort)); !errors.Is(err, http.ErrServerClosed) {
log.Crit("Failed to start http server", "error", err)
}
}()
return nil
}

Expand Down Expand Up @@ -191,7 +214,11 @@ func (p *Proposer) eventLoop() {
}

// Close closes the proposer instance.
func (p *Proposer) Close(_ context.Context) {
func (p *Proposer) Close(ctx context.Context) {
if err := p.server.Shutdown(ctx); err != nil {
log.Error("Failed to shut down prover server", "error", err)
}

p.wg.Wait()
}

Expand Down
118 changes: 118 additions & 0 deletions packages/taiko-client/proposer/server/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package server

import (
"bytes"
"encoding/hex"
"log"
"net/http"
"strings"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/labstack/echo/v4"
"github.com/taikoxyz/taiko-mono/packages/taiko-client/pkg/rpc"
)

// @title Taiko Proposer Server API
// @version 1.0
// @termsOfService http://swagger.io/terms/

// @contact.name API Support
// @contact.url https://community.taiko.xyz/
// @contact.email [email protected]

// @license.name MIT
// @license.url https://github.com/taikoxyz/taiko-mono/packages/taiko-client/blob/main/LICENSE.md

// Status represents the current proposer server status.
type Status struct {
}

// GetStatus handles a query to the current proposer server status.
//
// @Summary Get current proposer server status
// @ID get-status
// @Accept json
// @Produce json
// @Success 200 {object} Status
// @Router /status [get]
func (s *ProposerServer) GetStatus(c echo.Context) error {
return c.JSON(http.StatusOK, &Status{})
}

type buildBlockRequest struct {
L1StateBlockNumber uint32 `json:"l1StateBlockNumber"`
Timestamp uint64 `json:"timestamp"`
SignedTransactions []string `json:"signedTransactions"`
IncludeParentMetaHash bool `json:"includeParentMetaHash"`
Coinbase string `json:"coinbase"`
ExtraData string `json:"extraData"`
}

type buildBlockResponse struct {
RLPEncodedTx string `json:"rlpEncodedTx"`
}

// BuildBlock handles a query to build a block according to our protocol, given the inputs,
// and returns an unsigned transaction to `taikol1.ProposeBlock`.
//
// @Summary Build a block and return an unsigned `taikol1.ProposeBlock` transaction
// @ID build
// @Accept json
// @Produce json
// @Success 200 {object} BuildBlockResponse
// @Router /block/build [get]
func (s *ProposerServer) BuildBlock(c echo.Context) error {
req := &buildBlockRequest{}
if err := c.Bind(req); err != nil {
return c.JSON(http.StatusUnprocessableEntity, err)
}

var transactions types.Transactions

for _, signedTxHex := range req.SignedTransactions {
if strings.HasPrefix(signedTxHex, "0x") {
signedTxHex = signedTxHex[2:]
}

rlpEncodedBytes, err := hex.DecodeString(signedTxHex)
if err != nil {
return c.JSON(http.StatusUnprocessableEntity, err)
}

var tx types.Transaction
if err := rlp.DecodeBytes(rlpEncodedBytes, &tx); err != nil {
return c.JSON(http.StatusUnprocessableEntity, err)
}

transactions = append(transactions, &tx)
}

txListBytes, err := rlp.EncodeToBytes(transactions)
if err != nil {
log.Fatalf("Failed to RLP encode transactions: %v", err)
}

tx, err := s.txBuilder.BuildUnsigned(
c.Request().Context(),
txListBytes,
req.L1StateBlockNumber,
req.Timestamp,
common.HexToAddress(req.Coinbase),
rpc.StringToBytes32(req.ExtraData),
)
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

// RLP encode the transaction
var rlpEncodedTx bytes.Buffer
if err := rlp.Encode(&rlpEncodedTx, tx); err != nil {
log.Fatalf("Failed to RLP encode the transaction: %v", err)
}

hexEncodedTx := hex.EncodeToString(rlpEncodedTx.Bytes())

return c.JSON(http.StatusOK, buildBlockResponse{RLPEncodedTx: hexEncodedTx})
}
19 changes: 19 additions & 0 deletions packages/taiko-client/proposer/server/api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package server

import (
"encoding/json"
"io"
"net/http"
)

func (s *ProposerServerTestSuite) TestGetStatusSuccess() {
res := s.sendReq("/status")
s.Equal(http.StatusOK, res.StatusCode)

status := new(Status)

defer res.Body.Close()
b, err := io.ReadAll(res.Body)
s.Nil(err)
s.Nil(json.Unmarshal(b, &status))
}
Loading

0 comments on commit 7951c8a

Please sign in to comment.