-
Notifications
You must be signed in to change notification settings - Fork 0
[WIP][Shannon][Refactor] Create GatewayClient and move relevant code from PATH to Shannon SDK #39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
commoddity
wants to merge
32
commits into
main
Choose a base branch
from
shannon-sdk-refactor-pt2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 22 commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
a0516f9
feat: phase 1 of major refactor - move fullnode functionality to SDK
eb145f2
comments
2f7029b
make validte relay request a method on the full node
ca3d365
feat: implement GatewayClients and move relevant code from PATH to Sh…
8cea41c
move FullNode interface to sdk package
8585235
make gateway client structs private
6d88a19
gateway mode method on gateway client
d6dd265
remove unused queryCodec
a94f720
Merge branch 'shannon-sdk-refactor' into shannon-sdk-refactor-pt2
c19c78a
update to sync comments with PATH PR #298
88ebd61
chore: merge conflicts
a549c5f
chore: merge conflicts
0a86437
updated to incorporate PR 298 changes
de5522f
move error handling for observations for delegated mode
71f0037
update comments in full node config
3489fb4
Merge branch 'shannon-sdk-refactor' into shannon-sdk-refactor-pt2
d81e4bd
chore: merge conflicts
9740238
fix: implement review comments
b37b272
fix: implement review comments
f4fdaac
make 'getAccountPubKey' private
544fd19
review comments and minor refactor
b2d5a08
fix observation errors
1106f83
fix: implement review comments
8b09728
fix: implement review comments
e715f0c
fix: implement review comments
c6e7b6b
improve logs and erros in gateway client
990759a
add comments make pub key fetch private
545fc0e
fix: implement review comments
a3a227f
reintroduce "lazy" fetching concept as GRPC client
6dc1456
fix comments
b556cff
fix comment
4f67b8a
fix nil logger
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| package client | ||
|
|
||
| import ( | ||
| "net" | ||
| "net/url" | ||
| "time" | ||
| ) | ||
|
|
||
| type ( | ||
| // FullNodeConfig is the configuration for the full node used by the GatewayClient. | ||
| FullNodeConfig struct { | ||
| // RPC URL is used to make RPC calls to the full node. | ||
| RpcURL string `yaml:"rpc_url"` | ||
| // GRPCConfig is the configuration for the gRPC connection to the full node. | ||
| GRPCConfig GRPCConfig `yaml:"grpc_config"` | ||
| // CacheConfig configures the caching behavior of the full node, including whether caching is enabled. | ||
| CacheConfig CacheConfig `yaml:"cache_config"` | ||
| } | ||
|
|
||
| // GRPCConfig configures the gRPC connection to the full node. | ||
| GRPCConfig struct { | ||
| // HostPort is the host and port of the full node. | ||
| // eg: localhost:26657 | ||
| HostPort string `yaml:"host_port"` | ||
| // UseInsecureGRPCConn determines if the gRPC connection to the full node should use TLS. | ||
| // This is useful for local development. | ||
| UseInsecureGRPCConn bool `yaml:"insecure"` | ||
| } | ||
|
|
||
| // CacheConfig configures the caching behavior of the full node, including whether caching is enabled. | ||
| CacheConfig struct { | ||
| // CachingEnabled determines if the full node should use caching. | ||
| // If set to `false`, the full node will not use caching, and will be returned directly. | ||
| // If set to `true`, the full node will be wrapped in a SturdyC-based cache. | ||
| CachingEnabled bool `yaml:"caching_enabled"` | ||
| // SessionTTL is the time to live for the session cache. | ||
| // Optional. If not set, the default session TTL will be used. | ||
| SessionTTL time.Duration `yaml:"session_ttl"` | ||
| } | ||
| ) | ||
|
|
||
| func (c FullNodeConfig) Validate() error { | ||
| if !isValidURL(c.RpcURL) { | ||
| return errShannonInvalidNodeURL | ||
| } | ||
| if !isValidHostPort(c.GRPCConfig.HostPort) { | ||
| return errShannonInvalidGrpcHostPort | ||
| } | ||
| if err := c.CacheConfig.validate(); err != nil { | ||
| return err | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // defaultSessionCacheTTL is the default time to live for the session cache. | ||
| // It should match the protocol's session length. | ||
| // | ||
| // TODO_NEXT(@commoddity): Session refresh handling should be significantly reworked as part | ||
| // of the next changes following PATH PR #297. | ||
| // The proposed change is to align session refreshes with actual session expiry time, | ||
| // using the session expiry block and the Shannon SDK's block client. | ||
| // When this is done, session cache TTL can be removed altogether. | ||
| const defaultSessionCacheTTL = 30 * time.Second | ||
|
|
||
| // validate validates the cache configuration for the full node. | ||
| func (c *CacheConfig) validate() error { | ||
| // Cannot set both lazy mode and cache configuration. | ||
| if !c.CachingEnabled && c.SessionTTL != 0 { | ||
| return errShannonCacheConfigSetForLazyMode | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // hydrateDefaults hydrates the cache configuration with defaults for any fields that are not set. | ||
| func (c *CacheConfig) hydrateDefaults() { | ||
| if c.SessionTTL == 0 { | ||
| c.SessionTTL = defaultSessionCacheTTL | ||
| } | ||
| } | ||
|
|
||
| // isValidURL returns true if the supplied URL string can be parsed into a valid URL accepted by the Shannon SDK. | ||
| func isValidURL(urlStr string) bool { | ||
| u, err := url.Parse(urlStr) | ||
| if err != nil { | ||
| return false | ||
| } | ||
|
|
||
| if u.Scheme == "" || u.Host == "" { | ||
| return false | ||
| } | ||
|
|
||
| return true | ||
| } | ||
|
|
||
| // isValidHostPort returns true if the supplied string can be parsed into a host and port combination. | ||
| func isValidHostPort(hostPort string) bool { | ||
| host, port, err := net.SplitHostPort(hostPort) | ||
|
|
||
| if err != nil { | ||
| return false | ||
| } | ||
|
|
||
| if host == "" || port == "" { | ||
| return false | ||
| } | ||
|
|
||
| return true | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package client | ||
|
|
||
| import "errors" | ||
|
|
||
| var ( | ||
| errShannonInvalidNodeURL = errors.New("invalid node URL") | ||
| errShannonInvalidGrpcHostPort = errors.New("invalid grpc host port") | ||
| errShannonCacheConfigSetForLazyMode = errors.New("session TTL cannot be set when caching is disabled") | ||
| ) | ||
|
|
||
| var ( | ||
| // could not get onchain data for app | ||
| ErrProtocolContextSetupAppFetchErr = errors.New("error getting onchain data for app owned by the gateway") | ||
| // app does not delegate to the gateway | ||
| ErrProtocolContextSetupAppDelegation = errors.New("app does not delegate to the gateway") | ||
| // no active sessions could be retrieved for the service. | ||
| ErrProtocolContextSetupNoSessions = errors.New("no active sessions could be retrieved for the service") | ||
| // app is not staked for the service. | ||
| ErrProtocolContextSetupAppNotStaked = errors.New("app is not staked for the service") | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| package client | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
|
|
||
| cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" | ||
| "github.com/cosmos/cosmos-sdk/types" | ||
| accounttypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||
| "github.com/pokt-network/poktroll/pkg/polylog" | ||
| apptypes "github.com/pokt-network/poktroll/x/application/types" | ||
| sessiontypes "github.com/pokt-network/poktroll/x/session/types" | ||
|
|
||
| sdk "github.com/pokt-network/shannon-sdk" | ||
| sdkTypes "github.com/pokt-network/shannon-sdk/types" | ||
| ) | ||
|
|
||
| // TODO_IN_THIS_PR(@commoddity): start a "micro readme" (just with bullet points) that captures more details about full node implementations? | ||
|
|
||
| // fullNode: default implementation of a full node for the Shannon. | ||
| // | ||
| // A fullNode queries the onchain data for every data item it needs to do an action (e.g. serve a relay request, etc). | ||
| // | ||
| // This is done to enable supporting short block times (a few seconds), by avoiding caching | ||
| // which can result in failures due to stale data in the cache. | ||
| // | ||
| // Key differences from a caching full node: | ||
| // - Intentionally avoids caching: | ||
| // - Enables support for short block times (e.g. LocalNet) | ||
| // - Use CachingFullNode struct if caching is desired for performance | ||
| // | ||
| // Implements the FullNode interface. | ||
| type fullNode struct { | ||
| logger polylog.Logger | ||
|
|
||
| appClient *sdk.ApplicationClient | ||
| sessionClient *sdk.SessionClient | ||
| blockClient *sdk.BlockClient | ||
| accountClient *sdk.AccountClient | ||
| } | ||
|
|
||
| // newFullNode builds and returns a fullNode using the provided configuration. | ||
| func newFullNode(logger polylog.Logger, rpcURL string, fullNodeConfig FullNodeConfig) (*fullNode, error) { | ||
| grpcConn, err := connectGRPC( | ||
| fullNodeConfig.GRPCConfig.HostPort, | ||
| fullNodeConfig.GRPCConfig.UseInsecureGRPCConn, | ||
| ) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("NewFullNode: error creating new GRPC connection at url %s: %w", | ||
| fullNodeConfig.GRPCConfig.HostPort, err) | ||
| } | ||
|
|
||
| blockClient, err := newBlockClient(rpcURL) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("NewFullNode: error creating new Shannon block client at URL %s: %w", rpcURL, err) | ||
| } | ||
|
|
||
| fullNode := &fullNode{ | ||
| logger: logger, | ||
| sessionClient: newSessionClient(grpcConn), | ||
| appClient: newAppClient(grpcConn), | ||
| accountClient: newAccClient(grpcConn), | ||
| blockClient: blockClient, | ||
| } | ||
|
|
||
| return fullNode, nil | ||
| } | ||
|
|
||
| // GetApp: | ||
| // - Returns the onchain application matching the supplied application address. | ||
| // - Required to fulfill the FullNode interface. | ||
| func (fn *fullNode) GetApp(ctx context.Context, appAddr string) (*apptypes.Application, error) { | ||
| app, err := fn.appClient.GetApplication(ctx, appAddr) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("GetApp: error getting the application for address %s: %w", appAddr, err) | ||
| } | ||
|
|
||
| fn.logger.Debug().Msgf("GetApp: fetched application %s", app) | ||
|
|
||
| return &app, err | ||
| } | ||
|
|
||
| // GetSession: | ||
| // - Uses the session client to fetch a session for the (serviceID, appAddr) combination. | ||
| // - Required to fulfill the FullNode interface. | ||
| func (fn *fullNode) GetSession( | ||
| ctx context.Context, | ||
| serviceID sdk.ServiceID, | ||
| appAddr string, | ||
| ) (sessiontypes.Session, error) { | ||
| session, err := fn.sessionClient.GetSession( | ||
| ctx, | ||
| appAddr, | ||
| string(serviceID), | ||
| 0, | ||
| ) | ||
|
|
||
| if err != nil { | ||
| return sessiontypes.Session{}, | ||
| fmt.Errorf("GetSession: error getting the session for service %s app %s: %w", | ||
| serviceID, appAddr, err, | ||
| ) | ||
| } | ||
|
|
||
| if session == nil { | ||
| return sessiontypes.Session{}, | ||
| fmt.Errorf("GetSession: got nil session for service %s app %s: %w", | ||
| serviceID, appAddr, err, | ||
| ) | ||
| } | ||
|
|
||
| fn.logger.Debug().Msgf("GetSession: fetched session %s", session) | ||
|
|
||
| return *session, nil | ||
| } | ||
|
|
||
| // IsHealthy: | ||
| // - Always returns true for a fullNode. | ||
| // - Required to fulfill the shannonFullNode interface. | ||
| func (fn *fullNode) IsHealthy() bool { | ||
| return true | ||
| } | ||
|
|
||
| // GetAccountPubKey returns the public key of the account with the given address. | ||
| // | ||
| // - Queries the account module using the gRPC query client. | ||
| func (fn *fullNode) getAccountPubKey( | ||
| ctx context.Context, | ||
| address string, | ||
| ) (pubKey cryptotypes.PubKey, err error) { | ||
| req := &accounttypes.QueryAccountRequest{Address: address} | ||
|
|
||
| res, err := fn.accountClient.Account(ctx, req) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| var fetchedAccount types.AccountI | ||
| if err = sdkTypes.QueryCodec.UnpackAny(res.Account, &fetchedAccount); err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return fetchedAccount.GetPubKey(), nil | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[linter-name (fail-on-found)] reported by reviewdog 🐶
// TODO_IN_THIS_PR(@commoddity): start a "micro readme" (just with bullet points) that captures more details about full node implementations?