diff --git a/pkg/relayer/interface.go b/pkg/relayer/interface.go index 51735a548..24ef17dfd 100644 --- a/pkg/relayer/interface.go +++ b/pkg/relayer/interface.go @@ -45,6 +45,8 @@ type RelayerProxy interface { SignRelayResponse(relayResponse *types.RelayResponse) error } +type RelayerProxyOption func(RelayerProxy) + // RelayServer is the interface of the advertised relay servers provided by the RelayerProxy. type RelayServer interface { // Start starts the service server and returns an error if it fails. diff --git a/pkg/relayer/proxy/errors.go b/pkg/relayer/proxy/errors.go index 4d2b56241..6a0815b58 100644 --- a/pkg/relayer/proxy/errors.go +++ b/pkg/relayer/proxy/errors.go @@ -3,9 +3,11 @@ package proxy import sdkerrors "cosmossdk.io/errors" var ( - codespace = "relayer/proxy" - ErrUnsupportedRPCType = sdkerrors.Register(codespace, 1, "unsupported rpc type") - ErrInvalidRelayRequestSignature = sdkerrors.Register(codespace, 2, "invalid relay request signature") - ErrInvalidSession = sdkerrors.Register(codespace, 3, "invalid session") - ErrInvalidSupplier = sdkerrors.Register(codespace, 4, "invalid supplier") + codespace = "relayer_proxy" + ErrRelayerProxyUnsupportedRPCType = sdkerrors.Register(codespace, 1, "unsupported relayer proxy rpc type") + ErrRelayerProxyInvalidRelayRequestSignature = sdkerrors.Register(codespace, 2, "invalid relay request signature") + ErrRelayerProxyInvalidSession = sdkerrors.Register(codespace, 3, "invalid session in relayer request") + ErrRelayerProxyInvalidSupplier = sdkerrors.Register(codespace, 4, "invalid relayer proxy supplier") + ErrRelayerProxyUndefinedSigningKeyName = sdkerrors.Register(codespace, 5, "undefined relayer proxy signing key name") + ErrRelayerProxyUndefinedProxiedServicesEndpoints = sdkerrors.Register(codespace, 6, "undefined proxied services endpoints for relayer proxy") ) diff --git a/pkg/relayer/proxy/options.go b/pkg/relayer/proxy/options.go new file mode 100644 index 000000000..4304d6067 --- /dev/null +++ b/pkg/relayer/proxy/options.go @@ -0,0 +1,20 @@ +package proxy + +import ( + "github.com/pokt-network/poktroll/pkg/relayer" +) + +// WithSigningKeyName sets the signing key name used by the relayer proxy to sign relay responses. +// It is used along with the keyring to get the supplier address and sign the relay responses. +func WithSigningKeyName(keyName string) relayer.RelayerProxyOption { + return func(relProxy relayer.RelayerProxy) { + relProxy.(*relayerProxy).signingKeyName = keyName + } +} + +// WithProxiedServicesEndpoints sets the endpoints of the proxied services. +func WithProxiedServicesEndpoints(proxiedServicesEndpoints servicesEndpointsMap) relayer.RelayerProxyOption { + return func(relProxy relayer.RelayerProxy) { + relProxy.(*relayerProxy).proxiedServicesEndpoints = proxiedServicesEndpoints + } +} diff --git a/pkg/relayer/proxy/proxy.go b/pkg/relayer/proxy/proxy.go index 6c64516cd..ea73031c8 100644 --- a/pkg/relayer/proxy/proxy.go +++ b/pkg/relayer/proxy/proxy.go @@ -4,6 +4,7 @@ import ( "context" "net/url" + "cosmossdk.io/depinject" sdkclient "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/crypto/keyring" accounttypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -32,10 +33,10 @@ type ( // when the miner enters the claim/proof phase. // TODO_TEST: Have tests for the relayer proxy. type relayerProxy struct { - // keyName is the supplier's key name in the Cosmos's keybase. It is used along with the keyring to + // signingKeyName is the supplier's key name in the Cosmos's keybase. It is used along with the keyring to // get the supplier address and sign the relay responses. - keyName string - keyring keyring.Keyring + signingKeyName string + keyring keyring.Keyring // blocksClient is the client used to get the block at the latest height from the blockchain // and be notified of new incoming blocks. It is used to update the current session data. @@ -75,30 +76,40 @@ type relayerProxy struct { supplierAddress string } +// NewRelayerProxy creates a new relayer proxy with the given dependencies or returns +// an error if the dependencies fail to resolve or the options are invalid. func NewRelayerProxy( - clientCtx sdkclient.Context, - keyName string, - keyring keyring.Keyring, - proxiedServicesEndpoints servicesEndpointsMap, - blockClient blocktypes.BlockClient, -) relayer.RelayerProxy { - accountQuerier := accounttypes.NewQueryClient(clientCtx) - supplierQuerier := suppliertypes.NewQueryClient(clientCtx) - sessionQuerier := sessiontypes.NewQueryClient(clientCtx) + deps depinject.Config, + opts ...relayer.RelayerProxyOption, +) (relayer.RelayerProxy, error) { + rp := &relayerProxy{} + + if err := depinject.Inject( + deps, + &rp.clientCtx, + &rp.blockClient, + ); err != nil { + return nil, err + } + servedRelays, servedRelaysProducer := channel.NewObservable[*types.Relay]() - return &relayerProxy{ - blockClient: blockClient, - keyName: keyName, - keyring: keyring, - accountsQuerier: accountQuerier, - supplierQuerier: supplierQuerier, - sessionQuerier: sessionQuerier, - proxiedServicesEndpoints: proxiedServicesEndpoints, - servedRelays: servedRelays, - servedRelaysProducer: servedRelaysProducer, - clientCtx: clientCtx, + rp.servedRelays = servedRelays + rp.servedRelaysProducer = servedRelaysProducer + rp.accountsQuerier = accounttypes.NewQueryClient(rp.clientCtx) + rp.supplierQuerier = suppliertypes.NewQueryClient(rp.clientCtx) + rp.sessionQuerier = sessiontypes.NewQueryClient(rp.clientCtx) + rp.keyring = rp.clientCtx.Keyring + + for _, opt := range opts { + opt(rp) } + + if err := rp.validateConfig(); err != nil { + return nil, err + } + + return rp, nil } // Start concurrently starts all advertised relay servers and returns an error if any of them fails to start. @@ -145,3 +156,17 @@ func (rp *relayerProxy) Stop(ctx context.Context) error { func (rp *relayerProxy) ServedRelays() observable.Observable[*types.Relay] { return rp.servedRelays } + +// validateConfig validates the relayer proxy's configuration options and returns an error if it is invalid. +// TODO_TEST: Add tests for validating these configurations. +func (rp *relayerProxy) validateConfig() error { + if rp.signingKeyName == "" { + return ErrRelayerProxyUndefinedSigningKeyName + } + + if rp.proxiedServicesEndpoints == nil { + return ErrRelayerProxyUndefinedProxiedServicesEndpoints + } + + return nil +} diff --git a/pkg/relayer/proxy/relay_signer.go b/pkg/relayer/proxy/relay_signer.go index bc172af00..5ab929cbe 100644 --- a/pkg/relayer/proxy/relay_signer.go +++ b/pkg/relayer/proxy/relay_signer.go @@ -19,7 +19,7 @@ func (rp *relayerProxy) SignRelayResponse(relayResponse *types.RelayResponse) er } hash := crypto.Sha256(responseBz) - relayResponse.Meta.SupplierSignature, _, err = rp.keyring.Sign(rp.keyName, hash) + relayResponse.Meta.SupplierSignature, _, err = rp.keyring.Sign(rp.signingKeyName, hash) return err } diff --git a/pkg/relayer/proxy/relay_verifier.go b/pkg/relayer/proxy/relay_verifier.go index 54f1685a4..db9cbe7dc 100644 --- a/pkg/relayer/proxy/relay_verifier.go +++ b/pkg/relayer/proxy/relay_verifier.go @@ -37,7 +37,7 @@ func (rp *relayerProxy) VerifyRelayRequest( } if !account.GetPubKey().VerifySignature(hash, relayRequest.Meta.Signature) { - return ErrInvalidRelayRequestSignature + return ErrRelayerProxyInvalidRelayRequestSignature } // Query for the current session to check if relayRequest sessionId matches the current session. @@ -62,7 +62,7 @@ func (rp *relayerProxy) VerifyRelayRequest( // matches the relayRequest sessionId. // TODO_INVESTIGATE: Revisit the assumptions above at some point in the future, but good enough for now. if session.SessionId != relayRequest.Meta.SessionHeader.SessionId { - return ErrInvalidSession + return ErrRelayerProxyInvalidSession } // Check if the relayRequest is allowed to be served by the relayer proxy. @@ -72,5 +72,5 @@ func (rp *relayerProxy) VerifyRelayRequest( } } - return ErrInvalidSupplier + return ErrRelayerProxyInvalidSupplier } diff --git a/pkg/relayer/proxy/server_builder.go b/pkg/relayer/proxy/server_builder.go index a821b5752..a5abc47bd 100644 --- a/pkg/relayer/proxy/server_builder.go +++ b/pkg/relayer/proxy/server_builder.go @@ -13,7 +13,7 @@ import ( // is responsible for listening for incoming relay requests and relaying them to the supported proxied service. func (rp *relayerProxy) BuildProvidedServices(ctx context.Context) error { // Get the supplier address from the keyring - supplierAddress, err := rp.keyring.Key(rp.keyName) + supplierAddress, err := rp.keyring.Key(rp.signingKeyName) if err != nil { return err } @@ -48,7 +48,7 @@ func (rp *relayerProxy) BuildProvidedServices(ctx context.Context) error { rp, ) default: - return ErrUnsupportedRPCType + return ErrRelayerProxyUnsupportedRPCType } serviceEndpoints = append(serviceEndpoints, server)