Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Optional async decoupling for secondary writes and reworked E2E metric assertions #182

Merged
merged 20 commits into from
Oct 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ced2a95
chore: Better abstract secondary storage
epociask Oct 12, 2024
ab6b939
chore: Better abstract secondary storage - add channel stream for sec…
epociask Oct 12, 2024
a598791
chore: Better abstract secondary storage - add channel stream for sec…
epociask Oct 12, 2024
3c3271d
chore: Better abstract secondary storage - observe secondary storage …
epociask Oct 12, 2024
bb9b433
chore: Better abstract secondary storage - observe secondary storage …
epociask Oct 13, 2024
4b9b0e2
chore: Better abstract secondary storage - observe secondary storage …
epociask Oct 13, 2024
13f221b
chore: Better abstract secondary storage - observe secondary storage …
epociask Oct 13, 2024
95790f2
chore: Better abstract secondary storage - observe secondary storage …
epociask Oct 13, 2024
8ef8108
chore: Better abstract secondary storage - observe secondary storage …
epociask Oct 16, 2024
2fce490
chore: Better abstract secondary storage - observe secondary storage …
epociask Oct 17, 2024
89f8272
chore: Better abstract secondary storage - observe secondary storage …
epociask Oct 17, 2024
167df0e
chore: Better abstract secondary storage - observe secondary storage …
epociask Oct 17, 2024
ab57599
chore: Better abstract secondary storage - address PR feedback, add b…
epociask Oct 20, 2024
2bb21b6
chore: Better abstract secondary storage - refactor tests
epociask Oct 20, 2024
0c3a48c
chore: Better abstract secondary storage - more test clean ups
epociask Oct 20, 2024
346e47c
Merge branch 'main' of github.com:Layr-Labs/op-plasma-eigenda into ep…
epociask Oct 20, 2024
1d858c7
Merge branch 'main' of github.com:Layr-Labs/op-plasma-eigenda into ep…
epociask Oct 21, 2024
69187fb
Merge branch 'main' of github.com:Layr-Labs/op-plasma-eigenda into ep…
epociask Oct 21, 2024
9959633
chore: Better abstract secondary storage - update go mock ref
epociask Oct 24, 2024
2d3559f
chore: Better abstract secondary storage - address PR feedback
epociask Oct 26, 2024
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
10 changes: 3 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,13 @@ install-lint:
@echo "Installing golangci-lint..."
@sh -c $(GET_LINT_CMD)

gosec:
@echo "Running security scan with gosec..."
gosec ./...

submodules:
git submodule update --init --recursive

op-devnet-allocs:
@echo "Generating devnet allocs..."
@./scripts/op-devnet-allocs.sh

benchmark:
go test -benchmem -run=^$ -bench . ./e2e -test.parallel 4 -deploy-config ../.devnet/devnetL1.json

.PHONY: \
clean \
test
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ In order to disperse to the EigenDA network in production, or at high throughput
| `--s3.enable-tls` | | `$EIGENDA_PROXY_S3_ENABLE_TLS` | Enable TLS connection to S3 endpoint. |
| `--routing.fallback-targets` | `[]` | `$EIGENDA_PROXY_FALLBACK_TARGETS` | Fall back backend targets. Supports S3. | Backup storage locations to read from in the event of eigenda retrieval failure. |
| `--routing.cache-targets` | `[]` | `$EIGENDA_PROXY_CACHE_TARGETS` | Caching targets. Supports S3. | Caches data to backend targets after dispersing to DA, retrieved from before trying read from EigenDA. |
| `--routing.concurrent-write-threads` | `0` | `$EIGENDA_PROXY_CONCURRENT_WRITE_THREADS` | Number of threads spun-up for async secondary storage insertions. (<=0) denotes single threaded insertions where (>0) indicates decoupled writes. |
samlaf marked this conversation as resolved.
Show resolved Hide resolved
| `--s3.timeout` | `5s` | `$EIGENDA_PROXY_S3_TIMEOUT` | timeout for S3 storage operations (e.g. get, put) |
| `--redis.db` | `0` | `$EIGENDA_PROXY_REDIS_DB` | redis database to use after connecting to server |
| `--redis.endpoint` | `""` | `$EIGENDA_PROXY_REDIS_ENDPOINT` | redis endpoint url |
Expand Down Expand Up @@ -97,6 +98,9 @@ An optional `--eigenda-eth-confirmation-depth` flag can be provided to specify a

An ephemeral memory store backend can be used for faster feedback testing when testing rollup integrations. To target this feature, use the CLI flags `--memstore.enabled`, `--memstore.expiration`.

### Asynchronous Secondary Insertions
An optional `--routing.concurrent-write-routines` flag can be provided to enable asynchronous processing for secondary writes - allowing for more efficient dispersals in the presence of a hefty secondary routing layer. This flag specifies the number of write routines spun-up with supported thread counts in range `[1, 100)`.

### Storage Fallback
An optional storage fallback CLI flag `--routing.fallback-targets` can be leveraged to ensure resiliency when **reading**. When enabled, a blob is persisted to a fallback target after being successfully dispersed. Fallback targets use the keccak256 hash of the existing EigenDA commitment as their key, for succinctness. In the event that blobs cannot be read from EigenDA, they will then be retrieved in linear order from the provided fallback targets.

Expand Down Expand Up @@ -210,6 +214,9 @@ The `raw commitment` is an RLP-encoded [EigenDA certificate](https://github.com/

Unit tests can be ran via invoking `make test`.

### Integration
End-to-end (E2E) tests can be ran via `make e2e-test`.

### Holesky

A holesky integration test can be ran using `make holesky-test` to assert proper dispersal/retrieval against a public network. Please **note** that EigenDA Holesky network which is subject to rate-limiting and slow confirmation times *(i.e, >10 minutes per blob confirmation)*. Please advise EigenDA's [inabox](https://github.com/Layr-Labs/eigenda/tree/master/inabox#readme) if you'd like to spin-up a local DA network for faster iteration testing.
Expand Down
7 changes: 4 additions & 3 deletions cmd/server/entrypoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,16 @@ func StartProxySvr(cliCtx *cli.Context) error {
return fmt.Errorf("failed to pretty print config: %w", err)
}

m := metrics.NewMetrics("default")

ctx, ctxCancel := context.WithCancel(cliCtx.Context)
defer ctxCancel()

daRouter, err := server.LoadStoreRouter(ctx, cfg, log)
sm, err := server.LoadStoreManager(ctx, cfg, log, m)
if err != nil {
return fmt.Errorf("failed to create store: %w", err)
}
m := metrics.NewMetrics("default")
server := server.NewServer(cliCtx.String(flags.ListenAddrFlagName), cliCtx.Int(flags.PortFlagName), daRouter, log, m)
server := server.NewServer(cliCtx.String(flags.ListenAddrFlagName), cliCtx.Int(flags.PortFlagName), sm, log, m)

if err := server.Start(); err != nil {
return fmt.Errorf("failed to start the DA server: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion commitments/mode.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
type CommitmentMeta struct {
Mode CommitmentMode
// CertVersion is shared for all modes and denotes version of the EigenDA certificate
CertVersion byte
CertVersion uint8
epociask marked this conversation as resolved.
Show resolved Hide resolved
}

type CommitmentMode string
Expand Down
40 changes: 40 additions & 0 deletions e2e/benchmark_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package e2e

import (
"context"
"fmt"
"os"
"strconv"
"testing"

"github.com/Layr-Labs/eigenda-proxy/client"
)

// BenchmarkPutsWithSecondary ... Takes in an async worker count and profiles blob insertions using
// constant blob sizes in parallel
func BenchmarkPutsWithSecondary(b *testing.B) {
testCfg := TestConfig(true)
testCfg.UseS3Caching = true
writeThreadCount := os.Getenv("WRITE_THREAD_COUNT")
threadInt, err := strconv.Atoi(writeThreadCount)
if err != nil {
panic(fmt.Errorf("Could not parse WRITE_THREAD_COUNT field %w", err))
}
testCfg.WriteThreadCount = threadInt

tsConfig := TestSuiteConfig(testCfg)
ts, kill := CreateTestSuite(tsConfig)
defer kill()

cfg := &client.Config{
URL: ts.Address(),
}
daClient := client.New(cfg)

for i := 0; i < b.N; i++ {
_, err := daClient.SetData(context.Background(), []byte("I am a blob and I only live for 14 days on EigenDA"))
if err != nil {
panic(err)
}
}
}
70 changes: 68 additions & 2 deletions e2e/main_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
package e2e_test

import (
"net/http"
"os"
"testing"

"github.com/Layr-Labs/eigenda-proxy/client"
"github.com/Layr-Labs/eigenda-proxy/commitments"
"github.com/Layr-Labs/eigenda-proxy/e2e"
"github.com/Layr-Labs/eigenda-proxy/store"
altda "github.com/ethereum-optimism/optimism/op-alt-da"

"github.com/Layr-Labs/eigenda-proxy/metrics"
"github.com/stretchr/testify/require"
)

// Integration tests are run against memstore whereas.
Expand All @@ -11,17 +21,73 @@ import (
// e.g, in TestProxyServerCaching we only assert to read metrics with EigenDA
// when referencing memstore since we don't profile the eigenDAClient interactions
var (
runTestnetIntegrationTests bool
runIntegrationTests bool
runTestnetIntegrationTests bool // holesky tests
runIntegrationTests bool // memstore tests
)

// ParseEnv ... reads testing cfg fields. Go test flags don't work for this library due to the dependency on Optimism's E2E framework
// which initializes test flags per init function which is called before an init in this package.
func ParseEnv() {
runIntegrationTests = os.Getenv("INTEGRATION") == "true" || os.Getenv("INTEGRATION") == "1"
runTestnetIntegrationTests = os.Getenv("TESTNET") == "true" || os.Getenv("TESTNET") == "1"
}

// TestMain ... run main controller
func TestMain(m *testing.M) {
ParseEnv()
code := m.Run()
os.Exit(code)
}

// requireDispersalRetrievalEigenDA ... ensure that blob was successfully dispersed/read to/from EigenDA
func requireDispersalRetrievalEigenDA(t *testing.T, cm *metrics.CountMap, mode commitments.CommitmentMode) {
writeCount, err := cm.Get(string(mode), http.MethodPost)
require.NoError(t, err)
require.True(t, writeCount > 0)

readCount, err := cm.Get(string(mode), http.MethodGet)
require.NoError(t, err)
require.True(t, readCount > 0)
}

// requireWriteReadSecondary ... ensure that secondary backend was successfully written/read to/from
func requireWriteReadSecondary(t *testing.T, cm *metrics.CountMap, bt store.BackendType) {
writeCount, err := cm.Get(http.MethodPut, store.Success, bt.String())
require.NoError(t, err)
require.True(t, writeCount > 0)

readCount, err := cm.Get(http.MethodGet, store.Success, bt.String())
require.NoError(t, err)
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) {
cfg := &client.Config{
URL: ts.Address(),
}
daClient := client.New(cfg)

t.Log("Setting input data on proxy server...")
blobInfo, err := daClient.SetData(ts.Ctx, blob)
require.NoError(t, err)

t.Log("Getting input data from proxy server...")
preimage, err := daClient.GetData(ts.Ctx, blobInfo)
require.NoError(t, err)
require.Equal(t, blob, preimage)

}

// requireOPClientSetGet ... ensures that alt-da client can disperse and read a blob
func requireOPClientSetGet(t *testing.T, ts e2e.TestSuite, blob []byte, precompute bool) {
daClient := altda.NewDAClient(ts.Address(), false, precompute)

commit, err := daClient.SetInput(ts.Ctx, blob)
require.NoError(t, err)

preimage, err := daClient.GetInput(ts.Ctx, commit)
require.NoError(t, err)
require.Equal(t, blob, preimage)

}
23 changes: 7 additions & 16 deletions e2e/optimism_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package e2e_test
import (
"testing"

"github.com/Layr-Labs/eigenda-proxy/commitments"
"github.com/Layr-Labs/eigenda-proxy/e2e"
altda "github.com/ethereum-optimism/optimism/op-alt-da"
"github.com/ethereum-optimism/optimism/op-e2e/config"
Expand Down Expand Up @@ -125,8 +126,8 @@ func TestOptimismKeccak256Commitment(gt *testing.T) {
testCfg := e2e.TestConfig(useMemory())
testCfg.UseKeccak256ModeS3 = true

tsConfig := e2e.TestSuiteConfig(gt, testCfg)
proxyTS, shutDown := e2e.CreateTestSuite(gt, tsConfig)
tsConfig := e2e.TestSuiteConfig(testCfg)
proxyTS, shutDown := e2e.CreateTestSuite(tsConfig)
defer shutDown()

t := actions.NewDefaultTesting(gt)
Expand Down Expand Up @@ -167,20 +168,16 @@ func TestOptimismKeccak256Commitment(gt *testing.T) {
optimism.sequencer.ActL2PipelineFull(t)
optimism.ActL1Finalized(t)

// assert that EigenDA proxy's was written and read from
stat := proxyTS.Server.GetS3Stats()

require.Equal(t, 1, stat.Entries)
require.Equal(t, 1, stat.Reads)
requireDispersalRetrievalEigenDA(gt, proxyTS.Metrics.HTTPServerRequestsTotal, commitments.OptimismKeccak)
}

func TestOptimismGenericCommitment(gt *testing.T) {
if !runIntegrationTests && !runTestnetIntegrationTests {
gt.Skip("Skipping test as INTEGRATION or TESTNET env var not set")
}

tsConfig := e2e.TestSuiteConfig(gt, e2e.TestConfig(useMemory()))
proxyTS, shutDown := e2e.CreateTestSuite(gt, tsConfig)
tsConfig := e2e.TestSuiteConfig(e2e.TestConfig(useMemory()))
proxyTS, shutDown := e2e.CreateTestSuite(tsConfig)
defer shutDown()

t := actions.NewDefaultTesting(gt)
Expand Down Expand Up @@ -221,11 +218,5 @@ func TestOptimismGenericCommitment(gt *testing.T) {
optimism.sequencer.ActL2PipelineFull(t)
optimism.ActL1Finalized(t)

// assert that EigenDA proxy's was written and read from

if useMemory() {
stat := proxyTS.Server.GetEigenDAStats()
require.Equal(t, 1, stat.Entries)
require.Equal(t, 1, stat.Reads)
}
requireDispersalRetrievalEigenDA(gt, proxyTS.Metrics.HTTPServerRequestsTotal, commitments.OptimismGeneric)
}
Loading
Loading