Skip to content

Commit

Permalink
feat: separate simple client into its own module (#208)
Browse files Browse the repository at this point in the history
* feat: separate simple client into its own module

This will make it easier to import it into other projects without importing all of the other dependencies of our root go.mod.
We will first merge this PR with a replace directive in the main go.mod, then release v0.1.0 of the new client module, and then
make a new PR to use that version in the main go.mod file.

* chore: SimpleClient -> Standard Client (#210)

---------

Co-authored-by: Ethen <ethen@eigenlabs.org>
  • Loading branch information
samlaf and epociask authored Dec 9, 2024
1 parent 2fd70b9 commit 0bfc81f
Show file tree
Hide file tree
Showing 12 changed files with 79 additions and 65 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ Both `keccak256` (i.e, S3 storage using hash of pre-image for commitment value)

OP Stack itself only has a conception of the first byte (`commit type`) and does no semantical interpretation of any subsequent bytes within the encoding. The `da layer type` byte for EigenDA is always `0x00`. However it is currently unused by OP Stack with name space values still being actively [discussed](https://github.com/ethereum-optimism/specs/discussions/135#discussioncomment-9271282).

### Simple Commitment Mode
For simple clients communicating with proxy (e.g, arbitrum nitro), the following commitment schema is supported:
### Standard Commitment Mode
For standard clients (i.e, `client/client.go`) communicating with proxy (e.g, arbitrum nitro), the following commitment schema is supported:

```
0 1 N
Expand Down
40 changes: 20 additions & 20 deletions client/simple.go → client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,28 @@ type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
}

// SimpleCommitmentClient implements a simple client for the eigenda-proxy
// that can put/get simple commitment data and query the health endpoint.
type ClientOption func(c *Client)

// WithHTTPClient ... Embeds custom http client type
func WithHTTPClient(client HTTPClient) ClientOption {
return func(c *Client) {
c.httpClient = client
}
}

// Client implements a standard client for the eigenda-proxy
// that can put/get standard commitment data and query the health endpoint.
// Currently it is meant to be used by Arbitrum nitro integrations but can be extended to others in the future.
// Optimism has its own client: https://github.com/ethereum-optimism/optimism/blob/develop/op-alt-da/daclient.go
// so clients wanting to send op commitment mode data should use that client.
type SimpleCommitmentClient struct {
type Client struct {
cfg *Config
httpClient HTTPClient
}

type SimpleClientOption func(scc *SimpleCommitmentClient)

// WithHTTPClient ... Embeds custom http client type
func WithHTTPClient(client HTTPClient) SimpleClientOption {
return func(scc *SimpleCommitmentClient) {
scc.httpClient = client
}
}

// New ... Constructor
func New(cfg *Config, opts ...SimpleClientOption) *SimpleCommitmentClient {
scc := &SimpleCommitmentClient{
// New ... constructor
func New(cfg *Config, opts ...ClientOption) *Client {
scc := &Client{
cfg,
http.DefaultClient,
}
Expand All @@ -56,7 +56,7 @@ func New(cfg *Config, opts ...SimpleClientOption) *SimpleCommitmentClient {

// Health indicates if the server is operational; useful for event based awaits
// when integration testing
func (c *SimpleCommitmentClient) Health() error {
func (c *Client) Health() error {
url := c.cfg.URL + "/health"
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, url, nil)
if err != nil {
Expand All @@ -77,8 +77,8 @@ func (c *SimpleCommitmentClient) Health() error {
}

// GetData fetches blob data associated with a DA certificate
func (c *SimpleCommitmentClient) GetData(ctx context.Context, comm []byte) ([]byte, error) {
url := fmt.Sprintf("%s/get/0x%x?commitment_mode=simple", c.cfg.URL, comm)
func (c *Client) GetData(ctx context.Context, comm []byte) ([]byte, error) {
url := fmt.Sprintf("%s/get/0x%x?commitment_mode=standard", c.cfg.URL, comm)

req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
Expand Down Expand Up @@ -107,8 +107,8 @@ func (c *SimpleCommitmentClient) GetData(ctx context.Context, comm []byte) ([]by

// SetData writes raw byte data to DA and returns the associated certificate
// which should be verified within the proxy
func (c *SimpleCommitmentClient) SetData(ctx context.Context, b []byte) ([]byte, error) {
url := fmt.Sprintf("%s/put?commitment_mode=simple", c.cfg.URL)
func (c *Client) SetData(ctx context.Context, b []byte) ([]byte, error) {
url := fmt.Sprintf("%s/put?commitment_mode=standard", c.cfg.URL)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(b))
if err != nil {
return nil, fmt.Errorf("failed to create HTTP request: %w", err)
Expand Down
10 changes: 10 additions & 0 deletions client/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// We use a separate module for the client to allow dependencies to import it without importing all of proxy's main module's dependencies.
// This follows the recommendation in: https://go.dev/wiki/Modules#should-i-have-multiple-modules-in-a-single-repository
//
// Two example scenarios where it can make sense to have more than one go.mod in a repository:
// 1. [omitted]
// 2. if you have a repository with a complex set of dependencies, but you have a client API with a smaller set of dependencies.
// In some cases, it might make sense to have an api or clientapi or similar directory with its own go.mod, or to separate out that clientapi into its own repository.
module github.com/Layr-Labs/eigenda-proxy/client

go 1.21.0
12 changes: 6 additions & 6 deletions commitments/mode.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ type CommitmentMeta struct {
type CommitmentMode string

const (
OptimismKeccak CommitmentMode = "optimism_keccak256"
OptimismGeneric CommitmentMode = "optimism_generic"
SimpleCommitmentMode CommitmentMode = "simple"
OptimismKeccak CommitmentMode = "optimism_keccak256"
OptimismGeneric CommitmentMode = "optimism_generic"
Standard CommitmentMode = "standard"
)

func StringToCommitmentMode(s string) (CommitmentMode, error) {
Expand All @@ -24,8 +24,8 @@ func StringToCommitmentMode(s string) (CommitmentMode, error) {
return OptimismKeccak, nil
case string(OptimismGeneric):
return OptimismGeneric, nil
case string(SimpleCommitmentMode):
return SimpleCommitmentMode, nil
case string(Standard):
return Standard, nil
default:
return "", fmt.Errorf("unknown commitment mode: %s", s)
}
Expand All @@ -42,7 +42,7 @@ func EncodeCommitment(b []byte, c CommitmentMode) ([]byte, error) {
altDACommit := NewGenericCommitment(svcCommit).Encode()
return altDACommit, nil

case SimpleCommitmentMode:
case Standard:
return NewV0CertCommitment(b).Encode(), nil
}

Expand Down
4 changes: 2 additions & 2 deletions e2e/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ func requireWriteReadSecondary(t *testing.T, cm *metrics.CountMap, bt common.Bac
require.True(t, readCount > 0)
}

// requireSimpleClientSetGet ... ensures that simple proxy client can disperse and read a blob
func requireSimpleClientSetGet(t *testing.T, ts e2e.TestSuite, blob []byte) {
// requireStandardClientSetGet ... ensures that std proxy client can disperse and read a blob
func requireStandardClientSetGet(t *testing.T, ts e2e.TestSuite, blob []byte) {
cfg := &client.Config{
URL: ts.Address(),
}
Expand Down
2 changes: 1 addition & 1 deletion e2e/safety_checks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func TestProxyClientMalformedInputCases(t *testing.T) {

t.Run("get data edge cases - huge cert", func(t *testing.T) {
// TODO: we need to add the 0 version byte at the beginning.
// should this not be done automatically by the simple_commitment client?
// should this not be done automatically by the std_commitment client?
testCert := append([]byte{0}, e2e.RandBytes(10000)...)
_, err := daClient.GetData(ts.Ctx, testCert)
require.Error(t, err)
Expand Down
20 changes: 10 additions & 10 deletions e2e/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ func TestProxyClientWriteRead(t *testing.T) {
ts, kill := e2e.CreateTestSuite(tsConfig)
defer kill()

requireSimpleClientSetGet(t, ts, e2e.RandBytes(100))
requireDispersalRetrievalEigenDA(t, ts.Metrics.HTTPServerRequestsTotal, commitments.SimpleCommitmentMode)
requireStandardClientSetGet(t, ts, e2e.RandBytes(100))
requireDispersalRetrievalEigenDA(t, ts.Metrics.HTTPServerRequestsTotal, commitments.Standard)
}

func TestProxyWithMaximumSizedBlob(t *testing.T) {
Expand All @@ -78,8 +78,8 @@ func TestProxyWithMaximumSizedBlob(t *testing.T) {
ts, kill := e2e.CreateTestSuite(tsConfig)
defer kill()

requireSimpleClientSetGet(t, ts, e2e.RandBytes(16_000_000))
requireDispersalRetrievalEigenDA(t, ts.Metrics.HTTPServerRequestsTotal, commitments.SimpleCommitmentMode)
requireStandardClientSetGet(t, ts, e2e.RandBytes(16_000_000))
requireDispersalRetrievalEigenDA(t, ts.Metrics.HTTPServerRequestsTotal, commitments.Standard)
}

/*
Expand All @@ -99,9 +99,9 @@ func TestProxyCaching(t *testing.T) {
ts, kill := e2e.CreateTestSuite(tsConfig)
defer kill()

requireSimpleClientSetGet(t, ts, e2e.RandBytes(1_000_000))
requireStandardClientSetGet(t, ts, e2e.RandBytes(1_000_000))
requireWriteReadSecondary(t, ts.Metrics.SecondaryRequestsTotal, common.S3BackendType)
requireDispersalRetrievalEigenDA(t, ts.Metrics.HTTPServerRequestsTotal, commitments.SimpleCommitmentMode)
requireDispersalRetrievalEigenDA(t, ts.Metrics.HTTPServerRequestsTotal, commitments.Standard)
}

func TestProxyCachingWithRedis(t *testing.T) {
Expand All @@ -118,9 +118,9 @@ func TestProxyCachingWithRedis(t *testing.T) {
ts, kill := e2e.CreateTestSuite(tsConfig)
defer kill()

requireSimpleClientSetGet(t, ts, e2e.RandBytes(1_000_000))
requireStandardClientSetGet(t, ts, e2e.RandBytes(1_000_000))
requireWriteReadSecondary(t, ts.Metrics.SecondaryRequestsTotal, common.RedisBackendType)
requireDispersalRetrievalEigenDA(t, ts.Metrics.HTTPServerRequestsTotal, commitments.SimpleCommitmentMode)
requireDispersalRetrievalEigenDA(t, ts.Metrics.HTTPServerRequestsTotal, commitments.Standard)
}

/*
Expand Down Expand Up @@ -162,7 +162,7 @@ func TestProxyReadFallback(t *testing.T) {
require.NoError(t, err)
require.Equal(t, expectedBlob, actualBlob)

requireSimpleClientSetGet(t, ts, e2e.RandBytes(1_000_000))
requireStandardClientSetGet(t, ts, e2e.RandBytes(1_000_000))
requireWriteReadSecondary(t, ts.Metrics.SecondaryRequestsTotal, common.S3BackendType)
requireDispersalRetrievalEigenDA(t, ts.Metrics.HTTPServerRequestsTotal, commitments.SimpleCommitmentMode)
requireDispersalRetrievalEigenDA(t, ts.Metrics.HTTPServerRequestsTotal, commitments.Standard)
}
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ toolchain go1.22.7

require (
github.com/Layr-Labs/eigenda v0.8.5-rc.0.0.20241101212705-fa8776ae648c
github.com/Layr-Labs/eigenda-proxy/client v0.0.0-00010101000000-000000000000
github.com/avast/retry-go/v4 v4.6.0
github.com/consensys/gnark-crypto v0.12.1
github.com/ethereum-optimism/optimism v1.9.5
Expand All @@ -24,6 +25,9 @@ require (
google.golang.org/grpc v1.64.1
)

// TODO: Remove this after we have published v0.1.0 of the new client module.
replace github.com/Layr-Labs/eigenda-proxy/client => ./client/

require (
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
Expand Down
12 changes: 6 additions & 6 deletions server/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ func (svr *Server) handleHealth(w http.ResponseWriter, _ *http.Request) error {
// GET ROUTES
// =================================================================================================

// handleGetSimpleCommitment handles the GET request for simple commitments.
func (svr *Server) handleGetSimpleCommitment(w http.ResponseWriter, r *http.Request) error {
// handleGetStdCommitment handles the GET request for std commitments.
func (svr *Server) handleGetStdCommitment(w http.ResponseWriter, r *http.Request) error {
versionByte, err := parseVersionByte(w, r)
if err != nil {
return fmt.Errorf("error parsing version byte: %w", err)
}
commitmentMeta := commitments.CommitmentMeta{
Mode: commitments.SimpleCommitmentMode,
Mode: commitments.Standard,
CertVersion: versionByte,
}

Expand Down Expand Up @@ -118,10 +118,10 @@ func (svr *Server) handleGetShared(ctx context.Context, w http.ResponseWriter, c
// POST ROUTES
// =================================================================================================

// handlePostSimpleCommitment handles the POST request for simple commitments.
func (svr *Server) handlePostSimpleCommitment(w http.ResponseWriter, r *http.Request) error {
// handlePostStdCommitment handles the POST request for std commitments.
func (svr *Server) handlePostStdCommitment(w http.ResponseWriter, r *http.Request) error {
commitmentMeta := commitments.CommitmentMeta{
Mode: commitments.SimpleCommitmentMode,
Mode: commitments.Standard,
CertVersion: byte(commitments.CertV0), // TODO: hardcoded for now
}
return svr.handlePostShared(w, r, nil, commitmentMeta)
Expand Down
12 changes: 6 additions & 6 deletions server/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
)

const (
simpleCommitmentPrefix = "\x00"
stdCommitmentPrefix = "\x00"

// [alt-da, da layer, cert version]
opGenericPrefixStr = "\x01\x00\x00"
Expand Down Expand Up @@ -145,14 +145,14 @@ func TestHandlerPutSuccess(t *testing.T) {
expectedBody: "",
},
{
name: "Success Simple Commitment Mode",
url: "/put?commitment_mode=simple",
name: "Success Standard Commitment Mode",
url: "/put?commitment_mode=standard",
body: []byte("some data that will successfully be written to EigenDA"),
mockBehavior: func() {
mockStorageMgr.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte(testCommitStr), nil)
},
expectedCode: http.StatusOK,
expectedBody: simpleCommitmentPrefix + testCommitStr,
expectedBody: stdCommitmentPrefix + testCommitStr,
},
}

Expand Down Expand Up @@ -198,8 +198,8 @@ func TestHandlerPutErrors(t *testing.T) {
url: fmt.Sprintf("/put/0x00%s", testCommitStr),
},
{
name: "Simple Commitment Mode",
url: "/put?commitment_mode=simple",
name: "Standard Commitment Mode",
url: "/put?commitment_mode=standard",
},
}

Expand Down
18 changes: 9 additions & 9 deletions server/routing.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ const (

func (svr *Server) registerRoutes(r *mux.Router) {
subrouterGET := r.Methods("GET").PathPrefix("/get").Subrouter()
// simple commitments (for nitro)
// std commitments (for nitro)
subrouterGET.HandleFunc("/"+
"{optional_prefix:(?:0x)?}"+ // commitments can be prefixed with 0x
"{"+routingVarNameVersionByteHex+":[0-9a-fA-F]{2}}"+ // should always be 0x00 for now but we let others through to return a 404
"{"+routingVarNameRawCommitmentHex+":[0-9a-fA-F]*}",
withLogging(withMetrics(svr.handleGetSimpleCommitment, svr.m, commitments.SimpleCommitmentMode), svr.log),
).Queries("commitment_mode", "simple")
withLogging(withMetrics(svr.handleGetStdCommitment, svr.m, commitments.Standard), svr.log),
).Queries("commitment_mode", "standard")
// op keccak256 commitments (write to S3)
subrouterGET.HandleFunc("/"+
"{optional_prefix:(?:0x)?}"+ // commitments can be prefixed with 0x
Expand Down Expand Up @@ -51,13 +51,13 @@ func (svr *Server) registerRoutes(r *mux.Router) {
commitType := mux.Vars(r)[routingVarNameCommitTypeByteHex]
http.Error(w, fmt.Sprintf("unsupported commitment type %s", commitType), http.StatusBadRequest)
},
).MatcherFunc(notCommitmentModeSimple)
).MatcherFunc(notCommitmentModeStandard)

subrouterPOST := r.Methods("POST").PathPrefix("/put").Subrouter()
// simple commitments (for nitro)
// std commitments (for nitro)
subrouterPOST.HandleFunc("", // commitment is calculated by the server using the body data
withLogging(withMetrics(svr.handlePostSimpleCommitment, svr.m, commitments.SimpleCommitmentMode), svr.log),
).Queries("commitment_mode", "simple")
withLogging(withMetrics(svr.handlePostStdCommitment, svr.m, commitments.Standard), svr.log),
).Queries("commitment_mode", "standard")
// op keccak256 commitments (write to S3)
subrouterPOST.HandleFunc("/"+
"{optional_prefix:(?:0x)?}"+ // commitments can be prefixed with 0x
Expand All @@ -80,7 +80,7 @@ func (svr *Server) registerRoutes(r *mux.Router) {
r.HandleFunc("/health", withLogging(svr.handleHealth, svr.log)).Methods("GET")
}

func notCommitmentModeSimple(r *http.Request, _ *mux.RouteMatch) bool {
func notCommitmentModeStandard(r *http.Request, _ *mux.RouteMatch) bool {
commitmentMode := r.URL.Query().Get("commitment_mode")
return commitmentMode == "" || commitmentMode != "simple"
return commitmentMode == "" || commitmentMode != "standard"
}
6 changes: 3 additions & 3 deletions store/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type IManager interface {
type Manager struct {
log log.Logger
// primary storage backends
eigenda common.GeneratedKeyStore // ALT DA commitment type for OP mode && simple commitment mode for standard /client
eigenda common.GeneratedKeyStore // ALT DA commitment type for OP mode && std commitment mode for standard /client
s3 common.PrecomputedKeyStore // OP commitment mode && keccak256 commitment type

// secondary storage backends (caching and fallbacks)
Expand Down Expand Up @@ -63,7 +63,7 @@ func (m *Manager) Get(ctx context.Context, key []byte, cm commitments.Commitment
}
return value, nil

case commitments.SimpleCommitmentMode, commitments.OptimismGeneric:
case commitments.Standard, commitments.OptimismGeneric:
if m.eigenda == nil {
return nil, errors.New("expected EigenDA backend for DA commitment type, but none configured")
}
Expand Down Expand Up @@ -117,7 +117,7 @@ func (m *Manager) Put(ctx context.Context, cm commitments.CommitmentMode, key, v
switch cm {
case commitments.OptimismKeccak: // caching and fallbacks are unsupported for this commitment mode
return m.putKeccak256Mode(ctx, key, value)
case commitments.OptimismGeneric, commitments.SimpleCommitmentMode:
case commitments.OptimismGeneric, commitments.Standard:
commit, err = m.putEigenDAMode(ctx, value)
default:
return nil, fmt.Errorf("unknown commitment mode")
Expand Down

0 comments on commit 0bfc81f

Please sign in to comment.