From 13157a663abb98573b65bb4209f6661d9b1daecd Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 4 Dec 2023 14:53:54 +0100 Subject: [PATCH 01/34] feat: Working SDK with AppGateServer integration --- pkg/appgateserver/cmd/cmd.go | 2 + pkg/appgateserver/endpoint_selector.go | 35 ++---- pkg/appgateserver/errors.go | 16 +-- pkg/appgateserver/server.go | 92 ++-------------- pkg/appgateserver/session.go | 47 -------- pkg/appgateserver/synchronous.go | 89 +-------------- pkg/client/interface.go | 12 ++ pkg/client/query/accquerier.go | 7 +- pkg/client/query/appquerier.go | 7 +- pkg/client/query/errors.go | 1 + pkg/client/query/sessionquerier.go | 64 +++++++++++ pkg/client/services.go | 2 +- pkg/deps/config/suppliers.go | 71 ++++++++++++ pkg/sdk/deps_builder.go | 80 ++++++++++++++ pkg/sdk/errors.go | 10 ++ pkg/sdk/interface.go | 28 +++++ pkg/{appgateserver => sdk}/relay_verifier.go | 18 +-- pkg/sdk/sdk.go | 98 +++++++++++++++++ pkg/sdk/send_relay.go | 109 +++++++++++++++++++ pkg/sdk/session.go | 106 ++++++++++++++++++ 20 files changed, 632 insertions(+), 262 deletions(-) delete mode 100644 pkg/appgateserver/session.go create mode 100644 pkg/client/query/sessionquerier.go create mode 100644 pkg/sdk/deps_builder.go create mode 100644 pkg/sdk/errors.go create mode 100644 pkg/sdk/interface.go rename pkg/{appgateserver => sdk}/relay_verifier.go (75%) create mode 100644 pkg/sdk/sdk.go create mode 100644 pkg/sdk/send_relay.go create mode 100644 pkg/sdk/session.go diff --git a/pkg/appgateserver/cmd/cmd.go b/pkg/appgateserver/cmd/cmd.go index df77f17e7..cf53436cd 100644 --- a/pkg/appgateserver/cmd/cmd.go +++ b/pkg/appgateserver/cmd/cmd.go @@ -145,7 +145,9 @@ func setupAppGateServerDependencies( config.NewSupplyQueryClientContextFn(queryNodeURL.String()), // leaf config.NewSupplyAccountQuerierFn(), // leaf config.NewSupplyApplicationQuerierFn(), // leaf + config.NewSupplySessionQuerierFn(), // leaf config.NewSupplyRingCacheFn(), + config.NewSupplyPOKTRollSDKFn(queryNodeURL, appGateConfig.SigningKey), } return config.SupplyConfig(ctx, cmd, supplierFuncs) diff --git a/pkg/appgateserver/endpoint_selector.go b/pkg/appgateserver/endpoint_selector.go index fd559c8ba..702b3adc0 100644 --- a/pkg/appgateserver/endpoint_selector.go +++ b/pkg/appgateserver/endpoint_selector.go @@ -2,10 +2,8 @@ package appgateserver import ( "context" - "log" - "net/url" - sessiontypes "github.com/pokt-network/poktroll/x/session/types" + "github.com/pokt-network/poktroll/pkg/sdk" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) @@ -18,29 +16,20 @@ func (app *appGateServer) getRelayerUrl( ctx context.Context, serviceId string, rpcType sharedtypes.RPCType, - session *sessiontypes.Session, -) (supplierUrl *url.URL, supplierAddress string, err error) { - for _, supplier := range session.Suppliers { - for _, service := range supplier.Services { - // Skip services that don't match the requested serviceId. - if service.Service.Id != serviceId { - continue - } + suppliersEndpoints []*sdk.SupplierEndpoint, +) (supplierEndpoint *sdk.SupplierEndpoint, err error) { + for _, supplierEndpoint := range suppliersEndpoints { + // Skip services that don't match the requested serviceId. + if supplierEndpoint.Header.Service.Id != serviceId { + continue + } - for _, endpoint := range service.Endpoints { - // Return the first endpoint url that matches the request's RpcType. - if endpoint.RpcType == rpcType { - supplierUrl, err := url.Parse(endpoint.Url) - if err != nil { - log.Printf("ERROR: error parsing url: %s", err) - continue - } - return supplierUrl, supplier.Address, nil - } - } + // Return the first endpoint url that matches the request's RpcType. + if supplierEndpoint.RpcType == rpcType { + return supplierEndpoint, nil } } // Return an error if no relayer endpoints were found. - return nil, "", ErrAppGateNoRelayEndpoints + return nil, ErrAppGateNoRelayEndpoints } diff --git a/pkg/appgateserver/errors.go b/pkg/appgateserver/errors.go index c07a7843f..17f5456d6 100644 --- a/pkg/appgateserver/errors.go +++ b/pkg/appgateserver/errors.go @@ -3,14 +3,10 @@ package appgateserver import sdkerrors "cosmossdk.io/errors" var ( - codespace = "appgateserver" - ErrAppGateInvalidRelayResponseSignature = sdkerrors.Register(codespace, 1, "invalid relay response signature") - ErrAppGateNoRelayEndpoints = sdkerrors.Register(codespace, 2, "no relay endpoints found") - ErrAppGateInvalidRequestURL = sdkerrors.Register(codespace, 3, "invalid request URL") - ErrAppGateMissingAppAddress = sdkerrors.Register(codespace, 4, "missing application address") - ErrAppGateMissingSigningInformation = sdkerrors.Register(codespace, 5, "missing app client signing information") - ErrAppGateMissingListeningEndpoint = sdkerrors.Register(codespace, 6, "missing app client listening endpoint") - ErrAppGateEmptyRelayResponseMeta = sdkerrors.Register(codespace, 7, "empty relay response metadata") - ErrAppGateEmptyRelayResponseSignature = sdkerrors.Register(codespace, 8, "empty relay response signature") - ErrAppGateHandleRelay = sdkerrors.Register(codespace, 9, "internal error handling relay request") + codespace = "appgateserver" + ErrAppGateNoRelayEndpoints = sdkerrors.Register(codespace, 1, "no relay endpoints found") + ErrAppGateMissingAppAddress = sdkerrors.Register(codespace, 2, "missing application address") + ErrAppGateMissingSigningInformation = sdkerrors.Register(codespace, 3, "missing app client signing information") + ErrAppGateMissingListeningEndpoint = sdkerrors.Register(codespace, 4, "missing app client listening endpoint") + ErrAppGateHandleRelay = sdkerrors.Register(codespace, 5, "internal error handling relay request") ) diff --git a/pkg/appgateserver/server.go b/pkg/appgateserver/server.go index 2041c675f..bb65f28d3 100644 --- a/pkg/appgateserver/server.go +++ b/pkg/appgateserver/server.go @@ -1,6 +1,7 @@ package appgateserver import ( + "bytes" "context" "fmt" "io" @@ -8,20 +9,11 @@ import ( "net/http" "net/url" "strings" - "sync" "cosmossdk.io/depinject" - ring_secp256k1 "github.com/athanorlabs/go-dleq/secp256k1" - ringtypes "github.com/athanorlabs/go-dleq/types" - cosmosclient "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - - "github.com/pokt-network/poktroll/pkg/client" + querytypes "github.com/pokt-network/poktroll/pkg/client/query/types" - "github.com/pokt-network/poktroll/pkg/crypto" - sessiontypes "github.com/pokt-network/poktroll/x/session/types" + "github.com/pokt-network/poktroll/pkg/sdk" ) // SigningInformation is a struct that holds information related to the signing @@ -35,10 +27,6 @@ type SigningInformation struct { // private key used to sign relay requests. SigningKeyName string - // SigningKey is the scalar point on the appropriate curve corresponding to the - // signer's private key, and is used to sign relay requests via a ring signature - SigningKey ringtypes.Scalar - // AppAddress is the address of the application that the server is serving if // If it is nil, then the application address must be included in each request via a query parameter. AppAddress string @@ -54,32 +42,14 @@ type appGateServer struct { // signing information holds the signing key and application address for the server signingInformation *SigningInformation - // ringCache is used to obtain and store the ring for the application. - ringCache crypto.RingCache - // clientCtx is the client context for the application. // It is used to query for the application's account to unmarshal the supplier's account // and get the public key to verify the relay response signature. clientCtx querytypes.Context - // sessionQuerier is the querier for the session module. - // It used to get the current session for the application given a requested service. - sessionQuerier sessiontypes.QueryClient - - // sessionMu is a mutex to protect currentSession map reads and and updates. - sessionMu sync.RWMutex - - // currentSessions is the current session for the application given a block height. - // It is updated by the goListenForNewSessions goroutine. - currentSessions map[string]*sessiontypes.Session - - // accountQuerier is the querier for the account module. - // It is used to get the the supplier's public key to verify the relay response signature. - accountQuerier client.AccountQueryClient - - // blockClient is the client for the block module. - // It is used to get the current block height to query for the current session. - blockClient client.BlockClient + // sdk is the POKTRollSDK that the appGateServer uses to query for the current session + // and send relay requests to the supplier. + sdk sdk.POKTRollSDK // listeningEndpoint is the endpoint that the appGateServer will listen on. listeningEndpoint *url.URL @@ -87,10 +57,6 @@ type appGateServer struct { // server is the HTTP server that will be used capture application requests // so that they can be signed and relayed to the supplier. server *http.Server - - // accountCache is a cache of the supplier accounts that has been queried - // TODO_TECHDEBT: Add a size limit to the cache. - supplierAccountCache map[string]cryptotypes.PubKey } // NewAppGateServer creates a new appGateServer instance with the given dependencies. @@ -98,17 +64,12 @@ func NewAppGateServer( deps depinject.Config, opts ...appGateServerOption, ) (*appGateServer, error) { - app := &appGateServer{ - currentSessions: make(map[string]*sessiontypes.Session), - supplierAccountCache: make(map[string]cryptotypes.PubKey), - } + app := &appGateServer{} if err := depinject.Inject( deps, &app.clientCtx, - &app.blockClient, - &app.accountQuerier, - &app.ringCache, + &app.sdk, ); err != nil { return nil, err } @@ -134,18 +95,6 @@ func NewAppGateServer( app.signingInformation.AppAddress = appAddress.String() } - // Convert the key record to a private key and return the scalar - // point on the secp256k1 curve that it corresponds to. - // If the key is not a secp256k1 key, this will return an error. - signingKey, err := recordLocalToScalar(keyRecord.GetLocal()) - if err != nil { - return nil, fmt.Errorf("failed to convert private key to scalar: %w", err) - } - app.signingInformation.SigningKey = signingKey - - clientCtx := cosmosclient.Context(app.clientCtx) - - app.sessionQuerier = sessiontypes.NewQueryClient(clientCtx) app.server = &http.Server{Addr: app.listeningEndpoint.Host} return app, nil @@ -212,8 +161,12 @@ func (app *appGateServer) ServeHTTP(writer http.ResponseWriter, request *http.Re if appAddress == "" { app.replyWithError(payloadBz, writer, ErrAppGateMissingAppAddress) log.Print("ERROR: no application address provided") + return } + // Put the request body bytes back into the request body. + request.Body = io.NopCloser(bytes.NewBuffer(payloadBz)) + // TODO(@h5law, @red0ne): Add support for asynchronous relays, and switch on // the request type here. // TODO_RESEARCH: Should this be started in a goroutine, to allow for @@ -239,25 +192,4 @@ func (app *appGateServer) validateConfig() error { return nil } -// recordLocalToScalar converts the private key obtained from a -// key record to a scalar point on the secp256k1 curve -func recordLocalToScalar(local *keyring.Record_Local) (ringtypes.Scalar, error) { - if local == nil { - return nil, fmt.Errorf("cannot extract private key from key record: nil") - } - priv, ok := local.PrivKey.GetCachedValue().(cryptotypes.PrivKey) - if !ok { - return nil, fmt.Errorf("cannot extract private key from key record: %T", local.PrivKey.GetCachedValue()) - } - if _, ok := priv.(*secp256k1.PrivKey); !ok { - return nil, fmt.Errorf("unexpected private key type: %T, want %T", priv, &secp256k1.PrivKey{}) - } - crv := ring_secp256k1.NewCurve() - privKey, err := crv.DecodeToScalar(priv.Bytes()) - if err != nil { - return nil, fmt.Errorf("failed to decode private key: %w", err) - } - return privKey, nil -} - type appGateServerOption func(*appGateServer) diff --git a/pkg/appgateserver/session.go b/pkg/appgateserver/session.go deleted file mode 100644 index 5db25465d..000000000 --- a/pkg/appgateserver/session.go +++ /dev/null @@ -1,47 +0,0 @@ -package appgateserver - -import ( - "context" - - sessiontypes "github.com/pokt-network/poktroll/x/session/types" - sharedtypes "github.com/pokt-network/poktroll/x/shared/types" -) - -// getCurrentSession gets the current session for the given service -// It returns the current session if it exists and is still valid, otherwise it -// queries for the latest session, caches and returns it. -func (app *appGateServer) getCurrentSession( - ctx context.Context, - appAddress, serviceId string, -) (*sessiontypes.Session, error) { - app.sessionMu.RLock() - defer app.sessionMu.RUnlock() - - latestBlock := app.blockClient.LatestBlock(ctx) - if currentSession, ok := app.currentSessions[serviceId]; ok { - sessionEndBlockHeight := currentSession.Header.SessionStartBlockHeight + currentSession.NumBlocksPerSession - - // Return the current session if it is still valid. - if latestBlock.Height() < sessionEndBlockHeight { - return currentSession, nil - } - } - - // Query for the current session. - sessionQueryReq := sessiontypes.QueryGetSessionRequest{ - ApplicationAddress: appAddress, - Service: &sharedtypes.Service{Id: serviceId}, - BlockHeight: latestBlock.Height(), - } - sessionQueryRes, err := app.sessionQuerier.GetSession(ctx, &sessionQueryReq) - if err != nil { - return nil, err - } - - session := sessionQueryRes.Session - - // Cache the current session. - app.currentSessions[serviceId] = session - - return session, nil -} diff --git a/pkg/appgateserver/synchronous.go b/pkg/appgateserver/synchronous.go index d8414bf90..4127e98cb 100644 --- a/pkg/appgateserver/synchronous.go +++ b/pkg/appgateserver/synchronous.go @@ -1,17 +1,11 @@ package appgateserver import ( - "bytes" "context" - "io" "log" "net/http" - "github.com/cometbft/cometbft/crypto" - "github.com/pokt-network/poktroll/pkg/partials" - "github.com/pokt-network/poktroll/pkg/signer" - "github.com/pokt-network/poktroll/x/service/types" ) // handleSynchronousRelay handles relay requests for synchronous protocols, where @@ -31,94 +25,21 @@ func (app *appGateServer) handleSynchronousRelay( if err != nil { return ErrAppGateHandleRelay.Wrapf("getting request type: %s", err) } - session, err := app.getCurrentSession(ctx, appAddress, serviceId) + + sessionSuppliers, err := app.sdk.GetCurrentSession(ctx, appAddress, serviceId) if err != nil { return ErrAppGateHandleRelay.Wrapf("getting current session: %s", err) } - log.Printf("DEBUG: Current session ID: %s", session.SessionId) // Get a supplier URL and address for the given service and session. - supplierUrl, supplierAddress, err := app.getRelayerUrl(ctx, serviceId, requestType, session) + supplierEndpoint, err := app.getRelayerUrl(ctx, serviceId, requestType, sessionSuppliers) if err != nil { return ErrAppGateHandleRelay.Wrapf("getting supplier URL: %s", err) } - // Create the relay request. - relayRequest := &types.RelayRequest{ - Meta: &types.RelayRequestMetadata{ - SessionHeader: session.Header, - Signature: nil, // signature added below - }, - Payload: payloadBz, - } - - // Get the application's signer. - appRing, err := app.ringCache.GetRingForAddress(ctx, appAddress) - if err != nil { - return ErrAppGateHandleRelay.Wrapf("getting app ring: %s", err) - } - signer := signer.NewRingSigner(appRing, app.signingInformation.SigningKey) - - // Hash and sign the request's signable bytes. - signableBz, err := relayRequest.GetSignableBytes() - if err != nil { - return ErrAppGateHandleRelay.Wrapf("getting signable bytes: %s", err) - } - - hash := crypto.Sha256(signableBz) - signature, err := signer.Sign(hash) - if err != nil { - return ErrAppGateHandleRelay.Wrapf("signing relay: %s", err) - } - relayRequest.Meta.Signature = signature - - // Marshal the relay request to bytes and create a reader to be used as an HTTP request body. - cdc := types.ModuleCdc - relayRequestBz, err := cdc.Marshal(relayRequest) + relayResponse, err := app.sdk.SendRelay(ctx, supplierEndpoint, request) if err != nil { - return ErrAppGateHandleRelay.Wrapf("marshaling relay request: %s", err) - } - relayRequestReader := io.NopCloser(bytes.NewReader(relayRequestBz)) - var relayReq types.RelayRequest - if err := relayReq.Unmarshal(relayRequestBz); err != nil { - return ErrAppGateHandleRelay.Wrapf("unmarshaling relay response: %s", err) - } - - // Create the HTTP request to send the request to the relayer. - relayHTTPRequest := &http.Request{ - Method: request.Method, - Header: request.Header, - URL: supplierUrl, - Body: relayRequestReader, - } - - log.Printf("DEBUG: Sending signed relay request to %s", supplierUrl) - relayHTTPResponse, err := http.DefaultClient.Do(relayHTTPRequest) - if err != nil { - return ErrAppGateHandleRelay.Wrapf("sending relay request: %s", err) - } - - // Read the response body bytes. - relayResponseBz, err := io.ReadAll(relayHTTPResponse.Body) - if err != nil { - return ErrAppGateHandleRelay.Wrapf("reading relay response body: %s", err) - } - - // Unmarshal the response bytes into a RelayResponse. - relayResponse := &types.RelayResponse{} - if err := relayResponse.Unmarshal(relayResponseBz); err != nil { - return ErrAppGateHandleRelay.Wrapf("unmarshaling relay response: %s", err) - } - - // Verify the response signature. We use the supplier address that we got from - // the getRelayerUrl function since this is the address we are expecting to sign the response. - // TODO_TECHDEBT: if the RelayResponse is an internal error response, we should not verify the signature - // as in some relayer early failures, it may not be signed by the supplier. - // TODO_IMPROVE: Add more logging & telemetry so we can get visibility and signal into - // failed responses. - if err := app.verifyResponse(ctx, supplierAddress, relayResponse); err != nil { - // TODO_DISCUSS: should this be its own error type and asserted against in tests? - return ErrAppGateHandleRelay.Wrapf("verifying relay response signature: %s", err) + return err } // Reply with the RelayResponse payload. diff --git a/pkg/client/interface.go b/pkg/client/interface.go index 1b6f34c19..7159b1c49 100644 --- a/pkg/client/interface.go +++ b/pkg/client/interface.go @@ -195,3 +195,15 @@ type ApplicationQueryClient interface { // GetApplication queries the chain for the details of the application provided GetApplication(ctx context.Context, appAddress string) (apptypes.Application, error) } + +// SessionQueryClient defines an interface that enables the querying of the +// on-chain session information +type SessionQueryClient interface { + // GetSession queries the chain for the details of the session provided + GetSession( + ctx context.Context, + address string, + serviceId string, + blockHeight int64, + ) (*sessiontypes.Session, error) +} diff --git a/pkg/client/query/accquerier.go b/pkg/client/query/accquerier.go index 890550b16..475204b74 100644 --- a/pkg/client/query/accquerier.go +++ b/pkg/client/query/accquerier.go @@ -4,18 +4,17 @@ import ( "context" "cosmossdk.io/depinject" - cosmosclient "github.com/cosmos/cosmos-sdk/client" accounttypes "github.com/cosmos/cosmos-sdk/x/auth/types" + grpc "github.com/cosmos/gogoproto/grpc" "github.com/pokt-network/poktroll/pkg/client" - "github.com/pokt-network/poktroll/pkg/client/query/types" ) // accQuerier is a wrapper around the accounttypes.QueryClient that enables the // querying of on-chain account information through a single exposed method // which returns an accounttypes.AccountI interface type accQuerier struct { - clientCtx types.Context + clientCtx grpc.ClientConn accountQuerier accounttypes.QueryClient } @@ -34,7 +33,7 @@ func NewAccountQuerier(deps depinject.Config) (client.AccountQueryClient, error) return nil, err } - aq.accountQuerier = accounttypes.NewQueryClient(cosmosclient.Context(aq.clientCtx)) + aq.accountQuerier = accounttypes.NewQueryClient(aq.clientCtx) return aq, nil } diff --git a/pkg/client/query/appquerier.go b/pkg/client/query/appquerier.go index 91162ba68..9e8c340d4 100644 --- a/pkg/client/query/appquerier.go +++ b/pkg/client/query/appquerier.go @@ -4,10 +4,9 @@ import ( "context" "cosmossdk.io/depinject" - cosmosclient "github.com/cosmos/cosmos-sdk/client" + grpc "github.com/cosmos/gogoproto/grpc" "github.com/pokt-network/poktroll/pkg/client" - "github.com/pokt-network/poktroll/pkg/client/query/types" apptypes "github.com/pokt-network/poktroll/x/application/types" ) @@ -15,7 +14,7 @@ import ( // querying of on-chain application information through a single exposed method // which returns an apptypes.Application interface type appQuerier struct { - clientCtx types.Context + clientCtx grpc.ClientConn applicationQuerier apptypes.QueryClient } @@ -34,7 +33,7 @@ func NewApplicationQuerier(deps depinject.Config) (client.ApplicationQueryClient return nil, err } - aq.applicationQuerier = apptypes.NewQueryClient(cosmosclient.Context(aq.clientCtx)) + aq.applicationQuerier = apptypes.NewQueryClient(aq.clientCtx) return aq, nil } diff --git a/pkg/client/query/errors.go b/pkg/client/query/errors.go index e651076aa..d2ef4d7a3 100644 --- a/pkg/client/query/errors.go +++ b/pkg/client/query/errors.go @@ -8,4 +8,5 @@ var ( codespace = "query" ErrQueryAccountNotFound = sdkerrors.Register(codespace, 1, "account not found") ErrQueryUnableToDeserialiseAccount = sdkerrors.Register(codespace, 2, "unable to deserialise account") + ErrQueryInvalidSession = sdkerrors.Register(codespace, 3, "invalid session") ) diff --git a/pkg/client/query/sessionquerier.go b/pkg/client/query/sessionquerier.go new file mode 100644 index 000000000..15f1c42c8 --- /dev/null +++ b/pkg/client/query/sessionquerier.go @@ -0,0 +1,64 @@ +package query + +import ( + "context" + + "cosmossdk.io/depinject" + grpc "github.com/cosmos/gogoproto/grpc" + + "github.com/pokt-network/poktroll/pkg/client" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" +) + +// sessionQuerier is a wrapper around the sessiontypes.QueryClient that enables the +// querying of on-chain session information through a single exposed method +// which returns an sessiontypes.Session struct +type sessionQuerier struct { + clientCtx grpc.ClientConn + sessionQuerier sessiontypes.QueryClient +} + +// NewSessionQuerier returns a new instance of a client.SessionQueryClient by +// injecting the dependecies provided by the depinject.Config. +// +// Required dependencies: +// - clientCtx +func NewSessionQuerier(deps depinject.Config) (client.SessionQueryClient, error) { + sessq := &sessionQuerier{} + + if err := depinject.Inject( + deps, + &sessq.clientCtx, + ); err != nil { + return nil, err + } + + sessq.sessionQuerier = sessiontypes.NewQueryClient(sessq.clientCtx) + + return sessq, nil +} + +// GetSession returns an sessiontypes.Session struct for a given appAddress, +// serviceId and blockHeight +func (sessq *sessionQuerier) GetSession( + ctx context.Context, + appAddress string, + serviceId string, + blockHeight int64, +) (*sessiontypes.Session, error) { + service := &sharedtypes.Service{Id: serviceId} + req := &sessiontypes.QueryGetSessionRequest{ + ApplicationAddress: appAddress, + Service: service, + BlockHeight: blockHeight, + } + res, err := sessq.sessionQuerier.GetSession(ctx, req) + if err != nil { + return nil, ErrQueryInvalidSession.Wrapf( + "address: %s,serviceId %s, block height %d [%v]", + appAddress, serviceId, blockHeight, err, + ) + } + return res.Session, nil +} diff --git a/pkg/client/services.go b/pkg/client/services.go index 1e2667cf9..08fbaee03 100644 --- a/pkg/client/services.go +++ b/pkg/client/services.go @@ -9,7 +9,7 @@ import ( // NewTestApplicationServiceConfig returns a slice of application service configs for testing. func NewTestApplicationServiceConfig(prefix string, count int) []*sharedtypes.ApplicationServiceConfig { appSvcCfg := make([]*sharedtypes.ApplicationServiceConfig, count) - for i, _ := range appSvcCfg { + for i := range appSvcCfg { serviceId := fmt.Sprintf("%s%d", prefix, i) appSvcCfg[i] = &sharedtypes.ApplicationServiceConfig{ Service: &sharedtypes.Service{Id: serviceId}, diff --git a/pkg/deps/config/suppliers.go b/pkg/deps/config/suppliers.go index d1c2ccbfc..f7096dfc4 100644 --- a/pkg/deps/config/suppliers.go +++ b/pkg/deps/config/suppliers.go @@ -3,10 +3,13 @@ package config import ( "context" "fmt" + "net/url" "cosmossdk.io/depinject" cosmosclient "github.com/cosmos/cosmos-sdk/client" cosmosflags "github.com/cosmos/cosmos-sdk/client/flags" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + grpc "github.com/cosmos/gogoproto/grpc" "github.com/spf13/cobra" "github.com/pokt-network/poktroll/pkg/client/block" @@ -15,6 +18,7 @@ import ( querytypes "github.com/pokt-network/poktroll/pkg/client/query/types" txtypes "github.com/pokt-network/poktroll/pkg/client/tx/types" "github.com/pokt-network/poktroll/pkg/crypto/rings" + "github.com/pokt-network/poktroll/pkg/sdk" ) // hostToWebsocketURL converts the provided host into a websocket URL that can @@ -112,6 +116,7 @@ func NewSupplyQueryClientContextFn(pocketQueryNodeURL string) SupplierFn { } deps = depinject.Configs(deps, depinject.Supply( querytypes.Context(queryClientCtx), + grpc.ClientConn(queryClientCtx), )) // Restore the flag's original value in order for other components @@ -225,3 +230,69 @@ func NewSupplyRingCacheFn() SupplierFn { return depinject.Configs(deps, depinject.Supply(ringCache)), nil } } + +// NewSupplySessionQuerierFn returns a function which constructs a +// SessionQuerier instance with the required dependencies and returns a new +// depinject.Config which is supplied with the given deps and the new SessionQuerier. +func NewSupplySessionQuerierFn() SupplierFn { + return func( + _ context.Context, + deps depinject.Config, + _ *cobra.Command, + ) (depinject.Config, error) { + // Create the session querier. + sessionQuerier, err := query.NewSessionQuerier(deps) + if err != nil { + return nil, err + } + + // Supply the session querier to the provided deps + return depinject.Configs(deps, depinject.Supply(sessionQuerier)), nil + } +} + +// NewSupplyPOKTRollSDKFn returns a function which constructs a +// POKTRollSDK instance with the required dependencies and returns a new +// depinject.Config which is supplied with the given deps and the new POKTRollSDK. +func NewSupplyPOKTRollSDKFn( + queryNodeURL *url.URL, + signingKeyName string, +) SupplierFn { + return func( + ctx context.Context, + deps depinject.Config, + _ *cobra.Command, + ) (depinject.Config, error) { + var clientCtx cosmosclient.Context + + // On a Cosmos environment we get the private key from the keyring + // Inject the client context, get the keyring from it then get the private key + if err := depinject.Inject(deps, &clientCtx); err != nil { + return nil, err + } + + keyRecord, err := clientCtx.Keyring.Key(signingKeyName) + if err != nil { + return nil, err + } + + privateKey, ok := keyRecord.GetLocal().PrivKey.GetCachedValue().(cryptotypes.PrivKey) + if !ok { + return nil, err + } + + config := &sdk.POKTRollSDKConfig{ + PrivateKey: privateKey, + PocketNodeUrl: queryNodeURL, + Deps: deps, + } + + poktrollSDK, err := sdk.NewPOKTRollSDK(ctx, config) + if err != nil { + return nil, err + } + + // Supply the session querier to the provided deps + return depinject.Configs(deps, depinject.Supply(poktrollSDK)), nil + } +} diff --git a/pkg/sdk/deps_builder.go b/pkg/sdk/deps_builder.go new file mode 100644 index 000000000..1517df465 --- /dev/null +++ b/pkg/sdk/deps_builder.go @@ -0,0 +1,80 @@ +package sdk + +import ( + "context" + "fmt" + + "cosmossdk.io/depinject" + grpctypes "github.com/cosmos/gogoproto/grpc" + grpc "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + block "github.com/pokt-network/poktroll/pkg/client/block" + eventsquery "github.com/pokt-network/poktroll/pkg/client/events_query" + "github.com/pokt-network/poktroll/pkg/client/query" + "github.com/pokt-network/poktroll/pkg/crypto/rings" +) + +// buildDeps builds the dependencies for the POKTRollSDK if they are not provided +// in the config. This is useful for the SDK consumers that do not want or +// cannot provide the dependencies through depinject. +func (sdk *poktrollSDK) buildDeps( + ctx context.Context, + config *POKTRollSDKConfig, +) (depinject.Config, error) { + pocketNodeWebsocketURL := fmt.Sprintf("ws://%s/websocket", config.PocketNodeUrl.Host) + + // Have a new depinject config + deps := depinject.Configs() + + // Create and supply the events query client + eventsQueryClient := eventsquery.NewEventsQueryClient(pocketNodeWebsocketURL) + depinject.Configs(deps, depinject.Supply(eventsQueryClient)) + + // Create and supply the block client that depends on the events query client + blockClient, err := block.NewBlockClient(ctx, deps, pocketNodeWebsocketURL) + if err != nil { + return nil, err + } + depinject.Configs(deps, depinject.Supply(blockClient)) + + // Create and supply the grpc client used by the queriers + // TODO_TECHDEBT: Configure the grpc client options from the config + var grpcClient grpctypes.ClientConn + grpcClient, err = grpc.Dial( + config.PocketNodeUrl.Host, + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + if err != nil { + return nil, err + } + depinject.Configs(deps, depinject.Supply(grpcClient)) + + // Create and supply the queriers (application, account, session) + accountQuerier, err := query.NewAccountQuerier(deps) + if err != nil { + return nil, err + } + depinject.Configs(deps, depinject.Supply(accountQuerier)) + + applicationQuerier, err := query.NewApplicationQuerier(deps) + if err != nil { + return nil, err + } + depinject.Configs(deps, depinject.Supply(applicationQuerier)) + + sessionQuerier, err := query.NewSessionQuerier(deps) + if err != nil { + return nil, err + } + depinject.Configs(deps, depinject.Supply(sessionQuerier)) + + // Create and supply the ring cache that depends on application and account queriers + ringCache, err := rings.NewRingCache(deps) + if err != nil { + return nil, err + } + depinject.Configs(deps, depinject.Supply(ringCache)) + + return deps, nil +} diff --git a/pkg/sdk/errors.go b/pkg/sdk/errors.go new file mode 100644 index 000000000..04f34bf53 --- /dev/null +++ b/pkg/sdk/errors.go @@ -0,0 +1,10 @@ +package sdk + +import sdkerrors "cosmossdk.io/errors" + +var ( + codespace = "poktrollsdk" + ErrSDKHandleRelay = sdkerrors.Register(codespace, 1, "internal error handling relay request") + ErrSDKInvalidRelayResponseSignature = sdkerrors.Register(codespace, 2, "invalid relay response signature") + ErrSDKEmptyRelayResponseSignature = sdkerrors.Register(codespace, 3, "empty relay response signature") +) diff --git a/pkg/sdk/interface.go b/pkg/sdk/interface.go new file mode 100644 index 000000000..d04c19840 --- /dev/null +++ b/pkg/sdk/interface.go @@ -0,0 +1,28 @@ +package sdk + +import ( + "context" + "net/http" + + servicetypes "github.com/pokt-network/poktroll/x/service/types" +) + +// POKTRollSDK is the interface for the POKTRoll SDK. It is used by gateways +// to interact with the Pocket protocol. +type POKTRollSDK interface { + + // GetSession returns the suppliers endpoints of the current session for + // the given application and service. + GetCurrentSession( + ctx context.Context, + appAddress string, + serviceId string, + ) (session []*SupplierEndpoint, err error) + + // SendRelay sends a relay request to the given supplier's endpoint. + SendRelay( + ctx context.Context, + sessionSupplierEndpoint *SupplierEndpoint, + request *http.Request, + ) (response *servicetypes.RelayResponse, err error) +} diff --git a/pkg/appgateserver/relay_verifier.go b/pkg/sdk/relay_verifier.go similarity index 75% rename from pkg/appgateserver/relay_verifier.go rename to pkg/sdk/relay_verifier.go index 155470bc9..f5ebcce9b 100644 --- a/pkg/appgateserver/relay_verifier.go +++ b/pkg/sdk/relay_verifier.go @@ -1,4 +1,4 @@ -package appgateserver +package sdk import ( "context" @@ -10,20 +10,20 @@ import ( ) // verifyResponse verifies the relay response signature. -func (app *appGateServer) verifyResponse( +func (sdk *poktrollSDK) verifyResponse( ctx context.Context, supplierAddress string, relayResponse *types.RelayResponse, ) error { // Get the supplier's public key. - supplierPubKey, err := app.getSupplierPubKeyFromAddress(ctx, supplierAddress) + supplierPubKey, err := sdk.getSupplierPubKeyFromAddress(ctx, supplierAddress) if err != nil { return err } // Extract the supplier's signature if relayResponse.Meta == nil { - return ErrAppGateEmptyRelayResponseSignature.Wrapf( + return ErrSDKEmptyRelayResponseSignature.Wrapf( "response payload: %s", relayResponse.Payload, ) } @@ -38,7 +38,7 @@ func (app *appGateServer) verifyResponse( // Verify the relay response signature. if !supplierPubKey.VerifySignature(hash, supplierSignature) { - return ErrAppGateInvalidRelayResponseSignature + return ErrSDKInvalidRelayResponseSignature } return nil @@ -46,25 +46,25 @@ func (app *appGateServer) verifyResponse( // getSupplierPubKeyFromAddress gets the supplier's public key from the cache or // queries if it is not found. The public key is then cached before being returned. -func (app *appGateServer) getSupplierPubKeyFromAddress( +func (sdk *poktrollSDK) getSupplierPubKeyFromAddress( ctx context.Context, supplierAddress string, ) (cryptotypes.PubKey, error) { - supplierPubKey, ok := app.supplierAccountCache[supplierAddress] + supplierPubKey, ok := sdk.supplierAccountCache[supplierAddress] if ok { return supplierPubKey, nil } // Query for the supplier account to get the application's public key // to verify the relay request signature. - acc, err := app.accountQuerier.GetAccount(ctx, supplierAddress) + acc, err := sdk.accountQuerier.GetAccount(ctx, supplierAddress) if err != nil { return nil, err } fetchedPubKey := acc.GetPubKey() // Cache the retrieved public key. - app.supplierAccountCache[supplierAddress] = fetchedPubKey + sdk.supplierAccountCache[supplierAddress] = fetchedPubKey return fetchedPubKey, nil } diff --git a/pkg/sdk/sdk.go b/pkg/sdk/sdk.go new file mode 100644 index 000000000..3acb0a2f3 --- /dev/null +++ b/pkg/sdk/sdk.go @@ -0,0 +1,98 @@ +package sdk + +import ( + "context" + "fmt" + "net/url" + "sync" + + "cosmossdk.io/depinject" + ring_secp256k1 "github.com/athanorlabs/go-dleq/secp256k1" + ringtypes "github.com/athanorlabs/go-dleq/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + + "github.com/pokt-network/poktroll/pkg/client" + "github.com/pokt-network/poktroll/pkg/crypto" +) + +var _ POKTRollSDK = (*poktrollSDK)(nil) + +// POKTRollSDKConfig is the configuration for the POKTRollSDK. +// It contains the Pocket Node URL to be used by the queriers and the private key +// to be used for signing relay requests. +// Deps is an optional field that can be used to provide the needed dependencies +// for the SDK. If it is not provided, the SDK will build the dependencies. +type POKTRollSDKConfig struct { + PocketNodeUrl *url.URL + PrivateKey cryptotypes.PrivKey + Deps depinject.Config +} + +// poktrollSDK is the implementation of the POKTRollSDK. +type poktrollSDK struct { + config *POKTRollSDKConfig + + signingKey ringtypes.Scalar + + // ringCache is used to obtain and store the ring for the application. + ringCache crypto.RingCache + + // sessionQuerier is the querier for the session module. + // It used to get the current session for the application given a requested service. + sessionQuerier client.SessionQueryClient + + // sessionMu is a mutex to protect currentSession map reads and and updates. + sessionMu sync.RWMutex + + // latestSessions is a latest sessions map of serviceId -> appAddress -> SessionSuppliers. + latestSessions map[string]map[string]*sessionSuppliers + + // accountQuerier is the querier for the account module. + // It is used to get the the supplier's public key to verify the relay response signature. + accountQuerier client.AccountQueryClient + + // blockClient is the client for the block module. + // It is used to get the current block height to query for the current session. + blockClient client.BlockClient + + // accountCache is a cache of the supplier accounts that has been queried + // TODO_TECHDEBT: Add a size limit to the cache. + supplierAccountCache map[string]cryptotypes.PubKey +} + +func NewPOKTRollSDK(ctx context.Context, config *POKTRollSDKConfig) (POKTRollSDK, error) { + sdk := &poktrollSDK{ + config: config, + latestSessions: make(map[string]map[string]*sessionSuppliers), + supplierAccountCache: make(map[string]cryptotypes.PubKey), + } + + var err error + var deps depinject.Config + + // Build the dependencies if they are not provided in the config. + if config.Deps != nil { + deps = config.Deps + } else if deps, err = sdk.buildDeps(ctx, config); err != nil { + return nil, err + } + + if err := depinject.Inject( + deps, + &sdk.ringCache, + &sdk.sessionQuerier, + &sdk.accountQuerier, + &sdk.blockClient, + ); err != nil { + return nil, err + } + + // Store the private key as a ring scalar to be used for ring signatures. + crv := ring_secp256k1.NewCurve() + sdk.signingKey, err = crv.DecodeToScalar(config.PrivateKey.Bytes()) + if err != nil { + return nil, fmt.Errorf("failed to decode private key: %w", err) + } + + return sdk, nil +} diff --git a/pkg/sdk/send_relay.go b/pkg/sdk/send_relay.go new file mode 100644 index 000000000..ce48808ef --- /dev/null +++ b/pkg/sdk/send_relay.go @@ -0,0 +1,109 @@ +package sdk + +import ( + "bytes" + "context" + "io" + "log" + "net/http" + + cryptocomet "github.com/cometbft/cometbft/crypto" + "github.com/pokt-network/poktroll/pkg/signer" + "github.com/pokt-network/poktroll/x/service/types" +) + +// SendRelay sends a relay request to the given supplier's endpoint. +// It signs the request, relays it to the supplier and verifies the response signature. +// It takes an http.Request as an argument and uses its method and headers to create +// the relay request. +func (sdk *poktrollSDK) SendRelay( + ctx context.Context, + supplierEndpoint *SupplierEndpoint, + request *http.Request, +) (response *types.RelayResponse, err error) { + payloadBz, err := io.ReadAll(request.Body) + if err != nil { + return nil, ErrSDKHandleRelay.Wrapf("reading request body: %s", err) + } + + // Create the relay request. + relayRequest := &types.RelayRequest{ + Meta: &types.RelayRequestMetadata{ + SessionHeader: supplierEndpoint.Header, + Signature: nil, // signature added below + }, + Payload: payloadBz, + } + + // Get the application's signer. + appAddress := supplierEndpoint.Header.ApplicationAddress + appRing, err := sdk.ringCache.GetRingForAddress(ctx, appAddress) + if err != nil { + return nil, ErrSDKHandleRelay.Wrapf("getting app ring: %s", err) + } + signer := signer.NewRingSigner(appRing, sdk.signingKey) + + // Hash and sign the request's signable bytes. + signableBz, err := relayRequest.GetSignableBytes() + if err != nil { + return nil, ErrSDKHandleRelay.Wrapf("getting signable bytes: %s", err) + } + + hash := cryptocomet.Sha256(signableBz) + signature, err := signer.Sign(hash) + if err != nil { + return nil, ErrSDKHandleRelay.Wrapf("signing relay: %s", err) + } + relayRequest.Meta.Signature = signature + + // Marshal the relay request to bytes and create a reader to be used as an HTTP request body. + cdc := types.ModuleCdc + relayRequestBz, err := cdc.Marshal(relayRequest) + if err != nil { + return nil, ErrSDKHandleRelay.Wrapf("marshaling relay request: %s", err) + } + relayRequestReader := io.NopCloser(bytes.NewReader(relayRequestBz)) + var relayReq types.RelayRequest + if err := relayReq.Unmarshal(relayRequestBz); err != nil { + return nil, ErrSDKHandleRelay.Wrapf("unmarshaling relay response: %s", err) + } + + // Create the HTTP request to send the request to the relayer. + relayHTTPRequest := &http.Request{ + Method: request.Method, + Header: request.Header, + URL: supplierEndpoint.Url, + Body: relayRequestReader, + } + + log.Printf("DEBUG: Sending signed relay request to %s", supplierEndpoint.Url) + relayHTTPResponse, err := http.DefaultClient.Do(relayHTTPRequest) + if err != nil { + return nil, ErrSDKHandleRelay.Wrapf("sending relay request: %s", err) + } + + // Read the response body bytes. + relayResponseBz, err := io.ReadAll(relayHTTPResponse.Body) + if err != nil { + return nil, ErrSDKHandleRelay.Wrapf("reading relay response body: %s", err) + } + + // Unmarshal the response bytes into a RelayResponse. + relayResponse := &types.RelayResponse{} + if err := relayResponse.Unmarshal(relayResponseBz); err != nil { + return nil, ErrSDKHandleRelay.Wrapf("unmarshaling relay response: %s", err) + } + + // Verify the response signature. We use the supplier address that we got from + // the getRelayerUrl function since this is the address we are expecting to sign the response. + // TODO_TECHDEBT: if the RelayResponse is an internal error response, we should not verify the signature + // as in some relayer early failures, it may not be signed by the supplier. + // TODO_IMPROVE: Add more logging & telemetry so we can get visibility and signal into + // failed responses. + if err := sdk.verifyResponse(ctx, supplierEndpoint.SupplierAddress, relayResponse); err != nil { + // TODO_DISCUSS: should this be its own error type and asserted against in tests? + return nil, ErrSDKHandleRelay.Wrapf("verifying relay response signature: %s", err) + } + + return relayResponse, nil +} diff --git a/pkg/sdk/session.go b/pkg/sdk/session.go new file mode 100644 index 000000000..278ef4c4b --- /dev/null +++ b/pkg/sdk/session.go @@ -0,0 +1,106 @@ +package sdk + +import ( + "context" + "log" + "net/url" + + sessiontypes "github.com/pokt-network/poktroll/x/session/types" + sharedtypes "github.com/pokt-network/poktroll/x/shared/types" +) + +// sessionSuppliers is the structure that represents a session's end block height +// and its matching suppliers. +type sessionSuppliers struct { + // SessionEndBlockHeight is the session's end block height that helps + // determine if the session is still valid without looking into SupplierEndpoints slice. + SessionEndBlockHeight int64 + SuppliersEndpoints []*SupplierEndpoint +} + +// SupplierEndpoint is the structure that represents a supplier's endpoint +// augmented with the session's header and the supplier's address for easy +// access to the needed information when sending a relay request. +type SupplierEndpoint struct { + Url *url.URL + RpcType sharedtypes.RPCType + SupplierAddress string + Header *sessiontypes.SessionHeader +} + +// GetCurrentSession gets the current session for the given service +// It returns the current state if it exists and is still valid, otherwise it +// queries for the latest session, constructs the SessionSuppliers, caches and +// returns its SupplierEndpoints. +func (sdk *poktrollSDK) GetCurrentSession( + ctx context.Context, + appAddress, serviceId string, +) ([]*SupplierEndpoint, error) { + sdk.sessionMu.RLock() + defer sdk.sessionMu.RUnlock() + + latestBlockHeight := sdk.blockClient.LatestBlock(ctx).Height() + + // Create the latestSessions map entry for the serviceId if it doesn't exist. + if _, ok := sdk.latestSessions[serviceId]; !ok { + sdk.latestSessions[serviceId] = map[string]*sessionSuppliers{} + } + + // Create the latestSessions[serviceId] map entry for the appAddress if it doesn't exist. + if _, ok := sdk.latestSessions[serviceId][appAddress]; !ok { + sdk.latestSessions[serviceId][appAddress] = &sessionSuppliers{} + } + + currentSession := sdk.latestSessions[serviceId][appAddress] + + // Return the current session's SuppliersEndpoints if the session is still valid. + if latestBlockHeight < currentSession.SessionEndBlockHeight { + return currentSession.SuppliersEndpoints, nil + } + + // Query for the current session. + session, err := sdk.sessionQuerier.GetSession( + ctx, + appAddress, + serviceId, + latestBlockHeight, + ) + if err != nil { + return nil, err + } + + // Override the old SessionSuppliers and constructs the new one. + currentSession.SessionEndBlockHeight = session.Header.SessionEndBlockHeight + currentSession.SuppliersEndpoints = []*SupplierEndpoint{} + + for _, supplier := range session.Suppliers { + for _, services := range supplier.Services { + // Skip the session's services that don't match the requested serviceId. + if services.Service.Id != serviceId { + continue + } + + // Loop through the services' endpoints and add them to the + // SessionSuppliers.SuppliersEndpoints slice. + for _, endpoint := range services.Endpoints { + url, err := url.Parse(endpoint.Url) + if err != nil { + log.Printf("error parsing url: %s", err) + continue + } + + currentSession.SuppliersEndpoints = append( + currentSession.SuppliersEndpoints, + &SupplierEndpoint{ + Url: url, + RpcType: endpoint.RpcType, + SupplierAddress: supplier.Address, + Header: session.Header, + }, + ) + } + } + } + + return currentSession.SuppliersEndpoints, nil +} From 8c5587e208cbaf146fdfe7c984226b647d0f9027 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Tue, 5 Dec 2023 16:37:04 +0100 Subject: [PATCH 02/34] chore: Address change requests --- pkg/appgateserver/endpoint_selector.go | 4 ++-- pkg/appgateserver/server.go | 14 +++++++------- pkg/appgateserver/synchronous.go | 2 +- pkg/client/interface.go | 2 +- pkg/client/query/accquerier.go | 8 +++++--- pkg/client/query/appquerier.go | 8 +++++--- pkg/client/query/errors.go | 2 +- pkg/client/query/sessionquerier.go | 14 ++++++++------ pkg/sdk/deps_builder.go | 4 +++- pkg/sdk/errors.go | 1 + pkg/sdk/interface.go | 5 ++--- pkg/sdk/sdk.go | 9 ++++++--- pkg/sdk/send_relay.go | 15 ++++++++------- pkg/sdk/session.go | 16 ++++++++-------- 14 files changed, 58 insertions(+), 46 deletions(-) diff --git a/pkg/appgateserver/endpoint_selector.go b/pkg/appgateserver/endpoint_selector.go index 702b3adc0..db9aa3442 100644 --- a/pkg/appgateserver/endpoint_selector.go +++ b/pkg/appgateserver/endpoint_selector.go @@ -16,9 +16,9 @@ func (app *appGateServer) getRelayerUrl( ctx context.Context, serviceId string, rpcType sharedtypes.RPCType, - suppliersEndpoints []*sdk.SupplierEndpoint, + supplierEndpoints []*sdk.SupplierEndpoint, ) (supplierEndpoint *sdk.SupplierEndpoint, err error) { - for _, supplierEndpoint := range suppliersEndpoints { + for _, supplierEndpoint := range supplierEndpoints { // Skip services that don't match the requested serviceId. if supplierEndpoint.Header.Service.Id != serviceId { continue diff --git a/pkg/appgateserver/server.go b/pkg/appgateserver/server.go index bb65f28d3..f1c4655ff 100644 --- a/pkg/appgateserver/server.go +++ b/pkg/appgateserver/server.go @@ -141,17 +141,17 @@ func (app *appGateServer) ServeHTTP(writer http.ResponseWriter, request *http.Re serviceId := strings.Split(path, "/")[1] // Read the request body bytes. - payloadBz, err := io.ReadAll(request.Body) + requestPayloadBz, err := io.ReadAll(request.Body) if err != nil { app.replyWithError( - payloadBz, + requestPayloadBz, writer, ErrAppGateHandleRelay.Wrapf("reading relay request body: %s", err), ) log.Printf("ERROR: failed reading relay request body: %s", err) return } - log.Printf("DEBUG: relay request body: %s", string(payloadBz)) + log.Printf("DEBUG: relay request body: %s", string(requestPayloadBz)) // Determine the application address. appAddress := app.signingInformation.AppAddress @@ -159,21 +159,21 @@ func (app *appGateServer) ServeHTTP(writer http.ResponseWriter, request *http.Re appAddress = request.URL.Query().Get("senderAddr") } if appAddress == "" { - app.replyWithError(payloadBz, writer, ErrAppGateMissingAppAddress) + app.replyWithError(requestPayloadBz, writer, ErrAppGateMissingAppAddress) log.Print("ERROR: no application address provided") return } // Put the request body bytes back into the request body. - request.Body = io.NopCloser(bytes.NewBuffer(payloadBz)) + request.Body = io.NopCloser(bytes.NewBuffer(requestPayloadBz)) // TODO(@h5law, @red0ne): Add support for asynchronous relays, and switch on // the request type here. // TODO_RESEARCH: Should this be started in a goroutine, to allow for // concurrent requests from numerous applications? - if err := app.handleSynchronousRelay(ctx, appAddress, serviceId, payloadBz, request, writer); err != nil { + if err := app.handleSynchronousRelay(ctx, appAddress, serviceId, requestPayloadBz, request, writer); err != nil { // Reply with an error response if there was an error handling the relay. - app.replyWithError(payloadBz, writer, err) + app.replyWithError(requestPayloadBz, writer, err) log.Printf("ERROR: failed handling relay: %s", err) return } diff --git a/pkg/appgateserver/synchronous.go b/pkg/appgateserver/synchronous.go index 4127e98cb..e202be085 100644 --- a/pkg/appgateserver/synchronous.go +++ b/pkg/appgateserver/synchronous.go @@ -26,7 +26,7 @@ func (app *appGateServer) handleSynchronousRelay( return ErrAppGateHandleRelay.Wrapf("getting request type: %s", err) } - sessionSuppliers, err := app.sdk.GetCurrentSession(ctx, appAddress, serviceId) + sessionSuppliers, err := app.sdk.GetSessionSupplierEndpoints(ctx, appAddress, serviceId) if err != nil { return ErrAppGateHandleRelay.Wrapf("getting current session: %s", err) } diff --git a/pkg/client/interface.go b/pkg/client/interface.go index 7159b1c49..d3b8cb5b5 100644 --- a/pkg/client/interface.go +++ b/pkg/client/interface.go @@ -202,7 +202,7 @@ type SessionQueryClient interface { // GetSession queries the chain for the details of the session provided GetSession( ctx context.Context, - address string, + appAddress string, serviceId string, blockHeight int64, ) (*sessiontypes.Session, error) diff --git a/pkg/client/query/accquerier.go b/pkg/client/query/accquerier.go index 475204b74..73ed42b51 100644 --- a/pkg/client/query/accquerier.go +++ b/pkg/client/query/accquerier.go @@ -10,11 +10,13 @@ import ( "github.com/pokt-network/poktroll/pkg/client" ) +var _ client.AccountQueryClient = (*accQuerier)(nil) + // accQuerier is a wrapper around the accounttypes.QueryClient that enables the // querying of on-chain account information through a single exposed method // which returns an accounttypes.AccountI interface type accQuerier struct { - clientCtx grpc.ClientConn + clientConn grpc.ClientConn accountQuerier accounttypes.QueryClient } @@ -28,12 +30,12 @@ func NewAccountQuerier(deps depinject.Config) (client.AccountQueryClient, error) if err := depinject.Inject( deps, - &aq.clientCtx, + &aq.clientConn, ); err != nil { return nil, err } - aq.accountQuerier = accounttypes.NewQueryClient(aq.clientCtx) + aq.accountQuerier = accounttypes.NewQueryClient(aq.clientConn) return aq, nil } diff --git a/pkg/client/query/appquerier.go b/pkg/client/query/appquerier.go index 9e8c340d4..310a25dfe 100644 --- a/pkg/client/query/appquerier.go +++ b/pkg/client/query/appquerier.go @@ -10,11 +10,13 @@ import ( apptypes "github.com/pokt-network/poktroll/x/application/types" ) +var _ client.ApplicationQueryClient = (*appQuerier)(nil) + // appQuerier is a wrapper around the apptypes.QueryClient that enables the // querying of on-chain application information through a single exposed method // which returns an apptypes.Application interface type appQuerier struct { - clientCtx grpc.ClientConn + clientConn grpc.ClientConn applicationQuerier apptypes.QueryClient } @@ -28,12 +30,12 @@ func NewApplicationQuerier(deps depinject.Config) (client.ApplicationQueryClient if err := depinject.Inject( deps, - &aq.clientCtx, + &aq.clientConn, ); err != nil { return nil, err } - aq.applicationQuerier = apptypes.NewQueryClient(aq.clientCtx) + aq.applicationQuerier = apptypes.NewQueryClient(aq.clientConn) return aq, nil } diff --git a/pkg/client/query/errors.go b/pkg/client/query/errors.go index d2ef4d7a3..04cb7fc3b 100644 --- a/pkg/client/query/errors.go +++ b/pkg/client/query/errors.go @@ -8,5 +8,5 @@ var ( codespace = "query" ErrQueryAccountNotFound = sdkerrors.Register(codespace, 1, "account not found") ErrQueryUnableToDeserialiseAccount = sdkerrors.Register(codespace, 2, "unable to deserialise account") - ErrQueryInvalidSession = sdkerrors.Register(codespace, 3, "invalid session") + ErrQueryRetrieveSession = sdkerrors.Register(codespace, 3, "error while trying to retrieve a session") ) diff --git a/pkg/client/query/sessionquerier.go b/pkg/client/query/sessionquerier.go index 15f1c42c8..6a86205fe 100644 --- a/pkg/client/query/sessionquerier.go +++ b/pkg/client/query/sessionquerier.go @@ -11,11 +11,13 @@ import ( sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) +var _ client.SessionQueryClient = (*sessionQuerier)(nil) + // sessionQuerier is a wrapper around the sessiontypes.QueryClient that enables the // querying of on-chain session information through a single exposed method // which returns an sessiontypes.Session struct type sessionQuerier struct { - clientCtx grpc.ClientConn + clientConn grpc.ClientConn sessionQuerier sessiontypes.QueryClient } @@ -29,18 +31,18 @@ func NewSessionQuerier(deps depinject.Config) (client.SessionQueryClient, error) if err := depinject.Inject( deps, - &sessq.clientCtx, + &sessq.clientConn, ); err != nil { return nil, err } - sessq.sessionQuerier = sessiontypes.NewQueryClient(sessq.clientCtx) + sessq.sessionQuerier = sessiontypes.NewQueryClient(sessq.clientConn) return sessq, nil } // GetSession returns an sessiontypes.Session struct for a given appAddress, -// serviceId and blockHeight +// serviceId and blockHeight. It implements the SessionQueryClient#GetSession function. func (sessq *sessionQuerier) GetSession( ctx context.Context, appAddress string, @@ -55,8 +57,8 @@ func (sessq *sessionQuerier) GetSession( } res, err := sessq.sessionQuerier.GetSession(ctx, req) if err != nil { - return nil, ErrQueryInvalidSession.Wrapf( - "address: %s,serviceId %s, block height %d [%v]", + return nil, ErrQueryRetrieveSession.Wrapf( + "address: %s; serviceId: %s; block height: %d; error: [%v]", appAddress, serviceId, blockHeight, err, ) } diff --git a/pkg/sdk/deps_builder.go b/pkg/sdk/deps_builder.go index 1517df465..7fbedef06 100644 --- a/pkg/sdk/deps_builder.go +++ b/pkg/sdk/deps_builder.go @@ -50,19 +50,21 @@ func (sdk *poktrollSDK) buildDeps( } depinject.Configs(deps, depinject.Supply(grpcClient)) - // Create and supply the queriers (application, account, session) + // Create and supply the account querier accountQuerier, err := query.NewAccountQuerier(deps) if err != nil { return nil, err } depinject.Configs(deps, depinject.Supply(accountQuerier)) + // Create and supply the application querier applicationQuerier, err := query.NewApplicationQuerier(deps) if err != nil { return nil, err } depinject.Configs(deps, depinject.Supply(applicationQuerier)) + // Create and supply the session querier sessionQuerier, err := query.NewSessionQuerier(deps) if err != nil { return nil, err diff --git a/pkg/sdk/errors.go b/pkg/sdk/errors.go index 04f34bf53..c7d1c4cc7 100644 --- a/pkg/sdk/errors.go +++ b/pkg/sdk/errors.go @@ -7,4 +7,5 @@ var ( ErrSDKHandleRelay = sdkerrors.Register(codespace, 1, "internal error handling relay request") ErrSDKInvalidRelayResponseSignature = sdkerrors.Register(codespace, 2, "invalid relay response signature") ErrSDKEmptyRelayResponseSignature = sdkerrors.Register(codespace, 3, "empty relay response signature") + ErrSDKVerifyResponseSignature = sdkerrors.Register(codespace, 4, "error verifying relay response signature") ) diff --git a/pkg/sdk/interface.go b/pkg/sdk/interface.go index d04c19840..a9c8b8e1f 100644 --- a/pkg/sdk/interface.go +++ b/pkg/sdk/interface.go @@ -8,12 +8,11 @@ import ( ) // POKTRollSDK is the interface for the POKTRoll SDK. It is used by gateways -// to interact with the Pocket protocol. +// and/or applications to interact with the Pocket protocol. type POKTRollSDK interface { - // GetSession returns the suppliers endpoints of the current session for // the given application and service. - GetCurrentSession( + GetSessionSupplierEndpoints( ctx context.Context, appAddress string, serviceId string, diff --git a/pkg/sdk/sdk.go b/pkg/sdk/sdk.go index 3acb0a2f3..b95620b04 100644 --- a/pkg/sdk/sdk.go +++ b/pkg/sdk/sdk.go @@ -21,7 +21,7 @@ var _ POKTRollSDK = (*poktrollSDK)(nil) // It contains the Pocket Node URL to be used by the queriers and the private key // to be used for signing relay requests. // Deps is an optional field that can be used to provide the needed dependencies -// for the SDK. If it is not provided, the SDK will build the dependencies. +// for the SDK. If it is not provided, the SDK will build the dependencies itself. type POKTRollSDKConfig struct { PocketNodeUrl *url.URL PrivateKey cryptotypes.PrivKey @@ -32,6 +32,8 @@ type POKTRollSDKConfig struct { type poktrollSDK struct { config *POKTRollSDKConfig + // signingKey is the scalar representation of the private key to be used + // for signing relay requests. signingKey ringtypes.Scalar // ringCache is used to obtain and store the ring for the application. @@ -41,10 +43,11 @@ type poktrollSDK struct { // It used to get the current session for the application given a requested service. sessionQuerier client.SessionQueryClient - // sessionMu is a mutex to protect currentSession map reads and and updates. + // sessionMu is a mutex to protect latestSessions map reads and updates. sessionMu sync.RWMutex - // latestSessions is a latest sessions map of serviceId -> appAddress -> SessionSuppliers. + // latestSessions is a latest sessions map of serviceId -> {appAddress -> SessionSuppliers} + // based on the latest block data available. latestSessions map[string]map[string]*sessionSuppliers // accountQuerier is the querier for the account module. diff --git a/pkg/sdk/send_relay.go b/pkg/sdk/send_relay.go index ce48808ef..b7610a84a 100644 --- a/pkg/sdk/send_relay.go +++ b/pkg/sdk/send_relay.go @@ -60,15 +60,17 @@ func (sdk *poktrollSDK) SendRelay( cdc := types.ModuleCdc relayRequestBz, err := cdc.Marshal(relayRequest) if err != nil { - return nil, ErrSDKHandleRelay.Wrapf("marshaling relay request: %s", err) + return nil, ErrSDKHandleRelay.Wrapf("error marshaling relay request: %s", err) } relayRequestReader := io.NopCloser(bytes.NewReader(relayRequestBz)) var relayReq types.RelayRequest if err := relayReq.Unmarshal(relayRequestBz); err != nil { - return nil, ErrSDKHandleRelay.Wrapf("unmarshaling relay response: %s", err) + return nil, ErrSDKHandleRelay.Wrapf("error unmarshaling relay request: %s", err) } // Create the HTTP request to send the request to the relayer. + // All the RPC protocols to be supported (JSONRPC, Rest, Websockets, gRPC, etc) + // use HTTP under the hood. relayHTTPRequest := &http.Request{ Method: request.Method, Header: request.Header, @@ -79,19 +81,19 @@ func (sdk *poktrollSDK) SendRelay( log.Printf("DEBUG: Sending signed relay request to %s", supplierEndpoint.Url) relayHTTPResponse, err := http.DefaultClient.Do(relayHTTPRequest) if err != nil { - return nil, ErrSDKHandleRelay.Wrapf("sending relay request: %s", err) + return nil, ErrSDKHandleRelay.Wrapf("error sending relay request: %s", err) } // Read the response body bytes. relayResponseBz, err := io.ReadAll(relayHTTPResponse.Body) if err != nil { - return nil, ErrSDKHandleRelay.Wrapf("reading relay response body: %s", err) + return nil, ErrSDKHandleRelay.Wrapf("error reading relay response body: %s", err) } // Unmarshal the response bytes into a RelayResponse. relayResponse := &types.RelayResponse{} if err := relayResponse.Unmarshal(relayResponseBz); err != nil { - return nil, ErrSDKHandleRelay.Wrapf("unmarshaling relay response: %s", err) + return nil, ErrSDKHandleRelay.Wrapf("error unmarshaling relay response: %s", err) } // Verify the response signature. We use the supplier address that we got from @@ -101,8 +103,7 @@ func (sdk *poktrollSDK) SendRelay( // TODO_IMPROVE: Add more logging & telemetry so we can get visibility and signal into // failed responses. if err := sdk.verifyResponse(ctx, supplierEndpoint.SupplierAddress, relayResponse); err != nil { - // TODO_DISCUSS: should this be its own error type and asserted against in tests? - return nil, ErrSDKHandleRelay.Wrapf("verifying relay response signature: %s", err) + return nil, ErrSDKVerifyResponseSignature.Wrapf("%s", err) } return relayResponse, nil diff --git a/pkg/sdk/session.go b/pkg/sdk/session.go index 278ef4c4b..c1aa35a12 100644 --- a/pkg/sdk/session.go +++ b/pkg/sdk/session.go @@ -28,11 +28,10 @@ type SupplierEndpoint struct { Header *sessiontypes.SessionHeader } -// GetCurrentSession gets the current session for the given service -// It returns the current state if it exists and is still valid, otherwise it -// queries for the latest session, constructs the SessionSuppliers, caches and -// returns its SupplierEndpoints. -func (sdk *poktrollSDK) GetCurrentSession( +// GetSessionSupplierEndpoints returns a flattened structure of the endpoints +// from all suppliers in the session and returns them as a SupplierEndpoint slice. +// It queries for the latest session and caches it if the cached one is outdated. +func (sdk *poktrollSDK) GetSessionSupplierEndpoints( ctx context.Context, appAddress, serviceId string, ) ([]*SupplierEndpoint, error) { @@ -51,6 +50,7 @@ func (sdk *poktrollSDK) GetCurrentSession( sdk.latestSessions[serviceId][appAddress] = &sessionSuppliers{} } + // currentSession is guaranteed to exist after the checks above. currentSession := sdk.latestSessions[serviceId][appAddress] // Return the current session's SuppliersEndpoints if the session is still valid. @@ -74,15 +74,15 @@ func (sdk *poktrollSDK) GetCurrentSession( currentSession.SuppliersEndpoints = []*SupplierEndpoint{} for _, supplier := range session.Suppliers { - for _, services := range supplier.Services { + for _, service := range supplier.Services { // Skip the session's services that don't match the requested serviceId. - if services.Service.Id != serviceId { + if service.Service.Id != serviceId { continue } // Loop through the services' endpoints and add them to the // SessionSuppliers.SuppliersEndpoints slice. - for _, endpoint := range services.Endpoints { + for _, endpoint := range service.Endpoints { url, err := url.Parse(endpoint.Url) if err != nil { log.Printf("error parsing url: %s", err) From f309253fe452e3ec37dfe7b9ea154a96ebd2403d Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 6 Dec 2023 13:52:55 +0100 Subject: [PATCH 03/34] fix: Chain depinject configs --- pkg/sdk/deps_builder.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/sdk/deps_builder.go b/pkg/sdk/deps_builder.go index 7fbedef06..f1682dd4d 100644 --- a/pkg/sdk/deps_builder.go +++ b/pkg/sdk/deps_builder.go @@ -29,14 +29,14 @@ func (sdk *poktrollSDK) buildDeps( // Create and supply the events query client eventsQueryClient := eventsquery.NewEventsQueryClient(pocketNodeWebsocketURL) - depinject.Configs(deps, depinject.Supply(eventsQueryClient)) + deps = depinject.Configs(deps, depinject.Supply(eventsQueryClient)) // Create and supply the block client that depends on the events query client blockClient, err := block.NewBlockClient(ctx, deps, pocketNodeWebsocketURL) if err != nil { return nil, err } - depinject.Configs(deps, depinject.Supply(blockClient)) + deps = depinject.Configs(deps, depinject.Supply(blockClient)) // Create and supply the grpc client used by the queriers // TODO_TECHDEBT: Configure the grpc client options from the config @@ -48,35 +48,35 @@ func (sdk *poktrollSDK) buildDeps( if err != nil { return nil, err } - depinject.Configs(deps, depinject.Supply(grpcClient)) + deps = depinject.Configs(deps, depinject.Supply(grpcClient)) // Create and supply the account querier accountQuerier, err := query.NewAccountQuerier(deps) if err != nil { return nil, err } - depinject.Configs(deps, depinject.Supply(accountQuerier)) + deps = depinject.Configs(deps, depinject.Supply(accountQuerier)) // Create and supply the application querier applicationQuerier, err := query.NewApplicationQuerier(deps) if err != nil { return nil, err } - depinject.Configs(deps, depinject.Supply(applicationQuerier)) + deps = depinject.Configs(deps, depinject.Supply(applicationQuerier)) // Create and supply the session querier sessionQuerier, err := query.NewSessionQuerier(deps) if err != nil { return nil, err } - depinject.Configs(deps, depinject.Supply(sessionQuerier)) + deps = depinject.Configs(deps, depinject.Supply(sessionQuerier)) // Create and supply the ring cache that depends on application and account queriers ringCache, err := rings.NewRingCache(deps) if err != nil { return nil, err } - depinject.Configs(deps, depinject.Supply(ringCache)) + deps = depinject.Configs(deps, depinject.Supply(ringCache)) return deps, nil } From cb999a08cb23da380a91afcc37e14d4f4d6b43a5 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 6 Dec 2023 21:23:32 +0100 Subject: [PATCH 04/34] chore: Expose the full SessionSuppliers struct --- pkg/appgateserver/endpoint_selector.go | 4 +-- pkg/appgateserver/synchronous.go | 7 ++++- pkg/sdk/interface.go | 4 +-- pkg/sdk/sdk.go | 16 +++++----- pkg/sdk/send_relay.go | 8 ++--- pkg/sdk/session.go | 42 +++++++++++++------------- 6 files changed, 42 insertions(+), 39 deletions(-) diff --git a/pkg/appgateserver/endpoint_selector.go b/pkg/appgateserver/endpoint_selector.go index db9aa3442..821b18018 100644 --- a/pkg/appgateserver/endpoint_selector.go +++ b/pkg/appgateserver/endpoint_selector.go @@ -16,8 +16,8 @@ func (app *appGateServer) getRelayerUrl( ctx context.Context, serviceId string, rpcType sharedtypes.RPCType, - supplierEndpoints []*sdk.SupplierEndpoint, -) (supplierEndpoint *sdk.SupplierEndpoint, err error) { + supplierEndpoints []*sdk.SingleSupplierEndpoint, +) (supplierEndpoint *sdk.SingleSupplierEndpoint, err error) { for _, supplierEndpoint := range supplierEndpoints { // Skip services that don't match the requested serviceId. if supplierEndpoint.Header.Service.Id != serviceId { diff --git a/pkg/appgateserver/synchronous.go b/pkg/appgateserver/synchronous.go index b079a14a8..5d0b46a5a 100644 --- a/pkg/appgateserver/synchronous.go +++ b/pkg/appgateserver/synchronous.go @@ -38,7 +38,12 @@ func (app *appGateServer) handleSynchronousRelay( } // Get a supplier URL and address for the given service and session. - supplierEndpoint, err := app.getRelayerUrl(ctx, serviceId, requestType, sessionSuppliers) + supplierEndpoint, err := app.getRelayerUrl( + ctx, + serviceId, + requestType, + sessionSuppliers.SuppliersEndpoints, + ) if err != nil { return ErrAppGateHandleRelay.Wrapf("getting supplier URL: %s", err) } diff --git a/pkg/sdk/interface.go b/pkg/sdk/interface.go index a9c8b8e1f..8fcb22586 100644 --- a/pkg/sdk/interface.go +++ b/pkg/sdk/interface.go @@ -16,12 +16,12 @@ type POKTRollSDK interface { ctx context.Context, appAddress string, serviceId string, - ) (session []*SupplierEndpoint, err error) + ) (session *SessionSuppliers, err error) // SendRelay sends a relay request to the given supplier's endpoint. SendRelay( ctx context.Context, - sessionSupplierEndpoint *SupplierEndpoint, + sessionSupplierEndpoint *SingleSupplierEndpoint, request *http.Request, ) (response *servicetypes.RelayResponse, err error) } diff --git a/pkg/sdk/sdk.go b/pkg/sdk/sdk.go index 6cf676c62..233807cec 100644 --- a/pkg/sdk/sdk.go +++ b/pkg/sdk/sdk.go @@ -45,12 +45,12 @@ type poktrollSDK struct { // It used to get the current session for the application given a requested service. sessionQuerier client.SessionQueryClient - // sessionMu is a mutex to protect latestSessions map reads and updates. - sessionMu sync.RWMutex + // serviceSessionSuppliersMu is a mutex to protect latestSessions map reads and updates. + serviceSessionSuppliersMu sync.RWMutex - // latestSessions is a latest sessions map of serviceId -> {appAddress -> SessionSuppliers} - // based on the latest block data available. - latestSessions map[string]map[string]*sessionSuppliers + // serviceSessionSuppliers is a map of serviceId -> {appAddress -> SessionSuppliers} + // for a specific session + serviceSessionSuppliers map[string]map[string]*SessionSuppliers // accountQuerier is the querier for the account module. // It is used to get the the supplier's public key to verify the relay response signature. @@ -67,9 +67,9 @@ type poktrollSDK struct { func NewPOKTRollSDK(ctx context.Context, config *POKTRollSDKConfig) (POKTRollSDK, error) { sdk := &poktrollSDK{ - config: config, - latestSessions: make(map[string]map[string]*sessionSuppliers), - supplierAccountCache: make(map[string]cryptotypes.PubKey), + config: config, + serviceSessionSuppliers: make(map[string]map[string]*SessionSuppliers), + supplierAccountCache: make(map[string]cryptotypes.PubKey), } var err error diff --git a/pkg/sdk/send_relay.go b/pkg/sdk/send_relay.go index d24d17838..f1583aba8 100644 --- a/pkg/sdk/send_relay.go +++ b/pkg/sdk/send_relay.go @@ -6,7 +6,6 @@ import ( "io" "net/http" - cryptocomet "github.com/cometbft/cometbft/crypto" "github.com/pokt-network/poktroll/pkg/signer" "github.com/pokt-network/poktroll/x/service/types" ) @@ -17,7 +16,7 @@ import ( // the relay request. func (sdk *poktrollSDK) SendRelay( ctx context.Context, - supplierEndpoint *SupplierEndpoint, + supplierEndpoint *SingleSupplierEndpoint, request *http.Request, ) (response *types.RelayResponse, err error) { payloadBz, err := io.ReadAll(request.Body) @@ -48,12 +47,11 @@ func (sdk *poktrollSDK) SendRelay( return nil, ErrSDKHandleRelay.Wrapf("getting signable bytes: %s", err) } - hash := cryptocomet.Sha256(signableBz) - signature, err := signer.Sign(hash) + requestSig, err := signer.Sign(signableBz) if err != nil { return nil, ErrSDKHandleRelay.Wrapf("signing relay: %s", err) } - relayRequest.Meta.Signature = signature + relayRequest.Meta.Signature = requestSig // Marshal the relay request to bytes and create a reader to be used as an HTTP request body. cdc := types.ModuleCdc diff --git a/pkg/sdk/session.go b/pkg/sdk/session.go index 26e6db4fe..c99ebb2e6 100644 --- a/pkg/sdk/session.go +++ b/pkg/sdk/session.go @@ -8,19 +8,19 @@ import ( sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) -// sessionSuppliers is the structure that represents a session's end block height +// SessionSuppliers is the structure that represents a session's end block height // and its matching suppliers. -type sessionSuppliers struct { +type SessionSuppliers struct { // SessionEndBlockHeight is the session's end block height that helps // determine if the session is still valid without looking into SupplierEndpoints slice. - SessionEndBlockHeight int64 - SuppliersEndpoints []*SupplierEndpoint + Session *sessiontypes.Session + SuppliersEndpoints []*SingleSupplierEndpoint } -// SupplierEndpoint is the structure that represents a supplier's endpoint +// SingleSupplierEndpoint is the structure that represents a supplier's endpoint // augmented with the session's header and the supplier's address for easy // access to the needed information when sending a relay request. -type SupplierEndpoint struct { +type SingleSupplierEndpoint struct { Url *url.URL RpcType sharedtypes.RPCType SupplierAddress string @@ -33,28 +33,28 @@ type SupplierEndpoint struct { func (sdk *poktrollSDK) GetSessionSupplierEndpoints( ctx context.Context, appAddress, serviceId string, -) ([]*SupplierEndpoint, error) { - sdk.sessionMu.RLock() - defer sdk.sessionMu.RUnlock() +) (*SessionSuppliers, error) { + sdk.serviceSessionSuppliersMu.RLock() + defer sdk.serviceSessionSuppliersMu.RUnlock() latestBlockHeight := sdk.blockClient.LatestBlock(ctx).Height() // Create the latestSessions map entry for the serviceId if it doesn't exist. - if _, ok := sdk.latestSessions[serviceId]; !ok { - sdk.latestSessions[serviceId] = map[string]*sessionSuppliers{} + if _, ok := sdk.serviceSessionSuppliers[serviceId]; !ok { + sdk.serviceSessionSuppliers[serviceId] = map[string]*SessionSuppliers{} } // Create the latestSessions[serviceId] map entry for the appAddress if it doesn't exist. - if _, ok := sdk.latestSessions[serviceId][appAddress]; !ok { - sdk.latestSessions[serviceId][appAddress] = &sessionSuppliers{} + if _, ok := sdk.serviceSessionSuppliers[serviceId][appAddress]; !ok { + sdk.serviceSessionSuppliers[serviceId][appAddress] = &SessionSuppliers{} } // currentSession is guaranteed to exist after the checks above. - currentSession := sdk.latestSessions[serviceId][appAddress] + currentSession := sdk.serviceSessionSuppliers[serviceId][appAddress] // Return the current session's SuppliersEndpoints if the session is still valid. - if latestBlockHeight < currentSession.SessionEndBlockHeight { - return currentSession.SuppliersEndpoints, nil + if latestBlockHeight < currentSession.Session.Header.SessionEndBlockHeight { + return currentSession, nil } // Query for the current session. @@ -68,9 +68,9 @@ func (sdk *poktrollSDK) GetSessionSupplierEndpoints( return nil, err } - // Override the old SessionSuppliers and constructs the new one. - currentSession.SessionEndBlockHeight = session.Header.SessionEndBlockHeight - currentSession.SuppliersEndpoints = []*SupplierEndpoint{} + // Override the old Session and SessionSuppliers and construct the new one. + currentSession.Session = session + currentSession.SuppliersEndpoints = []*SingleSupplierEndpoint{} for _, supplier := range session.Suppliers { for _, service := range supplier.Services { @@ -93,7 +93,7 @@ func (sdk *poktrollSDK) GetSessionSupplierEndpoints( currentSession.SuppliersEndpoints = append( currentSession.SuppliersEndpoints, - &SupplierEndpoint{ + &SingleSupplierEndpoint{ Url: url, RpcType: endpoint.RpcType, SupplierAddress: supplier.Address, @@ -104,5 +104,5 @@ func (sdk *poktrollSDK) GetSessionSupplierEndpoints( } } - return currentSession.SuppliersEndpoints, nil + return currentSession, nil } From 94f8f24ca8bca90d9eba5a5251dcb169c832ea0c Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 6 Dec 2023 21:34:38 +0100 Subject: [PATCH 05/34] fix: Avoid nil sessions on GetSessionSupplierEndpoints --- pkg/sdk/session.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/sdk/session.go b/pkg/sdk/session.go index c99ebb2e6..b80d4ebbc 100644 --- a/pkg/sdk/session.go +++ b/pkg/sdk/session.go @@ -53,7 +53,8 @@ func (sdk *poktrollSDK) GetSessionSupplierEndpoints( currentSession := sdk.serviceSessionSuppliers[serviceId][appAddress] // Return the current session's SuppliersEndpoints if the session is still valid. - if latestBlockHeight < currentSession.Session.Header.SessionEndBlockHeight { + if currentSession.Session != nil && + latestBlockHeight < currentSession.Session.Header.SessionEndBlockHeight { return currentSession, nil } From f3cc97e04d261b3f6b1371e1eabff52f337a191b Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 8 Dec 2023 21:20:01 +0100 Subject: [PATCH 06/34] chore: Explain SingleSupplierEndpoint struct usage --- pkg/sdk/session.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pkg/sdk/session.go b/pkg/sdk/session.go index b80d4ebbc..693076a1f 100644 --- a/pkg/sdk/session.go +++ b/pkg/sdk/session.go @@ -11,9 +11,14 @@ import ( // SessionSuppliers is the structure that represents a session's end block height // and its matching suppliers. type SessionSuppliers struct { - // SessionEndBlockHeight is the session's end block height that helps - // determine if the session is still valid without looking into SupplierEndpoints slice. - Session *sessiontypes.Session + // Session is the fully hydrated session object returned by the query. + Session *sessiontypes.Session + + // SuppliersEndpoints is a slice of the session's suppliers endpoints each + // item representing a single supplier endpoint augmented with the session + // header and the supplier's address. + // An item from this slice is what needs to be passed to the `SendRelay` + // function so it has all the information needed to send the relay request. SuppliersEndpoints []*SingleSupplierEndpoint } From 605e8ad97ae6ede2d3bcbf4eab536b55590cf52a Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 8 Dec 2023 22:05:21 +0100 Subject: [PATCH 07/34] fix: Rename client/event import as per main chainges --- pkg/sdk/deps_builder.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/sdk/deps_builder.go b/pkg/sdk/deps_builder.go index 32dc28ff3..439722ac4 100644 --- a/pkg/sdk/deps_builder.go +++ b/pkg/sdk/deps_builder.go @@ -2,7 +2,6 @@ package sdk import ( "context" - "fmt" "cosmossdk.io/depinject" grpctypes "github.com/cosmos/gogoproto/grpc" @@ -10,7 +9,7 @@ import ( "google.golang.org/grpc/credentials/insecure" block "github.com/pokt-network/poktroll/pkg/client/block" - eventsquery "github.com/pokt-network/poktroll/pkg/client/events_query" + eventsquery "github.com/pokt-network/poktroll/pkg/client/events" "github.com/pokt-network/poktroll/pkg/client/query" "github.com/pokt-network/poktroll/pkg/crypto/rings" "github.com/pokt-network/poktroll/pkg/polylog" From a117bac16d5796e979cf32f5d80e82eddb57f22f Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 8 Dec 2023 22:10:42 +0100 Subject: [PATCH 08/34] fix: Add missing fmt package --- pkg/sdk/deps_builder.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/sdk/deps_builder.go b/pkg/sdk/deps_builder.go index 439722ac4..73464d821 100644 --- a/pkg/sdk/deps_builder.go +++ b/pkg/sdk/deps_builder.go @@ -2,6 +2,7 @@ package sdk import ( "context" + "fmt" "cosmossdk.io/depinject" grpctypes "github.com/cosmos/gogoproto/grpc" From 62069d5c89ca1161ec42878fe28d7a6702b70f73 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Mon, 11 Dec 2023 15:43:52 +0100 Subject: [PATCH 09/34] feat: Enable gRPC client connection --- Tiltfile | 2 +- localnet/kubernetes/values-appgateserver.yaml | 3 +- localnet/kubernetes/values-relayminer.yaml | 6 +- .../config/appgate_server_config.yaml | 8 +- .../poktrolld/config/relayminer_config.yaml | 10 +- pkg/appgateserver/cmd/cmd.go | 45 ++++--- .../config/appgate_configs_reader.go | 47 +++++--- .../config/appgate_configs_reader_test.go | 95 ++++++++++++--- pkg/appgateserver/config/errors.go | 11 +- pkg/client/query/codec.go | 2 + pkg/client/query/supplierquerier.go | 9 +- pkg/deps/config/suppliers.go | 72 ++++++----- pkg/relayer/cmd/cmd.go | 42 ++++--- pkg/relayer/config/errors.go | 15 +-- .../config/relayminer_configs_reader.go | 52 ++++---- .../config/relayminer_configs_reader_test.go | 112 +++++++++++++----- pkg/sdk/deps_builder.go | 12 +- pkg/sdk/sdk.go | 7 +- 18 files changed, 378 insertions(+), 172 deletions(-) diff --git a/Tiltfile b/Tiltfile index b7093223a..7885180a1 100644 --- a/Tiltfile +++ b/Tiltfile @@ -152,7 +152,7 @@ k8s_resource( "sequencer", labels=["blockchains"], resource_deps=["celestia-rollkit"], - port_forwards=["36657", "40004"], + port_forwards=["36657", "40004", "36658"], ) k8s_resource( "relayminers", diff --git a/localnet/kubernetes/values-appgateserver.yaml b/localnet/kubernetes/values-appgateserver.yaml index 80357e815..d5eb44bff 100644 --- a/localnet/kubernetes/values-appgateserver.yaml +++ b/localnet/kubernetes/values-appgateserver.yaml @@ -1,2 +1,3 @@ config: - query_node_url: tcp://sequencer-poktroll-sequencer:36657 + query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 + pocket_node_websocket_url: tcp://sequencer-poktroll-sequencer:36657 \ No newline at end of file diff --git a/localnet/kubernetes/values-relayminer.yaml b/localnet/kubernetes/values-relayminer.yaml index 573d05bcb..2de5a78f0 100644 --- a/localnet/kubernetes/values-relayminer.yaml +++ b/localnet/kubernetes/values-relayminer.yaml @@ -1,4 +1,4 @@ config: - query_node_url: tcp://sequencer-poktroll-sequencer:36657 - network_node_url: tcp://sequencer-poktroll-sequencer:36657 - \ No newline at end of file + query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 + network_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 + pocket_node_websocket_url: tcp://sequencer-poktroll-sequencer:36657 \ No newline at end of file diff --git a/localnet/poktrolld/config/appgate_server_config.yaml b/localnet/poktrolld/config/appgate_server_config.yaml index 646753cae..bb760eb76 100644 --- a/localnet/poktrolld/config/appgate_server_config.yaml +++ b/localnet/poktrolld/config/appgate_server_config.yaml @@ -4,5 +4,9 @@ self_signing: true signing_key: app1 # The host and port that the appgate server will listen on listening_endpoint: http://localhost:42069 -# tcp://: to a full pocket node for reading data and listening for on-chain events -query_node_url: tcp://127.0.0.1:36657 +# tcp://: to a full pocket node for reading data +query_node_grpc_url: tcp://127.0.0.1:36658 +# grpc client insecure flag +grpc_insecure: true +# tcp://: to a full pocket node websocket endpoint for listening for on-chain events +pocket_node_websocket_url: tcp://127.0.0.1:36657 diff --git a/localnet/poktrolld/config/relayminer_config.yaml b/localnet/poktrolld/config/relayminer_config.yaml index 710f8722b..2b69a6a62 100644 --- a/localnet/poktrolld/config/relayminer_config.yaml +++ b/localnet/poktrolld/config/relayminer_config.yaml @@ -1,7 +1,11 @@ -# tcp://: to a full pocket node for reading data and listening for on-chain events -query_node_url: tcp://localhost:36657 +# tcp://: to a full pocket node for reading data +query_node_grpc_url: tcp://127.0.0.1:36658 # tcp://: to a pocket node that gossips transactions throughout the network (may or may not be the sequencer) -network_node_url: tcp://127.0.0.1:36657 +network_node_grpc_url: tcp://127.0.0.1:36658 +# grpc client insecure flag +grpc_insecure: true +# tcp://: to a full pocket node websocket endpoint for listening for on-chain events +pocket_node_websocket_url: tcp://127.0.0.1:36657 # Name of the key (in the keyring) to sign transactions signing_key_name: supplier1 # TODO_TECHDEBT(#137, #130): Once the `relayer.json` config file is implemented AND a local LLM RPC service diff --git a/pkg/appgateserver/cmd/cmd.go b/pkg/appgateserver/cmd/cmd.go index 4810bb67a..74cda0a0c 100644 --- a/pkg/appgateserver/cmd/cmd.go +++ b/pkg/appgateserver/cmd/cmd.go @@ -25,8 +25,9 @@ import ( const omittedDefaultFlagValue = "explicitly omitting default" var ( - flagAppGateConfig string - flagCosmosNodeURL string + flagAppGateConfig string + flagCosmosNodeURL string + flagCosmosNodeGRPCURL string ) // AppGateServerCmd returns the Cobra command for running the AppGate server. @@ -66,8 +67,9 @@ provided that: // Cosmos flags cmd.Flags().String(cosmosflags.FlagKeyringBackend, "", "Select keyring's backend (os|file|kwallet|pass|test)") - cmd.Flags(). - StringVar(&flagCosmosNodeURL, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialize the Cosmos query context correctly. It can be used to override the `QueryNodeUrl` field in the config file if specified.") + cmd.Flags().StringVar(&flagCosmosNodeURL, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialise the Cosmos query context correctly. It can be used to override the `QueryNodeUrl` field in the config file if specified.") + cmd.Flags().StringVar(&flagCosmosNodeGRPCURL, cosmosflags.FlagGRPC, omittedDefaultFlagValue, "Register the default Cosmos node grpc flag, which is needed to initialise the Cosmos query context with grpc correctly. It can be used to override the `QueryNodeGRPCUrl` field in the config file if specified.") + cmd.Flags().Bool(cosmosflags.FlagGRPCInsecure, true, "Used to initialise the Cosmos query context with grpc security options. It can be used to override the `QueryNodeGRPCInsecure` field in the config file if specified.") return cmd } @@ -145,11 +147,22 @@ func setupAppGateServerDependencies( cmd *cobra.Command, appGateConfig *appgateconfig.AppGateServerConfig, ) (_ depinject.Config, err error) { - queryNodeURL := appGateConfig.QueryNodeUrl - // Override the config file's `QueryNodeUrl` fields + pocketNodeWebsocketURL := appGateConfig.PocketNodeWebsocketUrl + queryNodeGRPCURL := appGateConfig.QueryNodeGRPCUrl + + // Override the config file's `QueryNodeGRPCUrl` fields + // with the `--grpc-addr` flag if it was specified. + if flagCosmosNodeGRPCURL != omittedDefaultFlagValue { + queryNodeGRPCURL, err = url.Parse(flagCosmosNodeGRPCURL) + if err != nil { + return nil, fmt.Errorf("failed to parse Cosmos node URL: %w", err) + } + } + + // Override the config file's `PocketNodeWebsocketUrl` fields // with the `--node` flag if it was specified. if flagCosmosNodeURL != omittedDefaultFlagValue { - queryNodeURL, err = url.Parse(flagCosmosNodeURL) + pocketNodeWebsocketURL, err = url.Parse(flagCosmosNodeURL) if err != nil { return nil, fmt.Errorf("failed to parse Cosmos node URL: %w", err) } @@ -157,14 +170,18 @@ func setupAppGateServerDependencies( supplierFuncs := []config.SupplierFn{ config.NewSupplyLoggerFromCtx(ctx), - config.NewSupplyEventsQueryClientFn(queryNodeURL.Host), // leaf - config.NewSupplyBlockClientFn(queryNodeURL.Host), // leaf - config.NewSupplyQueryClientContextFn(queryNodeURL.String()), // leaf - config.NewSupplyAccountQuerierFn(), // leaf - config.NewSupplyApplicationQuerierFn(), // leaf - config.NewSupplySessionQuerierFn(), // leaf + config.NewSupplyEventsQueryClientFn(pocketNodeWebsocketURL), // leaf + config.NewSupplyBlockClientFn(pocketNodeWebsocketURL), // leaf + config.NewSupplyQueryClientContextFn(queryNodeGRPCURL, appGateConfig.GRPCInsecure), // leaf + config.NewSupplyAccountQuerierFn(), // leaf + config.NewSupplyApplicationQuerierFn(), // leaf + config.NewSupplySessionQuerierFn(), // leaf config.NewSupplyRingCacheFn(), - config.NewSupplyPOKTRollSDKFn(queryNodeURL, appGateConfig.SigningKey), + config.NewSupplyPOKTRollSDKFn( + queryNodeGRPCURL, + pocketNodeWebsocketURL, + appGateConfig.SigningKey, + ), } return config.SupplyConfig(ctx, cmd, supplierFuncs) diff --git a/pkg/appgateserver/config/appgate_configs_reader.go b/pkg/appgateserver/config/appgate_configs_reader.go index da801e6fc..55d00735a 100644 --- a/pkg/appgateserver/config/appgate_configs_reader.go +++ b/pkg/appgateserver/config/appgate_configs_reader.go @@ -9,18 +9,22 @@ import ( // YAMLAppGateServerConfig is the structure used to unmarshal the AppGateServer config file // TODO_DOCUMENT(@red-0ne): Add proper README documentation for yaml config files. type YAMLAppGateServerConfig struct { - SelfSigning bool `yaml:"self_signing"` - SigningKey string `yaml:"signing_key"` - ListeningEndpoint string `yaml:"listening_endpoint"` - QueryNodeUrl string `yaml:"query_node_url"` + SelfSigning bool `yaml:"self_signing"` + SigningKey string `yaml:"signing_key"` + ListeningEndpoint string `yaml:"listening_endpoint"` + QueryNodeGRPCUrl string `yaml:"query_node_grpc_url"` + GRPCInsecure bool `yaml:"grpc_insecure"` + PocketNodeWebsocketUrl string `yaml:"pocket_node_websocket_url"` } // AppGateServerConfig is the structure describing the AppGateServer config type AppGateServerConfig struct { - SelfSigning bool - SigningKey string - ListeningEndpoint *url.URL - QueryNodeUrl *url.URL + SelfSigning bool + SigningKey string + ListeningEndpoint *url.URL + QueryNodeGRPCUrl *url.URL + GRPCInsecure bool + PocketNodeWebsocketUrl *url.URL } // ParseAppGateServerConfigs parses the stake config file into a AppGateConfig @@ -46,21 +50,32 @@ func ParseAppGateServerConfigs(configContent []byte) (*AppGateServerConfig, erro return nil, ErrAppGateConfigInvalidListeningEndpoint.Wrapf("%s", err) } - if yamlAppGateServerConfig.QueryNodeUrl == "" { - return nil, ErrAppGateConfigInvalidQueryNodeUrl + if yamlAppGateServerConfig.QueryNodeGRPCUrl == "" { + return nil, ErrAppGateConfigInvalidQueryNodeGRPCUrl } - queryNodeUrl, err := url.Parse(yamlAppGateServerConfig.QueryNodeUrl) + queryNodeGRPCUrl, err := url.Parse(yamlAppGateServerConfig.QueryNodeGRPCUrl) if err != nil { - return nil, ErrAppGateConfigInvalidQueryNodeUrl.Wrapf("%s", err) + return nil, ErrAppGateConfigInvalidQueryNodeGRPCUrl.Wrapf("%s", err) + } + + if yamlAppGateServerConfig.PocketNodeWebsocketUrl == "" { + return nil, ErrAppGateConfigInvalidPocketNodeWebsocketUrl + } + + pocketNodeWebsocketUrl, err := url.Parse(yamlAppGateServerConfig.PocketNodeWebsocketUrl) + if err != nil { + return nil, ErrAppGateConfigInvalidPocketNodeWebsocketUrl.Wrapf("%s", err) } // Populate the appGateServerConfig with the values from the yamlAppGateServerConfig appGateServerConfig := &AppGateServerConfig{ - SelfSigning: yamlAppGateServerConfig.SelfSigning, - SigningKey: yamlAppGateServerConfig.SigningKey, - ListeningEndpoint: listeningEndpoint, - QueryNodeUrl: queryNodeUrl, + SelfSigning: yamlAppGateServerConfig.SelfSigning, + SigningKey: yamlAppGateServerConfig.SigningKey, + ListeningEndpoint: listeningEndpoint, + QueryNodeGRPCUrl: queryNodeGRPCUrl, + GRPCInsecure: yamlAppGateServerConfig.GRPCInsecure, + PocketNodeWebsocketUrl: pocketNodeWebsocketUrl, } return appGateServerConfig, nil diff --git a/pkg/appgateserver/config/appgate_configs_reader_test.go b/pkg/appgateserver/config/appgate_configs_reader_test.go index aae5ffdc5..5ecfaf7a4 100644 --- a/pkg/appgateserver/config/appgate_configs_reader_test.go +++ b/pkg/appgateserver/config/appgate_configs_reader_test.go @@ -29,15 +29,19 @@ func Test_ParseAppGateConfigs(t *testing.T) { self_signing: true signing_key: app1 listening_endpoint: http://localhost:42069 - query_node_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + grpc_insecure: true + pocket_node_websocket_url: tcp://127.0.0.1:36657 `, expectedError: nil, expectedConfig: &config.AppGateServerConfig{ - SelfSigning: true, - SigningKey: "app1", - ListeningEndpoint: &url.URL{Scheme: "http", Host: "localhost:42069"}, - QueryNodeUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, + SelfSigning: true, + SigningKey: "app1", + ListeningEndpoint: &url.URL{Scheme: "http", Host: "localhost:42069"}, + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + GRPCInsecure: true, + PocketNodeWebsocketUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657", Path: "webcosket"}, }, }, { @@ -46,15 +50,40 @@ func Test_ParseAppGateConfigs(t *testing.T) { inputConfig: ` signing_key: app1 listening_endpoint: http://localhost:42069 - query_node_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + grpc_insecure: true + pocket_node_websocket_url: tcp://127.0.0.1:36657 `, expectedError: nil, expectedConfig: &config.AppGateServerConfig{ - SelfSigning: false, - SigningKey: "app1", - ListeningEndpoint: &url.URL{Scheme: "http", Host: "localhost:42069"}, - QueryNodeUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, + SelfSigning: false, + SigningKey: "app1", + ListeningEndpoint: &url.URL{Scheme: "http", Host: "localhost:42069"}, + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + GRPCInsecure: true, + PocketNodeWebsocketUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657", Path: "webcosket"}, + }, + }, + { + desc: "valid: AppGateServer config with undefined grpc insecure", + + inputConfig: ` + self_signing: true + signing_key: app1 + listening_endpoint: http://localhost:42069 + query_node_grpc_url: tcp://127.0.0.1:36658 + pocket_node_websocket_url: tcp://127.0.0.1:36657 + `, + + expectedError: nil, + expectedConfig: &config.AppGateServerConfig{ + SelfSigning: true, + SigningKey: "app1", + ListeningEndpoint: &url.URL{Scheme: "http", Host: "localhost:42069"}, + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + GRPCInsecure: false, + PocketNodeWebsocketUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657", Path: "webcosket"}, }, }, // Invalid Configs @@ -72,7 +101,9 @@ func Test_ParseAppGateConfigs(t *testing.T) { self_signing: true signing_key: listening_endpoint: http://localhost:42069 - query_node_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + grpc_insecure: true + pocket_node_websocket_url: tcp://127.0.0.1:36657 `, expectedError: config.ErrAppGateConfigEmptySigningKey, @@ -84,22 +115,53 @@ func Test_ParseAppGateConfigs(t *testing.T) { self_signing: true signing_key: app1 listening_endpoint: &localhost:42069 - query_node_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + grpc_insecure: true + pocket_node_websocket_url: tcp://127.0.0.1:36657 `, expectedError: config.ErrAppGateConfigInvalidListeningEndpoint, }, { - desc: "invalid: invalid query node url", + desc: "invalid: invalid query node grpc url", + + inputConfig: ` + self_signing: true + signing_key: app1 + listening_endpoint: http://localhost:42069 + query_node_grpc_url: &127.0.0.1:36658 + grpc_insecure: true + pocket_node_websocket_url: tcp://127.0.0.1:36657 + `, + + expectedError: config.ErrAppGateConfigInvalidQueryNodeGRPCUrl, + }, + { + desc: "invalid: invalid pocket node websocket", + + inputConfig: ` + self_signing: true + signing_key: app1 + listening_endpoint: http://localhost:42069 + query_node_grpc_url: tcp://127.0.0.1:36658 + grpc_insecure: true + pocket_node_websocket_url: &127.0.0.1:36657 + `, + + expectedError: config.ErrAppGateConfigInvalidPocketNodeWebsocketUrl, + }, + { + desc: "invalid: missing pocket node websocket url", inputConfig: ` self_signing: true signing_key: app1 listening_endpoint: http://localhost:42069 - query_node_url: &127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + grpc_insecure: true `, - expectedError: config.ErrAppGateConfigInvalidQueryNodeUrl, + expectedError: config.ErrAppGateConfigInvalidPocketNodeWebsocketUrl, }, } @@ -123,7 +185,8 @@ func Test_ParseAppGateConfigs(t *testing.T) { require.Equal(t, tt.expectedConfig.SelfSigning, config.SelfSigning) require.Equal(t, tt.expectedConfig.SigningKey, config.SigningKey) require.Equal(t, tt.expectedConfig.ListeningEndpoint.String(), config.ListeningEndpoint.String()) - require.Equal(t, tt.expectedConfig.QueryNodeUrl.String(), config.QueryNodeUrl.String()) + require.Equal(t, tt.expectedConfig.QueryNodeGRPCUrl.String(), config.QueryNodeGRPCUrl.String()) + require.Equal(t, tt.expectedConfig.QueryNodeGRPCUrl.String(), config.QueryNodeGRPCUrl.String()) }) } } diff --git a/pkg/appgateserver/config/errors.go b/pkg/appgateserver/config/errors.go index 3d4d6831f..2d43b9189 100644 --- a/pkg/appgateserver/config/errors.go +++ b/pkg/appgateserver/config/errors.go @@ -3,9 +3,10 @@ package config import sdkerrors "cosmossdk.io/errors" var ( - codespace = "appgate_config" - ErrAppGateConfigUnmarshalYAML = sdkerrors.Register(codespace, 1, "config reader cannot unmarshal yaml content") - ErrAppGateConfigEmptySigningKey = sdkerrors.Register(codespace, 2, "empty signing key in AppGateServer config") - ErrAppGateConfigInvalidListeningEndpoint = sdkerrors.Register(codespace, 3, "invalid listening endpoint in AppGateServer config") - ErrAppGateConfigInvalidQueryNodeUrl = sdkerrors.Register(codespace, 4, "invalid pocket query node url in AppGateServer config") + codespace = "appgate_config" + ErrAppGateConfigUnmarshalYAML = sdkerrors.Register(codespace, 1, "config reader cannot unmarshal yaml content") + ErrAppGateConfigEmptySigningKey = sdkerrors.Register(codespace, 2, "empty signing key in AppGateServer config") + ErrAppGateConfigInvalidListeningEndpoint = sdkerrors.Register(codespace, 3, "invalid listening endpoint in AppGateServer config") + ErrAppGateConfigInvalidQueryNodeGRPCUrl = sdkerrors.Register(codespace, 5, "invalid pocket query node grpc url in AppGateServer config") + ErrAppGateConfigInvalidPocketNodeWebsocketUrl = sdkerrors.Register(codespace, 6, "invalid pocket node websocket url in AppGateServer config") ) diff --git a/pkg/client/query/codec.go b/pkg/client/query/codec.go index fd9e83125..536df1484 100644 --- a/pkg/client/query/codec.go +++ b/pkg/client/query/codec.go @@ -3,6 +3,7 @@ package query import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" accounttypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -14,5 +15,6 @@ var queryCodec *codec.ProtoCodec func init() { reg := codectypes.NewInterfaceRegistry() accounttypes.RegisterInterfaces(reg) + cryptocodec.RegisterInterfaces(reg) queryCodec = codec.NewProtoCodec(reg) } diff --git a/pkg/client/query/supplierquerier.go b/pkg/client/query/supplierquerier.go index 4f8647838..4c4a91b2f 100644 --- a/pkg/client/query/supplierquerier.go +++ b/pkg/client/query/supplierquerier.go @@ -4,10 +4,9 @@ import ( "context" "cosmossdk.io/depinject" - cosmosclient "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/gogoproto/grpc" "github.com/pokt-network/poktroll/pkg/client" - "github.com/pokt-network/poktroll/pkg/client/query/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" ) @@ -16,7 +15,7 @@ import ( // querying of on-chain supplier information through a single exposed method // which returns an sharedtypes.Supplier struct type supplierQuerier struct { - clientCtx types.Context + clientConn grpc.ClientConn supplierQuerier suppliertypes.QueryClient } @@ -30,12 +29,12 @@ func NewSupplierQuerier(deps depinject.Config) (client.SupplierQueryClient, erro if err := depinject.Inject( deps, - &supq.clientCtx, + &supq.clientConn, ); err != nil { return nil, err } - supq.supplierQuerier = suppliertypes.NewQueryClient(cosmosclient.Context(supq.clientCtx)) + supq.supplierQuerier = suppliertypes.NewQueryClient(supq.clientConn) return supq, nil } diff --git a/pkg/deps/config/suppliers.go b/pkg/deps/config/suppliers.go index 48283f849..01eedf445 100644 --- a/pkg/deps/config/suppliers.go +++ b/pkg/deps/config/suppliers.go @@ -2,7 +2,6 @@ package config import ( "context" - "fmt" "net/url" "cosmossdk.io/depinject" @@ -57,15 +56,15 @@ func NewSupplyLoggerFromCtx(ctx context.Context) SupplierFn { // EventsQueryClient instance, with the given hostname converted into a websocket // URL to subscribe to, and returns a new depinject.Config which is supplied // with the given deps and the new EventsQueryClient. -func NewSupplyEventsQueryClientFn(queryHost string) SupplierFn { +func NewSupplyEventsQueryClientFn(pocketNodeWebsocketURL *url.URL) SupplierFn { return func( _ context.Context, deps depinject.Config, _ *cobra.Command, ) (depinject.Config, error) { // Convert the host to a websocket URL - pocketNodeWebsocketURL := hostToWebsocketURL(queryHost) - eventsQueryClient := events.NewEventsQueryClient(pocketNodeWebsocketURL) + nodeWebsocketURL := sdk.HostToWebsocketURL(pocketNodeWebsocketURL.Host) + eventsQueryClient := events.NewEventsQueryClient(nodeWebsocketURL) return depinject.Configs(deps, depinject.Supply(eventsQueryClient)), nil } @@ -75,15 +74,15 @@ func NewSupplyEventsQueryClientFn(queryHost string) SupplierFn { // instance with the given hostname, which is converted into a websocket URL, // to listen for block events on-chain, and returns a new depinject.Config which // is supplied with the given deps and the new BlockClient. -func NewSupplyBlockClientFn(queryHost string) SupplierFn { +func NewSupplyBlockClientFn(pocketNodeWebsocketURL *url.URL) SupplierFn { return func( ctx context.Context, deps depinject.Config, _ *cobra.Command, ) (depinject.Config, error) { // Convert the host to a websocket URL - pocketNodeWebsocketURL := hostToWebsocketURL(queryHost) - blockClient, err := block.NewBlockClient(ctx, deps, pocketNodeWebsocketURL) + nodeWebsocketURL := sdk.HostToWebsocketURL(pocketNodeWebsocketURL.Host) + blockClient, err := block.NewBlockClient(ctx, deps, nodeWebsocketURL) if err != nil { return nil, err } @@ -95,17 +94,29 @@ func NewSupplyBlockClientFn(queryHost string) SupplierFn { // NewSupplyQueryClientContextFn returns a function with constructs a ClientContext // instance with the given cmd and returns a new depinject.Config which is // supplied with the given deps and the new ClientContext. -func NewSupplyQueryClientContextFn(pocketQueryNodeURL string) SupplierFn { +func NewSupplyQueryClientContextFn( + pocketQueryNodeGRPCURL *url.URL, + pocketQueryNodeGRPCInsecure bool, +) SupplierFn { return func(_ context.Context, deps depinject.Config, cmd *cobra.Command, ) (depinject.Config, error) { // Temporarily store the flag's current value - tmp := cosmosflags.FlagNode + tmp := cosmosflags.FlagGRPC - // Set --node flag to the pocketQueryNodeURL for the client context + // Set --grpc-addr flag to the pocketQueryNodeURL for the client context // This flag is read by cosmosclient.GetClientQueryContext. - if err := cmd.Flags().Set(cosmosflags.FlagNode, pocketQueryNodeURL); err != nil { + if err := cmd.Flags().Set(cosmosflags.FlagGRPC, pocketQueryNodeGRPCURL.Host); err != nil { + return nil, err + } + + grpcInscureFlagValue := "false" + if pocketQueryNodeGRPCInsecure { + grpcInscureFlagValue = "true" + } + + if err := cmd.Flags().Set(cosmosflags.FlagGRPCInsecure, grpcInscureFlagValue); err != nil { return nil, err } @@ -127,7 +138,7 @@ func NewSupplyQueryClientContextFn(pocketQueryNodeURL string) SupplierFn { // Restore the flag's original value in order for other components // to use the flag as expected. - if err := cmd.Flags().Set(cosmosflags.FlagNode, tmp); err != nil { + if err := cmd.Flags().Set(cosmosflags.FlagGRPC, tmp); err != nil { return nil, err } @@ -138,17 +149,28 @@ func NewSupplyQueryClientContextFn(pocketQueryNodeURL string) SupplierFn { // NewSupplyTxClientContextFn returns a function with constructs a ClientContext // instance with the given cmd and returns a new depinject.Config which is // supplied with the given deps and the new ClientContext. -func NewSupplyTxClientContextFn(pocketTxNodeURL string) SupplierFn { +func NewSupplyTxClientContextFn( + pocketTxNodeGRPCURL *url.URL, + pocketTxNodeGRPCInsecure bool, +) SupplierFn { return func(_ context.Context, deps depinject.Config, cmd *cobra.Command, ) (depinject.Config, error) { // Temporarily store the flag's current value - tmp := cosmosflags.FlagNode + tmp := cosmosflags.FlagGRPC // Set --node flag to the pocketTxNodeURL for the client context // This flag is read by cosmosclient.GetClientTxContext. - if err := cmd.Flags().Set(cosmosflags.FlagNode, pocketTxNodeURL); err != nil { + if err := cmd.Flags().Set(cosmosflags.FlagGRPC, pocketTxNodeGRPCURL.Host); err != nil { + return nil, err + } + + grpcInscureFlagValue := "false" + if pocketTxNodeGRPCInsecure { + grpcInscureFlagValue = "true" + } + if err := cmd.Flags().Set(cosmosflags.FlagGRPCInsecure, grpcInscureFlagValue); err != nil { return nil, err } @@ -168,7 +190,7 @@ func NewSupplyTxClientContextFn(pocketTxNodeURL string) SupplierFn { // Restore the flag's original value in order for other components // to use the flag as expected. - if err := cmd.Flags().Set(cosmosflags.FlagNode, tmp); err != nil { + if err := cmd.Flags().Set(cosmosflags.FlagGRPC, tmp); err != nil { return nil, err } @@ -282,7 +304,8 @@ func NewSupplyRingCacheFn() SupplierFn { // POKTRollSDK instance with the required dependencies and returns a new // depinject.Config which is supplied with the given deps and the new POKTRollSDK. func NewSupplyPOKTRollSDKFn( - queryNodeURL *url.URL, + queryNodeGRPCURL *url.URL, + queryNodeWebsocketURL *url.URL, signingKeyName string, ) SupplierFn { return func( @@ -309,9 +332,10 @@ func NewSupplyPOKTRollSDKFn( } config := &sdk.POKTRollSDKConfig{ - PrivateKey: privateKey, - PocketNodeUrl: queryNodeURL, - Deps: deps, + PrivateKey: privateKey, + PocketNodeGRPCUrl: queryNodeGRPCURL, + PocketNodeWebsocketUrl: queryNodeWebsocketURL, + Deps: deps, } poktrollSDK, err := sdk.NewPOKTRollSDK(ctx, config) @@ -323,11 +347,3 @@ func NewSupplyPOKTRollSDKFn( return depinject.Configs(deps, depinject.Supply(poktrollSDK)), nil } } - -// hostToWebsocketURL converts the provided host into a websocket URL that can -// be used to subscribe to onchain events and query the chain via a client -// context or send transactions via a tx client context. -func hostToWebsocketURL(host string) string { - websocketURL := fmt.Sprintf("ws://%s/websocket", host) - return websocketURL -} diff --git a/pkg/relayer/cmd/cmd.go b/pkg/relayer/cmd/cmd.go index 1812bc5d7..8c469964a 100644 --- a/pkg/relayer/cmd/cmd.go +++ b/pkg/relayer/cmd/cmd.go @@ -34,8 +34,9 @@ const omittedDefaultFlagValue = "explicitly omitting default" // TODO_CONSIDERATION: Consider moving all flags defined in `/pkg` to a `flags.go` file. var ( - flagRelayMinerConfig string - flagCosmosNodeURL string + flagRelayMinerConfig string + flagCosmosNodeURL string + flagCosmosNodeGRPCURL string ) // RelayerCmd returns the Cobra command for running the relay miner. @@ -64,8 +65,9 @@ for such operations.`, // Cosmos flags cmd.Flags().String(cosmosflags.FlagKeyringBackend, "", "Select keyring's backend (os|file|kwallet|pass|test)") - cmd.Flags(). - StringVar(&flagCosmosNodeURL, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialize the Cosmos query and tx contexts correctly. It can be used to override the `QueryNodeUrl` and `NetworkNodeUrl` fields in the config file if specified.") + cmd.Flags().StringVar(&flagCosmosNodeURL, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialise the Cosmos query and tx contexts correctly. It can be used to override the `QueryNodeUrl` and `NetworkNodeUrl` fields in the config file if specified.") + cmd.Flags().StringVar(&flagCosmosNodeGRPCURL, cosmosflags.FlagGRPC, omittedDefaultFlagValue, "Register the default Cosmos node grpc flag, which is needed to initialise the Cosmos query context with grpc correctly. It can be used to override the `QueryNodeGRPCUrl` field in the config file if specified.") + cmd.Flags().Bool(cosmosflags.FlagGRPCInsecure, true, "Used to initialise the Cosmos query context with grpc security options. It can be used to override the `QueryNodeGRPCInsecure` field in the config file if specified.") return cmd } @@ -133,29 +135,41 @@ func setupRelayerDependencies( cmd *cobra.Command, relayMinerConfig *relayerconfig.RelayMinerConfig, ) (deps depinject.Config, err error) { - queryNodeURL := relayMinerConfig.QueryNodeUrl - networkNodeURL := relayMinerConfig.NetworkNodeUrl - // Override the config file's `QueryNodeUrl` and `NetworkNodeUrl` fields + pocketNodeWebsocketUrl := relayMinerConfig.PocketNodeWebsocketUrl + queryNodeGRPCURL := relayMinerConfig.QueryNodeGRPCUrl + networkNodeGRPCURL := relayMinerConfig.NetworkNodeGRPCUrl + + // Override the config file's `QueryNodeGRPCUrl` and `NetworkNodeGRPCUrl` fields + // with the `--grpc-addr` flag if it was specified. + if flagCosmosNodeGRPCURL != omittedDefaultFlagValue { + cosmosParsedGRPCURL, err := url.Parse(flagCosmosNodeGRPCURL) + if err != nil { + return nil, fmt.Errorf("failed to parse Cosmos node URL: %w", err) + } + queryNodeGRPCURL = cosmosParsedGRPCURL + networkNodeGRPCURL = cosmosParsedGRPCURL + } + + // Override the config file's `QueryNodeUrl` fields // with the `--node` flag if it was specified. if flagCosmosNodeURL != omittedDefaultFlagValue { - cosmosParsedURL, err := url.Parse(flagCosmosNodeURL) + pocketNodeWebsocketUrl, err = url.Parse(flagCosmosNodeURL) if err != nil { return nil, fmt.Errorf("failed to parse Cosmos node URL: %w", err) } - queryNodeURL = cosmosParsedURL - networkNodeURL = cosmosParsedURL } + signingKeyName := relayMinerConfig.SigningKeyName proxiedServiceEndpoints := relayMinerConfig.ProxiedServiceEndpoints smtStorePath := relayMinerConfig.SmtStorePath supplierFuncs := []config.SupplierFn{ config.NewSupplyLoggerFromCtx(ctx), - config.NewSupplyEventsQueryClientFn(queryNodeURL.Host), // leaf - config.NewSupplyBlockClientFn(queryNodeURL.Host), // leaf - config.NewSupplyQueryClientContextFn(queryNodeURL.String()), // leaf + config.NewSupplyEventsQueryClientFn(pocketNodeWebsocketUrl), // leaf + config.NewSupplyBlockClientFn(pocketNodeWebsocketUrl), // leaf + config.NewSupplyQueryClientContextFn(queryNodeGRPCURL, relayMinerConfig.GRPCInsecure), // leaf supplyMiner, // leaf - config.NewSupplyTxClientContextFn(networkNodeURL.String()), // leaf + config.NewSupplyTxClientContextFn(networkNodeGRPCURL, relayMinerConfig.GRPCInsecure), // leaf config.NewSupplyAccountQuerierFn(), config.NewSupplyApplicationQuerierFn(), config.NewSupplySupplierQuerierFn(), diff --git a/pkg/relayer/config/errors.go b/pkg/relayer/config/errors.go index cabd22e76..2738eef1a 100644 --- a/pkg/relayer/config/errors.go +++ b/pkg/relayer/config/errors.go @@ -3,11 +3,12 @@ package config import sdkerrors "cosmossdk.io/errors" var ( - codespace = "relayminer_config" - ErrRelayMinerConfigUnmarshalYAML = sdkerrors.Register(codespace, 1, "config reader cannot unmarshal yaml content") - ErrRelayMinerConfigInvalidQueryNodeUrl = sdkerrors.Register(codespace, 2, "invalid query node url in RelayMiner config") - ErrRelayMinerConfigInvalidNetworkNodeUrl = sdkerrors.Register(codespace, 3, "invalid network node url in RelayMiner config") - ErrRelayMinerConfigInvalidServiceEndpoint = sdkerrors.Register(codespace, 4, "invalid service endpoint in RelayMiner config") - ErrRelayMinerConfigInvalidSigningKeyName = sdkerrors.Register(codespace, 5, "invalid signing key name in RelayMiner config") - ErrRelayMinerConfigInvalidSmtStorePath = sdkerrors.Register(codespace, 6, "invalid smt store path in RelayMiner config") + codespace = "relayminer_config" + ErrRelayMinerConfigUnmarshalYAML = sdkerrors.Register(codespace, 1, "config reader cannot unmarshal yaml content") + ErrRelayMinerConfigInvalidQueryNodeGRPCUrl = sdkerrors.Register(codespace, 2, "invalid query node grpc url in RelayMiner config") + ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl = sdkerrors.Register(codespace, 3, "invalid network node grpc url in RelayMiner config") + ErrRelayMinerConfigInvalidPocketNodeWebsocketUrl = sdkerrors.Register(codespace, 4, "invalid pocket node websocket url in RelayMiner config") + ErrRelayMinerConfigInvalidServiceEndpoint = sdkerrors.Register(codespace, 5, "invalid service endpoint in RelayMiner config") + ErrRelayMinerConfigInvalidSigningKeyName = sdkerrors.Register(codespace, 6, "invalid signing key name in RelayMiner config") + ErrRelayMinerConfigInvalidSmtStorePath = sdkerrors.Register(codespace, 7, "invalid smt store path in RelayMiner config") ) diff --git a/pkg/relayer/config/relayminer_configs_reader.go b/pkg/relayer/config/relayminer_configs_reader.go index 489b1497f..3f95ac23a 100644 --- a/pkg/relayer/config/relayminer_configs_reader.go +++ b/pkg/relayer/config/relayminer_configs_reader.go @@ -1,7 +1,6 @@ package config import ( - "fmt" "net/url" "gopkg.in/yaml.v2" @@ -10,8 +9,9 @@ import ( // YAMLRelayMinerConfig is the structure used to unmarshal the RelayMiner config file // TODO_DOCUMENT(@red-0ne): Add proper README documentation for yaml config files. type YAMLRelayMinerConfig struct { - QueryNodeUrl string `yaml:"query_node_url"` - NetworkNodeUrl string `yaml:"network_node_url"` + QueryNodeGRPCUrl string `yaml:"query_node_grpc_url"` + NetworkNodeGRPCUrl string `yaml:"network_node_grpc_url"` + GRPCInsecure bool `yaml:"grpc_insecure"` PocketNodeWebsocketUrl string `yaml:"pocket_node_websocket_url"` SigningKeyName string `yaml:"signing_key_name"` ProxiedServiceEndpoints map[string]string `yaml:"proxied_service_endpoints"` @@ -20,9 +20,10 @@ type YAMLRelayMinerConfig struct { // RelayMinerConfig is the structure describing the RelayMiner config type RelayMinerConfig struct { - QueryNodeUrl *url.URL - NetworkNodeUrl *url.URL - PocketNodeWebsocketUrl string + QueryNodeGRPCUrl *url.URL + NetworkNodeGRPCUrl *url.URL + GRPCInsecure bool + PocketNodeWebsocketUrl *url.URL SigningKeyName string ProxiedServiceEndpoints map[string]*url.URL SmtStorePath string @@ -37,30 +38,38 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { return nil, ErrRelayMinerConfigUnmarshalYAML.Wrapf("%s", err) } - // Check that the query node URL is provided - if yamlRelayMinerConfig.QueryNodeUrl == "" { - return nil, ErrRelayMinerConfigInvalidQueryNodeUrl.Wrapf("query node url is required") + // Check that the query node GRPC URL is provided + if yamlRelayMinerConfig.QueryNodeGRPCUrl == "" { + return nil, ErrRelayMinerConfigInvalidQueryNodeGRPCUrl.Wrapf("query node url is required") } - // Parse the query node URL - queryNodeUrl, err := url.Parse(yamlRelayMinerConfig.QueryNodeUrl) + // Parse the query node GRPC URL + queryNodeGRPCUrl, err := url.Parse(yamlRelayMinerConfig.QueryNodeGRPCUrl) if err != nil { - return nil, ErrRelayMinerConfigInvalidQueryNodeUrl.Wrapf("%s", err) + return nil, ErrRelayMinerConfigInvalidQueryNodeGRPCUrl.Wrapf("%s", err) } - // Check that the network node URL is provided - if yamlRelayMinerConfig.NetworkNodeUrl == "" { - return nil, ErrRelayMinerConfigInvalidNetworkNodeUrl.Wrapf("network node url is required") + // Check that the network node GRPC URL is provided + if yamlRelayMinerConfig.NetworkNodeGRPCUrl == "" { + return nil, ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl.Wrapf("network node url is required") } - // Parse the network node URL - networkNodeUrl, err := url.Parse(yamlRelayMinerConfig.NetworkNodeUrl) + // Parse the network node GRPC URL + networkNodeGRPCUrl, err := url.Parse(yamlRelayMinerConfig.NetworkNodeGRPCUrl) if err != nil { - return nil, ErrRelayMinerConfigInvalidNetworkNodeUrl.Wrapf("%s", err) + return nil, ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl.Wrapf("%s", err) + } + + // Check that the network node websocket URL is provided + if yamlRelayMinerConfig.PocketNodeWebsocketUrl == "" { + return nil, ErrRelayMinerConfigInvalidPocketNodeWebsocketUrl.Wrapf("pocket node websocket url is required") } // Parse the websocket URL of the Pocket Node to connect to for subscribing to on-chain events. - pocketNodeWebsocketUrl := fmt.Sprintf("ws://%s/websocket", queryNodeUrl.Host) + pocketNodeWebsocketUrl, err := url.Parse(yamlRelayMinerConfig.PocketNodeWebsocketUrl) + if err != nil { + return nil, ErrRelayMinerConfigInvalidPocketNodeWebsocketUrl.Wrapf("%s", err) + } if yamlRelayMinerConfig.SigningKeyName == "" { return nil, ErrRelayMinerConfigInvalidSigningKeyName @@ -89,8 +98,9 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { } relayMinerCMDConfig := &RelayMinerConfig{ - QueryNodeUrl: queryNodeUrl, - NetworkNodeUrl: networkNodeUrl, + QueryNodeGRPCUrl: queryNodeGRPCUrl, + NetworkNodeGRPCUrl: networkNodeGRPCUrl, + GRPCInsecure: yamlRelayMinerConfig.GRPCInsecure, PocketNodeWebsocketUrl: pocketNodeWebsocketUrl, SigningKeyName: yamlRelayMinerConfig.SigningKeyName, ProxiedServiceEndpoints: proxiedServiceEndpoints, diff --git a/pkg/relayer/config/relayminer_configs_reader_test.go b/pkg/relayer/config/relayminer_configs_reader_test.go index 20bc32de7..4fcce0b74 100644 --- a/pkg/relayer/config/relayminer_configs_reader_test.go +++ b/pkg/relayer/config/relayminer_configs_reader_test.go @@ -26,8 +26,10 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "valid: relay miner config", inputConfig: ` - query_node_url: tcp://localhost:26657 - network_node_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:26658 + network_node_grpc_url: tcp://127.0.0.1:36658 + grpc_insecure: true + pocket_node_websocket_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: http://anvil:8080 @@ -37,9 +39,39 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { expectedError: nil, expectedConfig: &config.RelayMinerConfig{ - QueryNodeUrl: &url.URL{Scheme: "tcp", Host: "localhost:26657"}, - NetworkNodeUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, - SigningKeyName: "servicer1", + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:26658"}, + NetworkNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + GRPCInsecure: true, + PocketNodeWebsocketUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, + SigningKeyName: "servicer1", + ProxiedServiceEndpoints: map[string]*url.URL{ + "anvil": {Scheme: "http", Host: "anvil:8080"}, + "svc1": {Scheme: "http", Host: "svc1:8080"}, + }, + SmtStorePath: "smt_stores", + }, + }, + { + desc: "valid: relay miner config with undefined grpc insecure", + + inputConfig: ` + query_node_grpc_url: tcp://127.0.0.1:26658 + network_node_grpc_url: tcp://127.0.0.1:36658 + pocket_node_websocket_url: tcp://127.0.0.1:36657 + signing_key_name: servicer1 + proxied_service_endpoints: + anvil: http://anvil:8080 + svc1: http://svc1:8080 + smt_store_path: smt_stores + `, + + expectedError: nil, + expectedConfig: &config.RelayMinerConfig{ + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:26658"}, + NetworkNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + GRPCInsecure: false, + PocketNodeWebsocketUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, + SigningKeyName: "servicer1", ProxiedServiceEndpoints: map[string]*url.URL{ "anvil": {Scheme: "http", Host: "anvil:8080"}, "svc1": {Scheme: "http", Host: "svc1:8080"}, @@ -52,8 +84,10 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: invalid network node url", inputConfig: ` - query_node_url: tcp://localhost:26657 - network_node_url: &tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:26658 + network_node_grpc_url: &tcp://127.0.0.1:36658 + grpc_insecure: true + pocket_node_websocket_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: http://anvil:8080 @@ -61,13 +95,15 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeUrl, + expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, }, { desc: "invalid: missing network node url", inputConfig: ` - query_node_url: tcp://localhost:26657 + query_node_grpc_url: tcp://127.0.0.1:26658 + grpc_insecure: true + pocket_node_websocket_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: http://anvil:8080 @@ -75,14 +111,16 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeUrl, + expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, }, { desc: "invalid: invalid query node url", inputConfig: ` - query_node_url: &tcp://localhost:26657 - network_node_url: tcp://127.0.0.1:36657 + query_node_grpc_url: &tcp://127.0.0.1:26658 + network_node_grpc_url: tcp://127.0.0.1:36658 + grpc_insecure: true + pocket_node_websocket_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: http://anvil:8080 @@ -90,13 +128,15 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeUrl, + expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, }, { desc: "invalid: missing query node url", inputConfig: ` - network_node_url: tcp://127.0.0.1:36657 + network_node_grpc_url: tcp://128.0.0.1:36658 + grpc_insecure: true + pocket_node_websocket_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: http://anvil:8080 @@ -104,14 +144,16 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeUrl, + expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, }, { desc: "invalid: missing signing key name", inputConfig: ` - query_node_url: tcp://localhost:26657 - network_node_url: &tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:26658 + network_node_grpc_url: &tcp://127.0.0.1:36658 + grpc_insecure: true + pocket_node_websocket_url: tcp://127.0.0.1:36657 signing_key_name: proxied_service_endpoints: anvil: http://anvil:8080 @@ -119,41 +161,47 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeUrl, + expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, }, { desc: "invalid: missing smt store path", inputConfig: ` - query_node_url: tcp://localhost:26657 - network_node_url: &tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:26658 + network_node_grpc_url: &tcp://127.0.0.1:36658 + grpc_insecure + pocket_node_websocket_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: http://anvil:8080 svc1: http://svc1:8080 `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeUrl, + expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, }, { desc: "invalid: empty proxied service endpoints", inputConfig: ` - query_node_url: tcp://localhost:26657 - network_node_url: &tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:26658 + network_node_grpc_url: &tcp://127.0.0.1:36658 + grpc_insecure: true + pocket_node_websocket_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeUrl, + expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, }, { desc: "invalid: invalid proxied service endpoint", inputConfig: ` - query_node_url: tcp://localhost:26657 - network_node_url: &tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:26658 + network_node_grpc_url: &tcp://127.0.0.1:36658 + grpc_insecure: true + pocket_node_websocket_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: &http://anvil:8080 @@ -161,14 +209,16 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeUrl, + expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, }, { desc: "invalid: invalid network node url", inputConfig: ` - query_node_url: tcp://localhost:26657 - network_node_url: &tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:26658 + network_node_grpc_url: &tcp://127.0.0.1:36658 + grpc_insecure: true + pocket_node_websocket_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 smt_store_path: smt_stores `, @@ -201,8 +251,8 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { require.NoError(t, err) - require.Equal(t, tt.expectedConfig.QueryNodeUrl.String(), config.QueryNodeUrl.String()) - require.Equal(t, tt.expectedConfig.NetworkNodeUrl.String(), config.NetworkNodeUrl.String()) + require.Equal(t, tt.expectedConfig.QueryNodeGRPCUrl.String(), config.QueryNodeGRPCUrl.String()) + require.Equal(t, tt.expectedConfig.NetworkNodeGRPCUrl.String(), config.NetworkNodeGRPCUrl.String()) require.Equal(t, tt.expectedConfig.SigningKeyName, config.SigningKeyName) require.Equal(t, tt.expectedConfig.SmtStorePath, config.SmtStorePath) require.Equal(t, len(tt.expectedConfig.ProxiedServiceEndpoints), len(config.ProxiedServiceEndpoints)) diff --git a/pkg/sdk/deps_builder.go b/pkg/sdk/deps_builder.go index 73464d821..3ce1edb0e 100644 --- a/pkg/sdk/deps_builder.go +++ b/pkg/sdk/deps_builder.go @@ -23,7 +23,7 @@ func (sdk *poktrollSDK) buildDeps( ctx context.Context, config *POKTRollSDKConfig, ) (depinject.Config, error) { - pocketNodeWebsocketURL := fmt.Sprintf("ws://%s/websocket", config.PocketNodeUrl.Host) + pocketNodeWebsocketURL := HostToWebsocketURL(config.PocketNodeWebsocketUrl.Host) // Have a new depinject config deps := depinject.Configs() @@ -46,7 +46,7 @@ func (sdk *poktrollSDK) buildDeps( // TODO_TECHDEBT: Configure the grpc client options from the config var grpcClient grpctypes.ClientConn grpcClient, err = grpc.Dial( - config.PocketNodeUrl.Host, + config.PocketNodeGRPCUrl.Host, grpc.WithTransportCredentials(insecure.NewCredentials()), ) if err != nil { @@ -84,3 +84,11 @@ func (sdk *poktrollSDK) buildDeps( return deps, nil } + +// hostToWebsocketURL converts the provided host into a websocket URL that can +// be used to subscribe to onchain events and query the chain via a client +// context or send transactions via a tx client context. +func HostToWebsocketURL(host string) string { + websocketURL := fmt.Sprintf("ws://%s/websocket", host) + return websocketURL +} diff --git a/pkg/sdk/sdk.go b/pkg/sdk/sdk.go index 233807cec..72c6f4e7e 100644 --- a/pkg/sdk/sdk.go +++ b/pkg/sdk/sdk.go @@ -24,9 +24,10 @@ var _ POKTRollSDK = (*poktrollSDK)(nil) // Deps is an optional field that can be used to provide the needed dependencies // for the SDK. If it is not provided, the SDK will build the dependencies itself. type POKTRollSDKConfig struct { - PocketNodeUrl *url.URL - PrivateKey cryptotypes.PrivKey - Deps depinject.Config + PocketNodeGRPCUrl *url.URL + PocketNodeWebsocketUrl *url.URL + PrivateKey cryptotypes.PrivKey + Deps depinject.Config } // poktrollSDK is the implementation of the POKTRollSDK. From c0c73c912320be999fa9d2a3edb82ed49b6bc571 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Tue, 12 Dec 2023 16:27:29 +0100 Subject: [PATCH 10/34] feat: Have distinct JSON-RPC and gRPC urls --- Tiltfile | 2 +- pkg/client/query/codec.go | 2 ++ pkg/client/query/supplierquerier.go | 9 ++++----- pkg/deps/config/suppliers.go | 5 ++--- pkg/sdk/deps_builder.go | 12 ++++++++++-- pkg/sdk/sdk.go | 7 ++++--- 6 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Tiltfile b/Tiltfile index b7093223a..e7444a901 100644 --- a/Tiltfile +++ b/Tiltfile @@ -152,7 +152,7 @@ k8s_resource( "sequencer", labels=["blockchains"], resource_deps=["celestia-rollkit"], - port_forwards=["36657", "40004"], + port_forwards=["36657", "36658", "40004"], ) k8s_resource( "relayminers", diff --git a/pkg/client/query/codec.go b/pkg/client/query/codec.go index fd9e83125..536df1484 100644 --- a/pkg/client/query/codec.go +++ b/pkg/client/query/codec.go @@ -3,6 +3,7 @@ package query import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" accounttypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -14,5 +15,6 @@ var queryCodec *codec.ProtoCodec func init() { reg := codectypes.NewInterfaceRegistry() accounttypes.RegisterInterfaces(reg) + cryptocodec.RegisterInterfaces(reg) queryCodec = codec.NewProtoCodec(reg) } diff --git a/pkg/client/query/supplierquerier.go b/pkg/client/query/supplierquerier.go index 4f8647838..543174e26 100644 --- a/pkg/client/query/supplierquerier.go +++ b/pkg/client/query/supplierquerier.go @@ -4,10 +4,9 @@ import ( "context" "cosmossdk.io/depinject" - cosmosclient "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/gogoproto/grpc" "github.com/pokt-network/poktroll/pkg/client" - "github.com/pokt-network/poktroll/pkg/client/query/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" ) @@ -16,7 +15,7 @@ import ( // querying of on-chain supplier information through a single exposed method // which returns an sharedtypes.Supplier struct type supplierQuerier struct { - clientCtx types.Context + clientConn grpc.ClientConn supplierQuerier suppliertypes.QueryClient } @@ -30,12 +29,12 @@ func NewSupplierQuerier(deps depinject.Config) (client.SupplierQueryClient, erro if err := depinject.Inject( deps, - &supq.clientCtx, + &supq.clientConn, ); err != nil { return nil, err } - supq.supplierQuerier = suppliertypes.NewQueryClient(cosmosclient.Context(supq.clientCtx)) + supq.supplierQuerier = suppliertypes.NewQueryClient(supq.clientConn) return supq, nil } diff --git a/pkg/deps/config/suppliers.go b/pkg/deps/config/suppliers.go index 48283f849..dd6897b22 100644 --- a/pkg/deps/config/suppliers.go +++ b/pkg/deps/config/suppliers.go @@ -309,9 +309,8 @@ func NewSupplyPOKTRollSDKFn( } config := &sdk.POKTRollSDKConfig{ - PrivateKey: privateKey, - PocketNodeUrl: queryNodeURL, - Deps: deps, + PrivateKey: privateKey, + Deps: deps, } poktrollSDK, err := sdk.NewPOKTRollSDK(ctx, config) diff --git a/pkg/sdk/deps_builder.go b/pkg/sdk/deps_builder.go index 73464d821..cd07cab55 100644 --- a/pkg/sdk/deps_builder.go +++ b/pkg/sdk/deps_builder.go @@ -3,6 +3,7 @@ package sdk import ( "context" "fmt" + "net/url" "cosmossdk.io/depinject" grpctypes "github.com/cosmos/gogoproto/grpc" @@ -23,7 +24,7 @@ func (sdk *poktrollSDK) buildDeps( ctx context.Context, config *POKTRollSDKConfig, ) (depinject.Config, error) { - pocketNodeWebsocketURL := fmt.Sprintf("ws://%s/websocket", config.PocketNodeUrl.Host) + pocketNodeWebsocketURL := queryNodeToWebsocketURL(config.QueryNodeUrl) // Have a new depinject config deps := depinject.Configs() @@ -46,7 +47,7 @@ func (sdk *poktrollSDK) buildDeps( // TODO_TECHDEBT: Configure the grpc client options from the config var grpcClient grpctypes.ClientConn grpcClient, err = grpc.Dial( - config.PocketNodeUrl.Host, + config.QueryNodeGRPCUrl.Host, grpc.WithTransportCredentials(insecure.NewCredentials()), ) if err != nil { @@ -84,3 +85,10 @@ func (sdk *poktrollSDK) buildDeps( return deps, nil } + +// hostToWebsocketURL converts the provided host into a websocket URL that can +// be used to subscribe to onchain events and query the chain via a client +// context or send transactions via a tx client context. +func queryNodeToWebsocketURL(queryNode *url.URL) string { + return fmt.Sprintf("ws://%s/websocket", queryNode.Host) +} diff --git a/pkg/sdk/sdk.go b/pkg/sdk/sdk.go index 233807cec..d3c97d867 100644 --- a/pkg/sdk/sdk.go +++ b/pkg/sdk/sdk.go @@ -24,9 +24,10 @@ var _ POKTRollSDK = (*poktrollSDK)(nil) // Deps is an optional field that can be used to provide the needed dependencies // for the SDK. If it is not provided, the SDK will build the dependencies itself. type POKTRollSDKConfig struct { - PocketNodeUrl *url.URL - PrivateKey cryptotypes.PrivKey - Deps depinject.Config + QueryNodeGRPCUrl *url.URL + QueryNodeUrl *url.URL + PrivateKey cryptotypes.PrivKey + Deps depinject.Config } // poktrollSDK is the implementation of the POKTRollSDK. From 824d2f6c1768c7db4b85fb5ea8e497052b2e48f0 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Tue, 12 Dec 2023 16:46:58 +0100 Subject: [PATCH 11/34] chore: Trigger e2e tests --- pkg/sdk/deps_builder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sdk/deps_builder.go b/pkg/sdk/deps_builder.go index cd07cab55..8433344bb 100644 --- a/pkg/sdk/deps_builder.go +++ b/pkg/sdk/deps_builder.go @@ -44,7 +44,7 @@ func (sdk *poktrollSDK) buildDeps( deps = depinject.Configs(deps, depinject.Supply(blockClient)) // Create and supply the grpc client used by the queriers - // TODO_TECHDEBT: Configure the grpc client options from the config + // TODO_TECHDEBT: Configure the grpc client options from the config. var grpcClient grpctypes.ClientConn grpcClient, err = grpc.Dial( config.QueryNodeGRPCUrl.Host, From 4ed010a6743174b0ec2ad2bdde0baaec99e68ab1 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Tue, 12 Dec 2023 23:19:33 +0100 Subject: [PATCH 12/34] chore: Rename config files entries and enable grpc for off-chain actors --- .github/workflows/reviewdog.yml | 24 +++- localnet/kubernetes/values-appgateserver.yaml | 4 +- localnet/kubernetes/values-relayminer.yaml | 4 +- .../config/appgate_server_config.yaml | 14 +- .../poktrolld/config/relayminer_config.yaml | 16 +-- pkg/appgateserver/cmd/cmd.go | 46 ++++--- .../config/appgate_configs_reader.go | 41 +++--- .../config/appgate_configs_reader_test.go | 86 +++++-------- pkg/appgateserver/config/errors.go | 12 +- pkg/client/query/supplierquerier.go | 2 +- pkg/deps/config/suppliers.go | 63 +++------ pkg/relayer/cmd/cmd.go | 40 +++--- pkg/relayer/config/errors.go | 16 +-- .../config/relayminer_configs_reader.go | 49 ++++--- .../config/relayminer_configs_reader_test.go | 121 ++++++++---------- 15 files changed, 247 insertions(+), 291 deletions(-) diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index 2fb9c9dd7..6c8473284 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -7,10 +7,9 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }} cancel-in-progress: true - jobs: - # Makes sure that comments like TODO_IN_THIS_PR or TODO_IN_THIS_COMMIT block merging to main - # More info: https://github.com/pokt-network/action-fail-on-found + # Makes sure that comments like TODO_IN_THIS_PR or TODO_IN_THIS_COMMIT block + # merging to main. See https://github.com/pokt-network/action-fail-on-found check_todo_in_this: name: Check TODO_IN_THIS_ runs-on: ubuntu-latest @@ -24,6 +23,25 @@ jobs: fail_on_error: true pattern: TODO_IN_THIS_ + # Ensure that we are using polylog (via logger.) instead of the golang's stdlib + # log package. + check_stdlog_in_off_chain_package: + name: Check stdlog in off-chain source code + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pokt-network/action-fail-on-found@v1 + with: + github_token: ${{ secrets.github_token }} + reporter: github-pr-review + level: error + fail_on_error: true + # Go stdlib `log` package import detector regex. + # See: https://regex101.com/r/CBEq1U/3. + pattern: import\s+(\(\n\s+)?[^\)]*"log" + + # There are multiple ways to validate (at compile time) that a struct + # implements a certain interface. This check enforces a common practice. check_non_standard_interface_implementations: name: Check for non-standard interface implementation statements runs-on: ubuntu-latest diff --git a/localnet/kubernetes/values-appgateserver.yaml b/localnet/kubernetes/values-appgateserver.yaml index d5eb44bff..d7fba6016 100644 --- a/localnet/kubernetes/values-appgateserver.yaml +++ b/localnet/kubernetes/values-appgateserver.yaml @@ -1,3 +1,3 @@ config: - query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 - pocket_node_websocket_url: tcp://sequencer-poktroll-sequencer:36657 \ No newline at end of file + query_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 + query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 \ No newline at end of file diff --git a/localnet/kubernetes/values-relayminer.yaml b/localnet/kubernetes/values-relayminer.yaml index 2de5a78f0..3f73f051b 100644 --- a/localnet/kubernetes/values-relayminer.yaml +++ b/localnet/kubernetes/values-relayminer.yaml @@ -1,4 +1,4 @@ config: + query_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 - network_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 - pocket_node_websocket_url: tcp://sequencer-poktroll-sequencer:36657 \ No newline at end of file + tx_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 \ No newline at end of file diff --git a/localnet/poktrolld/config/appgate_server_config.yaml b/localnet/poktrolld/config/appgate_server_config.yaml index bb760eb76..6a1512061 100644 --- a/localnet/poktrolld/config/appgate_server_config.yaml +++ b/localnet/poktrolld/config/appgate_server_config.yaml @@ -4,9 +4,11 @@ self_signing: true signing_key: app1 # The host and port that the appgate server will listen on listening_endpoint: http://localhost:42069 -# tcp://: to a full pocket node for reading data -query_node_grpc_url: tcp://127.0.0.1:36658 -# grpc client insecure flag -grpc_insecure: true -# tcp://: to a full pocket node websocket endpoint for listening for on-chain events -pocket_node_websocket_url: tcp://127.0.0.1:36657 +# Pocket node URL that exposes CometBFT JSON-RPC API. +# This can be used by the Cosmos client SDK, event subscriptions, etc... +query_node_rpc_url: tcp://poktroll-sequencer:36657 +# Pocket node URL that exposes the Cosmos gRPC service. +tx_node_grpc_url: tcp://poktroll-sequencer:36658 +# Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. +# If unspecified, defaults to `tx_node_grpc_url`. +query_node_grpc_url: tcp://poktroll-sequencer:36658 diff --git a/localnet/poktrolld/config/relayminer_config.yaml b/localnet/poktrolld/config/relayminer_config.yaml index 2b69a6a62..935d85464 100644 --- a/localnet/poktrolld/config/relayminer_config.yaml +++ b/localnet/poktrolld/config/relayminer_config.yaml @@ -1,11 +1,11 @@ -# tcp://: to a full pocket node for reading data -query_node_grpc_url: tcp://127.0.0.1:36658 -# tcp://: to a pocket node that gossips transactions throughout the network (may or may not be the sequencer) -network_node_grpc_url: tcp://127.0.0.1:36658 -# grpc client insecure flag -grpc_insecure: true -# tcp://: to a full pocket node websocket endpoint for listening for on-chain events -pocket_node_websocket_url: tcp://127.0.0.1:36657 +# Pocket node URL that exposes CometBFT JSON-RPC API. +# This can be used by the Cosmos client SDK, event subscriptions, etc... +query_node_rpc_url: tcp://poktroll-sequencer:36657 +# Pocket node URL that exposes the Cosmos gRPC service. +tx_node_grpc_url: tcp://poktroll-sequencer:36658 +# Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. +# If unspecified, defaults to `tx_node_grpc_url`. +query_node_grpc_url: tcp://poktroll-sequencer:36658 # Name of the key (in the keyring) to sign transactions signing_key_name: supplier1 # TODO_TECHDEBT(#137, #130): Once the `relayer.json` config file is implemented AND a local LLM RPC service diff --git a/pkg/appgateserver/cmd/cmd.go b/pkg/appgateserver/cmd/cmd.go index 74cda0a0c..50ce78283 100644 --- a/pkg/appgateserver/cmd/cmd.go +++ b/pkg/appgateserver/cmd/cmd.go @@ -25,9 +25,9 @@ import ( const omittedDefaultFlagValue = "explicitly omitting default" var ( - flagAppGateConfig string - flagCosmosNodeURL string - flagCosmosNodeGRPCURL string + flagAppGateConfig string + flagNodeRPCURL string + flagNodeGRPCURL string ) // AppGateServerCmd returns the Cobra command for running the AppGate server. @@ -67,9 +67,9 @@ provided that: // Cosmos flags cmd.Flags().String(cosmosflags.FlagKeyringBackend, "", "Select keyring's backend (os|file|kwallet|pass|test)") - cmd.Flags().StringVar(&flagCosmosNodeURL, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialise the Cosmos query context correctly. It can be used to override the `QueryNodeUrl` field in the config file if specified.") - cmd.Flags().StringVar(&flagCosmosNodeGRPCURL, cosmosflags.FlagGRPC, omittedDefaultFlagValue, "Register the default Cosmos node grpc flag, which is needed to initialise the Cosmos query context with grpc correctly. It can be used to override the `QueryNodeGRPCUrl` field in the config file if specified.") - cmd.Flags().Bool(cosmosflags.FlagGRPCInsecure, true, "Used to initialise the Cosmos query context with grpc security options. It can be used to override the `QueryNodeGRPCInsecure` field in the config file if specified.") + cmd.Flags().StringVar(&flagNodeRPCURL, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialize the Cosmos query context correctly. It can be used to override the `QueryNodeUrl` field in the config file if specified.") + cmd.Flags().StringVar(&flagNodeGRPCURL, cosmosflags.FlagGRPC, omittedDefaultFlagValue, "Register the default Cosmos node grpc flag, which is needed to initialize the Cosmos query context with grpc correctly. It can be used to override the `QueryNodeGRPCUrl` field in the config file if specified.") + cmd.Flags().Bool(cosmosflags.FlagGRPCInsecure, true, "Used to initialize the Cosmos query context with grpc security options. It can be used to override the `QueryNodeGRPCInsecure` field in the config file if specified.") return cmd } @@ -147,22 +147,24 @@ func setupAppGateServerDependencies( cmd *cobra.Command, appGateConfig *appgateconfig.AppGateServerConfig, ) (_ depinject.Config, err error) { - pocketNodeWebsocketURL := appGateConfig.PocketNodeWebsocketUrl + queryNodeRPCURL := appGateConfig.QueryNodeRPCUrl queryNodeGRPCURL := appGateConfig.QueryNodeGRPCUrl - // Override the config file's `QueryNodeGRPCUrl` fields + // Override the config file's `QueryNodeGRPCUrl` field // with the `--grpc-addr` flag if it was specified. - if flagCosmosNodeGRPCURL != omittedDefaultFlagValue { - queryNodeGRPCURL, err = url.Parse(flagCosmosNodeGRPCURL) + // TODO(#223) Remove this check once viper is used as SoT for overridable config values. + if flagNodeGRPCURL != omittedDefaultFlagValue { + queryNodeGRPCURL, err = url.Parse(flagNodeGRPCURL) if err != nil { return nil, fmt.Errorf("failed to parse Cosmos node URL: %w", err) } } - // Override the config file's `PocketNodeWebsocketUrl` fields + // Override the config file's `QueryNodeRPCURL` field // with the `--node` flag if it was specified. - if flagCosmosNodeURL != omittedDefaultFlagValue { - pocketNodeWebsocketURL, err = url.Parse(flagCosmosNodeURL) + // TODO(#223) Remove this check once viper is used as SoT for overridable config values. + if flagNodeRPCURL != omittedDefaultFlagValue { + queryNodeRPCURL, err = url.Parse(flagNodeRPCURL) if err != nil { return nil, fmt.Errorf("failed to parse Cosmos node URL: %w", err) } @@ -170,18 +172,14 @@ func setupAppGateServerDependencies( supplierFuncs := []config.SupplierFn{ config.NewSupplyLoggerFromCtx(ctx), - config.NewSupplyEventsQueryClientFn(pocketNodeWebsocketURL), // leaf - config.NewSupplyBlockClientFn(pocketNodeWebsocketURL), // leaf - config.NewSupplyQueryClientContextFn(queryNodeGRPCURL, appGateConfig.GRPCInsecure), // leaf - config.NewSupplyAccountQuerierFn(), // leaf - config.NewSupplyApplicationQuerierFn(), // leaf - config.NewSupplySessionQuerierFn(), // leaf + config.NewSupplyEventsQueryClientFn(queryNodeRPCURL), // leaf + config.NewSupplyBlockClientFn(queryNodeRPCURL), // leaf + config.NewSupplyQueryClientContextFn(queryNodeGRPCURL), // leaf + config.NewSupplyAccountQuerierFn(), // leaf + config.NewSupplyApplicationQuerierFn(), // leaf + config.NewSupplySessionQuerierFn(), // leaf config.NewSupplyRingCacheFn(), - config.NewSupplyPOKTRollSDKFn( - queryNodeGRPCURL, - pocketNodeWebsocketURL, - appGateConfig.SigningKey, - ), + config.NewSupplyPOKTRollSDKFn(appGateConfig.SigningKey), } return config.SupplyConfig(ctx, cmd, supplierFuncs) diff --git a/pkg/appgateserver/config/appgate_configs_reader.go b/pkg/appgateserver/config/appgate_configs_reader.go index 55d00735a..36f74043e 100644 --- a/pkg/appgateserver/config/appgate_configs_reader.go +++ b/pkg/appgateserver/config/appgate_configs_reader.go @@ -9,22 +9,20 @@ import ( // YAMLAppGateServerConfig is the structure used to unmarshal the AppGateServer config file // TODO_DOCUMENT(@red-0ne): Add proper README documentation for yaml config files. type YAMLAppGateServerConfig struct { - SelfSigning bool `yaml:"self_signing"` - SigningKey string `yaml:"signing_key"` - ListeningEndpoint string `yaml:"listening_endpoint"` - QueryNodeGRPCUrl string `yaml:"query_node_grpc_url"` - GRPCInsecure bool `yaml:"grpc_insecure"` - PocketNodeWebsocketUrl string `yaml:"pocket_node_websocket_url"` + SelfSigning bool `yaml:"self_signing"` + SigningKey string `yaml:"signing_key"` + ListeningEndpoint string `yaml:"listening_endpoint"` + QueryNodeGRPCUrl string `yaml:"query_node_grpc_url"` + QueryNodeRPCUrl string `yaml:"query_node_rpc_url"` } // AppGateServerConfig is the structure describing the AppGateServer config type AppGateServerConfig struct { - SelfSigning bool - SigningKey string - ListeningEndpoint *url.URL - QueryNodeGRPCUrl *url.URL - GRPCInsecure bool - PocketNodeWebsocketUrl *url.URL + SelfSigning bool + SigningKey string + ListeningEndpoint *url.URL + QueryNodeGRPCUrl *url.URL + QueryNodeRPCUrl *url.URL } // ParseAppGateServerConfigs parses the stake config file into a AppGateConfig @@ -59,23 +57,22 @@ func ParseAppGateServerConfigs(configContent []byte) (*AppGateServerConfig, erro return nil, ErrAppGateConfigInvalidQueryNodeGRPCUrl.Wrapf("%s", err) } - if yamlAppGateServerConfig.PocketNodeWebsocketUrl == "" { - return nil, ErrAppGateConfigInvalidPocketNodeWebsocketUrl + if yamlAppGateServerConfig.QueryNodeRPCUrl == "" { + return nil, ErrAppGateConfigInvalidQueryNodeRPCUrl } - pocketNodeWebsocketUrl, err := url.Parse(yamlAppGateServerConfig.PocketNodeWebsocketUrl) + queryNodeRPCUrl, err := url.Parse(yamlAppGateServerConfig.QueryNodeRPCUrl) if err != nil { - return nil, ErrAppGateConfigInvalidPocketNodeWebsocketUrl.Wrapf("%s", err) + return nil, ErrAppGateConfigInvalidQueryNodeRPCUrl.Wrapf("%s", err) } // Populate the appGateServerConfig with the values from the yamlAppGateServerConfig appGateServerConfig := &AppGateServerConfig{ - SelfSigning: yamlAppGateServerConfig.SelfSigning, - SigningKey: yamlAppGateServerConfig.SigningKey, - ListeningEndpoint: listeningEndpoint, - QueryNodeGRPCUrl: queryNodeGRPCUrl, - GRPCInsecure: yamlAppGateServerConfig.GRPCInsecure, - PocketNodeWebsocketUrl: pocketNodeWebsocketUrl, + SelfSigning: yamlAppGateServerConfig.SelfSigning, + SigningKey: yamlAppGateServerConfig.SigningKey, + ListeningEndpoint: listeningEndpoint, + QueryNodeGRPCUrl: queryNodeGRPCUrl, + QueryNodeRPCUrl: queryNodeRPCUrl, } return appGateServerConfig, nil diff --git a/pkg/appgateserver/config/appgate_configs_reader_test.go b/pkg/appgateserver/config/appgate_configs_reader_test.go index 5ecfaf7a4..8f784f65b 100644 --- a/pkg/appgateserver/config/appgate_configs_reader_test.go +++ b/pkg/appgateserver/config/appgate_configs_reader_test.go @@ -30,18 +30,16 @@ func Test_ParseAppGateConfigs(t *testing.T) { signing_key: app1 listening_endpoint: http://localhost:42069 query_node_grpc_url: tcp://127.0.0.1:36658 - grpc_insecure: true - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_rpc_url: tcp://127.0.0.1:36657 `, expectedError: nil, expectedConfig: &config.AppGateServerConfig{ - SelfSigning: true, - SigningKey: "app1", - ListeningEndpoint: &url.URL{Scheme: "http", Host: "localhost:42069"}, - QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - GRPCInsecure: true, - PocketNodeWebsocketUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657", Path: "webcosket"}, + SelfSigning: true, + SigningKey: "app1", + ListeningEndpoint: &url.URL{Scheme: "http", Host: "localhost:42069"}, + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, }, }, { @@ -51,39 +49,16 @@ func Test_ParseAppGateConfigs(t *testing.T) { signing_key: app1 listening_endpoint: http://localhost:42069 query_node_grpc_url: tcp://127.0.0.1:36658 - grpc_insecure: true - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_rpc_url: tcp://127.0.0.1:36657 `, expectedError: nil, expectedConfig: &config.AppGateServerConfig{ - SelfSigning: false, - SigningKey: "app1", - ListeningEndpoint: &url.URL{Scheme: "http", Host: "localhost:42069"}, - QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - GRPCInsecure: true, - PocketNodeWebsocketUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657", Path: "webcosket"}, - }, - }, - { - desc: "valid: AppGateServer config with undefined grpc insecure", - - inputConfig: ` - self_signing: true - signing_key: app1 - listening_endpoint: http://localhost:42069 - query_node_grpc_url: tcp://127.0.0.1:36658 - pocket_node_websocket_url: tcp://127.0.0.1:36657 - `, - - expectedError: nil, - expectedConfig: &config.AppGateServerConfig{ - SelfSigning: true, - SigningKey: "app1", - ListeningEndpoint: &url.URL{Scheme: "http", Host: "localhost:42069"}, - QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - GRPCInsecure: false, - PocketNodeWebsocketUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657", Path: "webcosket"}, + SelfSigning: false, + SigningKey: "app1", + ListeningEndpoint: &url.URL{Scheme: "http", Host: "localhost:42069"}, + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, }, }, // Invalid Configs @@ -99,11 +74,10 @@ func Test_ParseAppGateConfigs(t *testing.T) { inputConfig: ` self_signing: true - signing_key: + // explicitly missing signing key listening_endpoint: http://localhost:42069 query_node_grpc_url: tcp://127.0.0.1:36658 - grpc_insecure: true - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_rpc_url: tcp://127.0.0.1:36657 `, expectedError: config.ErrAppGateConfigEmptySigningKey, @@ -116,8 +90,7 @@ func Test_ParseAppGateConfigs(t *testing.T) { signing_key: app1 listening_endpoint: &localhost:42069 query_node_grpc_url: tcp://127.0.0.1:36658 - grpc_insecure: true - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_rpc_url: tcp://127.0.0.1:36657 `, expectedError: config.ErrAppGateConfigInvalidListeningEndpoint, @@ -130,38 +103,49 @@ func Test_ParseAppGateConfigs(t *testing.T) { signing_key: app1 listening_endpoint: http://localhost:42069 query_node_grpc_url: &127.0.0.1:36658 - grpc_insecure: true - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_rpc_url: tcp://127.0.0.1:36657 + `, + + expectedError: config.ErrAppGateConfigInvalidQueryNodeGRPCUrl, + }, + { + desc: "invalid: missing query node grpc url", + + inputConfig: ` + self_signing: true + signing_key: app1 + listening_endpoint: http://localhost:42069 + // explicitly missing query_node_grpc_url + query_node_rpc_url: tcp://127.0.0.1:36657 `, expectedError: config.ErrAppGateConfigInvalidQueryNodeGRPCUrl, }, { - desc: "invalid: invalid pocket node websocket", + desc: "invalid: invalid query node rpc url", inputConfig: ` self_signing: true signing_key: app1 listening_endpoint: http://localhost:42069 query_node_grpc_url: tcp://127.0.0.1:36658 - grpc_insecure: true - pocket_node_websocket_url: &127.0.0.1:36657 + query_node_rpc_url: &127.0.0.1:36657 `, - expectedError: config.ErrAppGateConfigInvalidPocketNodeWebsocketUrl, + expectedError: config.ErrAppGateConfigInvalidQueryNodeRPCUrl, }, { - desc: "invalid: missing pocket node websocket url", + desc: "invalid: missing query node rpc url", inputConfig: ` self_signing: true signing_key: app1 listening_endpoint: http://localhost:42069 query_node_grpc_url: tcp://127.0.0.1:36658 - grpc_insecure: true + // explicitly missing query_node_rpc_url `, - expectedError: config.ErrAppGateConfigInvalidPocketNodeWebsocketUrl, + expectedError: config.ErrAppGateConfigInvalidQueryNodeRPCUrl, }, } diff --git a/pkg/appgateserver/config/errors.go b/pkg/appgateserver/config/errors.go index 2d43b9189..00023cd35 100644 --- a/pkg/appgateserver/config/errors.go +++ b/pkg/appgateserver/config/errors.go @@ -3,10 +3,10 @@ package config import sdkerrors "cosmossdk.io/errors" var ( - codespace = "appgate_config" - ErrAppGateConfigUnmarshalYAML = sdkerrors.Register(codespace, 1, "config reader cannot unmarshal yaml content") - ErrAppGateConfigEmptySigningKey = sdkerrors.Register(codespace, 2, "empty signing key in AppGateServer config") - ErrAppGateConfigInvalidListeningEndpoint = sdkerrors.Register(codespace, 3, "invalid listening endpoint in AppGateServer config") - ErrAppGateConfigInvalidQueryNodeGRPCUrl = sdkerrors.Register(codespace, 5, "invalid pocket query node grpc url in AppGateServer config") - ErrAppGateConfigInvalidPocketNodeWebsocketUrl = sdkerrors.Register(codespace, 6, "invalid pocket node websocket url in AppGateServer config") + codespace = "appgate_config" + ErrAppGateConfigUnmarshalYAML = sdkerrors.Register(codespace, 1, "config reader cannot unmarshal yaml content") + ErrAppGateConfigEmptySigningKey = sdkerrors.Register(codespace, 2, "empty signing key in AppGateServer config") + ErrAppGateConfigInvalidListeningEndpoint = sdkerrors.Register(codespace, 3, "invalid listening endpoint in AppGateServer config") + ErrAppGateConfigInvalidQueryNodeGRPCUrl = sdkerrors.Register(codespace, 4, "invalid query node grpc url in AppGateServer config") + ErrAppGateConfigInvalidQueryNodeRPCUrl = sdkerrors.Register(codespace, 5, "invalid query node rpc url in AppGateServer config") ) diff --git a/pkg/client/query/supplierquerier.go b/pkg/client/query/supplierquerier.go index 4c4a91b2f..e476995d9 100644 --- a/pkg/client/query/supplierquerier.go +++ b/pkg/client/query/supplierquerier.go @@ -23,7 +23,7 @@ type supplierQuerier struct { // injecting the dependecies provided by the depinject.Config. // // Required dependencies: -// - clientCtx +// - clientConn func NewSupplierQuerier(deps depinject.Config) (client.SupplierQueryClient, error) { supq := &supplierQuerier{} diff --git a/pkg/deps/config/suppliers.go b/pkg/deps/config/suppliers.go index e6726a807..1ecdc05f7 100644 --- a/pkg/deps/config/suppliers.go +++ b/pkg/deps/config/suppliers.go @@ -57,15 +57,15 @@ func NewSupplyLoggerFromCtx(ctx context.Context) SupplierFn { // EventsQueryClient instance, with the given hostname converted into a websocket // URL to subscribe to, and returns a new depinject.Config which is supplied // with the given deps and the new EventsQueryClient. -func NewSupplyEventsQueryClientFn(pocketNodeWebsocketURL *url.URL) SupplierFn { +func NewSupplyEventsQueryClientFn(queryNodeRPCURL *url.URL) SupplierFn { return func( _ context.Context, deps depinject.Config, _ *cobra.Command, ) (depinject.Config, error) { // Convert the host to a websocket URL - nodeWebsocketURL := queryNodeToWebsocketURL(pocketNodeWebsocketURL) - eventsQueryClient := events.NewEventsQueryClient(nodeWebsocketURL) + queryNodeWebsocketURL := queryNodeToWebsocketURL(queryNodeRPCURL) + eventsQueryClient := events.NewEventsQueryClient(queryNodeWebsocketURL) return depinject.Configs(deps, depinject.Supply(eventsQueryClient)), nil } @@ -75,15 +75,15 @@ func NewSupplyEventsQueryClientFn(pocketNodeWebsocketURL *url.URL) SupplierFn { // instance with the given hostname, which is converted into a websocket URL, // to listen for block events on-chain, and returns a new depinject.Config which // is supplied with the given deps and the new BlockClient. -func NewSupplyBlockClientFn(pocketNodeWebsocketURL *url.URL) SupplierFn { +func NewSupplyBlockClientFn(queryNodeRPCURL *url.URL) SupplierFn { return func( ctx context.Context, deps depinject.Config, _ *cobra.Command, ) (depinject.Config, error) { // Convert the host to a websocket URL - nodeWebsocketURL := queryNodeToWebsocketURL(pocketNodeWebsocketURL) - blockClient, err := block.NewBlockClient(ctx, deps, nodeWebsocketURL) + queryNodeWebsocketURL := queryNodeToWebsocketURL(queryNodeRPCURL) + blockClient, err := block.NewBlockClient(ctx, deps, queryNodeWebsocketURL) if err != nil { return nil, err } @@ -95,29 +95,17 @@ func NewSupplyBlockClientFn(pocketNodeWebsocketURL *url.URL) SupplierFn { // NewSupplyQueryClientContextFn returns a function with constructs a ClientContext // instance with the given cmd and returns a new depinject.Config which is // supplied with the given deps and the new ClientContext. -func NewSupplyQueryClientContextFn( - pocketQueryNodeGRPCURL *url.URL, - pocketQueryNodeGRPCInsecure bool, -) SupplierFn { +func NewSupplyQueryClientContextFn(queryNodeGRPCURL *url.URL) SupplierFn { return func(_ context.Context, deps depinject.Config, cmd *cobra.Command, ) (depinject.Config, error) { // Temporarily store the flag's current value - tmp := cosmosflags.FlagGRPC + tmpGRPC := cosmosflags.FlagGRPC // Set --grpc-addr flag to the pocketQueryNodeURL for the client context // This flag is read by cosmosclient.GetClientQueryContext. - if err := cmd.Flags().Set(cosmosflags.FlagGRPC, pocketQueryNodeGRPCURL.Host); err != nil { - return nil, err - } - - grpcInscureFlagValue := "false" - if pocketQueryNodeGRPCInsecure { - grpcInscureFlagValue = "true" - } - - if err := cmd.Flags().Set(cosmosflags.FlagGRPCInsecure, grpcInscureFlagValue); err != nil { + if err := cmd.Flags().Set(cosmosflags.FlagGRPC, queryNodeGRPCURL.Host); err != nil { return nil, err } @@ -139,7 +127,7 @@ func NewSupplyQueryClientContextFn( // Restore the flag's original value in order for other components // to use the flag as expected. - if err := cmd.Flags().Set(cosmosflags.FlagGRPC, tmp); err != nil { + if err := cmd.Flags().Set(cosmosflags.FlagGRPC, tmpGRPC); err != nil { return nil, err } @@ -150,28 +138,17 @@ func NewSupplyQueryClientContextFn( // NewSupplyTxClientContextFn returns a function with constructs a ClientContext // instance with the given cmd and returns a new depinject.Config which is // supplied with the given deps and the new ClientContext. -func NewSupplyTxClientContextFn( - pocketTxNodeGRPCURL *url.URL, - pocketTxNodeGRPCInsecure bool, -) SupplierFn { +func NewSupplyTxClientContextFn(txNodeGRPCURL *url.URL) SupplierFn { return func(_ context.Context, deps depinject.Config, cmd *cobra.Command, ) (depinject.Config, error) { // Temporarily store the flag's current value - tmp := cosmosflags.FlagGRPC + tmpGRPC := cosmosflags.FlagGRPC // Set --node flag to the pocketTxNodeURL for the client context // This flag is read by cosmosclient.GetClientTxContext. - if err := cmd.Flags().Set(cosmosflags.FlagGRPC, pocketTxNodeGRPCURL.Host); err != nil { - return nil, err - } - - grpcInscureFlagValue := "false" - if pocketTxNodeGRPCInsecure { - grpcInscureFlagValue = "true" - } - if err := cmd.Flags().Set(cosmosflags.FlagGRPCInsecure, grpcInscureFlagValue); err != nil { + if err := cmd.Flags().Set(cosmosflags.FlagGRPC, txNodeGRPCURL.Host); err != nil { return nil, err } @@ -191,7 +168,7 @@ func NewSupplyTxClientContextFn( // Restore the flag's original value in order for other components // to use the flag as expected. - if err := cmd.Flags().Set(cosmosflags.FlagGRPC, tmp); err != nil { + if err := cmd.Flags().Set(cosmosflags.FlagGRPC, tmpGRPC); err != nil { return nil, err } @@ -304,11 +281,7 @@ func NewSupplyRingCacheFn() SupplierFn { // NewSupplyPOKTRollSDKFn returns a function which constructs a // POKTRollSDK instance with the required dependencies and returns a new // depinject.Config which is supplied with the given deps and the new POKTRollSDK. -func NewSupplyPOKTRollSDKFn( - queryNodeGRPCURL *url.URL, - queryNodeWebsocketURL *url.URL, - signingKeyName string, -) SupplierFn { +func NewSupplyPOKTRollSDKFn(signingKeyName string) SupplierFn { return func( ctx context.Context, deps depinject.Config, @@ -332,11 +305,7 @@ func NewSupplyPOKTRollSDKFn( return nil, err } - config := &sdk.POKTRollSDKConfig{ - PrivateKey: privateKey, - Deps: deps, - } - + config := &sdk.POKTRollSDKConfig{PrivateKey: privateKey, Deps: deps} poktrollSDK, err := sdk.NewPOKTRollSDK(ctx, config) if err != nil { return nil, err diff --git a/pkg/relayer/cmd/cmd.go b/pkg/relayer/cmd/cmd.go index 8c469964a..0c45990d9 100644 --- a/pkg/relayer/cmd/cmd.go +++ b/pkg/relayer/cmd/cmd.go @@ -34,9 +34,9 @@ const omittedDefaultFlagValue = "explicitly omitting default" // TODO_CONSIDERATION: Consider moving all flags defined in `/pkg` to a `flags.go` file. var ( - flagRelayMinerConfig string - flagCosmosNodeURL string - flagCosmosNodeGRPCURL string + flagRelayMinerConfig string + flagNodeRPCUrl string + flagNodeGRPCUrl string ) // RelayerCmd returns the Cobra command for running the relay miner. @@ -65,9 +65,9 @@ for such operations.`, // Cosmos flags cmd.Flags().String(cosmosflags.FlagKeyringBackend, "", "Select keyring's backend (os|file|kwallet|pass|test)") - cmd.Flags().StringVar(&flagCosmosNodeURL, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialise the Cosmos query and tx contexts correctly. It can be used to override the `QueryNodeUrl` and `NetworkNodeUrl` fields in the config file if specified.") - cmd.Flags().StringVar(&flagCosmosNodeGRPCURL, cosmosflags.FlagGRPC, omittedDefaultFlagValue, "Register the default Cosmos node grpc flag, which is needed to initialise the Cosmos query context with grpc correctly. It can be used to override the `QueryNodeGRPCUrl` field in the config file if specified.") - cmd.Flags().Bool(cosmosflags.FlagGRPCInsecure, true, "Used to initialise the Cosmos query context with grpc security options. It can be used to override the `QueryNodeGRPCInsecure` field in the config file if specified.") + cmd.Flags().StringVar(&flagNodeRPCUrl, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialize the Cosmos query and tx contexts correctly. It can be used to override the `QueryNodeUrl` and `NetworkNodeUrl` fields in the config file if specified.") + cmd.Flags().StringVar(&flagNodeGRPCUrl, cosmosflags.FlagGRPC, omittedDefaultFlagValue, "Register the default Cosmos node grpc flag, which is needed to initialize the Cosmos query context with grpc correctly. It can be used to override the `QueryNodeGRPCUrl` field in the config file if specified.") + cmd.Flags().Bool(cosmosflags.FlagGRPCInsecure, true, "Used to initialize the Cosmos query context with grpc security options. It can be used to override the `QueryNodeGRPCInsecure` field in the config file if specified.") return cmd } @@ -135,25 +135,27 @@ func setupRelayerDependencies( cmd *cobra.Command, relayMinerConfig *relayerconfig.RelayMinerConfig, ) (deps depinject.Config, err error) { - pocketNodeWebsocketUrl := relayMinerConfig.PocketNodeWebsocketUrl - queryNodeGRPCURL := relayMinerConfig.QueryNodeGRPCUrl - networkNodeGRPCURL := relayMinerConfig.NetworkNodeGRPCUrl + parsedFlagNodeRPCUrl := relayMinerConfig.QueryNodeRPCUrl + queryNodeGRPCUrl := relayMinerConfig.QueryNodeGRPCUrl + txNodeGRPCUrl := relayMinerConfig.TxNodeGRPCUrl // Override the config file's `QueryNodeGRPCUrl` and `NetworkNodeGRPCUrl` fields // with the `--grpc-addr` flag if it was specified. - if flagCosmosNodeGRPCURL != omittedDefaultFlagValue { - cosmosParsedGRPCURL, err := url.Parse(flagCosmosNodeGRPCURL) + // TODO(#223) Remove this check once viper is used as SoT for overridable config values. + if flagNodeGRPCUrl != omittedDefaultFlagValue { + parsedFlagNodeGRPCUrl, err := url.Parse(flagNodeGRPCUrl) if err != nil { return nil, fmt.Errorf("failed to parse Cosmos node URL: %w", err) } - queryNodeGRPCURL = cosmosParsedGRPCURL - networkNodeGRPCURL = cosmosParsedGRPCURL + queryNodeGRPCUrl = parsedFlagNodeGRPCUrl + txNodeGRPCUrl = parsedFlagNodeGRPCUrl } // Override the config file's `QueryNodeUrl` fields // with the `--node` flag if it was specified. - if flagCosmosNodeURL != omittedDefaultFlagValue { - pocketNodeWebsocketUrl, err = url.Parse(flagCosmosNodeURL) + // TODO(#223) Remove this check once viper is used as SoT for overridable config values. + if flagNodeRPCUrl != omittedDefaultFlagValue { + parsedFlagNodeRPCUrl, err = url.Parse(flagNodeRPCUrl) if err != nil { return nil, fmt.Errorf("failed to parse Cosmos node URL: %w", err) } @@ -165,11 +167,11 @@ func setupRelayerDependencies( supplierFuncs := []config.SupplierFn{ config.NewSupplyLoggerFromCtx(ctx), - config.NewSupplyEventsQueryClientFn(pocketNodeWebsocketUrl), // leaf - config.NewSupplyBlockClientFn(pocketNodeWebsocketUrl), // leaf - config.NewSupplyQueryClientContextFn(queryNodeGRPCURL, relayMinerConfig.GRPCInsecure), // leaf + config.NewSupplyEventsQueryClientFn(parsedFlagNodeRPCUrl), // leaf + config.NewSupplyBlockClientFn(parsedFlagNodeRPCUrl), // leaf + config.NewSupplyQueryClientContextFn(queryNodeGRPCUrl), // leaf supplyMiner, // leaf - config.NewSupplyTxClientContextFn(networkNodeGRPCURL, relayMinerConfig.GRPCInsecure), // leaf + config.NewSupplyTxClientContextFn(txNodeGRPCUrl), // leaf config.NewSupplyAccountQuerierFn(), config.NewSupplyApplicationQuerierFn(), config.NewSupplySupplierQuerierFn(), diff --git a/pkg/relayer/config/errors.go b/pkg/relayer/config/errors.go index 2738eef1a..bf2b52a6a 100644 --- a/pkg/relayer/config/errors.go +++ b/pkg/relayer/config/errors.go @@ -3,12 +3,12 @@ package config import sdkerrors "cosmossdk.io/errors" var ( - codespace = "relayminer_config" - ErrRelayMinerConfigUnmarshalYAML = sdkerrors.Register(codespace, 1, "config reader cannot unmarshal yaml content") - ErrRelayMinerConfigInvalidQueryNodeGRPCUrl = sdkerrors.Register(codespace, 2, "invalid query node grpc url in RelayMiner config") - ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl = sdkerrors.Register(codespace, 3, "invalid network node grpc url in RelayMiner config") - ErrRelayMinerConfigInvalidPocketNodeWebsocketUrl = sdkerrors.Register(codespace, 4, "invalid pocket node websocket url in RelayMiner config") - ErrRelayMinerConfigInvalidServiceEndpoint = sdkerrors.Register(codespace, 5, "invalid service endpoint in RelayMiner config") - ErrRelayMinerConfigInvalidSigningKeyName = sdkerrors.Register(codespace, 6, "invalid signing key name in RelayMiner config") - ErrRelayMinerConfigInvalidSmtStorePath = sdkerrors.Register(codespace, 7, "invalid smt store path in RelayMiner config") + codespace = "relayminer_config" + ErrRelayMinerConfigUnmarshalYAML = sdkerrors.Register(codespace, 1, "config reader cannot unmarshal yaml content") + ErrRelayMinerConfigInvalidQueryNodeGRPCUrl = sdkerrors.Register(codespace, 2, "invalid query node grpc url in RelayMiner config") + ErrRelayMinerConfigInvalidTxNodeGRPCUrl = sdkerrors.Register(codespace, 3, "invalid tx node grpc url in RelayMiner config") + ErrRelayMinerConfigInvalidQueryNodeRPCUrl = sdkerrors.Register(codespace, 4, "invalid query node rpc url in RelayMiner config") + ErrRelayMinerConfigInvalidServiceEndpoint = sdkerrors.Register(codespace, 5, "invalid service endpoint in RelayMiner config") + ErrRelayMinerConfigInvalidSigningKeyName = sdkerrors.Register(codespace, 6, "invalid signing key name in RelayMiner config") + ErrRelayMinerConfigInvalidSmtStorePath = sdkerrors.Register(codespace, 7, "invalid smt store path in RelayMiner config") ) diff --git a/pkg/relayer/config/relayminer_configs_reader.go b/pkg/relayer/config/relayminer_configs_reader.go index 3f95ac23a..9385108dd 100644 --- a/pkg/relayer/config/relayminer_configs_reader.go +++ b/pkg/relayer/config/relayminer_configs_reader.go @@ -10,9 +10,8 @@ import ( // TODO_DOCUMENT(@red-0ne): Add proper README documentation for yaml config files. type YAMLRelayMinerConfig struct { QueryNodeGRPCUrl string `yaml:"query_node_grpc_url"` - NetworkNodeGRPCUrl string `yaml:"network_node_grpc_url"` - GRPCInsecure bool `yaml:"grpc_insecure"` - PocketNodeWebsocketUrl string `yaml:"pocket_node_websocket_url"` + TxNodeGRPCUrl string `yaml:"tx_node_grpc_url"` + QueryNodeRPCUrl string `yaml:"query_node_rpc_url"` SigningKeyName string `yaml:"signing_key_name"` ProxiedServiceEndpoints map[string]string `yaml:"proxied_service_endpoints"` SmtStorePath string `yaml:"smt_store_path"` @@ -21,9 +20,8 @@ type YAMLRelayMinerConfig struct { // RelayMinerConfig is the structure describing the RelayMiner config type RelayMinerConfig struct { QueryNodeGRPCUrl *url.URL - NetworkNodeGRPCUrl *url.URL - GRPCInsecure bool - PocketNodeWebsocketUrl *url.URL + TxNodeGRPCUrl *url.URL + QueryNodeRPCUrl *url.URL SigningKeyName string ProxiedServiceEndpoints map[string]*url.URL SmtStorePath string @@ -38,37 +36,37 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { return nil, ErrRelayMinerConfigUnmarshalYAML.Wrapf("%s", err) } - // Check that the query node GRPC URL is provided - if yamlRelayMinerConfig.QueryNodeGRPCUrl == "" { - return nil, ErrRelayMinerConfigInvalidQueryNodeGRPCUrl.Wrapf("query node url is required") + // Check that the tx node GRPC URL is provided + if yamlRelayMinerConfig.TxNodeGRPCUrl == "" { + return nil, ErrRelayMinerConfigInvalidTxNodeGRPCUrl.Wrapf("tx node grpc url is required") } - // Parse the query node GRPC URL - queryNodeGRPCUrl, err := url.Parse(yamlRelayMinerConfig.QueryNodeGRPCUrl) + // Parse the tx node GRPC URL + txNodeGRPCUrl, err := url.Parse(yamlRelayMinerConfig.TxNodeGRPCUrl) if err != nil { - return nil, ErrRelayMinerConfigInvalidQueryNodeGRPCUrl.Wrapf("%s", err) + return nil, ErrRelayMinerConfigInvalidTxNodeGRPCUrl.Wrapf("%s", err) } - // Check that the network node GRPC URL is provided - if yamlRelayMinerConfig.NetworkNodeGRPCUrl == "" { - return nil, ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl.Wrapf("network node url is required") + // Check that the query node GRPC URL is provided and default to the tx node GRPC URL if not + if yamlRelayMinerConfig.QueryNodeGRPCUrl == "" { + yamlRelayMinerConfig.QueryNodeGRPCUrl = yamlRelayMinerConfig.TxNodeGRPCUrl } - // Parse the network node GRPC URL - networkNodeGRPCUrl, err := url.Parse(yamlRelayMinerConfig.NetworkNodeGRPCUrl) + // Parse the query node GRPC URL + queryNodeGRPCUrl, err := url.Parse(yamlRelayMinerConfig.QueryNodeGRPCUrl) if err != nil { - return nil, ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl.Wrapf("%s", err) + return nil, ErrRelayMinerConfigInvalidQueryNodeGRPCUrl.Wrapf("%s", err) } // Check that the network node websocket URL is provided - if yamlRelayMinerConfig.PocketNodeWebsocketUrl == "" { - return nil, ErrRelayMinerConfigInvalidPocketNodeWebsocketUrl.Wrapf("pocket node websocket url is required") + if yamlRelayMinerConfig.QueryNodeRPCUrl == "" { + return nil, ErrRelayMinerConfigInvalidQueryNodeRPCUrl.Wrapf("node rpc url is required") } - // Parse the websocket URL of the Pocket Node to connect to for subscribing to on-chain events. - pocketNodeWebsocketUrl, err := url.Parse(yamlRelayMinerConfig.PocketNodeWebsocketUrl) + // Parse the rpc URL of the Pocket Node to connect to for subscribing to on-chain events. + queryNodeRPCUrl, err := url.Parse(yamlRelayMinerConfig.QueryNodeRPCUrl) if err != nil { - return nil, ErrRelayMinerConfigInvalidPocketNodeWebsocketUrl.Wrapf("%s", err) + return nil, ErrRelayMinerConfigInvalidQueryNodeRPCUrl.Wrapf("%s", err) } if yamlRelayMinerConfig.SigningKeyName == "" { @@ -99,9 +97,8 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { relayMinerCMDConfig := &RelayMinerConfig{ QueryNodeGRPCUrl: queryNodeGRPCUrl, - NetworkNodeGRPCUrl: networkNodeGRPCUrl, - GRPCInsecure: yamlRelayMinerConfig.GRPCInsecure, - PocketNodeWebsocketUrl: pocketNodeWebsocketUrl, + TxNodeGRPCUrl: txNodeGRPCUrl, + QueryNodeRPCUrl: queryNodeRPCUrl, SigningKeyName: yamlRelayMinerConfig.SigningKeyName, ProxiedServiceEndpoints: proxiedServiceEndpoints, SmtStorePath: yamlRelayMinerConfig.SmtStorePath, diff --git a/pkg/relayer/config/relayminer_configs_reader_test.go b/pkg/relayer/config/relayminer_configs_reader_test.go index 4fcce0b74..135789021 100644 --- a/pkg/relayer/config/relayminer_configs_reader_test.go +++ b/pkg/relayer/config/relayminer_configs_reader_test.go @@ -26,10 +26,9 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "valid: relay miner config", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:26658 - network_node_grpc_url: tcp://127.0.0.1:36658 - grpc_insecure: true - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36658 + query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: http://anvil:8080 @@ -39,11 +38,10 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { expectedError: nil, expectedConfig: &config.RelayMinerConfig{ - QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:26658"}, - NetworkNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - GRPCInsecure: true, - PocketNodeWebsocketUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, - SigningKeyName: "servicer1", + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, + SigningKeyName: "servicer1", ProxiedServiceEndpoints: map[string]*url.URL{ "anvil": {Scheme: "http", Host: "anvil:8080"}, "svc1": {Scheme: "http", Host: "svc1:8080"}, @@ -52,12 +50,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { }, }, { - desc: "valid: relay miner config with undefined grpc insecure", + desc: "valid: relay miner config with query node grpc url defaulting to tx node grpc url", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:26658 - network_node_grpc_url: tcp://127.0.0.1:36658 - pocket_node_websocket_url: tcp://127.0.0.1:36657 + tx_node_grpc_url: tcp://127.0.0.1:36658 + query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: http://anvil:8080 @@ -67,11 +64,10 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { expectedError: nil, expectedConfig: &config.RelayMinerConfig{ - QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:26658"}, - NetworkNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - GRPCInsecure: false, - PocketNodeWebsocketUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, - SigningKeyName: "servicer1", + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, + SigningKeyName: "servicer1", ProxiedServiceEndpoints: map[string]*url.URL{ "anvil": {Scheme: "http", Host: "anvil:8080"}, "svc1": {Scheme: "http", Host: "svc1:8080"}, @@ -81,13 +77,12 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { }, // Invalid Configs { - desc: "invalid: invalid network node url", + desc: "invalid: invalid tx node grpc url", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:26658 - network_node_grpc_url: &tcp://127.0.0.1:36658 - grpc_insecure: true - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: &tcp://127.0.0.1:36658 + query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: http://anvil:8080 @@ -95,15 +90,14 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, }, { - desc: "invalid: missing network node url", + desc: "invalid: missing tx node grpc url", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:26658 - grpc_insecure: true - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: http://anvil:8080 @@ -111,16 +105,15 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, }, { - desc: "invalid: invalid query node url", + desc: "invalid: invalid query node grpc url", inputConfig: ` - query_node_grpc_url: &tcp://127.0.0.1:26658 - network_node_grpc_url: tcp://127.0.0.1:36658 - grpc_insecure: true - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_grpc_url: &tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36658 + query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: http://anvil:8080 @@ -128,15 +121,15 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, }, { - desc: "invalid: missing query node url", + desc: "invalid: missing query node rpc url", inputConfig: ` - network_node_grpc_url: tcp://128.0.0.1:36658 - grpc_insecure: true - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://128.0.0.1:36658 + tx_node_grpc_url: tcp://128.0.0.1:36658 + // explicitly missing query_node_rpc_url signing_key_name: servicer1 proxied_service_endpoints: anvil: http://anvil:8080 @@ -144,16 +137,15 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, }, { desc: "invalid: missing signing key name", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:26658 - network_node_grpc_url: &tcp://127.0.0.1:36658 - grpc_insecure: true - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: &tcp://127.0.0.1:36658 + query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: proxied_service_endpoints: anvil: http://anvil:8080 @@ -161,47 +153,44 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, }, { desc: "invalid: missing smt store path", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:26658 - network_node_grpc_url: &tcp://127.0.0.1:36658 - grpc_insecure - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: &tcp://127.0.0.1:36658 + query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: http://anvil:8080 svc1: http://svc1:8080 `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, }, { desc: "invalid: empty proxied service endpoints", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:26658 - network_node_grpc_url: &tcp://127.0.0.1:36658 - grpc_insecure: true - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: &tcp://127.0.0.1:36658 + query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, }, { desc: "invalid: invalid proxied service endpoint", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:26658 - network_node_grpc_url: &tcp://127.0.0.1:36658 - grpc_insecure: true - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: &tcp://127.0.0.1:36658 + query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: &http://anvil:8080 @@ -209,16 +198,15 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidNetworkNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, }, { - desc: "invalid: invalid network node url", + desc: "invalid: invalid tx node grpc url", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:26658 - network_node_grpc_url: &tcp://127.0.0.1:36658 - grpc_insecure: true - pocket_node_websocket_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: &tcp://127.0.0.1:36658 + query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 smt_store_path: smt_stores `, @@ -251,8 +239,9 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { require.NoError(t, err) + require.Equal(t, tt.expectedConfig.QueryNodeRPCUrl.String(), config.QueryNodeRPCUrl.String()) require.Equal(t, tt.expectedConfig.QueryNodeGRPCUrl.String(), config.QueryNodeGRPCUrl.String()) - require.Equal(t, tt.expectedConfig.NetworkNodeGRPCUrl.String(), config.NetworkNodeGRPCUrl.String()) + require.Equal(t, tt.expectedConfig.TxNodeGRPCUrl.String(), config.TxNodeGRPCUrl.String()) require.Equal(t, tt.expectedConfig.SigningKeyName, config.SigningKeyName) require.Equal(t, tt.expectedConfig.SmtStorePath, config.SmtStorePath) require.Equal(t, len(tt.expectedConfig.ProxiedServiceEndpoints), len(config.ProxiedServiceEndpoints)) From cad8f04d4dfc0a946b669745dbed3ad6d9f9f6fb Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Tue, 12 Dec 2023 23:20:27 +0100 Subject: [PATCH 13/34] chore: Revert reviewdog --- .github/workflows/reviewdog.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index 6c8473284..60d5ee2d5 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -7,6 +7,7 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }} cancel-in-progress: true + jobs: # Makes sure that comments like TODO_IN_THIS_PR or TODO_IN_THIS_COMMIT block # merging to main. See https://github.com/pokt-network/action-fail-on-found From 8d9588d993152eac923e144d2591d4778aca7bc3 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 13 Dec 2023 23:06:34 +0100 Subject: [PATCH 14/34] chore: Address request changes --- pkg/appgateserver/cmd/cmd.go | 5 ++-- .../config/appgate_configs_reader.go | 12 +++++--- .../config/appgate_configs_reader_test.go | 16 +++++------ pkg/appgateserver/config/errors.go | 1 + pkg/client/query/supplierquerier.go | 2 +- pkg/deps/config/suppliers.go | 13 ++++++++- pkg/relayer/cmd/cmd.go | 1 + pkg/relayer/config/errors.go | 1 + .../config/relayminer_configs_reader.go | 22 +++++++++------ .../config/relayminer_configs_reader_test.go | 28 +++++++++---------- 10 files changed, 62 insertions(+), 39 deletions(-) diff --git a/pkg/appgateserver/cmd/cmd.go b/pkg/appgateserver/cmd/cmd.go index 50ce78283..1b7e1f047 100644 --- a/pkg/appgateserver/cmd/cmd.go +++ b/pkg/appgateserver/cmd/cmd.go @@ -66,6 +66,7 @@ provided that: cmd.Flags().StringVar(&flagAppGateConfig, "config", "", "The path to the appgate config file") // Cosmos flags + // TODO_TECHDEBT(#256): Remove unneeded cosmos flags. cmd.Flags().String(cosmosflags.FlagKeyringBackend, "", "Select keyring's backend (os|file|kwallet|pass|test)") cmd.Flags().StringVar(&flagNodeRPCURL, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialize the Cosmos query context correctly. It can be used to override the `QueryNodeUrl` field in the config file if specified.") cmd.Flags().StringVar(&flagNodeGRPCURL, cosmosflags.FlagGRPC, omittedDefaultFlagValue, "Register the default Cosmos node grpc flag, which is needed to initialize the Cosmos query context with grpc correctly. It can be used to override the `QueryNodeGRPCUrl` field in the config file if specified.") @@ -152,7 +153,7 @@ func setupAppGateServerDependencies( // Override the config file's `QueryNodeGRPCUrl` field // with the `--grpc-addr` flag if it was specified. - // TODO(#223) Remove this check once viper is used as SoT for overridable config values. + // TODO_TECHDEBT(#223) Remove this check once viper is used as SoT for overridable config values. if flagNodeGRPCURL != omittedDefaultFlagValue { queryNodeGRPCURL, err = url.Parse(flagNodeGRPCURL) if err != nil { @@ -162,7 +163,7 @@ func setupAppGateServerDependencies( // Override the config file's `QueryNodeRPCURL` field // with the `--node` flag if it was specified. - // TODO(#223) Remove this check once viper is used as SoT for overridable config values. + // TODO_TECHDEBT(#223) Remove this check once viper is used as SoT for overridable config values. if flagNodeRPCURL != omittedDefaultFlagValue { queryNodeRPCURL, err = url.Parse(flagNodeRPCURL) if err != nil { diff --git a/pkg/appgateserver/config/appgate_configs_reader.go b/pkg/appgateserver/config/appgate_configs_reader.go index 36f74043e..ba03f8242 100644 --- a/pkg/appgateserver/config/appgate_configs_reader.go +++ b/pkg/appgateserver/config/appgate_configs_reader.go @@ -30,9 +30,13 @@ type AppGateServerConfig struct { func ParseAppGateServerConfigs(configContent []byte) (*AppGateServerConfig, error) { var yamlAppGateServerConfig YAMLAppGateServerConfig + if len(configContent) == 0 { + return nil, ErrAppGateConfigEmpty + } + // Unmarshal the stake config file into a yamlAppGateConfig if err := yaml.Unmarshal(configContent, &yamlAppGateServerConfig); err != nil { - return nil, ErrAppGateConfigUnmarshalYAML.Wrapf("%s", err) + return nil, ErrAppGateConfigUnmarshalYAML.Wrap(err.Error()) } if yamlAppGateServerConfig.SigningKey == "" { @@ -45,7 +49,7 @@ func ParseAppGateServerConfigs(configContent []byte) (*AppGateServerConfig, erro listeningEndpoint, err := url.Parse(yamlAppGateServerConfig.ListeningEndpoint) if err != nil { - return nil, ErrAppGateConfigInvalidListeningEndpoint.Wrapf("%s", err) + return nil, ErrAppGateConfigInvalidListeningEndpoint.Wrap(err.Error()) } if yamlAppGateServerConfig.QueryNodeGRPCUrl == "" { @@ -54,7 +58,7 @@ func ParseAppGateServerConfigs(configContent []byte) (*AppGateServerConfig, erro queryNodeGRPCUrl, err := url.Parse(yamlAppGateServerConfig.QueryNodeGRPCUrl) if err != nil { - return nil, ErrAppGateConfigInvalidQueryNodeGRPCUrl.Wrapf("%s", err) + return nil, ErrAppGateConfigInvalidQueryNodeGRPCUrl.Wrap(err.Error()) } if yamlAppGateServerConfig.QueryNodeRPCUrl == "" { @@ -63,7 +67,7 @@ func ParseAppGateServerConfigs(configContent []byte) (*AppGateServerConfig, erro queryNodeRPCUrl, err := url.Parse(yamlAppGateServerConfig.QueryNodeRPCUrl) if err != nil { - return nil, ErrAppGateConfigInvalidQueryNodeRPCUrl.Wrapf("%s", err) + return nil, ErrAppGateConfigInvalidQueryNodeRPCUrl.Wrap(err.Error()) } // Populate the appGateServerConfig with the values from the yamlAppGateServerConfig diff --git a/pkg/appgateserver/config/appgate_configs_reader_test.go b/pkg/appgateserver/config/appgate_configs_reader_test.go index 8f784f65b..28316a488 100644 --- a/pkg/appgateserver/config/appgate_configs_reader_test.go +++ b/pkg/appgateserver/config/appgate_configs_reader_test.go @@ -67,7 +67,7 @@ func Test_ParseAppGateConfigs(t *testing.T) { inputConfig: ``, - expectedError: config.ErrAppGateConfigUnmarshalYAML, + expectedError: config.ErrAppGateConfigEmpty, }, { desc: "invalid: no signing key", @@ -80,7 +80,7 @@ func Test_ParseAppGateConfigs(t *testing.T) { query_node_rpc_url: tcp://127.0.0.1:36657 `, - expectedError: config.ErrAppGateConfigEmptySigningKey, + expectedError: config.ErrAppGateConfigUnmarshalYAML, }, { desc: "invalid: invalid listening endpoint", @@ -88,7 +88,7 @@ func Test_ParseAppGateConfigs(t *testing.T) { inputConfig: ` self_signing: true signing_key: app1 - listening_endpoint: &localhost:42069 + listening_endpoint: l&ocalhost:42069 query_node_grpc_url: tcp://127.0.0.1:36658 query_node_rpc_url: tcp://127.0.0.1:36657 `, @@ -102,7 +102,7 @@ func Test_ParseAppGateConfigs(t *testing.T) { self_signing: true signing_key: app1 listening_endpoint: http://localhost:42069 - query_node_grpc_url: &127.0.0.1:36658 + query_node_grpc_url: 1&27.0.0.1:36658 query_node_rpc_url: tcp://127.0.0.1:36657 `, @@ -119,7 +119,7 @@ func Test_ParseAppGateConfigs(t *testing.T) { query_node_rpc_url: tcp://127.0.0.1:36657 `, - expectedError: config.ErrAppGateConfigInvalidQueryNodeGRPCUrl, + expectedError: config.ErrAppGateConfigUnmarshalYAML, }, { desc: "invalid: invalid query node rpc url", @@ -129,7 +129,7 @@ func Test_ParseAppGateConfigs(t *testing.T) { signing_key: app1 listening_endpoint: http://localhost:42069 query_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: &127.0.0.1:36657 + query_node_rpc_url: 1&27.0.0.1:36657 `, expectedError: config.ErrAppGateConfigInvalidQueryNodeRPCUrl, @@ -145,7 +145,7 @@ func Test_ParseAppGateConfigs(t *testing.T) { // explicitly missing query_node_rpc_url `, - expectedError: config.ErrAppGateConfigInvalidQueryNodeRPCUrl, + expectedError: config.ErrAppGateConfigUnmarshalYAML, }, } @@ -155,7 +155,7 @@ func Test_ParseAppGateConfigs(t *testing.T) { config, err := config.ParseAppGateServerConfigs([]byte(normalizedConfig)) if tt.expectedError != nil { - require.Error(t, err) + require.ErrorIs(t, err, tt.expectedError) require.Nil(t, config) stat, ok := status.FromError(tt.expectedError) require.True(t, ok) diff --git a/pkg/appgateserver/config/errors.go b/pkg/appgateserver/config/errors.go index 00023cd35..450c75378 100644 --- a/pkg/appgateserver/config/errors.go +++ b/pkg/appgateserver/config/errors.go @@ -9,4 +9,5 @@ var ( ErrAppGateConfigInvalidListeningEndpoint = sdkerrors.Register(codespace, 3, "invalid listening endpoint in AppGateServer config") ErrAppGateConfigInvalidQueryNodeGRPCUrl = sdkerrors.Register(codespace, 4, "invalid query node grpc url in AppGateServer config") ErrAppGateConfigInvalidQueryNodeRPCUrl = sdkerrors.Register(codespace, 5, "invalid query node rpc url in AppGateServer config") + ErrAppGateConfigEmpty = sdkerrors.Register(codespace, 6, "empty AppGateServer config") ) diff --git a/pkg/client/query/supplierquerier.go b/pkg/client/query/supplierquerier.go index e476995d9..c622ad9e5 100644 --- a/pkg/client/query/supplierquerier.go +++ b/pkg/client/query/supplierquerier.go @@ -23,7 +23,7 @@ type supplierQuerier struct { // injecting the dependecies provided by the depinject.Config. // // Required dependencies: -// - clientConn +// - grpc.ClientConn func NewSupplierQuerier(deps depinject.Config) (client.SupplierQueryClient, error) { supq := &supplierQuerier{} diff --git a/pkg/deps/config/suppliers.go b/pkg/deps/config/suppliers.go index 1ecdc05f7..9bd2adf1b 100644 --- a/pkg/deps/config/suppliers.go +++ b/pkg/deps/config/suppliers.go @@ -105,6 +105,8 @@ func NewSupplyQueryClientContextFn(queryNodeGRPCURL *url.URL) SupplierFn { // Set --grpc-addr flag to the pocketQueryNodeURL for the client context // This flag is read by cosmosclient.GetClientQueryContext. + // Cosmos-SDK is expecting a GRPC address formatted as [:], + // so we only need to set the Host parameter of the URL to cosmosflags.FlagGRPC value. if err := cmd.Flags().Set(cosmosflags.FlagGRPC, queryNodeGRPCURL.Host); err != nil { return nil, err } @@ -144,10 +146,16 @@ func NewSupplyTxClientContextFn(txNodeGRPCURL *url.URL) SupplierFn { cmd *cobra.Command, ) (depinject.Config, error) { // Temporarily store the flag's current value - tmpGRPC := cosmosflags.FlagGRPC + // TODO_TECHDEBT(#223) Retrieve value from viper instead, once integrated. + tmpGRPC, err := cmd.Flags().GetString(cosmosflags.FlagGRPC) + if err != nil { + return nil, err + } // Set --node flag to the pocketTxNodeURL for the client context // This flag is read by cosmosclient.GetClientTxContext. + // Cosmos-SDK is expecting a GRPC address formatted as [:], + // so we only need to set the Host parameter of the URL to cosmosflags.FlagGRPC value. if err := cmd.Flags().Set(cosmosflags.FlagGRPC, txNodeGRPCURL.Host); err != nil { return nil, err } @@ -316,6 +324,9 @@ func NewSupplyPOKTRollSDKFn(signingKeyName string) SupplierFn { } } +// queryNodeToWebsocketURL converts a query node URL to a CometBFT websocket URL. +// It takes the Host property of the queryNode URL and returns it as a websocket URL +// formatted as ws://:/websocket. func queryNodeToWebsocketURL(queryNode *url.URL) string { return fmt.Sprintf("ws://%s/websocket", queryNode.Host) } diff --git a/pkg/relayer/cmd/cmd.go b/pkg/relayer/cmd/cmd.go index 0c45990d9..f4d95a0b8 100644 --- a/pkg/relayer/cmd/cmd.go +++ b/pkg/relayer/cmd/cmd.go @@ -64,6 +64,7 @@ for such operations.`, cmd.Flags().StringVar(&flagRelayMinerConfig, "config", "", "The path to the relayminer config file") // Cosmos flags + // TODO_TECHDEBT(#256): Remove unneeded cosmos flags. cmd.Flags().String(cosmosflags.FlagKeyringBackend, "", "Select keyring's backend (os|file|kwallet|pass|test)") cmd.Flags().StringVar(&flagNodeRPCUrl, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialize the Cosmos query and tx contexts correctly. It can be used to override the `QueryNodeUrl` and `NetworkNodeUrl` fields in the config file if specified.") cmd.Flags().StringVar(&flagNodeGRPCUrl, cosmosflags.FlagGRPC, omittedDefaultFlagValue, "Register the default Cosmos node grpc flag, which is needed to initialize the Cosmos query context with grpc correctly. It can be used to override the `QueryNodeGRPCUrl` field in the config file if specified.") diff --git a/pkg/relayer/config/errors.go b/pkg/relayer/config/errors.go index bf2b52a6a..43bd9f417 100644 --- a/pkg/relayer/config/errors.go +++ b/pkg/relayer/config/errors.go @@ -11,4 +11,5 @@ var ( ErrRelayMinerConfigInvalidServiceEndpoint = sdkerrors.Register(codespace, 5, "invalid service endpoint in RelayMiner config") ErrRelayMinerConfigInvalidSigningKeyName = sdkerrors.Register(codespace, 6, "invalid signing key name in RelayMiner config") ErrRelayMinerConfigInvalidSmtStorePath = sdkerrors.Register(codespace, 7, "invalid smt store path in RelayMiner config") + ErrRelayMinerConfigEmpty = sdkerrors.Register(codespace, 8, "empty RelayMiner config") ) diff --git a/pkg/relayer/config/relayminer_configs_reader.go b/pkg/relayer/config/relayminer_configs_reader.go index 9385108dd..0667061fd 100644 --- a/pkg/relayer/config/relayminer_configs_reader.go +++ b/pkg/relayer/config/relayminer_configs_reader.go @@ -31,20 +31,24 @@ type RelayMinerConfig struct { func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { var yamlRelayMinerConfig YAMLRelayMinerConfig + if len(configContent) == 0 { + return nil, ErrRelayMinerConfigEmpty + } + // Unmarshal the stake config file into a yamlAppGateConfig if err := yaml.Unmarshal(configContent, &yamlRelayMinerConfig); err != nil { - return nil, ErrRelayMinerConfigUnmarshalYAML.Wrapf("%s", err) + return nil, ErrRelayMinerConfigUnmarshalYAML.Wrap(err.Error()) } // Check that the tx node GRPC URL is provided if yamlRelayMinerConfig.TxNodeGRPCUrl == "" { - return nil, ErrRelayMinerConfigInvalidTxNodeGRPCUrl.Wrapf("tx node grpc url is required") + return nil, ErrRelayMinerConfigInvalidTxNodeGRPCUrl.Wrap("tx node grpc url is required") } // Parse the tx node GRPC URL txNodeGRPCUrl, err := url.Parse(yamlRelayMinerConfig.TxNodeGRPCUrl) if err != nil { - return nil, ErrRelayMinerConfigInvalidTxNodeGRPCUrl.Wrapf("%s", err) + return nil, ErrRelayMinerConfigInvalidTxNodeGRPCUrl.Wrap(err.Error()) } // Check that the query node GRPC URL is provided and default to the tx node GRPC URL if not @@ -55,18 +59,18 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { // Parse the query node GRPC URL queryNodeGRPCUrl, err := url.Parse(yamlRelayMinerConfig.QueryNodeGRPCUrl) if err != nil { - return nil, ErrRelayMinerConfigInvalidQueryNodeGRPCUrl.Wrapf("%s", err) + return nil, ErrRelayMinerConfigInvalidQueryNodeGRPCUrl.Wrap(err.Error()) } // Check that the network node websocket URL is provided if yamlRelayMinerConfig.QueryNodeRPCUrl == "" { - return nil, ErrRelayMinerConfigInvalidQueryNodeRPCUrl.Wrapf("node rpc url is required") + return nil, ErrRelayMinerConfigInvalidQueryNodeRPCUrl.Wrap("query node rpc url is required") } // Parse the rpc URL of the Pocket Node to connect to for subscribing to on-chain events. queryNodeRPCUrl, err := url.Parse(yamlRelayMinerConfig.QueryNodeRPCUrl) if err != nil { - return nil, ErrRelayMinerConfigInvalidQueryNodeRPCUrl.Wrapf("%s", err) + return nil, ErrRelayMinerConfigInvalidQueryNodeRPCUrl.Wrap(err.Error()) } if yamlRelayMinerConfig.SigningKeyName == "" { @@ -78,11 +82,11 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { } if yamlRelayMinerConfig.ProxiedServiceEndpoints == nil { - return nil, ErrRelayMinerConfigInvalidServiceEndpoint.Wrapf("proxied service endpoints are required") + return nil, ErrRelayMinerConfigInvalidServiceEndpoint.Wrap("proxied service endpoints are required") } if len(yamlRelayMinerConfig.ProxiedServiceEndpoints) == 0 { - return nil, ErrRelayMinerConfigInvalidServiceEndpoint.Wrapf("no proxied service endpoints provided") + return nil, ErrRelayMinerConfigInvalidServiceEndpoint.Wrap("no proxied service endpoints provided") } // Parse the proxied service endpoints @@ -90,7 +94,7 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { for serviceId, endpointUrl := range yamlRelayMinerConfig.ProxiedServiceEndpoints { endpoint, err := url.Parse(endpointUrl) if err != nil { - return nil, ErrRelayMinerConfigInvalidServiceEndpoint.Wrapf("%s", err) + return nil, ErrRelayMinerConfigInvalidServiceEndpoint.Wrap(err.Error()) } proxiedServiceEndpoints[serviceId] = endpoint } diff --git a/pkg/relayer/config/relayminer_configs_reader_test.go b/pkg/relayer/config/relayminer_configs_reader_test.go index 135789021..705ce0176 100644 --- a/pkg/relayer/config/relayminer_configs_reader_test.go +++ b/pkg/relayer/config/relayminer_configs_reader_test.go @@ -121,7 +121,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidQueryNodeGRPCUrl, }, { desc: "invalid: missing query node rpc url", @@ -137,30 +137,30 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigUnmarshalYAML, }, { desc: "invalid: missing signing key name", inputConfig: ` query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: &tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36658 query_node_rpc_url: tcp://127.0.0.1:36657 - signing_key_name: + // explicitly missing signing_key_name proxied_service_endpoints: anvil: http://anvil:8080 svc1: http://svc1:8080 smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigUnmarshalYAML, }, { desc: "invalid: missing smt store path", inputConfig: ` query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: &tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36658 query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: @@ -168,28 +168,28 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { svc1: http://svc1:8080 `, - expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidSmtStorePath, }, { desc: "invalid: empty proxied service endpoints", inputConfig: ` query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: &tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36658 query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidServiceEndpoint, }, { desc: "invalid: invalid proxied service endpoint", inputConfig: ` query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: &tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36658 query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: @@ -198,7 +198,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidServiceEndpoint, }, { desc: "invalid: invalid tx node grpc url", @@ -211,14 +211,14 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores `, - expectedError: config.ErrRelayMinerConfigUnmarshalYAML, + expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, }, { desc: "invalid: empty RelayMiner config file", inputConfig: ``, - expectedError: config.ErrRelayMinerConfigUnmarshalYAML, + expectedError: config.ErrRelayMinerConfigEmpty, }, } @@ -228,7 +228,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { config, err := config.ParseRelayMinerConfigs([]byte(normalizedConfig)) if tt.expectedError != nil { - require.Error(t, err) + require.ErrorIs(t, err, tt.expectedError) require.Nil(t, config) stat, ok := status.FromError(tt.expectedError) require.True(t, ok) From 8b1465c0794c23f2c900dd90a4e53c28a2722e10 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 13 Dec 2023 23:10:25 +0100 Subject: [PATCH 15/34] chore: Fix temp assignment of FlagGRPC --- pkg/deps/config/suppliers.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/deps/config/suppliers.go b/pkg/deps/config/suppliers.go index 9bd2adf1b..08e9bef13 100644 --- a/pkg/deps/config/suppliers.go +++ b/pkg/deps/config/suppliers.go @@ -101,7 +101,11 @@ func NewSupplyQueryClientContextFn(queryNodeGRPCURL *url.URL) SupplierFn { cmd *cobra.Command, ) (depinject.Config, error) { // Temporarily store the flag's current value - tmpGRPC := cosmosflags.FlagGRPC + // TODO_TECHDEBT(#223) Retrieve value from viper instead, once integrated. + tmpGRPC, err := cmd.Flags().GetString(cosmosflags.FlagGRPC) + if err != nil { + return nil, err + } // Set --grpc-addr flag to the pocketQueryNodeURL for the client context // This flag is read by cosmosclient.GetClientQueryContext. From 6c51872d96b85c820ce99c31b13a194fc415cddd Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 15 Dec 2023 07:09:19 +0100 Subject: [PATCH 16/34] feat: [WIP] Implement new replayminer config --- pkg/relayer/cmd/cmd.go | 10 +- pkg/relayer/config/errors.go | 17 +- .../config/proxy_http_config_parser.go | 55 ++++ .../config/relayminer_configs_reader.go | 262 +++++++++++++----- pkg/relayer/config/types.go | 127 +++++++++ pkg/relayer/interface.go | 3 - pkg/relayer/proxy/errors.go | 2 + pkg/relayer/proxy/options.go | 5 +- pkg/relayer/proxy/proxy.go | 35 +-- pkg/relayer/proxy/proxy_test.go | 98 +++++-- pkg/relayer/proxy/server_builder.go | 91 +++--- pkg/relayer/proxy/synchronous.go | 72 +++-- testutil/testproxy/relayerproxy.go | 6 +- 13 files changed, 582 insertions(+), 201 deletions(-) create mode 100644 pkg/relayer/config/proxy_http_config_parser.go create mode 100644 pkg/relayer/config/types.go diff --git a/pkg/relayer/cmd/cmd.go b/pkg/relayer/cmd/cmd.go index f4d95a0b8..972d5b149 100644 --- a/pkg/relayer/cmd/cmd.go +++ b/pkg/relayer/cmd/cmd.go @@ -136,9 +136,9 @@ func setupRelayerDependencies( cmd *cobra.Command, relayMinerConfig *relayerconfig.RelayMinerConfig, ) (deps depinject.Config, err error) { - parsedFlagNodeRPCUrl := relayMinerConfig.QueryNodeRPCUrl - queryNodeGRPCUrl := relayMinerConfig.QueryNodeGRPCUrl - txNodeGRPCUrl := relayMinerConfig.TxNodeGRPCUrl + parsedFlagNodeRPCUrl := relayMinerConfig.Pocket.QueryNodeRPCUrl + queryNodeGRPCUrl := relayMinerConfig.Pocket.QueryNodeGRPCUrl + txNodeGRPCUrl := relayMinerConfig.Pocket.TxNodeGRPCUrl // Override the config file's `QueryNodeGRPCUrl` and `NetworkNodeGRPCUrl` fields // with the `--grpc-addr` flag if it was specified. @@ -163,7 +163,7 @@ func setupRelayerDependencies( } signingKeyName := relayMinerConfig.SigningKeyName - proxiedServiceEndpoints := relayMinerConfig.ProxiedServiceEndpoints + proxiedServiceEndpoints := relayMinerConfig.Proxies smtStorePath := relayMinerConfig.SmtStorePath supplierFuncs := []config.SupplierFn{ @@ -289,7 +289,7 @@ func newSupplySupplierClientFn(signingKeyName string) config.SupplierFn { // is supplied with the given deps and the new RelayerProxy. func newSupplyRelayerProxyFn( signingKeyName string, - proxiedServiceEndpoints map[string]*url.URL, + proxiedServiceEndpoints map[string]*relayerconfig.RelayMinerProxyConfig, ) config.SupplierFn { return func( _ context.Context, diff --git a/pkg/relayer/config/errors.go b/pkg/relayer/config/errors.go index 43bd9f417..eace596e3 100644 --- a/pkg/relayer/config/errors.go +++ b/pkg/relayer/config/errors.go @@ -3,13 +3,12 @@ package config import sdkerrors "cosmossdk.io/errors" var ( - codespace = "relayminer_config" - ErrRelayMinerConfigUnmarshalYAML = sdkerrors.Register(codespace, 1, "config reader cannot unmarshal yaml content") - ErrRelayMinerConfigInvalidQueryNodeGRPCUrl = sdkerrors.Register(codespace, 2, "invalid query node grpc url in RelayMiner config") - ErrRelayMinerConfigInvalidTxNodeGRPCUrl = sdkerrors.Register(codespace, 3, "invalid tx node grpc url in RelayMiner config") - ErrRelayMinerConfigInvalidQueryNodeRPCUrl = sdkerrors.Register(codespace, 4, "invalid query node rpc url in RelayMiner config") - ErrRelayMinerConfigInvalidServiceEndpoint = sdkerrors.Register(codespace, 5, "invalid service endpoint in RelayMiner config") - ErrRelayMinerConfigInvalidSigningKeyName = sdkerrors.Register(codespace, 6, "invalid signing key name in RelayMiner config") - ErrRelayMinerConfigInvalidSmtStorePath = sdkerrors.Register(codespace, 7, "invalid smt store path in RelayMiner config") - ErrRelayMinerConfigEmpty = sdkerrors.Register(codespace, 8, "empty RelayMiner config") + codespace = "relayminer_config" + ErrRelayMinerConfigUnmarshalYAML = sdkerrors.Register(codespace, 1, "config reader cannot unmarshal yaml content") + ErrRelayMinerConfigInvalidNodeUrl = sdkerrors.Register(codespace, 2, "invalid node url in RelayMiner config") + ErrRelayMinerConfigInvalidSigningKeyName = sdkerrors.Register(codespace, 3, "invalid signing key name in RelayMiner config") + ErrRelayMinerConfigInvalidSmtStorePath = sdkerrors.Register(codespace, 4, "invalid smt store path in RelayMiner config") + ErrRelayMinerConfigEmpty = sdkerrors.Register(codespace, 5, "empty RelayMiner config") + ErrRelayMinerConfigInvalidSupplier = sdkerrors.Register(codespace, 6, "invalid supplier in RelayMiner config") + ErrRelayMinerConfigInvalidProxy = sdkerrors.Register(codespace, 7, "invalid proxy in RelayMiner config") ) diff --git a/pkg/relayer/config/proxy_http_config_parser.go b/pkg/relayer/config/proxy_http_config_parser.go new file mode 100644 index 000000000..02251a0e4 --- /dev/null +++ b/pkg/relayer/config/proxy_http_config_parser.go @@ -0,0 +1,55 @@ +package config + +import "net/url" + +// parseRelayMinerConfigs populates the proxy fields of the target structure that +// are relevant to the "http" type in the proxy section of the config file. +func parseHTTPProxyConfig( + yamlProxyConfig YAMLRelayMinerProxyConfig, + proxyConfig *RelayMinerProxyConfig, +) error { + // Check if the proxy host is a valid URL + proxyUrl, err := url.Parse(yamlProxyConfig.Host) + if err != nil { + return ErrRelayMinerConfigInvalidProxy.Wrapf( + "invalid proxy host %s", + err.Error(), + ) + } + + proxyConfig.Host = proxyUrl.Host + return nil +} + +// parseRelayMinerConfigs populates the supplier fields of the target structure +// that are relevant to the "http" type in the supplier section of the config file. +func parseHTTPSupplierConfig( + yamlSupplierServiceConfig YAMLRelayMinerSupplierServiceConfig, + supplierServiceConfig *RelayMinerSupplierServiceConfig, +) error { + var err error + // Check if the supplier url is a valid URL + supplierServiceConfig.Url, err = url.Parse(yamlSupplierServiceConfig.Url) + if err != nil { + return ErrRelayMinerConfigInvalidSupplier.Wrapf( + "invalid supplier url %s", + err.Error(), + ) + } + + // If the Authentication section is not empty, populate the supplier service + // authentication fields + if yamlSupplierServiceConfig.Authentication != (YAMLRelayMinerSupplierServiceAuthentication{}) { + supplierServiceConfig.Authentication = &RelayMinerSupplierServiceAuthentication{ + Username: yamlSupplierServiceConfig.Authentication.Username, + Password: yamlSupplierServiceConfig.Authentication.Password, + } + } + + // If the Headers section is not empty, populate the supplier service headers fields + if yamlSupplierServiceConfig.Headers != nil { + supplierServiceConfig.Headers = yamlSupplierServiceConfig.Headers + } + + return nil +} diff --git a/pkg/relayer/config/relayminer_configs_reader.go b/pkg/relayer/config/relayminer_configs_reader.go index 0667061fd..4c2c42ad7 100644 --- a/pkg/relayer/config/relayminer_configs_reader.go +++ b/pkg/relayer/config/relayminer_configs_reader.go @@ -6,31 +6,14 @@ import ( "gopkg.in/yaml.v2" ) -// YAMLRelayMinerConfig is the structure used to unmarshal the RelayMiner config file -// TODO_DOCUMENT(@red-0ne): Add proper README documentation for yaml config files. -type YAMLRelayMinerConfig struct { - QueryNodeGRPCUrl string `yaml:"query_node_grpc_url"` - TxNodeGRPCUrl string `yaml:"tx_node_grpc_url"` - QueryNodeRPCUrl string `yaml:"query_node_rpc_url"` - SigningKeyName string `yaml:"signing_key_name"` - ProxiedServiceEndpoints map[string]string `yaml:"proxied_service_endpoints"` - SmtStorePath string `yaml:"smt_store_path"` -} - -// RelayMinerConfig is the structure describing the RelayMiner config -type RelayMinerConfig struct { - QueryNodeGRPCUrl *url.URL - TxNodeGRPCUrl *url.URL - QueryNodeRPCUrl *url.URL - SigningKeyName string - ProxiedServiceEndpoints map[string]*url.URL - SmtStorePath string -} - // ParseRelayMinerConfigs parses the relay miner config file into a RelayMinerConfig func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { - var yamlRelayMinerConfig YAMLRelayMinerConfig + var ( + yamlRelayMinerConfig YAMLRelayMinerConfig + err error + ) + // The config file should not be empty if len(configContent) == 0 { return nil, ErrRelayMinerConfigEmpty } @@ -40,72 +23,223 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { return nil, ErrRelayMinerConfigUnmarshalYAML.Wrap(err.Error()) } - // Check that the tx node GRPC URL is provided - if yamlRelayMinerConfig.TxNodeGRPCUrl == "" { - return nil, ErrRelayMinerConfigInvalidTxNodeGRPCUrl.Wrap("tx node grpc url is required") + // Top level section + // SigningKeyName is required + if yamlRelayMinerConfig.SigningKeyName == "" { + return nil, ErrRelayMinerConfigInvalidSigningKeyName } - // Parse the tx node GRPC URL - txNodeGRPCUrl, err := url.Parse(yamlRelayMinerConfig.TxNodeGRPCUrl) - if err != nil { - return nil, ErrRelayMinerConfigInvalidTxNodeGRPCUrl.Wrap(err.Error()) + // SmtStorePath is required + if yamlRelayMinerConfig.SmtStorePath == "" { + return nil, ErrRelayMinerConfigInvalidSmtStorePath } - // Check that the query node GRPC URL is provided and default to the tx node GRPC URL if not - if yamlRelayMinerConfig.QueryNodeGRPCUrl == "" { - yamlRelayMinerConfig.QueryNodeGRPCUrl = yamlRelayMinerConfig.TxNodeGRPCUrl - } + // Pocket node urls section + relayMinerPocketConfig := &RelayMinerPocketConfig{} + pocket := yamlRelayMinerConfig.Pocket - // Parse the query node GRPC URL - queryNodeGRPCUrl, err := url.Parse(yamlRelayMinerConfig.QueryNodeGRPCUrl) + // Check if the pocket node grpc url is a valid URL + relayMinerPocketConfig.TxNodeGRPCUrl, err = url.Parse(pocket.TxNodeGRPCUrl) if err != nil { - return nil, ErrRelayMinerConfigInvalidQueryNodeGRPCUrl.Wrap(err.Error()) + return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrapf( + "invalid tx node grpc url %s", + err.Error(), + ) } - // Check that the network node websocket URL is provided - if yamlRelayMinerConfig.QueryNodeRPCUrl == "" { - return nil, ErrRelayMinerConfigInvalidQueryNodeRPCUrl.Wrap("query node rpc url is required") + // If the query node grpc url is empty, use the tx node grpc url + if pocket.QueryNodeGRPCUrl == "" { + relayMinerPocketConfig.QueryNodeGRPCUrl = relayMinerPocketConfig.TxNodeGRPCUrl + } else { + // If the query node grpc url is not empty, make sure it is a valid URL + relayMinerPocketConfig.QueryNodeGRPCUrl, err = url.Parse(pocket.QueryNodeGRPCUrl) + if err != nil { + return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrapf( + "invalid query node grpc url %s", + err.Error(), + ) + } } - // Parse the rpc URL of the Pocket Node to connect to for subscribing to on-chain events. - queryNodeRPCUrl, err := url.Parse(yamlRelayMinerConfig.QueryNodeRPCUrl) + // Check if the query node rpc url is a valid URL + relayMinerPocketConfig.QueryNodeRPCUrl, err = url.Parse(pocket.QueryNodeRPCUrl) if err != nil { - return nil, ErrRelayMinerConfigInvalidQueryNodeRPCUrl.Wrap(err.Error()) + return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrapf( + "invalid query node rpc url %s", + err.Error(), + ) } - if yamlRelayMinerConfig.SigningKeyName == "" { - return nil, ErrRelayMinerConfigInvalidSigningKeyName + // Proxies section + // At least one proxy is required + if len(yamlRelayMinerConfig.Proxies) == 0 { + return nil, ErrRelayMinerConfigInvalidProxy.Wrap("no proxies provided") } - if yamlRelayMinerConfig.SmtStorePath == "" { - return nil, ErrRelayMinerConfigInvalidSmtStorePath - } + proxies := yamlRelayMinerConfig.Proxies + relayMinerProxiesConfig := make(map[string]*RelayMinerProxyConfig) - if yamlRelayMinerConfig.ProxiedServiceEndpoints == nil { - return nil, ErrRelayMinerConfigInvalidServiceEndpoint.Wrap("proxied service endpoints are required") + for _, yamlProxyConfig := range proxies { + // Proxy name is required + if yamlProxyConfig.Name == "" { + return nil, ErrRelayMinerConfigInvalidProxy.Wrap("proxy name is required") + } + + // Proxy name should not be unique + if _, ok := relayMinerProxiesConfig[yamlProxyConfig.Name]; ok { + return nil, ErrRelayMinerConfigInvalidProxy.Wrapf( + "duplicate porxy name %s", + yamlProxyConfig.Name, + ) + } + + proxyConfig := &RelayMinerProxyConfig{ + Name: yamlProxyConfig.Name, + Suppliers: make(map[string]*RelayMinerSupplierConfig), + } + + // Populate the proxy fields that are relevant to each supported proxy type + switch yamlProxyConfig.Type { + case "http": + if err := parseHTTPProxyConfig(yamlProxyConfig, proxyConfig); err != nil { + return nil, err + } + default: + // Fail if the proxy type is not supported + return nil, ErrRelayMinerConfigInvalidProxy.Wrapf( + "invalid proxy type %s", + yamlProxyConfig.Type, + ) + } + proxyConfig.Type = yamlProxyConfig.Type + + relayMinerProxiesConfig[proxyConfig.Name] = proxyConfig } - if len(yamlRelayMinerConfig.ProxiedServiceEndpoints) == 0 { - return nil, ErrRelayMinerConfigInvalidServiceEndpoint.Wrap("no proxied service endpoints provided") + // Suppliers section + suppliers := yamlRelayMinerConfig.Suppliers + relayMinerSuppliersConfig := make(map[string]*RelayMinerSupplierConfig) + + for _, yamlSupplierConfig := range suppliers { + // Supplier name is required + if yamlSupplierConfig.Name == "" { + return nil, ErrRelayMinerConfigInvalidSupplier.Wrap("supplier name is required") + } + + // Supplier name should not be unique + if _, ok := relayMinerSuppliersConfig[yamlSupplierConfig.Name]; ok { + return nil, ErrRelayMinerConfigInvalidSupplier.Wrapf( + "duplicate supplier name %s", + yamlSupplierConfig.Name, + ) + } + + supplierConfig := &RelayMinerSupplierConfig{ + Name: yamlSupplierConfig.Name, + Hosts: []string{}, + ServiceConfig: &RelayMinerSupplierServiceConfig{}, + } + + // Supplier hosts sub-section + existingHosts := make(map[string]bool) + for _, host := range yamlSupplierConfig.Hosts { + // Check if the supplier host is a valid URL + supplierHost, err := url.Parse(host) + if err != nil { + return nil, ErrRelayMinerConfigInvalidSupplier.Wrapf( + "invalid supplier host %s", + host, + ) + } + + // Check if the supplier host is unique + if _, ok := existingHosts[supplierHost.Host]; ok { + return nil, ErrRelayMinerConfigInvalidSupplier.Wrapf( + "duplicate supplier host %s", + host, + ) + } + existingHosts[supplierHost.Host] = true + + // Add the supplier host to the suppliers list + supplierConfig.Hosts = append(supplierConfig.Hosts, supplierHost.Host) + } + + // Add a default host which corresponds to the supplier name if it is not + // already in the list + if _, ok := existingHosts[supplierConfig.Name]; !ok { + supplierConfig.Hosts = append(supplierConfig.Hosts, supplierConfig.Name) + } + + // Supplier service sub-section + // Populate the supplier service fields that are relevant to each supported + // supplier type. + // If other supplier types are added in the future, they should be handled + // by their own functions. + switch yamlSupplierConfig.Type { + case "http": + if err := parseHTTPSupplierConfig( + yamlSupplierConfig.ServiceConfig, + supplierConfig.ServiceConfig, + ); err != nil { + return nil, err + } + default: + // Fail if the supplier type is not supported + return nil, ErrRelayMinerConfigInvalidSupplier.Wrapf( + "invalid supplier type %s", + yamlSupplierConfig.Type, + ) + } + supplierConfig.Type = yamlSupplierConfig.Type + + // Add the supplier config to the referenced proxies + for _, proxyName := range yamlSupplierConfig.ProxyNames { + // If the proxy name is referencing a non-existent proxy, fail + if _, ok := relayMinerProxiesConfig[proxyName]; !ok { + return nil, ErrRelayMinerConfigInvalidSupplier.Wrapf( + "no matching proxy %s for supplier %s", + supplierConfig.Name, + proxyName, + ) + } + + // If the proxy name is referencing a proxy of a different type, fail + if supplierConfig.Type != relayMinerProxiesConfig[proxyName].Type { + return nil, ErrRelayMinerConfigInvalidSupplier.Wrapf( + "supplier %s and proxy %s have different types", + supplierConfig.Name, + proxyName, + ) + } + + relayMinerProxiesConfig[proxyName].Suppliers[supplierConfig.Name] = supplierConfig + } } - // Parse the proxied service endpoints - proxiedServiceEndpoints := make(map[string]*url.URL, len(yamlRelayMinerConfig.ProxiedServiceEndpoints)) - for serviceId, endpointUrl := range yamlRelayMinerConfig.ProxiedServiceEndpoints { - endpoint, err := url.Parse(endpointUrl) - if err != nil { - return nil, ErrRelayMinerConfigInvalidServiceEndpoint.Wrap(err.Error()) + // Check that a proxy is not referencing a host more than once + for _, proxyConfig := range relayMinerProxiesConfig { + existingHosts := make(map[string]bool) + for _, supplierConfig := range proxyConfig.Suppliers { + for _, host := range supplierConfig.Hosts { + if _, ok := existingHosts[host]; ok { + return nil, ErrRelayMinerConfigInvalidProxy.Wrapf( + "duplicate host %s in proxy %s", + host, + proxyConfig.Name, + ) + } + existingHosts[host] = true + } } - proxiedServiceEndpoints[serviceId] = endpoint } + // Populate the relay miner config relayMinerCMDConfig := &RelayMinerConfig{ - QueryNodeGRPCUrl: queryNodeGRPCUrl, - TxNodeGRPCUrl: txNodeGRPCUrl, - QueryNodeRPCUrl: queryNodeRPCUrl, - SigningKeyName: yamlRelayMinerConfig.SigningKeyName, - ProxiedServiceEndpoints: proxiedServiceEndpoints, - SmtStorePath: yamlRelayMinerConfig.SmtStorePath, + SigningKeyName: yamlRelayMinerConfig.SigningKeyName, + SmtStorePath: yamlRelayMinerConfig.SmtStorePath, + Pocket: relayMinerPocketConfig, + Proxies: relayMinerProxiesConfig, } return relayMinerCMDConfig, nil diff --git a/pkg/relayer/config/types.go b/pkg/relayer/config/types.go new file mode 100644 index 000000000..80288d622 --- /dev/null +++ b/pkg/relayer/config/types.go @@ -0,0 +1,127 @@ +package config + +import "net/url" + +// YAMLRelayMinerConfig is the structure used to unmarshal the RelayMiner config file +// TODO_DOCUMENT(@red-0ne): Add proper README documentation for yaml config files. +type YAMLRelayMinerConfig struct { + SigningKeyName string `yaml:"signing_key_name"` + SmtStorePath string `yaml:"smt_store_path"` + Pocket YAMLRelayMinerPocketConfig `yaml:"pocket"` + Proxies []YAMLRelayMinerProxyConfig `yaml:"proxies"` + Suppliers []YAMLRelayMinerSupplierConfig `yaml:"suppliers"` +} + +// YAMLRelayMinerPocketConfig is the structure used to unmarshal the pocket +// node URLs section of the RelayMiner config file +type YAMLRelayMinerPocketConfig struct { + QueryNodeGRPCUrl string `yaml:"query_node_grpc_url"` + TxNodeGRPCUrl string `yaml:"tx_node_grpc_url"` + QueryNodeRPCUrl string `yaml:"query_node_rpc_url"` +} + +// YAMLRelayMinerProxyConfig is the structure used to unmarshal the proxy +// section of the RelayMiner config file +type YAMLRelayMinerProxyConfig struct { + Name string `yaml:"name"` + Host string `yaml:"host"` + Type string `yaml:"type"` +} + +// YAMLRelayMinerSupplierConfig is the structure used to unmarshal the supplier +// section of the RelayMiner config file +type YAMLRelayMinerSupplierConfig struct { + Name string `yaml:"name"` + Type string `yaml:"type"` + ServiceConfig YAMLRelayMinerSupplierServiceConfig `yaml:"service_config"` + Hosts []string `yaml:"hosts"` + ProxyNames []string `yaml:"proxy_names"` +} + +// YAMLRelayMinerSupplierServiceConfig is the structure used to unmarshal the supplier +// service sub-section of the RelayMiner config file +type YAMLRelayMinerSupplierServiceConfig struct { + Url string `yaml:"url"` + Authentication YAMLRelayMinerSupplierServiceAuthentication `yaml:"authentication,omitempty"` + Headers map[string]string `yaml:"headers,omitempty"` +} + +// YAMLRelayMinerSupplierServiceAuthentication is the structure used to unmarshal +// the supplier service basic auth of the RelayMiner config file when the +// supplier is of type "http" +type YAMLRelayMinerSupplierServiceAuthentication struct { + Username string `yaml:"username,omitempty"` + Password string `yaml:"password,omitempty"` +} + +// RelayMinerConfig is the structure describing the RelayMiner config +type RelayMinerConfig struct { + SigningKeyName string + SmtStorePath string + Pocket *RelayMinerPocketConfig + Proxies map[string]*RelayMinerProxyConfig +} + +// RelayMinerPocketConfig is the structure resulting from parsing the pocket +// node URLs section of the RelayMiner config file +type RelayMinerPocketConfig struct { + QueryNodeGRPCUrl *url.URL + TxNodeGRPCUrl *url.URL + QueryNodeRPCUrl *url.URL +} + +// RelayMinerProxyConfig is the structure resulting from parsing the proxy +// section of the RelayMiner config file. +// Each proxy embeds a map of supplier configs that are associated with it. +// Other proxy types may embed other fields in the future. eg. "https" may +// embed a TLS config. +type RelayMinerProxyConfig struct { + // Name is the name of the proxy server, used to identify it in the config + Name string + // Host is the host on which the proxy server will listen for incoming + // relay requests + Host string + // Type is the transport protocol used by the proxy server like (http, https, etc.) + Type string + // Suppliers is a map of serviceIds -> RelayMinerSupplierConfig + Suppliers map[string]*RelayMinerSupplierConfig +} + +// RelayMinerSupplierConfig is the structure resulting from parsing the supplier +// section of the RelayMiner config file. +type RelayMinerSupplierConfig struct { + // Name is the serviceId corresponding to the current configuration. + Name string + // Type is the transport protocol used by the supplier, it must match the + // type of the proxy it is associated with. + Type string + // Hosts is a list of hosts advertised on-chain by the supplier, the corresponding + // proxy server will accept relay requests for these hosts. + Hosts []string + // ServiceConfig is the config of the service that relays will be proxied to. + ServiceConfig *RelayMinerSupplierServiceConfig +} + +// RelayMinerSupplierServiceConfig is the structure resulting from parsing the supplier +// service sub-section of the RelayMiner config file. +// If the supplier is of type "http", it may embed a basic auth structure and +// a map of headers to be used for other authentication means. +// Other supplier types may embed other fields in the future. eg. "https" may +// embed a TLS config. +type RelayMinerSupplierServiceConfig struct { + // Url is the URL of the service that relays will be proxied to. + Url *url.URL + // Authentication is the basic auth structure used to authenticate to the + // request being proxied from the current proxy server. + Authentication *RelayMinerSupplierServiceAuthentication + // Headers is a map of headers to be used for other authentication means. + Headers map[string]string +} + +// RelayMinerSupplierServiceAuthentication is the structure resulting from parsing +// the supplier service basic auth of the RelayMiner config file when the +// supplier is of type "http" +type RelayMinerSupplierServiceAuthentication struct { + Username string + Password string +} diff --git a/pkg/relayer/interface.go b/pkg/relayer/interface.go index c35fe3fee..81fc81515 100644 --- a/pkg/relayer/interface.go +++ b/pkg/relayer/interface.go @@ -83,9 +83,6 @@ type RelayServer interface { // Stop terminates the service server and returns an error if it fails. Stop(ctx context.Context) error - - // Service returns the service to which the RelayServer relays. - Service() *sharedtypes.Service } // RelayerSessionsManager is responsible for managing the relayer's session lifecycles. diff --git a/pkg/relayer/proxy/errors.go b/pkg/relayer/proxy/errors.go index 7b14328c0..84604e836 100644 --- a/pkg/relayer/proxy/errors.go +++ b/pkg/relayer/proxy/errors.go @@ -15,4 +15,6 @@ var ( ErrRelayerProxyInvalidRelayRequest = sdkerrors.Register(codespace, 7, "invalid relay request") ErrRelayerProxyInvalidRelayResponse = sdkerrors.Register(codespace, 8, "invalid relay response") ErrRelayerProxyEmptyRelayRequestSignature = sdkerrors.Register(codespace, 9, "empty relay response signature") + ErrRelayerProxyServiceEndpointNotHandled = sdkerrors.Register(codespace, 10, "service endpoint not handled by relayer proxy") + ErrRelayerProxyUnsupportedTransportType = sdkerrors.Register(codespace, 11, "unsupported proxy transport type") ) diff --git a/pkg/relayer/proxy/options.go b/pkg/relayer/proxy/options.go index 4304d6067..ab9344c95 100644 --- a/pkg/relayer/proxy/options.go +++ b/pkg/relayer/proxy/options.go @@ -2,6 +2,7 @@ package proxy import ( "github.com/pokt-network/poktroll/pkg/relayer" + "github.com/pokt-network/poktroll/pkg/relayer/config" ) // WithSigningKeyName sets the signing key name used by the relayer proxy to sign relay responses. @@ -13,8 +14,8 @@ func WithSigningKeyName(keyName string) relayer.RelayerProxyOption { } // WithProxiedServicesEndpoints sets the endpoints of the proxied services. -func WithProxiedServicesEndpoints(proxiedServicesEndpoints servicesEndpointsMap) relayer.RelayerProxyOption { +func WithProxiedServicesEndpoints(proxyConfig map[string]*config.RelayMinerProxyConfig) relayer.RelayerProxyOption { return func(relProxy relayer.RelayerProxy) { - relProxy.(*relayerProxy).proxiedServicesEndpoints = proxiedServicesEndpoints + relProxy.(*relayerProxy).proxyConfigs = proxyConfig } } diff --git a/pkg/relayer/proxy/proxy.go b/pkg/relayer/proxy/proxy.go index 728b6a2c4..8805c67c9 100644 --- a/pkg/relayer/proxy/proxy.go +++ b/pkg/relayer/proxy/proxy.go @@ -2,7 +2,6 @@ package proxy import ( "context" - "net/url" "cosmossdk.io/depinject" "github.com/cosmos/cosmos-sdk/crypto/keyring" @@ -13,17 +12,12 @@ import ( "github.com/pokt-network/poktroll/pkg/observable/channel" "github.com/pokt-network/poktroll/pkg/polylog" "github.com/pokt-network/poktroll/pkg/relayer" + "github.com/pokt-network/poktroll/pkg/relayer/config" "github.com/pokt-network/poktroll/x/service/types" ) var _ relayer.RelayerProxy = (*relayerProxy)(nil) -type ( - serviceId = string - relayServersMap = map[serviceId][]relayer.RelayServer - servicesEndpointsMap = map[serviceId]*url.URL -) - // relayerProxy is the main relayer proxy that takes relay requests of supported services from the client // and proxies them to the supported proxied services. // It is responsible for notifying the miner about the relays that have been served so they can be counted @@ -49,13 +43,14 @@ type relayerProxy struct { // which is needed to check if the relay proxy should be serving an incoming relay request. sessionQuerier client.SessionQueryClient - // advertisedRelayServers is a map of the services provided by the relayer proxy. Each provided service + // proxyServers is a map of the proxy server provided by the relayer proxy. Each provided service // has the necessary information to start the server that listens for incoming relay requests and // the client that relays the request to the supported proxied service. - advertisedRelayServers relayServersMap + proxyServers map[string]relayer.RelayServer - // proxiedServicesEndpoints is a map of the proxied services endpoints that the relayer proxy supports. - proxiedServicesEndpoints servicesEndpointsMap + // proxyConfigs is a map of the proxy servers and their corresponding supplier + // advertised URLs and the services they proxy to. + proxyConfigs map[string]*config.RelayMinerProxyConfig // servedRelays is an observable that notifies the miner about the relays that have been served. servedRelays relayer.RelaysObservable @@ -129,11 +124,9 @@ func (rp *relayerProxy) Start(ctx context.Context) error { startGroup, ctx := errgroup.WithContext(ctx) - for _, relayServer := range rp.advertisedRelayServers { - for _, svr := range relayServer { - server := svr // create a new variable scoped to the anonymous function - startGroup.Go(func() error { return server.Start(ctx) }) - } + for _, relayServer := range rp.proxyServers { + server := relayServer // create a new variable scoped to the anonymous function + startGroup.Go(func() error { return server.Start(ctx) }) } return startGroup.Wait() @@ -144,11 +137,9 @@ func (rp *relayerProxy) Start(ctx context.Context) error { func (rp *relayerProxy) Stop(ctx context.Context) error { stopGroup, ctx := errgroup.WithContext(ctx) - for _, providedService := range rp.advertisedRelayServers { - for _, svr := range providedService { - server := svr // create a new variable scoped to the anonymous function - stopGroup.Go(func() error { return server.Stop(ctx) }) - } + for _, relayServer := range rp.proxyServers { + server := relayServer // create a new variable scoped to the anonymous function + stopGroup.Go(func() error { return server.Stop(ctx) }) } return stopGroup.Wait() @@ -168,7 +159,7 @@ func (rp *relayerProxy) validateConfig() error { return ErrRelayerProxyUndefinedSigningKeyName } - if rp.proxiedServicesEndpoints == nil || len(rp.proxiedServicesEndpoints) == 0 { + if rp.proxyConfigs == nil || len(rp.proxyConfigs) == 0 { return ErrRelayerProxyUndefinedProxiedServicesEndpoints } diff --git a/pkg/relayer/proxy/proxy_test.go b/pkg/relayer/proxy/proxy_test.go index 1887f6170..0c411b0b1 100644 --- a/pkg/relayer/proxy/proxy_test.go +++ b/pkg/relayer/proxy/proxy_test.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" "github.com/stretchr/testify/require" + "github.com/pokt-network/poktroll/pkg/relayer/config" "github.com/pokt-network/poktroll/pkg/relayer/proxy" "github.com/pokt-network/poktroll/testutil/testproxy" servicetypes "github.com/pokt-network/poktroll/x/service/types" @@ -22,37 +23,72 @@ import ( const blockHeight = 1 var ( - // TODO_TECHDEBT(@okdas, @red-0ne): Source relayerProxyUrl from its config file once - // RelayerProxy is building its servers from the provided config file - relayerProxyUrl string - // helpers used for tests that are initialized in init() supplierKeyName string supplierEndpoints []*sharedtypes.SupplierEndpoint appPrivateKey *secp256k1.PrivKey - proxiedServices map[string]*url.URL + // proxiedServices is the parsed configuration of the RelayMinerProxyConfig + proxiedServices map[string]*config.RelayMinerProxyConfig defaultRelayerProxyBehavior []func(*testproxy.TestBehavior) ) func init() { supplierKeyName = "supplierKeyName" + appPrivateKey = secp256k1.GenPrivKey() + supplierEndpoints = []*sharedtypes.SupplierEndpoint{ { - // TODO_TECHDEBT(@red-0ne): This URL is not used by the tests until we add - // support for the new `RelayMiner` config - // see https://github.com/pokt-network/poktroll/pull/246 Url: "http://supplier:8545", // TODO_EXTEND: Consider adding support for non JSON RPC services in the future RpcType: sharedtypes.RPCType_JSON_RPC, }, + { + Url: "http://supplier:8546", + RpcType: sharedtypes.RPCType_GRPC, + }, + { + Url: "http://supplier:8547", + RpcType: sharedtypes.RPCType_GRPC, + }, } - appPrivateKey = secp256k1.GenPrivKey() - relayerProxyUrl = "http://127.0.0.1:8545/" - proxiedServices = map[string]*url.URL{ - "service1": {Scheme: "http", Host: "localhost:8180", Path: "/"}, - "service2": {Scheme: "http", Host: "localhost:8181", Path: "/"}, + proxiedServices = map[string]*config.RelayMinerProxyConfig{ + "server1": { + Name: "server1", + Type: "http", + Host: "localhost:8080", + Suppliers: map[string]*config.RelayMinerSupplierConfig{ + "service1": { + Name: "service1", + Type: "http", + ServiceConfig: &config.RelayMinerSupplierServiceConfig{ + Url: &url.URL{Scheme: "http", Host: "supplier:8545", Path: "/"}, + }, + }, + "service2": { + Name: "service2", + Type: "http", + ServiceConfig: &config.RelayMinerSupplierServiceConfig{ + Url: &url.URL{Scheme: "http", Host: "supplier:8546", Path: "/"}, + }, + }, + }, + }, + "server2": { + Name: "server2", + Type: "http", + Host: "localhost:8081", + Suppliers: map[string]*config.RelayMinerSupplierConfig{ + "service3": { + Name: "service3", + Type: "http", + ServiceConfig: &config.RelayMinerSupplierServiceConfig{ + Url: &url.URL{Scheme: "http", Host: "supplier:8547", Path: "/"}, + }, + }, + }, + }, } defaultRelayerProxyBehavior = []func(*testproxy.TestBehavior){ @@ -84,7 +120,12 @@ func TestRelayerProxy_StartAndStop(t *testing.T) { time.Sleep(100 * time.Millisecond) // Test that RelayerProxy is handling requests (ignoring the actual response content) - res, err := http.DefaultClient.Get(relayerProxyUrl) + res, err := http.DefaultClient.Get(proxiedServices["server1"].Host) + require.NoError(t, err) + require.NotNil(t, res) + + // Test that RelayerProxy is handling requests from the other server + res, err = http.DefaultClient.Get(proxiedServices["server2"].Host) require.NoError(t, err) require.NotNil(t, res) @@ -131,7 +172,7 @@ func TestRelayerProxy_NoProxiedServices(t *testing.T) { _, err := proxy.NewRelayerProxy( test.Deps, proxy.WithSigningKeyName(supplierKeyName), - proxy.WithProxiedServicesEndpoints(make(map[string]*url.URL)), + proxy.WithProxiedServicesEndpoints(make(map[string]*config.RelayMinerProxyConfig)), ) require.Error(t, err) } @@ -177,6 +218,11 @@ func TestRelayerProxy_UnsupportedRpcType(t *testing.T) { require.Error(t, err) } +// TODO_THIS_COMMIT: Test non configured advertised services +// TODO_THIS_COMMIT: Test unsupported transport type +// TODO_THIS_COMMIT: Test X-Forwarded-Host header is set +// TODO_THIS_COMMIT: Test unsupported host + // Test different RelayRequest scenarios func TestRelayerProxy_Relays(t *testing.T) { tests := []struct { @@ -337,7 +383,7 @@ func sendRequestWithUnparsableBody( // Send non JSONRpc payload when the post request specifies json reader := io.NopCloser(bytes.NewReader([]byte("invalid request"))) - res, err := http.DefaultClient.Post(relayerProxyUrl, "application/json", reader) + res, err := http.DefaultClient.Post(proxiedServices["server1"].Host, "application/json", reader) require.NoError(t, err) require.NotNil(t, res) @@ -354,7 +400,7 @@ func sendRequestWithMissingMeta( Payload: testproxy.PrepareJsonRPCRequestPayload(), } - return testproxy.MarshalAndSend(test, relayerProxyUrl, req) + return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) } func sendRequestWithMissingSignature( @@ -369,7 +415,7 @@ func sendRequestWithMissingSignature( testproxy.PrepareJsonRPCRequestPayload(), ) req.Meta.Signature = nil - return testproxy.MarshalAndSend(test, relayerProxyUrl, req) + return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) } func sendRequestWithInvalidSignature( @@ -385,7 +431,7 @@ func sendRequestWithInvalidSignature( ) req.Meta.Signature = []byte("invalid signature") - return testproxy.MarshalAndSend(test, relayerProxyUrl, req) + return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) } func sendRequestWithMissingSessionHeaderApplicationAddress( @@ -408,7 +454,7 @@ func sendRequestWithMissingSessionHeaderApplicationAddress( // before looking at the application address req.Meta.Signature = testproxy.GetApplicationRingSignature(t, req, randomPrivKey) - return testproxy.MarshalAndSend(test, relayerProxyUrl, req) + return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) } func sendRequestWithNonStakedApplicationAddress( @@ -427,7 +473,7 @@ func sendRequestWithNonStakedApplicationAddress( // Have a valid signature from the non staked key req.Meta.Signature = testproxy.GetApplicationRingSignature(t, req, randomPrivKey) - return testproxy.MarshalAndSend(test, relayerProxyUrl, req) + return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) } func sendRequestWithRingSignatureMismatch( @@ -446,7 +492,7 @@ func sendRequestWithRingSignatureMismatch( randomPrivKey := secp256k1.GenPrivKey() req.Meta.Signature = testproxy.GetApplicationRingSignature(t, req, randomPrivKey) - return testproxy.MarshalAndSend(test, relayerProxyUrl, req) + return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) } func sendRequestWithDifferentSession( @@ -463,7 +509,7 @@ func sendRequestWithDifferentSession( ) req.Meta.Signature = testproxy.GetApplicationRingSignature(t, req, appPrivateKey) - return testproxy.MarshalAndSend(test, relayerProxyUrl, req) + return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) } func sendRequestWithInvalidRelaySupplier( @@ -479,7 +525,7 @@ func sendRequestWithInvalidRelaySupplier( ) req.Meta.Signature = testproxy.GetApplicationRingSignature(t, req, appPrivateKey) - return testproxy.MarshalAndSend(test, relayerProxyUrl, req) + return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) } func sendRequestWithSignatureForDifferentPayload( @@ -497,7 +543,7 @@ func sendRequestWithSignatureForDifferentPayload( // Alter the request payload so the hash doesn't match the one used by the signature req.Payload = []byte(`{"method":"someMethod","id":1,"jsonrpc":"2.0","params":["alteredParam"]}`) - return testproxy.MarshalAndSend(test, relayerProxyUrl, req) + return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) } func sendRequestWithSuccessfulReply( @@ -513,5 +559,5 @@ func sendRequestWithSuccessfulReply( ) req.Meta.Signature = testproxy.GetApplicationRingSignature(t, req, appPrivateKey) - return testproxy.MarshalAndSend(test, relayerProxyUrl, req) + return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) } diff --git a/pkg/relayer/proxy/server_builder.go b/pkg/relayer/proxy/server_builder.go index f6ed8d23f..90359c288 100644 --- a/pkg/relayer/proxy/server_builder.go +++ b/pkg/relayer/proxy/server_builder.go @@ -28,58 +28,59 @@ func (rp *relayerProxy) BuildProvidedServices(ctx context.Context) error { return err } - services := supplier.Services - - // Build the advertised relay servers map. For each service's endpoint, create the appropriate RelayServer. - providedServices := make(relayServersMap) - for _, serviceConfig := range services { - service := serviceConfig.Service - proxiedServicesEndpoints := rp.proxiedServicesEndpoints[service.Id] - var serviceEndpoints []relayer.RelayServer - - for _, endpoint := range serviceConfig.Endpoints { - // url, err := url.Parse(endpoint.Url) - // if err != nil { - // return err - // } - // supplierEndpointHost := url.Host - - // This will throw an error if we have more than one endpoint - supplierEndpointHost := "0.0.0.0:8545" - - rp.logger.Info(). - Fields(map[string]any{ - "service_id": service.Id, - "endpoint_url": endpoint.Url, - }). - Msg("starting relay server") + supplierServiceMap := make(map[string]*sharedtypes.Service) + for _, service := range supplier.Services { + supplierServiceMap[service.Service.Id] = service.Service + } - // Switch to the RPC type - // TODO(@h5law): Implement a switch that handles all synchronous - // RPC types in one server type and asynchronous RPC types in another - // to create the appropriate RelayServer - var server relayer.RelayServer - switch endpoint.RpcType { - case sharedtypes.RPCType_JSON_RPC: - server = NewSynchronousServer( - rp.logger, - service, - supplierEndpointHost, - proxiedServicesEndpoints, - rp.servedRelaysPublishCh, - rp, - ) - default: - return ErrRelayerProxyUnsupportedRPCType + // Check that the supplier's advertised services' endpoints are present in + // the proxy config and handled by a proxy host + // Iterate over the supplier's advertised services then iterate over each + // service's endpoint + for _, service := range supplier.Services { + for _, endpoint := range service.Endpoints { + found := false + // Iterate over the proxy configs and check if `endpoint.Url` is present + // and corresponds to the right service id + for _, proxyConfig := range rp.proxyConfigs { + supplierService, ok := proxyConfig.Suppliers[service.Service.Id] + if ok && endpoint.Url == supplierService.ServiceConfig.Url.String() { + found = true + break + } } + if !found { + return ErrRelayerProxyServiceEndpointNotHandled + } + } + } + + // Build the advertised relay servers map. For each service's endpoint, create the appropriate RelayServer. + providedServices := make(map[string]relayer.RelayServer) + for _, proxyConfig := range rp.proxyConfigs { + rp.logger.Info().Str("proxy host", proxyConfig.Host).Msg("starting relay proxy server") - serviceEndpoints = append(serviceEndpoints, server) + // Switch to the RPC type + // TODO(@h5law): Implement a switch that handles all synchronous + // RPC types in one server type and asynchronous RPC types in another + // to create the appropriate RelayServer + var server relayer.RelayServer + switch proxyConfig.Type { + case "http": + server = NewSynchronousServer( + rp.logger, + proxyConfig, + supplierServiceMap, + rp.servedRelaysPublishCh, + rp, + ) + default: + return ErrRelayerProxyUnsupportedTransportType } - providedServices[service.Id] = serviceEndpoints + providedServices[proxyConfig.Name] = server } - rp.advertisedRelayServers = providedServices rp.supplierAddress = supplier.Address return nil diff --git a/pkg/relayer/proxy/synchronous.go b/pkg/relayer/proxy/synchronous.go index 341413d34..15f9d8470 100644 --- a/pkg/relayer/proxy/synchronous.go +++ b/pkg/relayer/proxy/synchronous.go @@ -10,6 +10,7 @@ import ( sdkerrors "cosmossdk.io/errors" "github.com/pokt-network/poktroll/pkg/polylog" "github.com/pokt-network/poktroll/pkg/relayer" + "github.com/pokt-network/poktroll/pkg/relayer/config" "github.com/pokt-network/poktroll/x/service/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) @@ -22,11 +23,14 @@ var _ relayer.RelayServer = (*synchronousRPCServer)(nil) type synchronousRPCServer struct { logger polylog.Logger - // service is the service that the server is responsible for. - service *sharedtypes.Service + // supplierServiceMap is a map of serviceId -> SupplierServiceConfig + // representing the supplier's advertised services. + supplierServiceMap map[string]*sharedtypes.Service - // proxiedServiceEndpoint is the address of the proxied service that the server relays requests to. - proxiedServiceEndpoint *url.URL + // proxyConfig is the configuration of the proxy server. It contains the + // host address of the server, the service endpoint, and the advertised service. + // endpoints it gets relay requests from. + proxyConfig *config.RelayMinerProxyConfig // server is the HTTP server that listens for incoming relay requests. server *http.Server @@ -45,19 +49,17 @@ type synchronousRPCServer struct { // and returns a RelayServer that listens to incoming RelayRequests. func NewSynchronousServer( logger polylog.Logger, - service *sharedtypes.Service, - supplierEndpointHost string, - proxiedServiceEndpoint *url.URL, + proxyConfig *config.RelayMinerProxyConfig, + supplierServiceMap map[string]*sharedtypes.Service, servedRelaysProducer chan<- *types.Relay, proxy relayer.RelayerProxy, ) relayer.RelayServer { return &synchronousRPCServer{ - logger: logger, - service: service, - server: &http.Server{Addr: supplierEndpointHost}, - relayerProxy: proxy, - proxiedServiceEndpoint: proxiedServiceEndpoint, - servedRelaysProducer: servedRelaysProducer, + logger: logger, + supplierServiceMap: supplierServiceMap, + server: &http.Server{Addr: proxyConfig.Host}, + relayerProxy: proxy, + servedRelaysProducer: servedRelaysProducer, } } @@ -81,11 +83,6 @@ func (sync *synchronousRPCServer) Stop(ctx context.Context) error { return sync.server.Shutdown(ctx) } -// Service returns the underlying service object. -func (sync *synchronousRPCServer) Service() *sharedtypes.Service { - return sync.service -} - // ServeHTTP listens for incoming relay requests. It implements the respective // method of the http.Handler interface. It is called by http.ListenAndServe() // when synchronousRPCServer is used as an http.Handler with an http.Server. @@ -93,6 +90,33 @@ func (sync *synchronousRPCServer) Service() *sharedtypes.Service { func (sync *synchronousRPCServer) ServeHTTP(writer http.ResponseWriter, request *http.Request) { ctx := request.Context() + // Get the original host from X-Forwarded-Host header if present. + originHost := request.Header.Get("X-Forwarded-Host") + + // If X-Forwarded-Host is not present, fallback to the Host header + if originHost == "" { + originHost = request.Host + } + + var supplierService *sharedtypes.Service + var serviceUrl *url.URL + + // Get the Service and serviceUrl corresponding to the originHost. + for _, supplierServiceConfig := range sync.proxyConfig.Suppliers { + for _, host := range supplierServiceConfig.Hosts { + if host == originHost { + supplierService = sync.supplierServiceMap[supplierServiceConfig.Name] + serviceUrl = supplierServiceConfig.ServiceConfig.Url + break + } + } + } + + if supplierService == nil || serviceUrl == nil { + sync.replyWithError(ctx, []byte{}, writer, ErrRelayerProxyServiceEndpointNotHandled) + return + } + sync.logger.Debug().Msg("serving synchronous relay request") // Extract the relay request from the request body. @@ -115,7 +139,7 @@ func (sync *synchronousRPCServer) ServeHTTP(writer http.ResponseWriter, request } // Relay the request to the proxied service and build the response that will be sent back to the client. - relay, err := sync.serveHTTP(ctx, request, relayRequest) + relay, err := sync.serveHTTP(ctx, serviceUrl, supplierService, request, relayRequest) if err != nil { // Reply with an error if the relay could not be served. sync.replyWithError(ctx, relayRequest.Payload, writer, err) @@ -144,6 +168,8 @@ func (sync *synchronousRPCServer) ServeHTTP(writer http.ResponseWriter, request // serveHTTP holds the underlying logic of ServeHTTP. func (sync *synchronousRPCServer) serveHTTP( ctx context.Context, + serviceUrl *url.URL, + supplierService *sharedtypes.Service, request *http.Request, relayRequest *types.RelayRequest, ) (*types.Relay, error) { @@ -154,7 +180,7 @@ func (sync *synchronousRPCServer) serveHTTP( // request signature verification, session verification, and response signature. // This would help in separating concerns and improving code maintainability. // See https://github.com/pokt-network/poktroll/issues/160 - if err := sync.relayerProxy.VerifyRelayRequest(ctx, relayRequest, sync.service); err != nil { + if err := sync.relayerProxy.VerifyRelayRequest(ctx, relayRequest, supplierService); err != nil { return nil, err } @@ -169,14 +195,14 @@ func (sync *synchronousRPCServer) serveHTTP( // Build the request to be sent to the native service by substituting // the destination URL's host with the native service's listen address. sync.logger.Debug(). - Str("destination_url", sync.proxiedServiceEndpoint.String()). + Str("destination_url", serviceUrl.String()). Msg("building relay request payload to service") relayHTTPRequest := &http.Request{ Method: request.Method, Header: request.Header, - URL: sync.proxiedServiceEndpoint, - Host: sync.proxiedServiceEndpoint.Host, + URL: serviceUrl, + Host: serviceUrl.Host, Body: requestBodyReader, } diff --git a/testutil/testproxy/relayerproxy.go b/testutil/testproxy/relayerproxy.go index 9961584f0..4ff4bc235 100644 --- a/testutil/testproxy/relayerproxy.go +++ b/testutil/testproxy/relayerproxy.go @@ -6,7 +6,6 @@ import ( "encoding/json" "io" "net/http" - "net/url" "testing" "cosmossdk.io/depinject" @@ -21,6 +20,7 @@ import ( "github.com/pokt-network/poktroll/pkg/crypto/rings" "github.com/pokt-network/poktroll/pkg/polylog" + "github.com/pokt-network/poktroll/pkg/relayer/config" "github.com/pokt-network/poktroll/pkg/signer" "github.com/pokt-network/poktroll/testutil/testclient/testblock" testkeyring "github.com/pokt-network/poktroll/testutil/testclient/testkeyring" @@ -104,7 +104,9 @@ func WithRelayerProxyDependencies(keyName string) func(*TestBehavior) { // WithRelayerProxiedServices creates the services that the relayer proxy will // proxy requests to. -func WithRelayerProxiedServices(proxiedServices map[string]*url.URL) func(*TestBehavior) { +func WithRelayerProxiedServices( + proxiedServices map[string]*config.RelayMinerProxyConfig, +) func(*TestBehavior) { return func(test *TestBehavior) { for serviceId, endpoint := range proxiedServices { server := &http.Server{Addr: endpoint.Host} From 4b4df7a8ea1677d4cd7c8e444e434c9678aec183 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Tue, 19 Dec 2023 06:23:14 +0100 Subject: [PATCH 17/34] feat: Adapt tests to new relay miner config --- .../config/proxy_http_config_parser.go | 16 +- .../config/relayminer_configs_reader.go | 28 +- .../config/relayminer_configs_reader_test.go | 1202 +++++++++++++++-- pkg/relayer/config/types.go | 11 +- pkg/relayer/proxy/proxy_test.go | 203 ++- pkg/relayer/proxy/server_builder.go | 20 +- pkg/relayer/proxy/synchronous.go | 13 +- testutil/testproxy/relayerproxy.go | 58 +- 8 files changed, 1369 insertions(+), 182 deletions(-) diff --git a/pkg/relayer/config/proxy_http_config_parser.go b/pkg/relayer/config/proxy_http_config_parser.go index 02251a0e4..0dbd0c439 100644 --- a/pkg/relayer/config/proxy_http_config_parser.go +++ b/pkg/relayer/config/proxy_http_config_parser.go @@ -1,6 +1,9 @@ package config -import "net/url" +import ( + "fmt" + "net/url" +) // parseRelayMinerConfigs populates the proxy fields of the target structure that // are relevant to the "http" type in the proxy section of the config file. @@ -9,7 +12,7 @@ func parseHTTPProxyConfig( proxyConfig *RelayMinerProxyConfig, ) error { // Check if the proxy host is a valid URL - proxyUrl, err := url.Parse(yamlProxyConfig.Host) + proxyUrl, err := url.Parse(fmt.Sprintf("tcp://%s", yamlProxyConfig.Host)) if err != nil { return ErrRelayMinerConfigInvalidProxy.Wrapf( "invalid proxy host %s", @@ -17,6 +20,10 @@ func parseHTTPProxyConfig( ) } + if proxyUrl.Host == "" { + return ErrRelayMinerConfigInvalidProxy.Wrap("empty proxy host") + } + proxyConfig.Host = proxyUrl.Host return nil } @@ -28,6 +35,11 @@ func parseHTTPSupplierConfig( supplierServiceConfig *RelayMinerSupplierServiceConfig, ) error { var err error + // Check if the supplier url is not empty + if yamlSupplierServiceConfig.Url == "" { + return ErrRelayMinerConfigInvalidSupplier.Wrap("empty supplier url") + } + // Check if the supplier url is a valid URL supplierServiceConfig.Url, err = url.Parse(yamlSupplierServiceConfig.Url) if err != nil { diff --git a/pkg/relayer/config/relayminer_configs_reader.go b/pkg/relayer/config/relayminer_configs_reader.go index 4c2c42ad7..e8629699e 100644 --- a/pkg/relayer/config/relayminer_configs_reader.go +++ b/pkg/relayer/config/relayminer_configs_reader.go @@ -38,6 +38,10 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { relayMinerPocketConfig := &RelayMinerPocketConfig{} pocket := yamlRelayMinerConfig.Pocket + if pocket.TxNodeGRPCUrl == "" { + return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrap("tx node grpc url is required") + } + // Check if the pocket node grpc url is a valid URL relayMinerPocketConfig.TxNodeGRPCUrl, err = url.Parse(pocket.TxNodeGRPCUrl) if err != nil { @@ -61,6 +65,10 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { } } + if pocket.QueryNodeRPCUrl == "" { + return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrap("query node rpc url is required") + } + // Check if the query node rpc url is a valid URL relayMinerPocketConfig.QueryNodeRPCUrl, err = url.Parse(pocket.QueryNodeRPCUrl) if err != nil { @@ -94,8 +102,9 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { } proxyConfig := &RelayMinerProxyConfig{ - Name: yamlProxyConfig.Name, - Suppliers: make(map[string]*RelayMinerSupplierConfig), + Name: yamlProxyConfig.Name, + XForwardedHostLookup: yamlProxyConfig.XForwardedHostLookup, + Suppliers: make(map[string]*RelayMinerSupplierConfig), } // Populate the proxy fields that are relevant to each supported proxy type @@ -143,6 +152,11 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { // Supplier hosts sub-section existingHosts := make(map[string]bool) for _, host := range yamlSupplierConfig.Hosts { + // Check if the supplier host is empty + if host == "" { + return nil, ErrRelayMinerConfigInvalidSupplier.Wrap("empty supplier host") + } + // Check if the supplier host is a valid URL supplierHost, err := url.Parse(host) if err != nil { @@ -193,6 +207,14 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { } supplierConfig.Type = yamlSupplierConfig.Type + // Check if the supplier has proxies + if len(yamlSupplierConfig.ProxyNames) == 0 { + return nil, ErrRelayMinerConfigInvalidSupplier.Wrapf( + "supplier %s has no proxies", + supplierConfig.Name, + ) + } + // Add the supplier config to the referenced proxies for _, proxyName := range yamlSupplierConfig.ProxyNames { // If the proxy name is referencing a non-existent proxy, fail @@ -217,7 +239,7 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { } } - // Check that a proxy is not referencing a host more than once + // Check if a proxy is referencing a host more than once for _, proxyConfig := range relayMinerProxiesConfig { existingHosts := make(map[string]bool) for _, supplierConfig := range proxyConfig.Suppliers { diff --git a/pkg/relayer/config/relayminer_configs_reader_test.go b/pkg/relayer/config/relayminer_configs_reader_test.go index 705ce0176..cb96ec39f 100644 --- a/pkg/relayer/config/relayminer_configs_reader_test.go +++ b/pkg/relayer/config/relayminer_configs_reader_test.go @@ -26,53 +26,347 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "valid: relay miner config", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 - proxied_service_endpoints: - anvil: http://anvil:8080 - svc1: http://svc1:8080 smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + authentication: + username: user + password: pwd + headers: {} + hosts: + - tcp://ethereum.devnet1.poktroll.com + - tcp://ethereum + proxy_names: + - http-example `, expectedError: nil, expectedConfig: &config.RelayMinerConfig{ - QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, - SigningKeyName: "servicer1", - ProxiedServiceEndpoints: map[string]*url.URL{ - "anvil": {Scheme: "http", Host: "anvil:8080"}, - "svc1": {Scheme: "http", Host: "svc1:8080"}, + Pocket: &config.RelayMinerPocketConfig{ + QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, + }, + SigningKeyName: "servicer1", + SmtStorePath: "smt_stores", + Proxies: map[string]*config.RelayMinerProxyConfig{ + "http-example": { + Name: "http-example", + Host: "127.0.0.1:8080", + Type: "http", + XForwardedHostLookup: false, + Suppliers: map[string]*config.RelayMinerSupplierConfig{ + "ethereum": { + Name: "ethereum", + Type: "http", + ServiceConfig: &config.RelayMinerSupplierServiceConfig{ + Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, + Authentication: &config.RelayMinerSupplierServiceAuthentication{ + Username: "user", + Password: "pwd", + }, + Headers: map[string]string{}, + }, + Hosts: []string{ + "ethereum.devnet1.poktroll.com", + "ethereum", + }, + }, + }, + }, + }, + }, + }, + { + desc: "valid: multiple suppliers, single proxy", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + authentication: + username: user + password: pwd + headers: {} + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + - name: 7b-llm-model + type: http + service_config: + url: http://llama-endpoint + hosts: + - tcp://7b-llm-model.devnet1.poktroll.com + - tcp://7b-llm-model + proxy_names: + - http-example + `, + + expectedError: nil, + expectedConfig: &config.RelayMinerConfig{ + Pocket: &config.RelayMinerPocketConfig{ + QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, + }, + SigningKeyName: "servicer1", + SmtStorePath: "smt_stores", + Proxies: map[string]*config.RelayMinerProxyConfig{ + "http-example": { + Name: "http-example", + Host: "127.0.0.1:8080", + Type: "http", + XForwardedHostLookup: false, + Suppliers: map[string]*config.RelayMinerSupplierConfig{ + "ethereum": { + Name: "ethereum", + Type: "http", + ServiceConfig: &config.RelayMinerSupplierServiceConfig{ + Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, + Authentication: &config.RelayMinerSupplierServiceAuthentication{ + Username: "user", + Password: "pwd", + }, + Headers: map[string]string{}, + }, + Hosts: []string{ + "ethereum.devnet1.poktroll.com", + "ethereum", + }, + }, + "7b-llm-model": { + Name: "7b-llm-model", + Type: "http", + ServiceConfig: &config.RelayMinerSupplierServiceConfig{ + Url: &url.URL{Scheme: "http", Host: "llama-endpoint"}, + }, + Hosts: []string{ + "7b-llm-model.devnet1.poktroll.com", + "7b-llm-model", + }, + }, + }, + }, + }, + }, + }, + { + desc: "valid: multiple proxies for a single supplier, no auth", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: first-proxy + host: 127.0.0.1:8080 + type: http + - name: second-proxy + host: 127.0.0.1:8081 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - first-proxy + - second-proxy + `, + + expectedError: nil, + expectedConfig: &config.RelayMinerConfig{ + Pocket: &config.RelayMinerPocketConfig{ + QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, + }, + SigningKeyName: "servicer1", + SmtStorePath: "smt_stores", + Proxies: map[string]*config.RelayMinerProxyConfig{ + "first-proxy": { + Name: "first-proxy", + Host: "127.0.0.1:8080", + Type: "http", + XForwardedHostLookup: false, + Suppliers: map[string]*config.RelayMinerSupplierConfig{ + "ethereum": { + Name: "ethereum", + Type: "http", + ServiceConfig: &config.RelayMinerSupplierServiceConfig{ + Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, + }, + Hosts: []string{ + "ethereum.devnet1.poktroll.com", + }, + }, + }, + }, + "second-proxy": { + Name: "second-proxy", + Host: "127.0.0.1:8081", + Type: "http", + XForwardedHostLookup: false, + Suppliers: map[string]*config.RelayMinerSupplierConfig{ + "ethereum": { + Name: "ethereum", + Type: "http", + ServiceConfig: &config.RelayMinerSupplierServiceConfig{ + Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, + }, + Hosts: []string{ + "ethereum.devnet1.poktroll.com", + }, + }, + }, + }, }, - SmtStorePath: "smt_stores", }, }, { desc: "valid: relay miner config with query node grpc url defaulting to tx node grpc url", inputConfig: ` - tx_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + - tcp://ethereum + proxy_names: + - http-example + `, + + expectedError: nil, + expectedConfig: &config.RelayMinerConfig{ + Pocket: &config.RelayMinerPocketConfig{ + QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, + TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, + }, + SigningKeyName: "servicer1", + SmtStorePath: "smt_stores", + Proxies: map[string]*config.RelayMinerProxyConfig{ + "http-example": { + Name: "http-example", + Host: "127.0.0.1:8080", + Type: "http", + XForwardedHostLookup: false, + Suppliers: map[string]*config.RelayMinerSupplierConfig{ + "ethereum": { + Name: "ethereum", + Type: "http", + ServiceConfig: &config.RelayMinerSupplierServiceConfig{ + Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, + }, + Hosts: []string{ + "ethereum.devnet1.poktroll.com", + "ethereum", + }, + }, + }, + }, + }, + }, + }, + { + desc: "valid: relay miner config with x_forwarded_host_lookup set to true", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 - proxied_service_endpoints: - anvil: http://anvil:8080 - svc1: http://svc1:8080 smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + x_forwarded_host_lookup: true + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + - tcp://ethereum + proxy_names: + - http-example `, expectedError: nil, expectedConfig: &config.RelayMinerConfig{ - QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, - SigningKeyName: "servicer1", - ProxiedServiceEndpoints: map[string]*url.URL{ - "anvil": {Scheme: "http", Host: "anvil:8080"}, - "svc1": {Scheme: "http", Host: "svc1:8080"}, + Pocket: &config.RelayMinerPocketConfig{ + QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, + }, + SigningKeyName: "servicer1", + SmtStorePath: "smt_stores", + Proxies: map[string]*config.RelayMinerProxyConfig{ + "http-example": { + Name: "http-example", + Host: "127.0.0.1:8080", + Type: "http", + XForwardedHostLookup: true, + Suppliers: map[string]*config.RelayMinerSupplierConfig{ + "ethereum": { + Name: "ethereum", + Type: "http", + ServiceConfig: &config.RelayMinerSupplierServiceConfig{ + Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, + }, + Hosts: []string{ + "ethereum.devnet1.poktroll.com", + "ethereum", + }, + }, + }, + }, }, - SmtStorePath: "smt_stores", }, }, // Invalid Configs @@ -80,138 +374,759 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: invalid tx node grpc url", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: &tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: &tcp://127.0.0.1:36659 signing_key_name: servicer1 - proxied_service_endpoints: - anvil: http://anvil:8080 - svc1: http://svc1:8080 smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example `, - expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidNodeUrl, }, { desc: "invalid: missing tx node grpc url", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + # explicitly omitted tx node grpc url + query_node_grpc_url: tcp://127.0.0.1:36658 signing_key_name: servicer1 - proxied_service_endpoints: - anvil: http://anvil:8080 - svc1: http://svc1:8080 smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example `, - expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidNodeUrl, }, { desc: "invalid: invalid query node grpc url", inputConfig: ` - query_node_grpc_url: &tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: &tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidNodeUrl, + }, + { + desc: "invalid: invalid query node rpc url", + + inputConfig: ` + pocket: + query_node_rpc_url: &tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 - proxied_service_endpoints: - anvil: http://anvil:8080 - svc1: http://svc1:8080 smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example `, - expectedError: config.ErrRelayMinerConfigInvalidQueryNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidNodeUrl, }, { desc: "invalid: missing query node rpc url", inputConfig: ` - query_node_grpc_url: tcp://128.0.0.1:36658 - tx_node_grpc_url: tcp://128.0.0.1:36658 - // explicitly missing query_node_rpc_url + pocket: + # explicitly omitted query node rpc url + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 - proxied_service_endpoints: - anvil: http://anvil:8080 - svc1: http://svc1:8080 smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example `, - expectedError: config.ErrRelayMinerConfigUnmarshalYAML, + expectedError: config.ErrRelayMinerConfigInvalidNodeUrl, }, { desc: "invalid: missing signing key name", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 - // explicitly missing signing_key_name - proxied_service_endpoints: - anvil: http://anvil:8080 - svc1: http://svc1:8080 + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + # explicitly omitted signing key name smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example `, - expectedError: config.ErrRelayMinerConfigUnmarshalYAML, + expectedError: config.ErrRelayMinerConfigInvalidSigningKeyName, }, { desc: "invalid: missing smt store path", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 - proxied_service_endpoints: - anvil: http://anvil:8080 - svc1: http://svc1:8080 + # explicitly omitted smt store path + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example `, expectedError: config.ErrRelayMinerConfigInvalidSmtStorePath, }, { - desc: "invalid: empty proxied service endpoints", + desc: "invalid: missing proxies section", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 - proxied_service_endpoints: smt_store_path: smt_stores + # explicitly omitted proxies section + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example `, - expectedError: config.ErrRelayMinerConfigInvalidServiceEndpoint, + expectedError: config.ErrRelayMinerConfigInvalidProxy, }, { - desc: "invalid: invalid proxied service endpoint", + desc: "invalid: empty proxies section", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 - proxied_service_endpoints: - anvil: &http://anvil:8080 - svc1: http://svc1:8080 smt_store_path: smt_stores + proxies: # explicitly empty proxies section + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example `, - expectedError: config.ErrRelayMinerConfigInvalidServiceEndpoint, + expectedError: config.ErrRelayMinerConfigInvalidProxy, }, { - desc: "invalid: invalid tx node grpc url", + desc: "invalid: omitted proxy name", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + # explicitly omitted proxy name + - host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidProxy, + }, + { + desc: "invalid: empty proxy name", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: # explicitly empty proxy name + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidProxy, + }, + { + desc: "invalid: missing http proxy host", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + # explicitly missing proxy host + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidProxy, + }, + { + desc: "invalid: empty http proxy host", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: # explicitly empty proxy host + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidProxy, + }, + { + desc: "invalid: missing proxy type", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + # explicitly missing proxy type + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidProxy, + }, + { + desc: "invalid: empty proxy type", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: # explicitly empty proxy type + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidProxy, + }, + { + desc: "invalid: unsupported proxy type", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: unsupported + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidProxy, + }, + { + desc: "invalid: missing supplier name", inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: &tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + # explicitly missing supplier name + - type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example `, - expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, + expectedError: config.ErrRelayMinerConfigInvalidSupplier, + }, + { + desc: "invalid: empty supplier name", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: # explicitly empty supplier name + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidSupplier, + }, + { + desc: "invalid: unsupported supplier type", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: unsupported + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidSupplier, + }, + { + desc: "invalid: missing supplier type", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + # explicitly missing supplier type + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidSupplier, + }, + { + desc: "invalid: empty supplier type", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: # explicitly empty supplier type + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidSupplier, + }, + { + desc: "invalid: bad supplier service config url", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: &http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidSupplier, + }, + { + desc: "invalid: empty supplier service config url", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: # explicitly empty supplier service config url + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidSupplier, + }, + { + desc: "invalid: missing supplier service config url", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + # explicitly missing supplier service config url + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidSupplier, + }, + { + desc: "invalid: bad supplier host", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - &tcp://ethereum.devnet1.poktroll.com + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidSupplier, + }, + { + desc: "invalid: blank supplier host", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - # explicitly blank supplier host + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidSupplier, + }, + { + desc: "invalid: empty supplier proxy references", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://ethereum.devnet1.poktroll.com + proxy_names: + - bad-proxy-name + `, + + expectedError: config.ErrRelayMinerConfigInvalidSupplier, + }, + { + desc: "invalid: empty supplier proxy references", + + inputConfig: ` + pocket: + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_grpc_url: tcp://127.0.0.1:36659 + signing_key_name: servicer1 + smt_store_path: smt_stores + proxies: + - name: http-example + host: 127.0.0.1:8080 + type: http + suppliers: + - name: ethereum + type: http + service_config: + url: http://anvil.servicer:8545 + hosts: + - tcp://devnet1.poktroll.com # hosts for both suppliers are the same + proxy_names: + - http-example + - name: avax + type: http + service_config: + url: http://avax.servicer:8545 + hosts: + - tcp://devnet1.poktroll.com # hosts for both suppliers are the same + proxy_names: + - http-example + `, + + expectedError: config.ErrRelayMinerConfigInvalidProxy, }, { desc: "invalid: empty RelayMiner config file", @@ -220,6 +1135,8 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { expectedError: config.ErrRelayMinerConfigEmpty, }, + // TODO_NB: Test for supplier and proxy types mismatch once we have more + // than one proxy type. } for _, tt := range tests { @@ -239,14 +1156,109 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { require.NoError(t, err) - require.Equal(t, tt.expectedConfig.QueryNodeRPCUrl.String(), config.QueryNodeRPCUrl.String()) - require.Equal(t, tt.expectedConfig.QueryNodeGRPCUrl.String(), config.QueryNodeGRPCUrl.String()) - require.Equal(t, tt.expectedConfig.TxNodeGRPCUrl.String(), config.TxNodeGRPCUrl.String()) - require.Equal(t, tt.expectedConfig.SigningKeyName, config.SigningKeyName) - require.Equal(t, tt.expectedConfig.SmtStorePath, config.SmtStorePath) - require.Equal(t, len(tt.expectedConfig.ProxiedServiceEndpoints), len(config.ProxiedServiceEndpoints)) - for serviceId, endpoint := range tt.expectedConfig.ProxiedServiceEndpoints { - require.Equal(t, endpoint.String(), config.ProxiedServiceEndpoints[serviceId].String()) + require.Equal( + t, + tt.expectedConfig.SigningKeyName, + config.SigningKeyName, + ) + + require.Equal( + t, + tt.expectedConfig.SmtStorePath, + config.SmtStorePath, + ) + + require.Equal( + t, + tt.expectedConfig.Pocket.QueryNodeGRPCUrl.String(), + config.Pocket.QueryNodeGRPCUrl.String(), + ) + + require.Equal( + t, + tt.expectedConfig.Pocket.QueryNodeRPCUrl.String(), + config.Pocket.QueryNodeRPCUrl.String(), + ) + + require.Equal( + t, + tt.expectedConfig.Pocket.TxNodeGRPCUrl.String(), + config.Pocket.TxNodeGRPCUrl.String(), + ) + + for proxyName, proxy := range tt.expectedConfig.Proxies { + require.Equal( + t, + proxy.Name, + config.Proxies[proxyName].Name, + ) + + require.Equal( + t, + proxy.Host, + config.Proxies[proxyName].Host, + ) + + require.Equal( + t, + proxy.Type, + config.Proxies[proxyName].Type, + ) + + for supplierName, supplier := range proxy.Suppliers { + require.Equal( + t, + supplier.Name, + config.Proxies[proxyName].Suppliers[supplierName].Name, + ) + + require.Equal( + t, + supplier.Type, + config.Proxies[proxyName].Suppliers[supplierName].Type, + ) + + require.Equal( + t, + supplier.ServiceConfig.Url.String(), + config.Proxies[proxyName].Suppliers[supplierName].ServiceConfig.Url.String(), + ) + + if supplier.ServiceConfig.Authentication != nil { + require.NotNil( + t, + config.Proxies[proxyName].Suppliers[supplierName].ServiceConfig.Authentication, + ) + + require.Equal( + t, + supplier.ServiceConfig.Authentication.Username, + config.Proxies[proxyName].Suppliers[supplierName].ServiceConfig.Authentication.Username, + ) + + require.Equal( + t, + supplier.ServiceConfig.Authentication.Password, + config.Proxies[proxyName].Suppliers[supplierName].ServiceConfig.Authentication.Password, + ) + } + + for headerKey, headerValue := range supplier.ServiceConfig.Headers { + require.Equal( + t, + headerValue, + config.Proxies[proxyName].Suppliers[supplierName].ServiceConfig.Headers[headerKey], + ) + } + + for i, host := range supplier.Hosts { + require.Contains( + t, + host, + config.Proxies[proxyName].Suppliers[supplierName].Hosts[i], + ) + } + } } }) } diff --git a/pkg/relayer/config/types.go b/pkg/relayer/config/types.go index 80288d622..ee5e54ca7 100644 --- a/pkg/relayer/config/types.go +++ b/pkg/relayer/config/types.go @@ -23,9 +23,10 @@ type YAMLRelayMinerPocketConfig struct { // YAMLRelayMinerProxyConfig is the structure used to unmarshal the proxy // section of the RelayMiner config file type YAMLRelayMinerProxyConfig struct { - Name string `yaml:"name"` - Host string `yaml:"host"` - Type string `yaml:"type"` + Name string `yaml:"name"` + Host string `yaml:"host"` + Type string `yaml:"type"` + XForwardedHostLookup bool `yaml:"x_forwarded_host_lookup"` } // YAMLRelayMinerSupplierConfig is the structure used to unmarshal the supplier @@ -85,6 +86,10 @@ type RelayMinerProxyConfig struct { Type string // Suppliers is a map of serviceIds -> RelayMinerSupplierConfig Suppliers map[string]*RelayMinerSupplierConfig + // XForwardedHostLookup is a flag that indicates whether the proxy server + // should lookup the host from the X-Forwarded-Host header before falling + // back to the Host header. + XForwardedHostLookup bool } // RelayMinerSupplierConfig is the structure resulting from parsing the supplier diff --git a/pkg/relayer/proxy/proxy_test.go b/pkg/relayer/proxy/proxy_test.go index 0c411b0b1..ba239f779 100644 --- a/pkg/relayer/proxy/proxy_test.go +++ b/pkg/relayer/proxy/proxy_test.go @@ -3,6 +3,7 @@ package proxy_test import ( "bytes" "context" + "fmt" "io" "net/http" "net/url" @@ -25,7 +26,7 @@ const blockHeight = 1 var ( // helpers used for tests that are initialized in init() supplierKeyName string - supplierEndpoints []*sharedtypes.SupplierEndpoint + supplierEndpoints map[string][]*sharedtypes.SupplierEndpoint appPrivateKey *secp256k1.PrivKey // proxiedServices is the parsed configuration of the RelayMinerProxyConfig proxiedServices map[string]*config.RelayMinerProxyConfig @@ -37,19 +38,25 @@ func init() { supplierKeyName = "supplierKeyName" appPrivateKey = secp256k1.GenPrivKey() - supplierEndpoints = []*sharedtypes.SupplierEndpoint{ - { - Url: "http://supplier:8545", - // TODO_EXTEND: Consider adding support for non JSON RPC services in the future - RpcType: sharedtypes.RPCType_JSON_RPC, + supplierEndpoints = map[string][]*sharedtypes.SupplierEndpoint{ + "service1": { + { + Url: "http://supplier:8545/", + // TODO_EXTEND: Consider adding support for non JSON RPC services in the future + RpcType: sharedtypes.RPCType_JSON_RPC, + }, }, - { - Url: "http://supplier:8546", - RpcType: sharedtypes.RPCType_GRPC, + "service2": { + { + Url: "http://supplier:8546/", + RpcType: sharedtypes.RPCType_GRPC, + }, }, - { - Url: "http://supplier:8547", - RpcType: sharedtypes.RPCType_GRPC, + "service3": { + { + Url: "http://supplier:8547/", + RpcType: sharedtypes.RPCType_GRPC, + }, }, } @@ -57,20 +64,22 @@ func init() { "server1": { Name: "server1", Type: "http", - Host: "localhost:8080", + Host: "127.0.0.1:8080", Suppliers: map[string]*config.RelayMinerSupplierConfig{ "service1": { - Name: "service1", - Type: "http", + Name: "service1", + Type: "http", + Hosts: []string{"supplier:8545"}, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ - Url: &url.URL{Scheme: "http", Host: "supplier:8545", Path: "/"}, + Url: &url.URL{Scheme: "http", Host: "127.0.0.1:8545", Path: "/"}, }, }, "service2": { - Name: "service2", - Type: "http", + Name: "service2", + Type: "http", + Hosts: []string{"supplier:8546"}, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ - Url: &url.URL{Scheme: "http", Host: "supplier:8546", Path: "/"}, + Url: &url.URL{Scheme: "http", Host: "127.0.0.1:8546", Path: "/"}, }, }, }, @@ -78,13 +87,14 @@ func init() { "server2": { Name: "server2", Type: "http", - Host: "localhost:8081", + Host: "127.0.0.1:8081", Suppliers: map[string]*config.RelayMinerSupplierConfig{ "service3": { - Name: "service3", - Type: "http", + Name: "service3", + Type: "http", + Hosts: []string{"supplier:8547"}, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ - Url: &url.URL{Scheme: "http", Host: "supplier:8547", Path: "/"}, + Url: &url.URL{Scheme: "http", Host: "127.0.0.1:8547", Path: "/"}, }, }, }, @@ -120,12 +130,12 @@ func TestRelayerProxy_StartAndStop(t *testing.T) { time.Sleep(100 * time.Millisecond) // Test that RelayerProxy is handling requests (ignoring the actual response content) - res, err := http.DefaultClient.Get(proxiedServices["server1"].Host) + res, err := http.DefaultClient.Get(fmt.Sprintf("http://%s/", proxiedServices["server1"].Host)) require.NoError(t, err) require.NotNil(t, res) // Test that RelayerProxy is handling requests from the other server - res, err = http.DefaultClient.Get(proxiedServices["server2"].Host) + res, err = http.DefaultClient.Get(fmt.Sprintf("http://%s/", proxiedServices["server2"].Host)) require.NoError(t, err) require.NotNil(t, res) @@ -182,16 +192,13 @@ func TestRelayerProxy_NoProxiedServices(t *testing.T) { func TestRelayerProxy_UnsupportedRpcType(t *testing.T) { ctx := context.TODO() - unsupportedSupplierEndpoint := []*sharedtypes.SupplierEndpoint{ - { - Url: "http://supplier:8545/jsonrpc", - // TODO_EXTEND: Consider adding support for non JSON RPC services in the future - RpcType: sharedtypes.RPCType_JSON_RPC, - }, - { - Url: "http://supplier:8545/grpc", - // TODO_EXTEND: Consider adding support for non JSON RPC services in the future - RpcType: sharedtypes.RPCType_GRPC, + unsupportedSupplierEndpoint := map[string][]*sharedtypes.SupplierEndpoint{ + "service1": { + { + Url: "http://unsupported:8545/jsonrpc", + // TODO_EXTEND: Consider adding support for non JSON RPC services in the future + RpcType: sharedtypes.RPCType_JSON_RPC, + }, }, } @@ -218,10 +225,102 @@ func TestRelayerProxy_UnsupportedRpcType(t *testing.T) { require.Error(t, err) } -// TODO_THIS_COMMIT: Test non configured advertised services -// TODO_THIS_COMMIT: Test unsupported transport type -// TODO_THIS_COMMIT: Test X-Forwarded-Host header is set -// TODO_THIS_COMMIT: Test unsupported host +func TestRelayerProxy_UnsupportedTransportType(t *testing.T) { + ctx := context.TODO() + + badTransportSupplierEndpoints := map[string][]*sharedtypes.SupplierEndpoint{ + "service1": { + { + Url: "xttp://supplier:8545/", + RpcType: sharedtypes.RPCType_JSON_RPC, + }, + }, + } + + unsupportedTransportProxy := map[string]*config.RelayMinerProxyConfig{ + "server1": { + Name: "server1", + Type: "xttp", + Host: "127.0.0.1:8080", + Suppliers: map[string]*config.RelayMinerSupplierConfig{ + "service1": { + Name: "service1", + Type: "xttp", + Hosts: []string{"supplier:8545"}, + ServiceConfig: &config.RelayMinerSupplierServiceConfig{ + Url: &url.URL{Scheme: "http", Host: "127.0.0.1:8545", Path: "/"}, + }, + }, + }, + }, + } + + unsupportedTransportTypeBehavior := []func(*testproxy.TestBehavior){ + testproxy.WithRelayerProxyDependencies(supplierKeyName), + + // The proxy is configured with an unsupported transport type for the proxy + testproxy.WithRelayerProxiedServices(unsupportedTransportProxy), + testproxy.WithDefaultSupplier(supplierKeyName, badTransportSupplierEndpoints), + testproxy.WithDefaultApplication(appPrivateKey), + testproxy.WithDefaultSessionSupplier(supplierKeyName, "service1", appPrivateKey), + } + + test := testproxy.NewRelayerProxyTestBehavior(ctx, t, unsupportedTransportTypeBehavior...) + + rp, err := proxy.NewRelayerProxy( + test.Deps, + proxy.WithSigningKeyName(supplierKeyName), + proxy.WithProxiedServicesEndpoints(unsupportedTransportProxy), + ) + require.NoError(t, err) + + err = rp.Start(ctx) + require.ErrorIs(t, err, proxy.ErrRelayerProxyUnsupportedTransportType) +} + +func TestRelayerProxy_NonConfiguredSupplierServices(t *testing.T) { + ctx := context.TODO() + + missingServicesProxy := map[string]*config.RelayMinerProxyConfig{ + "server1": { + Name: "server1", + Type: "http", + Host: "127.0.0.1:8080", + Suppliers: map[string]*config.RelayMinerSupplierConfig{ + "service1": { + Name: "service1", + Type: "http", + Hosts: []string{"supplier:8545"}, + ServiceConfig: &config.RelayMinerSupplierServiceConfig{ + Url: &url.URL{Scheme: "http", Host: "127.0.0.1:8545", Path: "/"}, + }, + }, + }, + }, + } + + unsupportedTransportTypeBehavior := []func(*testproxy.TestBehavior){ + testproxy.WithRelayerProxyDependencies(supplierKeyName), + + // The proxy is configured with an unsupported transport type for the proxy + testproxy.WithRelayerProxiedServices(missingServicesProxy), + testproxy.WithDefaultSupplier(supplierKeyName, supplierEndpoints), + testproxy.WithDefaultApplication(appPrivateKey), + testproxy.WithDefaultSessionSupplier(supplierKeyName, "service1", appPrivateKey), + } + + test := testproxy.NewRelayerProxyTestBehavior(ctx, t, unsupportedTransportTypeBehavior...) + + rp, err := proxy.NewRelayerProxy( + test.Deps, + proxy.WithSigningKeyName(supplierKeyName), + proxy.WithProxiedServicesEndpoints(missingServicesProxy), + ) + require.NoError(t, err) + + err = rp.Start(ctx) + require.ErrorIs(t, err, proxy.ErrRelayerProxyServiceEndpointNotHandled) +} // Test different RelayRequest scenarios func TestRelayerProxy_Relays(t *testing.T) { @@ -383,7 +482,11 @@ func sendRequestWithUnparsableBody( // Send non JSONRpc payload when the post request specifies json reader := io.NopCloser(bytes.NewReader([]byte("invalid request"))) - res, err := http.DefaultClient.Post(proxiedServices["server1"].Host, "application/json", reader) + res, err := http.DefaultClient.Post( + fmt.Sprintf("http://%s", proxiedServices["server1"].Host), + "application/json", + reader, + ) require.NoError(t, err) require.NotNil(t, res) @@ -400,7 +503,7 @@ func sendRequestWithMissingMeta( Payload: testproxy.PrepareJsonRPCRequestPayload(), } - return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) + return testproxy.MarshalAndSend(test, proxiedServices, "server1", "service1", req) } func sendRequestWithMissingSignature( @@ -415,7 +518,7 @@ func sendRequestWithMissingSignature( testproxy.PrepareJsonRPCRequestPayload(), ) req.Meta.Signature = nil - return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) + return testproxy.MarshalAndSend(test, proxiedServices, "server1", "service1", req) } func sendRequestWithInvalidSignature( @@ -431,7 +534,7 @@ func sendRequestWithInvalidSignature( ) req.Meta.Signature = []byte("invalid signature") - return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) + return testproxy.MarshalAndSend(test, proxiedServices, "server1", "service1", req) } func sendRequestWithMissingSessionHeaderApplicationAddress( @@ -454,7 +557,7 @@ func sendRequestWithMissingSessionHeaderApplicationAddress( // before looking at the application address req.Meta.Signature = testproxy.GetApplicationRingSignature(t, req, randomPrivKey) - return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) + return testproxy.MarshalAndSend(test, proxiedServices, "server1", "service1", req) } func sendRequestWithNonStakedApplicationAddress( @@ -473,7 +576,7 @@ func sendRequestWithNonStakedApplicationAddress( // Have a valid signature from the non staked key req.Meta.Signature = testproxy.GetApplicationRingSignature(t, req, randomPrivKey) - return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) + return testproxy.MarshalAndSend(test, proxiedServices, "server1", "service1", req) } func sendRequestWithRingSignatureMismatch( @@ -492,7 +595,7 @@ func sendRequestWithRingSignatureMismatch( randomPrivKey := secp256k1.GenPrivKey() req.Meta.Signature = testproxy.GetApplicationRingSignature(t, req, randomPrivKey) - return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) + return testproxy.MarshalAndSend(test, proxiedServices, "server1", "service1", req) } func sendRequestWithDifferentSession( @@ -509,7 +612,7 @@ func sendRequestWithDifferentSession( ) req.Meta.Signature = testproxy.GetApplicationRingSignature(t, req, appPrivateKey) - return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) + return testproxy.MarshalAndSend(test, proxiedServices, "server1", "service1", req) } func sendRequestWithInvalidRelaySupplier( @@ -525,7 +628,7 @@ func sendRequestWithInvalidRelaySupplier( ) req.Meta.Signature = testproxy.GetApplicationRingSignature(t, req, appPrivateKey) - return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) + return testproxy.MarshalAndSend(test, proxiedServices, "server1", "service1", req) } func sendRequestWithSignatureForDifferentPayload( @@ -543,7 +646,7 @@ func sendRequestWithSignatureForDifferentPayload( // Alter the request payload so the hash doesn't match the one used by the signature req.Payload = []byte(`{"method":"someMethod","id":1,"jsonrpc":"2.0","params":["alteredParam"]}`) - return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) + return testproxy.MarshalAndSend(test, proxiedServices, "server1", "service1", req) } func sendRequestWithSuccessfulReply( @@ -559,5 +662,5 @@ func sendRequestWithSuccessfulReply( ) req.Meta.Signature = testproxy.GetApplicationRingSignature(t, req, appPrivateKey) - return testproxy.MarshalAndSend(test, proxiedServices["server1"].Host, req) + return testproxy.MarshalAndSend(test, proxiedServices, "server1", "service1", req) } diff --git a/pkg/relayer/proxy/server_builder.go b/pkg/relayer/proxy/server_builder.go index 90359c288..fd94c270f 100644 --- a/pkg/relayer/proxy/server_builder.go +++ b/pkg/relayer/proxy/server_builder.go @@ -2,6 +2,9 @@ package proxy import ( "context" + "net/url" + + "golang.org/x/exp/slices" "github.com/pokt-network/poktroll/pkg/relayer" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" @@ -39,18 +42,26 @@ func (rp *relayerProxy) BuildProvidedServices(ctx context.Context) error { // service's endpoint for _, service := range supplier.Services { for _, endpoint := range service.Endpoints { + endpointUrl, err := url.Parse(endpoint.Url) + if err != nil { + return err + } found := false - // Iterate over the proxy configs and check if `endpoint.Url` is present - // and corresponds to the right service id + // Iterate over the proxy configs and check if `endpointUrl` is present + // in any of the proxy config's suppliers' service's hosts for _, proxyConfig := range rp.proxyConfigs { supplierService, ok := proxyConfig.Suppliers[service.Service.Id] - if ok && endpoint.Url == supplierService.ServiceConfig.Url.String() { + if ok && slices.Contains(supplierService.Hosts, endpointUrl.Host) { found = true break } } + if !found { - return ErrRelayerProxyServiceEndpointNotHandled + return ErrRelayerProxyServiceEndpointNotHandled.Wrapf( + "service endpoint %s not handled by proxy", + endpoint.Url, + ) } } } @@ -81,6 +92,7 @@ func (rp *relayerProxy) BuildProvidedServices(ctx context.Context) error { providedServices[proxyConfig.Name] = server } + rp.proxyServers = providedServices rp.supplierAddress = supplier.Address return nil diff --git a/pkg/relayer/proxy/synchronous.go b/pkg/relayer/proxy/synchronous.go index 15f9d8470..5d49ca327 100644 --- a/pkg/relayer/proxy/synchronous.go +++ b/pkg/relayer/proxy/synchronous.go @@ -60,6 +60,7 @@ func NewSynchronousServer( server: &http.Server{Addr: proxyConfig.Host}, relayerProxy: proxy, servedRelaysProducer: servedRelaysProducer, + proxyConfig: proxyConfig, } } @@ -90,10 +91,13 @@ func (sync *synchronousRPCServer) Stop(ctx context.Context) error { func (sync *synchronousRPCServer) ServeHTTP(writer http.ResponseWriter, request *http.Request) { ctx := request.Context() - // Get the original host from X-Forwarded-Host header if present. - originHost := request.Header.Get("X-Forwarded-Host") + var originHost string + // Get the original host from X-Forwarded-Host header if specified in the proxy config. + // and fall back to the Host header if it is not specified. + if sync.proxyConfig.XForwardedHostLookup { + originHost = request.Header.Get("X-Forwarded-Host") + } - // If X-Forwarded-Host is not present, fallback to the Host header if originHost == "" { originHost = request.Host } @@ -101,13 +105,14 @@ func (sync *synchronousRPCServer) ServeHTTP(writer http.ResponseWriter, request var supplierService *sharedtypes.Service var serviceUrl *url.URL +outer: // Get the Service and serviceUrl corresponding to the originHost. for _, supplierServiceConfig := range sync.proxyConfig.Suppliers { for _, host := range supplierServiceConfig.Hosts { if host == originHost { supplierService = sync.supplierServiceMap[supplierServiceConfig.Name] serviceUrl = supplierServiceConfig.ServiceConfig.Url - break + break outer } } } diff --git a/testutil/testproxy/relayerproxy.go b/testutil/testproxy/relayerproxy.go index 4ff4bc235..3f18d4748 100644 --- a/testutil/testproxy/relayerproxy.go +++ b/testutil/testproxy/relayerproxy.go @@ -6,6 +6,7 @@ import ( "encoding/json" "io" "net/http" + "net/url" "testing" "cosmossdk.io/depinject" @@ -108,18 +109,20 @@ func WithRelayerProxiedServices( proxiedServices map[string]*config.RelayMinerProxyConfig, ) func(*TestBehavior) { return func(test *TestBehavior) { - for serviceId, endpoint := range proxiedServices { - server := &http.Server{Addr: endpoint.Host} - server.Handler = http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Write(prepareJsonRPCResponsePayload()) - }) - go func() { server.ListenAndServe() }() - go func() { - <-test.ctx.Done() - server.Shutdown(test.ctx) - }() - - test.proxiedServices[serviceId] = server + for _, proxy := range proxiedServices { + for serviceId, service := range proxy.Suppliers { + server := &http.Server{Addr: service.ServiceConfig.Url.Host} + server.Handler = http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Write(prepareJsonRPCResponsePayload()) + }) + go func() { server.ListenAndServe() }() + go func() { + <-test.ctx.Done() + server.Shutdown(test.ctx) + }() + + test.proxiedServices[serviceId] = server + } } } } @@ -127,7 +130,7 @@ func WithRelayerProxiedServices( // WithDefaultSupplier creates the default staked supplier for the test func WithDefaultSupplier( supplierKeyName string, - supplierEndpoints []*sharedtypes.SupplierEndpoint, + supplierEndpoints map[string][]*sharedtypes.SupplierEndpoint, ) func(*TestBehavior) { return func(test *TestBehavior) { var keyring keyringtypes.Keyring @@ -143,12 +146,14 @@ func WithDefaultSupplier( supplierAddress := supplierAccAddress.String() - testqueryclients.AddSuppliersWithServiceEndpoints( - test.t, - supplierAddress, - "service1", - supplierEndpoints, - ) + for serviceId, endpoints := range supplierEndpoints { + testqueryclients.AddSuppliersWithServiceEndpoints( + test.t, + supplierAddress, + serviceId, + endpoints, + ) + } } } @@ -211,14 +216,25 @@ func WithDefaultSessionSupplier( // MarshalAndSend marshals the request and sends it to the provided service func MarshalAndSend( test *TestBehavior, - url string, + proxiedServices map[string]*config.RelayMinerProxyConfig, + server string, + service string, request *servicetypes.RelayRequest, ) (errCode int32, errorMessage string) { reqBz, err := request.Marshal() require.NoError(test.t, err) reader := io.NopCloser(bytes.NewReader(reqBz)) - res, err := http.DefaultClient.Post(url, "application/json", reader) + req := &http.Request{ + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + URL: &url.URL{Scheme: proxiedServices[server].Type, Host: proxiedServices[server].Host}, + Host: proxiedServices[server].Suppliers[service].Hosts[0], + Body: reader, + } + res, err := http.DefaultClient.Do(req) require.NoError(test.t, err) require.NotNil(test.t, res) From f6338ca32bed86147e652ce75fa91e0e68259afe Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Tue, 19 Dec 2023 07:01:00 +0100 Subject: [PATCH 18/34] chore: Add relay miner config and full example --- .../poktrolld/config/relayminer_config.yaml | 71 +++++++++++---- .../relayminer_config_full_example.yaml | 91 +++++++++++++++++++ 2 files changed, 146 insertions(+), 16 deletions(-) create mode 100644 localnet/poktrolld/config/relayminer_config_full_example.yaml diff --git a/localnet/poktrolld/config/relayminer_config.yaml b/localnet/poktrolld/config/relayminer_config.yaml index 935d85464..954181fb3 100644 --- a/localnet/poktrolld/config/relayminer_config.yaml +++ b/localnet/poktrolld/config/relayminer_config.yaml @@ -1,19 +1,58 @@ -# Pocket node URL that exposes CometBFT JSON-RPC API. -# This can be used by the Cosmos client SDK, event subscriptions, etc... -query_node_rpc_url: tcp://poktroll-sequencer:36657 -# Pocket node URL that exposes the Cosmos gRPC service. -tx_node_grpc_url: tcp://poktroll-sequencer:36658 -# Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. -# If unspecified, defaults to `tx_node_grpc_url`. -query_node_grpc_url: tcp://poktroll-sequencer:36658 +# TODO_CONSIDERATION: We don't need this now, but it would be beneficial if the +# logic handling this config file could be designed in such a way that it allows for +# "soft" config changes in the future, meaning changes without restarting a process. +# This would be useful for adding a proxy or a supplier without interrupting the service. + +pocket: + # Pocket node URL that exposes CometBFT JSON-RPC API. + # This can be used by the Cosmos client SDK, event subscriptions, etc... + query_node_url: tcp://poktroll-sequencer:36657 + # Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. + # If unspecified, defaults to `tx_node_grpc_url`. + query_node_grpc_url: tcp://poktroll-sequencer:36658 + # Pocket node URL that exposes the Cosmos gRPC service. + tx_node_grpc_url: tcp://poktroll-sequencer:36658 + # Name of the key (in the keyring) to sign transactions -signing_key_name: supplier1 -# TODO_TECHDEBT(#137, #130): Once the `relayer.json` config file is implemented AND a local LLM RPC service -# is supported on LocalNet, this needs to be expanded to include more than one service. The ability to support -# multiple services is already in place but currently (as seen below) is hardcoded. -# TODO_UPNEXT(@okdas): this hostname should be updated to match that of the in-tilt anvil service. -proxied_service_endpoints: - anvil: http://anvil:8547 - svc1: http://localhost:8082 +signing_key_name: servicer1 # Path to where the data backing SMT KV store exists on disk smt_store_path: smt_stores + +# Proxies are endpoints that expose different suppliers to the internet. +proxies: + # Name of the proxy. It will be used to reference in a supplier. Must be unique. + # Required. + # TODO_CONSIDERATION: if we enforce DNS compliant names, it can potentially + #become handy in the future. + # More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names + - name: http-example + # Type of proxy: can be one of http, ws, tcp. MUST match the type of the supplier. + # Required. + type: http + # Hostname to open port on. Use 0.0.0.0 in containerized environments, + # 127.0.0.1 with a reverse-proxy when there's another process on localhost + # that can be used as a reverse proxy (nginx, apache, traefik, etc.). + # Required + host: 127.0.0.1:8080 + +# Suppliers are different services that can be offered through RelayMiner. +# When a supplier is configured to use a proxy and staked appropriately, +# the relays will start flowing through RelayMiner. +suppliers: + # Name of the supplier offered to the network. + # Must be unique. + # Required. + - name: anvil + # Type of how the supplier offers service through the network. + # Must match the type of the proxy the supplier is connected to. + # Required. + type: http + # Configuration of the service offered through RelayMiner. + service_config: + # URL RelayMiner proxies the requests to. + # Required + url: http://anvil:8547/ + # Names of proxies that this supplier is connected to. The supplier will be reached through the proxies listed here. + # Required. + proxy_names: + - http-example # when the RelayMiner server builder runs. \ No newline at end of file diff --git a/localnet/poktrolld/config/relayminer_config_full_example.yaml b/localnet/poktrolld/config/relayminer_config_full_example.yaml new file mode 100644 index 000000000..026bd07c5 --- /dev/null +++ b/localnet/poktrolld/config/relayminer_config_full_example.yaml @@ -0,0 +1,91 @@ +pocket: + # Pocket node URL that exposes CometBFT JSON-RPC API. + # This can be used by the Cosmos client SDK, event subscriptions, etc... + query_node_url: tcp://poktroll-sequencer:36657 + # Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. + # If unspecified, defaults to `tx_node_grpc_url`. + query_node_grpc_url: tcp://poktroll-sequencer:36658 + # Pocket node URL that exposes the Cosmos gRPC service. + tx_node_grpc_url: tcp://poktroll-sequencer:36658 + +# Name of the key (in the keyring) to sign transactions +signing_key_name: servicer1 +# Path to where the data backing SMT KV store exists on disk +smt_store_path: smt_stores + +# Proxies are endpoints that expose different suppliers to the internet. +proxies: + # Name of the proxy. It will be used to reference in a supplier. Must be unique. + # Required. + # + # TODO_CONSIDERATION: if we enforce DNS compliant names, it can potentially become handy in the future. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names. Not necessary though. + - name: http-example + # Hostname to open port on. Use 0.0.0.0 in containerized environments, 127.0.0.1 with a reverse-proxy when there's another process on localhost that can be used as a reverse proxy (nginx, apache, traefik, etc.). + # Required + # + # TODO_IMPROVE: We can add UNIX sockets, in addition to host+port. This is a premature optimization as of now, but can be explored in the future. + host: 127.0.0.1:8080 + # Type of proxy: can be one of http, ws, tcp. MUST match the type of the supplier. + # Required. + type: http + + # TODO_IMPROVE: No need to implement HTTPS, but this is how it could potentially look. + # - name: example-how-we-can-support-https + # host: 0.0.0.0:8443 + # type: https + # tls: + # enabled: true + # certificate: /path/to/crt + # key: /path/to/key + +# Suppliers are different services that can be offered through RelayMiner. When a supplier is configured to use a proxy and +# staked appropriately, the relays will start flowing through RelayMiner. +suppliers: + # Name of the supplier offered to the network. + # Must be unique. + # Required. + - name: ethereum + # Type of how the supplier offers service through the network. + # Must match the type of the proxy the supplier is connected to. + # Required. + type: http + # Configuration of the service offered through RelayMiner. + service_config: + # URL RelayMiner proxies the requests to. + # Required + url: http://anvil.servicer:8545 + # Authentication for the service. HTTP Basic Auth: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication + # Optional. + authentication: + username: user + password: pwd + + # TODO_IMPROVE: since this is not supported in the mainnet, we don't need to support this now, but some services authenticate via a header. + headers: {} + # For example, if the service requires a header like `Authorization: Bearer ` + # Authorization: Bearer + + # A list of hosts the HTTP service is offered on. When linked to the proxy, that hostname is going to be used to route the request to the correct supplier. + # That hostname is what the user should stake the supplier for. + # Required. + # Must be unique within a proxy/proxies it is set up on. In other words, one proxy can't offer the same hostname more than once. + # + # TODO_CONSIDERATION: automatically add the `name` of the supplier to hosts for potential troubleshooting/debugging purposes. See below. + hosts: + - ethereum.devnet1.poktroll.com + # - ethereum # <- this part is be added automatically. + # Names of proxies that this supplier is connected to. The supplier will be reached through the proxies listed here. + # Required. + # + # TODO_DISCUSS: we can make this just a string instead of an array to make implementation easier. I feel like having multiple proxies can be harder to implement as the number of different variables increases. We can always add an array later if needed, for example in case we implement HTTPs. + proxy_names: + - http-example # when the RelayMiner server builder runs. + - name: 7b-llm-model + type: http + service_config: + url: http://llama-endpoint + hosts: + - 7b-llm-model.devnet1.poktroll.com + - 7b-llm-model # <- this part can be added automatically. + proxy_names: + - http-example # when the RelayMiner server builder runs. \ No newline at end of file From 8f907f756bdc3c329bbf71b2be193df53bdbd4a7 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 20 Dec 2023 05:46:43 +0100 Subject: [PATCH 19/34] chore: add valid relay miner config --- localnet/kubernetes/values-relayminer.yaml | 25 ++++++++++++++++--- .../poktrolld/config/relayminer_config.yaml | 8 +++--- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/localnet/kubernetes/values-relayminer.yaml b/localnet/kubernetes/values-relayminer.yaml index d65acd18a..65c569c8a 100644 --- a/localnet/kubernetes/values-relayminer.yaml +++ b/localnet/kubernetes/values-relayminer.yaml @@ -1,4 +1,23 @@ config: - query_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 - query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 - tx_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 + pocket: + query_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 + query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 + tx_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 + + signing_key_name: supplier1 + smt_store_path: smt_stores + + proxies: + - name: http-proxy + type: http + host: 0.0.0.0:8545 + + suppliers: + - name: anvil + type: http + service_config: + url: http://anvil:8547/ + proxy_names: + - http-proxy + hosts: + - tcp://relayminers:8545 \ No newline at end of file diff --git a/localnet/poktrolld/config/relayminer_config.yaml b/localnet/poktrolld/config/relayminer_config.yaml index 954181fb3..6b51d174e 100644 --- a/localnet/poktrolld/config/relayminer_config.yaml +++ b/localnet/poktrolld/config/relayminer_config.yaml @@ -6,7 +6,7 @@ pocket: # Pocket node URL that exposes CometBFT JSON-RPC API. # This can be used by the Cosmos client SDK, event subscriptions, etc... - query_node_url: tcp://poktroll-sequencer:36657 + query_node_rpc_url: tcp://poktroll-sequencer:36657 # Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. # If unspecified, defaults to `tx_node_grpc_url`. query_node_grpc_url: tcp://poktroll-sequencer:36658 @@ -14,7 +14,7 @@ pocket: tx_node_grpc_url: tcp://poktroll-sequencer:36658 # Name of the key (in the keyring) to sign transactions -signing_key_name: servicer1 +signing_key_name: supplier1 # Path to where the data backing SMT KV store exists on disk smt_store_path: smt_stores @@ -25,7 +25,7 @@ proxies: # TODO_CONSIDERATION: if we enforce DNS compliant names, it can potentially #become handy in the future. # More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names - - name: http-example + - name: http-proxy # Type of proxy: can be one of http, ws, tcp. MUST match the type of the supplier. # Required. type: http @@ -55,4 +55,4 @@ suppliers: # Names of proxies that this supplier is connected to. The supplier will be reached through the proxies listed here. # Required. proxy_names: - - http-example # when the RelayMiner server builder runs. \ No newline at end of file + - http-proxy \ No newline at end of file From d91fdd217db49c54ee6608b5408f4ef108c1af8e Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 20 Dec 2023 07:30:31 +0100 Subject: [PATCH 20/34] chore: Address request changes --- .../config/appgate_server_config.yaml | 14 ++-- .../poktrolld/config/relayminer_config.yaml | 8 +- pkg/appgateserver/cmd/cmd.go | 8 +- .../config/appgate_configs_reader.go | 26 +++--- .../config/appgate_configs_reader_test.go | 80 +++++++++---------- pkg/deps/config/suppliers.go | 52 +++++------- pkg/relayer/cmd/cmd.go | 8 +- .../config/relayminer_configs_reader.go | 22 ++--- .../config/relayminer_configs_reader_test.go | 78 +++++++++--------- 9 files changed, 143 insertions(+), 153 deletions(-) diff --git a/localnet/poktrolld/config/appgate_server_config.yaml b/localnet/poktrolld/config/appgate_server_config.yaml index 6a1512061..4c8d8bc06 100644 --- a/localnet/poktrolld/config/appgate_server_config.yaml +++ b/localnet/poktrolld/config/appgate_server_config.yaml @@ -1,14 +1,12 @@ -# Whether the server should sign all incoming requests with its own ring (for applications) -self_signing: true -# The name of the key (in the keyring) that will be used to sign relays -signing_key: app1 -# The host and port that the appgate server will listen on -listening_endpoint: http://localhost:42069 # Pocket node URL that exposes CometBFT JSON-RPC API. # This can be used by the Cosmos client SDK, event subscriptions, etc... query_node_rpc_url: tcp://poktroll-sequencer:36657 -# Pocket node URL that exposes the Cosmos gRPC service. -tx_node_grpc_url: tcp://poktroll-sequencer:36658 # Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. # If unspecified, defaults to `tx_node_grpc_url`. query_node_grpc_url: tcp://poktroll-sequencer:36658 +# The name of the key (in the keyring) that will be used to sign relays +signing_key: app1 +# Whether the server should sign all incoming requests with its own ring (for applications) +self_signing: true +# The host and port that the appgate server will listen on +listening_endpoint: http://localhost:42069 \ No newline at end of file diff --git a/localnet/poktrolld/config/relayminer_config.yaml b/localnet/poktrolld/config/relayminer_config.yaml index 935d85464..c3b97477b 100644 --- a/localnet/poktrolld/config/relayminer_config.yaml +++ b/localnet/poktrolld/config/relayminer_config.yaml @@ -2,12 +2,14 @@ # This can be used by the Cosmos client SDK, event subscriptions, etc... query_node_rpc_url: tcp://poktroll-sequencer:36657 # Pocket node URL that exposes the Cosmos gRPC service. +query_node_grpc_url: tcp://poktroll-sequencer:36658 +# Name of the key (in the keyring) to sign transactions tx_node_grpc_url: tcp://poktroll-sequencer:36658 # Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. # If unspecified, defaults to `tx_node_grpc_url`. -query_node_grpc_url: tcp://poktroll-sequencer:36658 -# Name of the key (in the keyring) to sign transactions signing_key_name: supplier1 +# Path to where the data backing SMT KV store exists on disk +smt_store_path: smt_stores # TODO_TECHDEBT(#137, #130): Once the `relayer.json` config file is implemented AND a local LLM RPC service # is supported on LocalNet, this needs to be expanded to include more than one service. The ability to support # multiple services is already in place but currently (as seen below) is hardcoded. @@ -15,5 +17,3 @@ signing_key_name: supplier1 proxied_service_endpoints: anvil: http://anvil:8547 svc1: http://localhost:8082 -# Path to where the data backing SMT KV store exists on disk -smt_store_path: smt_stores diff --git a/pkg/appgateserver/cmd/cmd.go b/pkg/appgateserver/cmd/cmd.go index 1b7e1f047..b61180ea4 100644 --- a/pkg/appgateserver/cmd/cmd.go +++ b/pkg/appgateserver/cmd/cmd.go @@ -25,9 +25,13 @@ import ( const omittedDefaultFlagValue = "explicitly omitting default" var ( + // flagAppGateConfig is the variable containing the AppGate config filepath + // sourced from the `--config` flag. flagAppGateConfig string - flagNodeRPCURL string - flagNodeGRPCURL string + // flagNodeRPCURL is the variable containing the Cosmos node RPC URL flag value. + flagNodeRPCURL string + // flagNodeGRPCURL is the variable containing the Cosmos node GRPC URL flag value. + flagNodeGRPCURL string ) // AppGateServerCmd returns the Cobra command for running the AppGate server. diff --git a/pkg/appgateserver/config/appgate_configs_reader.go b/pkg/appgateserver/config/appgate_configs_reader.go index ba03f8242..706c0b926 100644 --- a/pkg/appgateserver/config/appgate_configs_reader.go +++ b/pkg/appgateserver/config/appgate_configs_reader.go @@ -9,20 +9,20 @@ import ( // YAMLAppGateServerConfig is the structure used to unmarshal the AppGateServer config file // TODO_DOCUMENT(@red-0ne): Add proper README documentation for yaml config files. type YAMLAppGateServerConfig struct { - SelfSigning bool `yaml:"self_signing"` + QueryNodeRPCUrl string `yaml:"query_node_rpc_url"` + QueryNodeGRPCUrl string `yaml:"query_node_grpc_url"` SigningKey string `yaml:"signing_key"` + SelfSigning bool `yaml:"self_signing"` ListeningEndpoint string `yaml:"listening_endpoint"` - QueryNodeGRPCUrl string `yaml:"query_node_grpc_url"` - QueryNodeRPCUrl string `yaml:"query_node_rpc_url"` } // AppGateServerConfig is the structure describing the AppGateServer config type AppGateServerConfig struct { - SelfSigning bool + QueryNodeRPCUrl *url.URL + QueryNodeGRPCUrl *url.URL SigningKey string + SelfSigning bool ListeningEndpoint *url.URL - QueryNodeGRPCUrl *url.URL - QueryNodeRPCUrl *url.URL } // ParseAppGateServerConfigs parses the stake config file into a AppGateConfig @@ -39,11 +39,11 @@ func ParseAppGateServerConfigs(configContent []byte) (*AppGateServerConfig, erro return nil, ErrAppGateConfigUnmarshalYAML.Wrap(err.Error()) } - if yamlAppGateServerConfig.SigningKey == "" { + if len(yamlAppGateServerConfig.SigningKey) == 0 { return nil, ErrAppGateConfigEmptySigningKey } - if yamlAppGateServerConfig.ListeningEndpoint == "" { + if len(yamlAppGateServerConfig.ListeningEndpoint) == 0 { return nil, ErrAppGateConfigInvalidListeningEndpoint } @@ -52,7 +52,7 @@ func ParseAppGateServerConfigs(configContent []byte) (*AppGateServerConfig, erro return nil, ErrAppGateConfigInvalidListeningEndpoint.Wrap(err.Error()) } - if yamlAppGateServerConfig.QueryNodeGRPCUrl == "" { + if len(yamlAppGateServerConfig.QueryNodeGRPCUrl) == 0 { return nil, ErrAppGateConfigInvalidQueryNodeGRPCUrl } @@ -61,7 +61,7 @@ func ParseAppGateServerConfigs(configContent []byte) (*AppGateServerConfig, erro return nil, ErrAppGateConfigInvalidQueryNodeGRPCUrl.Wrap(err.Error()) } - if yamlAppGateServerConfig.QueryNodeRPCUrl == "" { + if len(yamlAppGateServerConfig.QueryNodeRPCUrl) == 0 { return nil, ErrAppGateConfigInvalidQueryNodeRPCUrl } @@ -72,11 +72,11 @@ func ParseAppGateServerConfigs(configContent []byte) (*AppGateServerConfig, erro // Populate the appGateServerConfig with the values from the yamlAppGateServerConfig appGateServerConfig := &AppGateServerConfig{ - SelfSigning: yamlAppGateServerConfig.SelfSigning, + QueryNodeRPCUrl: queryNodeRPCUrl, + QueryNodeGRPCUrl: queryNodeGRPCUrl, SigningKey: yamlAppGateServerConfig.SigningKey, + SelfSigning: yamlAppGateServerConfig.SelfSigning, ListeningEndpoint: listeningEndpoint, - QueryNodeGRPCUrl: queryNodeGRPCUrl, - QueryNodeRPCUrl: queryNodeRPCUrl, } return appGateServerConfig, nil diff --git a/pkg/appgateserver/config/appgate_configs_reader_test.go b/pkg/appgateserver/config/appgate_configs_reader_test.go index 28316a488..e11838153 100644 --- a/pkg/appgateserver/config/appgate_configs_reader_test.go +++ b/pkg/appgateserver/config/appgate_configs_reader_test.go @@ -16,7 +16,7 @@ func Test_ParseAppGateConfigs(t *testing.T) { tests := []struct { desc string - inputConfig string + inputConfigYAML string expectedError *sdkerrors.Error expectedConfig *config.AppGateServerConfig @@ -25,59 +25,59 @@ func Test_ParseAppGateConfigs(t *testing.T) { { desc: "valid: AppGateServer config", - inputConfig: ` - self_signing: true + inputConfigYAML: ` + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 signing_key: app1 + self_signing: true listening_endpoint: http://localhost:42069 - query_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 `, expectedError: nil, expectedConfig: &config.AppGateServerConfig{ - SelfSigning: true, + QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, SigningKey: "app1", + SelfSigning: true, ListeningEndpoint: &url.URL{Scheme: "http", Host: "localhost:42069"}, - QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, }, }, { desc: "valid: AppGateServer config with undefined self signing", - inputConfig: ` + inputConfigYAML: ` + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 signing_key: app1 listening_endpoint: http://localhost:42069 - query_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 `, expectedError: nil, expectedConfig: &config.AppGateServerConfig{ - SelfSigning: false, + QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, SigningKey: "app1", + SelfSigning: false, ListeningEndpoint: &url.URL{Scheme: "http", Host: "localhost:42069"}, - QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, }, }, // Invalid Configs { desc: "invalid: empty AppGateServer config", - inputConfig: ``, + inputConfigYAML: ``, expectedError: config.ErrAppGateConfigEmpty, }, { desc: "invalid: no signing key", - inputConfig: ` + inputConfigYAML: ` + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 + # NB: explicitly missing signing key self_signing: true - // explicitly missing signing key listening_endpoint: http://localhost:42069 - query_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 `, expectedError: config.ErrAppGateConfigUnmarshalYAML, @@ -85,12 +85,12 @@ func Test_ParseAppGateConfigs(t *testing.T) { { desc: "invalid: invalid listening endpoint", - inputConfig: ` - self_signing: true + inputConfigYAML: ` + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 signing_key: app1 + self_signing: true listening_endpoint: l&ocalhost:42069 - query_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 `, expectedError: config.ErrAppGateConfigInvalidListeningEndpoint, @@ -98,12 +98,12 @@ func Test_ParseAppGateConfigs(t *testing.T) { { desc: "invalid: invalid query node grpc url", - inputConfig: ` - self_signing: true + inputConfigYAML: ` + query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: 1&27.0.0.1:36658 signing_key: app1 + self_signing: true listening_endpoint: http://localhost:42069 - query_node_grpc_url: 1&27.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 `, expectedError: config.ErrAppGateConfigInvalidQueryNodeGRPCUrl, @@ -111,12 +111,12 @@ func Test_ParseAppGateConfigs(t *testing.T) { { desc: "invalid: missing query node grpc url", - inputConfig: ` - self_signing: true + inputConfigYAML: ` + query_node_rpc_url: tcp://127.0.0.1:36657 + # NB: explicitly missing query_node_grpc_url signing_key: app1 + self_signing: true listening_endpoint: http://localhost:42069 - // explicitly missing query_node_grpc_url - query_node_rpc_url: tcp://127.0.0.1:36657 `, expectedError: config.ErrAppGateConfigUnmarshalYAML, @@ -124,12 +124,12 @@ func Test_ParseAppGateConfigs(t *testing.T) { { desc: "invalid: invalid query node rpc url", - inputConfig: ` - self_signing: true + inputConfigYAML: ` + query_node_rpc_url: 1&27.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 signing_key: app1 + self_signing: true listening_endpoint: http://localhost:42069 - query_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: 1&27.0.0.1:36657 `, expectedError: config.ErrAppGateConfigInvalidQueryNodeRPCUrl, @@ -137,12 +137,12 @@ func Test_ParseAppGateConfigs(t *testing.T) { { desc: "invalid: missing query node rpc url", - inputConfig: ` - self_signing: true + inputConfigYAML: ` + # NB: explicitly missing query_node_rpc_url + query_node_grpc_url: tcp://127.0.0.1:36658 signing_key: app1 + self_signing: true listening_endpoint: http://localhost:42069 - query_node_grpc_url: tcp://127.0.0.1:36658 - // explicitly missing query_node_rpc_url `, expectedError: config.ErrAppGateConfigUnmarshalYAML, @@ -151,7 +151,7 @@ func Test_ParseAppGateConfigs(t *testing.T) { for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { - normalizedConfig := yaml.NormalizeYAMLIndentation(tt.inputConfig) + normalizedConfig := yaml.NormalizeYAMLIndentation(tt.inputConfigYAML) config, err := config.ParseAppGateServerConfigs([]byte(normalizedConfig)) if tt.expectedError != nil { diff --git a/pkg/deps/config/suppliers.go b/pkg/deps/config/suppliers.go index 4bf2c56da..1ecb78094 100644 --- a/pkg/deps/config/suppliers.go +++ b/pkg/deps/config/suppliers.go @@ -58,10 +58,8 @@ func NewSupplyLoggerFromCtx(ctx context.Context) SupplierFn { } } -// NewSupplyEventsQueryClientFn returns a new function which constructs an -// EventsQueryClient instance, with the given hostname converted into a websocket -// URL to subscribe to, and returns a new depinject.Config which is supplied -// with the given deps and the new EventsQueryClient. +// NewSupplyEventsQueryClientFn supplies a depinject config with an eventsQueryClient +// from the given queryNodeRPCURL. func NewSupplyEventsQueryClientFn(queryNodeRPCURL *url.URL) SupplierFn { return func( _ context.Context, @@ -76,10 +74,8 @@ func NewSupplyEventsQueryClientFn(queryNodeRPCURL *url.URL) SupplierFn { } } -// NewSupplyBlockClientFn returns a function which constructs a BlockClient -// instance with the given hostname, which is converted into a websocket URL, -// to listen for block events on-chain, and returns a new depinject.Config which -// is supplied with the given deps and the new BlockClient. +// NewSupplyBlockClientFn supplies a depinject config with a blockClient from the +// the given queryNodeRPCURL. func NewSupplyBlockClientFn(queryNodeRPCURL *url.URL) SupplierFn { return func( ctx context.Context, @@ -97,9 +93,9 @@ func NewSupplyBlockClientFn(queryNodeRPCURL *url.URL) SupplierFn { } } -// NewSupplyQueryClientContextFn returns a function with constructs a ClientContext -// instance with the given cmd and returns a new depinject.Config which is -// supplied with the given deps and the new ClientContext. +// NewSupplyQueryClientContextFn supplies a depinject config with a query +// +// ClientContext, a GRPC client connection, and a keyring from the given queryNodeGRPCURL. func NewSupplyQueryClientContextFn(queryNodeGRPCURL *url.URL) SupplierFn { return func(_ context.Context, deps depinject.Config, @@ -146,9 +142,10 @@ func NewSupplyQueryClientContextFn(queryNodeGRPCURL *url.URL) SupplierFn { } } -// NewSupplyTxClientContextFn returns a function with constructs a ClientContext -// instance with the given cmd and returns a new depinject.Config which is -// supplied with the given deps and the new ClientContext. +// NewSupplyTxClientContextFn supplies a depinject config with a TxClientContext +// from the given txNodeGRPCURL. +// TODO_TECHDEBT(#256): Remove this function once the as we may no longer +// need to supply a TxClientContext to the RelayMiner. func NewSupplyTxClientContextFn(txNodeGRPCURL *url.URL) SupplierFn { return func(_ context.Context, deps depinject.Config, @@ -193,9 +190,7 @@ func NewSupplyTxClientContextFn(txNodeGRPCURL *url.URL) SupplierFn { } } -// NewSupplyAccountQuerierFn returns a function with constructs an AccountQuerier -// instance with the required dependencies and returns a new depinject.Config which -// is supplied with the given deps and the new AccountQuerier. +// NewSupplyAccountQuerierFn supplies a depinject config with an AccountQuerier. func NewSupplyAccountQuerierFn() SupplierFn { return func( _ context.Context, @@ -213,10 +208,7 @@ func NewSupplyAccountQuerierFn() SupplierFn { } } -// NewSupplyApplicationQuerierFn returns a function with constructs an -// ApplicationQuerier instance with the required dependencies and returns a new -// instance with the required dependencies and returns a new depinject.Config -// which is supplied with the given deps and the new ApplicationQuerier. +// NewSupplyApplicationQuerierFn supplies a depinject config with an ApplicationQuerier. func NewSupplyApplicationQuerierFn() SupplierFn { return func( _ context.Context, @@ -234,9 +226,7 @@ func NewSupplyApplicationQuerierFn() SupplierFn { } } -// NewSupplySessionQuerierFn returns a function which constructs a -// SessionQuerier instance with the required dependencies and returns a new -// depinject.Config which is supplied with the given deps and the new SessionQuerier. +// NewSupplySessionQuerierFn supplies a depinject config with a SessionQuerier. func NewSupplySessionQuerierFn() SupplierFn { return func( _ context.Context, @@ -254,10 +244,7 @@ func NewSupplySessionQuerierFn() SupplierFn { } } -// NewSupplySupplierQuerierFn returns a function which constructs a -// SupplierQuerier instance with the required dependencies and returns a new -// instance with the required dependencies and returns a new depinject.Config -// which is supplied with the given deps and the new SupplierQuerier. +// NewSupplySupplierQuerierFn supplies a depinject config with a SupplierQuerier. func NewSupplySupplierQuerierFn() SupplierFn { return func( _ context.Context, @@ -275,9 +262,7 @@ func NewSupplySupplierQuerierFn() SupplierFn { } } -// NewSupplyRingCacheFn returns a function with constructs a RingCache instance -// with the required dependencies and returns a new depinject.Config which is -// supplied with the given deps and the new RingCache. +// NewSupplyRingCacheFn supplies a depinject config with a RingCache. func NewSupplyRingCacheFn() SupplierFn { return func( _ context.Context, @@ -295,9 +280,8 @@ func NewSupplyRingCacheFn() SupplierFn { } } -// NewSupplyPOKTRollSDKFn returns a function which constructs a -// POKTRollSDK instance with the required dependencies and returns a new -// depinject.Config which is supplied with the given deps and the new POKTRollSDK. +// NewSupplyPOKTRollSDKFn supplies a depinject config with a POKTRollSDK given +// the signing key name. func NewSupplyPOKTRollSDKFn(signingKeyName string) SupplierFn { return func( ctx context.Context, diff --git a/pkg/relayer/cmd/cmd.go b/pkg/relayer/cmd/cmd.go index f4d95a0b8..508cc0c91 100644 --- a/pkg/relayer/cmd/cmd.go +++ b/pkg/relayer/cmd/cmd.go @@ -34,9 +34,13 @@ const omittedDefaultFlagValue = "explicitly omitting default" // TODO_CONSIDERATION: Consider moving all flags defined in `/pkg` to a `flags.go` file. var ( + // flagRelayMinerConfig is the variable containing the relay miner config filepath + // sourced from the `--config` flag. flagRelayMinerConfig string - flagNodeRPCUrl string - flagNodeGRPCUrl string + // flagNodeRPCUrl is the variable containing the Cosmos node RPC URL flag value. + flagNodeRPCUrl string + // flagNodeGRPCUrl is the variable containing the Cosmos node GRPC URL flag value. + flagNodeGRPCUrl string ) // RelayerCmd returns the Cobra command for running the relay miner. diff --git a/pkg/relayer/config/relayminer_configs_reader.go b/pkg/relayer/config/relayminer_configs_reader.go index af2290564..e0e5a8cc1 100644 --- a/pkg/relayer/config/relayminer_configs_reader.go +++ b/pkg/relayer/config/relayminer_configs_reader.go @@ -9,22 +9,22 @@ import ( // YAMLRelayMinerConfig is the structure used to unmarshal the RelayMiner config file // TODO_DOCUMENT(@red-0ne): Add proper README documentation for yaml config files. type YAMLRelayMinerConfig struct { + QueryNodeRPCUrl string `yaml:"query_node_rpc_url"` QueryNodeGRPCUrl string `yaml:"query_node_grpc_url"` TxNodeGRPCUrl string `yaml:"tx_node_grpc_url"` - QueryNodeRPCUrl string `yaml:"query_node_rpc_url"` SigningKeyName string `yaml:"signing_key_name"` - ProxiedServiceEndpoints map[string]string `yaml:"proxied_service_endpoints"` SmtStorePath string `yaml:"smt_store_path"` + ProxiedServiceEndpoints map[string]string `yaml:"proxied_service_endpoints"` } // RelayMinerConfig is the structure describing the RelayMiner config type RelayMinerConfig struct { + QueryNodeRPCUrl *url.URL QueryNodeGRPCUrl *url.URL TxNodeGRPCUrl *url.URL - QueryNodeRPCUrl *url.URL SigningKeyName string - ProxiedServiceEndpoints map[string]*url.URL SmtStorePath string + ProxiedServiceEndpoints map[string]*url.URL } // ParseRelayMinerConfigs parses the relay miner config file into a RelayMinerConfig @@ -41,7 +41,7 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { } // Check that the tx node GRPC URL is provided - if yamlRelayMinerConfig.TxNodeGRPCUrl == "" { + if len(yamlRelayMinerConfig.TxNodeGRPCUrl) == 0 { return nil, ErrRelayMinerConfigInvalidTxNodeGRPCUrl.Wrap("tx node grpc url is required") } @@ -52,7 +52,7 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { } // Check that the query node GRPC URL is provided and default to the tx node GRPC URL if not - if yamlRelayMinerConfig.QueryNodeGRPCUrl == "" { + if len(yamlRelayMinerConfig.QueryNodeGRPCUrl) == 0 { yamlRelayMinerConfig.QueryNodeGRPCUrl = yamlRelayMinerConfig.TxNodeGRPCUrl } @@ -63,7 +63,7 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { } // Check that the network node websocket URL is provided - if yamlRelayMinerConfig.QueryNodeRPCUrl == "" { + if len(yamlRelayMinerConfig.QueryNodeRPCUrl) == 0 { return nil, ErrRelayMinerConfigInvalidQueryNodeRPCUrl.Wrap("query node rpc url is required") } @@ -73,11 +73,11 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { return nil, ErrRelayMinerConfigInvalidQueryNodeRPCUrl.Wrap(err.Error()) } - if yamlRelayMinerConfig.SigningKeyName == "" { + if len(yamlRelayMinerConfig.SigningKeyName) == 0 { return nil, ErrRelayMinerConfigInvalidSigningKeyName } - if yamlRelayMinerConfig.SmtStorePath == "" { + if len(yamlRelayMinerConfig.SmtStorePath) == 0 { return nil, ErrRelayMinerConfigInvalidSmtStorePath } @@ -100,12 +100,12 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { } relayMinerCMDConfig := &RelayMinerConfig{ + QueryNodeRPCUrl: queryNodeRPCUrl, QueryNodeGRPCUrl: queryNodeGRPCUrl, TxNodeGRPCUrl: txNodeGRPCUrl, - QueryNodeRPCUrl: queryNodeRPCUrl, SigningKeyName: yamlRelayMinerConfig.SigningKeyName, - ProxiedServiceEndpoints: proxiedServiceEndpoints, SmtStorePath: yamlRelayMinerConfig.SmtStorePath, + ProxiedServiceEndpoints: proxiedServiceEndpoints, } return relayMinerCMDConfig, nil diff --git a/pkg/relayer/config/relayminer_configs_reader_test.go b/pkg/relayer/config/relayminer_configs_reader_test.go index 705ce0176..b16b0aa1a 100644 --- a/pkg/relayer/config/relayminer_configs_reader_test.go +++ b/pkg/relayer/config/relayminer_configs_reader_test.go @@ -16,7 +16,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { tests := []struct { desc string - inputConfig string + inputConfigYAML string expectedError *sdkerrors.Error expectedConfig *config.RelayMinerConfig @@ -25,69 +25,69 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { { desc: "valid: relay miner config", - inputConfig: ` + inputConfigYAML: ` + query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 + smt_store_path: smt_stores proxied_service_endpoints: anvil: http://anvil:8080 svc1: http://svc1:8080 - smt_store_path: smt_stores `, expectedError: nil, expectedConfig: &config.RelayMinerConfig{ + QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, SigningKeyName: "servicer1", + SmtStorePath: "smt_stores", ProxiedServiceEndpoints: map[string]*url.URL{ "anvil": {Scheme: "http", Host: "anvil:8080"}, "svc1": {Scheme: "http", Host: "svc1:8080"}, }, - SmtStorePath: "smt_stores", }, }, { desc: "valid: relay miner config with query node grpc url defaulting to tx node grpc url", - inputConfig: ` - tx_node_grpc_url: tcp://127.0.0.1:36658 + inputConfigYAML: ` query_node_rpc_url: tcp://127.0.0.1:36657 + tx_node_grpc_url: tcp://127.0.0.1:36658 signing_key_name: servicer1 + smt_store_path: smt_stores proxied_service_endpoints: anvil: http://anvil:8080 svc1: http://svc1:8080 - smt_store_path: smt_stores `, expectedError: nil, expectedConfig: &config.RelayMinerConfig{ + QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, SigningKeyName: "servicer1", + SmtStorePath: "smt_stores", ProxiedServiceEndpoints: map[string]*url.URL{ "anvil": {Scheme: "http", Host: "anvil:8080"}, "svc1": {Scheme: "http", Host: "svc1:8080"}, }, - SmtStorePath: "smt_stores", }, }, // Invalid Configs { desc: "invalid: invalid tx node grpc url", - inputConfig: ` + inputConfigYAML: ` + query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: &tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 + smt_store_path: smt_stores proxied_service_endpoints: anvil: http://anvil:8080 svc1: http://svc1:8080 - smt_store_path: smt_stores `, expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, @@ -95,14 +95,14 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { { desc: "invalid: missing tx node grpc url", - inputConfig: ` - query_node_grpc_url: tcp://127.0.0.1:36658 + inputConfigYAML: ` query_node_rpc_url: tcp://127.0.0.1:36657 + query_node_grpc_url: tcp://127.0.0.1:36658 signing_key_name: servicer1 + smt_store_path: smt_stores proxied_service_endpoints: anvil: http://anvil:8080 svc1: http://svc1:8080 - smt_store_path: smt_stores `, expectedError: config.ErrRelayMinerConfigInvalidTxNodeGRPCUrl, @@ -110,15 +110,15 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { { desc: "invalid: invalid query node grpc url", - inputConfig: ` + inputConfigYAML: ` + query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: &tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 + smt_store_path: smt_stores proxied_service_endpoints: anvil: http://anvil:8080 svc1: http://svc1:8080 - smt_store_path: smt_stores `, expectedError: config.ErrRelayMinerConfigInvalidQueryNodeGRPCUrl, @@ -126,15 +126,15 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { { desc: "invalid: missing query node rpc url", - inputConfig: ` + inputConfigYAML: ` + # NB: explicitly missing query_node_rpc_url query_node_grpc_url: tcp://128.0.0.1:36658 tx_node_grpc_url: tcp://128.0.0.1:36658 - // explicitly missing query_node_rpc_url signing_key_name: servicer1 + smt_store_path: smt_stores proxied_service_endpoints: anvil: http://anvil:8080 svc1: http://svc1:8080 - smt_store_path: smt_stores `, expectedError: config.ErrRelayMinerConfigUnmarshalYAML, @@ -142,15 +142,15 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { { desc: "invalid: missing signing key name", - inputConfig: ` + inputConfigYAML: ` + query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 - // explicitly missing signing_key_name + # NB: explicitly missing signing_key_name + smt_store_path: smt_stores proxied_service_endpoints: anvil: http://anvil:8080 svc1: http://svc1:8080 - smt_store_path: smt_stores `, expectedError: config.ErrRelayMinerConfigUnmarshalYAML, @@ -158,10 +158,10 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { { desc: "invalid: missing smt store path", - inputConfig: ` + inputConfigYAML: ` + query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 proxied_service_endpoints: anvil: http://anvil:8080 @@ -173,13 +173,13 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { { desc: "invalid: empty proxied service endpoints", - inputConfig: ` + inputConfigYAML: ` + query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 - proxied_service_endpoints: smt_store_path: smt_stores + proxied_service_endpoints: `, expectedError: config.ErrRelayMinerConfigInvalidServiceEndpoint, @@ -187,15 +187,15 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { { desc: "invalid: invalid proxied service endpoint", - inputConfig: ` + inputConfigYAML: ` + query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 + smt_store_path: smt_stores proxied_service_endpoints: anvil: &http://anvil:8080 svc1: http://svc1:8080 - smt_store_path: smt_stores `, expectedError: config.ErrRelayMinerConfigInvalidServiceEndpoint, @@ -203,10 +203,10 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { { desc: "invalid: invalid tx node grpc url", - inputConfig: ` + inputConfigYAML: ` + query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: &tcp://127.0.0.1:36658 - query_node_rpc_url: tcp://127.0.0.1:36657 signing_key_name: servicer1 smt_store_path: smt_stores `, @@ -216,7 +216,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { { desc: "invalid: empty RelayMiner config file", - inputConfig: ``, + inputConfigYAML: ``, expectedError: config.ErrRelayMinerConfigEmpty, }, @@ -224,7 +224,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { - normalizedConfig := yaml.NormalizeYAMLIndentation(tt.inputConfig) + normalizedConfig := yaml.NormalizeYAMLIndentation(tt.inputConfigYAML) config, err := config.ParseRelayMinerConfigs([]byte(normalizedConfig)) if tt.expectedError != nil { From 496cde948871d13809c99dc030802cba94715158 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 20 Dec 2023 07:35:26 +0100 Subject: [PATCH 21/34] fix: Correct tests error assertions --- pkg/appgateserver/config/appgate_configs_reader_test.go | 6 +++--- pkg/relayer/config/relayminer_configs_reader_test.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/appgateserver/config/appgate_configs_reader_test.go b/pkg/appgateserver/config/appgate_configs_reader_test.go index e11838153..82ee6e53f 100644 --- a/pkg/appgateserver/config/appgate_configs_reader_test.go +++ b/pkg/appgateserver/config/appgate_configs_reader_test.go @@ -80,7 +80,7 @@ func Test_ParseAppGateConfigs(t *testing.T) { listening_endpoint: http://localhost:42069 `, - expectedError: config.ErrAppGateConfigUnmarshalYAML, + expectedError: config.ErrAppGateConfigEmptySigningKey, }, { desc: "invalid: invalid listening endpoint", @@ -119,7 +119,7 @@ func Test_ParseAppGateConfigs(t *testing.T) { listening_endpoint: http://localhost:42069 `, - expectedError: config.ErrAppGateConfigUnmarshalYAML, + expectedError: config.ErrAppGateConfigInvalidQueryNodeGRPCUrl, }, { desc: "invalid: invalid query node rpc url", @@ -145,7 +145,7 @@ func Test_ParseAppGateConfigs(t *testing.T) { listening_endpoint: http://localhost:42069 `, - expectedError: config.ErrAppGateConfigUnmarshalYAML, + expectedError: config.ErrAppGateConfigInvalidQueryNodeRPCUrl, }, } diff --git a/pkg/relayer/config/relayminer_configs_reader_test.go b/pkg/relayer/config/relayminer_configs_reader_test.go index b16b0aa1a..97e9c79d4 100644 --- a/pkg/relayer/config/relayminer_configs_reader_test.go +++ b/pkg/relayer/config/relayminer_configs_reader_test.go @@ -137,7 +137,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { svc1: http://svc1:8080 `, - expectedError: config.ErrRelayMinerConfigUnmarshalYAML, + expectedError: config.ErrRelayMinerConfigInvalidQueryNodeRPCUrl, }, { desc: "invalid: missing signing key name", @@ -153,7 +153,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { svc1: http://svc1:8080 `, - expectedError: config.ErrRelayMinerConfigUnmarshalYAML, + expectedError: config.ErrRelayMinerConfigInvalidSigningKeyName, }, { desc: "invalid: missing smt store path", From 135dcd99e2d853c338e449085dedbd9f4e45b39c Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 20 Dec 2023 14:16:51 +0100 Subject: [PATCH 22/34] chore: Address request changes --- .../poktrolld/config/relayminer_config.yaml | 21 ++-- .../relayminer_config_full_example.yaml | 77 +++++++----- pkg/appgateserver/cmd/cmd.go | 4 +- pkg/deps/config/suppliers.go | 6 +- pkg/relayer/cmd/cmd.go | 23 ++-- .../config/proxy_http_config_parser.go | 28 +++-- .../config/relayminer_configs_reader.go | 56 ++++++--- .../config/relayminer_configs_reader_test.go | 114 +++++++++--------- pkg/relayer/config/types.go | 49 +++++--- pkg/relayer/interface.go | 2 +- pkg/relayer/proxy/proxy.go | 14 ++- pkg/relayer/proxy/proxy_test.go | 39 ++++-- pkg/relayer/proxy/server_builder.go | 48 +++++--- pkg/relayer/proxy/synchronous.go | 19 ++- testutil/testproxy/relayerproxy.go | 18 ++- 15 files changed, 311 insertions(+), 207 deletions(-) diff --git a/localnet/poktrolld/config/relayminer_config.yaml b/localnet/poktrolld/config/relayminer_config.yaml index d86e266cf..7f1746e02 100644 --- a/localnet/poktrolld/config/relayminer_config.yaml +++ b/localnet/poktrolld/config/relayminer_config.yaml @@ -1,9 +1,9 @@ # TODO_CONSIDERATION: We don't need this now, but it would be beneficial if the # logic handling this config file could be designed in such a way that it allows for -# "soft" config changes in the future, meaning changes without restarting a process. +# "hot" config changes in the future, meaning changes without restarting a process. # This would be useful for adding a proxy or a supplier without interrupting the service. -pocket: +pocket_node: # Pocket node URL that exposes CometBFT JSON-RPC API. # This can be used by the Cosmos client SDK, event subscriptions, etc... query_node_rpc_url: tcp://poktroll-sequencer:36657 @@ -15,7 +15,8 @@ pocket: # Name of the key (in the keyring) to sign transactions signing_key_name: supplier1 -# Path to where the data backing SMT KV store exists on disk +# Relative path (on the relayminer's machine) to where the data backing +# SMT KV store exists on disk smt_store_path: smt_stores # Proxies are endpoints that expose different suppliers to the internet. @@ -23,16 +24,18 @@ proxies: # Name of the proxy. It will be used to reference in a supplier. Must be unique. # Required. # TODO_CONSIDERATION: if we enforce DNS compliant names, it can potentially - #become handy in the future. + # become handy in the future. # More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names - name: http-proxy - # Type of proxy: can be one of http, ws, tcp. MUST match the type of the supplier. + # Type of proxy: currently only http is supported but will support more + # (https, tcp, quic ...) in the future. + # MUST match the type of the supplier. # Required. type: http # Hostname to open port on. Use 0.0.0.0 in containerized environments, # 127.0.0.1 with a reverse-proxy when there's another process on localhost # that can be used as a reverse proxy (nginx, apache, traefik, etc.). - # Required + # Required. host: 127.0.0.1:8080 # Suppliers are different services that can be offered through RelayMiner. @@ -50,9 +53,11 @@ suppliers: # Configuration of the service offered through RelayMiner. service_config: # URL RelayMiner proxies the requests to. - # Required + # Required. url: http://anvil:8547/ - # Names of proxies that this supplier is connected to. The supplier will be reached through the proxies listed here. + # Names of proxies that this supplier is connected to. + # This MUST correspond to the name in the `proxies` section + # in order for the supplier to be accessible to the external network. # Required. proxy_names: - http-proxy diff --git a/localnet/poktrolld/config/relayminer_config_full_example.yaml b/localnet/poktrolld/config/relayminer_config_full_example.yaml index 026bd07c5..00048606f 100644 --- a/localnet/poktrolld/config/relayminer_config_full_example.yaml +++ b/localnet/poktrolld/config/relayminer_config_full_example.yaml @@ -1,7 +1,12 @@ -pocket: +# TODO_CONSIDERATION: We don't need this now, but it would be beneficial if the +# logic handling this config file could be designed in such a way that it allows for +# "hot" config changes in the future, meaning changes without restarting a process. +# This would be useful for adding a proxy or a supplier without interrupting the service. + +pocket_node: # Pocket node URL that exposes CometBFT JSON-RPC API. # This can be used by the Cosmos client SDK, event subscriptions, etc... - query_node_url: tcp://poktroll-sequencer:36657 + query_node_rpc_url: tcp://poktroll-sequencer:36657 # Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. # If unspecified, defaults to `tx_node_grpc_url`. query_node_grpc_url: tcp://poktroll-sequencer:36658 @@ -9,37 +14,42 @@ pocket: tx_node_grpc_url: tcp://poktroll-sequencer:36658 # Name of the key (in the keyring) to sign transactions -signing_key_name: servicer1 -# Path to where the data backing SMT KV store exists on disk +signing_key_name: supplier1 +# Relative path (on the relayminer's machine) to where the data backing +# SMT KV store exists on disk smt_store_path: smt_stores # Proxies are endpoints that expose different suppliers to the internet. proxies: # Name of the proxy. It will be used to reference in a supplier. Must be unique. # Required. - # - # TODO_CONSIDERATION: if we enforce DNS compliant names, it can potentially become handy in the future. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names. Not necessary though. + # TODO_CONSIDERATION: if we enforce DNS compliant names, it can potentially + # become handy in the future. + # More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names - name: http-example - # Hostname to open port on. Use 0.0.0.0 in containerized environments, 127.0.0.1 with a reverse-proxy when there's another process on localhost that can be used as a reverse proxy (nginx, apache, traefik, etc.). - # Required - # - # TODO_IMPROVE: We can add UNIX sockets, in addition to host+port. This is a premature optimization as of now, but can be explored in the future. - host: 127.0.0.1:8080 - # Type of proxy: can be one of http, ws, tcp. MUST match the type of the supplier. + # Type of proxy: currently only http is supported but will support more + # (https, tcp, quic ...) in the future. + # MUST match the type of the supplier. # Required. type: http + # Hostname to open port on. Use 0.0.0.0 in containerized environments, + # 127.0.0.1 with a reverse-proxy when there's another process on localhost + # that can be used as a reverse proxy (nginx, apache, traefik, etc.). + # Required. + host: 127.0.0.1:8080 - # TODO_IMPROVE: No need to implement HTTPS, but this is how it could potentially look. + # TODO_IMPROVE: https is not currently supported, but this is how it could potentially look. # - name: example-how-we-can-support-https - # host: 0.0.0.0:8443 # type: https + # host: 0.0.0.0:8443 # tls: # enabled: true # certificate: /path/to/crt # key: /path/to/key -# Suppliers are different services that can be offered through RelayMiner. When a supplier is configured to use a proxy and -# staked appropriately, the relays will start flowing through RelayMiner. +# Suppliers are different services that can be offered through RelayMiner. +# When a supplier is configured to use a proxy and staked appropriately, +# the relays will start flowing through RelayMiner. suppliers: # Name of the supplier offered to the network. # Must be unique. @@ -52,32 +62,39 @@ suppliers: # Configuration of the service offered through RelayMiner. service_config: # URL RelayMiner proxies the requests to. - # Required + # Required. url: http://anvil.servicer:8545 - # Authentication for the service. HTTP Basic Auth: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication + # Authentication for the service. + # HTTP Basic Auth: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication # Optional. authentication: username: user password: pwd - # TODO_IMPROVE: since this is not supported in the mainnet, we don't need to support this now, but some services authenticate via a header. + # TODO_IMPROVE: This is not supported in code yet, + # but some services authenticate via a header. + # Example, if the service requires a header like `Authorization: Bearer ` + # Authorization: Bearer + # Optional. headers: {} - # For example, if the service requires a header like `Authorization: Bearer ` - # Authorization: Bearer - # A list of hosts the HTTP service is offered on. When linked to the proxy, that hostname is going to be used to route the request to the correct supplier. + # A list of hosts the HTTP service is offering. + # When linked to the proxy, that hostname is going to be used to route the + # request to the correct supplier. # That hostname is what the user should stake the supplier for. + # Must be unique within a proxy/proxies it is set up on; + # in other words, one proxy can't offer the same hostname more than once. + # The `name` of the supplier is automatically added to the hosts section + # for potential troubleshooting/debugging purposes # Required. - # Must be unique within a proxy/proxies it is set up on. In other words, one proxy can't offer the same hostname more than once. - # - # TODO_CONSIDERATION: automatically add the `name` of the supplier to hosts for potential troubleshooting/debugging purposes. See below. hosts: - ethereum.devnet1.poktroll.com # - ethereum # <- this part is be added automatically. - # Names of proxies that this supplier is connected to. The supplier will be reached through the proxies listed here. + + # Names of proxies that this supplier is connected to. + # This MUST correspond to the name in the `proxies` section + # in order for the supplier to be accessible to the external network. # Required. - # - # TODO_DISCUSS: we can make this just a string instead of an array to make implementation easier. I feel like having multiple proxies can be harder to implement as the number of different variables increases. We can always add an array later if needed, for example in case we implement HTTPs. proxy_names: - http-example # when the RelayMiner server builder runs. - name: 7b-llm-model @@ -86,6 +103,6 @@ suppliers: url: http://llama-endpoint hosts: - 7b-llm-model.devnet1.poktroll.com - - 7b-llm-model # <- this part can be added automatically. + # - 7b-llm-model # <- this part can be added automatically. proxy_names: - - http-example # when the RelayMiner server builder runs. \ No newline at end of file + - http-example \ No newline at end of file diff --git a/pkg/appgateserver/cmd/cmd.go b/pkg/appgateserver/cmd/cmd.go index b61180ea4..cf5d8d582 100644 --- a/pkg/appgateserver/cmd/cmd.go +++ b/pkg/appgateserver/cmd/cmd.go @@ -161,7 +161,7 @@ func setupAppGateServerDependencies( if flagNodeGRPCURL != omittedDefaultFlagValue { queryNodeGRPCURL, err = url.Parse(flagNodeGRPCURL) if err != nil { - return nil, fmt.Errorf("failed to parse Cosmos node URL: %w", err) + return nil, fmt.Errorf("failed to parse grpc query URL: %w", err) } } @@ -171,7 +171,7 @@ func setupAppGateServerDependencies( if flagNodeRPCURL != omittedDefaultFlagValue { queryNodeRPCURL, err = url.Parse(flagNodeRPCURL) if err != nil { - return nil, fmt.Errorf("failed to parse Cosmos node URL: %w", err) + return nil, fmt.Errorf("failed to parse rpc query URL: %w", err) } } diff --git a/pkg/deps/config/suppliers.go b/pkg/deps/config/suppliers.go index 1ecb78094..8165e9f5f 100644 --- a/pkg/deps/config/suppliers.go +++ b/pkg/deps/config/suppliers.go @@ -101,7 +101,8 @@ func NewSupplyQueryClientContextFn(queryNodeGRPCURL *url.URL) SupplierFn { deps depinject.Config, cmd *cobra.Command, ) (depinject.Config, error) { - // Temporarily store the flag's current value + // Temporarily store the flag's current value to be restored later, after + // the client context has been created with queryNodeGRPCURL. // TODO_TECHDEBT(#223) Retrieve value from viper instead, once integrated. tmpGRPC, err := cmd.Flags().GetString(cosmosflags.FlagGRPC) if err != nil { @@ -151,7 +152,8 @@ func NewSupplyTxClientContextFn(txNodeGRPCURL *url.URL) SupplierFn { deps depinject.Config, cmd *cobra.Command, ) (depinject.Config, error) { - // Temporarily store the flag's current value + // Temporarily store the flag's current value to be restored later, after + // the client context has been created with txNodeGRPCURL. // TODO_TECHDEBT(#223) Retrieve value from viper instead, once integrated. tmpGRPC, err := cmd.Flags().GetString(cosmosflags.FlagGRPC) if err != nil { diff --git a/pkg/relayer/cmd/cmd.go b/pkg/relayer/cmd/cmd.go index cca971a51..0cb5242d4 100644 --- a/pkg/relayer/cmd/cmd.go +++ b/pkg/relayer/cmd/cmd.go @@ -70,7 +70,7 @@ for such operations.`, // Cosmos flags // TODO_TECHDEBT(#256): Remove unneeded cosmos flags. cmd.Flags().String(cosmosflags.FlagKeyringBackend, "", "Select keyring's backend (os|file|kwallet|pass|test)") - cmd.Flags().StringVar(&flagNodeRPCUrl, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialize the Cosmos query and tx contexts correctly. It can be used to override the `QueryNodeUrl` and `NetworkNodeUrl` fields in the config file if specified.") + cmd.Flags().StringVar(&flagNodeRPCUrl, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialize the Cosmos query and tx contexts correctly. It can be used to override the `QueryNodeUrl` and `txNodeUrl` fields in the config file if specified.") cmd.Flags().StringVar(&flagNodeGRPCUrl, cosmosflags.FlagGRPC, omittedDefaultFlagValue, "Register the default Cosmos node grpc flag, which is needed to initialize the Cosmos query context with grpc correctly. It can be used to override the `QueryNodeGRPCUrl` field in the config file if specified.") cmd.Flags().Bool(cosmosflags.FlagGRPCInsecure, true, "Used to initialize the Cosmos query context with grpc security options. It can be used to override the `QueryNodeGRPCInsecure` field in the config file if specified.") @@ -140,17 +140,17 @@ func setupRelayerDependencies( cmd *cobra.Command, relayMinerConfig *relayerconfig.RelayMinerConfig, ) (deps depinject.Config, err error) { - parsedFlagNodeRPCUrl := relayMinerConfig.Pocket.QueryNodeRPCUrl - queryNodeGRPCUrl := relayMinerConfig.Pocket.QueryNodeGRPCUrl - txNodeGRPCUrl := relayMinerConfig.Pocket.TxNodeGRPCUrl + queryNodeRPCUrl := relayMinerConfig.PocketNode.QueryNodeRPCUrl + queryNodeGRPCUrl := relayMinerConfig.PocketNode.QueryNodeGRPCUrl + txNodeGRPCUrl := relayMinerConfig.PocketNode.TxNodeGRPCUrl - // Override the config file's `QueryNodeGRPCUrl` and `NetworkNodeGRPCUrl` fields + // Override the config file's `QueryNodeGRPCUrl` and `txNodeGRPCUrl` fields // with the `--grpc-addr` flag if it was specified. // TODO(#223) Remove this check once viper is used as SoT for overridable config values. if flagNodeGRPCUrl != omittedDefaultFlagValue { parsedFlagNodeGRPCUrl, err := url.Parse(flagNodeGRPCUrl) if err != nil { - return nil, fmt.Errorf("failed to parse Cosmos node URL: %w", err) + return nil, fmt.Errorf("failed to parse grpc query URL: %w", err) } queryNodeGRPCUrl = parsedFlagNodeGRPCUrl txNodeGRPCUrl = parsedFlagNodeGRPCUrl @@ -160,10 +160,11 @@ func setupRelayerDependencies( // with the `--node` flag if it was specified. // TODO(#223) Remove this check once viper is used as SoT for overridable config values. if flagNodeRPCUrl != omittedDefaultFlagValue { - parsedFlagNodeRPCUrl, err = url.Parse(flagNodeRPCUrl) + parsedFlagNodeRPCUrl, err := url.Parse(flagNodeRPCUrl) if err != nil { - return nil, fmt.Errorf("failed to parse Cosmos node URL: %w", err) + return nil, fmt.Errorf("failed to parse rpc query URL: %w", err) } + queryNodeRPCUrl = parsedFlagNodeRPCUrl } signingKeyName := relayMinerConfig.SigningKeyName @@ -172,9 +173,9 @@ func setupRelayerDependencies( supplierFuncs := []config.SupplierFn{ config.NewSupplyLoggerFromCtx(ctx), - config.NewSupplyEventsQueryClientFn(parsedFlagNodeRPCUrl), // leaf - config.NewSupplyBlockClientFn(parsedFlagNodeRPCUrl), // leaf - config.NewSupplyQueryClientContextFn(queryNodeGRPCUrl), // leaf + config.NewSupplyEventsQueryClientFn(queryNodeRPCUrl), // leaf + config.NewSupplyBlockClientFn(queryNodeRPCUrl), // leaf + config.NewSupplyQueryClientContextFn(queryNodeGRPCUrl), // leaf supplyMiner, // leaf config.NewSupplyTxClientContextFn(txNodeGRPCUrl), // leaf config.NewSupplyAccountQuerierFn(), diff --git a/pkg/relayer/config/proxy_http_config_parser.go b/pkg/relayer/config/proxy_http_config_parser.go index 0dbd0c439..a8f655f14 100644 --- a/pkg/relayer/config/proxy_http_config_parser.go +++ b/pkg/relayer/config/proxy_http_config_parser.go @@ -5,14 +5,18 @@ import ( "net/url" ) -// parseRelayMinerConfigs populates the proxy fields of the target structure that +// parseHTTPProxyConfig populates the proxy fields of the target structure that // are relevant to the "http" type in the proxy section of the config file. -func parseHTTPProxyConfig( +// This function alters the target RelayMinerProxyConfig structure as a side effect. +func (proxyConfig *RelayMinerProxyConfig) parseHTTPProxyConfig( yamlProxyConfig YAMLRelayMinerProxyConfig, - proxyConfig *RelayMinerProxyConfig, ) error { - // Check if the proxy host is a valid URL - proxyUrl, err := url.Parse(fmt.Sprintf("tcp://%s", yamlProxyConfig.Host)) + // Check if the proxy host is a valid URL. + // Since `yamlProxyConfig.Host` is a string representing the host, we need to + // prepend it with the "http://" scheme to make it a valid URL; we end up + // using the `Host` field of the resulting `url.URL` struct, so the prepended + // scheme is irrelevant. + proxyUrl, err := url.Parse(fmt.Sprintf("http://%s", yamlProxyConfig.Host)) if err != nil { return ErrRelayMinerConfigInvalidProxy.Wrapf( "invalid proxy host %s", @@ -28,20 +32,20 @@ func parseHTTPProxyConfig( return nil } -// parseRelayMinerConfigs populates the supplier fields of the target structure +// parseHTTPSupplierConfig populates the supplier fields of the target structure // that are relevant to the "http" type in the supplier section of the config file. -func parseHTTPSupplierConfig( +// This function alters the target RelayMinerSupplierServiceConfig structure +// as a side effect. +func (supplierServiceConfig *RelayMinerSupplierServiceConfig) parseHTTPSupplierConfig( yamlSupplierServiceConfig YAMLRelayMinerSupplierServiceConfig, - supplierServiceConfig *RelayMinerSupplierServiceConfig, ) error { - var err error // Check if the supplier url is not empty - if yamlSupplierServiceConfig.Url == "" { + if len(yamlSupplierServiceConfig.Url) == 0 { return ErrRelayMinerConfigInvalidSupplier.Wrap("empty supplier url") } // Check if the supplier url is a valid URL - supplierServiceConfig.Url, err = url.Parse(yamlSupplierServiceConfig.Url) + supplierServiceUrl, err := url.Parse(yamlSupplierServiceConfig.Url) if err != nil { return ErrRelayMinerConfigInvalidSupplier.Wrapf( "invalid supplier url %s", @@ -49,6 +53,8 @@ func parseHTTPSupplierConfig( ) } + supplierServiceConfig.Url = supplierServiceUrl + // If the Authentication section is not empty, populate the supplier service // authentication fields if yamlSupplierServiceConfig.Authentication != (YAMLRelayMinerSupplierServiceAuthentication{}) { diff --git a/pkg/relayer/config/relayminer_configs_reader.go b/pkg/relayer/config/relayminer_configs_reader.go index ecdd7da8d..1ba500ceb 100644 --- a/pkg/relayer/config/relayminer_configs_reader.go +++ b/pkg/relayer/config/relayminer_configs_reader.go @@ -35,48 +35,50 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { } // Pocket node urls section - relayMinerPocketConfig := &RelayMinerPocketConfig{} - pocket := yamlRelayMinerConfig.Pocket + relayMinerPocketConfig := &RelayMinerPocketNodeConfig{} - if len(pocket.TxNodeGRPCUrl) == 0 { + if len(yamlRelayMinerConfig.PocketNode.TxNodeGRPCUrl) == 0 { return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrap("tx node grpc url is required") } // Check if the pocket node grpc url is a valid URL - relayMinerPocketConfig.TxNodeGRPCUrl, err = url.Parse(pocket.TxNodeGRPCUrl) + txNodeGRPCUrl, err := url.Parse(yamlRelayMinerConfig.PocketNode.TxNodeGRPCUrl) if err != nil { return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrapf( "invalid tx node grpc url %s", err.Error(), ) } + relayMinerPocketConfig.TxNodeGRPCUrl = txNodeGRPCUrl // If the query node grpc url is empty, use the tx node grpc url - if len(pocket.QueryNodeGRPCUrl) == 0 { + if len(yamlRelayMinerConfig.PocketNode.QueryNodeGRPCUrl) == 0 { relayMinerPocketConfig.QueryNodeGRPCUrl = relayMinerPocketConfig.TxNodeGRPCUrl } else { // If the query node grpc url is not empty, make sure it is a valid URL - relayMinerPocketConfig.QueryNodeGRPCUrl, err = url.Parse(pocket.QueryNodeGRPCUrl) + queryNodeGRPCUrl, err := url.Parse(yamlRelayMinerConfig.PocketNode.QueryNodeGRPCUrl) if err != nil { return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrapf( "invalid query node grpc url %s", err.Error(), ) } + relayMinerPocketConfig.QueryNodeGRPCUrl = queryNodeGRPCUrl } - if len(pocket.QueryNodeRPCUrl) == 0 { + if len(yamlRelayMinerConfig.PocketNode.QueryNodeRPCUrl) == 0 { return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrap("query node rpc url is required") } // Check if the query node rpc url is a valid URL - relayMinerPocketConfig.QueryNodeRPCUrl, err = url.Parse(pocket.QueryNodeRPCUrl) + queryNodeRPCUrl, err := url.Parse(yamlRelayMinerConfig.PocketNode.QueryNodeRPCUrl) if err != nil { return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrapf( "invalid query node rpc url %s", err.Error(), ) } + relayMinerPocketConfig.QueryNodeRPCUrl = queryNodeRPCUrl // Proxies section // At least one proxy is required @@ -84,10 +86,9 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { return nil, ErrRelayMinerConfigInvalidProxy.Wrap("no proxies provided") } - proxies := yamlRelayMinerConfig.Proxies relayMinerProxiesConfig := make(map[string]*RelayMinerProxyConfig) - for _, yamlProxyConfig := range proxies { + for _, yamlProxyConfig := range yamlRelayMinerConfig.Proxies { // Proxy name is required if len(yamlProxyConfig.Name) == 0 { return nil, ErrRelayMinerConfigInvalidProxy.Wrap("proxy name is required") @@ -110,7 +111,7 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { // Populate the proxy fields that are relevant to each supported proxy type switch yamlProxyConfig.Type { case "http": - if err := parseHTTPProxyConfig(yamlProxyConfig, proxyConfig); err != nil { + if err := proxyConfig.parseHTTPProxyConfig(yamlProxyConfig); err != nil { return nil, err } default: @@ -120,16 +121,24 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { yamlProxyConfig.Type, ) } - proxyConfig.Type = yamlProxyConfig.Type + + switch yamlProxyConfig.Type { + case "http": + proxyConfig.Type = ProxyTypeHTTP + default: + ErrRelayMinerConfigInvalidProxy.Wrapf( + "invalid proxy type %s", + yamlProxyConfig.Type, + ) + } relayMinerProxiesConfig[proxyConfig.Name] = proxyConfig } // Suppliers section - suppliers := yamlRelayMinerConfig.Suppliers relayMinerSuppliersConfig := make(map[string]*RelayMinerSupplierConfig) - for _, yamlSupplierConfig := range suppliers { + for _, yamlSupplierConfig := range yamlRelayMinerConfig.Suppliers { // Supplier name is required if len(yamlSupplierConfig.Name) == 0 { return nil, ErrRelayMinerConfigInvalidSupplier.Wrap("supplier name is required") @@ -192,10 +201,8 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { // by their own functions. switch yamlSupplierConfig.Type { case "http": - if err := parseHTTPSupplierConfig( - yamlSupplierConfig.ServiceConfig, - supplierConfig.ServiceConfig, - ); err != nil { + if err := supplierConfig.ServiceConfig. + parseHTTPSupplierConfig(yamlSupplierConfig.ServiceConfig); err != nil { return nil, err } default: @@ -205,7 +212,16 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { yamlSupplierConfig.Type, ) } - supplierConfig.Type = yamlSupplierConfig.Type + + switch yamlSupplierConfig.Type { + case "http": + supplierConfig.Type = ProxyTypeHTTP + default: + ErrRelayMinerConfigInvalidProxy.Wrapf( + "invalid proxy type %s", + yamlSupplierConfig.Type, + ) + } // Check if the supplier has proxies if len(yamlSupplierConfig.ProxyNames) == 0 { @@ -258,7 +274,7 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { // Populate the relay miner config relayMinerCMDConfig := &RelayMinerConfig{ - Pocket: relayMinerPocketConfig, + PocketNode: relayMinerPocketConfig, SigningKeyName: yamlRelayMinerConfig.SigningKeyName, SmtStorePath: yamlRelayMinerConfig.SmtStorePath, Proxies: relayMinerProxiesConfig, diff --git a/pkg/relayer/config/relayminer_configs_reader_test.go b/pkg/relayer/config/relayminer_configs_reader_test.go index 4c5f7bde7..90d485880 100644 --- a/pkg/relayer/config/relayminer_configs_reader_test.go +++ b/pkg/relayer/config/relayminer_configs_reader_test.go @@ -26,7 +26,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "valid: relay miner config", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -54,7 +54,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { expectedError: nil, expectedConfig: &config.RelayMinerConfig{ - Pocket: &config.RelayMinerPocketConfig{ + PocketNode: &config.RelayMinerPocketNodeConfig{ QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, @@ -65,12 +65,12 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { "http-example": { Name: "http-example", Host: "127.0.0.1:8080", - Type: "http", + Type: config.ProxyTypeHTTP, XForwardedHostLookup: false, Suppliers: map[string]*config.RelayMinerSupplierConfig{ "ethereum": { Name: "ethereum", - Type: "http", + Type: config.ProxyTypeHTTP, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, Authentication: &config.RelayMinerSupplierServiceAuthentication{ @@ -93,7 +93,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "valid: multiple suppliers, single proxy", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -129,7 +129,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { expectedError: nil, expectedConfig: &config.RelayMinerConfig{ - Pocket: &config.RelayMinerPocketConfig{ + PocketNode: &config.RelayMinerPocketNodeConfig{ QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, @@ -140,12 +140,12 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { "http-example": { Name: "http-example", Host: "127.0.0.1:8080", - Type: "http", + Type: config.ProxyTypeHTTP, XForwardedHostLookup: false, Suppliers: map[string]*config.RelayMinerSupplierConfig{ "ethereum": { Name: "ethereum", - Type: "http", + Type: config.ProxyTypeHTTP, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, Authentication: &config.RelayMinerSupplierServiceAuthentication{ @@ -161,7 +161,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { }, "7b-llm-model": { Name: "7b-llm-model", - Type: "http", + Type: config.ProxyTypeHTTP, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "llama-endpoint"}, }, @@ -179,7 +179,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "valid: multiple proxies for a single supplier, no auth", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -206,7 +206,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { expectedError: nil, expectedConfig: &config.RelayMinerConfig{ - Pocket: &config.RelayMinerPocketConfig{ + PocketNode: &config.RelayMinerPocketNodeConfig{ QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, @@ -217,12 +217,12 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { "first-proxy": { Name: "first-proxy", Host: "127.0.0.1:8080", - Type: "http", + Type: config.ProxyTypeHTTP, XForwardedHostLookup: false, Suppliers: map[string]*config.RelayMinerSupplierConfig{ "ethereum": { Name: "ethereum", - Type: "http", + Type: config.ProxyTypeHTTP, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, }, @@ -235,12 +235,12 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { "second-proxy": { Name: "second-proxy", Host: "127.0.0.1:8081", - Type: "http", + Type: config.ProxyTypeHTTP, XForwardedHostLookup: false, Suppliers: map[string]*config.RelayMinerSupplierConfig{ "ethereum": { Name: "ethereum", - Type: "http", + Type: config.ProxyTypeHTTP, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, }, @@ -257,7 +257,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "valid: relay miner config with query node grpc url defaulting to tx node grpc url", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 tx_node_grpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 @@ -280,7 +280,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { expectedError: nil, expectedConfig: &config.RelayMinerConfig{ - Pocket: &config.RelayMinerPocketConfig{ + PocketNode: &config.RelayMinerPocketNodeConfig{ QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, @@ -291,12 +291,12 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { "http-example": { Name: "http-example", Host: "127.0.0.1:8080", - Type: "http", + Type: config.ProxyTypeHTTP, XForwardedHostLookup: false, Suppliers: map[string]*config.RelayMinerSupplierConfig{ "ethereum": { Name: "ethereum", - Type: "http", + Type: config.ProxyTypeHTTP, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, }, @@ -314,7 +314,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "valid: relay miner config with x_forwarded_host_lookup set to true", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -339,7 +339,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { expectedError: nil, expectedConfig: &config.RelayMinerConfig{ - Pocket: &config.RelayMinerPocketConfig{ + PocketNode: &config.RelayMinerPocketNodeConfig{ QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, @@ -350,12 +350,12 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { "http-example": { Name: "http-example", Host: "127.0.0.1:8080", - Type: "http", + Type: config.ProxyTypeHTTP, XForwardedHostLookup: true, Suppliers: map[string]*config.RelayMinerSupplierConfig{ "ethereum": { Name: "ethereum", - Type: "http", + Type: config.ProxyTypeHTTP, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, }, @@ -374,7 +374,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: invalid tx node grpc url", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: &tcp://127.0.0.1:36659 @@ -401,7 +401,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: missing tx node grpc url", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 # explicitly omitted tx node grpc url query_node_grpc_url: tcp://127.0.0.1:36658 @@ -428,7 +428,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: invalid query node grpc url", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: &tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -455,7 +455,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: invalid query node rpc url", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: &tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -482,7 +482,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: missing query node rpc url", inputConfigYAML: ` - pocket: + pocket_node: # explicitly omitted query node rpc url query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -509,7 +509,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: missing signing key name", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -536,7 +536,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: missing smt store path", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -563,7 +563,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: missing proxies section", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -587,7 +587,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: empty proxies section", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -611,7 +611,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: omitted proxy name", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -638,7 +638,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: empty proxy name", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -665,7 +665,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: missing http proxy host", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -692,7 +692,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: empty http proxy host", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -719,7 +719,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: missing proxy type", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -746,7 +746,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: empty proxy type", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -773,7 +773,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: unsupported proxy type", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -800,7 +800,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: missing supplier name", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -827,7 +827,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: empty supplier name", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -854,7 +854,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: unsupported supplier type", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -881,7 +881,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: missing supplier type", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -908,7 +908,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: empty supplier type", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -935,7 +935,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: bad supplier service config url", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -962,7 +962,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: empty supplier service config url", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -989,7 +989,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: missing supplier service config url", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -1016,7 +1016,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: bad supplier host", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -1043,7 +1043,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: blank supplier host", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -1070,7 +1070,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: empty supplier proxy references", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -1097,7 +1097,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { desc: "invalid: empty supplier proxy references", inputConfigYAML: ` - pocket: + pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 tx_node_grpc_url: tcp://127.0.0.1:36659 @@ -1170,20 +1170,20 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { require.Equal( t, - tt.expectedConfig.Pocket.QueryNodeGRPCUrl.String(), - config.Pocket.QueryNodeGRPCUrl.String(), + tt.expectedConfig.PocketNode.QueryNodeGRPCUrl.String(), + config.PocketNode.QueryNodeGRPCUrl.String(), ) require.Equal( t, - tt.expectedConfig.Pocket.QueryNodeRPCUrl.String(), - config.Pocket.QueryNodeRPCUrl.String(), + tt.expectedConfig.PocketNode.QueryNodeRPCUrl.String(), + config.PocketNode.QueryNodeRPCUrl.String(), ) require.Equal( t, - tt.expectedConfig.Pocket.TxNodeGRPCUrl.String(), - config.Pocket.TxNodeGRPCUrl.String(), + tt.expectedConfig.PocketNode.TxNodeGRPCUrl.String(), + config.PocketNode.TxNodeGRPCUrl.String(), ) for proxyName, proxy := range tt.expectedConfig.Proxies { diff --git a/pkg/relayer/config/types.go b/pkg/relayer/config/types.go index ee5e54ca7..9e4ef4a82 100644 --- a/pkg/relayer/config/types.go +++ b/pkg/relayer/config/types.go @@ -2,30 +2,37 @@ package config import "net/url" +type ProxyType int + +const ( + ProxyTypeHTTP ProxyType = iota +) + // YAMLRelayMinerConfig is the structure used to unmarshal the RelayMiner config file -// TODO_DOCUMENT(@red-0ne): Add proper README documentation for yaml config files. +// TODO_DOCUMENT(@red-0ne): Add proper README documentation for yaml config files +// and update inline comments accordingly. type YAMLRelayMinerConfig struct { + PocketNode YAMLRelayMinerPocketNodeConfig `yaml:"pocket_node"` SigningKeyName string `yaml:"signing_key_name"` SmtStorePath string `yaml:"smt_store_path"` - Pocket YAMLRelayMinerPocketConfig `yaml:"pocket"` Proxies []YAMLRelayMinerProxyConfig `yaml:"proxies"` Suppliers []YAMLRelayMinerSupplierConfig `yaml:"suppliers"` } -// YAMLRelayMinerPocketConfig is the structure used to unmarshal the pocket +// YAMLRelayMinerPocketNodeConfig is the structure used to unmarshal the pocket // node URLs section of the RelayMiner config file -type YAMLRelayMinerPocketConfig struct { +type YAMLRelayMinerPocketNodeConfig struct { + QueryNodeRPCUrl string `yaml:"query_node_rpc_url"` QueryNodeGRPCUrl string `yaml:"query_node_grpc_url"` TxNodeGRPCUrl string `yaml:"tx_node_grpc_url"` - QueryNodeRPCUrl string `yaml:"query_node_rpc_url"` } // YAMLRelayMinerProxyConfig is the structure used to unmarshal the proxy // section of the RelayMiner config file type YAMLRelayMinerProxyConfig struct { Name string `yaml:"name"` - Host string `yaml:"host"` Type string `yaml:"type"` + Host string `yaml:"host"` XForwardedHostLookup bool `yaml:"x_forwarded_host_lookup"` } @@ -34,8 +41,8 @@ type YAMLRelayMinerProxyConfig struct { type YAMLRelayMinerSupplierConfig struct { Name string `yaml:"name"` Type string `yaml:"type"` - ServiceConfig YAMLRelayMinerSupplierServiceConfig `yaml:"service_config"` Hosts []string `yaml:"hosts"` + ServiceConfig YAMLRelayMinerSupplierServiceConfig `yaml:"service_config"` ProxyNames []string `yaml:"proxy_names"` } @@ -57,18 +64,18 @@ type YAMLRelayMinerSupplierServiceAuthentication struct { // RelayMinerConfig is the structure describing the RelayMiner config type RelayMinerConfig struct { + PocketNode *RelayMinerPocketNodeConfig SigningKeyName string SmtStorePath string - Pocket *RelayMinerPocketConfig Proxies map[string]*RelayMinerProxyConfig } -// RelayMinerPocketConfig is the structure resulting from parsing the pocket +// RelayMinerPocketNodeConfig is the structure resulting from parsing the pocket // node URLs section of the RelayMiner config file -type RelayMinerPocketConfig struct { +type RelayMinerPocketNodeConfig struct { + QueryNodeRPCUrl *url.URL QueryNodeGRPCUrl *url.URL TxNodeGRPCUrl *url.URL - QueryNodeRPCUrl *url.URL } // RelayMinerProxyConfig is the structure resulting from parsing the proxy @@ -79,17 +86,17 @@ type RelayMinerPocketConfig struct { type RelayMinerProxyConfig struct { // Name is the name of the proxy server, used to identify it in the config Name string + // Type is the transport protocol used by the proxy server like (http, https, etc.) + Type ProxyType // Host is the host on which the proxy server will listen for incoming // relay requests Host string - // Type is the transport protocol used by the proxy server like (http, https, etc.) - Type string - // Suppliers is a map of serviceIds -> RelayMinerSupplierConfig - Suppliers map[string]*RelayMinerSupplierConfig // XForwardedHostLookup is a flag that indicates whether the proxy server // should lookup the host from the X-Forwarded-Host header before falling // back to the Host header. XForwardedHostLookup bool + // Suppliers is a map of serviceIds -> RelayMinerSupplierConfig + Suppliers map[string]*RelayMinerSupplierConfig } // RelayMinerSupplierConfig is the structure resulting from parsing the supplier @@ -99,27 +106,29 @@ type RelayMinerSupplierConfig struct { Name string // Type is the transport protocol used by the supplier, it must match the // type of the proxy it is associated with. - Type string + Type ProxyType // Hosts is a list of hosts advertised on-chain by the supplier, the corresponding // proxy server will accept relay requests for these hosts. Hosts []string // ServiceConfig is the config of the service that relays will be proxied to. + // Other supplier types may embed other fields in the future. eg. "https" may + // embed a TLS config. ServiceConfig *RelayMinerSupplierServiceConfig } // RelayMinerSupplierServiceConfig is the structure resulting from parsing the supplier // service sub-section of the RelayMiner config file. -// If the supplier is of type "http", it may embed a basic auth structure and -// a map of headers to be used for other authentication means. -// Other supplier types may embed other fields in the future. eg. "https" may -// embed a TLS config. type RelayMinerSupplierServiceConfig struct { // Url is the URL of the service that relays will be proxied to. Url *url.URL // Authentication is the basic auth structure used to authenticate to the // request being proxied from the current proxy server. + // If `RelayMinerSupplierConfig.Type` is `ProxyTypeHTTP` then `Authentication` + // may be a non-nil pointer to a `RelayMinerSupplierServiceAuthentication` Authentication *RelayMinerSupplierServiceAuthentication // Headers is a map of headers to be used for other authentication means. + // If `RelayMinerSupplierConfig.Type` is `ProxyTypeHTTP` then `Headers` may + // be a non-nil pointer to a `map[string]string` Headers map[string]string } diff --git a/pkg/relayer/interface.go b/pkg/relayer/interface.go index 81fc81515..7605b74f5 100644 --- a/pkg/relayer/interface.go +++ b/pkg/relayer/interface.go @@ -64,7 +64,7 @@ type RelayerProxy interface { VerifyRelayRequest( ctx context.Context, relayRequest *servicetypes.RelayRequest, - service *sharedtypes.Service, + serviceId *sharedtypes.Service, ) error // SignRelayResponse is a shared method used by RelayServers to sign diff --git a/pkg/relayer/proxy/proxy.go b/pkg/relayer/proxy/proxy.go index 8805c67c9..3b5c69c12 100644 --- a/pkg/relayer/proxy/proxy.go +++ b/pkg/relayer/proxy/proxy.go @@ -43,13 +43,14 @@ type relayerProxy struct { // which is needed to check if the relay proxy should be serving an incoming relay request. sessionQuerier client.SessionQueryClient - // proxyServers is a map of the proxy server provided by the relayer proxy. Each provided service - // has the necessary information to start the server that listens for incoming relay requests and - // the client that relays the request to the supported proxied service. + // proxyServers is a map of proxyName -> RelayServer provided by the relayer proxy, + // where proxyName is the name of the proxy defined in the config file and + // RelayServer is the server that listens for incoming relay requests. proxyServers map[string]relayer.RelayServer - // proxyConfigs is a map of the proxy servers and their corresponding supplier - // advertised URLs and the services they proxy to. + // proxyConfigs is a map of proxyName -> RelayMinerProxyConfig where proxyName + // is the name of the proxy defined in the config file and RelayMinerProxyConfig + // is the configuration of the proxy. proxyConfigs map[string]*config.RelayMinerProxyConfig // servedRelays is an observable that notifies the miner about the relays that have been served. @@ -138,7 +139,8 @@ func (rp *relayerProxy) Stop(ctx context.Context) error { stopGroup, ctx := errgroup.WithContext(ctx) for _, relayServer := range rp.proxyServers { - server := relayServer // create a new variable scoped to the anonymous function + // Create a new object (i.e. deep copy) variable scoped to the anonymous function below + server := relayServer stopGroup.Go(func() error { return server.Stop(ctx) }) } diff --git a/pkg/relayer/proxy/proxy_test.go b/pkg/relayer/proxy/proxy_test.go index ba239f779..20fb71e5a 100644 --- a/pkg/relayer/proxy/proxy_test.go +++ b/pkg/relayer/proxy/proxy_test.go @@ -25,12 +25,25 @@ const blockHeight = 1 var ( // helpers used for tests that are initialized in init() - supplierKeyName string + supplierKeyName string + + // supplierEndpoints is the map of serviceName -> []SupplierEndpoint + // where serviceName is the name of the service the supplier staked for + // and SupplierEndpoint is the endpoint of the service advertised on-chain + // by the supplier supplierEndpoints map[string][]*sharedtypes.SupplierEndpoint - appPrivateKey *secp256k1.PrivKey + + // appPrivateKey is the private key of the application that is used to sign + // relay responses. + // It is also used in these tests to derive the public key and address of the + // application. + appPrivateKey *secp256k1.PrivKey + // proxiedServices is the parsed configuration of the RelayMinerProxyConfig proxiedServices map[string]*config.RelayMinerProxyConfig + // defaultRelayerProxyBehavior is the list of functions that are used to + // define the behavior of the RelayerProxy in the tests. defaultRelayerProxyBehavior []func(*testproxy.TestBehavior) ) @@ -63,12 +76,12 @@ func init() { proxiedServices = map[string]*config.RelayMinerProxyConfig{ "server1": { Name: "server1", - Type: "http", + Type: config.ProxyTypeHTTP, Host: "127.0.0.1:8080", Suppliers: map[string]*config.RelayMinerSupplierConfig{ "service1": { Name: "service1", - Type: "http", + Type: config.ProxyTypeHTTP, Hosts: []string{"supplier:8545"}, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "127.0.0.1:8545", Path: "/"}, @@ -76,7 +89,7 @@ func init() { }, "service2": { Name: "service2", - Type: "http", + Type: config.ProxyTypeHTTP, Hosts: []string{"supplier:8546"}, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "127.0.0.1:8546", Path: "/"}, @@ -86,12 +99,12 @@ func init() { }, "server2": { Name: "server2", - Type: "http", + Type: config.ProxyTypeHTTP, Host: "127.0.0.1:8081", Suppliers: map[string]*config.RelayMinerSupplierConfig{ "service3": { Name: "service3", - Type: "http", + Type: config.ProxyTypeHTTP, Hosts: []string{"supplier:8547"}, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "127.0.0.1:8547", Path: "/"}, @@ -240,12 +253,14 @@ func TestRelayerProxy_UnsupportedTransportType(t *testing.T) { unsupportedTransportProxy := map[string]*config.RelayMinerProxyConfig{ "server1": { Name: "server1", - Type: "xttp", + // The proxy is configured with an unsupported transport type + Type: config.ProxyType(100), Host: "127.0.0.1:8080", Suppliers: map[string]*config.RelayMinerSupplierConfig{ "service1": { - Name: "service1", - Type: "xttp", + Name: "service1", + // The proxy is configured with an unsupported transport type + Type: config.ProxyType(100), Hosts: []string{"supplier:8545"}, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "127.0.0.1:8545", Path: "/"}, @@ -284,12 +299,12 @@ func TestRelayerProxy_NonConfiguredSupplierServices(t *testing.T) { missingServicesProxy := map[string]*config.RelayMinerProxyConfig{ "server1": { Name: "server1", - Type: "http", + Type: config.ProxyTypeHTTP, Host: "127.0.0.1:8080", Suppliers: map[string]*config.RelayMinerSupplierConfig{ "service1": { Name: "service1", - Type: "http", + Type: config.ProxyTypeHTTP, Hosts: []string{"supplier:8545"}, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "127.0.0.1:8545", Path: "/"}, diff --git a/pkg/relayer/proxy/server_builder.go b/pkg/relayer/proxy/server_builder.go index fd94c270f..559f9a3ed 100644 --- a/pkg/relayer/proxy/server_builder.go +++ b/pkg/relayer/proxy/server_builder.go @@ -7,6 +7,7 @@ import ( "golang.org/x/exp/slices" "github.com/pokt-network/poktroll/pkg/relayer" + "github.com/pokt-network/poktroll/pkg/relayer/config" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) @@ -31,11 +32,6 @@ func (rp *relayerProxy) BuildProvidedServices(ctx context.Context) error { return err } - supplierServiceMap := make(map[string]*sharedtypes.Service) - for _, service := range supplier.Services { - supplierServiceMap[service.Service.Id] = service.Service - } - // Check that the supplier's advertised services' endpoints are present in // the proxy config and handled by a proxy host // Iterate over the supplier's advertised services then iterate over each @@ -66,19 +62,38 @@ func (rp *relayerProxy) BuildProvidedServices(ctx context.Context) error { } } - // Build the advertised relay servers map. For each service's endpoint, create the appropriate RelayServer. - providedServices := make(map[string]relayer.RelayServer) + if rp.proxyServers, err = rp.initializeProxyServers(supplier.Services); err != nil { + return err + } + + rp.supplierAddress = supplier.Address + + return nil +} + +// initializeProxyServers initializes the proxy servers for each proxy config. +func (rp *relayerProxy) initializeProxyServers( + supplierServices []*sharedtypes.SupplierServiceConfig, +) (proxyServerMap map[string]relayer.RelayServer, err error) { + // Build a map of serviceId -> service for the supplier's advertised services + supplierServiceMap := make(map[string]*sharedtypes.Service) + for _, service := range supplierServices { + supplierServiceMap[service.Service.Id] = service.Service + } + + // Build a map of proxyName -> RelayServer for each proxy defined in the config file + proxyServers := make(map[string]relayer.RelayServer) + for _, proxyConfig := range rp.proxyConfigs { rp.logger.Info().Str("proxy host", proxyConfig.Host).Msg("starting relay proxy server") - // Switch to the RPC type // TODO(@h5law): Implement a switch that handles all synchronous // RPC types in one server type and asynchronous RPC types in another - // to create the appropriate RelayServer - var server relayer.RelayServer + // to create the appropriate RelayServer. + // Initialize the proxy server according to the proxy type defined in the config file switch proxyConfig.Type { - case "http": - server = NewSynchronousServer( + case config.ProxyTypeHTTP: + proxyServers[proxyConfig.Name] = NewSynchronousServer( rp.logger, proxyConfig, supplierServiceMap, @@ -86,14 +101,9 @@ func (rp *relayerProxy) BuildProvidedServices(ctx context.Context) error { rp, ) default: - return ErrRelayerProxyUnsupportedTransportType + return nil, ErrRelayerProxyUnsupportedTransportType } - - providedServices[proxyConfig.Name] = server } - rp.proxyServers = providedServices - rp.supplierAddress = supplier.Address - - return nil + return proxyServers, nil } diff --git a/pkg/relayer/proxy/synchronous.go b/pkg/relayer/proxy/synchronous.go index d9557d76b..8a698846d 100644 --- a/pkg/relayer/proxy/synchronous.go +++ b/pkg/relayer/proxy/synchronous.go @@ -93,8 +93,16 @@ func (sync *synchronousRPCServer) ServeHTTP(writer http.ResponseWriter, request ctx := request.Context() var originHost string - // Get the original host from X-Forwarded-Host header if specified in the proxy config. - // and fall back to the Host header if it is not specified. + // When the proxy is behind a reverse proxy, or is getting its requests from + // a CDN, the host header may not contain the on-chain advertized address + // needed to determine the service that the relay request is for. + // These CDNs and reverse proxies usually set the X-Forwarded-Host header + // to the original host. + // RelayMiner operators that have such a setup can set the XForwardedHostLookup + // option to true in the proxy config to enable the proxy to look up the + // original host from the X-Forwarded-Host header. + // Get the original host from X-Forwarded-Host header if specified in the proxy + // config and fall back to the Host header if it is not specified. if sync.proxyConfig.XForwardedHostLookup { originHost = request.Header.Get("X-Forwarded-Host") } @@ -106,16 +114,19 @@ func (sync *synchronousRPCServer) ServeHTTP(writer http.ResponseWriter, request var supplierService *sharedtypes.Service var serviceUrl *url.URL -outer: // Get the Service and serviceUrl corresponding to the originHost. for _, supplierServiceConfig := range sync.proxyConfig.Suppliers { for _, host := range supplierServiceConfig.Hosts { if host == originHost { supplierService = sync.supplierServiceMap[supplierServiceConfig.Name] serviceUrl = supplierServiceConfig.ServiceConfig.Url - break outer + break } } + + if serviceUrl != nil { + break + } } if supplierService == nil || serviceUrl == nil { diff --git a/testutil/testproxy/relayerproxy.go b/testutil/testproxy/relayerproxy.go index 3f18d4748..55e99a899 100644 --- a/testutil/testproxy/relayerproxy.go +++ b/testutil/testproxy/relayerproxy.go @@ -105,6 +105,8 @@ func WithRelayerProxyDependencies(keyName string) func(*TestBehavior) { // WithRelayerProxiedServices creates the services that the relayer proxy will // proxy requests to. +// It creates an HTTP server for each service and starts listening on the +// provided host. func WithRelayerProxiedServices( proxiedServices map[string]*config.RelayMinerProxyConfig, ) func(*TestBehavior) { @@ -217,21 +219,29 @@ func WithDefaultSessionSupplier( func MarshalAndSend( test *TestBehavior, proxiedServices map[string]*config.RelayMinerProxyConfig, - server string, - service string, + proxyServeName string, + serviceId string, request *servicetypes.RelayRequest, ) (errCode int32, errorMessage string) { reqBz, err := request.Marshal() require.NoError(test.t, err) + var scheme string + switch proxiedServices[proxyServeName].Type { + case config.ProxyTypeHTTP: + scheme = "http" + default: + require.FailNow(test.t, "unsupported proxy type") + } + reader := io.NopCloser(bytes.NewReader(reqBz)) req := &http.Request{ Method: http.MethodPost, Header: http.Header{ "Content-Type": []string{"application/json"}, }, - URL: &url.URL{Scheme: proxiedServices[server].Type, Host: proxiedServices[server].Host}, - Host: proxiedServices[server].Suppliers[service].Hosts[0], + URL: &url.URL{Scheme: scheme, Host: proxiedServices[proxyServeName].Host}, + Host: proxiedServices[proxyServeName].Suppliers[serviceId].Hosts[0], Body: reader, } res, err := http.DefaultClient.Do(req) From fab1dfb59c599ee478b5c0b117ce9c4ec625042b Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 21 Dec 2023 00:08:37 +0100 Subject: [PATCH 23/34] refactor: Split relayminer config parsing and validation logic --- .../config/pocket_node_config_hydrator.go | 56 ++++ pkg/relayer/config/proxies_config_hydrator.go | 63 +++++ .../config/relayminer_configs_reader.go | 246 ++---------------- pkg/relayer/config/supplier_hydrator.go | 82 ++++++ .../config/suppliers_config_hydrator.go | 51 ++++ 5 files changed, 267 insertions(+), 231 deletions(-) create mode 100644 pkg/relayer/config/pocket_node_config_hydrator.go create mode 100644 pkg/relayer/config/proxies_config_hydrator.go create mode 100644 pkg/relayer/config/supplier_hydrator.go create mode 100644 pkg/relayer/config/suppliers_config_hydrator.go diff --git a/pkg/relayer/config/pocket_node_config_hydrator.go b/pkg/relayer/config/pocket_node_config_hydrator.go new file mode 100644 index 000000000..4da7dc48c --- /dev/null +++ b/pkg/relayer/config/pocket_node_config_hydrator.go @@ -0,0 +1,56 @@ +package config + +import "net/url" + +// HydratePocketNodeUrls populates the pocket node fields of the RelayMinerConfig +// that are relevant to the "pocket_node" section in the config file. +func (relayMinerConfig *RelayMinerConfig) HydratePocketNodeUrls( + yamlPocketNodeConfig *YAMLRelayMinerPocketNodeConfig, +) error { + relayMinerConfig.PocketNode = &RelayMinerPocketNodeConfig{} + + if len(yamlPocketNodeConfig.TxNodeGRPCUrl) == 0 { + return ErrRelayMinerConfigInvalidNodeUrl.Wrap("tx node grpc url is required") + } + + // Check if the pocket node grpc url is a valid URL + txNodeGRPCUrl, err := url.Parse(yamlPocketNodeConfig.TxNodeGRPCUrl) + if err != nil { + return ErrRelayMinerConfigInvalidNodeUrl.Wrapf( + "invalid tx node grpc url %s", + err.Error(), + ) + } + relayMinerConfig.PocketNode.TxNodeGRPCUrl = txNodeGRPCUrl + + // If the query node grpc url is empty, use the tx node grpc url + if len(yamlPocketNodeConfig.QueryNodeGRPCUrl) == 0 { + relayMinerConfig.PocketNode.QueryNodeGRPCUrl = relayMinerConfig.PocketNode.TxNodeGRPCUrl + } else { + // If the query node grpc url is not empty, make sure it is a valid URL + queryNodeGRPCUrl, err := url.Parse(yamlPocketNodeConfig.QueryNodeGRPCUrl) + if err != nil { + return ErrRelayMinerConfigInvalidNodeUrl.Wrapf( + "invalid query node grpc url %s", + err.Error(), + ) + } + relayMinerConfig.PocketNode.QueryNodeGRPCUrl = queryNodeGRPCUrl + } + + if len(yamlPocketNodeConfig.QueryNodeRPCUrl) == 0 { + return ErrRelayMinerConfigInvalidNodeUrl.Wrap("query node rpc url is required") + } + + // Check if the query node rpc url is a valid URL + queryNodeRPCUrl, err := url.Parse(yamlPocketNodeConfig.QueryNodeRPCUrl) + if err != nil { + return ErrRelayMinerConfigInvalidNodeUrl.Wrapf( + "invalid query node rpc url %s", + err.Error(), + ) + } + relayMinerConfig.PocketNode.QueryNodeRPCUrl = queryNodeRPCUrl + + return nil +} diff --git a/pkg/relayer/config/proxies_config_hydrator.go b/pkg/relayer/config/proxies_config_hydrator.go new file mode 100644 index 000000000..9b776cfb5 --- /dev/null +++ b/pkg/relayer/config/proxies_config_hydrator.go @@ -0,0 +1,63 @@ +package config + +// HydrateProxies populates the proxies fields of the RelayMinerConfig that +// are relevant to the "proxies" section in the config file. +func (relayMinerConfig *RelayMinerConfig) HydrateProxies( + yamlProxyConfigs []YAMLRelayMinerProxyConfig, +) error { + // At least one proxy is required + if len(yamlProxyConfigs) == 0 { + return ErrRelayMinerConfigInvalidProxy.Wrap("no proxies provided") + } + + relayMinerConfig.Proxies = make(map[string]*RelayMinerProxyConfig) + + for _, yamlProxyConfig := range yamlProxyConfigs { + // Proxy name is required + if len(yamlProxyConfig.Name) == 0 { + return ErrRelayMinerConfigInvalidProxy.Wrap("proxy name is required") + } + + // Proxy name should not be unique + if _, ok := relayMinerConfig.Proxies[yamlProxyConfig.Name]; ok { + return ErrRelayMinerConfigInvalidProxy.Wrapf( + "duplicate porxy name %s", + yamlProxyConfig.Name, + ) + } + + proxyConfig := &RelayMinerProxyConfig{ + Name: yamlProxyConfig.Name, + XForwardedHostLookup: yamlProxyConfig.XForwardedHostLookup, + Suppliers: make(map[string]*RelayMinerSupplierConfig), + } + + // Populate the proxy fields that are relevant to each supported proxy type + switch yamlProxyConfig.Type { + case "http": + if err := proxyConfig.parseHTTPProxyConfig(yamlProxyConfig); err != nil { + return err + } + default: + // Fail if the proxy type is not supported + return ErrRelayMinerConfigInvalidProxy.Wrapf( + "invalid proxy type %s", + yamlProxyConfig.Type, + ) + } + + switch yamlProxyConfig.Type { + case "http": + proxyConfig.Type = ProxyTypeHTTP + default: + ErrRelayMinerConfigInvalidProxy.Wrapf( + "invalid proxy type %s", + yamlProxyConfig.Type, + ) + } + + relayMinerConfig.Proxies[proxyConfig.Name] = proxyConfig + } + + return nil +} diff --git a/pkg/relayer/config/relayminer_configs_reader.go b/pkg/relayer/config/relayminer_configs_reader.go index 1ba500ceb..9034daba9 100644 --- a/pkg/relayer/config/relayminer_configs_reader.go +++ b/pkg/relayer/config/relayminer_configs_reader.go @@ -1,16 +1,12 @@ package config -import ( - "net/url" - - yaml "gopkg.in/yaml.v2" -) +import yaml "gopkg.in/yaml.v2" // ParseRelayMinerConfigs parses the relay miner config file into a RelayMinerConfig func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { var ( yamlRelayMinerConfig YAMLRelayMinerConfig - err error + relayMinerConfig = &RelayMinerConfig{} ) // The config file should not be empty @@ -28,235 +24,31 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { if len(yamlRelayMinerConfig.SigningKeyName) == 0 { return nil, ErrRelayMinerConfigInvalidSigningKeyName } + relayMinerConfig.SigningKeyName = yamlRelayMinerConfig.SigningKeyName // SmtStorePath is required if len(yamlRelayMinerConfig.SmtStorePath) == 0 { return nil, ErrRelayMinerConfigInvalidSmtStorePath } + relayMinerConfig.SmtStorePath = yamlRelayMinerConfig.SmtStorePath - // Pocket node urls section - relayMinerPocketConfig := &RelayMinerPocketNodeConfig{} - - if len(yamlRelayMinerConfig.PocketNode.TxNodeGRPCUrl) == 0 { - return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrap("tx node grpc url is required") - } - - // Check if the pocket node grpc url is a valid URL - txNodeGRPCUrl, err := url.Parse(yamlRelayMinerConfig.PocketNode.TxNodeGRPCUrl) - if err != nil { - return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrapf( - "invalid tx node grpc url %s", - err.Error(), - ) + // Hydrate the pocket node urls + if err := relayMinerConfig.HydratePocketNodeUrls(&yamlRelayMinerConfig.PocketNode); err != nil { + return nil, err } - relayMinerPocketConfig.TxNodeGRPCUrl = txNodeGRPCUrl - // If the query node grpc url is empty, use the tx node grpc url - if len(yamlRelayMinerConfig.PocketNode.QueryNodeGRPCUrl) == 0 { - relayMinerPocketConfig.QueryNodeGRPCUrl = relayMinerPocketConfig.TxNodeGRPCUrl - } else { - // If the query node grpc url is not empty, make sure it is a valid URL - queryNodeGRPCUrl, err := url.Parse(yamlRelayMinerConfig.PocketNode.QueryNodeGRPCUrl) - if err != nil { - return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrapf( - "invalid query node grpc url %s", - err.Error(), - ) - } - relayMinerPocketConfig.QueryNodeGRPCUrl = queryNodeGRPCUrl - } - - if len(yamlRelayMinerConfig.PocketNode.QueryNodeRPCUrl) == 0 { - return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrap("query node rpc url is required") + // Hydrate the proxies + if err := relayMinerConfig.HydrateProxies(yamlRelayMinerConfig.Proxies); err != nil { + return nil, err } - // Check if the query node rpc url is a valid URL - queryNodeRPCUrl, err := url.Parse(yamlRelayMinerConfig.PocketNode.QueryNodeRPCUrl) - if err != nil { - return nil, ErrRelayMinerConfigInvalidNodeUrl.Wrapf( - "invalid query node rpc url %s", - err.Error(), - ) - } - relayMinerPocketConfig.QueryNodeRPCUrl = queryNodeRPCUrl - - // Proxies section - // At least one proxy is required - if len(yamlRelayMinerConfig.Proxies) == 0 { - return nil, ErrRelayMinerConfigInvalidProxy.Wrap("no proxies provided") - } - - relayMinerProxiesConfig := make(map[string]*RelayMinerProxyConfig) - - for _, yamlProxyConfig := range yamlRelayMinerConfig.Proxies { - // Proxy name is required - if len(yamlProxyConfig.Name) == 0 { - return nil, ErrRelayMinerConfigInvalidProxy.Wrap("proxy name is required") - } - - // Proxy name should not be unique - if _, ok := relayMinerProxiesConfig[yamlProxyConfig.Name]; ok { - return nil, ErrRelayMinerConfigInvalidProxy.Wrapf( - "duplicate porxy name %s", - yamlProxyConfig.Name, - ) - } - - proxyConfig := &RelayMinerProxyConfig{ - Name: yamlProxyConfig.Name, - XForwardedHostLookup: yamlProxyConfig.XForwardedHostLookup, - Suppliers: make(map[string]*RelayMinerSupplierConfig), - } - - // Populate the proxy fields that are relevant to each supported proxy type - switch yamlProxyConfig.Type { - case "http": - if err := proxyConfig.parseHTTPProxyConfig(yamlProxyConfig); err != nil { - return nil, err - } - default: - // Fail if the proxy type is not supported - return nil, ErrRelayMinerConfigInvalidProxy.Wrapf( - "invalid proxy type %s", - yamlProxyConfig.Type, - ) - } - - switch yamlProxyConfig.Type { - case "http": - proxyConfig.Type = ProxyTypeHTTP - default: - ErrRelayMinerConfigInvalidProxy.Wrapf( - "invalid proxy type %s", - yamlProxyConfig.Type, - ) - } - - relayMinerProxiesConfig[proxyConfig.Name] = proxyConfig - } - - // Suppliers section - relayMinerSuppliersConfig := make(map[string]*RelayMinerSupplierConfig) - - for _, yamlSupplierConfig := range yamlRelayMinerConfig.Suppliers { - // Supplier name is required - if len(yamlSupplierConfig.Name) == 0 { - return nil, ErrRelayMinerConfigInvalidSupplier.Wrap("supplier name is required") - } - - // Supplier name should not be unique - if _, ok := relayMinerSuppliersConfig[yamlSupplierConfig.Name]; ok { - return nil, ErrRelayMinerConfigInvalidSupplier.Wrapf( - "duplicate supplier name %s", - yamlSupplierConfig.Name, - ) - } - - supplierConfig := &RelayMinerSupplierConfig{ - Name: yamlSupplierConfig.Name, - Hosts: []string{}, - ServiceConfig: &RelayMinerSupplierServiceConfig{}, - } - - // Supplier hosts sub-section - existingHosts := make(map[string]bool) - for _, host := range yamlSupplierConfig.Hosts { - // Check if the supplier host is empty - if len(host) == 0 { - return nil, ErrRelayMinerConfigInvalidSupplier.Wrap("empty supplier host") - } - - // Check if the supplier host is a valid URL - supplierHost, err := url.Parse(host) - if err != nil { - return nil, ErrRelayMinerConfigInvalidSupplier.Wrapf( - "invalid supplier host %s", - host, - ) - } - - // Check if the supplier host is unique - if _, ok := existingHosts[supplierHost.Host]; ok { - return nil, ErrRelayMinerConfigInvalidSupplier.Wrapf( - "duplicate supplier host %s", - host, - ) - } - existingHosts[supplierHost.Host] = true - - // Add the supplier host to the suppliers list - supplierConfig.Hosts = append(supplierConfig.Hosts, supplierHost.Host) - } - - // Add a default host which corresponds to the supplier name if it is not - // already in the list - if _, ok := existingHosts[supplierConfig.Name]; !ok { - supplierConfig.Hosts = append(supplierConfig.Hosts, supplierConfig.Name) - } - - // Supplier service sub-section - // Populate the supplier service fields that are relevant to each supported - // supplier type. - // If other supplier types are added in the future, they should be handled - // by their own functions. - switch yamlSupplierConfig.Type { - case "http": - if err := supplierConfig.ServiceConfig. - parseHTTPSupplierConfig(yamlSupplierConfig.ServiceConfig); err != nil { - return nil, err - } - default: - // Fail if the supplier type is not supported - return nil, ErrRelayMinerConfigInvalidSupplier.Wrapf( - "invalid supplier type %s", - yamlSupplierConfig.Type, - ) - } - - switch yamlSupplierConfig.Type { - case "http": - supplierConfig.Type = ProxyTypeHTTP - default: - ErrRelayMinerConfigInvalidProxy.Wrapf( - "invalid proxy type %s", - yamlSupplierConfig.Type, - ) - } - - // Check if the supplier has proxies - if len(yamlSupplierConfig.ProxyNames) == 0 { - return nil, ErrRelayMinerConfigInvalidSupplier.Wrapf( - "supplier %s has no proxies", - supplierConfig.Name, - ) - } - - // Add the supplier config to the referenced proxies - for _, proxyName := range yamlSupplierConfig.ProxyNames { - // If the proxy name is referencing a non-existent proxy, fail - if _, ok := relayMinerProxiesConfig[proxyName]; !ok { - return nil, ErrRelayMinerConfigInvalidSupplier.Wrapf( - "no matching proxy %s for supplier %s", - supplierConfig.Name, - proxyName, - ) - } - - // If the proxy name is referencing a proxy of a different type, fail - if supplierConfig.Type != relayMinerProxiesConfig[proxyName].Type { - return nil, ErrRelayMinerConfigInvalidSupplier.Wrapf( - "supplier %s and proxy %s have different types", - supplierConfig.Name, - proxyName, - ) - } - - relayMinerProxiesConfig[proxyName].Suppliers[supplierConfig.Name] = supplierConfig - } + // Hydrate the suppliers + if err := relayMinerConfig.HydrateSuppliers(yamlRelayMinerConfig.Suppliers); err != nil { + return nil, err } // Check if a proxy is referencing a host more than once - for _, proxyConfig := range relayMinerProxiesConfig { + for _, proxyConfig := range relayMinerConfig.Proxies { existingHosts := make(map[string]bool) for _, supplierConfig := range proxyConfig.Suppliers { for _, host := range supplierConfig.Hosts { @@ -272,13 +64,5 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { } } - // Populate the relay miner config - relayMinerCMDConfig := &RelayMinerConfig{ - PocketNode: relayMinerPocketConfig, - SigningKeyName: yamlRelayMinerConfig.SigningKeyName, - SmtStorePath: yamlRelayMinerConfig.SmtStorePath, - Proxies: relayMinerProxiesConfig, - } - - return relayMinerCMDConfig, nil + return relayMinerConfig, nil } diff --git a/pkg/relayer/config/supplier_hydrator.go b/pkg/relayer/config/supplier_hydrator.go new file mode 100644 index 000000000..7b3be7fe3 --- /dev/null +++ b/pkg/relayer/config/supplier_hydrator.go @@ -0,0 +1,82 @@ +package config + +import "net/url" + +// HydrateSupplier populates a single supplier's fields of the RelayMinerConfig +// that are relevant to each supplier in the "suppliers" section of the config file. +func (supplierConfig *RelayMinerSupplierConfig) HydrateSupplier( + yamlSupplierConfig YAMLRelayMinerSupplierConfig, +) error { + // Supplier name is required + if len(yamlSupplierConfig.Name) == 0 { + return ErrRelayMinerConfigInvalidSupplier.Wrap("supplier name is required") + } + supplierConfig.Name = yamlSupplierConfig.Name + + // Supplier hosts + supplierConfig.Hosts = []string{} + existingHosts := make(map[string]bool) + for _, host := range yamlSupplierConfig.Hosts { + // Check if the supplier host is empty + if len(host) == 0 { + return ErrRelayMinerConfigInvalidSupplier.Wrap("empty supplier host") + } + + // Check if the supplier host is a valid URL + supplierHost, err := url.Parse(host) + if err != nil { + return ErrRelayMinerConfigInvalidSupplier.Wrapf( + "invalid supplier host %s", + host, + ) + } + + // Check if the supplier host is unique + if _, ok := existingHosts[supplierHost.Host]; ok { + return ErrRelayMinerConfigInvalidSupplier.Wrapf( + "duplicate supplier host %s", + host, + ) + } + existingHosts[supplierHost.Host] = true + + // Add the supplier host to the suppliers list + supplierConfig.Hosts = append(supplierConfig.Hosts, supplierHost.Host) + } + + // Add a default host which corresponds to the supplier name if it is not + // already in the list + if _, ok := existingHosts[supplierConfig.Name]; !ok { + supplierConfig.Hosts = append(supplierConfig.Hosts, supplierConfig.Name) + } + + // Populate the supplier service fields that are relevant to each supported + // supplier type. + // If other supplier types are added in the future, they should be handled + // by their own functions. + supplierConfig.ServiceConfig = &RelayMinerSupplierServiceConfig{} + switch yamlSupplierConfig.Type { + case "http": + supplierConfig.Type = ProxyTypeHTTP + if err := supplierConfig.ServiceConfig. + parseHTTPSupplierConfig(yamlSupplierConfig.ServiceConfig); err != nil { + return err + } + default: + // Fail if the supplier type is not supported + return ErrRelayMinerConfigInvalidSupplier.Wrapf( + "invalid supplier type %s", + yamlSupplierConfig.Type, + ) + } + + // Check if the supplier has proxies + if len(yamlSupplierConfig.ProxyNames) == 0 { + return ErrRelayMinerConfigInvalidSupplier.Wrapf( + "supplier %s has no proxies", + supplierConfig.Name, + ) + } + + return nil +} diff --git a/pkg/relayer/config/suppliers_config_hydrator.go b/pkg/relayer/config/suppliers_config_hydrator.go new file mode 100644 index 000000000..bcf321a57 --- /dev/null +++ b/pkg/relayer/config/suppliers_config_hydrator.go @@ -0,0 +1,51 @@ +package config + +// HydrateSuppliers populates the suppliers fields of the RelayMinerConfig that +// are relevant to the "suppliers" section in the config file. +func (relayMinerConfig *RelayMinerConfig) HydrateSuppliers( + yamlSupplierConfigs []YAMLRelayMinerSupplierConfig, +) error { + existingSuppliers := make(map[string]bool) + for _, yamlSupplierConfig := range yamlSupplierConfigs { + // Hydrate and validate each supplier in the suppliers list of the config file. + supplierConfig := &RelayMinerSupplierConfig{} + if err := supplierConfig.HydrateSupplier(yamlSupplierConfig); err != nil { + return err + } + + // Supplier name should not be unique + if _, ok := existingSuppliers[yamlSupplierConfig.Name]; ok { + return ErrRelayMinerConfigInvalidSupplier.Wrapf( + "duplicate supplier name %s", + yamlSupplierConfig.Name, + ) + } + // Mark the supplier as existing + existingSuppliers[yamlSupplierConfig.Name] = true + + // Add the supplier config to the referenced proxies + for _, proxyName := range yamlSupplierConfig.ProxyNames { + // If the proxy name is referencing a non-existent proxy, fail + if _, ok := relayMinerConfig.Proxies[proxyName]; !ok { + return ErrRelayMinerConfigInvalidSupplier.Wrapf( + "no matching proxy %s for supplier %s", + supplierConfig.Name, + proxyName, + ) + } + + // If the proxy name is referencing a proxy of a different type, fail + if supplierConfig.Type != relayMinerConfig.Proxies[proxyName].Type { + return ErrRelayMinerConfigInvalidSupplier.Wrapf( + "supplier %s and proxy %s have different types", + supplierConfig.Name, + proxyName, + ) + } + + relayMinerConfig.Proxies[proxyName].Suppliers[supplierConfig.Name] = supplierConfig + } + } + + return nil +} From 6ea61bcc2dc3374e8a4175b0de836b2d7ca81c9e Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 21 Dec 2023 00:14:57 +0100 Subject: [PATCH 24/34] chore: Add TODO to make MarshalAndSend RPC-type agnostic --- testutil/testproxy/relayerproxy.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/testutil/testproxy/relayerproxy.go b/testutil/testproxy/relayerproxy.go index 55e99a899..96768aabb 100644 --- a/testutil/testproxy/relayerproxy.go +++ b/testutil/testproxy/relayerproxy.go @@ -215,7 +215,12 @@ func WithDefaultSessionSupplier( } } -// MarshalAndSend marshals the request and sends it to the provided service +// TODO_TECHDEBT(@red-0ne): This function only supports JSON-RPC requests and +// needs to have its http.Request "Content-Type" header passed-in as a parameter +// and take out the GetRelayResponseError function which parses JSON-RPC responses +// to make it RPC-type agnostic. + +// MarshalAndSend marshals the request and sends it to the provided service. func MarshalAndSend( test *TestBehavior, proxiedServices map[string]*config.RelayMinerProxyConfig, From f342d05ba6a8ea8d46302412cc2b5677cc9fb629 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 21 Dec 2023 00:17:03 +0100 Subject: [PATCH 25/34] chore: Strip-off comments form AppGateServer config, add documented example config --- localnet/poktrolld/config/appgate_server_config.yaml | 7 ------- .../config/appgate_server_config_example.yaml | 12 ++++++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 localnet/poktrolld/config/appgate_server_config_example.yaml diff --git a/localnet/poktrolld/config/appgate_server_config.yaml b/localnet/poktrolld/config/appgate_server_config.yaml index 4c8d8bc06..f41c267f4 100644 --- a/localnet/poktrolld/config/appgate_server_config.yaml +++ b/localnet/poktrolld/config/appgate_server_config.yaml @@ -1,12 +1,5 @@ -# Pocket node URL that exposes CometBFT JSON-RPC API. -# This can be used by the Cosmos client SDK, event subscriptions, etc... query_node_rpc_url: tcp://poktroll-sequencer:36657 -# Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. -# If unspecified, defaults to `tx_node_grpc_url`. query_node_grpc_url: tcp://poktroll-sequencer:36658 -# The name of the key (in the keyring) that will be used to sign relays signing_key: app1 -# Whether the server should sign all incoming requests with its own ring (for applications) self_signing: true -# The host and port that the appgate server will listen on listening_endpoint: http://localhost:42069 \ No newline at end of file diff --git a/localnet/poktrolld/config/appgate_server_config_example.yaml b/localnet/poktrolld/config/appgate_server_config_example.yaml new file mode 100644 index 000000000..4c8d8bc06 --- /dev/null +++ b/localnet/poktrolld/config/appgate_server_config_example.yaml @@ -0,0 +1,12 @@ +# Pocket node URL that exposes CometBFT JSON-RPC API. +# This can be used by the Cosmos client SDK, event subscriptions, etc... +query_node_rpc_url: tcp://poktroll-sequencer:36657 +# Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. +# If unspecified, defaults to `tx_node_grpc_url`. +query_node_grpc_url: tcp://poktroll-sequencer:36658 +# The name of the key (in the keyring) that will be used to sign relays +signing_key: app1 +# Whether the server should sign all incoming requests with its own ring (for applications) +self_signing: true +# The host and port that the appgate server will listen on +listening_endpoint: http://localhost:42069 \ No newline at end of file From 22cd59e9bb74ec0082f6136a0326dcf24032c336 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 21 Dec 2023 00:30:20 +0100 Subject: [PATCH 26/34] chore: Strip comments out of relay miner config and reorder entries --- .../poktrolld/config/relayminer_config.yaml | 52 ++----------------- .../relayminer_config_full_example.yaml | 12 ++--- 2 files changed, 9 insertions(+), 55 deletions(-) diff --git a/localnet/poktrolld/config/relayminer_config.yaml b/localnet/poktrolld/config/relayminer_config.yaml index 7f1746e02..69ffb5062 100644 --- a/localnet/poktrolld/config/relayminer_config.yaml +++ b/localnet/poktrolld/config/relayminer_config.yaml @@ -1,63 +1,17 @@ -# TODO_CONSIDERATION: We don't need this now, but it would be beneficial if the -# logic handling this config file could be designed in such a way that it allows for -# "hot" config changes in the future, meaning changes without restarting a process. -# This would be useful for adding a proxy or a supplier without interrupting the service. - +signing_key_name: supplier1 +smt_store_path: smt_stores pocket_node: - # Pocket node URL that exposes CometBFT JSON-RPC API. - # This can be used by the Cosmos client SDK, event subscriptions, etc... query_node_rpc_url: tcp://poktroll-sequencer:36657 - # Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. - # If unspecified, defaults to `tx_node_grpc_url`. query_node_grpc_url: tcp://poktroll-sequencer:36658 - # Pocket node URL that exposes the Cosmos gRPC service. tx_node_grpc_url: tcp://poktroll-sequencer:36658 - -# Name of the key (in the keyring) to sign transactions -signing_key_name: supplier1 -# Relative path (on the relayminer's machine) to where the data backing -# SMT KV store exists on disk -smt_store_path: smt_stores - -# Proxies are endpoints that expose different suppliers to the internet. proxies: - # Name of the proxy. It will be used to reference in a supplier. Must be unique. - # Required. - # TODO_CONSIDERATION: if we enforce DNS compliant names, it can potentially - # become handy in the future. - # More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names - name: http-proxy - # Type of proxy: currently only http is supported but will support more - # (https, tcp, quic ...) in the future. - # MUST match the type of the supplier. - # Required. type: http - # Hostname to open port on. Use 0.0.0.0 in containerized environments, - # 127.0.0.1 with a reverse-proxy when there's another process on localhost - # that can be used as a reverse proxy (nginx, apache, traefik, etc.). - # Required. - host: 127.0.0.1:8080 - -# Suppliers are different services that can be offered through RelayMiner. -# When a supplier is configured to use a proxy and staked appropriately, -# the relays will start flowing through RelayMiner. + host: 0.0.0.0:8080 suppliers: - # Name of the supplier offered to the network. - # Must be unique. - # Required. - name: anvil - # Type of how the supplier offers service through the network. - # Must match the type of the proxy the supplier is connected to. - # Required. type: http - # Configuration of the service offered through RelayMiner. service_config: - # URL RelayMiner proxies the requests to. - # Required. url: http://anvil:8547/ - # Names of proxies that this supplier is connected to. - # This MUST correspond to the name in the `proxies` section - # in order for the supplier to be accessible to the external network. - # Required. proxy_names: - http-proxy diff --git a/localnet/poktrolld/config/relayminer_config_full_example.yaml b/localnet/poktrolld/config/relayminer_config_full_example.yaml index 00048606f..3a3f9b65d 100644 --- a/localnet/poktrolld/config/relayminer_config_full_example.yaml +++ b/localnet/poktrolld/config/relayminer_config_full_example.yaml @@ -3,6 +3,12 @@ # "hot" config changes in the future, meaning changes without restarting a process. # This would be useful for adding a proxy or a supplier without interrupting the service. +# Name of the key (in the keyring) to sign transactions +signing_key_name: supplier1 +# Relative path (on the relayminer's machine) to where the data backing +# SMT KV store exists on disk +smt_store_path: smt_stores + pocket_node: # Pocket node URL that exposes CometBFT JSON-RPC API. # This can be used by the Cosmos client SDK, event subscriptions, etc... @@ -13,12 +19,6 @@ pocket_node: # Pocket node URL that exposes the Cosmos gRPC service. tx_node_grpc_url: tcp://poktroll-sequencer:36658 -# Name of the key (in the keyring) to sign transactions -signing_key_name: supplier1 -# Relative path (on the relayminer's machine) to where the data backing -# SMT KV store exists on disk -smt_store_path: smt_stores - # Proxies are endpoints that expose different suppliers to the internet. proxies: # Name of the proxy. It will be used to reference in a supplier. Must be unique. From e9efceca47612569b879096e0699463f0067ad06 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 21 Dec 2023 02:10:16 +0100 Subject: [PATCH 27/34] chore: Update flagNode variables and command documentation --- .../poktrolld/config/relayminer_config.yaml | 4 ++-- pkg/relayer/cmd/cmd.go | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/localnet/poktrolld/config/relayminer_config.yaml b/localnet/poktrolld/config/relayminer_config.yaml index c3b97477b..fceee3fc9 100644 --- a/localnet/poktrolld/config/relayminer_config.yaml +++ b/localnet/poktrolld/config/relayminer_config.yaml @@ -3,10 +3,10 @@ query_node_rpc_url: tcp://poktroll-sequencer:36657 # Pocket node URL that exposes the Cosmos gRPC service. query_node_grpc_url: tcp://poktroll-sequencer:36658 -# Name of the key (in the keyring) to sign transactions -tx_node_grpc_url: tcp://poktroll-sequencer:36658 # Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. # If unspecified, defaults to `tx_node_grpc_url`. +tx_node_grpc_url: tcp://poktroll-sequencer:36658 +# Name of the key (in the keyring) to sign transactions signing_key_name: supplier1 # Path to where the data backing SMT KV store exists on disk smt_store_path: smt_stores diff --git a/pkg/relayer/cmd/cmd.go b/pkg/relayer/cmd/cmd.go index 508cc0c91..efc204a90 100644 --- a/pkg/relayer/cmd/cmd.go +++ b/pkg/relayer/cmd/cmd.go @@ -37,10 +37,10 @@ var ( // flagRelayMinerConfig is the variable containing the relay miner config filepath // sourced from the `--config` flag. flagRelayMinerConfig string - // flagNodeRPCUrl is the variable containing the Cosmos node RPC URL flag value. - flagNodeRPCUrl string - // flagNodeGRPCUrl is the variable containing the Cosmos node GRPC URL flag value. - flagNodeGRPCUrl string + // flagNodeRPCURL is the variable containing the Cosmos node RPC URL flag value. + flagNodeRPCURL string + // flagNodeGRPCURL is the variable containing the Cosmos node GRPC URL flag value. + flagNodeGRPCURL string ) // RelayerCmd returns the Cobra command for running the relay miner. @@ -70,8 +70,8 @@ for such operations.`, // Cosmos flags // TODO_TECHDEBT(#256): Remove unneeded cosmos flags. cmd.Flags().String(cosmosflags.FlagKeyringBackend, "", "Select keyring's backend (os|file|kwallet|pass|test)") - cmd.Flags().StringVar(&flagNodeRPCUrl, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialize the Cosmos query and tx contexts correctly. It can be used to override the `QueryNodeUrl` and `NetworkNodeUrl` fields in the config file if specified.") - cmd.Flags().StringVar(&flagNodeGRPCUrl, cosmosflags.FlagGRPC, omittedDefaultFlagValue, "Register the default Cosmos node grpc flag, which is needed to initialize the Cosmos query context with grpc correctly. It can be used to override the `QueryNodeGRPCUrl` field in the config file if specified.") + cmd.Flags().StringVar(&flagNodeRPCURL, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialize the Cosmos query context correctly. It can be used to override the `QueryNodeRPCURL` field in the config file if specified.") + cmd.Flags().StringVar(&flagNodeGRPCURL, cosmosflags.FlagGRPC, omittedDefaultFlagValue, "Register the default Cosmos node grpc flag, which is needed to initialize the Cosmos query and tx contexts with grpc correctly. It can be used to override the `QueryNodeGRPCURL` and `TxNodeGRPCURL` fields in the config file if specified.") cmd.Flags().Bool(cosmosflags.FlagGRPCInsecure, true, "Used to initialize the Cosmos query context with grpc security options. It can be used to override the `QueryNodeGRPCInsecure` field in the config file if specified.") return cmd @@ -147,8 +147,8 @@ func setupRelayerDependencies( // Override the config file's `QueryNodeGRPCUrl` and `NetworkNodeGRPCUrl` fields // with the `--grpc-addr` flag if it was specified. // TODO(#223) Remove this check once viper is used as SoT for overridable config values. - if flagNodeGRPCUrl != omittedDefaultFlagValue { - parsedFlagNodeGRPCUrl, err := url.Parse(flagNodeGRPCUrl) + if flagNodeGRPCURL != omittedDefaultFlagValue { + parsedFlagNodeGRPCUrl, err := url.Parse(flagNodeGRPCURL) if err != nil { return nil, fmt.Errorf("failed to parse Cosmos node URL: %w", err) } @@ -159,8 +159,8 @@ func setupRelayerDependencies( // Override the config file's `QueryNodeUrl` fields // with the `--node` flag if it was specified. // TODO(#223) Remove this check once viper is used as SoT for overridable config values. - if flagNodeRPCUrl != omittedDefaultFlagValue { - parsedFlagNodeRPCUrl, err = url.Parse(flagNodeRPCUrl) + if flagNodeRPCURL != omittedDefaultFlagValue { + parsedFlagNodeRPCUrl, err = url.Parse(flagNodeRPCURL) if err != nil { return nil, fmt.Errorf("failed to parse Cosmos node URL: %w", err) } From b8847b5264db737a698e66605b453dd6116d5f89 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 21 Dec 2023 04:10:05 +0100 Subject: [PATCH 28/34] fix: Update sequencer host used in local net --- localnet/kubernetes/values-relayminer.yaml | 9 +++------ localnet/poktrolld/config/appgate_server_config.yaml | 4 ++-- .../config/appgate_server_config_example.yaml | 4 ++-- localnet/poktrolld/config/relayminer_config.yaml | 10 ++++++---- .../config/relayminer_config_full_example.yaml | 6 +++--- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/localnet/kubernetes/values-relayminer.yaml b/localnet/kubernetes/values-relayminer.yaml index 5406ef277..e9224442c 100644 --- a/localnet/kubernetes/values-relayminer.yaml +++ b/localnet/kubernetes/values-relayminer.yaml @@ -1,17 +1,14 @@ config: - pocket: + signing_key_name: supplier1 + smt_store_path: smt_stores + pocket_node: query_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 tx_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 - - signing_key_name: supplier1 - smt_store_path: smt_stores - proxies: - name: http-proxy type: http host: 0.0.0.0:8545 - suppliers: - name: anvil type: http diff --git a/localnet/poktrolld/config/appgate_server_config.yaml b/localnet/poktrolld/config/appgate_server_config.yaml index f41c267f4..475678930 100644 --- a/localnet/poktrolld/config/appgate_server_config.yaml +++ b/localnet/poktrolld/config/appgate_server_config.yaml @@ -1,5 +1,5 @@ -query_node_rpc_url: tcp://poktroll-sequencer:36657 -query_node_grpc_url: tcp://poktroll-sequencer:36658 +query_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 +query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 signing_key: app1 self_signing: true listening_endpoint: http://localhost:42069 \ No newline at end of file diff --git a/localnet/poktrolld/config/appgate_server_config_example.yaml b/localnet/poktrolld/config/appgate_server_config_example.yaml index 4c8d8bc06..42a88be81 100644 --- a/localnet/poktrolld/config/appgate_server_config_example.yaml +++ b/localnet/poktrolld/config/appgate_server_config_example.yaml @@ -1,9 +1,9 @@ # Pocket node URL that exposes CometBFT JSON-RPC API. # This can be used by the Cosmos client SDK, event subscriptions, etc... -query_node_rpc_url: tcp://poktroll-sequencer:36657 +query_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 # Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. # If unspecified, defaults to `tx_node_grpc_url`. -query_node_grpc_url: tcp://poktroll-sequencer:36658 +query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 # The name of the key (in the keyring) that will be used to sign relays signing_key: app1 # Whether the server should sign all incoming requests with its own ring (for applications) diff --git a/localnet/poktrolld/config/relayminer_config.yaml b/localnet/poktrolld/config/relayminer_config.yaml index 69ffb5062..b82ede740 100644 --- a/localnet/poktrolld/config/relayminer_config.yaml +++ b/localnet/poktrolld/config/relayminer_config.yaml @@ -1,13 +1,13 @@ signing_key_name: supplier1 smt_store_path: smt_stores pocket_node: - query_node_rpc_url: tcp://poktroll-sequencer:36657 - query_node_grpc_url: tcp://poktroll-sequencer:36658 - tx_node_grpc_url: tcp://poktroll-sequencer:36658 + query_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 + query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 + tx_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 proxies: - name: http-proxy type: http - host: 0.0.0.0:8080 + host: 0.0.0.0:8545 suppliers: - name: anvil type: http @@ -15,3 +15,5 @@ suppliers: url: http://anvil:8547/ proxy_names: - http-proxy + hosts: + - tcp://relayminers:8545 diff --git a/localnet/poktrolld/config/relayminer_config_full_example.yaml b/localnet/poktrolld/config/relayminer_config_full_example.yaml index 3a3f9b65d..8864a4f95 100644 --- a/localnet/poktrolld/config/relayminer_config_full_example.yaml +++ b/localnet/poktrolld/config/relayminer_config_full_example.yaml @@ -12,12 +12,12 @@ smt_store_path: smt_stores pocket_node: # Pocket node URL that exposes CometBFT JSON-RPC API. # This can be used by the Cosmos client SDK, event subscriptions, etc... - query_node_rpc_url: tcp://poktroll-sequencer:36657 + query_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 # Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. # If unspecified, defaults to `tx_node_grpc_url`. - query_node_grpc_url: tcp://poktroll-sequencer:36658 + query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 # Pocket node URL that exposes the Cosmos gRPC service. - tx_node_grpc_url: tcp://poktroll-sequencer:36658 + tx_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 # Proxies are endpoints that expose different suppliers to the internet. proxies: From 7fa3f511be6609287cf9258f46287ea6427d433a Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 22 Dec 2023 03:25:45 +0100 Subject: [PATCH 29/34] chore: Address change requests --- .../relayminer_config_full_example.yaml | 40 ++++++++++++------- .../config/relayminer_configs_reader.go | 15 +++++-- pkg/relayer/config/types.go | 14 +++++-- pkg/relayer/interface.go | 2 +- 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/localnet/poktrolld/config/relayminer_config_full_example.yaml b/localnet/poktrolld/config/relayminer_config_full_example.yaml index 8864a4f95..5fdcc4bc2 100644 --- a/localnet/poktrolld/config/relayminer_config_full_example.yaml +++ b/localnet/poktrolld/config/relayminer_config_full_example.yaml @@ -21,9 +21,11 @@ pocket_node: # Proxies are endpoints that expose different suppliers to the internet. proxies: - # Name of the proxy. It will be used to reference in a supplier. Must be unique. + # Name of the proxy. It will be used to reference in a supplier. + # Must be unique. # Required. # TODO_CONSIDERATION: if we enforce DNS compliant names, it can potentially + # TODO_CONSIDERATION: Rename to `proxy_name` # become handy in the future. # More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names - name: http-example @@ -32,8 +34,9 @@ proxies: # MUST match the type of the supplier. # Required. type: http - # Hostname to open port on. Use 0.0.0.0 in containerized environments, - # 127.0.0.1 with a reverse-proxy when there's another process on localhost + # Hostname to open port on. + # Use 0.0.0.0 in containerized environments. + # 127.0.0.1 with a reverse proxy when there's another process on localhost # that can be used as a reverse proxy (nginx, apache, traefik, etc.). # Required. host: 127.0.0.1:8080 @@ -51,7 +54,8 @@ proxies: # When a supplier is configured to use a proxy and staked appropriately, # the relays will start flowing through RelayMiner. suppliers: - # Name of the supplier offered to the network. + # Name of the supplier offered to the network . + # It must match the serviceId of the service that has been staked for. # Must be unique. # Required. - name: ethereum @@ -62,6 +66,7 @@ suppliers: # Configuration of the service offered through RelayMiner. service_config: # URL RelayMiner proxies the requests to. + # Also known as the data node, or service node in some cases. # Required. url: http://anvil.servicer:8545 # Authentication for the service. @@ -78,18 +83,25 @@ suppliers: # Optional. headers: {} - # A list of hosts the HTTP service is offering. - # When linked to the proxy, that hostname is going to be used to route the - # request to the correct supplier. - # That hostname is what the user should stake the supplier for. - # Must be unique within a proxy/proxies it is set up on; - # in other words, one proxy can't offer the same hostname more than once. - # The `name` of the supplier is automatically added to the hosts section - # for potential troubleshooting/debugging purposes + # A list of hosts the proxy is accepting requests from. + # When linked to the proxy, each host is going to be used to lookup the + # the Supplier.Service in the Pocket Network. + # Each host in the list must match a Supplier.Service.Endpoint that the Supplier + # has advertised on-chain when staking for that Service. + # The reasons to have multiple hosts for the same supplier service are: + # - The on-chain Supplier may provide the same Service on multiple domains + # (e.g. for different regions). + # - The operator may want to route requests of different RPC types to + # the same proxy + # - Migrating from one domain to another. Where the operator could still + # accept requests on the old domain while the new domain is being propagated. + # Must be unique within the proxy it is referenced in. # Required. hosts: - ethereum.devnet1.poktroll.com - # - ethereum # <- this part is be added automatically. + # The `name` of the supplier is automatically added to the hosts section + # for potential troubleshooting/debugging purposes + # - ethereum # <- this part is added automatically. # Names of proxies that this supplier is connected to. # This MUST correspond to the name in the `proxies` section @@ -103,6 +115,6 @@ suppliers: url: http://llama-endpoint hosts: - 7b-llm-model.devnet1.poktroll.com - # - 7b-llm-model # <- this part can be added automatically. + # - 7b-llm-model # <- this part is added automatically. proxy_names: - http-example \ No newline at end of file diff --git a/pkg/relayer/config/relayminer_configs_reader.go b/pkg/relayer/config/relayminer_configs_reader.go index 9034daba9..ddf72f2ba 100644 --- a/pkg/relayer/config/relayminer_configs_reader.go +++ b/pkg/relayer/config/relayminer_configs_reader.go @@ -47,13 +47,22 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { return nil, err } - // Check if a proxy is referencing a host more than once + // Check if proxies are referencing hosts more than once + if err := relayMinerConfig.EnsureUniqueHosts(); err != nil { + return nil, err + } + + return relayMinerConfig, nil +} + +// EnsureUniqueHosts checks if each proxy is referencing a host more than once +func (relayMinerConfig *RelayMinerConfig) EnsureUniqueHosts() error { for _, proxyConfig := range relayMinerConfig.Proxies { existingHosts := make(map[string]bool) for _, supplierConfig := range proxyConfig.Suppliers { for _, host := range supplierConfig.Hosts { if _, ok := existingHosts[host]; ok { - return nil, ErrRelayMinerConfigInvalidProxy.Wrapf( + return ErrRelayMinerConfigInvalidProxy.Wrapf( "duplicate host %s in proxy %s", host, proxyConfig.Name, @@ -64,5 +73,5 @@ func ParseRelayMinerConfigs(configContent []byte) (*RelayMinerConfig, error) { } } - return relayMinerConfig, nil + return nil } diff --git a/pkg/relayer/config/types.go b/pkg/relayer/config/types.go index 9e4ef4a82..b4d9a8f1b 100644 --- a/pkg/relayer/config/types.go +++ b/pkg/relayer/config/types.go @@ -6,6 +6,7 @@ type ProxyType int const ( ProxyTypeHTTP ProxyType = iota + // TODO: Support other proxy types: HTTPS, TCP, UNIX socket, QUIC, WebRTC ... ) // YAMLRelayMinerConfig is the structure used to unmarshal the RelayMiner config file @@ -123,12 +124,17 @@ type RelayMinerSupplierServiceConfig struct { Url *url.URL // Authentication is the basic auth structure used to authenticate to the // request being proxied from the current proxy server. - // If `RelayMinerSupplierConfig.Type` is `ProxyTypeHTTP` then `Authentication` - // may be a non-nil pointer to a `RelayMinerSupplierServiceAuthentication` + // If the service the relay requests are forwarded to requires basic auth + // then this field must be populated. + // TODO_TECHDEBT(@red-0ne): Pass the authentication to the service instance + // when the relay request is forwarded to it. Authentication *RelayMinerSupplierServiceAuthentication // Headers is a map of headers to be used for other authentication means. - // If `RelayMinerSupplierConfig.Type` is `ProxyTypeHTTP` then `Headers` may - // be a non-nil pointer to a `map[string]string` + // If the service the relay requests are forwarded to requires header based + // authentication then this field must be populated accordingly. + // For example: { "Authorization": "Bearer " } + // TODO_TECHDEBT(@red-0ne): Add these headers to the forwarded request + // before sending it to the service instance. Headers map[string]string } diff --git a/pkg/relayer/interface.go b/pkg/relayer/interface.go index 7605b74f5..81fc81515 100644 --- a/pkg/relayer/interface.go +++ b/pkg/relayer/interface.go @@ -64,7 +64,7 @@ type RelayerProxy interface { VerifyRelayRequest( ctx context.Context, relayRequest *servicetypes.RelayRequest, - serviceId *sharedtypes.Service, + service *sharedtypes.Service, ) error // SignRelayResponse is a shared method used by RelayServers to sign From 0b6bd0e4ded65af9a17278110c8b7d6dd9d32612 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Fri, 22 Dec 2023 03:29:45 +0100 Subject: [PATCH 30/34] chore: Add UDP in TODO comment --- pkg/relayer/config/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/relayer/config/types.go b/pkg/relayer/config/types.go index b4d9a8f1b..512a521d5 100644 --- a/pkg/relayer/config/types.go +++ b/pkg/relayer/config/types.go @@ -6,7 +6,7 @@ type ProxyType int const ( ProxyTypeHTTP ProxyType = iota - // TODO: Support other proxy types: HTTPS, TCP, UNIX socket, QUIC, WebRTC ... + // TODO: Support other proxy types: HTTPS, TCP, UNIX socket, UDP, QUIC, WebRTC ... ) // YAMLRelayMinerConfig is the structure used to unmarshal the RelayMiner config file From 272606bee5955bd098687b219df2f235807a26d4 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Tue, 2 Jan 2024 15:30:25 +0100 Subject: [PATCH 31/34] chore: Improve documentation about multiple hosts config --- .../poktrolld/config/relayminer_config.yaml | 4 +- .../relayminer_config_full_example.yaml | 30 +-- pkg/relayer/config/proxies_config_hydrator.go | 10 +- .../config/relayminer_configs_reader.go | 2 +- .../config/relayminer_configs_reader_test.go | 178 +++++++++--------- pkg/relayer/config/supplier_hydrator.go | 10 +- .../config/suppliers_config_hydrator.go | 12 +- pkg/relayer/config/types.go | 12 +- pkg/relayer/proxy/proxy_test.go | 46 ++--- pkg/relayer/proxy/server_builder.go | 2 +- pkg/relayer/proxy/synchronous.go | 11 +- 11 files changed, 164 insertions(+), 153 deletions(-) diff --git a/localnet/poktrolld/config/relayminer_config.yaml b/localnet/poktrolld/config/relayminer_config.yaml index b82ede740..7f5645cf3 100644 --- a/localnet/poktrolld/config/relayminer_config.yaml +++ b/localnet/poktrolld/config/relayminer_config.yaml @@ -5,11 +5,11 @@ pocket_node: query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 tx_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 proxies: - - name: http-proxy + - proxy_name: http-proxy type: http host: 0.0.0.0:8545 suppliers: - - name: anvil + - service_id: anvil type: http service_config: url: http://anvil:8547/ diff --git a/localnet/poktrolld/config/relayminer_config_full_example.yaml b/localnet/poktrolld/config/relayminer_config_full_example.yaml index 5fdcc4bc2..759af1b5f 100644 --- a/localnet/poktrolld/config/relayminer_config_full_example.yaml +++ b/localnet/poktrolld/config/relayminer_config_full_example.yaml @@ -25,10 +25,9 @@ proxies: # Must be unique. # Required. # TODO_CONSIDERATION: if we enforce DNS compliant names, it can potentially - # TODO_CONSIDERATION: Rename to `proxy_name` # become handy in the future. # More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names - - name: http-example + - proxy_name: http-example # Type of proxy: currently only http is supported but will support more # (https, tcp, quic ...) in the future. # MUST match the type of the supplier. @@ -54,11 +53,11 @@ proxies: # When a supplier is configured to use a proxy and staked appropriately, # the relays will start flowing through RelayMiner. suppliers: - # Name of the supplier offered to the network . - # It must match the serviceId of the service that has been staked for. + # The serviceId the supplier offered to the network . + # It must match the Service.Id of the service that has been staked for. # Must be unique. # Required. - - name: ethereum + - service_id: ethereum # Type of how the supplier offers service through the network. # Must match the type of the proxy the supplier is connected to. # Required. @@ -85,31 +84,38 @@ suppliers: # A list of hosts the proxy is accepting requests from. # When linked to the proxy, each host is going to be used to lookup the - # the Supplier.Service in the Pocket Network. + # the Supplier.Service in Pocket Network. # Each host in the list must match a Supplier.Service.Endpoint that the Supplier # has advertised on-chain when staking for that Service. - # The reasons to have multiple hosts for the same supplier service are: + # There are various reasons to having multiple hosts for the same supplier services, # - The on-chain Supplier may provide the same Service on multiple domains # (e.g. for different regions). # - The operator may want to route requests of different RPC types to # the same proxy # - Migrating from one domain to another. Where the operator could still # accept requests on the old domain while the new domain is being propagated. + # - The operator may want to have a different domain for internal requests. + # - The on-chain Service configuration accepts multiple endpoints. # Must be unique within the proxy it is referenced in. # Required. hosts: - ethereum.devnet1.poktroll.com - # The `name` of the supplier is automatically added to the hosts section - # for potential troubleshooting/debugging purposes + # The `service_id` of the supplier is automatically added to the hosts section + # for potential troubleshooting/debugging purposes such as: + # Having internal requests coming from non-FQDNs because of complex routing. + # Sending requests from k8s pods. + # Specify the `host` in curl requests when testing `curl -H "Host: ethereum" ...` + # and make the proxy server process the request without the need for an + # on-chain Endpoint entry. # - ethereum # <- this part is added automatically. # Names of proxies that this supplier is connected to. - # This MUST correspond to the name in the `proxies` section - # in order for the supplier to be accessible to the external network. + # This MUST correspond to the `proxy_name` entry in the `proxies` section + # in order for the supplier to be available to the external network. # Required. proxy_names: - http-example # when the RelayMiner server builder runs. - - name: 7b-llm-model + - service_id: 7b-llm-model type: http service_config: url: http://llama-endpoint diff --git a/pkg/relayer/config/proxies_config_hydrator.go b/pkg/relayer/config/proxies_config_hydrator.go index 9b776cfb5..f3b7628ed 100644 --- a/pkg/relayer/config/proxies_config_hydrator.go +++ b/pkg/relayer/config/proxies_config_hydrator.go @@ -14,20 +14,20 @@ func (relayMinerConfig *RelayMinerConfig) HydrateProxies( for _, yamlProxyConfig := range yamlProxyConfigs { // Proxy name is required - if len(yamlProxyConfig.Name) == 0 { + if len(yamlProxyConfig.ProxyName) == 0 { return ErrRelayMinerConfigInvalidProxy.Wrap("proxy name is required") } // Proxy name should not be unique - if _, ok := relayMinerConfig.Proxies[yamlProxyConfig.Name]; ok { + if _, ok := relayMinerConfig.Proxies[yamlProxyConfig.ProxyName]; ok { return ErrRelayMinerConfigInvalidProxy.Wrapf( "duplicate porxy name %s", - yamlProxyConfig.Name, + yamlProxyConfig.ProxyName, ) } proxyConfig := &RelayMinerProxyConfig{ - Name: yamlProxyConfig.Name, + ProxyName: yamlProxyConfig.ProxyName, XForwardedHostLookup: yamlProxyConfig.XForwardedHostLookup, Suppliers: make(map[string]*RelayMinerSupplierConfig), } @@ -56,7 +56,7 @@ func (relayMinerConfig *RelayMinerConfig) HydrateProxies( ) } - relayMinerConfig.Proxies[proxyConfig.Name] = proxyConfig + relayMinerConfig.Proxies[proxyConfig.ProxyName] = proxyConfig } return nil diff --git a/pkg/relayer/config/relayminer_configs_reader.go b/pkg/relayer/config/relayminer_configs_reader.go index ddf72f2ba..8f7c3b5ca 100644 --- a/pkg/relayer/config/relayminer_configs_reader.go +++ b/pkg/relayer/config/relayminer_configs_reader.go @@ -65,7 +65,7 @@ func (relayMinerConfig *RelayMinerConfig) EnsureUniqueHosts() error { return ErrRelayMinerConfigInvalidProxy.Wrapf( "duplicate host %s in proxy %s", host, - proxyConfig.Name, + proxyConfig.ProxyName, ) } existingHosts[host] = true diff --git a/pkg/relayer/config/relayminer_configs_reader_test.go b/pkg/relayer/config/relayminer_configs_reader_test.go index 90d485880..a3906a3dc 100644 --- a/pkg/relayer/config/relayminer_configs_reader_test.go +++ b/pkg/relayer/config/relayminer_configs_reader_test.go @@ -33,11 +33,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -63,14 +63,14 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { SmtStorePath: "smt_stores", Proxies: map[string]*config.RelayMinerProxyConfig{ "http-example": { - Name: "http-example", + ProxyName: "http-example", Host: "127.0.0.1:8080", Type: config.ProxyTypeHTTP, XForwardedHostLookup: false, Suppliers: map[string]*config.RelayMinerSupplierConfig{ "ethereum": { - Name: "ethereum", - Type: config.ProxyTypeHTTP, + ServiceId: "ethereum", + Type: config.ProxyTypeHTTP, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, Authentication: &config.RelayMinerSupplierServiceAuthentication{ @@ -100,11 +100,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -116,7 +116,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { - tcp://ethereum.devnet1.poktroll.com proxy_names: - http-example - - name: 7b-llm-model + - service_id: 7b-llm-model type: http service_config: url: http://llama-endpoint @@ -138,14 +138,14 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { SmtStorePath: "smt_stores", Proxies: map[string]*config.RelayMinerProxyConfig{ "http-example": { - Name: "http-example", + ProxyName: "http-example", Host: "127.0.0.1:8080", Type: config.ProxyTypeHTTP, XForwardedHostLookup: false, Suppliers: map[string]*config.RelayMinerSupplierConfig{ "ethereum": { - Name: "ethereum", - Type: config.ProxyTypeHTTP, + ServiceId: "ethereum", + Type: config.ProxyTypeHTTP, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, Authentication: &config.RelayMinerSupplierServiceAuthentication{ @@ -160,8 +160,8 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { }, }, "7b-llm-model": { - Name: "7b-llm-model", - Type: config.ProxyTypeHTTP, + ServiceId: "7b-llm-model", + Type: config.ProxyTypeHTTP, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "llama-endpoint"}, }, @@ -186,14 +186,14 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: first-proxy + - proxy_name: first-proxy host: 127.0.0.1:8080 type: http - - name: second-proxy + - proxy_name: second-proxy host: 127.0.0.1:8081 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -215,14 +215,14 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { SmtStorePath: "smt_stores", Proxies: map[string]*config.RelayMinerProxyConfig{ "first-proxy": { - Name: "first-proxy", + ProxyName: "first-proxy", Host: "127.0.0.1:8080", Type: config.ProxyTypeHTTP, XForwardedHostLookup: false, Suppliers: map[string]*config.RelayMinerSupplierConfig{ "ethereum": { - Name: "ethereum", - Type: config.ProxyTypeHTTP, + ServiceId: "ethereum", + Type: config.ProxyTypeHTTP, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, }, @@ -233,14 +233,14 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { }, }, "second-proxy": { - Name: "second-proxy", + ProxyName: "second-proxy", Host: "127.0.0.1:8081", Type: config.ProxyTypeHTTP, XForwardedHostLookup: false, Suppliers: map[string]*config.RelayMinerSupplierConfig{ "ethereum": { - Name: "ethereum", - Type: config.ProxyTypeHTTP, + ServiceId: "ethereum", + Type: config.ProxyTypeHTTP, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, }, @@ -263,11 +263,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -289,14 +289,14 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { SmtStorePath: "smt_stores", Proxies: map[string]*config.RelayMinerProxyConfig{ "http-example": { - Name: "http-example", + ProxyName: "http-example", Host: "127.0.0.1:8080", Type: config.ProxyTypeHTTP, XForwardedHostLookup: false, Suppliers: map[string]*config.RelayMinerSupplierConfig{ "ethereum": { - Name: "ethereum", - Type: config.ProxyTypeHTTP, + ServiceId: "ethereum", + Type: config.ProxyTypeHTTP, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, }, @@ -321,12 +321,12 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http x_forwarded_host_lookup: true suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -348,14 +348,14 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { SmtStorePath: "smt_stores", Proxies: map[string]*config.RelayMinerProxyConfig{ "http-example": { - Name: "http-example", + ProxyName: "http-example", Host: "127.0.0.1:8080", Type: config.ProxyTypeHTTP, XForwardedHostLookup: true, Suppliers: map[string]*config.RelayMinerSupplierConfig{ "ethereum": { - Name: "ethereum", - Type: config.ProxyTypeHTTP, + ServiceId: "ethereum", + Type: config.ProxyTypeHTTP, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "anvil.servicer:8545"}, }, @@ -381,11 +381,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -408,11 +408,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -435,11 +435,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -462,11 +462,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -489,11 +489,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -516,11 +516,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { # explicitly omitted signing key name smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -543,11 +543,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 # explicitly omitted smt store path proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -571,7 +571,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores # explicitly omitted proxies section suppliers: - - name: ethereum + - proxy_name: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -595,7 +595,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { smt_store_path: smt_stores proxies: # explicitly empty proxies section suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -622,7 +622,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { - host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -645,11 +645,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: # explicitly empty proxy name + - proxy_name: # explicitly empty proxy name host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -672,11 +672,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example # explicitly missing proxy host type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -699,11 +699,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: # explicitly empty proxy host type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -726,11 +726,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 # explicitly missing proxy type suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -753,11 +753,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: # explicitly empty proxy type suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -780,11 +780,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: unsupported suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -807,7 +807,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: @@ -834,11 +834,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: # explicitly empty supplier name + - service_id: # explicitly empty supplier name type: http service_config: url: http://anvil.servicer:8545 @@ -861,11 +861,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: unsupported service_config: url: http://anvil.servicer:8545 @@ -888,11 +888,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum # explicitly missing supplier type service_config: url: http://anvil.servicer:8545 @@ -915,11 +915,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: # explicitly empty supplier type service_config: url: http://anvil.servicer:8545 @@ -942,11 +942,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: &http://anvil.servicer:8545 @@ -969,11 +969,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: # explicitly empty supplier service config url @@ -996,11 +996,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: # explicitly missing supplier service config url @@ -1023,11 +1023,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -1050,11 +1050,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -1077,11 +1077,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -1104,11 +1104,11 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { signing_key_name: servicer1 smt_store_path: smt_stores proxies: - - name: http-example + - proxy_name: http-example host: 127.0.0.1:8080 type: http suppliers: - - name: ethereum + - service_id: ethereum type: http service_config: url: http://anvil.servicer:8545 @@ -1116,7 +1116,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { - tcp://devnet1.poktroll.com # hosts for both suppliers are the same proxy_names: - http-example - - name: avax + - service_id: avax type: http service_config: url: http://avax.servicer:8545 @@ -1189,8 +1189,8 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { for proxyName, proxy := range tt.expectedConfig.Proxies { require.Equal( t, - proxy.Name, - config.Proxies[proxyName].Name, + proxy.ProxyName, + config.Proxies[proxyName].ProxyName, ) require.Equal( @@ -1208,8 +1208,8 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { for supplierName, supplier := range proxy.Suppliers { require.Equal( t, - supplier.Name, - config.Proxies[proxyName].Suppliers[supplierName].Name, + supplier.ServiceId, + config.Proxies[proxyName].Suppliers[supplierName].ServiceId, ) require.Equal( diff --git a/pkg/relayer/config/supplier_hydrator.go b/pkg/relayer/config/supplier_hydrator.go index 7b3be7fe3..0b54a36f0 100644 --- a/pkg/relayer/config/supplier_hydrator.go +++ b/pkg/relayer/config/supplier_hydrator.go @@ -8,10 +8,10 @@ func (supplierConfig *RelayMinerSupplierConfig) HydrateSupplier( yamlSupplierConfig YAMLRelayMinerSupplierConfig, ) error { // Supplier name is required - if len(yamlSupplierConfig.Name) == 0 { + if len(yamlSupplierConfig.ServiceId) == 0 { return ErrRelayMinerConfigInvalidSupplier.Wrap("supplier name is required") } - supplierConfig.Name = yamlSupplierConfig.Name + supplierConfig.ServiceId = yamlSupplierConfig.ServiceId // Supplier hosts supplierConfig.Hosts = []string{} @@ -46,8 +46,8 @@ func (supplierConfig *RelayMinerSupplierConfig) HydrateSupplier( // Add a default host which corresponds to the supplier name if it is not // already in the list - if _, ok := existingHosts[supplierConfig.Name]; !ok { - supplierConfig.Hosts = append(supplierConfig.Hosts, supplierConfig.Name) + if _, ok := existingHosts[supplierConfig.ServiceId]; !ok { + supplierConfig.Hosts = append(supplierConfig.Hosts, supplierConfig.ServiceId) } // Populate the supplier service fields that are relevant to each supported @@ -74,7 +74,7 @@ func (supplierConfig *RelayMinerSupplierConfig) HydrateSupplier( if len(yamlSupplierConfig.ProxyNames) == 0 { return ErrRelayMinerConfigInvalidSupplier.Wrapf( "supplier %s has no proxies", - supplierConfig.Name, + supplierConfig.ServiceId, ) } diff --git a/pkg/relayer/config/suppliers_config_hydrator.go b/pkg/relayer/config/suppliers_config_hydrator.go index bcf321a57..b8f0f4fa7 100644 --- a/pkg/relayer/config/suppliers_config_hydrator.go +++ b/pkg/relayer/config/suppliers_config_hydrator.go @@ -14,14 +14,14 @@ func (relayMinerConfig *RelayMinerConfig) HydrateSuppliers( } // Supplier name should not be unique - if _, ok := existingSuppliers[yamlSupplierConfig.Name]; ok { + if _, ok := existingSuppliers[yamlSupplierConfig.ServiceId]; ok { return ErrRelayMinerConfigInvalidSupplier.Wrapf( "duplicate supplier name %s", - yamlSupplierConfig.Name, + yamlSupplierConfig.ServiceId, ) } // Mark the supplier as existing - existingSuppliers[yamlSupplierConfig.Name] = true + existingSuppliers[yamlSupplierConfig.ServiceId] = true // Add the supplier config to the referenced proxies for _, proxyName := range yamlSupplierConfig.ProxyNames { @@ -29,7 +29,7 @@ func (relayMinerConfig *RelayMinerConfig) HydrateSuppliers( if _, ok := relayMinerConfig.Proxies[proxyName]; !ok { return ErrRelayMinerConfigInvalidSupplier.Wrapf( "no matching proxy %s for supplier %s", - supplierConfig.Name, + supplierConfig.ServiceId, proxyName, ) } @@ -38,12 +38,12 @@ func (relayMinerConfig *RelayMinerConfig) HydrateSuppliers( if supplierConfig.Type != relayMinerConfig.Proxies[proxyName].Type { return ErrRelayMinerConfigInvalidSupplier.Wrapf( "supplier %s and proxy %s have different types", - supplierConfig.Name, + supplierConfig.ServiceId, proxyName, ) } - relayMinerConfig.Proxies[proxyName].Suppliers[supplierConfig.Name] = supplierConfig + relayMinerConfig.Proxies[proxyName].Suppliers[supplierConfig.ServiceId] = supplierConfig } } diff --git a/pkg/relayer/config/types.go b/pkg/relayer/config/types.go index 512a521d5..f96647acc 100644 --- a/pkg/relayer/config/types.go +++ b/pkg/relayer/config/types.go @@ -31,7 +31,7 @@ type YAMLRelayMinerPocketNodeConfig struct { // YAMLRelayMinerProxyConfig is the structure used to unmarshal the proxy // section of the RelayMiner config file type YAMLRelayMinerProxyConfig struct { - Name string `yaml:"name"` + ProxyName string `yaml:"proxy_name"` Type string `yaml:"type"` Host string `yaml:"host"` XForwardedHostLookup bool `yaml:"x_forwarded_host_lookup"` @@ -40,7 +40,7 @@ type YAMLRelayMinerProxyConfig struct { // YAMLRelayMinerSupplierConfig is the structure used to unmarshal the supplier // section of the RelayMiner config file type YAMLRelayMinerSupplierConfig struct { - Name string `yaml:"name"` + ServiceId string `yaml:"service_id"` Type string `yaml:"type"` Hosts []string `yaml:"hosts"` ServiceConfig YAMLRelayMinerSupplierServiceConfig `yaml:"service_config"` @@ -85,8 +85,8 @@ type RelayMinerPocketNodeConfig struct { // Other proxy types may embed other fields in the future. eg. "https" may // embed a TLS config. type RelayMinerProxyConfig struct { - // Name is the name of the proxy server, used to identify it in the config - Name string + // ProxyName is the name of the proxy server, used to identify it in the config + ProxyName string // Type is the transport protocol used by the proxy server like (http, https, etc.) Type ProxyType // Host is the host on which the proxy server will listen for incoming @@ -103,8 +103,8 @@ type RelayMinerProxyConfig struct { // RelayMinerSupplierConfig is the structure resulting from parsing the supplier // section of the RelayMiner config file. type RelayMinerSupplierConfig struct { - // Name is the serviceId corresponding to the current configuration. - Name string + // ServiceId is the serviceId corresponding to the current configuration. + ServiceId string // Type is the transport protocol used by the supplier, it must match the // type of the proxy it is associated with. Type ProxyType diff --git a/pkg/relayer/proxy/proxy_test.go b/pkg/relayer/proxy/proxy_test.go index 20fb71e5a..bb699be71 100644 --- a/pkg/relayer/proxy/proxy_test.go +++ b/pkg/relayer/proxy/proxy_test.go @@ -75,22 +75,22 @@ func init() { proxiedServices = map[string]*config.RelayMinerProxyConfig{ "server1": { - Name: "server1", - Type: config.ProxyTypeHTTP, - Host: "127.0.0.1:8080", + ProxyName: "server1", + Type: config.ProxyTypeHTTP, + Host: "127.0.0.1:8080", Suppliers: map[string]*config.RelayMinerSupplierConfig{ "service1": { - Name: "service1", - Type: config.ProxyTypeHTTP, - Hosts: []string{"supplier:8545"}, + ServiceId: "service1", + Type: config.ProxyTypeHTTP, + Hosts: []string{"supplier:8545"}, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "127.0.0.1:8545", Path: "/"}, }, }, "service2": { - Name: "service2", - Type: config.ProxyTypeHTTP, - Hosts: []string{"supplier:8546"}, + ServiceId: "service2", + Type: config.ProxyTypeHTTP, + Hosts: []string{"supplier:8546"}, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "127.0.0.1:8546", Path: "/"}, }, @@ -98,14 +98,14 @@ func init() { }, }, "server2": { - Name: "server2", - Type: config.ProxyTypeHTTP, - Host: "127.0.0.1:8081", + ProxyName: "server2", + Type: config.ProxyTypeHTTP, + Host: "127.0.0.1:8081", Suppliers: map[string]*config.RelayMinerSupplierConfig{ "service3": { - Name: "service3", - Type: config.ProxyTypeHTTP, - Hosts: []string{"supplier:8547"}, + ServiceId: "service3", + Type: config.ProxyTypeHTTP, + Hosts: []string{"supplier:8547"}, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "127.0.0.1:8547", Path: "/"}, }, @@ -252,13 +252,13 @@ func TestRelayerProxy_UnsupportedTransportType(t *testing.T) { unsupportedTransportProxy := map[string]*config.RelayMinerProxyConfig{ "server1": { - Name: "server1", + ProxyName: "server1", // The proxy is configured with an unsupported transport type Type: config.ProxyType(100), Host: "127.0.0.1:8080", Suppliers: map[string]*config.RelayMinerSupplierConfig{ "service1": { - Name: "service1", + ServiceId: "service1", // The proxy is configured with an unsupported transport type Type: config.ProxyType(100), Hosts: []string{"supplier:8545"}, @@ -298,14 +298,14 @@ func TestRelayerProxy_NonConfiguredSupplierServices(t *testing.T) { missingServicesProxy := map[string]*config.RelayMinerProxyConfig{ "server1": { - Name: "server1", - Type: config.ProxyTypeHTTP, - Host: "127.0.0.1:8080", + ProxyName: "server1", + Type: config.ProxyTypeHTTP, + Host: "127.0.0.1:8080", Suppliers: map[string]*config.RelayMinerSupplierConfig{ "service1": { - Name: "service1", - Type: config.ProxyTypeHTTP, - Hosts: []string{"supplier:8545"}, + ServiceId: "service1", + Type: config.ProxyTypeHTTP, + Hosts: []string{"supplier:8545"}, ServiceConfig: &config.RelayMinerSupplierServiceConfig{ Url: &url.URL{Scheme: "http", Host: "127.0.0.1:8545", Path: "/"}, }, diff --git a/pkg/relayer/proxy/server_builder.go b/pkg/relayer/proxy/server_builder.go index 559f9a3ed..a42e876be 100644 --- a/pkg/relayer/proxy/server_builder.go +++ b/pkg/relayer/proxy/server_builder.go @@ -93,7 +93,7 @@ func (rp *relayerProxy) initializeProxyServers( // Initialize the proxy server according to the proxy type defined in the config file switch proxyConfig.Type { case config.ProxyTypeHTTP: - proxyServers[proxyConfig.Name] = NewSynchronousServer( + proxyServers[proxyConfig.ProxyName] = NewSynchronousServer( rp.logger, proxyConfig, supplierServiceMap, diff --git a/pkg/relayer/proxy/synchronous.go b/pkg/relayer/proxy/synchronous.go index 8a698846d..85b181f43 100644 --- a/pkg/relayer/proxy/synchronous.go +++ b/pkg/relayer/proxy/synchronous.go @@ -94,8 +94,8 @@ func (sync *synchronousRPCServer) ServeHTTP(writer http.ResponseWriter, request var originHost string // When the proxy is behind a reverse proxy, or is getting its requests from - // a CDN, the host header may not contain the on-chain advertized address - // needed to determine the service that the relay request is for. + // a CDN or a load balancer, the host header may not contain the on-chain + // advertized address needed to determine the service that the relay request is for. // These CDNs and reverse proxies usually set the X-Forwarded-Host header // to the original host. // RelayMiner operators that have such a setup can set the XForwardedHostLookup @@ -115,10 +115,15 @@ func (sync *synchronousRPCServer) ServeHTTP(writer http.ResponseWriter, request var serviceUrl *url.URL // Get the Service and serviceUrl corresponding to the originHost. + // TODO_IMPROVE(red-0ne): Checking that the originHost is currently done by + // iterating over the proxy config's suppliers and checking if the originHost + // is present in any of the supplier's service's hosts. We could improve this + // by building a map at the server initialization level with originHost as the + // key so that we can get the service and serviceUrl in O(1) time. for _, supplierServiceConfig := range sync.proxyConfig.Suppliers { for _, host := range supplierServiceConfig.Hosts { if host == originHost { - supplierService = sync.supplierServiceMap[supplierServiceConfig.Name] + supplierService = sync.supplierServiceMap[supplierServiceConfig.ServiceId] serviceUrl = supplierServiceConfig.ServiceConfig.Url break } From 80c66d6d8111dd740cdeeadbcaffd0aedb2462fb Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 3 Jan 2024 22:09:04 +0100 Subject: [PATCH 32/34] chore: Add change to trigger e2e test --- localnet/poktrolld/config/relayminer_config_full_example.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/localnet/poktrolld/config/relayminer_config_full_example.yaml b/localnet/poktrolld/config/relayminer_config_full_example.yaml index 759af1b5f..fda028b9d 100644 --- a/localnet/poktrolld/config/relayminer_config_full_example.yaml +++ b/localnet/poktrolld/config/relayminer_config_full_example.yaml @@ -91,7 +91,7 @@ suppliers: # - The on-chain Supplier may provide the same Service on multiple domains # (e.g. for different regions). # - The operator may want to route requests of different RPC types to - # the same proxy + # the same proxy. # - Migrating from one domain to another. Where the operator could still # accept requests on the old domain while the new domain is being propagated. # - The operator may want to have a different domain for internal requests. From 6bc4394c1e8013bd1fc4c29932be768c723f1a92 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 4 Jan 2024 00:09:53 +0100 Subject: [PATCH 33/34] chore: e2e bump --- localnet/poktrolld/config/relayminer_config_full_example.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/localnet/poktrolld/config/relayminer_config_full_example.yaml b/localnet/poktrolld/config/relayminer_config_full_example.yaml index fda028b9d..c7419fac5 100644 --- a/localnet/poktrolld/config/relayminer_config_full_example.yaml +++ b/localnet/poktrolld/config/relayminer_config_full_example.yaml @@ -3,10 +3,10 @@ # "hot" config changes in the future, meaning changes without restarting a process. # This would be useful for adding a proxy or a supplier without interrupting the service. -# Name of the key (in the keyring) to sign transactions +# Name of the key (in the keyring) to sign transactions. signing_key_name: supplier1 # Relative path (on the relayminer's machine) to where the data backing -# SMT KV store exists on disk +# SMT KV store exists on disk. smt_store_path: smt_stores pocket_node: From e64c6e601aff930d923fb1ad508d117451c27b66 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Thu, 4 Jan 2024 17:22:15 +0100 Subject: [PATCH 34/34] fix: Use RPC url for tx broadcasting --- localnet/kubernetes/values-relayminer.yaml | 2 +- .../config/appgate_server_config_example.yaml | 1 - .../poktrolld/config/relayminer_config.yaml | 2 +- .../relayminer_config_full_example.yaml | 6 +- pkg/deps/config/suppliers.go | 32 ++++++- pkg/relayer/cmd/cmd.go | 14 +-- .../config/pocket_node_config_hydrator.go | 38 ++++---- .../config/relayminer_configs_reader_test.go | 90 +++++++++---------- pkg/relayer/config/types.go | 4 +- 9 files changed, 106 insertions(+), 83 deletions(-) diff --git a/localnet/kubernetes/values-relayminer.yaml b/localnet/kubernetes/values-relayminer.yaml index 63e15465b..3e5300a78 100644 --- a/localnet/kubernetes/values-relayminer.yaml +++ b/localnet/kubernetes/values-relayminer.yaml @@ -4,7 +4,7 @@ config: pocket_node: query_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 - tx_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 + tx_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 proxies: - proxy_name: http-proxy type: http diff --git a/localnet/poktrolld/config/appgate_server_config_example.yaml b/localnet/poktrolld/config/appgate_server_config_example.yaml index 42a88be81..d34252066 100644 --- a/localnet/poktrolld/config/appgate_server_config_example.yaml +++ b/localnet/poktrolld/config/appgate_server_config_example.yaml @@ -2,7 +2,6 @@ # This can be used by the Cosmos client SDK, event subscriptions, etc... query_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 # Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. -# If unspecified, defaults to `tx_node_grpc_url`. query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 # The name of the key (in the keyring) that will be used to sign relays signing_key: app1 diff --git a/localnet/poktrolld/config/relayminer_config.yaml b/localnet/poktrolld/config/relayminer_config.yaml index 7f5645cf3..0f01695b3 100644 --- a/localnet/poktrolld/config/relayminer_config.yaml +++ b/localnet/poktrolld/config/relayminer_config.yaml @@ -3,7 +3,7 @@ smt_store_path: smt_stores pocket_node: query_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 - tx_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 + tx_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 proxies: - proxy_name: http-proxy type: http diff --git a/localnet/poktrolld/config/relayminer_config_full_example.yaml b/localnet/poktrolld/config/relayminer_config_full_example.yaml index c7419fac5..99f370900 100644 --- a/localnet/poktrolld/config/relayminer_config_full_example.yaml +++ b/localnet/poktrolld/config/relayminer_config_full_example.yaml @@ -12,12 +12,12 @@ smt_store_path: smt_stores pocket_node: # Pocket node URL that exposes CometBFT JSON-RPC API. # This can be used by the Cosmos client SDK, event subscriptions, etc... + # If unspecified, defaults to `tx_node_rpc_url`. query_node_rpc_url: tcp://sequencer-poktroll-sequencer:36657 # Pocket node URL that exposes the Cosmos gRPC service, dedicated to querying purposes. - # If unspecified, defaults to `tx_node_grpc_url`. query_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 - # Pocket node URL that exposes the Cosmos gRPC service. - tx_node_grpc_url: tcp://sequencer-poktroll-sequencer:36658 + # Pocket node URL that exposes the TendermintRPC service. + tx_node_rpc_url: tcp://sequencer-poktroll-sequencer:36658 # Proxies are endpoints that expose different suppliers to the internet. proxies: diff --git a/pkg/deps/config/suppliers.go b/pkg/deps/config/suppliers.go index 902d2b5ff..4a9d536e9 100644 --- a/pkg/deps/config/suppliers.go +++ b/pkg/deps/config/suppliers.go @@ -146,24 +146,42 @@ func NewSupplyQueryClientContextFn(queryNodeGRPCURL *url.URL) SupplierFn { // from the given txNodeGRPCURL. // TODO_TECHDEBT(#256): Remove this function once the as we may no longer // need to supply a TxClientContext to the RelayMiner. -func NewSupplyTxClientContextFn(txNodeGRPCURL *url.URL) SupplierFn { +func NewSupplyTxClientContextFn( + queryNodeGRPCURL *url.URL, + txNodeRPCURL *url.URL, +) SupplierFn { return func(_ context.Context, deps depinject.Config, cmd *cobra.Command, ) (depinject.Config, error) { // Temporarily store the flag's current value to be restored later, after - // the client context has been created with txNodeGRPCURL. + // the client context has been created with txNodeRPCURL. + // TODO_TECHDEBT(#223) Retrieve value from viper instead, once integrated. + tmpNode, err := cmd.Flags().GetString(cosmosflags.FlagNode) + if err != nil { + return nil, err + } + + // Temporarily store the flag's current value to be restored later, after + // the client context has been created with queryNodeGRPCURL. // TODO_TECHDEBT(#223) Retrieve value from viper instead, once integrated. tmpGRPC, err := cmd.Flags().GetString(cosmosflags.FlagGRPC) if err != nil { return nil, err } - // Set --node flag to the pocketTxNodeURL for the client context + // Set --node flag to the txNodeRPCURL for the client context // This flag is read by cosmosclient.GetClientTxContext. + if err := cmd.Flags().Set(cosmosflags.FlagNode, txNodeRPCURL.String()); err != nil { + return nil, err + } + + // Set --grpc-addr flag to the queryNodeGRPCURL for the client context + // This flag is read by cosmosclient.GetClientTxContext to query accounts + // for transaction signing. // Cosmos-SDK is expecting a GRPC address formatted as [:], // so we only need to set the Host parameter of the URL to cosmosflags.FlagGRPC value. - if err := cmd.Flags().Set(cosmosflags.FlagGRPC, txNodeGRPCURL.Host); err != nil { + if err := cmd.Flags().Set(cosmosflags.FlagGRPC, queryNodeGRPCURL.Host); err != nil { return nil, err } @@ -187,6 +205,12 @@ func NewSupplyTxClientContextFn(txNodeGRPCURL *url.URL) SupplierFn { return nil, err } + // Restore the flag's original value in order for other components + // to use the flag as expected. + if err := cmd.Flags().Set(cosmosflags.FlagNode, tmpNode); err != nil { + return nil, err + } + return deps, nil } } diff --git a/pkg/relayer/cmd/cmd.go b/pkg/relayer/cmd/cmd.go index 5f5763240..1dbc61b76 100644 --- a/pkg/relayer/cmd/cmd.go +++ b/pkg/relayer/cmd/cmd.go @@ -70,8 +70,8 @@ for such operations.`, // Cosmos flags // TODO_TECHDEBT(#256): Remove unneeded cosmos flags. cmd.Flags().String(cosmosflags.FlagKeyringBackend, "", "Select keyring's backend (os|file|kwallet|pass|test)") - cmd.Flags().StringVar(&flagNodeRPCURL, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialize the Cosmos query context correctly. It can be used to override the `QueryNodeRPCURL` field in the config file if specified.") - cmd.Flags().StringVar(&flagNodeGRPCURL, cosmosflags.FlagGRPC, omittedDefaultFlagValue, "Register the default Cosmos node grpc flag, which is needed to initialize the Cosmos query and tx contexts with grpc correctly. It can be used to override the `QueryNodeGRPCURL` and `TxNodeGRPCURL` fields in the config file if specified.") + cmd.Flags().StringVar(&flagNodeRPCURL, cosmosflags.FlagNode, omittedDefaultFlagValue, "Register the default Cosmos node flag, which is needed to initialize the Cosmos query and tx contexts correctly. It can be used to override the `QueryNodeRPCURL` and `TxNodeRPCURL` fields in the config file if specified.") + cmd.Flags().StringVar(&flagNodeGRPCURL, cosmosflags.FlagGRPC, omittedDefaultFlagValue, "Register the default Cosmos node grpc flag, which is needed to initialize the Cosmos query context with grpc correctly. It can be used to override the `QueryNodeGRPCURL` field in the config file if specified.") cmd.Flags().Bool(cosmosflags.FlagGRPCInsecure, true, "Used to initialize the Cosmos query context with grpc security options. It can be used to override the `QueryNodeGRPCInsecure` field in the config file if specified.") return cmd @@ -142,9 +142,9 @@ func setupRelayerDependencies( ) (deps depinject.Config, err error) { queryNodeRPCUrl := relayMinerConfig.PocketNode.QueryNodeRPCUrl queryNodeGRPCUrl := relayMinerConfig.PocketNode.QueryNodeGRPCUrl - txNodeGRPCUrl := relayMinerConfig.PocketNode.TxNodeGRPCUrl + txNodeRPCUrl := relayMinerConfig.PocketNode.TxNodeRPCUrl - // Override the config file's `QueryNodeGRPCUrl` and `txNodeGRPCUrl` fields + // Override the config file's `QueryNodeGRPCUrl` fields // with the `--grpc-addr` flag if it was specified. // TODO(#223) Remove this check once viper is used as SoT for overridable config values. if flagNodeGRPCURL != omittedDefaultFlagValue { @@ -153,10 +153,9 @@ func setupRelayerDependencies( return nil, fmt.Errorf("failed to parse grpc query URL: %w", err) } queryNodeGRPCUrl = parsedFlagNodeGRPCUrl - txNodeGRPCUrl = parsedFlagNodeGRPCUrl } - // Override the config file's `QueryNodeUrl` fields + // Override the config file's `QueryNodeUrl` and `txNodeRPCUrl` fields // with the `--node` flag if it was specified. // TODO(#223) Remove this check once viper is used as SoT for overridable config values. if flagNodeRPCURL != omittedDefaultFlagValue { @@ -165,6 +164,7 @@ func setupRelayerDependencies( return nil, fmt.Errorf("failed to parse rpc query URL: %w", err) } queryNodeRPCUrl = parsedFlagNodeRPCUrl + txNodeRPCUrl = parsedFlagNodeRPCUrl } signingKeyName := relayMinerConfig.SigningKeyName @@ -177,7 +177,7 @@ func setupRelayerDependencies( config.NewSupplyBlockClientFn(), // leaf config.NewSupplyQueryClientContextFn(queryNodeGRPCUrl), // leaf supplyMiner, // leaf - config.NewSupplyTxClientContextFn(txNodeGRPCUrl), // leaf + config.NewSupplyTxClientContextFn(queryNodeGRPCUrl, txNodeRPCUrl), // leaf config.NewSupplyAccountQuerierFn(), config.NewSupplyApplicationQuerierFn(), config.NewSupplySupplierQuerierFn(), diff --git a/pkg/relayer/config/pocket_node_config_hydrator.go b/pkg/relayer/config/pocket_node_config_hydrator.go index 4da7dc48c..88a57fa85 100644 --- a/pkg/relayer/config/pocket_node_config_hydrator.go +++ b/pkg/relayer/config/pocket_node_config_hydrator.go @@ -9,48 +9,48 @@ func (relayMinerConfig *RelayMinerConfig) HydratePocketNodeUrls( ) error { relayMinerConfig.PocketNode = &RelayMinerPocketNodeConfig{} - if len(yamlPocketNodeConfig.TxNodeGRPCUrl) == 0 { - return ErrRelayMinerConfigInvalidNodeUrl.Wrap("tx node grpc url is required") + if len(yamlPocketNodeConfig.TxNodeRPCUrl) == 0 { + return ErrRelayMinerConfigInvalidNodeUrl.Wrap("tx node rpc url is required") } - // Check if the pocket node grpc url is a valid URL - txNodeGRPCUrl, err := url.Parse(yamlPocketNodeConfig.TxNodeGRPCUrl) + // Check if the pocket node rpc url is a valid URL + txNodeRPCUrl, err := url.Parse(yamlPocketNodeConfig.TxNodeRPCUrl) if err != nil { return ErrRelayMinerConfigInvalidNodeUrl.Wrapf( - "invalid tx node grpc url %s", + "invalid tx node rpc url %s", err.Error(), ) } - relayMinerConfig.PocketNode.TxNodeGRPCUrl = txNodeGRPCUrl + relayMinerConfig.PocketNode.TxNodeRPCUrl = txNodeRPCUrl - // If the query node grpc url is empty, use the tx node grpc url - if len(yamlPocketNodeConfig.QueryNodeGRPCUrl) == 0 { - relayMinerConfig.PocketNode.QueryNodeGRPCUrl = relayMinerConfig.PocketNode.TxNodeGRPCUrl + // If the query node rpc url is empty, use the tx node rpc url + if len(yamlPocketNodeConfig.QueryNodeRPCUrl) == 0 { + relayMinerConfig.PocketNode.QueryNodeRPCUrl = relayMinerConfig.PocketNode.TxNodeRPCUrl } else { - // If the query node grpc url is not empty, make sure it is a valid URL - queryNodeGRPCUrl, err := url.Parse(yamlPocketNodeConfig.QueryNodeGRPCUrl) + // If the query node rpc url is not empty, make sure it is a valid URL + queryNodeRPCUrl, err := url.Parse(yamlPocketNodeConfig.QueryNodeRPCUrl) if err != nil { return ErrRelayMinerConfigInvalidNodeUrl.Wrapf( - "invalid query node grpc url %s", + "invalid query node rpc url %s", err.Error(), ) } - relayMinerConfig.PocketNode.QueryNodeGRPCUrl = queryNodeGRPCUrl + relayMinerConfig.PocketNode.QueryNodeRPCUrl = queryNodeRPCUrl } - if len(yamlPocketNodeConfig.QueryNodeRPCUrl) == 0 { - return ErrRelayMinerConfigInvalidNodeUrl.Wrap("query node rpc url is required") + if len(yamlPocketNodeConfig.QueryNodeGRPCUrl) == 0 { + return ErrRelayMinerConfigInvalidNodeUrl.Wrap("query node grpc url is required") } - // Check if the query node rpc url is a valid URL - queryNodeRPCUrl, err := url.Parse(yamlPocketNodeConfig.QueryNodeRPCUrl) + // Check if the query node grpc url is a valid URL + queryNodeGRPCUrl, err := url.Parse(yamlPocketNodeConfig.QueryNodeGRPCUrl) if err != nil { return ErrRelayMinerConfigInvalidNodeUrl.Wrapf( - "invalid query node rpc url %s", + "invalid query node grpc url %s", err.Error(), ) } - relayMinerConfig.PocketNode.QueryNodeRPCUrl = queryNodeRPCUrl + relayMinerConfig.PocketNode.QueryNodeGRPCUrl = queryNodeGRPCUrl return nil } diff --git a/pkg/relayer/config/relayminer_configs_reader_test.go b/pkg/relayer/config/relayminer_configs_reader_test.go index a3906a3dc..6b8bc3c60 100644 --- a/pkg/relayer/config/relayminer_configs_reader_test.go +++ b/pkg/relayer/config/relayminer_configs_reader_test.go @@ -29,7 +29,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -57,7 +57,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { PocketNode: &config.RelayMinerPocketNodeConfig{ QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, + TxNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, }, SigningKeyName: "servicer1", SmtStorePath: "smt_stores", @@ -96,7 +96,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -132,7 +132,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { PocketNode: &config.RelayMinerPocketNodeConfig{ QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, + TxNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, }, SigningKeyName: "servicer1", SmtStorePath: "smt_stores", @@ -182,7 +182,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -209,7 +209,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { PocketNode: &config.RelayMinerPocketNodeConfig{ QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, + TxNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, }, SigningKeyName: "servicer1", SmtStorePath: "smt_stores", @@ -254,12 +254,12 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { }, }, { - desc: "valid: relay miner config with query node grpc url defaulting to tx node grpc url", + desc: "valid: relay miner config with query node rpc url defaulting to tx node rpc url", inputConfigYAML: ` pocket_node: - query_node_rpc_url: tcp://127.0.0.1:36657 - tx_node_grpc_url: tcp://127.0.0.1:36659 + query_node_grpc_url: tcp://127.0.0.1:36658 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -281,9 +281,9 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { expectedError: nil, expectedConfig: &config.RelayMinerConfig{ PocketNode: &config.RelayMinerPocketNodeConfig{ - QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, - QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, - TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, + QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, + QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, + TxNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, }, SigningKeyName: "servicer1", SmtStorePath: "smt_stores", @@ -317,7 +317,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -342,7 +342,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { PocketNode: &config.RelayMinerPocketNodeConfig{ QueryNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36657"}, QueryNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36658"}, - TxNodeGRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, + TxNodeRPCUrl: &url.URL{Scheme: "tcp", Host: "127.0.0.1:36659"}, }, SigningKeyName: "servicer1", SmtStorePath: "smt_stores", @@ -377,7 +377,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: &tcp://127.0.0.1:36659 + tx_node_rpc_url: &tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -431,7 +431,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: &tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -458,7 +458,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: &tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -479,13 +479,13 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { expectedError: config.ErrRelayMinerConfigInvalidNodeUrl, }, { - desc: "invalid: missing query node rpc url", + desc: "invalid: missing query node grpc url", inputConfigYAML: ` pocket_node: # explicitly omitted query node rpc url - query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + query_node_rpc_url: tcp://127.0.0.1:36657 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -512,7 +512,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 # explicitly omitted signing key name smt_store_path: smt_stores proxies: @@ -539,7 +539,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 # explicitly omitted smt store path proxies: @@ -566,7 +566,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores # explicitly omitted proxies section @@ -590,7 +590,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: # explicitly empty proxies section @@ -614,7 +614,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -641,7 +641,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -668,7 +668,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -695,7 +695,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -722,7 +722,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -749,7 +749,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -776,7 +776,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -803,7 +803,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -830,7 +830,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -857,7 +857,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -884,7 +884,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -911,7 +911,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -938,7 +938,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -965,7 +965,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -992,7 +992,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -1019,7 +1019,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -1046,7 +1046,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -1073,7 +1073,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -1100,7 +1100,7 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { pocket_node: query_node_rpc_url: tcp://127.0.0.1:36657 query_node_grpc_url: tcp://127.0.0.1:36658 - tx_node_grpc_url: tcp://127.0.0.1:36659 + tx_node_rpc_url: tcp://127.0.0.1:36659 signing_key_name: servicer1 smt_store_path: smt_stores proxies: @@ -1182,8 +1182,8 @@ func Test_ParseRelayMinerConfigs(t *testing.T) { require.Equal( t, - tt.expectedConfig.PocketNode.TxNodeGRPCUrl.String(), - config.PocketNode.TxNodeGRPCUrl.String(), + tt.expectedConfig.PocketNode.TxNodeRPCUrl.String(), + config.PocketNode.TxNodeRPCUrl.String(), ) for proxyName, proxy := range tt.expectedConfig.Proxies { diff --git a/pkg/relayer/config/types.go b/pkg/relayer/config/types.go index f96647acc..fb14b8b20 100644 --- a/pkg/relayer/config/types.go +++ b/pkg/relayer/config/types.go @@ -25,7 +25,7 @@ type YAMLRelayMinerConfig struct { type YAMLRelayMinerPocketNodeConfig struct { QueryNodeRPCUrl string `yaml:"query_node_rpc_url"` QueryNodeGRPCUrl string `yaml:"query_node_grpc_url"` - TxNodeGRPCUrl string `yaml:"tx_node_grpc_url"` + TxNodeRPCUrl string `yaml:"tx_node_rpc_url"` } // YAMLRelayMinerProxyConfig is the structure used to unmarshal the proxy @@ -76,7 +76,7 @@ type RelayMinerConfig struct { type RelayMinerPocketNodeConfig struct { QueryNodeRPCUrl *url.URL QueryNodeGRPCUrl *url.URL - TxNodeGRPCUrl *url.URL + TxNodeRPCUrl *url.URL } // RelayMinerProxyConfig is the structure resulting from parsing the proxy