diff --git a/core/eth/reader.go b/core/eth/reader.go index d2227106f..c52312412 100644 --- a/core/eth/reader.go +++ b/core/eth/reader.go @@ -434,8 +434,8 @@ func (t *Reader) GetOperatorStakesForQuorums(ctx context.Context, quorums []core Context: ctx, }, t.bindings.RegCoordinatorAddr, quorumBytes, blockNumber) if err != nil { - t.logger.Error("Failed to fetch operator state", "err", err) - return nil, err + t.logger.Errorf("Failed to fetch operator state: %s", err) + return nil, fmt.Errorf("failed to fetch operator state: %w", err) } state := make(core.OperatorStakes, len(state_)) diff --git a/core/eth/writer.go b/core/eth/writer.go index d088b6871..5e8770f5d 100644 --- a/core/eth/writer.go +++ b/core/eth/writer.go @@ -6,6 +6,9 @@ import ( "encoding/hex" "encoding/json" "fmt" + "github.com/Layr-Labs/eigenda/api" + dreg "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDADisperserRegistry" + "log" "math/big" "github.com/Layr-Labs/eigenda/api/grpc/churner" @@ -329,3 +332,39 @@ func (t *Writer) ConfirmBatch(ctx context.Context, batchHeader *core.BatchHeader } return receipt, nil } + +// SetDisperserAddress sets the address of the disperser. Since there is currently only one disperser, this function +// can only be used to set the address of that disperser. +func (t *Writer) SetDisperserAddress(ctx context.Context, address gethcommon.Address) error { + registry := t.bindings.DisperserRegistry + if registry == nil { + log.Printf("disperser registry not deployed") + return errors.New("disperser registry not deployed") + } + + log.Printf("Setting disperser %d address to %s", api.EigenLabsDisperserID, address.String()) + + options, err := t.ethClient.GetNoSendTransactOpts() + if err != nil { + t.logger.Error("Failed to generate transact opts", "err", err) + return err + } + options.Context = ctx + + transaction, err := registry.SetDisperserInfo( + options, + api.EigenLabsDisperserID, + dreg.DisperserInfo{ + DisperserAddress: address, + }) + if err != nil { + return fmt.Errorf("failed to create transaction for setting disperser address: %w", err) + } + + err = t.ethClient.SendTransaction(ctx, transaction) + if err != nil { + return fmt.Errorf("failed to set disperser address: %w", err) + } + + return nil +} diff --git a/inabox/deploy/config.go b/inabox/deploy/config.go index b5ceeb050..718eb85cb 100644 --- a/inabox/deploy/config.go +++ b/inabox/deploy/config.go @@ -329,7 +329,10 @@ func (env *Config) generateEncoderV2Vars(ind int, grpcPort string) EncoderVars { return v } -func (env *Config) generateControllerVars(ind int, graphUrl string) ControllerVars { +func (env *Config) generateControllerVars( + ind int, + graphUrl string) ControllerVars { + v := ControllerVars{ CONTROLLER_LOG_FORMAT: "text", CONTROLLER_DYNAMODB_TABLE_NAME: "test-BlobMetadata-v2", @@ -352,7 +355,8 @@ func (env *Config) generateControllerVars(ind int, graphUrl string) ControllerVa CONTROLLER_AWS_ENDPOINT_URL: "", CONTROLLER_ENCODER_ADDRESS: "0.0.0.0:34001", CONTROLLER_FINALIZATION_BLOCK_DELAY: "0", - CONTROLLER_DISPERSER_STORE_CHUNKS_SIGNING_DISABLED: "true", + CONTROLLER_DISPERSER_STORE_CHUNKS_SIGNING_DISABLED: "false", + CONTROLLER_DISPERSER_KMS_KEY_ID: env.DisperserKMSKeyID, } env.applyDefaults(&v, "CONTROLLER", "controller", ind) @@ -442,7 +446,7 @@ func (env *Config) generateOperatorVars(ind int, name, key, churnerUrl, logPath, NODE_NUM_CONFIRMATIONS: "0", NODE_ONCHAIN_METRICS_INTERVAL: "-1", NODE_ENABLE_V2: "true", - NODE_DISABLE_DISPERSAL_AUTHENTICATION: "true", + NODE_DISABLE_DISPERSAL_AUTHENTICATION: "false", } env.applyDefaults(&v, "NODE", "opr", ind) @@ -583,15 +587,13 @@ func (env *Config) GenerateAllVariables() { // hardcode graphurl for now graphUrl := "http://localhost:8000/subgraphs/name/Layr-Labs/eigenda-operator-state" + env.localstackEndpoint = "http://localhost:4570" + env.localstackRegion = "us-east-1" + // Create envs directory createDirectory(env.Path + "/envs") changeDirectory(env.rootPath + "/inabox") - // Gather keys - // keyData := readFile(gethPrivateKeys) - // keys := strings.Split(string(keyData), "\n") - // id := 1 - // Create compose file composeFile := env.Path + "/docker-compose.yml" servicesMap := make(map[string]map[string]interface{}) diff --git a/inabox/deploy/config_types.go b/inabox/deploy/config_types.go index eec02c0d9..970696b47 100644 --- a/inabox/deploy/config_types.go +++ b/inabox/deploy/config_types.go @@ -2,6 +2,7 @@ package deploy import ( "encoding/json" + "github.com/ethereum/go-ethereum/common" "log" "os" "path/filepath" @@ -182,10 +183,19 @@ type Config struct { Retriever RetrieverVars Controller ControllerVars Relays []RelayVars + + localstackEndpoint string + localstackRegion string + + // DisperserAddress is the address of disperser 0 (aka the only disperser at the current time) + DisperserAddress common.Address + + // DisperserKMSKeyID is the KMS key ID used to encrypt disperser data + DisperserKMSKeyID string } -func (c Config) IsEigenDADeployed() bool { - return c.EigenDA.ServiceManager != "" +func (env *Config) IsEigenDADeployed() bool { + return env.EigenDA.ServiceManager != "" } func NewTestConfig(testName, rootPath string) (testEnv *Config) { diff --git a/inabox/deploy/deploy.go b/inabox/deploy/deploy.go index 73405fe0a..516d6748f 100644 --- a/inabox/deploy/deploy.go +++ b/inabox/deploy/deploy.go @@ -4,17 +4,24 @@ import ( "context" "encoding/json" "fmt" + "github.com/Layr-Labs/eigenda/common" + caws "github.com/Layr-Labs/eigenda/common/aws" + relayreg "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDARelayRegistry" + eigendasrvmg "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDAServiceManager" + thresholdreg "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDAThresholdRegistry" + "github.com/Layr-Labs/eigenda/core/eth" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/kms" + "github.com/aws/aws-sdk-go-v2/service/kms/types" + "github.com/ethereum/go-ethereum/crypto" "io" "log" "math/big" "os" "path/filepath" "strconv" - - "github.com/Layr-Labs/eigenda/common" - relayreg "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDARelayRegistry" - eigendasrvmg "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDAServiceManager" - thresholdreg "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDAThresholdRegistry" + "strings" + "time" "github.com/Layr-Labs/eigenda/core" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -155,12 +162,108 @@ func (env *Config) DeployExperiment() { env.deploySubgraphs(startBlock) } + // Ideally these should be set in GenerateAllVariables, but they need to be used in GenerateDisperserKeypair + // which is called before GenerateAllVariables + env.localstackEndpoint = "http://localhost:4570" + env.localstackRegion = "us-east-1" + + fmt.Println("Generating disperser keypair") + err = env.GenerateDisperserKeypair() + if err != nil { + log.Panicf("could not generate disperser keypair: %v", err) + } + fmt.Println("Generating variables") env.GenerateAllVariables() fmt.Println("Test environment has successfully deployed!") } +// GenerateDisperserKeypair generates a disperser keypair using AWS KMS. +func (env *Config) GenerateDisperserKeypair() error { + + // Generate a keypair in AWS KMS + + keyManager := kms.New(kms.Options{ + Region: env.localstackRegion, + BaseEndpoint: aws.String(env.localstackEndpoint), + }) + + createKeyOutput, err := keyManager.CreateKey(context.Background(), &kms.CreateKeyInput{ + KeySpec: types.KeySpecEccSecgP256k1, + KeyUsage: types.KeyUsageTypeSignVerify, + }) + if err != nil { + if strings.Contains(err.Error(), "connect: connection refused") { + log.Printf("Unable to reach local stack, skipping disperser keypair generation. Error: %v", err) + err = nil + } + return err + } + + env.DisperserKMSKeyID = *createKeyOutput.KeyMetadata.KeyId + + // Load the public key and convert it to an Ethereum address + + key, err := caws.LoadPublicKeyKMS(context.Background(), keyManager, env.DisperserKMSKeyID) + if err != nil { + return fmt.Errorf("could not load public key: %v", err) + } + + env.DisperserAddress = crypto.PubkeyToAddress(*key) + log.Printf("Generated disperser keypair: key ID: %s, address: %s", + env.DisperserKMSKeyID, env.DisperserAddress.Hex()) + + return nil +} + +// RegisterDisperserKeypair registers the disperser's public key on-chain. +func (env *Config) RegisterDisperserKeypair(ethClient common.EthClient) error { + + // Write the disperser's public key to on-chain storage + + loggerConfig := common.DefaultLoggerConfig() + logger, err := common.NewLogger(loggerConfig) + if err != nil { + return fmt.Errorf("could not create logger: %v", err) + } + + writer, err := eth.NewWriter( + logger, + ethClient, + env.Retriever.RETRIEVER_BLS_OPERATOR_STATE_RETRIVER, + env.Retriever.RETRIEVER_EIGENDA_SERVICE_MANAGER) + if err != nil { + return fmt.Errorf("could not create writer: %v", err) + } + + err = writer.SetDisperserAddress(context.Background(), env.DisperserAddress) + if err != nil { + return fmt.Errorf("could not set disperser address: %v", err) + } + + // Read the disperser's public key from on-chain storage to verify it was written correctly + + retryTimeout := time.Now().Add(1 * time.Minute) + ticker := time.NewTicker(1 * time.Second) + + for time.Now().Before(retryTimeout) { + address, err := writer.GetDisperserAddress(context.Background(), 0) + if err != nil { + logger.Warnf("could not get disperser address: %v", err) + } else { + if address != env.DisperserAddress { + return fmt.Errorf("expected disperser address %s, got %s", env.DisperserAddress, address) + } + return nil + } + + <-ticker.C + } + + return fmt.Errorf("timed out waiting for disperser address to be set") +} + func (env *Config) RegisterBlobVersionAndRelays(ethClient common.EthClient) map[uint32]string { dasmAddr := gcommon.HexToAddress(env.EigenDA.ServiceManager) contractEigenDAServiceManager, err := eigendasrvmg.NewContractEigenDAServiceManager(dasmAddr, ethClient) diff --git a/inabox/tests/integration_suite_test.go b/inabox/tests/integration_suite_test.go index a4f442270..85ac8b364 100644 --- a/inabox/tests/integration_suite_test.go +++ b/inabox/tests/integration_suite_test.go @@ -111,13 +111,13 @@ var _ = BeforeSuite(func() { testConfig.StartGraphNode() } - fmt.Println("Deploying experiment") - testConfig.DeployExperiment() - loggerConfig := common.DefaultLoggerConfig() logger, err = common.NewLogger(loggerConfig) Expect(err).To(BeNil()) + fmt.Println("Deploying experiment") + testConfig.DeployExperiment() + pk := testConfig.Pks.EcdsaMap["default"].PrivateKey pk = strings.TrimPrefix(pk, "0x") pk = strings.TrimPrefix(pk, "0X") @@ -128,12 +128,19 @@ var _ = BeforeSuite(func() { NumRetries: numRetries, }, gcommon.Address{}, logger) Expect(err).To(BeNil()) + rpcClient, err = ethrpc.Dial(testConfig.Deployers[0].RPC) Expect(err).To(BeNil()) fmt.Println("Registering blob versions and relays") relays = testConfig.RegisterBlobVersionAndRelays(ethClient) + fmt.Println("Registering disperser keypair") + err = testConfig.RegisterDisperserKeypair(ethClient) + if err != nil { + panic(err) + } + fmt.Println("Starting binaries") testConfig.StartBinaries() diff --git a/node/auth/request_signing.go b/node/auth/request_signing.go index 6e660bbfa..1591c4807 100644 --- a/node/auth/request_signing.go +++ b/node/auth/request_signing.go @@ -29,7 +29,7 @@ func VerifyStoreChunksRequest(key gethcommon.Address, request *grpc.StoreChunksR signingPublicKey, err := crypto.SigToPub(requestHash, request.Signature) if err != nil { - return fmt.Errorf("failed to recover public key from signature: %w", err) + return fmt.Errorf("failed to recover public key from signature %x: %w", request.Signature, err) } signingAddress := crypto.PubkeyToAddress(*signingPublicKey)