From 9f4320b65db631c8d67731f7184256e46ce0df5f Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Sat, 21 Sep 2024 18:38:29 -0700 Subject: [PATCH 01/18] refactor: move flags from config.go -> flags.go --- server/config.go | 296 ++---------------------------------------- server/config_test.go | 4 +- server/flags.go | 287 +++++++++++++++++++++++++++++++++++++++- server/load_store.go | 2 + 4 files changed, 298 insertions(+), 291 deletions(-) diff --git a/server/config.go b/server/config.go index 2193e61a..67042631 100644 --- a/server/config.go +++ b/server/config.go @@ -5,64 +5,14 @@ import ( "runtime" "time" + "github.com/urfave/cli/v2" + "github.com/Layr-Labs/eigenda-proxy/store" "github.com/Layr-Labs/eigenda-proxy/utils" "github.com/Layr-Labs/eigenda-proxy/verify" "github.com/Layr-Labs/eigenda/api/clients" "github.com/Layr-Labs/eigenda/api/clients/codecs" "github.com/Layr-Labs/eigenda/encoding/kzg" - "github.com/urfave/cli/v2" -) - -const ( - // eigenda client flags - EigenDADisperserRPCFlagName = "eigenda-disperser-rpc" - StatusQueryRetryIntervalFlagName = "eigenda-status-query-retry-interval" - StatusQueryTimeoutFlagName = "eigenda-status-query-timeout" - DisableTLSFlagName = "eigenda-disable-tls" - ResponseTimeoutFlagName = "eigenda-response-timeout" - CustomQuorumIDsFlagName = "eigenda-custom-quorum-ids" - SignerPrivateKeyHexFlagName = "eigenda-signer-private-key-hex" - PutBlobEncodingVersionFlagName = "eigenda-put-blob-encoding-version" - DisablePointVerificationModeFlagName = "eigenda-disable-point-verification-mode" - - // cert verification flags - CertVerificationEnabledFlagName = "eigenda-cert-verification-enabled" - EthRPCFlagName = "eigenda-eth-rpc" - SvcManagerAddrFlagName = "eigenda-svc-manager-addr" - EthConfirmationDepthFlagName = "eigenda-eth-confirmation-depth" - - // kzg flags - G1PathFlagName = "eigenda-g1-path" - G2TauFlagName = "eigenda-g2-tau-path" - CachePathFlagName = "eigenda-cache-path" - MaxBlobLengthFlagName = "eigenda-max-blob-length" - - // memstore flags - MemstoreFlagName = "memstore.enabled" - MemstoreExpirationFlagName = "memstore.expiration" - MemstorePutLatencyFlagName = "memstore.put-latency" - MemstoreGetLatencyFlagName = "memstore.get-latency" - - // redis client flags - RedisEndpointFlagName = "redis.endpoint" - RedisPasswordFlagName = "redis.password" - RedisDBFlagName = "redis.db" - RedisEvictionFlagName = "redis.eviction" - - // S3 client flags - S3CredentialTypeFlagName = "s3.credential-type" // #nosec G101 - S3BucketFlagName = "s3.bucket" // #nosec G101 - S3PathFlagName = "s3.path" - S3EndpointFlagName = "s3.endpoint" - S3AccessKeyIDFlagName = "s3.access-key-id" // #nosec G101 - S3AccessKeySecretFlagName = "s3.access-key-secret" // #nosec G101 - S3BackupFlagName = "s3.backup" - S3TimeoutFlagName = "s3.timeout" - - // routing flags - FallbackTargets = "routing.fallback-targets" - CacheTargets = "routing.cache-targets" ) const ( @@ -111,8 +61,8 @@ type Config struct { CacheTargets []string // secondary storage - RedisCfg store.RedisConfig - S3Config store.S3Config + RedisConfig store.RedisConfig + S3Config store.S3Config } // GetMaxBlobLength ... returns the maximum blob length in bytes @@ -161,7 +111,7 @@ func (cfg *Config) VerificationCfg() *verify.Config { // ReadConfig ... parses the Config from the provided flags or environment variables. func ReadConfig(ctx *cli.Context) Config { cfg := Config{ - RedisCfg: store.RedisConfig{ + RedisConfig: store.RedisConfig{ Endpoint: ctx.String(RedisEndpointFlagName), Password: ctx.String(RedisPasswordFlagName), DB: ctx.Int(RedisDBFlagName), @@ -191,8 +141,8 @@ func ReadConfig(ctx *cli.Context) Config { G1Path: ctx.String(G1PathFlagName), G2PowerOfTauPath: ctx.String(G2TauFlagName), CacheDir: ctx.String(CachePathFlagName), - CertVerificationEnabled: ctx.Bool(CertVerificationEnabledFlagName), MaxBlobLength: ctx.String(MaxBlobLengthFlagName), + CertVerificationEnabled: ctx.Bool(CertVerificationEnabledFlagName), SvcManagerAddr: ctx.String(SvcManagerAddrFlagName), EthRPC: ctx.String(EthRPCFlagName), EthConfirmationDepth: ctx.Int64(EthConfirmationDepthFlagName), @@ -200,8 +150,8 @@ func ReadConfig(ctx *cli.Context) Config { MemstoreBlobExpiration: ctx.Duration(MemstoreExpirationFlagName), MemstoreGetLatency: ctx.Duration(MemstoreGetLatencyFlagName), MemstorePutLatency: ctx.Duration(MemstorePutLatencyFlagName), - FallbackTargets: ctx.StringSlice(FallbackTargets), - CacheTargets: ctx.StringSlice(CacheTargets), + FallbackTargets: ctx.StringSlice(FallbackTargetsFlagName), + CacheTargets: ctx.StringSlice(CacheTargetsFlagName), } // the eigenda client can only wait for 0 confirmations or finality // the da-proxy has a more fine-grained notion of confirmation depth @@ -273,7 +223,7 @@ func (cfg *Config) Check() error { } } - if cfg.RedisCfg.Endpoint == "" && cfg.RedisCfg.Password != "" { + if cfg.RedisConfig.Endpoint == "" && cfg.RedisConfig.Password != "" { return fmt.Errorf("redis password is set, but endpoint is not") } @@ -296,231 +246,3 @@ func (cfg *Config) Check() error { return nil } - -// s3Flags ... used for S3 backend configuration -func s3Flags() []cli.Flag { - return []cli.Flag{ - &cli.StringFlag{ - Name: S3CredentialTypeFlagName, - Usage: "The way to authenticate to S3, options are [iam, static]", - EnvVars: prefixEnvVars("S3_CREDENTIAL_TYPE"), - }, - &cli.StringFlag{ - Name: S3BucketFlagName, - Usage: "bucket name for S3 storage", - EnvVars: prefixEnvVars("S3_BUCKET"), - }, - &cli.StringFlag{ - Name: S3PathFlagName, - Usage: "path for S3 storage", - EnvVars: prefixEnvVars("S3_PATH"), - }, - &cli.StringFlag{ - Name: S3EndpointFlagName, - Usage: "endpoint for S3 storage", - Value: "", - EnvVars: prefixEnvVars("S3_ENDPOINT"), - }, - &cli.StringFlag{ - Name: S3AccessKeyIDFlagName, - Usage: "access key id for S3 storage", - Value: "", - EnvVars: prefixEnvVars("S3_ACCESS_KEY_ID"), - }, - &cli.StringFlag{ - Name: S3AccessKeySecretFlagName, - Usage: "access key secret for S3 storage", - Value: "", - EnvVars: prefixEnvVars("S3_ACCESS_KEY_SECRET"), - }, - &cli.BoolFlag{ - Name: S3BackupFlagName, - Usage: "whether to use S3 as a backup store to ensure resiliency in case of EigenDA read failure", - Value: false, - EnvVars: prefixEnvVars("S3_BACKUP"), - }, - &cli.DurationFlag{ - Name: S3TimeoutFlagName, - Usage: "timeout for S3 storage operations (e.g. get, put)", - Value: 5 * time.Second, - EnvVars: prefixEnvVars("S3_TIMEOUT"), - }, - } -} - -// redisFlags ... used for Redis backend configuration -func redisFlags() []cli.Flag { - return []cli.Flag{ - &cli.StringFlag{ - Name: RedisEndpointFlagName, - Usage: "Redis endpoint", - EnvVars: prefixEnvVars("REDIS_ENDPOINT"), - }, - &cli.StringFlag{ - Name: RedisPasswordFlagName, - Usage: "Redis password", - EnvVars: prefixEnvVars("REDIS_PASSWORD"), - }, - &cli.IntFlag{ - Name: RedisDBFlagName, - Usage: "Redis database", - Value: 0, - EnvVars: prefixEnvVars("REDIS_DB"), - }, - &cli.DurationFlag{ - Name: RedisEvictionFlagName, - Usage: "Redis eviction time", - Value: 24 * time.Hour, - EnvVars: prefixEnvVars("REDIS_EVICTION"), - }, - } -} - -func CLIFlags() []cli.Flag { - // TODO: Decompose all flags into constituent parts based on their respective category / usage - flags := []cli.Flag{ - &cli.StringFlag{ - Name: EigenDADisperserRPCFlagName, - Usage: "RPC endpoint of the EigenDA disperser.", - EnvVars: prefixEnvVars("EIGENDA_DISPERSER_RPC"), - }, - &cli.DurationFlag{ - Name: StatusQueryTimeoutFlagName, - Usage: "Duration to wait for a blob to finalize after being sent for dispersal. Default is 30 minutes.", - Value: 30 * time.Minute, - EnvVars: prefixEnvVars("STATUS_QUERY_TIMEOUT"), - }, - &cli.DurationFlag{ - Name: StatusQueryRetryIntervalFlagName, - Usage: "Interval between retries when awaiting network blob finalization. Default is 5 seconds.", - Value: 5 * time.Second, - EnvVars: prefixEnvVars("STATUS_QUERY_INTERVAL"), - }, - &cli.BoolFlag{ - Name: DisableTLSFlagName, - Usage: "Disable TLS for gRPC communication with the EigenDA disperser. Default is false.", - Value: false, - EnvVars: prefixEnvVars("GRPC_DISABLE_TLS"), - }, - &cli.DurationFlag{ - Name: ResponseTimeoutFlagName, - Usage: "Total time to wait for a response from the EigenDA disperser. Default is 60 seconds.", - Value: 60 * time.Second, - EnvVars: prefixEnvVars("RESPONSE_TIMEOUT"), - }, - &cli.UintSliceFlag{ - Name: CustomQuorumIDsFlagName, - Usage: "Custom quorum IDs for writing blobs. Should not include default quorums 0 or 1.", - Value: cli.NewUintSlice(), - EnvVars: prefixEnvVars("CUSTOM_QUORUM_IDS"), - }, - &cli.StringFlag{ - Name: SignerPrivateKeyHexFlagName, - Usage: "Hex-encoded signer private key. This key should not be associated with an Ethereum address holding any funds.", - EnvVars: prefixEnvVars("SIGNER_PRIVATE_KEY_HEX"), - }, - &cli.UintFlag{ - Name: PutBlobEncodingVersionFlagName, - Usage: "Blob encoding version to use when writing blobs from the high-level interface.", - EnvVars: prefixEnvVars("PUT_BLOB_ENCODING_VERSION"), - Value: 0, - }, - &cli.BoolFlag{ - Name: DisablePointVerificationModeFlagName, - Usage: "Disable point verification mode. This mode performs IFFT on data before writing and FFT on data after reading. Disabling requires supplying the entire blob for verification against the KZG commitment.", - EnvVars: prefixEnvVars("DISABLE_POINT_VERIFICATION_MODE"), - Value: false, - }, - &cli.StringFlag{ - Name: MaxBlobLengthFlagName, - Usage: "Maximum blob length to be written or read from EigenDA. Determines the number of SRS points loaded into memory for KZG commitments. Example units: '30MiB', '4Kb', '30MB'. Maximum size slightly exceeds 1GB.", - EnvVars: prefixEnvVars("MAX_BLOB_LENGTH"), - Value: "16MiB", - }, - &cli.StringFlag{ - Name: G1PathFlagName, - Usage: "Directory path to g1.point file.", - EnvVars: prefixEnvVars("TARGET_KZG_G1_PATH"), - Value: "resources/g1.point", - }, - &cli.StringFlag{ - Name: G2TauFlagName, - Usage: "Directory path to g2.point.powerOf2 file.", - EnvVars: prefixEnvVars("TARGET_G2_TAU_PATH"), - Value: "resources/g2.point.powerOf2", - }, - &cli.StringFlag{ - Name: CachePathFlagName, - Usage: "Directory path to SRS tables for caching.", - EnvVars: prefixEnvVars("TARGET_CACHE_PATH"), - Value: "resources/SRSTables/", - }, - &cli.BoolFlag{ - Name: CertVerificationEnabledFlagName, - Usage: "Whether to verify certificates received from EigenDA disperser.", - EnvVars: prefixEnvVars("CERT_VERIFICATION_ENABLED"), - // TODO: ideally we'd want this to be turned on by default when eigenda backend is used (memstore.enabled=false) - Value: false, - }, - &cli.StringFlag{ - Name: EthRPCFlagName, - Usage: "JSON RPC node endpoint for the Ethereum network used for finalizing DA blobs.\n" + - "See available list here: https://docs.eigenlayer.xyz/eigenda/networks/\n" + - fmt.Sprintf("Mandatory when %s is true.", CertVerificationEnabledFlagName), - EnvVars: prefixEnvVars("ETH_RPC"), - }, - &cli.StringFlag{ - Name: SvcManagerAddrFlagName, - Usage: "The deployed EigenDA service manager address.\n" + - "The list can be found here: https://github.com/Layr-Labs/eigenlayer-middleware/?tab=readme-ov-file#current-mainnet-deployment\n" + - fmt.Sprintf("Mandatory when %s is true.", CertVerificationEnabledFlagName), - EnvVars: prefixEnvVars("SERVICE_MANAGER_ADDR"), - }, - &cli.Int64Flag{ - Name: EthConfirmationDepthFlagName, - Usage: "The number of Ethereum blocks to wait before considering a submitted blob's DA batch submission confirmed.\n" + - "`0` means wait for inclusion only. `-1` means wait for finality.", - EnvVars: prefixEnvVars("ETH_CONFIRMATION_DEPTH"), - Value: -1, - }, - &cli.BoolFlag{ - Name: MemstoreFlagName, - Usage: "Whether to use mem-store for DA logic.", - EnvVars: prefixEnvVars("MEMSTORE_ENABLED"), - }, - &cli.DurationFlag{ - Name: MemstoreExpirationFlagName, - Usage: "Duration that a mem-store blob/commitment pair are allowed to live.", - Value: 25 * time.Minute, - EnvVars: prefixEnvVars("MEMSTORE_EXPIRATION"), - }, - &cli.DurationFlag{ - Name: MemstorePutLatencyFlagName, - Usage: "Artificial latency added for memstore backend to mimic EigenDA's dispersal latency.", - Value: 0, - EnvVars: prefixEnvVars("MEMSTORE_PUT_LATENCY"), - }, - &cli.DurationFlag{ - Name: MemstoreGetLatencyFlagName, - Usage: "Artificial latency added for memstore backend to mimic EigenDA's retrieval latency.", - Value: 0, - EnvVars: prefixEnvVars("MEMSTORE_GET_LATENCY"), - }, - &cli.StringSliceFlag{ - Name: FallbackTargets, - Usage: "List of read fallback targets to rollover to if cert can't be read from EigenDA.", - Value: cli.NewStringSlice(), - EnvVars: prefixEnvVars("FALLBACK_TARGETS"), - }, - &cli.StringSliceFlag{ - Name: CacheTargets, - Usage: "List of caching targets to use fast reads from EigenDA.", - Value: cli.NewStringSlice(), - EnvVars: prefixEnvVars("CACHE_TARGETS"), - }, - } - - flags = append(flags, s3Flags()...) - flags = append(flags, redisFlags()...) - return flags -} diff --git a/server/config_test.go b/server/config_test.go index 36ac6244..24a2388a 100644 --- a/server/config_test.go +++ b/server/config_test.go @@ -11,7 +11,7 @@ import ( func validCfg() *Config { return &Config{ - RedisCfg: store.RedisConfig{ + RedisConfig: store.RedisConfig{ Endpoint: "localhost:6379", Password: "password", DB: 0, @@ -186,7 +186,7 @@ func TestConfigVerification(t *testing.T) { t.Run("BadRedisConfiguration", func(t *testing.T) { cfg := validCfg() - cfg.RedisCfg.Endpoint = "" + cfg.RedisConfig.Endpoint = "" err := cfg.Check() require.Error(t, err) diff --git a/server/flags.go b/server/flags.go index 9046e3b7..002bf9ce 100644 --- a/server/flags.go +++ b/server/flags.go @@ -1,6 +1,8 @@ package server import ( + "time" + "github.com/Layr-Labs/eigenda-proxy/store" "github.com/urfave/cli/v2" @@ -9,9 +11,63 @@ import ( opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" ) +const ( + MemstoreFlagsCategory = "Memstore" +) + const ( ListenAddrFlagName = "addr" PortFlagName = "port" + + // eigenda client flags + EigenDADisperserRPCFlagName = "eigenda-disperser-rpc" + StatusQueryRetryIntervalFlagName = "eigenda-status-query-retry-interval" + StatusQueryTimeoutFlagName = "eigenda-status-query-timeout" + DisableTLSFlagName = "eigenda-disable-tls" + ResponseTimeoutFlagName = "eigenda-response-timeout" + CustomQuorumIDsFlagName = "eigenda-custom-quorum-ids" + SignerPrivateKeyHexFlagName = "eigenda-signer-private-key-hex" + PutBlobEncodingVersionFlagName = "eigenda-put-blob-encoding-version" + DisablePointVerificationModeFlagName = "eigenda-disable-point-verification-mode" + + // cert verification flags + // TODO: should we remove the eigenda prefix since these are not eigenda-client flags? + CertVerificationEnabledFlagName = "eigenda-cert-verification-enabled" + EthRPCFlagName = "eigenda-eth-rpc" + SvcManagerAddrFlagName = "eigenda-svc-manager-addr" + EthConfirmationDepthFlagName = "eigenda-eth-confirmation-depth" + + // kzg flags + G1PathFlagName = "eigenda-g1-path" + G2TauFlagName = "eigenda-g2-tau-path" + CachePathFlagName = "eigenda-cache-path" + MaxBlobLengthFlagName = "eigenda-max-blob-length" + + // memstore flags + MemstoreFlagName = "memstore.enabled" + MemstoreExpirationFlagName = "memstore.expiration" + MemstorePutLatencyFlagName = "memstore.put-latency" + MemstoreGetLatencyFlagName = "memstore.get-latency" + + // redis client flags + RedisEndpointFlagName = "redis.endpoint" + RedisPasswordFlagName = "redis.password" + RedisDBFlagName = "redis.db" + RedisEvictionFlagName = "redis.eviction" + + // S3 client flags + S3CredentialTypeFlagName = "s3.credential-type" // #nosec G101 + S3BucketFlagName = "s3.bucket" // #nosec G101 + S3PathFlagName = "s3.path" + S3EndpointFlagName = "s3.endpoint" + S3AccessKeyIDFlagName = "s3.access-key-id" // #nosec G101 + S3AccessKeySecretFlagName = "s3.access-key-secret" // #nosec G101 + S3BackupFlagName = "s3.backup" + S3TimeoutFlagName = "s3.timeout" + + // routing flags + FallbackTargetsFlagName = "routing.fallback-targets" + CacheTargetsFlagName = "routing.cache-targets" ) const EnvVarPrefix = "EIGENDA_PROXY" @@ -36,9 +92,236 @@ var Flags = []cli.Flag{ }, } +// s3Flags ... used for S3 backend configuration +func s3Flags() []cli.Flag { + return []cli.Flag{ + &cli.StringFlag{ + Name: S3CredentialTypeFlagName, + Usage: "The way to authenticate to S3, options are [iam, static]", + EnvVars: prefixEnvVars("S3_CREDENTIAL_TYPE"), + }, + &cli.StringFlag{ + Name: S3BucketFlagName, + Usage: "bucket name for S3 storage", + EnvVars: prefixEnvVars("S3_BUCKET"), + }, + &cli.StringFlag{ + Name: S3PathFlagName, + Usage: "path for S3 storage", + EnvVars: prefixEnvVars("S3_PATH"), + }, + &cli.StringFlag{ + Name: S3EndpointFlagName, + Usage: "endpoint for S3 storage", + Value: "", + EnvVars: prefixEnvVars("S3_ENDPOINT"), + }, + &cli.StringFlag{ + Name: S3AccessKeyIDFlagName, + Usage: "access key id for S3 storage", + Value: "", + EnvVars: prefixEnvVars("S3_ACCESS_KEY_ID"), + }, + &cli.StringFlag{ + Name: S3AccessKeySecretFlagName, + Usage: "access key secret for S3 storage", + Value: "", + EnvVars: prefixEnvVars("S3_ACCESS_KEY_SECRET"), + }, + &cli.BoolFlag{ + Name: S3BackupFlagName, + Usage: "whether to use S3 as a backup store to ensure resiliency in case of EigenDA read failure", + Value: false, + EnvVars: prefixEnvVars("S3_BACKUP"), + }, + &cli.DurationFlag{ + Name: S3TimeoutFlagName, + Usage: "timeout for S3 storage operations (e.g. get, put)", + Value: 5 * time.Second, + EnvVars: prefixEnvVars("S3_TIMEOUT"), + }, + } +} + +// redisFlags ... used for Redis backend configuration +func redisFlags() []cli.Flag { + return []cli.Flag{ + &cli.StringFlag{ + Name: RedisEndpointFlagName, + Usage: "Redis endpoint", + EnvVars: prefixEnvVars("REDIS_ENDPOINT"), + }, + &cli.StringFlag{ + Name: RedisPasswordFlagName, + Usage: "Redis password", + EnvVars: prefixEnvVars("REDIS_PASSWORD"), + }, + &cli.IntFlag{ + Name: RedisDBFlagName, + Usage: "Redis database", + Value: 0, + EnvVars: prefixEnvVars("REDIS_DB"), + }, + &cli.DurationFlag{ + Name: RedisEvictionFlagName, + Usage: "Redis eviction time", + Value: 24 * time.Hour, + EnvVars: prefixEnvVars("REDIS_EVICTION"), + }, + } +} + +func CLIFlags() []cli.Flag { + // TODO: Decompose all flags into constituent parts based on their respective category / usage + flags := []cli.Flag{ + &cli.StringFlag{ + Name: EigenDADisperserRPCFlagName, + Usage: "RPC endpoint of the EigenDA disperser.", + EnvVars: prefixEnvVars("EIGENDA_DISPERSER_RPC"), + }, + &cli.DurationFlag{ + Name: StatusQueryTimeoutFlagName, + Usage: "Duration to wait for a blob to finalize after being sent for dispersal. Default is 30 minutes.", + Value: 30 * time.Minute, + EnvVars: prefixEnvVars("STATUS_QUERY_TIMEOUT"), + }, + &cli.DurationFlag{ + Name: StatusQueryRetryIntervalFlagName, + Usage: "Interval between retries when awaiting network blob finalization. Default is 5 seconds.", + Value: 5 * time.Second, + EnvVars: prefixEnvVars("STATUS_QUERY_INTERVAL"), + }, + &cli.BoolFlag{ + Name: DisableTLSFlagName, + Usage: "Disable TLS for gRPC communication with the EigenDA disperser. Default is false.", + Value: false, + EnvVars: prefixEnvVars("GRPC_DISABLE_TLS"), + }, + &cli.DurationFlag{ + Name: ResponseTimeoutFlagName, + Usage: "Total time to wait for a response from the EigenDA disperser. Default is 60 seconds.", + Value: 60 * time.Second, + EnvVars: prefixEnvVars("RESPONSE_TIMEOUT"), + }, + &cli.UintSliceFlag{ + Name: CustomQuorumIDsFlagName, + Usage: "Custom quorum IDs for writing blobs. Should not include default quorums 0 or 1.", + Value: cli.NewUintSlice(), + EnvVars: prefixEnvVars("CUSTOM_QUORUM_IDS"), + }, + &cli.StringFlag{ + Name: SignerPrivateKeyHexFlagName, + Usage: "Hex-encoded signer private key. This key should not be associated with an Ethereum address holding any funds.", + EnvVars: prefixEnvVars("SIGNER_PRIVATE_KEY_HEX"), + }, + &cli.UintFlag{ + Name: PutBlobEncodingVersionFlagName, + Usage: "Blob encoding version to use when writing blobs from the high-level interface.", + EnvVars: prefixEnvVars("PUT_BLOB_ENCODING_VERSION"), + Value: 0, + }, + &cli.BoolFlag{ + Name: DisablePointVerificationModeFlagName, + Usage: "Disable point verification mode. This mode performs IFFT on data before writing and FFT on data after reading. Disabling requires supplying the entire blob for verification against the KZG commitment.", + EnvVars: prefixEnvVars("DISABLE_POINT_VERIFICATION_MODE"), + Value: false, + }, + &cli.StringFlag{ + Name: MaxBlobLengthFlagName, + Usage: "Maximum blob length to be written or read from EigenDA. Determines the number of SRS points loaded into memory for KZG commitments. Example units: '30MiB', '4Kb', '30MB'. Maximum size slightly exceeds 1GB.", + EnvVars: prefixEnvVars("MAX_BLOB_LENGTH"), + Value: "16MiB", + }, + &cli.StringFlag{ + Name: G1PathFlagName, + Usage: "Directory path to g1.point file.", + EnvVars: prefixEnvVars("TARGET_KZG_G1_PATH"), + Value: "resources/g1.point", + }, + &cli.StringFlag{ + Name: G2TauFlagName, + Usage: "Directory path to g2.point.powerOf2 file.", + EnvVars: prefixEnvVars("TARGET_G2_TAU_PATH"), + Value: "resources/g2.point.powerOf2", + }, + &cli.StringFlag{ + Name: CachePathFlagName, + Usage: "Directory path to SRS tables for caching.", + EnvVars: prefixEnvVars("TARGET_CACHE_PATH"), + Value: "resources/SRSTables/", + }, + &cli.BoolFlag{ + Name: CertVerificationEnabledFlagName, + Usage: "Whether to verify certificates received from EigenDA disperser.", + EnvVars: prefixEnvVars("CERT_VERIFICATION_ENABLED"), + // TODO: ideally we'd want this to be turned on by default when eigenda backend is used (memstore.enabled=false) + Value: false, + }, + &cli.StringFlag{ + Name: EthRPCFlagName, + Usage: "JSON RPC node endpoint for the Ethereum network used for finalizing DA blobs. See available list here: https://docs.eigenlayer.xyz/eigenda/networks/", + EnvVars: prefixEnvVars("ETH_RPC"), + }, + &cli.StringFlag{ + Name: SvcManagerAddrFlagName, + Usage: "The deployed EigenDA service manager address. The list can be found here: https://github.com/Layr-Labs/eigenlayer-middleware/?tab=readme-ov-file#current-mainnet-deployment", + EnvVars: prefixEnvVars("SERVICE_MANAGER_ADDR"), + }, + &cli.Int64Flag{ + Name: EthConfirmationDepthFlagName, + Usage: "The number of Ethereum blocks to wait before considering a submitted blob's DA batch submission confirmed. `0` means wait for inclusion only. `-1` means wait for finality.", + EnvVars: prefixEnvVars("ETH_CONFIRMATION_DEPTH"), + Value: -1, + }, + &cli.BoolFlag{ + Name: MemstoreFlagName, + Usage: "Whether to use mem-store for DA logic.", + EnvVars: prefixEnvVars("MEMSTORE_ENABLED"), + Category: MemstoreFlagsCategory, + }, + &cli.DurationFlag{ + Name: MemstoreExpirationFlagName, + Usage: "Duration that a mem-store blob/commitment pair are allowed to live.", + Value: 25 * time.Minute, + EnvVars: prefixEnvVars("MEMSTORE_EXPIRATION"), + Category: MemstoreFlagsCategory, + }, + &cli.DurationFlag{ + Name: MemstorePutLatencyFlagName, + Usage: "Artificial latency added for memstore backend to mimic EigenDA's dispersal latency.", + Value: 0, + EnvVars: prefixEnvVars("MEMSTORE_PUT_LATENCY"), + Category: MemstoreFlagsCategory, + }, + &cli.DurationFlag{ + Name: MemstoreGetLatencyFlagName, + Usage: "Artificial latency added for memstore backend to mimic EigenDA's retrieval latency.", + Value: 0, + EnvVars: prefixEnvVars("MEMSTORE_GET_LATENCY"), + Category: MemstoreFlagsCategory, + }, + &cli.StringSliceFlag{ + Name: FallbackTargetsFlagName, + Usage: "List of read fallback targets to rollover to if cert can't be read from EigenDA.", + Value: cli.NewStringSlice(), + EnvVars: prefixEnvVars("FALLBACK_TARGETS"), + }, + &cli.StringSliceFlag{ + Name: CacheTargetsFlagName, + Usage: "List of caching targets to use fast reads from EigenDA.", + Value: cli.NewStringSlice(), + EnvVars: prefixEnvVars("CACHE_TARGETS"), + }, + } + + flags = append(flags, s3Flags()...) + flags = append(flags, redisFlags()...) + return flags +} + func init() { + Flags = CLIFlags() Flags = append(Flags, oplog.CLIFlags(EnvVarPrefix)...) - Flags = append(Flags, CLIFlags()...) Flags = append(Flags, opmetrics.CLIFlags(EnvVarPrefix)...) } @@ -52,7 +335,7 @@ type CLIConfig struct { func ReadCLIConfig(ctx *cli.Context) CLIConfig { config := ReadConfig(ctx) return CLIConfig{ - RedisCfg: config.RedisCfg, + RedisCfg: config.RedisConfig, EigenDAConfig: config, MetricsCfg: opmetrics.ReadCLIConfig(ctx), S3Config: config.S3Config, diff --git a/server/load_store.go b/server/load_store.go index 53e798ca..5be90e4b 100644 --- a/server/load_store.go +++ b/server/load_store.go @@ -77,6 +77,8 @@ func LoadStoreRouter(ctx context.Context, cfg CLIConfig, log log.Logger) (store. log.Warn("Verification disabled") } + // TODO: change this logic... we shouldn't need to calculate this here. + // It should already be part of the config maxBlobLength, err := daCfg.GetMaxBlobLength() if err != nil { return nil, err From 0b0cf9de5dbaf5e827e0a79474f01ffd1d9ad5dc Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Sat, 21 Sep 2024 23:21:55 -0700 Subject: [PATCH 02/18] refactor: move flags+config to new cli package --- {server => cli}/config.go | 2 +- {server => cli}/config_test.go | 2 +- {server => cli}/flags.go | 7 +---- cmd/server/entrypoint.go | 8 ++--- cmd/server/main.go | 4 +-- e2e/server_test.go | 2 +- e2e/setup.go | 53 +++++++++++++++++----------------- server/load_store.go | 11 +++---- 8 files changed, 43 insertions(+), 46 deletions(-) rename {server => cli}/config.go (99%) rename {server => cli}/config_test.go (99%) rename {server => cli}/flags.go (98%) diff --git a/server/config.go b/cli/config.go similarity index 99% rename from server/config.go rename to cli/config.go index 67042631..4317ad46 100644 --- a/server/config.go +++ b/cli/config.go @@ -1,4 +1,4 @@ -package server +package cli import ( "fmt" diff --git a/server/config_test.go b/cli/config_test.go similarity index 99% rename from server/config_test.go rename to cli/config_test.go index 24a2388a..7d493aa7 100644 --- a/server/config_test.go +++ b/cli/config_test.go @@ -1,4 +1,4 @@ -package server +package cli import ( "testing" diff --git a/server/flags.go b/cli/flags.go similarity index 98% rename from server/flags.go rename to cli/flags.go index 002bf9ce..dcde6c0d 100644 --- a/server/flags.go +++ b/cli/flags.go @@ -1,9 +1,8 @@ -package server +package cli import ( "time" - "github.com/Layr-Labs/eigenda-proxy/store" "github.com/urfave/cli/v2" opservice "github.com/ethereum-optimism/optimism/op-service" @@ -326,8 +325,6 @@ func init() { } type CLIConfig struct { - RedisCfg store.RedisConfig - S3Config store.S3Config EigenDAConfig Config MetricsCfg opmetrics.CLIConfig } @@ -335,10 +332,8 @@ type CLIConfig struct { func ReadCLIConfig(ctx *cli.Context) CLIConfig { config := ReadConfig(ctx) return CLIConfig{ - RedisCfg: config.RedisConfig, EigenDAConfig: config, MetricsCfg: opmetrics.ReadCLIConfig(ctx), - S3Config: config.S3Config, } } diff --git a/cmd/server/entrypoint.go b/cmd/server/entrypoint.go index 3f6eac2a..2302aca0 100644 --- a/cmd/server/entrypoint.go +++ b/cmd/server/entrypoint.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + proxycli "github.com/Layr-Labs/eigenda-proxy/cli" "github.com/Layr-Labs/eigenda-proxy/metrics" "github.com/Layr-Labs/eigenda-proxy/server" "github.com/urfave/cli/v2" @@ -17,22 +18,21 @@ func StartProxySvr(cliCtx *cli.Context) error { oplog.SetGlobalLogHandler(log.Handler()) log.Info("Starting EigenDA Proxy Server", "version", Version, "date", Date, "commit", Commit) - cfg := server.ReadCLIConfig(cliCtx) + cfg := proxycli.ReadCLIConfig(cliCtx) if err := cfg.Check(); err != nil { return err } ctx, ctxCancel := context.WithCancel(cliCtx.Context) defer ctxCancel() - m := metrics.NewMetrics("default") - log.Info("Initializing EigenDA proxy server...") daRouter, err := server.LoadStoreRouter(ctx, cfg, log) if err != nil { return fmt.Errorf("failed to create store: %w", err) } - server := server.NewServer(cliCtx.String(server.ListenAddrFlagName), cliCtx.Int(server.PortFlagName), daRouter, log, m) + m := metrics.NewMetrics("default") + server := server.NewServer(cliCtx.String(proxycli.ListenAddrFlagName), cliCtx.Int(proxycli.PortFlagName), daRouter, log, m) if err := server.Start(); err != nil { return fmt.Errorf("failed to start the DA server: %w", err) diff --git a/cmd/server/main.go b/cmd/server/main.go index 910a6112..71553cda 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -8,8 +8,8 @@ import ( "github.com/joho/godotenv" "github.com/urfave/cli/v2" + proxycli "github.com/Layr-Labs/eigenda-proxy/cli" "github.com/Layr-Labs/eigenda-proxy/metrics" - "github.com/Layr-Labs/eigenda-proxy/server" "github.com/ethereum-optimism/optimism/op-service/cliapp" oplog "github.com/ethereum-optimism/optimism/op-service/log" "github.com/ethereum-optimism/optimism/op-service/metrics/doc" @@ -26,7 +26,7 @@ func main() { oplog.SetupDefaults() app := cli.NewApp() - app.Flags = cliapp.ProtectFlags(server.Flags) + app.Flags = cliapp.ProtectFlags(proxycli.Flags) app.Version = Version app.Name = "eigenda-proxy" app.Usage = "EigenDA Proxy Sidecar Service" diff --git a/e2e/server_test.go b/e2e/server_test.go index b3d2c1a8..78637191 100644 --- a/e2e/server_test.go +++ b/e2e/server_test.go @@ -110,7 +110,7 @@ func TestKeccak256CommitmentRequestErrorsWhenS3NotSet(t *testing.T) { testCfg.UseKeccak256ModeS3 = true tsConfig := e2e.TestSuiteConfig(t, testCfg) - tsConfig.S3Config.Endpoint = "" + tsConfig.EigenDAConfig.S3Config.Endpoint = "" ts, kill := e2e.CreateTestSuite(t, tsConfig) defer kill() diff --git a/e2e/setup.go b/e2e/setup.go index b91cdd67..29d42e3b 100644 --- a/e2e/setup.go +++ b/e2e/setup.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/Layr-Labs/eigenda-proxy/cli" "github.com/Layr-Labs/eigenda-proxy/metrics" "github.com/Layr-Labs/eigenda-proxy/server" "github.com/Layr-Labs/eigenda-proxy/store" @@ -52,40 +53,40 @@ func TestConfig(useMemory bool) *Cfg { } } -func createRedisConfig(eigendaCfg server.Config) server.CLIConfig { - return server.CLIConfig{ +func createRedisConfig(eigendaCfg cli.Config) cli.CLIConfig { + eigendaCfg.RedisConfig = store.RedisConfig{ + Endpoint: "127.0.0.1:9001", + Password: "", + DB: 0, + Eviction: 10 * time.Minute, + Profile: true, + } + return cli.CLIConfig{ EigenDAConfig: eigendaCfg, - RedisCfg: store.RedisConfig{ - Endpoint: "127.0.0.1:9001", - Password: "", - DB: 0, - Eviction: 10 * time.Minute, - Profile: true, - }, } } -func createS3Config(eigendaCfg server.Config) server.CLIConfig { +func createS3Config(eigendaCfg cli.Config) cli.CLIConfig { // generate random string bucketName := "eigenda-proxy-test-" + RandString(10) createS3Bucket(bucketName) - return server.CLIConfig{ + eigendaCfg.S3Config = store.S3Config{ + Profiling: true, + Bucket: bucketName, + Path: "", + Endpoint: "localhost:4566", + AccessKeySecret: "minioadmin", + AccessKeyID: "minioadmin", + S3CredentialType: store.S3CredentialStatic, + Backup: false, + } + return cli.CLIConfig{ EigenDAConfig: eigendaCfg, - S3Config: store.S3Config{ - Profiling: true, - Bucket: bucketName, - Path: "", - Endpoint: "localhost:4566", - AccessKeySecret: "minioadmin", - AccessKeyID: "minioadmin", - S3CredentialType: store.S3CredentialStatic, - Backup: false, - }, } } -func TestSuiteConfig(t *testing.T, testCfg *Cfg) server.CLIConfig { +func TestSuiteConfig(t *testing.T, testCfg *Cfg) cli.CLIConfig { // load signer key from environment pk := os.Getenv(privateKey) if pk == "" && !testCfg.UseMemory { @@ -105,7 +106,7 @@ func TestSuiteConfig(t *testing.T, testCfg *Cfg) server.CLIConfig { pollInterval = time.Minute * 1 } - eigendaCfg := server.Config{ + eigendaCfg := cli.Config{ ClientConfig: clients.EigenDAClientConfig{ RPC: holeskyDA, StatusQueryTimeout: time.Minute * 45, @@ -129,7 +130,7 @@ func TestSuiteConfig(t *testing.T, testCfg *Cfg) server.CLIConfig { eigendaCfg.ClientConfig.SignerPrivateKeyHex = "0000000000000000000100000000000000000000000000000000000000000000" } - var cfg server.CLIConfig + var cfg cli.CLIConfig switch { case testCfg.UseKeccak256ModeS3: cfg = createS3Config(eigendaCfg) @@ -147,7 +148,7 @@ func TestSuiteConfig(t *testing.T, testCfg *Cfg) server.CLIConfig { cfg = createRedisConfig(eigendaCfg) default: - cfg = server.CLIConfig{ + cfg = cli.CLIConfig{ EigenDAConfig: eigendaCfg, MetricsCfg: opmetrics.CLIConfig{}, } @@ -162,7 +163,7 @@ type TestSuite struct { Server *server.Server } -func CreateTestSuite(t *testing.T, testSuiteCfg server.CLIConfig) (TestSuite, func()) { +func CreateTestSuite(t *testing.T, testSuiteCfg cli.CLIConfig) (TestSuite, func()) { log := oplog.NewLogger(os.Stdout, oplog.CLIConfig{ Level: log.LevelDebug, Format: oplog.FormatLogFmt, diff --git a/server/load_store.go b/server/load_store.go index 5be90e4b..811249ed 100644 --- a/server/load_store.go +++ b/server/load_store.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/Layr-Labs/eigenda-proxy/cli" "github.com/Layr-Labs/eigenda-proxy/store" "github.com/Layr-Labs/eigenda-proxy/verify" "github.com/Layr-Labs/eigenda/api/clients" @@ -39,24 +40,24 @@ func populateTargets(targets []string, s3 store.PrecomputedKeyStore, redis *stor } // LoadStoreRouter ... creates storage backend clients and instruments them into a storage routing abstraction -func LoadStoreRouter(ctx context.Context, cfg CLIConfig, log log.Logger) (store.IRouter, error) { +func LoadStoreRouter(ctx context.Context, cfg cli.CLIConfig, log log.Logger) (store.IRouter, error) { // create S3 backend store (if enabled) var err error var s3 store.PrecomputedKeyStore var redis *store.RedStore - if cfg.S3Config.Bucket != "" && cfg.S3Config.Endpoint != "" { + if cfg.EigenDAConfig.S3Config.Bucket != "" && cfg.EigenDAConfig.S3Config.Endpoint != "" { log.Info("Using S3 backend") - s3, err = store.NewS3(cfg.S3Config) + s3, err = store.NewS3(cfg.EigenDAConfig.S3Config) if err != nil { return nil, fmt.Errorf("failed to create S3 store: %w", err) } } - if cfg.RedisCfg.Endpoint != "" { + if cfg.EigenDAConfig.RedisConfig.Endpoint != "" { log.Info("Using Redis backend") // create Redis backend store - redis, err = store.NewRedisStore(&cfg.RedisCfg) + redis, err = store.NewRedisStore(&cfg.EigenDAConfig.RedisConfig) if err != nil { return nil, fmt.Errorf("failed to create Redis store: %w", err) } From 25d2c1788d9c60918a25f4627fa71e85a8679196 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Sat, 21 Sep 2024 23:46:43 -0700 Subject: [PATCH 03/18] refactor: stores into subdirs (precomputed_key and generated_key) --- cli/config.go | 16 +++--- cli/config_test.go | 11 ++-- e2e/server_test.go | 2 +- e2e/setup.go | 9 ++-- server/load_store.go | 36 +++++++------ store/{ => generated_key/eigenda}/eigenda.go | 33 ++++++------ .../memstore/memstore.go} | 25 ++++----- .../memstore/memstore_test.go} | 12 ++--- store/{ => precomputed_key/redis}/redis.go | 33 ++++++------ store/{ => precomputed_key/s3}/s3.go | 53 ++++++++++--------- store/store.go | 24 ++++----- 11 files changed, 133 insertions(+), 121 deletions(-) rename store/{ => generated_key/eigenda}/eigenda.go (82%) rename store/{memory.go => generated_key/memstore/memstore.go} (92%) rename store/{memory_test.go => generated_key/memstore/memstore_test.go} (93%) rename store/{ => precomputed_key/redis}/redis.go (67%) rename store/{ => precomputed_key/s3}/s3.go (62%) diff --git a/cli/config.go b/cli/config.go index 4317ad46..0e806618 100644 --- a/cli/config.go +++ b/cli/config.go @@ -8,6 +8,8 @@ import ( "github.com/urfave/cli/v2" "github.com/Layr-Labs/eigenda-proxy/store" + "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" + "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" "github.com/Layr-Labs/eigenda-proxy/utils" "github.com/Layr-Labs/eigenda-proxy/verify" "github.com/Layr-Labs/eigenda/api/clients" @@ -61,8 +63,8 @@ type Config struct { CacheTargets []string // secondary storage - RedisConfig store.RedisConfig - S3Config store.S3Config + RedisConfig redis.Config + S3Config s3.Config } // GetMaxBlobLength ... returns the maximum blob length in bytes @@ -111,14 +113,14 @@ func (cfg *Config) VerificationCfg() *verify.Config { // ReadConfig ... parses the Config from the provided flags or environment variables. func ReadConfig(ctx *cli.Context) Config { cfg := Config{ - RedisConfig: store.RedisConfig{ + RedisConfig: redis.Config{ Endpoint: ctx.String(RedisEndpointFlagName), Password: ctx.String(RedisPasswordFlagName), DB: ctx.Int(RedisDBFlagName), Eviction: ctx.Duration(RedisEvictionFlagName), }, - S3Config: store.S3Config{ - S3CredentialType: store.StringToS3CredentialType(ctx.String(S3CredentialTypeFlagName)), + S3Config: s3.Config{ + S3CredentialType: s3.StringToCredentialType(ctx.String(S3CredentialTypeFlagName)), Bucket: ctx.String(S3BucketFlagName), Path: ctx.String(S3PathFlagName), Endpoint: ctx.String(S3EndpointFlagName), @@ -214,10 +216,10 @@ func (cfg *Config) Check() error { } } - if cfg.S3Config.S3CredentialType == store.S3CredentialUnknown && cfg.S3Config.Endpoint != "" { + if cfg.S3Config.S3CredentialType == s3.CredentialTypeUnknown && cfg.S3Config.Endpoint != "" { return fmt.Errorf("s3 credential type must be set") } - if cfg.S3Config.S3CredentialType == store.S3CredentialStatic { + if cfg.S3Config.S3CredentialType == s3.CredentialTypeStatic { if cfg.S3Config.Endpoint != "" && (cfg.S3Config.AccessKeyID == "" || cfg.S3Config.AccessKeySecret == "") { return fmt.Errorf("s3 endpoint is set, but access key id or access key secret is not set") } diff --git a/cli/config_test.go b/cli/config_test.go index 7d493aa7..f3862959 100644 --- a/cli/config_test.go +++ b/cli/config_test.go @@ -4,20 +4,21 @@ import ( "testing" "time" - "github.com/Layr-Labs/eigenda-proxy/store" + "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" + "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" "github.com/Layr-Labs/eigenda/api/clients" "github.com/stretchr/testify/require" ) func validCfg() *Config { return &Config{ - RedisConfig: store.RedisConfig{ + RedisConfig: redis.Config{ Endpoint: "localhost:6379", Password: "password", DB: 0, Eviction: 10 * time.Minute, }, - S3Config: store.S3Config{ + S3Config: s3.Config{ Bucket: "test-bucket", Path: "", Endpoint: "http://localhost:9000", @@ -110,7 +111,7 @@ func TestConfigVerification(t *testing.T) { t.Run("MissingS3AccessKeys", func(t *testing.T) { cfg := validCfg() - cfg.S3Config.S3CredentialType = store.S3CredentialStatic + cfg.S3Config.S3CredentialType = s3.CredentialTypeStatic cfg.S3Config.Endpoint = "http://localhost:9000" cfg.S3Config.AccessKeyID = "" @@ -121,7 +122,7 @@ func TestConfigVerification(t *testing.T) { t.Run("MissingS3Credential", func(t *testing.T) { cfg := validCfg() - cfg.S3Config.S3CredentialType = store.S3CredentialUnknown + cfg.S3Config.S3CredentialType = s3.CredentialTypeUnknown err := cfg.Check() require.Error(t, err) diff --git a/e2e/server_test.go b/e2e/server_test.go index 78637191..2b9ebc24 100644 --- a/e2e/server_test.go +++ b/e2e/server_test.go @@ -393,7 +393,7 @@ func TestProxyServerCachingWithRedis(t *testing.T) { require.Equal(t, testPreimage, preimage) // ensure that read was from cache - redStats, err := ts.Server.GetStoreStats(store.Redis) + redStats, err := ts.Server.GetStoreStats(store.RedisBackendType) require.NoError(t, err) require.Equal(t, 1, redStats.Reads) diff --git a/e2e/setup.go b/e2e/setup.go index 29d42e3b..dab71858 100644 --- a/e2e/setup.go +++ b/e2e/setup.go @@ -10,7 +10,8 @@ import ( "github.com/Layr-Labs/eigenda-proxy/cli" "github.com/Layr-Labs/eigenda-proxy/metrics" "github.com/Layr-Labs/eigenda-proxy/server" - "github.com/Layr-Labs/eigenda-proxy/store" + "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" + "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" "github.com/Layr-Labs/eigenda/api/clients" "github.com/ethereum/go-ethereum/log" "github.com/minio/minio-go/v7" @@ -54,7 +55,7 @@ func TestConfig(useMemory bool) *Cfg { } func createRedisConfig(eigendaCfg cli.Config) cli.CLIConfig { - eigendaCfg.RedisConfig = store.RedisConfig{ + eigendaCfg.RedisConfig = redis.Config{ Endpoint: "127.0.0.1:9001", Password: "", DB: 0, @@ -71,14 +72,14 @@ func createS3Config(eigendaCfg cli.Config) cli.CLIConfig { bucketName := "eigenda-proxy-test-" + RandString(10) createS3Bucket(bucketName) - eigendaCfg.S3Config = store.S3Config{ + eigendaCfg.S3Config = s3.Config{ Profiling: true, Bucket: bucketName, Path: "", Endpoint: "localhost:4566", AccessKeySecret: "minioadmin", AccessKeyID: "minioadmin", - S3CredentialType: store.S3CredentialStatic, + S3CredentialType: s3.CredentialTypeStatic, Backup: false, } return cli.CLIConfig{ diff --git a/server/load_store.go b/server/load_store.go index 811249ed..7cb5f962 100644 --- a/server/load_store.go +++ b/server/load_store.go @@ -6,26 +6,30 @@ import ( "github.com/Layr-Labs/eigenda-proxy/cli" "github.com/Layr-Labs/eigenda-proxy/store" + "github.com/Layr-Labs/eigenda-proxy/store/generated_key/eigenda" + "github.com/Layr-Labs/eigenda-proxy/store/generated_key/memstore" + "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" + "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" "github.com/Layr-Labs/eigenda-proxy/verify" "github.com/Layr-Labs/eigenda/api/clients" "github.com/ethereum/go-ethereum/log" ) // populateTargets ... creates a list of storage backends based on the provided target strings -func populateTargets(targets []string, s3 store.PrecomputedKeyStore, redis *store.RedStore) []store.PrecomputedKeyStore { +func populateTargets(targets []string, s3 store.PrecomputedKeyStore, redis *redis.Store) []store.PrecomputedKeyStore { stores := make([]store.PrecomputedKeyStore, len(targets)) for i, f := range targets { b := store.StringToBackendType(f) switch b { - case store.Redis: + case store.RedisBackendType: stores[i] = redis - case store.S3: + case store.S3BackendType: stores[i] = s3 - case store.EigenDA, store.Memory: + case store.EigenDABackendType, store.MemoryBackendType: panic(fmt.Sprintf("Invalid target for fallback: %s", f)) case store.Unknown: @@ -43,12 +47,12 @@ func populateTargets(targets []string, s3 store.PrecomputedKeyStore, redis *stor func LoadStoreRouter(ctx context.Context, cfg cli.CLIConfig, log log.Logger) (store.IRouter, error) { // create S3 backend store (if enabled) var err error - var s3 store.PrecomputedKeyStore - var redis *store.RedStore + var s3Store store.PrecomputedKeyStore + var redisStore *redis.Store if cfg.EigenDAConfig.S3Config.Bucket != "" && cfg.EigenDAConfig.S3Config.Endpoint != "" { log.Info("Using S3 backend") - s3, err = store.NewS3(cfg.EigenDAConfig.S3Config) + s3Store, err = s3.NewS3(cfg.EigenDAConfig.S3Config) if err != nil { return nil, fmt.Errorf("failed to create S3 store: %w", err) } @@ -57,7 +61,7 @@ func LoadStoreRouter(ctx context.Context, cfg cli.CLIConfig, log log.Logger) (st if cfg.EigenDAConfig.RedisConfig.Endpoint != "" { log.Info("Using Redis backend") // create Redis backend store - redis, err = store.NewRedisStore(&cfg.EigenDAConfig.RedisConfig) + redisStore, err = redis.NewStore(&cfg.EigenDAConfig.RedisConfig) if err != nil { return nil, fmt.Errorf("failed to create Redis store: %w", err) } @@ -86,10 +90,10 @@ func LoadStoreRouter(ctx context.Context, cfg cli.CLIConfig, log log.Logger) (st } // create EigenDA backend store - var eigenda store.KeyGeneratedStore + var eigenDA store.KeyGeneratedStore if cfg.EigenDAConfig.MemstoreEnabled { log.Info("Using mem-store backend for EigenDA") - eigenda, err = store.NewMemStore(ctx, verifier, log, store.MemStoreConfig{ + eigenDA, err = memstore.New(ctx, verifier, log, memstore.Config{ MaxBlobSizeBytes: maxBlobLength, BlobExpiration: cfg.EigenDAConfig.MemstoreBlobExpiration, PutLatency: cfg.EigenDAConfig.MemstorePutLatency, @@ -103,11 +107,11 @@ func LoadStoreRouter(ctx context.Context, cfg cli.CLIConfig, log log.Logger) (st return nil, err } - eigenda, err = store.NewEigenDAStore( + eigenDA, err = eigenda.NewStore( client, verifier, log, - &store.EigenDAStoreConfig{ + &eigenda.StoreConfig{ MaxBlobSizeBytes: maxBlobLength, EthConfirmationDepth: uint64(cfg.EigenDAConfig.EthConfirmationDepth), // #nosec G115 StatusQueryTimeout: cfg.EigenDAConfig.ClientConfig.StatusQueryTimeout, @@ -120,9 +124,9 @@ func LoadStoreRouter(ctx context.Context, cfg cli.CLIConfig, log log.Logger) (st } // determine read fallbacks - fallbacks := populateTargets(cfg.EigenDAConfig.FallbackTargets, s3, redis) - caches := populateTargets(cfg.EigenDAConfig.CacheTargets, s3, redis) + fallbacks := populateTargets(cfg.EigenDAConfig.FallbackTargets, s3Store, redisStore) + caches := populateTargets(cfg.EigenDAConfig.CacheTargets, s3Store, redisStore) - log.Info("Creating storage router", "eigenda backend type", eigenda != nil, "s3 backend type", s3 != nil) - return store.NewRouter(eigenda, s3, log, caches, fallbacks) + log.Info("Creating storage router", "eigenda backend type", eigenDA != nil, "s3 backend type", s3Store != nil) + return store.NewRouter(eigenDA, s3Store, log, caches, fallbacks) } diff --git a/store/eigenda.go b/store/generated_key/eigenda/eigenda.go similarity index 82% rename from store/eigenda.go rename to store/generated_key/eigenda/eigenda.go index c1811a05..177fce5a 100644 --- a/store/eigenda.go +++ b/store/generated_key/eigenda/eigenda.go @@ -1,4 +1,4 @@ -package store +package eigenda import ( "context" @@ -6,13 +6,14 @@ import ( "fmt" "time" + "github.com/Layr-Labs/eigenda-proxy/store" "github.com/Layr-Labs/eigenda-proxy/verify" "github.com/Layr-Labs/eigenda/api/clients" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" ) -type EigenDAStoreConfig struct { +type StoreConfig struct { MaxBlobSizeBytes uint64 // the # of Ethereum blocks to wait after the EigenDA L1BlockReference # before attempting to verify // & accredit a blob @@ -22,19 +23,19 @@ type EigenDAStoreConfig struct { StatusQueryTimeout time.Duration } -// EigenDAStore does storage interactions and verifications for blobs with DA. -type EigenDAStore struct { +// Store does storage interactions and verifications for blobs with DA. +type Store struct { client *clients.EigenDAClient verifier *verify.Verifier - cfg *EigenDAStoreConfig + cfg *StoreConfig log log.Logger } -var _ KeyGeneratedStore = (*EigenDAStore)(nil) +var _ store.KeyGeneratedStore = (*Store)(nil) -func NewEigenDAStore(client *clients.EigenDAClient, - v *verify.Verifier, log log.Logger, cfg *EigenDAStoreConfig) (*EigenDAStore, error) { - return &EigenDAStore{ +func NewStore(client *clients.EigenDAClient, + v *verify.Verifier, log log.Logger, cfg *StoreConfig) (*Store, error) { + return &Store{ client: client, verifier: v, log: log, @@ -44,7 +45,7 @@ func NewEigenDAStore(client *clients.EigenDAClient, // Get fetches a blob from DA using certificate fields and verifies blob // against commitment to ensure data is valid and non-tampered. -func (e EigenDAStore) Get(ctx context.Context, key []byte) ([]byte, error) { +func (e Store) Get(ctx context.Context, key []byte) ([]byte, error) { var cert verify.Certificate err := rlp.DecodeBytes(key, &cert) if err != nil { @@ -60,13 +61,13 @@ func (e EigenDAStore) Get(ctx context.Context, key []byte) ([]byte, error) { } // Put disperses a blob for some pre-image and returns the associated RLP encoded certificate commit. -func (e EigenDAStore) Put(ctx context.Context, value []byte) ([]byte, error) { +func (e Store) Put(ctx context.Context, value []byte) ([]byte, error) { encodedBlob, err := e.client.GetCodec().EncodeBlob(value) if err != nil { return nil, fmt.Errorf("EigenDA client failed to re-encode blob: %w", err) } if uint64(len(encodedBlob)) > e.cfg.MaxBlobSizeBytes { - return nil, fmt.Errorf("%w: blob length %d, max blob size %d", ErrProxyOversizedBlob, len(value), e.cfg.MaxBlobSizeBytes) + return nil, fmt.Errorf("%w: blob length %d, max blob size %d", store.ErrProxyOversizedBlob, len(value), e.cfg.MaxBlobSizeBytes) } dispersalStart := time.Now() @@ -116,18 +117,18 @@ func (e EigenDAStore) Put(ctx context.Context, value []byte) ([]byte, error) { } // Entries are a no-op for EigenDA Store -func (e EigenDAStore) Stats() *Stats { +func (e Store) Stats() *store.Stats { return nil } // Backend returns the backend type for EigenDA Store -func (e EigenDAStore) BackendType() BackendType { - return EigenDA +func (e Store) BackendType() store.BackendType { + return store.EigenDABackendType } // Key is used to recover certificate fields and that verifies blob // against commitment to ensure data is valid and non-tampered. -func (e EigenDAStore) Verify(key []byte, value []byte) error { +func (e Store) Verify(key []byte, value []byte) error { var cert verify.Certificate err := rlp.DecodeBytes(key, &cert) if err != nil { diff --git a/store/memory.go b/store/generated_key/memstore/memstore.go similarity index 92% rename from store/memory.go rename to store/generated_key/memstore/memstore.go index 03b80f70..aeb1e78c 100644 --- a/store/memory.go +++ b/store/generated_key/memstore/memstore.go @@ -1,4 +1,4 @@ -package store +package memstore import ( "context" @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" + "github.com/Layr-Labs/eigenda-proxy/store" "github.com/Layr-Labs/eigenda-proxy/verify" "github.com/Layr-Labs/eigenda/api/clients/codecs" "github.com/Layr-Labs/eigenda/api/grpc/common" @@ -22,7 +23,7 @@ const ( DefaultPruneInterval = 500 * time.Millisecond ) -type MemStoreConfig struct { +type Config struct { MaxBlobSizeBytes uint64 BlobExpiration time.Duration // artificial latency added for memstore backend to mimic eigenda's latency @@ -38,7 +39,7 @@ EigenDA operators. type MemStore struct { sync.RWMutex - config MemStoreConfig + config Config l log.Logger keyStarts map[string]time.Time store map[string][]byte @@ -48,11 +49,11 @@ type MemStore struct { reads int } -var _ KeyGeneratedStore = (*MemStore)(nil) +var _ store.KeyGeneratedStore = (*MemStore)(nil) -// NewMemStore ... constructor -func NewMemStore( - ctx context.Context, verifier *verify.Verifier, l log.Logger, config MemStoreConfig, +// New ... constructor +func New( + ctx context.Context, verifier *verify.Verifier, l log.Logger, config Config, ) (*MemStore, error) { store := &MemStore{ l: l, @@ -134,7 +135,7 @@ func (e *MemStore) Get(_ context.Context, commit []byte) ([]byte, error) { func (e *MemStore) Put(_ context.Context, value []byte) ([]byte, error) { time.Sleep(e.config.PutLatency) if uint64(len(value)) > e.config.MaxBlobSizeBytes { - return nil, fmt.Errorf("%w: blob length %d, max blob size %d", ErrProxyOversizedBlob, len(value), e.config.MaxBlobSizeBytes) + return nil, fmt.Errorf("%w: blob length %d, max blob size %d", store.ErrProxyOversizedBlob, len(value), e.config.MaxBlobSizeBytes) } e.Lock() @@ -222,15 +223,15 @@ func (e *MemStore) Verify(_, _ []byte) error { } // Stats ... returns the current usage metrics of the in-memory key-value data store. -func (e *MemStore) Stats() *Stats { +func (e *MemStore) Stats() *store.Stats { e.RLock() defer e.RUnlock() - return &Stats{ + return &store.Stats{ Entries: len(e.store), Reads: e.reads, } } -func (e *MemStore) BackendType() BackendType { - return Memory +func (e *MemStore) BackendType() store.BackendType { + return store.MemoryBackendType } diff --git a/store/memory_test.go b/store/generated_key/memstore/memstore_test.go similarity index 93% rename from store/memory_test.go rename to store/generated_key/memstore/memstore_test.go index 63103fba..05a91de3 100644 --- a/store/memory_test.go +++ b/store/generated_key/memstore/memstore_test.go @@ -1,4 +1,4 @@ -package store +package memstore import ( "context" @@ -16,8 +16,8 @@ const ( testPreimage = "Four score and seven years ago" ) -func getDefaultMemStoreTestConfig() MemStoreConfig { - return MemStoreConfig{ +func getDefaultMemStoreTestConfig() Config { + return Config{ MaxBlobSizeBytes: 1024 * 1024, BlobExpiration: 0, PutLatency: 0, @@ -46,7 +46,7 @@ func TestGetSet(t *testing.T) { verifier, err := verify.NewVerifier(getDefaultVerifierTestConfig(), nil) require.NoError(t, err) - ms, err := NewMemStore( + ms, err := New( ctx, verifier, log.New(), @@ -75,7 +75,7 @@ func TestExpiration(t *testing.T) { memstoreConfig := getDefaultMemStoreTestConfig() memstoreConfig.BlobExpiration = 10 * time.Millisecond - ms, err := NewMemStore( + ms, err := New( ctx, verifier, log.New(), @@ -111,7 +111,7 @@ func TestLatency(t *testing.T) { config := getDefaultMemStoreTestConfig() config.PutLatency = putLatency config.GetLatency = getLatency - ms, err := NewMemStore(ctx, verifier, log.New(), config) + ms, err := New(ctx, verifier, log.New(), config) require.NoError(t, err) diff --git a/store/redis.go b/store/precomputed_key/redis/redis.go similarity index 67% rename from store/redis.go rename to store/precomputed_key/redis/redis.go index 4985698e..6b2975ac 100644 --- a/store/redis.go +++ b/store/precomputed_key/redis/redis.go @@ -1,4 +1,4 @@ -package store +package redis import ( "context" @@ -6,11 +6,12 @@ import ( "fmt" "time" + "github.com/Layr-Labs/eigenda-proxy/store" "github.com/go-redis/redis/v8" ) -// RedisConfig ... user configurable -type RedisConfig struct { +// Config ... user configurable +type Config struct { Endpoint string Password string DB int @@ -18,8 +19,8 @@ type RedisConfig struct { Profile bool } -// RedStore ... Redis storage backend implementation (This not safe for concurrent usage) -type RedStore struct { +// Store ... Redis storage backend implementation (This not safe for concurrent usage) +type Store struct { eviction time.Duration client *redis.Client @@ -29,10 +30,10 @@ type RedStore struct { entries int } -var _ PrecomputedKeyStore = (*RedStore)(nil) +var _ store.PrecomputedKeyStore = (*Store)(nil) -// NewRedisStore ... constructor -func NewRedisStore(cfg *RedisConfig) (*RedStore, error) { +// NewStore ... constructor +func NewStore(cfg *Config) (*Store, error) { client := redis.NewClient(&redis.Options{ Addr: cfg.Endpoint, Password: cfg.Password, @@ -48,7 +49,7 @@ func NewRedisStore(cfg *RedisConfig) (*RedStore, error) { return nil, fmt.Errorf("failed to ping redis server: %w", cmd.Err()) } - return &RedStore{ + return &Store{ eviction: cfg.Eviction, client: client, profile: cfg.Profile, @@ -58,7 +59,7 @@ func NewRedisStore(cfg *RedisConfig) (*RedStore, error) { // Get ... retrieves a value from the Redis store. Returns nil if the key is not found vs. an error // if the key is found but the value is not retrievable. -func (r *RedStore) Get(ctx context.Context, key []byte) ([]byte, error) { +func (r *Store) Get(ctx context.Context, key []byte) ([]byte, error) { value, err := r.client.Get(ctx, string(key)).Result() if errors.Is(err, redis.Nil) { // key DNE return nil, nil @@ -75,7 +76,7 @@ func (r *RedStore) Get(ctx context.Context, key []byte) ([]byte, error) { } // Put ... inserts a value into the Redis store -func (r *RedStore) Put(ctx context.Context, key []byte, value []byte) error { +func (r *Store) Put(ctx context.Context, key []byte, value []byte) error { err := r.client.Set(ctx, string(key), string(value), r.eviction).Err() if err == nil && r.profile { r.entries++ @@ -84,16 +85,16 @@ func (r *RedStore) Put(ctx context.Context, key []byte, value []byte) error { return err } -func (r *RedStore) Verify(_ []byte, _ []byte) error { +func (r *Store) Verify(_ []byte, _ []byte) error { return nil } -func (r *RedStore) BackendType() BackendType { - return Redis +func (r *Store) BackendType() store.BackendType { + return store.RedisBackendType } -func (r *RedStore) Stats() *Stats { - return &Stats{ +func (r *Store) Stats() *store.Stats { + return &store.Stats{ Entries: r.entries, Reads: r.reads, } diff --git a/store/s3.go b/store/precomputed_key/s3/s3.go similarity index 62% rename from store/s3.go rename to store/precomputed_key/s3/s3.go index bfcd1802..a7d9fb7b 100644 --- a/store/s3.go +++ b/store/precomputed_key/s3/s3.go @@ -1,4 +1,4 @@ -package store +package s3 import ( "bytes" @@ -9,6 +9,7 @@ import ( "path" "time" + "github.com/Layr-Labs/eigenda-proxy/store" "github.com/ethereum/go-ethereum/crypto" "github.com/minio/minio-go/v7" @@ -16,27 +17,27 @@ import ( ) const ( - S3CredentialStatic S3CredentialType = "static" - S3CredentialIAM S3CredentialType = "iam" - S3CredentialUnknown S3CredentialType = "unknown" + CredentialTypeStatic CredentialType = "static" + CredentialTypeIAM CredentialType = "iam" + CredentialTypeUnknown CredentialType = "unknown" ) -func StringToS3CredentialType(s string) S3CredentialType { +func StringToCredentialType(s string) CredentialType { switch s { case "static": - return S3CredentialStatic + return CredentialTypeStatic case "iam": - return S3CredentialIAM + return CredentialTypeIAM default: - return S3CredentialUnknown + return CredentialTypeUnknown } } -var _ PrecomputedKeyStore = (*S3Store)(nil) +var _ store.PrecomputedKeyStore = (*Store)(nil) -type S3CredentialType string -type S3Config struct { - S3CredentialType S3CredentialType +type CredentialType string +type Config struct { + S3CredentialType CredentialType Bucket string Path string Endpoint string @@ -47,13 +48,13 @@ type S3Config struct { Timeout time.Duration } -type S3Store struct { - cfg S3Config +type Store struct { + cfg Config client *minio.Client - stats *Stats + stats *store.Stats } -func NewS3(cfg S3Config) (*S3Store, error) { +func NewS3(cfg Config) (*Store, error) { client, err := minio.New(cfg.Endpoint, &minio.Options{ Creds: creds(cfg), Secure: false, @@ -62,17 +63,17 @@ func NewS3(cfg S3Config) (*S3Store, error) { return nil, err } - return &S3Store{ + return &Store{ cfg: cfg, client: client, - stats: &Stats{ + stats: &store.Stats{ Entries: 0, Reads: 0, }, }, nil } -func (s *S3Store) Get(ctx context.Context, key []byte) ([]byte, error) { +func (s *Store) Get(ctx context.Context, key []byte) ([]byte, error) { result, err := s.client.GetObject(ctx, s.cfg.Bucket, path.Join(s.cfg.Path, hex.EncodeToString(key)), minio.GetObjectOptions{}) if err != nil { errResponse := minio.ToErrorResponse(err) @@ -94,7 +95,7 @@ func (s *S3Store) Get(ctx context.Context, key []byte) ([]byte, error) { return data, nil } -func (s *S3Store) Put(ctx context.Context, key []byte, value []byte) error { +func (s *Store) Put(ctx context.Context, key []byte, value []byte) error { _, err := s.client.PutObject(ctx, s.cfg.Bucket, path.Join(s.cfg.Path, hex.EncodeToString(key)), bytes.NewReader(value), int64(len(value)), minio.PutObjectOptions{}) if err != nil { return err @@ -107,7 +108,7 @@ func (s *S3Store) Put(ctx context.Context, key []byte, value []byte) error { return nil } -func (s *S3Store) Verify(key []byte, value []byte) error { +func (s *Store) Verify(key []byte, value []byte) error { h := crypto.Keccak256Hash(value) if !bytes.Equal(h[:], key) { return errors.New("key does not match value") @@ -116,16 +117,16 @@ func (s *S3Store) Verify(key []byte, value []byte) error { return nil } -func (s *S3Store) Stats() *Stats { +func (s *Store) Stats() *store.Stats { return s.stats } -func (s *S3Store) BackendType() BackendType { - return S3 +func (s *Store) BackendType() store.BackendType { + return store.S3BackendType } -func creds(cfg S3Config) *credentials.Credentials { - if cfg.S3CredentialType == S3CredentialIAM { +func creds(cfg Config) *credentials.Credentials { + if cfg.S3CredentialType == CredentialTypeIAM { return credentials.NewIAM("") } return credentials.NewStaticV4(cfg.AccessKeyID, cfg.AccessKeySecret, "") diff --git a/store/store.go b/store/store.go index c48c89d7..050fbd2a 100644 --- a/store/store.go +++ b/store/store.go @@ -9,10 +9,10 @@ import ( type BackendType uint8 const ( - EigenDA BackendType = iota - Memory - S3 - Redis + EigenDABackendType BackendType = iota + MemoryBackendType + S3BackendType + RedisBackendType Unknown ) @@ -24,13 +24,13 @@ var ( func (b BackendType) String() string { switch b { - case EigenDA: + case EigenDABackendType: return "EigenDA" - case Memory: + case MemoryBackendType: return "Memory" - case S3: + case S3BackendType: return "S3" - case Redis: + case RedisBackendType: return "Redis" case Unknown: fallthrough @@ -44,13 +44,13 @@ func StringToBackendType(s string) BackendType { switch lower { case "eigenda": - return EigenDA + return EigenDABackendType case "memory": - return Memory + return MemoryBackendType case "s3": - return S3 + return S3BackendType case "redis": - return Redis + return RedisBackendType case "unknown": fallthrough default: From 1ccae1719c3d5e2cacd90aa75442309237e2b48f Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Sat, 21 Sep 2024 23:57:27 -0700 Subject: [PATCH 04/18] fix: memstore test --- store/generated_key/memstore/memstore_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/store/generated_key/memstore/memstore_test.go b/store/generated_key/memstore/memstore_test.go index 05a91de3..a8030515 100644 --- a/store/generated_key/memstore/memstore_test.go +++ b/store/generated_key/memstore/memstore_test.go @@ -29,9 +29,9 @@ func getDefaultVerifierTestConfig() *verify.Config { return &verify.Config{ VerifyCerts: false, KzgConfig: &kzg.KzgConfig{ - G1Path: "../resources/g1.point", - G2PowerOf2Path: "../resources/g2.point.powerOf2", - CacheDir: "../resources/SRSTables", + G1Path: "../../../resources/g1.point", + G2PowerOf2Path: "../../../resources/g2.point.powerOf2", + CacheDir: "../../..resources/SRSTables", SRSOrder: 3000, SRSNumberToLoad: 3000, NumWorker: uint64(runtime.GOMAXPROCS(0)), From 4662a20ce9c4621fb5d139336e7f26470236c145 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Sat, 21 Sep 2024 23:57:52 -0700 Subject: [PATCH 05/18] refactor: move config back to server package + rename cli->flags --- cmd/server/entrypoint.go | 6 +-- cmd/server/main.go | 4 +- e2e/setup.go | 19 ++++--- {cli => flags}/flags.go | 23 +------- {cli => server}/config.go | 96 +++++++++++++++++++++------------- {cli => server}/config_test.go | 2 +- server/load_store.go | 3 +- 7 files changed, 77 insertions(+), 76 deletions(-) rename {cli => flags}/flags.go (96%) rename {cli => server}/config.go (68%) rename {cli => server}/config_test.go (99%) diff --git a/cmd/server/entrypoint.go b/cmd/server/entrypoint.go index 2302aca0..66975d65 100644 --- a/cmd/server/entrypoint.go +++ b/cmd/server/entrypoint.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - proxycli "github.com/Layr-Labs/eigenda-proxy/cli" + "github.com/Layr-Labs/eigenda-proxy/flags" "github.com/Layr-Labs/eigenda-proxy/metrics" "github.com/Layr-Labs/eigenda-proxy/server" "github.com/urfave/cli/v2" @@ -18,7 +18,7 @@ func StartProxySvr(cliCtx *cli.Context) error { oplog.SetGlobalLogHandler(log.Handler()) log.Info("Starting EigenDA Proxy Server", "version", Version, "date", Date, "commit", Commit) - cfg := proxycli.ReadCLIConfig(cliCtx) + cfg := server.ReadCLIConfig(cliCtx) if err := cfg.Check(); err != nil { return err } @@ -32,7 +32,7 @@ func StartProxySvr(cliCtx *cli.Context) error { return fmt.Errorf("failed to create store: %w", err) } m := metrics.NewMetrics("default") - server := server.NewServer(cliCtx.String(proxycli.ListenAddrFlagName), cliCtx.Int(proxycli.PortFlagName), daRouter, log, m) + server := server.NewServer(cliCtx.String(flags.ListenAddrFlagName), cliCtx.Int(flags.PortFlagName), daRouter, log, m) if err := server.Start(); err != nil { return fmt.Errorf("failed to start the DA server: %w", err) diff --git a/cmd/server/main.go b/cmd/server/main.go index 71553cda..3bb73a4c 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -8,7 +8,7 @@ import ( "github.com/joho/godotenv" "github.com/urfave/cli/v2" - proxycli "github.com/Layr-Labs/eigenda-proxy/cli" + "github.com/Layr-Labs/eigenda-proxy/flags" "github.com/Layr-Labs/eigenda-proxy/metrics" "github.com/ethereum-optimism/optimism/op-service/cliapp" oplog "github.com/ethereum-optimism/optimism/op-service/log" @@ -26,7 +26,7 @@ func main() { oplog.SetupDefaults() app := cli.NewApp() - app.Flags = cliapp.ProtectFlags(proxycli.Flags) + app.Flags = cliapp.ProtectFlags(flags.Flags) app.Version = Version app.Name = "eigenda-proxy" app.Usage = "EigenDA Proxy Sidecar Service" diff --git a/e2e/setup.go b/e2e/setup.go index dab71858..7b09637b 100644 --- a/e2e/setup.go +++ b/e2e/setup.go @@ -7,7 +7,6 @@ import ( "testing" "time" - "github.com/Layr-Labs/eigenda-proxy/cli" "github.com/Layr-Labs/eigenda-proxy/metrics" "github.com/Layr-Labs/eigenda-proxy/server" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" @@ -54,7 +53,7 @@ func TestConfig(useMemory bool) *Cfg { } } -func createRedisConfig(eigendaCfg cli.Config) cli.CLIConfig { +func createRedisConfig(eigendaCfg server.Config) server.CLIConfig { eigendaCfg.RedisConfig = redis.Config{ Endpoint: "127.0.0.1:9001", Password: "", @@ -62,12 +61,12 @@ func createRedisConfig(eigendaCfg cli.Config) cli.CLIConfig { Eviction: 10 * time.Minute, Profile: true, } - return cli.CLIConfig{ + return server.CLIConfig{ EigenDAConfig: eigendaCfg, } } -func createS3Config(eigendaCfg cli.Config) cli.CLIConfig { +func createS3Config(eigendaCfg server.Config) server.CLIConfig { // generate random string bucketName := "eigenda-proxy-test-" + RandString(10) createS3Bucket(bucketName) @@ -82,12 +81,12 @@ func createS3Config(eigendaCfg cli.Config) cli.CLIConfig { S3CredentialType: s3.CredentialTypeStatic, Backup: false, } - return cli.CLIConfig{ + return server.CLIConfig{ EigenDAConfig: eigendaCfg, } } -func TestSuiteConfig(t *testing.T, testCfg *Cfg) cli.CLIConfig { +func TestSuiteConfig(t *testing.T, testCfg *Cfg) server.CLIConfig { // load signer key from environment pk := os.Getenv(privateKey) if pk == "" && !testCfg.UseMemory { @@ -107,7 +106,7 @@ func TestSuiteConfig(t *testing.T, testCfg *Cfg) cli.CLIConfig { pollInterval = time.Minute * 1 } - eigendaCfg := cli.Config{ + eigendaCfg := server.Config{ ClientConfig: clients.EigenDAClientConfig{ RPC: holeskyDA, StatusQueryTimeout: time.Minute * 45, @@ -131,7 +130,7 @@ func TestSuiteConfig(t *testing.T, testCfg *Cfg) cli.CLIConfig { eigendaCfg.ClientConfig.SignerPrivateKeyHex = "0000000000000000000100000000000000000000000000000000000000000000" } - var cfg cli.CLIConfig + var cfg server.CLIConfig switch { case testCfg.UseKeccak256ModeS3: cfg = createS3Config(eigendaCfg) @@ -149,7 +148,7 @@ func TestSuiteConfig(t *testing.T, testCfg *Cfg) cli.CLIConfig { cfg = createRedisConfig(eigendaCfg) default: - cfg = cli.CLIConfig{ + cfg = server.CLIConfig{ EigenDAConfig: eigendaCfg, MetricsCfg: opmetrics.CLIConfig{}, } @@ -164,7 +163,7 @@ type TestSuite struct { Server *server.Server } -func CreateTestSuite(t *testing.T, testSuiteCfg cli.CLIConfig) (TestSuite, func()) { +func CreateTestSuite(t *testing.T, testSuiteCfg server.CLIConfig) (TestSuite, func()) { log := oplog.NewLogger(os.Stdout, oplog.CLIConfig{ Level: log.LevelDebug, Format: oplog.FormatLogFmt, diff --git a/cli/flags.go b/flags/flags.go similarity index 96% rename from cli/flags.go rename to flags/flags.go index dcde6c0d..fc204338 100644 --- a/cli/flags.go +++ b/flags/flags.go @@ -1,4 +1,4 @@ -package cli +package flags import ( "time" @@ -323,24 +323,3 @@ func init() { Flags = append(Flags, oplog.CLIFlags(EnvVarPrefix)...) Flags = append(Flags, opmetrics.CLIFlags(EnvVarPrefix)...) } - -type CLIConfig struct { - EigenDAConfig Config - MetricsCfg opmetrics.CLIConfig -} - -func ReadCLIConfig(ctx *cli.Context) CLIConfig { - config := ReadConfig(ctx) - return CLIConfig{ - EigenDAConfig: config, - MetricsCfg: opmetrics.ReadCLIConfig(ctx), - } -} - -func (c CLIConfig) Check() error { - err := c.EigenDAConfig.Check() - if err != nil { - return err - } - return nil -} diff --git a/cli/config.go b/server/config.go similarity index 68% rename from cli/config.go rename to server/config.go index 0e806618..ebbdb17c 100644 --- a/cli/config.go +++ b/server/config.go @@ -1,4 +1,4 @@ -package cli +package server import ( "fmt" @@ -7,6 +7,7 @@ import ( "github.com/urfave/cli/v2" + "github.com/Layr-Labs/eigenda-proxy/flags" "github.com/Layr-Labs/eigenda-proxy/store" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" @@ -15,6 +16,8 @@ import ( "github.com/Layr-Labs/eigenda/api/clients" "github.com/Layr-Labs/eigenda/api/clients/codecs" "github.com/Layr-Labs/eigenda/encoding/kzg" + + opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" ) const ( @@ -114,46 +117,46 @@ func (cfg *Config) VerificationCfg() *verify.Config { func ReadConfig(ctx *cli.Context) Config { cfg := Config{ RedisConfig: redis.Config{ - Endpoint: ctx.String(RedisEndpointFlagName), - Password: ctx.String(RedisPasswordFlagName), - DB: ctx.Int(RedisDBFlagName), - Eviction: ctx.Duration(RedisEvictionFlagName), + Endpoint: ctx.String(flags.RedisEndpointFlagName), + Password: ctx.String(flags.RedisPasswordFlagName), + DB: ctx.Int(flags.RedisDBFlagName), + Eviction: ctx.Duration(flags.RedisEvictionFlagName), }, S3Config: s3.Config{ - S3CredentialType: s3.StringToCredentialType(ctx.String(S3CredentialTypeFlagName)), - Bucket: ctx.String(S3BucketFlagName), - Path: ctx.String(S3PathFlagName), - Endpoint: ctx.String(S3EndpointFlagName), - AccessKeyID: ctx.String(S3AccessKeyIDFlagName), - AccessKeySecret: ctx.String(S3AccessKeySecretFlagName), - Backup: ctx.Bool(S3BackupFlagName), - Timeout: ctx.Duration(S3TimeoutFlagName), + S3CredentialType: s3.StringToCredentialType(ctx.String(flags.S3CredentialTypeFlagName)), + Bucket: ctx.String(flags.S3BucketFlagName), + Path: ctx.String(flags.S3PathFlagName), + Endpoint: ctx.String(flags.S3EndpointFlagName), + AccessKeyID: ctx.String(flags.S3AccessKeyIDFlagName), + AccessKeySecret: ctx.String(flags.S3AccessKeySecretFlagName), + Backup: ctx.Bool(flags.S3BackupFlagName), + Timeout: ctx.Duration(flags.S3TimeoutFlagName), }, ClientConfig: clients.EigenDAClientConfig{ - RPC: ctx.String(EigenDADisperserRPCFlagName), - StatusQueryRetryInterval: ctx.Duration(StatusQueryRetryIntervalFlagName), - StatusQueryTimeout: ctx.Duration(StatusQueryTimeoutFlagName), - DisableTLS: ctx.Bool(DisableTLSFlagName), - ResponseTimeout: ctx.Duration(ResponseTimeoutFlagName), - CustomQuorumIDs: ctx.UintSlice(CustomQuorumIDsFlagName), - SignerPrivateKeyHex: ctx.String(SignerPrivateKeyHexFlagName), - PutBlobEncodingVersion: codecs.BlobEncodingVersion(ctx.Uint(PutBlobEncodingVersionFlagName)), - DisablePointVerificationMode: ctx.Bool(DisablePointVerificationModeFlagName), + RPC: ctx.String(flags.EigenDADisperserRPCFlagName), + StatusQueryRetryInterval: ctx.Duration(flags.StatusQueryRetryIntervalFlagName), + StatusQueryTimeout: ctx.Duration(flags.StatusQueryTimeoutFlagName), + DisableTLS: ctx.Bool(flags.DisableTLSFlagName), + ResponseTimeout: ctx.Duration(flags.ResponseTimeoutFlagName), + CustomQuorumIDs: ctx.UintSlice(flags.CustomQuorumIDsFlagName), + SignerPrivateKeyHex: ctx.String(flags.SignerPrivateKeyHexFlagName), + PutBlobEncodingVersion: codecs.BlobEncodingVersion(ctx.Uint(flags.PutBlobEncodingVersionFlagName)), + DisablePointVerificationMode: ctx.Bool(flags.DisablePointVerificationModeFlagName), }, - G1Path: ctx.String(G1PathFlagName), - G2PowerOfTauPath: ctx.String(G2TauFlagName), - CacheDir: ctx.String(CachePathFlagName), - MaxBlobLength: ctx.String(MaxBlobLengthFlagName), - CertVerificationEnabled: ctx.Bool(CertVerificationEnabledFlagName), - SvcManagerAddr: ctx.String(SvcManagerAddrFlagName), - EthRPC: ctx.String(EthRPCFlagName), - EthConfirmationDepth: ctx.Int64(EthConfirmationDepthFlagName), - MemstoreEnabled: ctx.Bool(MemstoreFlagName), - MemstoreBlobExpiration: ctx.Duration(MemstoreExpirationFlagName), - MemstoreGetLatency: ctx.Duration(MemstoreGetLatencyFlagName), - MemstorePutLatency: ctx.Duration(MemstorePutLatencyFlagName), - FallbackTargets: ctx.StringSlice(FallbackTargetsFlagName), - CacheTargets: ctx.StringSlice(CacheTargetsFlagName), + G1Path: ctx.String(flags.G1PathFlagName), + G2PowerOfTauPath: ctx.String(flags.G2TauFlagName), + CacheDir: ctx.String(flags.CachePathFlagName), + MaxBlobLength: ctx.String(flags.MaxBlobLengthFlagName), + CertVerificationEnabled: ctx.Bool(flags.CertVerificationEnabledFlagName), + SvcManagerAddr: ctx.String(flags.SvcManagerAddrFlagName), + EthRPC: ctx.String(flags.EthRPCFlagName), + EthConfirmationDepth: ctx.Int64(flags.EthConfirmationDepthFlagName), + MemstoreEnabled: ctx.Bool(flags.MemstoreFlagName), + MemstoreBlobExpiration: ctx.Duration(flags.MemstoreExpirationFlagName), + MemstoreGetLatency: ctx.Duration(flags.MemstoreGetLatencyFlagName), + MemstorePutLatency: ctx.Duration(flags.MemstorePutLatencyFlagName), + FallbackTargets: ctx.StringSlice(flags.FallbackTargetsFlagName), + CacheTargets: ctx.StringSlice(flags.CacheTargetsFlagName), } // the eigenda client can only wait for 0 confirmations or finality // the da-proxy has a more fine-grained notion of confirmation depth @@ -248,3 +251,24 @@ func (cfg *Config) Check() error { return nil } + +type CLIConfig struct { + EigenDAConfig Config + MetricsCfg opmetrics.CLIConfig +} + +func ReadCLIConfig(ctx *cli.Context) CLIConfig { + config := ReadConfig(ctx) + return CLIConfig{ + EigenDAConfig: config, + MetricsCfg: opmetrics.ReadCLIConfig(ctx), + } +} + +func (c CLIConfig) Check() error { + err := c.EigenDAConfig.Check() + if err != nil { + return err + } + return nil +} diff --git a/cli/config_test.go b/server/config_test.go similarity index 99% rename from cli/config_test.go rename to server/config_test.go index f3862959..b317e54c 100644 --- a/cli/config_test.go +++ b/server/config_test.go @@ -1,4 +1,4 @@ -package cli +package server import ( "testing" diff --git a/server/load_store.go b/server/load_store.go index 7cb5f962..9e5796ce 100644 --- a/server/load_store.go +++ b/server/load_store.go @@ -4,7 +4,6 @@ import ( "context" "fmt" - "github.com/Layr-Labs/eigenda-proxy/cli" "github.com/Layr-Labs/eigenda-proxy/store" "github.com/Layr-Labs/eigenda-proxy/store/generated_key/eigenda" "github.com/Layr-Labs/eigenda-proxy/store/generated_key/memstore" @@ -44,7 +43,7 @@ func populateTargets(targets []string, s3 store.PrecomputedKeyStore, redis *redi } // LoadStoreRouter ... creates storage backend clients and instruments them into a storage routing abstraction -func LoadStoreRouter(ctx context.Context, cfg cli.CLIConfig, log log.Logger) (store.IRouter, error) { +func LoadStoreRouter(ctx context.Context, cfg CLIConfig, log log.Logger) (store.IRouter, error) { // create S3 backend store (if enabled) var err error var s3Store store.PrecomputedKeyStore From 159149495328234c61dbaebf9cbd1f7406140d38 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Sun, 22 Sep 2024 00:16:56 -0700 Subject: [PATCH 06/18] refactor: move redis flags+config into redis package cli.go --- flags/flags.go | 38 ++---------------- server/config.go | 7 +--- store/precomputed_key/redis/cli.go | 64 ++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 41 deletions(-) create mode 100644 store/precomputed_key/redis/cli.go diff --git a/flags/flags.go b/flags/flags.go index fc204338..57d7a53c 100644 --- a/flags/flags.go +++ b/flags/flags.go @@ -3,6 +3,7 @@ package flags import ( "time" + "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" "github.com/urfave/cli/v2" opservice "github.com/ethereum-optimism/optimism/op-service" @@ -12,6 +13,7 @@ import ( const ( MemstoreFlagsCategory = "Memstore" + RedisCategory = "Redis" ) const ( @@ -48,12 +50,6 @@ const ( MemstorePutLatencyFlagName = "memstore.put-latency" MemstoreGetLatencyFlagName = "memstore.get-latency" - // redis client flags - RedisEndpointFlagName = "redis.endpoint" - RedisPasswordFlagName = "redis.password" - RedisDBFlagName = "redis.db" - RedisEvictionFlagName = "redis.eviction" - // S3 client flags S3CredentialTypeFlagName = "s3.credential-type" // #nosec G101 S3BucketFlagName = "s3.bucket" // #nosec G101 @@ -142,34 +138,6 @@ func s3Flags() []cli.Flag { } } -// redisFlags ... used for Redis backend configuration -func redisFlags() []cli.Flag { - return []cli.Flag{ - &cli.StringFlag{ - Name: RedisEndpointFlagName, - Usage: "Redis endpoint", - EnvVars: prefixEnvVars("REDIS_ENDPOINT"), - }, - &cli.StringFlag{ - Name: RedisPasswordFlagName, - Usage: "Redis password", - EnvVars: prefixEnvVars("REDIS_PASSWORD"), - }, - &cli.IntFlag{ - Name: RedisDBFlagName, - Usage: "Redis database", - Value: 0, - EnvVars: prefixEnvVars("REDIS_DB"), - }, - &cli.DurationFlag{ - Name: RedisEvictionFlagName, - Usage: "Redis eviction time", - Value: 24 * time.Hour, - EnvVars: prefixEnvVars("REDIS_EVICTION"), - }, - } -} - func CLIFlags() []cli.Flag { // TODO: Decompose all flags into constituent parts based on their respective category / usage flags := []cli.Flag{ @@ -314,7 +282,6 @@ func CLIFlags() []cli.Flag { } flags = append(flags, s3Flags()...) - flags = append(flags, redisFlags()...) return flags } @@ -322,4 +289,5 @@ func init() { Flags = CLIFlags() Flags = append(Flags, oplog.CLIFlags(EnvVarPrefix)...) Flags = append(Flags, opmetrics.CLIFlags(EnvVarPrefix)...) + Flags = append(Flags, redis.CLIFlags(EnvVarPrefix, RedisCategory)...) } diff --git a/server/config.go b/server/config.go index ebbdb17c..b98e4051 100644 --- a/server/config.go +++ b/server/config.go @@ -116,12 +116,7 @@ func (cfg *Config) VerificationCfg() *verify.Config { // ReadConfig ... parses the Config from the provided flags or environment variables. func ReadConfig(ctx *cli.Context) Config { cfg := Config{ - RedisConfig: redis.Config{ - Endpoint: ctx.String(flags.RedisEndpointFlagName), - Password: ctx.String(flags.RedisPasswordFlagName), - DB: ctx.Int(flags.RedisDBFlagName), - Eviction: ctx.Duration(flags.RedisEvictionFlagName), - }, + RedisConfig: redis.ReadConfig(ctx), S3Config: s3.Config{ S3CredentialType: s3.StringToCredentialType(ctx.String(flags.S3CredentialTypeFlagName)), Bucket: ctx.String(flags.S3BucketFlagName), diff --git a/store/precomputed_key/redis/cli.go b/store/precomputed_key/redis/cli.go new file mode 100644 index 00000000..423d6f8f --- /dev/null +++ b/store/precomputed_key/redis/cli.go @@ -0,0 +1,64 @@ +package redis + +import ( + "time" + + "github.com/urfave/cli/v2" +) + +var ( + EndpointFlagName = withFlagPrefix("endpoint") + PasswordFlagName = withFlagPrefix("password") + DBFlagName = withFlagPrefix("db") + EvictionFlagName = withFlagPrefix("eviction") +) + +func withFlagPrefix(s string) string { + return "redis." + s +} + +func withEnvPrefix(envPrefix, s string) []string { + return []string{envPrefix + "_REDIS_" + s} +} + +// CLIFlags ... used for Redis backend configuration +// category is used to group the flags in the help output (see https://cli.urfave.org/v2/examples/flags/#grouping) +func CLIFlags(envPrefix, category string) []cli.Flag { + return []cli.Flag{ + &cli.StringFlag{ + Name: EndpointFlagName, + Usage: "Redis endpoint", + EnvVars: withEnvPrefix(envPrefix, "ENDPOINT"), + Category: category, + }, + &cli.StringFlag{ + Name: PasswordFlagName, + Usage: "Redis password", + EnvVars: withEnvPrefix(envPrefix, "PASSWORD"), + Category: category, + }, + &cli.IntFlag{ + Name: DBFlagName, + Usage: "Redis database", + Value: 0, + EnvVars: withEnvPrefix(envPrefix, "DB"), + Category: category, + }, + &cli.DurationFlag{ + Name: EvictionFlagName, + Usage: "Redis eviction time", + Value: 24 * time.Hour, + EnvVars: withEnvPrefix(envPrefix, "EVICTION"), + Category: category, + }, + } +} + +func ReadConfig(ctx *cli.Context) Config { + return Config{ + Endpoint: ctx.String(EndpointFlagName), + Password: ctx.String(PasswordFlagName), + DB: ctx.Int(DBFlagName), + Eviction: ctx.Duration(EvictionFlagName), + } +} From 86aecb6ec05aa498c580a5ed1db7d1545b043c51 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Sun, 22 Sep 2024 11:59:04 -0700 Subject: [PATCH 07/18] refactor: move s3 flags to their own package cli.go --- e2e/setup.go | 16 +++--- flags/flags.go | 96 +++++++-------------------------- server/config.go | 15 ++---- server/config_test.go | 4 +- store/precomputed_key/s3/cli.go | 92 +++++++++++++++++++++++++++++++ store/precomputed_key/s3/s3.go | 20 +++---- 6 files changed, 133 insertions(+), 110 deletions(-) create mode 100644 store/precomputed_key/s3/cli.go diff --git a/e2e/setup.go b/e2e/setup.go index 7b09637b..20c35035 100644 --- a/e2e/setup.go +++ b/e2e/setup.go @@ -72,14 +72,14 @@ func createS3Config(eigendaCfg server.Config) server.CLIConfig { createS3Bucket(bucketName) eigendaCfg.S3Config = s3.Config{ - Profiling: true, - Bucket: bucketName, - Path: "", - Endpoint: "localhost:4566", - AccessKeySecret: "minioadmin", - AccessKeyID: "minioadmin", - S3CredentialType: s3.CredentialTypeStatic, - Backup: false, + Profiling: true, + Bucket: bucketName, + Path: "", + Endpoint: "localhost:4566", + AccessKeySecret: "minioadmin", + AccessKeyID: "minioadmin", + CredentialType: s3.CredentialTypeStatic, + Backup: false, } return server.CLIConfig{ EigenDAConfig: eigendaCfg, diff --git a/flags/flags.go b/flags/flags.go index 57d7a53c..455334f4 100644 --- a/flags/flags.go +++ b/flags/flags.go @@ -4,6 +4,7 @@ import ( "time" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" + "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" "github.com/urfave/cli/v2" opservice "github.com/ethereum-optimism/optimism/op-service" @@ -14,6 +15,7 @@ import ( const ( MemstoreFlagsCategory = "Memstore" RedisCategory = "Redis" + S3Category = "S3" ) const ( @@ -50,16 +52,6 @@ const ( MemstorePutLatencyFlagName = "memstore.put-latency" MemstoreGetLatencyFlagName = "memstore.get-latency" - // S3 client flags - S3CredentialTypeFlagName = "s3.credential-type" // #nosec G101 - S3BucketFlagName = "s3.bucket" // #nosec G101 - S3PathFlagName = "s3.path" - S3EndpointFlagName = "s3.endpoint" - S3AccessKeyIDFlagName = "s3.access-key-id" // #nosec G101 - S3AccessKeySecretFlagName = "s3.access-key-secret" // #nosec G101 - S3BackupFlagName = "s3.backup" - S3TimeoutFlagName = "s3.timeout" - // routing flags FallbackTargetsFlagName = "routing.fallback-targets" CacheTargetsFlagName = "routing.cache-targets" @@ -71,76 +63,21 @@ func prefixEnvVars(name string) []string { return opservice.PrefixEnvVar(EnvVarPrefix, name) } -// Flags contains the list of configuration options available to the binary. -var Flags = []cli.Flag{ - &cli.StringFlag{ - Name: ListenAddrFlagName, - Usage: "server listening address", - Value: "0.0.0.0", - EnvVars: prefixEnvVars("ADDR"), - }, - &cli.IntFlag{ - Name: PortFlagName, - Usage: "server listening port", - Value: 3100, - EnvVars: prefixEnvVars("PORT"), - }, -} - -// s3Flags ... used for S3 backend configuration -func s3Flags() []cli.Flag { - return []cli.Flag{ - &cli.StringFlag{ - Name: S3CredentialTypeFlagName, - Usage: "The way to authenticate to S3, options are [iam, static]", - EnvVars: prefixEnvVars("S3_CREDENTIAL_TYPE"), - }, - &cli.StringFlag{ - Name: S3BucketFlagName, - Usage: "bucket name for S3 storage", - EnvVars: prefixEnvVars("S3_BUCKET"), - }, - &cli.StringFlag{ - Name: S3PathFlagName, - Usage: "path for S3 storage", - EnvVars: prefixEnvVars("S3_PATH"), - }, - &cli.StringFlag{ - Name: S3EndpointFlagName, - Usage: "endpoint for S3 storage", - Value: "", - EnvVars: prefixEnvVars("S3_ENDPOINT"), - }, - &cli.StringFlag{ - Name: S3AccessKeyIDFlagName, - Usage: "access key id for S3 storage", - Value: "", - EnvVars: prefixEnvVars("S3_ACCESS_KEY_ID"), - }, - &cli.StringFlag{ - Name: S3AccessKeySecretFlagName, - Usage: "access key secret for S3 storage", - Value: "", - EnvVars: prefixEnvVars("S3_ACCESS_KEY_SECRET"), - }, - &cli.BoolFlag{ - Name: S3BackupFlagName, - Usage: "whether to use S3 as a backup store to ensure resiliency in case of EigenDA read failure", - Value: false, - EnvVars: prefixEnvVars("S3_BACKUP"), - }, - &cli.DurationFlag{ - Name: S3TimeoutFlagName, - Usage: "timeout for S3 storage operations (e.g. get, put)", - Value: 5 * time.Second, - EnvVars: prefixEnvVars("S3_TIMEOUT"), - }, - } -} - func CLIFlags() []cli.Flag { // TODO: Decompose all flags into constituent parts based on their respective category / usage flags := []cli.Flag{ + &cli.StringFlag{ + Name: ListenAddrFlagName, + Usage: "server listening address", + Value: "0.0.0.0", + EnvVars: prefixEnvVars("ADDR"), + }, + &cli.IntFlag{ + Name: PortFlagName, + Usage: "server listening port", + Value: 3100, + EnvVars: prefixEnvVars("PORT"), + }, &cli.StringFlag{ Name: EigenDADisperserRPCFlagName, Usage: "RPC endpoint of the EigenDA disperser.", @@ -281,13 +218,16 @@ func CLIFlags() []cli.Flag { }, } - flags = append(flags, s3Flags()...) return flags } +// Flags contains the list of configuration options available to the binary. +var Flags = []cli.Flag{} + func init() { Flags = CLIFlags() Flags = append(Flags, oplog.CLIFlags(EnvVarPrefix)...) Flags = append(Flags, opmetrics.CLIFlags(EnvVarPrefix)...) Flags = append(Flags, redis.CLIFlags(EnvVarPrefix, RedisCategory)...) + Flags = append(Flags, s3.CLIFlags(EnvVarPrefix, S3Category)...) } diff --git a/server/config.go b/server/config.go index b98e4051..a37f68ca 100644 --- a/server/config.go +++ b/server/config.go @@ -117,16 +117,7 @@ func (cfg *Config) VerificationCfg() *verify.Config { func ReadConfig(ctx *cli.Context) Config { cfg := Config{ RedisConfig: redis.ReadConfig(ctx), - S3Config: s3.Config{ - S3CredentialType: s3.StringToCredentialType(ctx.String(flags.S3CredentialTypeFlagName)), - Bucket: ctx.String(flags.S3BucketFlagName), - Path: ctx.String(flags.S3PathFlagName), - Endpoint: ctx.String(flags.S3EndpointFlagName), - AccessKeyID: ctx.String(flags.S3AccessKeyIDFlagName), - AccessKeySecret: ctx.String(flags.S3AccessKeySecretFlagName), - Backup: ctx.Bool(flags.S3BackupFlagName), - Timeout: ctx.Duration(flags.S3TimeoutFlagName), - }, + S3Config: s3.ReadConfig(ctx), ClientConfig: clients.EigenDAClientConfig{ RPC: ctx.String(flags.EigenDADisperserRPCFlagName), StatusQueryRetryInterval: ctx.Duration(flags.StatusQueryRetryIntervalFlagName), @@ -214,10 +205,10 @@ func (cfg *Config) Check() error { } } - if cfg.S3Config.S3CredentialType == s3.CredentialTypeUnknown && cfg.S3Config.Endpoint != "" { + if cfg.S3Config.CredentialType == s3.CredentialTypeUnknown && cfg.S3Config.Endpoint != "" { return fmt.Errorf("s3 credential type must be set") } - if cfg.S3Config.S3CredentialType == s3.CredentialTypeStatic { + if cfg.S3Config.CredentialType == s3.CredentialTypeStatic { if cfg.S3Config.Endpoint != "" && (cfg.S3Config.AccessKeyID == "" || cfg.S3Config.AccessKeySecret == "") { return fmt.Errorf("s3 endpoint is set, but access key id or access key secret is not set") } diff --git a/server/config_test.go b/server/config_test.go index b317e54c..2ee82b3f 100644 --- a/server/config_test.go +++ b/server/config_test.go @@ -111,7 +111,7 @@ func TestConfigVerification(t *testing.T) { t.Run("MissingS3AccessKeys", func(t *testing.T) { cfg := validCfg() - cfg.S3Config.S3CredentialType = s3.CredentialTypeStatic + cfg.S3Config.CredentialType = s3.CredentialTypeStatic cfg.S3Config.Endpoint = "http://localhost:9000" cfg.S3Config.AccessKeyID = "" @@ -122,7 +122,7 @@ func TestConfigVerification(t *testing.T) { t.Run("MissingS3Credential", func(t *testing.T) { cfg := validCfg() - cfg.S3Config.S3CredentialType = s3.CredentialTypeUnknown + cfg.S3Config.CredentialType = s3.CredentialTypeUnknown err := cfg.Check() require.Error(t, err) diff --git a/store/precomputed_key/s3/cli.go b/store/precomputed_key/s3/cli.go new file mode 100644 index 00000000..7826ba4a --- /dev/null +++ b/store/precomputed_key/s3/cli.go @@ -0,0 +1,92 @@ +package s3 + +import ( + "time" + + "github.com/urfave/cli/v2" +) + +var ( + EndpointFlagName = withFlagPrefix("endpoint") + CredentialTypeFlagName = withFlagPrefix("credential-type") + AccessKeyIDFlagName = withFlagPrefix("access-key-id") // #nosec G101 + AccessKeySecretFlagName = withFlagPrefix("access-key-secret") // #nosec G101 + BucketFlagName = withFlagPrefix("bucket") + PathFlagName = withFlagPrefix("path") + BackupFlagName = withFlagPrefix("backup") + TimeoutFlagName = withFlagPrefix("timeout") +) + +func withFlagPrefix(s string) string { + return "s3." + s +} + +func withEnvPrefix(envPrefix, s string) []string { + return []string{envPrefix + "_S3_" + s} +} + +// CLIFlags ... used for S3 backend configuration +// category is used to group the flags in the help output (see https://cli.urfave.org/v2/examples/flags/#grouping) +func CLIFlags(envPrefix, category string) []cli.Flag { + return []cli.Flag{ + &cli.StringFlag{ + Name: EndpointFlagName, + Usage: "endpoint for S3 storage", + Value: "", + EnvVars: withEnvPrefix(envPrefix, "S3_ENDPOINT"), + }, + &cli.StringFlag{ + Name: CredentialTypeFlagName, + Usage: "The way to authenticate to S3, options are [iam, static]", + EnvVars: withEnvPrefix(envPrefix, "CREDENTIAL_TYPE"), + Category: category, + }, + &cli.StringFlag{ + Name: AccessKeyIDFlagName, + Usage: "access key id for S3 storage", + Value: "", + EnvVars: withEnvPrefix(envPrefix, "ACCESS_KEY_ID"), + }, + &cli.StringFlag{ + Name: AccessKeySecretFlagName, + Usage: "access key secret for S3 storage", + Value: "", + EnvVars: withEnvPrefix(envPrefix, "ACCESS_KEY_SECRET"), + }, + &cli.StringFlag{ + Name: BucketFlagName, + Usage: "bucket name for S3 storage", + EnvVars: withEnvPrefix(envPrefix, "BUCKET"), + }, + &cli.StringFlag{ + Name: PathFlagName, + Usage: "path for S3 storage", + EnvVars: withEnvPrefix(envPrefix, "PATH"), + }, + &cli.BoolFlag{ + Name: BackupFlagName, + Usage: "whether to use S3 as a backup store to ensure resiliency in case of EigenDA read failure", + Value: false, + EnvVars: withEnvPrefix(envPrefix, "BACKUP"), + }, + &cli.DurationFlag{ + Name: TimeoutFlagName, + Usage: "timeout for S3 storage operations (e.g. get, put)", + Value: 5 * time.Second, + EnvVars: withEnvPrefix(envPrefix, "TIMEOUT"), + }, + } +} + +func ReadConfig(ctx *cli.Context) Config { + return Config{ + CredentialType: StringToCredentialType(ctx.String(CredentialTypeFlagName)), + Endpoint: ctx.String(EndpointFlagName), + AccessKeyID: ctx.String(AccessKeyIDFlagName), + AccessKeySecret: ctx.String(AccessKeySecretFlagName), + Bucket: ctx.String(BucketFlagName), + Path: ctx.String(PathFlagName), + Backup: ctx.Bool(BackupFlagName), + Timeout: ctx.Duration(TimeoutFlagName), + } +} diff --git a/store/precomputed_key/s3/s3.go b/store/precomputed_key/s3/s3.go index a7d9fb7b..6213245d 100644 --- a/store/precomputed_key/s3/s3.go +++ b/store/precomputed_key/s3/s3.go @@ -37,15 +37,15 @@ var _ store.PrecomputedKeyStore = (*Store)(nil) type CredentialType string type Config struct { - S3CredentialType CredentialType - Bucket string - Path string - Endpoint string - AccessKeyID string - AccessKeySecret string - Profiling bool - Backup bool - Timeout time.Duration + CredentialType CredentialType + Endpoint string + AccessKeyID string + AccessKeySecret string + Bucket string + Path string + Backup bool + Timeout time.Duration + Profiling bool } type Store struct { @@ -126,7 +126,7 @@ func (s *Store) BackendType() store.BackendType { } func creds(cfg Config) *credentials.Credentials { - if cfg.S3CredentialType == CredentialTypeIAM { + if cfg.CredentialType == CredentialTypeIAM { return credentials.NewIAM("") } return credentials.NewStaticV4(cfg.AccessKeyID, cfg.AccessKeySecret, "") From fee342c88b2a205df7761e4b3b6bde0531af5ec6 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Sun, 22 Sep 2024 12:28:28 -0700 Subject: [PATCH 08/18] refactor: move eigenda_client flags to their own (temporary) package --- e2e/setup.go | 4 +- flags/eigenda_flags/cli.go | 112 +++++++++++++++++++++++++++++++++++++ flags/flags.go | 72 ++---------------------- server/config.go | 23 +++----- server/config_test.go | 4 +- server/load_store.go | 4 +- 6 files changed, 131 insertions(+), 88 deletions(-) create mode 100644 flags/eigenda_flags/cli.go diff --git a/e2e/setup.go b/e2e/setup.go index 20c35035..d9a7b63c 100644 --- a/e2e/setup.go +++ b/e2e/setup.go @@ -107,7 +107,7 @@ func TestSuiteConfig(t *testing.T, testCfg *Cfg) server.CLIConfig { } eigendaCfg := server.Config{ - ClientConfig: clients.EigenDAClientConfig{ + EdaClientConfig: clients.EigenDAClientConfig{ RPC: holeskyDA, StatusQueryTimeout: time.Minute * 45, StatusQueryRetryInterval: pollInterval, @@ -127,7 +127,7 @@ func TestSuiteConfig(t *testing.T, testCfg *Cfg) server.CLIConfig { } if testCfg.UseMemory { - eigendaCfg.ClientConfig.SignerPrivateKeyHex = "0000000000000000000100000000000000000000000000000000000000000000" + eigendaCfg.EdaClientConfig.SignerPrivateKeyHex = "0000000000000000000100000000000000000000000000000000000000000000" } var cfg server.CLIConfig diff --git a/flags/eigenda_flags/cli.go b/flags/eigenda_flags/cli.go new file mode 100644 index 00000000..d350961e --- /dev/null +++ b/flags/eigenda_flags/cli.go @@ -0,0 +1,112 @@ +package eigenda_flags + +import ( + "time" + + "github.com/Layr-Labs/eigenda/api/clients" + "github.com/Layr-Labs/eigenda/api/clients/codecs" + "github.com/urfave/cli/v2" +) + +// TODO: we should eventually move all of these flags into the eigenda repo + +var ( + DisperserRPCFlagName = withFlagPrefix("disperser-rpc") + StatusQueryRetryIntervalFlagName = withFlagPrefix("status-query-retry-interval") + StatusQueryTimeoutFlagName = withFlagPrefix("status-query-timeout") + DisableTLSFlagName = withFlagPrefix("disable-tls") + ResponseTimeoutFlagName = withFlagPrefix("response-timeout") + CustomQuorumIDsFlagName = withFlagPrefix("custom-quorum-ids") + SignerPrivateKeyHexFlagName = withFlagPrefix("signer-private-key-hex") + PutBlobEncodingVersionFlagName = withFlagPrefix("put-blob-encoding-version") + DisablePointVerificationModeFlagName = withFlagPrefix("disable-point-verification-mode") +) + +func withFlagPrefix(s string) string { + return "eigenda." + s +} + +func withEnvPrefix(envPrefix, s string) []string { + return []string{envPrefix + "_EIGENDA_" + s} +} + +// CLIFlags ... used for EigenDA client configuration +func CLIFlags(envPrefix, category string) []cli.Flag { + return []cli.Flag{ + &cli.StringFlag{ + Name: DisperserRPCFlagName, + Usage: "RPC endpoint of the EigenDA disperser.", + EnvVars: withEnvPrefix(envPrefix, "DISPERSER_RPC"), + Category: category, + }, + &cli.DurationFlag{ + Name: StatusQueryTimeoutFlagName, + Usage: "Duration to wait for a blob to finalize after being sent for dispersal. Default is 30 minutes.", + Value: 30 * time.Minute, + EnvVars: withEnvPrefix(envPrefix, "STATUS_QUERY_TIMEOUT"), + Category: category, + }, + &cli.DurationFlag{ + Name: StatusQueryRetryIntervalFlagName, + Usage: "Interval between retries when awaiting network blob finalization. Default is 5 seconds.", + Value: 5 * time.Second, + EnvVars: withEnvPrefix(envPrefix, "STATUS_QUERY_INTERVAL"), + Category: category, + }, + &cli.BoolFlag{ + Name: DisableTLSFlagName, + Usage: "Disable TLS for gRPC communication with the EigenDA disperser. Default is false.", + Value: false, + EnvVars: withEnvPrefix(envPrefix, "GRPC_DISABLE_TLS"), + Category: category, + }, + &cli.DurationFlag{ + Name: ResponseTimeoutFlagName, + Usage: "Total time to wait for a response from the EigenDA disperser. Default is 60 seconds.", + Value: 60 * time.Second, + EnvVars: withEnvPrefix(envPrefix, "RESPONSE_TIMEOUT"), + Category: category, + }, + &cli.UintSliceFlag{ + Name: CustomQuorumIDsFlagName, + Usage: "Custom quorum IDs for writing blobs. Should not include default quorums 0 or 1.", + Value: cli.NewUintSlice(), + EnvVars: withEnvPrefix(envPrefix, "CUSTOM_QUORUM_IDS"), + Category: category, + }, + &cli.StringFlag{ + Name: SignerPrivateKeyHexFlagName, + Usage: "Hex-encoded signer private key. This key should not be associated with an Ethereum address holding any funds.", + EnvVars: withEnvPrefix(envPrefix, "SIGNER_PRIVATE_KEY_HEX"), + Category: category, + }, + &cli.UintFlag{ + Name: PutBlobEncodingVersionFlagName, + Usage: "Blob encoding version to use when writing blobs from the high-level interface.", + EnvVars: withEnvPrefix(envPrefix, "PUT_BLOB_ENCODING_VERSION"), + Value: 0, + Category: category, + }, + &cli.BoolFlag{ + Name: DisablePointVerificationModeFlagName, + Usage: "Disable point verification mode. This mode performs IFFT on data before writing and FFT on data after reading. Disabling requires supplying the entire blob for verification against the KZG commitment.", + EnvVars: withEnvPrefix(envPrefix, "DISABLE_POINT_VERIFICATION_MODE"), + Value: false, + Category: category, + }, + } +} + +func ReadConfig(ctx *cli.Context) clients.EigenDAClientConfig { + return clients.EigenDAClientConfig{ + RPC: ctx.String(DisperserRPCFlagName), + StatusQueryRetryInterval: ctx.Duration(StatusQueryRetryIntervalFlagName), + StatusQueryTimeout: ctx.Duration(StatusQueryTimeoutFlagName), + DisableTLS: ctx.Bool(DisableTLSFlagName), + ResponseTimeout: ctx.Duration(ResponseTimeoutFlagName), + CustomQuorumIDs: ctx.UintSlice(CustomQuorumIDsFlagName), + SignerPrivateKeyHex: ctx.String(SignerPrivateKeyHexFlagName), + PutBlobEncodingVersion: codecs.BlobEncodingVersion(ctx.Uint(PutBlobEncodingVersionFlagName)), + DisablePointVerificationMode: ctx.Bool(DisablePointVerificationModeFlagName), + } +} diff --git a/flags/flags.go b/flags/flags.go index 455334f4..96d57969 100644 --- a/flags/flags.go +++ b/flags/flags.go @@ -3,6 +3,7 @@ package flags import ( "time" + "github.com/Layr-Labs/eigenda-proxy/flags/eigenda_flags" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" "github.com/urfave/cli/v2" @@ -13,26 +14,16 @@ import ( ) const ( - MemstoreFlagsCategory = "Memstore" - RedisCategory = "Redis" - S3Category = "S3" + EigenDAClientCategory = "EigenDA Client" + MemstoreFlagsCategory = "Memstore (replaces EigenDA when enabled)" + RedisCategory = "Redis Cache/Fallback" + S3Category = "S3 Cache/Fallback" ) const ( ListenAddrFlagName = "addr" PortFlagName = "port" - // eigenda client flags - EigenDADisperserRPCFlagName = "eigenda-disperser-rpc" - StatusQueryRetryIntervalFlagName = "eigenda-status-query-retry-interval" - StatusQueryTimeoutFlagName = "eigenda-status-query-timeout" - DisableTLSFlagName = "eigenda-disable-tls" - ResponseTimeoutFlagName = "eigenda-response-timeout" - CustomQuorumIDsFlagName = "eigenda-custom-quorum-ids" - SignerPrivateKeyHexFlagName = "eigenda-signer-private-key-hex" - PutBlobEncodingVersionFlagName = "eigenda-put-blob-encoding-version" - DisablePointVerificationModeFlagName = "eigenda-disable-point-verification-mode" - // cert verification flags // TODO: should we remove the eigenda prefix since these are not eigenda-client flags? CertVerificationEnabledFlagName = "eigenda-cert-verification-enabled" @@ -78,58 +69,6 @@ func CLIFlags() []cli.Flag { Value: 3100, EnvVars: prefixEnvVars("PORT"), }, - &cli.StringFlag{ - Name: EigenDADisperserRPCFlagName, - Usage: "RPC endpoint of the EigenDA disperser.", - EnvVars: prefixEnvVars("EIGENDA_DISPERSER_RPC"), - }, - &cli.DurationFlag{ - Name: StatusQueryTimeoutFlagName, - Usage: "Duration to wait for a blob to finalize after being sent for dispersal. Default is 30 minutes.", - Value: 30 * time.Minute, - EnvVars: prefixEnvVars("STATUS_QUERY_TIMEOUT"), - }, - &cli.DurationFlag{ - Name: StatusQueryRetryIntervalFlagName, - Usage: "Interval between retries when awaiting network blob finalization. Default is 5 seconds.", - Value: 5 * time.Second, - EnvVars: prefixEnvVars("STATUS_QUERY_INTERVAL"), - }, - &cli.BoolFlag{ - Name: DisableTLSFlagName, - Usage: "Disable TLS for gRPC communication with the EigenDA disperser. Default is false.", - Value: false, - EnvVars: prefixEnvVars("GRPC_DISABLE_TLS"), - }, - &cli.DurationFlag{ - Name: ResponseTimeoutFlagName, - Usage: "Total time to wait for a response from the EigenDA disperser. Default is 60 seconds.", - Value: 60 * time.Second, - EnvVars: prefixEnvVars("RESPONSE_TIMEOUT"), - }, - &cli.UintSliceFlag{ - Name: CustomQuorumIDsFlagName, - Usage: "Custom quorum IDs for writing blobs. Should not include default quorums 0 or 1.", - Value: cli.NewUintSlice(), - EnvVars: prefixEnvVars("CUSTOM_QUORUM_IDS"), - }, - &cli.StringFlag{ - Name: SignerPrivateKeyHexFlagName, - Usage: "Hex-encoded signer private key. This key should not be associated with an Ethereum address holding any funds.", - EnvVars: prefixEnvVars("SIGNER_PRIVATE_KEY_HEX"), - }, - &cli.UintFlag{ - Name: PutBlobEncodingVersionFlagName, - Usage: "Blob encoding version to use when writing blobs from the high-level interface.", - EnvVars: prefixEnvVars("PUT_BLOB_ENCODING_VERSION"), - Value: 0, - }, - &cli.BoolFlag{ - Name: DisablePointVerificationModeFlagName, - Usage: "Disable point verification mode. This mode performs IFFT on data before writing and FFT on data after reading. Disabling requires supplying the entire blob for verification against the KZG commitment.", - EnvVars: prefixEnvVars("DISABLE_POINT_VERIFICATION_MODE"), - Value: false, - }, &cli.StringFlag{ Name: MaxBlobLengthFlagName, Usage: "Maximum blob length to be written or read from EigenDA. Determines the number of SRS points loaded into memory for KZG commitments. Example units: '30MiB', '4Kb', '30MB'. Maximum size slightly exceeds 1GB.", @@ -228,6 +167,7 @@ func init() { Flags = CLIFlags() Flags = append(Flags, oplog.CLIFlags(EnvVarPrefix)...) Flags = append(Flags, opmetrics.CLIFlags(EnvVarPrefix)...) + Flags = append(Flags, eigenda_flags.CLIFlags(EnvVarPrefix, EigenDAClientCategory)...) Flags = append(Flags, redis.CLIFlags(EnvVarPrefix, RedisCategory)...) Flags = append(Flags, s3.CLIFlags(EnvVarPrefix, S3Category)...) } diff --git a/server/config.go b/server/config.go index a37f68ca..308e5572 100644 --- a/server/config.go +++ b/server/config.go @@ -8,6 +8,7 @@ import ( "github.com/urfave/cli/v2" "github.com/Layr-Labs/eigenda-proxy/flags" + "github.com/Layr-Labs/eigenda-proxy/flags/eigenda_flags" "github.com/Layr-Labs/eigenda-proxy/store" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" @@ -32,7 +33,7 @@ var ( type Config struct { // eigenda - ClientConfig clients.EigenDAClientConfig + EdaClientConfig clients.EigenDAClientConfig // the blob encoding version to use when writing blobs from the high level interface. PutBlobEncodingVersion codecs.BlobEncodingVersion @@ -116,19 +117,9 @@ func (cfg *Config) VerificationCfg() *verify.Config { // ReadConfig ... parses the Config from the provided flags or environment variables. func ReadConfig(ctx *cli.Context) Config { cfg := Config{ - RedisConfig: redis.ReadConfig(ctx), - S3Config: s3.ReadConfig(ctx), - ClientConfig: clients.EigenDAClientConfig{ - RPC: ctx.String(flags.EigenDADisperserRPCFlagName), - StatusQueryRetryInterval: ctx.Duration(flags.StatusQueryRetryIntervalFlagName), - StatusQueryTimeout: ctx.Duration(flags.StatusQueryTimeoutFlagName), - DisableTLS: ctx.Bool(flags.DisableTLSFlagName), - ResponseTimeout: ctx.Duration(flags.ResponseTimeoutFlagName), - CustomQuorumIDs: ctx.UintSlice(flags.CustomQuorumIDsFlagName), - SignerPrivateKeyHex: ctx.String(flags.SignerPrivateKeyHexFlagName), - PutBlobEncodingVersion: codecs.BlobEncodingVersion(ctx.Uint(flags.PutBlobEncodingVersionFlagName)), - DisablePointVerificationMode: ctx.Bool(flags.DisablePointVerificationModeFlagName), - }, + RedisConfig: redis.ReadConfig(ctx), + S3Config: s3.ReadConfig(ctx), + EdaClientConfig: eigenda_flags.ReadConfig(ctx), G1Path: ctx.String(flags.G1PathFlagName), G2PowerOfTauPath: ctx.String(flags.G2TauFlagName), CacheDir: ctx.String(flags.CachePathFlagName), @@ -150,7 +141,7 @@ func ReadConfig(ctx *cli.Context) Config { // for the da-proxy to 0 (because negative confirmation depth doesn't mean anything and leads to errors) // TODO: should the eigenda-client implement this feature for us instead? if cfg.EthConfirmationDepth < 0 { - cfg.ClientConfig.WaitForFinalization = true + cfg.EdaClientConfig.WaitForFinalization = true cfg.EthConfirmationDepth = 0 } @@ -188,7 +179,7 @@ func (cfg *Config) Check() error { } if !cfg.MemstoreEnabled { - if cfg.ClientConfig.RPC == "" { + if cfg.EdaClientConfig.RPC == "" { return fmt.Errorf("using eigenda backend (memstore.enabled=false) but eigenda disperser rpc url is not set") } } diff --git a/server/config_test.go b/server/config_test.go index 2ee82b3f..bfe0586d 100644 --- a/server/config_test.go +++ b/server/config_test.go @@ -25,7 +25,7 @@ func validCfg() *Config { AccessKeyID: "access-key-id", AccessKeySecret: "access-key-secret", }, - ClientConfig: clients.EigenDAClientConfig{ + EdaClientConfig: clients.EigenDAClientConfig{ RPC: "http://localhost:8545", StatusQueryRetryInterval: 5 * time.Second, StatusQueryTimeout: 30 * time.Minute, @@ -130,7 +130,7 @@ func TestConfigVerification(t *testing.T) { t.Run("MissingEigenDADisperserRPC", func(t *testing.T) { cfg := validCfg() - cfg.ClientConfig.RPC = "" + cfg.EdaClientConfig.RPC = "" cfg.MemstoreEnabled = false err := cfg.Check() diff --git a/server/load_store.go b/server/load_store.go index 9e5796ce..a41ff621 100644 --- a/server/load_store.go +++ b/server/load_store.go @@ -101,7 +101,7 @@ func LoadStoreRouter(ctx context.Context, cfg CLIConfig, log log.Logger) (store. } else { var client *clients.EigenDAClient log.Info("Using EigenDA backend") - client, err = clients.NewEigenDAClient(log.With("subsystem", "eigenda-client"), daCfg.ClientConfig) + client, err = clients.NewEigenDAClient(log.With("subsystem", "eigenda-client"), daCfg.EdaClientConfig) if err != nil { return nil, err } @@ -113,7 +113,7 @@ func LoadStoreRouter(ctx context.Context, cfg CLIConfig, log log.Logger) (store. &eigenda.StoreConfig{ MaxBlobSizeBytes: maxBlobLength, EthConfirmationDepth: uint64(cfg.EigenDAConfig.EthConfirmationDepth), // #nosec G115 - StatusQueryTimeout: cfg.EigenDAConfig.ClientConfig.StatusQueryTimeout, + StatusQueryTimeout: cfg.EigenDAConfig.EdaClientConfig.StatusQueryTimeout, }, ) } From 34fd364b1645339cf0a0705151a64aa26c4da38d Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Sun, 22 Sep 2024 14:06:47 -0700 Subject: [PATCH 09/18] refactor: move verifier flags/config into its own package cli.go --- e2e/setup.go | 25 ++++--- flags/flags.go | 60 ----------------- server/config.go | 123 ++++++---------------------------- server/config_test.go | 57 ++++++++-------- server/load_store.go | 21 +++--- verify/cli.go | 151 ++++++++++++++++++++++++++++++++++++++++++ verify/verifier.go | 1 + 7 files changed, 223 insertions(+), 215 deletions(-) create mode 100644 verify/cli.go diff --git a/e2e/setup.go b/e2e/setup.go index d9a7b63c..b22ee4c2 100644 --- a/e2e/setup.go +++ b/e2e/setup.go @@ -11,7 +11,10 @@ import ( "github.com/Layr-Labs/eigenda-proxy/server" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" + "github.com/Layr-Labs/eigenda-proxy/utils" + "github.com/Layr-Labs/eigenda-proxy/verify" "github.com/Layr-Labs/eigenda/api/clients" + "github.com/Layr-Labs/eigenda/encoding/kzg" "github.com/ethereum/go-ethereum/log" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" @@ -106,6 +109,8 @@ func TestSuiteConfig(t *testing.T, testCfg *Cfg) server.CLIConfig { pollInterval = time.Minute * 1 } + maxBlobLengthBytes, err := utils.ParseBytesAmount("16mib") + require.NoError(t, err) eigendaCfg := server.Config{ EdaClientConfig: clients.EigenDAClientConfig{ RPC: holeskyDA, @@ -114,16 +119,20 @@ func TestSuiteConfig(t *testing.T, testCfg *Cfg) server.CLIConfig { DisableTLS: false, SignerPrivateKeyHex: pk, }, - EthRPC: ethRPC, - SvcManagerAddr: "0xD4A7E1Bd8015057293f0D0A557088c286942e84b", // incompatible with non holeskly networks - CacheDir: "../resources/SRSTables", - G1Path: "../resources/g1.point", - MaxBlobLength: "16mib", - G2PowerOfTauPath: "../resources/g2.point.powerOf2", - PutBlobEncodingVersion: 0x00, + VerifierConfig: verify.Config{ + VerifyCerts: true, + RPCURL: ethRPC, + SvcManagerAddr: "0xD4A7E1Bd8015057293f0D0A557088c286942e84b", // incompatible with non holeskly networks + EthConfirmationDepth: 0, + KzgConfig: &kzg.KzgConfig{ + G1Path: "../resources/g1.point", + G2PowerOf2Path: "../resources/g2.point.powerOf2", + CacheDir: "../resources/SRSTables", + SRSOrder: maxBlobLengthBytes / 32, + }, + }, MemstoreEnabled: testCfg.UseMemory, MemstoreBlobExpiration: testCfg.Expiration, - EthConfirmationDepth: 0, } if testCfg.UseMemory { diff --git a/flags/flags.go b/flags/flags.go index 96d57969..62c8a92c 100644 --- a/flags/flags.go +++ b/flags/flags.go @@ -24,19 +24,6 @@ const ( ListenAddrFlagName = "addr" PortFlagName = "port" - // cert verification flags - // TODO: should we remove the eigenda prefix since these are not eigenda-client flags? - CertVerificationEnabledFlagName = "eigenda-cert-verification-enabled" - EthRPCFlagName = "eigenda-eth-rpc" - SvcManagerAddrFlagName = "eigenda-svc-manager-addr" - EthConfirmationDepthFlagName = "eigenda-eth-confirmation-depth" - - // kzg flags - G1PathFlagName = "eigenda-g1-path" - G2TauFlagName = "eigenda-g2-tau-path" - CachePathFlagName = "eigenda-cache-path" - MaxBlobLengthFlagName = "eigenda-max-blob-length" - // memstore flags MemstoreFlagName = "memstore.enabled" MemstoreExpirationFlagName = "memstore.expiration" @@ -69,53 +56,6 @@ func CLIFlags() []cli.Flag { Value: 3100, EnvVars: prefixEnvVars("PORT"), }, - &cli.StringFlag{ - Name: MaxBlobLengthFlagName, - Usage: "Maximum blob length to be written or read from EigenDA. Determines the number of SRS points loaded into memory for KZG commitments. Example units: '30MiB', '4Kb', '30MB'. Maximum size slightly exceeds 1GB.", - EnvVars: prefixEnvVars("MAX_BLOB_LENGTH"), - Value: "16MiB", - }, - &cli.StringFlag{ - Name: G1PathFlagName, - Usage: "Directory path to g1.point file.", - EnvVars: prefixEnvVars("TARGET_KZG_G1_PATH"), - Value: "resources/g1.point", - }, - &cli.StringFlag{ - Name: G2TauFlagName, - Usage: "Directory path to g2.point.powerOf2 file.", - EnvVars: prefixEnvVars("TARGET_G2_TAU_PATH"), - Value: "resources/g2.point.powerOf2", - }, - &cli.StringFlag{ - Name: CachePathFlagName, - Usage: "Directory path to SRS tables for caching.", - EnvVars: prefixEnvVars("TARGET_CACHE_PATH"), - Value: "resources/SRSTables/", - }, - &cli.BoolFlag{ - Name: CertVerificationEnabledFlagName, - Usage: "Whether to verify certificates received from EigenDA disperser.", - EnvVars: prefixEnvVars("CERT_VERIFICATION_ENABLED"), - // TODO: ideally we'd want this to be turned on by default when eigenda backend is used (memstore.enabled=false) - Value: false, - }, - &cli.StringFlag{ - Name: EthRPCFlagName, - Usage: "JSON RPC node endpoint for the Ethereum network used for finalizing DA blobs. See available list here: https://docs.eigenlayer.xyz/eigenda/networks/", - EnvVars: prefixEnvVars("ETH_RPC"), - }, - &cli.StringFlag{ - Name: SvcManagerAddrFlagName, - Usage: "The deployed EigenDA service manager address. The list can be found here: https://github.com/Layr-Labs/eigenlayer-middleware/?tab=readme-ov-file#current-mainnet-deployment", - EnvVars: prefixEnvVars("SERVICE_MANAGER_ADDR"), - }, - &cli.Int64Flag{ - Name: EthConfirmationDepthFlagName, - Usage: "The number of Ethereum blocks to wait before considering a submitted blob's DA batch submission confirmed. `0` means wait for inclusion only. `-1` means wait for finality.", - EnvVars: prefixEnvVars("ETH_CONFIRMATION_DEPTH"), - Value: -1, - }, &cli.BoolFlag{ Name: MemstoreFlagName, Usage: "Whether to use mem-store for DA logic.", diff --git a/server/config.go b/server/config.go index 308e5572..1654c606 100644 --- a/server/config.go +++ b/server/config.go @@ -2,7 +2,6 @@ package server import ( "fmt" - "runtime" "time" "github.com/urfave/cli/v2" @@ -15,46 +14,18 @@ import ( "github.com/Layr-Labs/eigenda-proxy/utils" "github.com/Layr-Labs/eigenda-proxy/verify" "github.com/Layr-Labs/eigenda/api/clients" - "github.com/Layr-Labs/eigenda/api/clients/codecs" - "github.com/Layr-Labs/eigenda/encoding/kzg" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" ) -const ( - BytesPerSymbol = 31 - MaxCodingRatio = 8 -) - -var ( - MaxSRSPoints = 1 << 28 // 2^28 - MaxAllowedBlobSize = uint64(MaxSRSPoints * BytesPerSymbol / MaxCodingRatio) -) - type Config struct { // eigenda EdaClientConfig clients.EigenDAClientConfig - // the blob encoding version to use when writing blobs from the high level interface. - PutBlobEncodingVersion codecs.BlobEncodingVersion - + VerifierConfig verify.Config // eth verification vars // TODO: right now verification and confirmation depth are tightly coupled // we should decouple them - CertVerificationEnabled bool - EthRPC string - SvcManagerAddr string - EthConfirmationDepth int64 - - // kzg vars - CacheDir string - G1Path string - G2Path string - G2PowerOfTauPath string - - // size constraints - MaxBlobLength string - maxBlobLengthBytes uint64 // memstore MemstoreEnabled bool @@ -71,78 +42,28 @@ type Config struct { S3Config s3.Config } -// GetMaxBlobLength ... returns the maximum blob length in bytes -func (cfg *Config) GetMaxBlobLength() (uint64, error) { - if cfg.maxBlobLengthBytes == 0 { - numBytes, err := utils.ParseBytesAmount(cfg.MaxBlobLength) - if err != nil { - return 0, err - } - - if numBytes > MaxAllowedBlobSize { - return 0, fmt.Errorf("excluding disperser constraints on max blob size, SRS points constrain the maxBlobLength configuration parameter to be less than than %d bytes", MaxAllowedBlobSize) - } - - cfg.maxBlobLengthBytes = numBytes - } - - return cfg.maxBlobLengthBytes, nil -} - -// VerificationCfg ... returns certificate config used to verify blobs from eigenda -func (cfg *Config) VerificationCfg() *verify.Config { - numBytes, err := cfg.GetMaxBlobLength() - if err != nil { - panic(fmt.Errorf("failed to read max blob length: %w", err)) - } - - kzgCfg := &kzg.KzgConfig{ - G1Path: cfg.G1Path, - G2PowerOf2Path: cfg.G2PowerOfTauPath, - CacheDir: cfg.CacheDir, - SRSOrder: 268435456, // 2 ^ 32 - SRSNumberToLoad: numBytes / 32, // # of fr.Elements - NumWorker: uint64(runtime.GOMAXPROCS(0)), // #nosec G115 - } - - return &verify.Config{ - KzgConfig: kzgCfg, - VerifyCerts: cfg.CertVerificationEnabled, - RPCURL: cfg.EthRPC, - SvcManagerAddr: cfg.SvcManagerAddr, - EthConfirmationDepth: uint64(cfg.EthConfirmationDepth), // #nosec G115 - } -} - // ReadConfig ... parses the Config from the provided flags or environment variables. func ReadConfig(ctx *cli.Context) Config { cfg := Config{ - RedisConfig: redis.ReadConfig(ctx), - S3Config: s3.ReadConfig(ctx), - EdaClientConfig: eigenda_flags.ReadConfig(ctx), - G1Path: ctx.String(flags.G1PathFlagName), - G2PowerOfTauPath: ctx.String(flags.G2TauFlagName), - CacheDir: ctx.String(flags.CachePathFlagName), - MaxBlobLength: ctx.String(flags.MaxBlobLengthFlagName), - CertVerificationEnabled: ctx.Bool(flags.CertVerificationEnabledFlagName), - SvcManagerAddr: ctx.String(flags.SvcManagerAddrFlagName), - EthRPC: ctx.String(flags.EthRPCFlagName), - EthConfirmationDepth: ctx.Int64(flags.EthConfirmationDepthFlagName), - MemstoreEnabled: ctx.Bool(flags.MemstoreFlagName), - MemstoreBlobExpiration: ctx.Duration(flags.MemstoreExpirationFlagName), - MemstoreGetLatency: ctx.Duration(flags.MemstoreGetLatencyFlagName), - MemstorePutLatency: ctx.Duration(flags.MemstorePutLatencyFlagName), - FallbackTargets: ctx.StringSlice(flags.FallbackTargetsFlagName), - CacheTargets: ctx.StringSlice(flags.CacheTargetsFlagName), + RedisConfig: redis.ReadConfig(ctx), + S3Config: s3.ReadConfig(ctx), + EdaClientConfig: eigenda_flags.ReadConfig(ctx), + VerifierConfig: verify.ReadConfig(ctx), + MemstoreEnabled: ctx.Bool(flags.MemstoreFlagName), + MemstoreBlobExpiration: ctx.Duration(flags.MemstoreExpirationFlagName), + MemstoreGetLatency: ctx.Duration(flags.MemstoreGetLatencyFlagName), + MemstorePutLatency: ctx.Duration(flags.MemstorePutLatencyFlagName), + FallbackTargets: ctx.StringSlice(flags.FallbackTargetsFlagName), + CacheTargets: ctx.StringSlice(flags.CacheTargetsFlagName), } // the eigenda client can only wait for 0 confirmations or finality // the da-proxy has a more fine-grained notion of confirmation depth // we use -1 to let the da client wait for finality, and then need to set the confirmation depth // for the da-proxy to 0 (because negative confirmation depth doesn't mean anything and leads to errors) // TODO: should the eigenda-client implement this feature for us instead? - if cfg.EthConfirmationDepth < 0 { + if cfg.VerifierConfig.EthConfirmationDepth < 0 { cfg.EdaClientConfig.WaitForFinalization = true - cfg.EthConfirmationDepth = 0 + cfg.VerifierConfig.EthConfirmationDepth = 0 } return cfg @@ -169,14 +90,6 @@ func (cfg *Config) checkTargets(targets []string) error { // Check ... verifies that configuration values are adequately set func (cfg *Config) Check() error { - l, err := cfg.GetMaxBlobLength() - if err != nil { - return err - } - - if l == 0 { - return fmt.Errorf("max blob length is 0") - } if !cfg.MemstoreEnabled { if cfg.EdaClientConfig.RPC == "" { @@ -184,14 +97,16 @@ func (cfg *Config) Check() error { } } - if cfg.CertVerificationEnabled { + // cert verification is enabled + // TODO: move this verification logic to verify/cli.go + if cfg.VerifierConfig.VerifyCerts { if cfg.MemstoreEnabled { return fmt.Errorf("cannot enable cert verification when memstore is enabled") } - if cfg.EthRPC == "" { + if cfg.VerifierConfig.RPCURL == "" { return fmt.Errorf("cert verification enabled but eth rpc is not set") } - if cfg.SvcManagerAddr == "" { + if cfg.VerifierConfig.SvcManagerAddr == "" { return fmt.Errorf("cert verification enabled but svc manager address is not set") } } @@ -209,7 +124,7 @@ func (cfg *Config) Check() error { return fmt.Errorf("redis password is set, but endpoint is not") } - err = cfg.checkTargets(cfg.FallbackTargets) + err := cfg.checkTargets(cfg.FallbackTargets) if err != nil { return err } diff --git a/server/config_test.go b/server/config_test.go index bfe0586d..2f542893 100644 --- a/server/config_test.go +++ b/server/config_test.go @@ -6,11 +6,18 @@ import ( "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" + "github.com/Layr-Labs/eigenda-proxy/utils" + "github.com/Layr-Labs/eigenda-proxy/verify" "github.com/Layr-Labs/eigenda/api/clients" + "github.com/Layr-Labs/eigenda/encoding/kzg" "github.com/stretchr/testify/require" ) func validCfg() *Config { + maxBlobLengthBytes, err := utils.ParseBytesAmount("2MiB") + if err != nil { + panic(err) + } return &Config{ RedisConfig: redis.Config{ Endpoint: "localhost:6379", @@ -36,16 +43,20 @@ func validCfg() *Config { PutBlobEncodingVersion: 0, DisablePointVerificationMode: false, }, - G1Path: "path/to/g1", - G2PowerOfTauPath: "path/to/g2", - CacheDir: "path/to/cache", - MaxBlobLength: "2MiB", - CertVerificationEnabled: false, - SvcManagerAddr: "0x1234567890abcdef", - EthRPC: "http://localhost:8545", - EthConfirmationDepth: 12, - MemstoreEnabled: true, - MemstoreBlobExpiration: 25 * time.Minute, + VerifierConfig: verify.Config{ + KzgConfig: &kzg.KzgConfig{ + G1Path: "path/to/g1", + G2PowerOf2Path: "path/to/g2", + CacheDir: "path/to/cache", + SRSOrder: maxBlobLengthBytes / 32, + }, + VerifyCerts: false, + SvcManagerAddr: "0x1234567890abcdef", + RPCURL: "http://localhost:8545", + EthConfirmationDepth: 12, + }, + MemstoreEnabled: true, + MemstoreBlobExpiration: 25 * time.Minute, } } @@ -57,22 +68,6 @@ func TestConfigVerification(t *testing.T) { require.NoError(t, err) }) - t.Run("InvalidMaxBlobLength", func(t *testing.T) { - cfg := validCfg() - cfg.MaxBlobLength = "0kzg" - - err := cfg.Check() - require.Error(t, err) - }) - - t.Run("0MaxBlobLength", func(t *testing.T) { - cfg := validCfg() - cfg.MaxBlobLength = "0kib" - - err := cfg.Check() - require.Error(t, err) - }) - t.Run("CertVerificationEnabled", func(t *testing.T) { // when eigenDABackend is enabled (memstore.enabled = false), // some extra fields are required. @@ -80,8 +75,8 @@ func TestConfigVerification(t *testing.T) { cfg := validCfg() // cert verification only makes sense when memstore is disabled (we use eigenda as backend) cfg.MemstoreEnabled = false - cfg.CertVerificationEnabled = true - cfg.SvcManagerAddr = "" + cfg.VerifierConfig.VerifyCerts = true + cfg.VerifierConfig.SvcManagerAddr = "" err := cfg.Check() require.Error(t, err) @@ -91,8 +86,8 @@ func TestConfigVerification(t *testing.T) { cfg := validCfg() // cert verification only makes sense when memstore is disabled (we use eigenda as backend) cfg.MemstoreEnabled = false - cfg.CertVerificationEnabled = true - cfg.EthRPC = "" + cfg.VerifierConfig.VerifyCerts = true + cfg.VerifierConfig.RPCURL = "" err := cfg.Check() require.Error(t, err) @@ -101,7 +96,7 @@ func TestConfigVerification(t *testing.T) { t.Run("CantDoCertVerificationWhenMemstoreEnabled", func(t *testing.T) { cfg := validCfg() cfg.MemstoreEnabled = true - cfg.CertVerificationEnabled = true + cfg.VerifierConfig.VerifyCerts = true err := cfg.Check() require.Error(t, err) diff --git a/server/load_store.go b/server/load_store.go index a41ff621..e2490139 100644 --- a/server/load_store.go +++ b/server/load_store.go @@ -68,9 +68,9 @@ func LoadStoreRouter(ctx context.Context, cfg CLIConfig, log log.Logger) (store. // create cert/data verification type daCfg := cfg.EigenDAConfig - vCfg := daCfg.VerificationCfg() + vCfg := daCfg.VerifierConfig - verifier, err := verify.NewVerifier(vCfg, log) + verifier, err := verify.NewVerifier(&vCfg, log) if err != nil { return nil, fmt.Errorf("failed to create verifier: %w", err) } @@ -81,19 +81,16 @@ func LoadStoreRouter(ctx context.Context, cfg CLIConfig, log log.Logger) (store. log.Warn("Verification disabled") } - // TODO: change this logic... we shouldn't need to calculate this here. - // It should already be part of the config - maxBlobLength, err := daCfg.GetMaxBlobLength() - if err != nil { - return nil, err - } - // create EigenDA backend store var eigenDA store.KeyGeneratedStore if cfg.EigenDAConfig.MemstoreEnabled { log.Info("Using mem-store backend for EigenDA") eigenDA, err = memstore.New(ctx, verifier, log, memstore.Config{ - MaxBlobSizeBytes: maxBlobLength, + // TODO: there has to be a better way to get MaxBlobLengthBytes + // right now we get it from the verifier cli, but there's probably a way to share flags more nicely? + // maybe use a duplicate but hidden flag in memstore category, and set it using the action by reading + // from the other flag? + MaxBlobSizeBytes: verify.MaxBlobLengthBytes, BlobExpiration: cfg.EigenDAConfig.MemstoreBlobExpiration, PutLatency: cfg.EigenDAConfig.MemstorePutLatency, GetLatency: cfg.EigenDAConfig.MemstoreGetLatency, @@ -111,8 +108,8 @@ func LoadStoreRouter(ctx context.Context, cfg CLIConfig, log log.Logger) (store. verifier, log, &eigenda.StoreConfig{ - MaxBlobSizeBytes: maxBlobLength, - EthConfirmationDepth: uint64(cfg.EigenDAConfig.EthConfirmationDepth), // #nosec G115 + MaxBlobSizeBytes: verify.MaxBlobLengthBytes, + EthConfirmationDepth: uint64(cfg.EigenDAConfig.VerifierConfig.EthConfirmationDepth), // #nosec G115 StatusQueryTimeout: cfg.EigenDAConfig.EdaClientConfig.StatusQueryTimeout, }, ) diff --git a/verify/cli.go b/verify/cli.go new file mode 100644 index 00000000..b9aafe55 --- /dev/null +++ b/verify/cli.go @@ -0,0 +1,151 @@ +package verify + +import ( + "fmt" + "runtime" + + "github.com/Layr-Labs/eigenda-proxy/utils" + "github.com/Layr-Labs/eigenda/encoding/kzg" + "github.com/urfave/cli/v2" +) + +var ( + BytesPerSymbol = 31 + MaxCodingRatio = 8 + MaxSRSPoints = 1 << 28 // 2^28 + MaxAllowedBlobSize = uint64(MaxSRSPoints * BytesPerSymbol / MaxCodingRatio) +) + +// TODO: should this live in the resources pkg? +// So that if we ever change the SRS files there we can change this value +const srsOrder = 268435456 // 2 ^ 32 + +var ( + // cert verification flags + // TODO: we keep the eigenda prefix like eigenda client flags, because we + // plan to upstream this verification logic into the eigenda client + CertVerificationEnabledFlagName = withFlagPrefix("cert-verification-enabled") + EthRPCFlagName = withFlagPrefix("eth-rpc") + SvcManagerAddrFlagName = withFlagPrefix("svc-manager-addr") + EthConfirmationDepthFlagName = withFlagPrefix("eth-confirmation-depth") + + // kzg flags + G1PathFlagName = withFlagPrefix("g1-path") + G2TauFlagName = withFlagPrefix("g2-tau-path") + CachePathFlagName = withFlagPrefix("cache-path") + MaxBlobLengthFlagName = withFlagPrefix("max-blob-length") +) + +func withFlagPrefix(s string) string { + return "eigenda." + s +} + +func withEnvPrefix(envPrefix, s string) []string { + return []string{envPrefix + "_EIGENDA_" + s} +} + +// CLIFlags ... used for Verifier configuration +// category is used to group the flags in the help output (see https://cli.urfave.org/v2/examples/flags/#grouping) +func CLIFlags(envPrefix, category string) []cli.Flag { + return []cli.Flag{ + &cli.BoolFlag{ + Name: CertVerificationEnabledFlagName, + Usage: "Whether to verify certificates received from EigenDA disperser.", + EnvVars: withEnvPrefix(envPrefix, "CERT_VERIFICATION_ENABLED"), + // TODO: ideally we'd want this to be turned on by default when eigenda backend is used (memstore.enabled=false) + Value: false, + Category: category, + }, + &cli.StringFlag{ + Name: EthRPCFlagName, + Usage: "JSON RPC node endpoint for the Ethereum network used for finalizing DA blobs. See available list here: https://docs.eigenlayer.xyz/eigenda/networks/", + EnvVars: withEnvPrefix(envPrefix, "ETH_RPC"), + Category: category, + }, + &cli.StringFlag{ + Name: SvcManagerAddrFlagName, + Usage: "The deployed EigenDA service manager address. The list can be found here: https://github.com/Layr-Labs/eigenlayer-middleware/?tab=readme-ov-file#current-mainnet-deployment", + EnvVars: withEnvPrefix(envPrefix, "SERVICE_MANAGER_ADDR"), + Category: category, + }, + &cli.Int64Flag{ + Name: EthConfirmationDepthFlagName, + Usage: "The number of Ethereum blocks to wait before considering a submitted blob's DA batch submission confirmed. `0` means wait for inclusion only. `-1` means wait for finality.", + EnvVars: withEnvPrefix(envPrefix, "ETH_CONFIRMATION_DEPTH"), + Value: -1, + Category: category, + }, + // kzg flags + &cli.StringFlag{ + Name: G1PathFlagName, + Usage: "Directory path to g1.point file.", + EnvVars: withEnvPrefix(envPrefix, "TARGET_KZG_G1_PATH"), + // TODO: should use absolute path wrt root directory to prevent future errors + // in case we move this file around + Value: "../resources/g1.point", + Category: category, + }, + &cli.StringFlag{ + Name: G2TauFlagName, + Usage: "Directory path to g2.point.powerOf2 file.", + EnvVars: withEnvPrefix(envPrefix, "TARGET_G2_TAU_PATH"), + Value: "../resources/g2.point.powerOf2", + Category: category, + }, + &cli.StringFlag{ + Name: CachePathFlagName, + Usage: "Directory path to SRS tables for caching.", + EnvVars: withEnvPrefix(envPrefix, "TARGET_CACHE_PATH"), + Value: "../resources/SRSTables/", + Category: category, + }, + // TODO: can we use a genericFlag for this, and automatically parse the string into a uint64? + &cli.StringFlag{ + Name: MaxBlobLengthFlagName, + Usage: "Maximum blob length to be written or read from EigenDA. Determines the number of SRS points loaded into memory for KZG commitments. Example units: '30MiB', '4Kb', '30MB'. Maximum size slightly exceeds 1GB.", + EnvVars: withEnvPrefix(envPrefix, "MAX_BLOB_LENGTH"), + Value: "16MiB", + Action: func(c *cli.Context, maxBlobLengthStr string) error { + // parse the string to a uint64 and set the maxBlobLengthBytes var to be used by ReadConfig() + numBytes, err := utils.ParseBytesAmount(maxBlobLengthStr) + if err != nil { + return fmt.Errorf("failed to parse max blob length flag: %w", err) + } + if numBytes == 0 { + return fmt.Errorf("max blob length is 0") + } + if numBytes > MaxAllowedBlobSize { + return fmt.Errorf("excluding disperser constraints on max blob size, SRS points constrain the maxBlobLength configuration parameter to be less than than %d bytes", MaxAllowedBlobSize) + } + MaxBlobLengthBytes = numBytes + return nil + }, + // we also use this flag for memstore. + // should we duplicate the flag? Or is there a better way to handle this? + Category: category, + }, + } +} + +// this var is set by the action in the MaxBlobLengthFlagName flag +// TODO: there's def a better way to deal with this... perhaps a generic flag that can parse the string into a uint64? +var MaxBlobLengthBytes uint64 + +func ReadConfig(ctx *cli.Context) Config { + kzgCfg := &kzg.KzgConfig{ + G1Path: ctx.String(G1PathFlagName), + G2PowerOf2Path: ctx.String(G2TauFlagName), + CacheDir: ctx.String(CachePathFlagName), + SRSOrder: srsOrder, + SRSNumberToLoad: MaxBlobLengthBytes / 32, // # of fr.Elements + NumWorker: uint64(runtime.GOMAXPROCS(0)), // #nosec G115 + } + + return Config{ + KzgConfig: kzgCfg, + VerifyCerts: ctx.Bool(CertVerificationEnabledFlagName), + RPCURL: ctx.String(EthRPCFlagName), + SvcManagerAddr: ctx.String(SvcManagerAddrFlagName), + EthConfirmationDepth: uint64(ctx.Int64(EthConfirmationDepthFlagName)), // #nosec G115 + } +} diff --git a/verify/verifier.go b/verify/verifier.go index 77195a2f..5e374f0f 100644 --- a/verify/verifier.go +++ b/verify/verifier.go @@ -25,6 +25,7 @@ type Config struct { EthConfirmationDepth uint64 } +// TODO: right now verification and confirmation depth are tightly coupled. we should decouple them type Verifier struct { // kzgVerifier is needed to commit blobs to the memstore kzgVerifier *kzgverifier.Verifier From ce20b0f32fc254fba933d89a21c943e6f7a30c7a Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Sun, 22 Sep 2024 19:30:15 -0700 Subject: [PATCH 10/18] fix: lint Also added WaitForFinalization eigenda flag --- flags/{eigenda_flags => eigendaflags}/cli.go | 11 ++++++++- flags/flags.go | 4 ++-- server/config.go | 25 ++++---------------- server/load_store.go | 2 +- verify/cli.go | 8 +++---- 5 files changed, 21 insertions(+), 29 deletions(-) rename flags/{eigenda_flags => eigendaflags}/cli.go (91%) diff --git a/flags/eigenda_flags/cli.go b/flags/eigendaflags/cli.go similarity index 91% rename from flags/eigenda_flags/cli.go rename to flags/eigendaflags/cli.go index d350961e..7106afcd 100644 --- a/flags/eigenda_flags/cli.go +++ b/flags/eigendaflags/cli.go @@ -1,4 +1,4 @@ -package eigenda_flags +package eigendaflags import ( "time" @@ -20,6 +20,7 @@ var ( SignerPrivateKeyHexFlagName = withFlagPrefix("signer-private-key-hex") PutBlobEncodingVersionFlagName = withFlagPrefix("put-blob-encoding-version") DisablePointVerificationModeFlagName = withFlagPrefix("disable-point-verification-mode") + WaitForFinalizationFlagName = withFlagPrefix("wait-for-finalization") ) func withFlagPrefix(s string) string { @@ -94,6 +95,13 @@ func CLIFlags(envPrefix, category string) []cli.Flag { Value: false, Category: category, }, + &cli.BoolFlag{ + Name: WaitForFinalizationFlagName, + Usage: "Wait for blob finalization before returning from PutBlob.", + EnvVars: withEnvPrefix(envPrefix, "WAIT_FOR_FINALIZATION"), + Value: false, + Category: category, + }, } } @@ -108,5 +116,6 @@ func ReadConfig(ctx *cli.Context) clients.EigenDAClientConfig { SignerPrivateKeyHex: ctx.String(SignerPrivateKeyHexFlagName), PutBlobEncodingVersion: codecs.BlobEncodingVersion(ctx.Uint(PutBlobEncodingVersionFlagName)), DisablePointVerificationMode: ctx.Bool(DisablePointVerificationModeFlagName), + WaitForFinalization: ctx.Bool(WaitForFinalizationFlagName), } } diff --git a/flags/flags.go b/flags/flags.go index 62c8a92c..9376daf7 100644 --- a/flags/flags.go +++ b/flags/flags.go @@ -3,7 +3,7 @@ package flags import ( "time" - "github.com/Layr-Labs/eigenda-proxy/flags/eigenda_flags" + "github.com/Layr-Labs/eigenda-proxy/flags/eigendaflags" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" "github.com/urfave/cli/v2" @@ -107,7 +107,7 @@ func init() { Flags = CLIFlags() Flags = append(Flags, oplog.CLIFlags(EnvVarPrefix)...) Flags = append(Flags, opmetrics.CLIFlags(EnvVarPrefix)...) - Flags = append(Flags, eigenda_flags.CLIFlags(EnvVarPrefix, EigenDAClientCategory)...) + Flags = append(Flags, eigendaflags.CLIFlags(EnvVarPrefix, EigenDAClientCategory)...) Flags = append(Flags, redis.CLIFlags(EnvVarPrefix, RedisCategory)...) Flags = append(Flags, s3.CLIFlags(EnvVarPrefix, S3Category)...) } diff --git a/server/config.go b/server/config.go index 1654c606..c09ed6e2 100644 --- a/server/config.go +++ b/server/config.go @@ -7,7 +7,7 @@ import ( "github.com/urfave/cli/v2" "github.com/Layr-Labs/eigenda-proxy/flags" - "github.com/Layr-Labs/eigenda-proxy/flags/eigenda_flags" + "github.com/Layr-Labs/eigenda-proxy/flags/eigendaflags" "github.com/Layr-Labs/eigenda-proxy/store" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" @@ -19,13 +19,8 @@ import ( ) type Config struct { - // eigenda EdaClientConfig clients.EigenDAClientConfig - - VerifierConfig verify.Config - // eth verification vars - // TODO: right now verification and confirmation depth are tightly coupled - // we should decouple them + VerifierConfig verify.Config // memstore MemstoreEnabled bool @@ -44,10 +39,10 @@ type Config struct { // ReadConfig ... parses the Config from the provided flags or environment variables. func ReadConfig(ctx *cli.Context) Config { - cfg := Config{ + return Config{ RedisConfig: redis.ReadConfig(ctx), S3Config: s3.ReadConfig(ctx), - EdaClientConfig: eigenda_flags.ReadConfig(ctx), + EdaClientConfig: eigendaflags.ReadConfig(ctx), VerifierConfig: verify.ReadConfig(ctx), MemstoreEnabled: ctx.Bool(flags.MemstoreFlagName), MemstoreBlobExpiration: ctx.Duration(flags.MemstoreExpirationFlagName), @@ -56,17 +51,6 @@ func ReadConfig(ctx *cli.Context) Config { FallbackTargets: ctx.StringSlice(flags.FallbackTargetsFlagName), CacheTargets: ctx.StringSlice(flags.CacheTargetsFlagName), } - // the eigenda client can only wait for 0 confirmations or finality - // the da-proxy has a more fine-grained notion of confirmation depth - // we use -1 to let the da client wait for finality, and then need to set the confirmation depth - // for the da-proxy to 0 (because negative confirmation depth doesn't mean anything and leads to errors) - // TODO: should the eigenda-client implement this feature for us instead? - if cfg.VerifierConfig.EthConfirmationDepth < 0 { - cfg.EdaClientConfig.WaitForFinalization = true - cfg.VerifierConfig.EthConfirmationDepth = 0 - } - - return cfg } // checkTargets ... verifies that a backend target slice is constructed correctly @@ -90,7 +74,6 @@ func (cfg *Config) checkTargets(targets []string) error { // Check ... verifies that configuration values are adequately set func (cfg *Config) Check() error { - if !cfg.MemstoreEnabled { if cfg.EdaClientConfig.RPC == "" { return fmt.Errorf("using eigenda backend (memstore.enabled=false) but eigenda disperser rpc url is not set") diff --git a/server/load_store.go b/server/load_store.go index e2490139..dd7c2fd1 100644 --- a/server/load_store.go +++ b/server/load_store.go @@ -109,7 +109,7 @@ func LoadStoreRouter(ctx context.Context, cfg CLIConfig, log log.Logger) (store. log, &eigenda.StoreConfig{ MaxBlobSizeBytes: verify.MaxBlobLengthBytes, - EthConfirmationDepth: uint64(cfg.EigenDAConfig.VerifierConfig.EthConfirmationDepth), // #nosec G115 + EthConfirmationDepth: cfg.EigenDAConfig.VerifierConfig.EthConfirmationDepth, StatusQueryTimeout: cfg.EigenDAConfig.EdaClientConfig.StatusQueryTimeout, }, ) diff --git a/verify/cli.go b/verify/cli.go index b9aafe55..3c97c694 100644 --- a/verify/cli.go +++ b/verify/cli.go @@ -68,11 +68,11 @@ func CLIFlags(envPrefix, category string) []cli.Flag { EnvVars: withEnvPrefix(envPrefix, "SERVICE_MANAGER_ADDR"), Category: category, }, - &cli.Int64Flag{ + &cli.Uint64Flag{ Name: EthConfirmationDepthFlagName, - Usage: "The number of Ethereum blocks to wait before considering a submitted blob's DA batch submission confirmed. `0` means wait for inclusion only. `-1` means wait for finality.", + Usage: "The number of Ethereum blocks to wait before considering a submitted blob's DA batch submission confirmed. `0` means wait for inclusion only.", EnvVars: withEnvPrefix(envPrefix, "ETH_CONFIRMATION_DEPTH"), - Value: -1, + Value: 0, Category: category, }, // kzg flags @@ -105,7 +105,7 @@ func CLIFlags(envPrefix, category string) []cli.Flag { Usage: "Maximum blob length to be written or read from EigenDA. Determines the number of SRS points loaded into memory for KZG commitments. Example units: '30MiB', '4Kb', '30MB'. Maximum size slightly exceeds 1GB.", EnvVars: withEnvPrefix(envPrefix, "MAX_BLOB_LENGTH"), Value: "16MiB", - Action: func(c *cli.Context, maxBlobLengthStr string) error { + Action: func(_ *cli.Context, maxBlobLengthStr string) error { // parse the string to a uint64 and set the maxBlobLengthBytes var to be used by ReadConfig() numBytes, err := utils.ParseBytesAmount(maxBlobLengthStr) if err != nil { From 01b429293418d0e2775fb1219525e849ed8b316e Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Sun, 22 Sep 2024 20:20:16 -0700 Subject: [PATCH 11/18] refactor: move memstore flags to their own package cli.go --- e2e/setup.go | 7 ++- flags/flags.go | 37 +-------------- server/config.go | 27 +++++------ server/config_test.go | 7 ++- server/load_store.go | 11 +---- store/generated_key/memstore/cli.go | 70 +++++++++++++++++++++++++++++ 6 files changed, 94 insertions(+), 65 deletions(-) create mode 100644 store/generated_key/memstore/cli.go diff --git a/e2e/setup.go b/e2e/setup.go index b22ee4c2..a16cb8d3 100644 --- a/e2e/setup.go +++ b/e2e/setup.go @@ -9,6 +9,7 @@ import ( "github.com/Layr-Labs/eigenda-proxy/metrics" "github.com/Layr-Labs/eigenda-proxy/server" + "github.com/Layr-Labs/eigenda-proxy/store/generated_key/memstore" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" "github.com/Layr-Labs/eigenda-proxy/utils" @@ -131,8 +132,10 @@ func TestSuiteConfig(t *testing.T, testCfg *Cfg) server.CLIConfig { SRSOrder: maxBlobLengthBytes / 32, }, }, - MemstoreEnabled: testCfg.UseMemory, - MemstoreBlobExpiration: testCfg.Expiration, + MemstoreEnabled: testCfg.UseMemory, + MemstoreConfig: memstore.Config{ + BlobExpiration: testCfg.Expiration, + }, } if testCfg.UseMemory { diff --git a/flags/flags.go b/flags/flags.go index 9376daf7..445dbfd3 100644 --- a/flags/flags.go +++ b/flags/flags.go @@ -1,9 +1,8 @@ package flags import ( - "time" - "github.com/Layr-Labs/eigenda-proxy/flags/eigendaflags" + "github.com/Layr-Labs/eigenda-proxy/store/generated_key/memstore" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" "github.com/urfave/cli/v2" @@ -24,12 +23,6 @@ const ( ListenAddrFlagName = "addr" PortFlagName = "port" - // memstore flags - MemstoreFlagName = "memstore.enabled" - MemstoreExpirationFlagName = "memstore.expiration" - MemstorePutLatencyFlagName = "memstore.put-latency" - MemstoreGetLatencyFlagName = "memstore.get-latency" - // routing flags FallbackTargetsFlagName = "routing.fallback-targets" CacheTargetsFlagName = "routing.cache-targets" @@ -56,33 +49,6 @@ func CLIFlags() []cli.Flag { Value: 3100, EnvVars: prefixEnvVars("PORT"), }, - &cli.BoolFlag{ - Name: MemstoreFlagName, - Usage: "Whether to use mem-store for DA logic.", - EnvVars: prefixEnvVars("MEMSTORE_ENABLED"), - Category: MemstoreFlagsCategory, - }, - &cli.DurationFlag{ - Name: MemstoreExpirationFlagName, - Usage: "Duration that a mem-store blob/commitment pair are allowed to live.", - Value: 25 * time.Minute, - EnvVars: prefixEnvVars("MEMSTORE_EXPIRATION"), - Category: MemstoreFlagsCategory, - }, - &cli.DurationFlag{ - Name: MemstorePutLatencyFlagName, - Usage: "Artificial latency added for memstore backend to mimic EigenDA's dispersal latency.", - Value: 0, - EnvVars: prefixEnvVars("MEMSTORE_PUT_LATENCY"), - Category: MemstoreFlagsCategory, - }, - &cli.DurationFlag{ - Name: MemstoreGetLatencyFlagName, - Usage: "Artificial latency added for memstore backend to mimic EigenDA's retrieval latency.", - Value: 0, - EnvVars: prefixEnvVars("MEMSTORE_GET_LATENCY"), - Category: MemstoreFlagsCategory, - }, &cli.StringSliceFlag{ Name: FallbackTargetsFlagName, Usage: "List of read fallback targets to rollover to if cert can't be read from EigenDA.", @@ -110,4 +76,5 @@ func init() { Flags = append(Flags, eigendaflags.CLIFlags(EnvVarPrefix, EigenDAClientCategory)...) Flags = append(Flags, redis.CLIFlags(EnvVarPrefix, RedisCategory)...) Flags = append(Flags, s3.CLIFlags(EnvVarPrefix, S3Category)...) + Flags = append(Flags, memstore.CLIFlags(EnvVarPrefix, MemstoreFlagsCategory)...) } diff --git a/server/config.go b/server/config.go index c09ed6e2..4cb0c8bf 100644 --- a/server/config.go +++ b/server/config.go @@ -2,13 +2,13 @@ package server import ( "fmt" - "time" "github.com/urfave/cli/v2" "github.com/Layr-Labs/eigenda-proxy/flags" "github.com/Layr-Labs/eigenda-proxy/flags/eigendaflags" "github.com/Layr-Labs/eigenda-proxy/store" + "github.com/Layr-Labs/eigenda-proxy/store/generated_key/memstore" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" "github.com/Layr-Labs/eigenda-proxy/utils" @@ -22,11 +22,8 @@ type Config struct { EdaClientConfig clients.EigenDAClientConfig VerifierConfig verify.Config - // memstore - MemstoreEnabled bool - MemstoreBlobExpiration time.Duration - MemstoreGetLatency time.Duration - MemstorePutLatency time.Duration + MemstoreEnabled bool + MemstoreConfig memstore.Config // routing FallbackTargets []string @@ -40,16 +37,14 @@ type Config struct { // ReadConfig ... parses the Config from the provided flags or environment variables. func ReadConfig(ctx *cli.Context) Config { return Config{ - RedisConfig: redis.ReadConfig(ctx), - S3Config: s3.ReadConfig(ctx), - EdaClientConfig: eigendaflags.ReadConfig(ctx), - VerifierConfig: verify.ReadConfig(ctx), - MemstoreEnabled: ctx.Bool(flags.MemstoreFlagName), - MemstoreBlobExpiration: ctx.Duration(flags.MemstoreExpirationFlagName), - MemstoreGetLatency: ctx.Duration(flags.MemstoreGetLatencyFlagName), - MemstorePutLatency: ctx.Duration(flags.MemstorePutLatencyFlagName), - FallbackTargets: ctx.StringSlice(flags.FallbackTargetsFlagName), - CacheTargets: ctx.StringSlice(flags.CacheTargetsFlagName), + RedisConfig: redis.ReadConfig(ctx), + S3Config: s3.ReadConfig(ctx), + EdaClientConfig: eigendaflags.ReadConfig(ctx), + VerifierConfig: verify.ReadConfig(ctx), + MemstoreEnabled: ctx.Bool(memstore.EnabledFlagName), + MemstoreConfig: memstore.ReadConfig(ctx), + FallbackTargets: ctx.StringSlice(flags.FallbackTargetsFlagName), + CacheTargets: ctx.StringSlice(flags.CacheTargetsFlagName), } } diff --git a/server/config_test.go b/server/config_test.go index 2f542893..4d747dd0 100644 --- a/server/config_test.go +++ b/server/config_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/Layr-Labs/eigenda-proxy/store/generated_key/memstore" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/redis" "github.com/Layr-Labs/eigenda-proxy/store/precomputed_key/s3" "github.com/Layr-Labs/eigenda-proxy/utils" @@ -55,8 +56,10 @@ func validCfg() *Config { RPCURL: "http://localhost:8545", EthConfirmationDepth: 12, }, - MemstoreEnabled: true, - MemstoreBlobExpiration: 25 * time.Minute, + MemstoreEnabled: true, + MemstoreConfig: memstore.Config{ + BlobExpiration: 25 * time.Minute, + }, } } diff --git a/server/load_store.go b/server/load_store.go index dd7c2fd1..98ae27de 100644 --- a/server/load_store.go +++ b/server/load_store.go @@ -85,16 +85,7 @@ func LoadStoreRouter(ctx context.Context, cfg CLIConfig, log log.Logger) (store. var eigenDA store.KeyGeneratedStore if cfg.EigenDAConfig.MemstoreEnabled { log.Info("Using mem-store backend for EigenDA") - eigenDA, err = memstore.New(ctx, verifier, log, memstore.Config{ - // TODO: there has to be a better way to get MaxBlobLengthBytes - // right now we get it from the verifier cli, but there's probably a way to share flags more nicely? - // maybe use a duplicate but hidden flag in memstore category, and set it using the action by reading - // from the other flag? - MaxBlobSizeBytes: verify.MaxBlobLengthBytes, - BlobExpiration: cfg.EigenDAConfig.MemstoreBlobExpiration, - PutLatency: cfg.EigenDAConfig.MemstorePutLatency, - GetLatency: cfg.EigenDAConfig.MemstoreGetLatency, - }) + eigenDA, err = memstore.New(ctx, verifier, log, cfg.EigenDAConfig.MemstoreConfig) } else { var client *clients.EigenDAClient log.Info("Using EigenDA backend") diff --git a/store/generated_key/memstore/cli.go b/store/generated_key/memstore/cli.go new file mode 100644 index 00000000..250482e4 --- /dev/null +++ b/store/generated_key/memstore/cli.go @@ -0,0 +1,70 @@ +package memstore + +import ( + "time" + + "github.com/Layr-Labs/eigenda-proxy/verify" + "github.com/urfave/cli/v2" +) + +var ( + EnabledFlagName = withFlagPrefix("enabled") + ExpirationFlagName = withFlagPrefix("expiration") + PutLatencyFlagName = withFlagPrefix("put-latency") + GetLatencyFlagName = withFlagPrefix("get-latency") +) + +func withFlagPrefix(s string) string { + return "memstore." + s +} + +func withEnvPrefix(envPrefix, s string) []string { + return []string{envPrefix + "_MEMSTORE_" + s} +} + +// CLIFlags ... used for Redis backend configuration +// category is used to group the flags in the help output (see https://cli.urfave.org/v2/examples/flags/#grouping) +func CLIFlags(envPrefix, category string) []cli.Flag { + return []cli.Flag{ + &cli.BoolFlag{ + Name: EnabledFlagName, + Usage: "Whether to use mem-store for DA logic.", + EnvVars: withEnvPrefix(envPrefix, "ENABLED"), + Category: category, + }, + &cli.DurationFlag{ + Name: ExpirationFlagName, + Usage: "Duration that a memstore blob/commitment pair is allowed to live.", + Value: 25 * time.Minute, + EnvVars: withEnvPrefix(envPrefix, "EXPIRATION"), + Category: category, + }, + &cli.DurationFlag{ + Name: PutLatencyFlagName, + Usage: "Artificial latency added for memstore backend to mimic EigenDA's dispersal latency.", + Value: 0, + EnvVars: withEnvPrefix(envPrefix, "PUT_LATENCY"), + Category: category, + }, + &cli.DurationFlag{ + Name: GetLatencyFlagName, + Usage: "Artificial latency added for memstore backend to mimic EigenDA's retrieval latency.", + Value: 0, + EnvVars: withEnvPrefix(envPrefix, "GET_LATENCY"), + Category: category, + }, + } +} + +func ReadConfig(ctx *cli.Context) Config { + return Config{ + // TODO: there has to be a better way to get MaxBlobLengthBytes + // right now we get it from the verifier cli, but there's probably a way to share flags more nicely? + // maybe use a duplicate but hidden flag in memstore category, and set it using the action by reading + // from the other flag? + MaxBlobSizeBytes: verify.MaxBlobLengthBytes, + BlobExpiration: ctx.Duration(ExpirationFlagName), + PutLatency: ctx.Duration(PutLatencyFlagName), + GetLatency: ctx.Duration(GetLatencyFlagName), + } +} From 86371f76f98428457a72f36c454cb2fb95c20093 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Sun, 22 Sep 2024 20:30:44 -0700 Subject: [PATCH 12/18] fix: e2e holesky-test --- e2e/setup.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/e2e/setup.go b/e2e/setup.go index a16cb8d3..55a34f25 100644 --- a/e2e/setup.go +++ b/e2e/setup.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "os" + "runtime" "testing" "time" @@ -126,10 +127,12 @@ func TestSuiteConfig(t *testing.T, testCfg *Cfg) server.CLIConfig { SvcManagerAddr: "0xD4A7E1Bd8015057293f0D0A557088c286942e84b", // incompatible with non holeskly networks EthConfirmationDepth: 0, KzgConfig: &kzg.KzgConfig{ - G1Path: "../resources/g1.point", - G2PowerOf2Path: "../resources/g2.point.powerOf2", - CacheDir: "../resources/SRSTables", - SRSOrder: maxBlobLengthBytes / 32, + G1Path: "../resources/g1.point", + G2PowerOf2Path: "../resources/g2.point.powerOf2", + CacheDir: "../resources/SRSTables", + SRSOrder: 268435456, + SRSNumberToLoad: maxBlobLengthBytes / 32, + NumWorker: uint64(runtime.GOMAXPROCS(0)), }, }, MemstoreEnabled: testCfg.UseMemory, From 8454231e0ab27e86ed69ec65d00121198fca4671 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Sun, 22 Sep 2024 20:50:15 -0700 Subject: [PATCH 13/18] fix: e2e tests --- Makefile | 4 ++-- e2e/setup.go | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 29fdac1b..ef00d5c2 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,8 @@ LDFLAGSSTRING +=-X main.Date=$(BUILD_TIME) LDFLAGSSTRING +=-X main.Version=$(GIT_TAG) LDFLAGS := -ldflags "$(LDFLAGSSTRING)" -E2ETEST = INTEGRATION=true go test -timeout 1m -v ./e2e -parallel 4 -deploy-config ../.devnet/devnetL1.json -HOLESKYTEST = TESTNET=true go test -timeout 50m -v ./e2e -parallel 4 -deploy-config ../.devnet/devnetL1.json +E2ETEST = INTEGRATION=true go test -timeout 1m ./e2e -parallel 4 -deploy-config ../.devnet/devnetL1.json +HOLESKYTEST = TESTNET=true go test -timeout 50m ./e2e -parallel 4 -deploy-config ../.devnet/devnetL1.json .PHONY: eigenda-proxy eigenda-proxy: diff --git a/e2e/setup.go b/e2e/setup.go index 55a34f25..02071569 100644 --- a/e2e/setup.go +++ b/e2e/setup.go @@ -122,7 +122,7 @@ func TestSuiteConfig(t *testing.T, testCfg *Cfg) server.CLIConfig { SignerPrivateKeyHex: pk, }, VerifierConfig: verify.Config{ - VerifyCerts: true, + VerifyCerts: false, RPCURL: ethRPC, SvcManagerAddr: "0xD4A7E1Bd8015057293f0D0A557088c286942e84b", // incompatible with non holeskly networks EthConfirmationDepth: 0, @@ -137,7 +137,8 @@ func TestSuiteConfig(t *testing.T, testCfg *Cfg) server.CLIConfig { }, MemstoreEnabled: testCfg.UseMemory, MemstoreConfig: memstore.Config{ - BlobExpiration: testCfg.Expiration, + BlobExpiration: testCfg.Expiration, + MaxBlobSizeBytes: maxBlobLengthBytes, }, } From db48e6f179723b5d94ebaee3cc615e9f0c22787c Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Sun, 22 Sep 2024 20:59:37 -0700 Subject: [PATCH 14/18] fix: e2e tests (attempt 2) --- server/load_store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/load_store.go b/server/load_store.go index 98ae27de..f8de7329 100644 --- a/server/load_store.go +++ b/server/load_store.go @@ -99,7 +99,7 @@ func LoadStoreRouter(ctx context.Context, cfg CLIConfig, log log.Logger) (store. verifier, log, &eigenda.StoreConfig{ - MaxBlobSizeBytes: verify.MaxBlobLengthBytes, + MaxBlobSizeBytes: cfg.EigenDAConfig.MemstoreConfig.MaxBlobSizeBytes, EthConfirmationDepth: cfg.EigenDAConfig.VerifierConfig.EthConfirmationDepth, StatusQueryTimeout: cfg.EigenDAConfig.EdaClientConfig.StatusQueryTimeout, }, From a16d5ddffa0fd22ccb1ae54dda6313746daeeff1 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Mon, 23 Sep 2024 17:20:54 -0700 Subject: [PATCH 15/18] refactor: rename KeyGeneratedStore -> GeneratedKeyStore --- mocks/router.go | 4 ++-- server/load_store.go | 2 +- store/generated_key/eigenda/eigenda.go | 2 +- store/generated_key/memstore/memstore.go | 2 +- store/router.go | 8 ++++---- store/store.go | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mocks/router.go b/mocks/router.go index 97c171fc..f1ca67c5 100644 --- a/mocks/router.go +++ b/mocks/router.go @@ -80,10 +80,10 @@ func (mr *MockIRouterMockRecorder) Get(arg0, arg1, arg2 interface{}) *gomock.Cal } // GetEigenDAStore mocks base method. -func (m *MockIRouter) GetEigenDAStore() store.KeyGeneratedStore { +func (m *MockIRouter) GetEigenDAStore() store.GeneratedKeyStore { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetEigenDAStore") - ret0, _ := ret[0].(store.KeyGeneratedStore) + ret0, _ := ret[0].(store.GeneratedKeyStore) return ret0 } diff --git a/server/load_store.go b/server/load_store.go index f8de7329..0c042b1b 100644 --- a/server/load_store.go +++ b/server/load_store.go @@ -82,7 +82,7 @@ func LoadStoreRouter(ctx context.Context, cfg CLIConfig, log log.Logger) (store. } // create EigenDA backend store - var eigenDA store.KeyGeneratedStore + var eigenDA store.GeneratedKeyStore if cfg.EigenDAConfig.MemstoreEnabled { log.Info("Using mem-store backend for EigenDA") eigenDA, err = memstore.New(ctx, verifier, log, cfg.EigenDAConfig.MemstoreConfig) diff --git a/store/generated_key/eigenda/eigenda.go b/store/generated_key/eigenda/eigenda.go index 177fce5a..05e8a4f8 100644 --- a/store/generated_key/eigenda/eigenda.go +++ b/store/generated_key/eigenda/eigenda.go @@ -31,7 +31,7 @@ type Store struct { log log.Logger } -var _ store.KeyGeneratedStore = (*Store)(nil) +var _ store.GeneratedKeyStore = (*Store)(nil) func NewStore(client *clients.EigenDAClient, v *verify.Verifier, log log.Logger, cfg *StoreConfig) (*Store, error) { diff --git a/store/generated_key/memstore/memstore.go b/store/generated_key/memstore/memstore.go index aeb1e78c..a25eac6f 100644 --- a/store/generated_key/memstore/memstore.go +++ b/store/generated_key/memstore/memstore.go @@ -49,7 +49,7 @@ type MemStore struct { reads int } -var _ store.KeyGeneratedStore = (*MemStore)(nil) +var _ store.GeneratedKeyStore = (*MemStore)(nil) // New ... constructor func New( diff --git a/store/router.go b/store/router.go index ad2805cc..6ee35aa2 100644 --- a/store/router.go +++ b/store/router.go @@ -17,7 +17,7 @@ type IRouter interface { Get(ctx context.Context, key []byte, cm commitments.CommitmentMode) ([]byte, error) Put(ctx context.Context, cm commitments.CommitmentMode, key, value []byte) ([]byte, error) - GetEigenDAStore() KeyGeneratedStore + GetEigenDAStore() GeneratedKeyStore GetS3Store() PrecomputedKeyStore Caches() []PrecomputedKeyStore Fallbacks() []PrecomputedKeyStore @@ -26,7 +26,7 @@ type IRouter interface { // Router ... storage backend routing layer type Router struct { log log.Logger - eigenda KeyGeneratedStore + eigenda GeneratedKeyStore s3 PrecomputedKeyStore caches []PrecomputedKeyStore @@ -36,7 +36,7 @@ type Router struct { fallbackLock sync.RWMutex } -func NewRouter(eigenda KeyGeneratedStore, s3 PrecomputedKeyStore, l log.Logger, +func NewRouter(eigenda GeneratedKeyStore, s3 PrecomputedKeyStore, l log.Logger, caches []PrecomputedKeyStore, fallbacks []PrecomputedKeyStore) (IRouter, error) { return &Router{ log: l, @@ -252,7 +252,7 @@ func (r *Router) cacheEnabled() bool { } // GetEigenDAStore ... -func (r *Router) GetEigenDAStore() KeyGeneratedStore { +func (r *Router) GetEigenDAStore() GeneratedKeyStore { return r.eigenda } diff --git a/store/store.go b/store/store.go index 050fbd2a..0b757896 100644 --- a/store/store.go +++ b/store/store.go @@ -73,7 +73,7 @@ type Store interface { Verify(key []byte, value []byte) error } -type KeyGeneratedStore interface { +type GeneratedKeyStore interface { Store // Get retrieves the given key if it's present in the key-value data store. Get(ctx context.Context, key []byte) ([]byte, error) From f80fb01d04f424265e8f04a099a7b2dd52e447b6 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Mon, 23 Sep 2024 21:29:20 -0700 Subject: [PATCH 16/18] style(flags): remove unneeded explicit "" values --- store/precomputed_key/s3/cli.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/store/precomputed_key/s3/cli.go b/store/precomputed_key/s3/cli.go index 7826ba4a..fd550d58 100644 --- a/store/precomputed_key/s3/cli.go +++ b/store/precomputed_key/s3/cli.go @@ -32,7 +32,6 @@ func CLIFlags(envPrefix, category string) []cli.Flag { &cli.StringFlag{ Name: EndpointFlagName, Usage: "endpoint for S3 storage", - Value: "", EnvVars: withEnvPrefix(envPrefix, "S3_ENDPOINT"), }, &cli.StringFlag{ @@ -44,13 +43,11 @@ func CLIFlags(envPrefix, category string) []cli.Flag { &cli.StringFlag{ Name: AccessKeyIDFlagName, Usage: "access key id for S3 storage", - Value: "", EnvVars: withEnvPrefix(envPrefix, "ACCESS_KEY_ID"), }, &cli.StringFlag{ Name: AccessKeySecretFlagName, Usage: "access key secret for S3 storage", - Value: "", EnvVars: withEnvPrefix(envPrefix, "ACCESS_KEY_SECRET"), }, &cli.StringFlag{ From 7ba527221f88a4ac165bdac2dcba00f10ec657b0 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Mon, 23 Sep 2024 22:14:35 -0700 Subject: [PATCH 17/18] style: add category to all s3 flags (forgot in previous commit) --- store/precomputed_key/s3/cli.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/store/precomputed_key/s3/cli.go b/store/precomputed_key/s3/cli.go index fd550d58..c40e85f8 100644 --- a/store/precomputed_key/s3/cli.go +++ b/store/precomputed_key/s3/cli.go @@ -33,6 +33,7 @@ func CLIFlags(envPrefix, category string) []cli.Flag { Name: EndpointFlagName, Usage: "endpoint for S3 storage", EnvVars: withEnvPrefix(envPrefix, "S3_ENDPOINT"), + Category: category, }, &cli.StringFlag{ Name: CredentialTypeFlagName, @@ -44,33 +45,39 @@ func CLIFlags(envPrefix, category string) []cli.Flag { Name: AccessKeyIDFlagName, Usage: "access key id for S3 storage", EnvVars: withEnvPrefix(envPrefix, "ACCESS_KEY_ID"), + Category: category, }, &cli.StringFlag{ Name: AccessKeySecretFlagName, Usage: "access key secret for S3 storage", EnvVars: withEnvPrefix(envPrefix, "ACCESS_KEY_SECRET"), + Category: category, }, &cli.StringFlag{ Name: BucketFlagName, Usage: "bucket name for S3 storage", EnvVars: withEnvPrefix(envPrefix, "BUCKET"), + Category: category, }, &cli.StringFlag{ Name: PathFlagName, Usage: "path for S3 storage", EnvVars: withEnvPrefix(envPrefix, "PATH"), + Category: category, }, &cli.BoolFlag{ Name: BackupFlagName, Usage: "whether to use S3 as a backup store to ensure resiliency in case of EigenDA read failure", Value: false, EnvVars: withEnvPrefix(envPrefix, "BACKUP"), + Category: category, }, &cli.DurationFlag{ Name: TimeoutFlagName, Usage: "timeout for S3 storage operations (e.g. get, put)", Value: 5 * time.Second, EnvVars: withEnvPrefix(envPrefix, "TIMEOUT"), + Category: category, }, } } From a50358de24723ce485a33884ce17ba1851f6ccd4 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere Date: Mon, 23 Sep 2024 22:27:13 -0700 Subject: [PATCH 18/18] style: lint --- store/precomputed_key/s3/cli.go | 46 ++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/store/precomputed_key/s3/cli.go b/store/precomputed_key/s3/cli.go index c40e85f8..4e2d0be2 100644 --- a/store/precomputed_key/s3/cli.go +++ b/store/precomputed_key/s3/cli.go @@ -30,9 +30,9 @@ func withEnvPrefix(envPrefix, s string) []string { func CLIFlags(envPrefix, category string) []cli.Flag { return []cli.Flag{ &cli.StringFlag{ - Name: EndpointFlagName, - Usage: "endpoint for S3 storage", - EnvVars: withEnvPrefix(envPrefix, "S3_ENDPOINT"), + Name: EndpointFlagName, + Usage: "endpoint for S3 storage", + EnvVars: withEnvPrefix(envPrefix, "S3_ENDPOINT"), Category: category, }, &cli.StringFlag{ @@ -42,41 +42,41 @@ func CLIFlags(envPrefix, category string) []cli.Flag { Category: category, }, &cli.StringFlag{ - Name: AccessKeyIDFlagName, - Usage: "access key id for S3 storage", - EnvVars: withEnvPrefix(envPrefix, "ACCESS_KEY_ID"), + Name: AccessKeyIDFlagName, + Usage: "access key id for S3 storage", + EnvVars: withEnvPrefix(envPrefix, "ACCESS_KEY_ID"), Category: category, }, &cli.StringFlag{ - Name: AccessKeySecretFlagName, - Usage: "access key secret for S3 storage", - EnvVars: withEnvPrefix(envPrefix, "ACCESS_KEY_SECRET"), + Name: AccessKeySecretFlagName, + Usage: "access key secret for S3 storage", + EnvVars: withEnvPrefix(envPrefix, "ACCESS_KEY_SECRET"), Category: category, }, &cli.StringFlag{ - Name: BucketFlagName, - Usage: "bucket name for S3 storage", - EnvVars: withEnvPrefix(envPrefix, "BUCKET"), + Name: BucketFlagName, + Usage: "bucket name for S3 storage", + EnvVars: withEnvPrefix(envPrefix, "BUCKET"), Category: category, }, &cli.StringFlag{ - Name: PathFlagName, - Usage: "path for S3 storage", - EnvVars: withEnvPrefix(envPrefix, "PATH"), + Name: PathFlagName, + Usage: "path for S3 storage", + EnvVars: withEnvPrefix(envPrefix, "PATH"), Category: category, }, &cli.BoolFlag{ - Name: BackupFlagName, - Usage: "whether to use S3 as a backup store to ensure resiliency in case of EigenDA read failure", - Value: false, - EnvVars: withEnvPrefix(envPrefix, "BACKUP"), + Name: BackupFlagName, + Usage: "whether to use S3 as a backup store to ensure resiliency in case of EigenDA read failure", + Value: false, + EnvVars: withEnvPrefix(envPrefix, "BACKUP"), Category: category, }, &cli.DurationFlag{ - Name: TimeoutFlagName, - Usage: "timeout for S3 storage operations (e.g. get, put)", - Value: 5 * time.Second, - EnvVars: withEnvPrefix(envPrefix, "TIMEOUT"), + Name: TimeoutFlagName, + Usage: "timeout for S3 storage operations (e.g. get, put)", + Value: 5 * time.Second, + EnvVars: withEnvPrefix(envPrefix, "TIMEOUT"), Category: category, }, }