Skip to content

Commit

Permalink
Support multiple versions of header (#52)
Browse files Browse the repository at this point in the history
* Support multiple versions of header

- Define the Header of the verison 0.3
- Support the serde of multiple versions
- Test the client API with espresso dev ndoe
- Restructure the folders

* Build commitment for v0.3 header and re-export types

---------

Co-authored-by: Sneh Koul <snehkoul1999@gmail.com>
  • Loading branch information
ImJeremyHe and Sneh1999 authored Oct 25, 2024
1 parent 2efcdfd commit e28e125
Show file tree
Hide file tree
Showing 24 changed files with 1,663 additions and 692 deletions.
19 changes: 10 additions & 9 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import (
"net/http"
"strings"

"github.com/EspressoSystems/espresso-sequencer-go/types"
types "github.com/EspressoSystems/espresso-sequencer-go/types"
common "github.com/EspressoSystems/espresso-sequencer-go/types/common"
)

var _ QueryService = (*Client)(nil)
Expand All @@ -30,7 +31,7 @@ func NewClient(url string) *Client {
}
}

func (c *Client) FetchVidCommonByHeight(ctx context.Context, blockHeight uint64) (types.VidCommon, error) {
func (c *Client) FetchVidCommonByHeight(ctx context.Context, blockHeight uint64) (common.VidCommon, error) {
var res types.VidCommonQueryData
if err := c.get(ctx, &res, "availability/vid/common/%d", blockHeight); err != nil {
return types.VidCommon{}, err
Expand All @@ -46,18 +47,18 @@ func (c *Client) FetchLatestBlockHeight(ctx context.Context) (uint64, error) {
return res, nil
}

func (c *Client) FetchHeaderByHeight(ctx context.Context, blockHeight uint64) (types.Header, error) {
var res types.Header
func (c *Client) FetchHeaderByHeight(ctx context.Context, blockHeight uint64) (types.HeaderImpl, error) {
var res types.HeaderImpl
if err := c.get(ctx, &res, "availability/header/%d", blockHeight); err != nil {
return types.Header{}, err
return types.HeaderImpl{}, err
}
return res, nil
}

func (c *Client) FetchHeadersByRange(ctx context.Context, from uint64, until uint64) ([]types.Header, error) {
var res []types.Header
func (c *Client) FetchHeadersByRange(ctx context.Context, from uint64, until uint64) ([]types.HeaderImpl, error) {
var res []types.HeaderImpl
if err := c.get(ctx, &res, "availability/header/%d/%d", from, until); err != nil {
return []types.Header{}, err
return []types.HeaderImpl{}, err
}
return res, nil
}
Expand Down Expand Up @@ -188,7 +189,7 @@ func (c *Client) get(ctx context.Context, out any, format string, args ...any) e
return err
}
if err := json.Unmarshal(body, out); err != nil {
return err
return fmt.Errorf("request failed with body %s and error %v", string(body), err)
}
return nil
}
108 changes: 108 additions & 0 deletions client/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package client

import (
"context"
"os/exec"
"testing"
"time"

"github.com/ethereum/go-ethereum/log"
)

var workingDir = "./dev-node"

func TestApiWithEspressoDevNode(t *testing.T) {
ctx := context.Background()
cleanup := runEspresso(t, ctx)
defer cleanup()

err := waitForEspressoNode(t, ctx)
if err != nil {
t.Fatal("failed to start espresso dev node", err)
}

client := NewClient("http://localhost:21000")

blockHeight, err := client.FetchLatestBlockHeight(ctx)
if err != nil {
t.Fatal("failed to fetch block height")
}

_, err = client.FetchHeaderByHeight(ctx, blockHeight)
if err != nil {
t.Fatal("failed to fetch header", err)
}

_, err = client.FetchVidCommonByHeight(ctx, blockHeight)
if err != nil {
t.Fatal("failed to fetch vid common", err)
}

_, err = client.FetchHeadersByRange(ctx, 1, blockHeight)
if err != nil {
t.Fatal("failed to fetch headers by range", err)
}

}

func runEspresso(t *testing.T, ctx context.Context) func() {
shutdown := func() {
p := exec.Command("docker", "compose", "down")
p.Dir = workingDir
err := p.Run()
if err != nil {
panic(err)
}
}

shutdown()
invocation := []string{"compose", "up", "-d", "--build"}
nodes := []string{
"espresso-dev-node",
}
invocation = append(invocation, nodes...)
procees := exec.Command("docker", invocation...)
procees.Dir = workingDir

go func() {
if err := procees.Run(); err != nil {
log.Error(err.Error())
panic(err)
}
}()
return shutdown
}

func waitForWith(
t *testing.T,
ctxinput context.Context,
timeout time.Duration,
interval time.Duration,
condition func() bool,
) error {
ctx, cancel := context.WithTimeout(ctxinput, timeout)
defer cancel()

for {
if condition() {
return nil
}
select {
case <-time.After(interval):
case <-ctx.Done():
return ctx.Err()
}
}
}

func waitForEspressoNode(t *testing.T, ctx context.Context) error {
return waitForWith(t, ctx, 30*time.Second, 1*time.Second, func() bool {
out, err := exec.Command("curl", "-s", "-L", "-f", "http://localhost:21000/availability/block/10").Output()
if err != nil {
log.Warn("error executing curl command:", "err", err)
return false
}

return len(out) > 0
})
}
3 changes: 3 additions & 0 deletions client/dev-node/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ESPRESSO_SEQUENCER_API_PORT=21000
ESPRESSO_BUILDER_PORT=23000
ESPRESSO_DEV_NODE_PORT=20000
16 changes: 16 additions & 0 deletions client/dev-node/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: '3.9'
services:
espresso-dev-node:
image: ghcr.io/espressosystems/espresso-sequencer/espresso-dev-node:main
ports:
- "$ESPRESSO_SEQUENCER_API_PORT:$ESPRESSO_SEQUENCER_API_PORT"
- "$ESPRESSO_BUILDER_PORT:$ESPRESSO_BUILDER_PORT"
- "$ESPRESSO_DEV_NODE_PORT:$ESPRESSO_DEV_NODE_PORT"
environment:
- ESPRESSO_SEQUENCER_API_PORT
- ESPRESSO_BUILDER_PORT
- ESPRESSO_DEV_NODE_PORT
- RUST_LOG=info
- RUST_LOG_FORMAT
extra_hosts:
- "host.docker.internal:host-gateway"
6 changes: 3 additions & 3 deletions client/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import (
"encoding/json"
"fmt"

"github.com/EspressoSystems/espresso-sequencer-go/types"
types "github.com/EspressoSystems/espresso-sequencer-go/types"
)

// Interface to the Espresso Sequencer query service.
type QueryService interface {
// Get the latest block number
FetchLatestBlockHeight(ctx context.Context) (uint64, error)
// Get the header for block number `height`.
FetchHeaderByHeight(ctx context.Context, height uint64) (types.Header, error)
FetchHeaderByHeight(ctx context.Context, height uint64) (types.HeaderImpl, error)
// Get the headers starting from the given :from up until the given :until
FetchHeadersByRange(ctx context.Context, from uint64, until uint64) ([]types.Header, error)
FetchHeadersByRange(ctx context.Context, from uint64, until uint64) ([]types.HeaderImpl, error)
// Get the transactions belonging to the given namespace at the block height,
// along with a proof that these are all such transactions.
FetchTransactionsInBlock(ctx context.Context, blockHeight uint64, namespace uint64) (TransactionsInBlock, error)
Expand Down
4 changes: 2 additions & 2 deletions client/submit.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package client
import (
"context"

"github.com/EspressoSystems/espresso-sequencer-go/types"
common "github.com/EspressoSystems/espresso-sequencer-go/types/common"
)

// Interface to the Espresso Sequencer submit API
type SubmitAPI interface {
// Submit a transaction to the espresso sequencer.
SubmitTransaction(ctx context.Context, tx types.Transaction) (*types.TaggedBase64, error)
SubmitTransaction(ctx context.Context, tx common.Transaction) (*common.TaggedBase64, error)
}
14 changes: 7 additions & 7 deletions light-client/light_client_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"math/big"

"github.com/EspressoSystems/espresso-sequencer-go/types"
common_types "github.com/EspressoSystems/espresso-sequencer-go/types/common"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
)
Expand All @@ -13,7 +13,7 @@ var _ LightClientReaderInterface = (*LightClientReader)(nil)

type LightClientReaderInterface interface {
ValidatedHeight() (validatedHeight uint64, l1Height uint64, err error)
FetchMerkleRoot(hotShotHeight uint64, opts *bind.CallOpts) (types.BlockMerkleSnapshot, error)
FetchMerkleRoot(hotShotHeight uint64, opts *bind.CallOpts) (common_types.BlockMerkleSnapshot, error)

IsHotShotLive(delayThreshold uint64) (bool, error)
IsHotShotLiveAtHeight(height, delayThreshold uint64) (bool, error)
Expand Down Expand Up @@ -53,16 +53,16 @@ func (l *LightClientReader) ValidatedHeight() (validatedHeight uint64, l1Height

// Fetch the merkle root at the first light client snapshot that proves the provided hotshot leaf height.
// CallOpt included as a parameter in case validators need to fetch historical merkle roots if they are catching up.
func (l *LightClientReader) FetchMerkleRoot(hotShotHeight uint64, opts *bind.CallOpts) (types.BlockMerkleSnapshot, error) {
func (l *LightClientReader) FetchMerkleRoot(hotShotHeight uint64, opts *bind.CallOpts) (common_types.BlockMerkleSnapshot, error) {
snapshot, err := l.LightClient.GetHotShotCommitment(opts, new(big.Int).SetUint64(hotShotHeight))
if err != nil {
return types.BlockMerkleSnapshot{}, err
return common_types.BlockMerkleSnapshot{}, err
}
root, err := types.CommitmentFromUint256(types.NewU256().SetBigInt(snapshot.HotShotBlockCommRoot))
root, err := common_types.CommitmentFromUint256(common_types.NewU256().SetBigInt(snapshot.HotShotBlockCommRoot))
if err != nil {
return types.BlockMerkleSnapshot{}, err
return common_types.BlockMerkleSnapshot{}, err
}
return types.BlockMerkleSnapshot{
return common_types.BlockMerkleSnapshot{
Root: root,
Height: snapshot.HotshotBlockHeight,
}, nil
Expand Down
Loading

0 comments on commit e28e125

Please sign in to comment.