From 2d3605a7fbf1fbe21a4b481a78aea70d4ae80784 Mon Sep 17 00:00:00 2001 From: Blade <99137075+nodiesBlade@users.noreply.github.com> Date: Fri, 29 Mar 2024 23:14:52 -0500 Subject: [PATCH] Enhancement: Session Error handling and caching (#26) --- .gitignore | 8 +- README.md | 2 +- .../config/dot_env_config_provider.go | 30 +- .../internal/models/qos_node.go | 1 + .../internal/transform/qos_node.go | 10 +- cmd/gateway_server/main.go | 4 +- docker-compose.yml | 33 - docker-compose.yml.sample | 42 + go.mod | 1 + go.sum | 7 + .../checks/async_relay_handler.go | 2 +- .../checks/error_handler.go | 38 +- .../node_selector_service/models/qos_node.go | 49 +- .../node_selector_service.go | 13 +- internal/relayer/relayer.go | 11 +- internal/relayer/relayer_test.go | 6 +- .../cached_session_registry_service.go | 66 +- .../session_registry_service.go | 4 +- .../session_registry/session_registry_mock.go | 32 +- .../ttl_cache_service_mock.go | 46 + pkg/pokt/pokt_v0/basic_client.go | 7 + pkg/pokt/pokt_v0/models/relay.go | 2 + pkg/pokt/pokt_v0/models/relay_ffjson.go | 826 ++---------------- pkg/pokt/pokt_v0/models/session.go | 6 +- pkg/pokt/pokt_v0/models/session_ffjson.go | 24 +- pkg/ttl_cache/ttl_cache.go | 1 + 26 files changed, 353 insertions(+), 918 deletions(-) delete mode 100644 docker-compose.yml create mode 100644 docker-compose.yml.sample diff --git a/.gitignore b/.gitignore index 511e255..4b1be86 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,10 @@ /*.sqlite ## environment vars -.env \ No newline at end of file +.env + +## docker compose file +docker-compose.yml + +## MAC +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md index ecf8b70..b613053 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ To onboard the gateway server without having to dig deep, you can follow the [Qu Every release candidate is published to https://github.com/pokt-network/gateway-server/pkgs/container/pocket-gateway-server ## Docker Compose -There is an all-inclusive docker-compose file available for development [docker-compose.yml](docker-compose.yml) +There is an all-inclusive docker-compose file available for development [docker-compose.yml](docker-compose.yml.sample) ## Minimum Hardware Requirements to run - 1GB of RAM diff --git a/cmd/gateway_server/internal/config/dot_env_config_provider.go b/cmd/gateway_server/internal/config/dot_env_config_provider.go index cba89ca..273bcec 100644 --- a/cmd/gateway_server/internal/config/dot_env_config_provider.go +++ b/cmd/gateway_server/internal/config/dot_env_config_provider.go @@ -87,45 +87,47 @@ func (c DotEnvGlobalConfigProvider) GetAltruistRequestTimeout() time.Duration { func NewDotEnvConfigProvider() *DotEnvGlobalConfigProvider { _ = godotenv.Load() - poktRPCTimeout, err := time.ParseDuration(getEnvVar(poktRPCTimeoutEnv)) + poktRPCTimeout, err := time.ParseDuration(getEnvVar(poktRPCTimeoutEnv, "")) if err != nil { panic(fmt.Sprintf("Error parsing %s: %s", poktRPCTimeoutEnv, err)) } - httpServerPort, err := strconv.ParseUint(getEnvVar(httpServerPortEnv), 10, 64) + httpServerPort, err := strconv.ParseUint(getEnvVar(httpServerPortEnv, ""), 10, 64) if err != nil { panic(fmt.Sprintf("Error parsing %s: %s", httpServerPortEnv, err)) } - sessionCacheTTLDuration, err := time.ParseDuration(getEnvVar(sessionCacheTTLEnv)) + sessionCacheTTLDuration, err := time.ParseDuration(getEnvVar(sessionCacheTTLEnv, "")) if err != nil { panic(fmt.Sprintf("Error parsing %s: %s", sessionCacheTTLDuration, err)) } - altruistRequestTimeoutDuration, err := time.ParseDuration(getEnvVar(altruistRequestTimeoutEnv)) + altruistRequestTimeoutDuration, err := time.ParseDuration(getEnvVar(altruistRequestTimeoutEnv, defaultAltruistRequestTimeout.String())) if err != nil { // Provide a default to prevent any breaking changes with new env variable. altruistRequestTimeoutDuration = defaultAltruistRequestTimeout } return &DotEnvGlobalConfigProvider{ - poktRPCFullHost: getEnvVar(poktRPCFullHostEnv), + poktRPCFullHost: getEnvVar(poktRPCFullHostEnv, ""), httpServerPort: uint(httpServerPort), poktRPCRequestTimeout: poktRPCTimeout, sessionCacheTTL: sessionCacheTTLDuration, - databaseConnectionUrl: getEnvVar(dbConnectionUrlEnv), - environmentStage: global_config.EnvironmentStage(getEnvVar(environmentStageEnv)), - poktApplicationsEncryptionKey: getEnvVar(poktApplicationsEncryptionKeyEnv), - apiKey: getEnvVar(apiKey), + databaseConnectionUrl: getEnvVar(dbConnectionUrlEnv, ""), + environmentStage: global_config.EnvironmentStage(getEnvVar(environmentStageEnv, "")), + poktApplicationsEncryptionKey: getEnvVar(poktApplicationsEncryptionKeyEnv, ""), + apiKey: getEnvVar(apiKey, ""), altruistRequestTimeout: altruistRequestTimeoutDuration, } } // getEnvVar retrieves the value of the environment variable with error handling. -func getEnvVar(name string) string { - value, exists := os.LookupEnv(name) - if !exists { - panic(fmt.Errorf("%s not set", name)) +func getEnvVar(name string, defaultValue string) string { + if value, exists := os.LookupEnv(name); exists { + return value } - return value + if defaultValue != "" { + return defaultValue + } + panic(fmt.Errorf("%s not set", name)) } diff --git a/cmd/gateway_server/internal/models/qos_node.go b/cmd/gateway_server/internal/models/qos_node.go index 02f9df3..bc3d9aa 100644 --- a/cmd/gateway_server/internal/models/qos_node.go +++ b/cmd/gateway_server/internal/models/qos_node.go @@ -13,4 +13,5 @@ type PublicQosNode struct { IsHeathy bool `json:"is_heathy"` IsSynced bool `json:"is_synced"` LastKnownHeight uint64 `json:"last_known_height"` + P90Latency float64 `json:"p90_latency"` } diff --git a/cmd/gateway_server/internal/transform/qos_node.go b/cmd/gateway_server/internal/transform/qos_node.go index 19d26f4..499bc44 100644 --- a/cmd/gateway_server/internal/transform/qos_node.go +++ b/cmd/gateway_server/internal/transform/qos_node.go @@ -1,21 +1,27 @@ package transform import ( + "math" "pokt_gateway_server/cmd/gateway_server/internal/models" internal_model "pokt_gateway_server/internal/node_selector_service/models" ) func ToPublicQosNode(node *internal_model.QosNode) *models.PublicQosNode { + latency := node.LatencyTracker.GetP90Latency() + if math.IsNaN(latency) { + latency = 0.0 + } return &models.PublicQosNode{ ServiceUrl: node.MorseNode.ServiceUrl, Chain: node.GetChain(), - SessionHeight: node.PocketSession.SessionHeader.SessionHeight, - AppPublicKey: node.AppSigner.PublicKey, + SessionHeight: node.MorseSession.SessionHeader.SessionHeight, + AppPublicKey: node.MorseSigner.PublicKey, TimeoutReason: string(node.GetTimeoutReason()), LastKnownErr: node.GetLastKnownErrorStr(), IsHeathy: node.IsHealthy(), IsSynced: node.IsSynced(), LastKnownHeight: node.GetLastKnownHeight(), TimeoutUntil: node.GetTimeoutUntil(), + P90Latency: latency, } } diff --git a/cmd/gateway_server/main.go b/cmd/gateway_server/main.go index 8d377e3..762f910 100644 --- a/cmd/gateway_server/main.go +++ b/cmd/gateway_server/main.go @@ -59,8 +59,8 @@ func main() { ttlcache.WithTTL[string, *session_registry.Session](gatewayConfigProvider.GetSessionCacheTTL()), ) - nodeCache := ttlcache.New[string, []*qos_models.QosNode]( - ttlcache.WithTTL[string, []*qos_models.QosNode](gatewayConfigProvider.GetSessionCacheTTL()), + nodeCache := ttlcache.New[qos_models.SessionChainKey, []*qos_models.QosNode]( + ttlcache.WithTTL[qos_models.SessionChainKey, []*qos_models.QosNode](gatewayConfigProvider.GetSessionCacheTTL()), ) poktApplicationRegistry := apps_registry.NewCachedAppsRegistry(client, querier, gatewayConfigProvider, logger.Named("pokt_application_registry")) diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index ddd86e3..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,33 +0,0 @@ -version: '3' - -services: - gateway-server: - build: . - volumes: - - .env:/app/.env - ports: - - "${HTTP_SERVER_PORT}:${HTTP_SERVER_PORT}" - env_file: - - ./.env - networks: - - bridged_network - - postgres: - image: postgres:latest - environment: - POSTGRES_DB: mydatabase - POSTGRES_USER: myuser - POSTGRES_PASSWORD: mypassword - ports: - - "5433:5432" - volumes: - - postgres_data:/var/lib/postgresql/data - networks: - - bridged_network - -volumes: - postgres_data: - -networks: - bridged_network: - driver: bridge \ No newline at end of file diff --git a/docker-compose.yml.sample b/docker-compose.yml.sample new file mode 100644 index 0000000..766939b --- /dev/null +++ b/docker-compose.yml.sample @@ -0,0 +1,42 @@ +version: '3' + +services: + gateway-server: + build: . + volumes: + - .env:/app/.env + ports: + - "${HTTP_SERVER_PORT}:${HTTP_SERVER_PORT}" + env_file: + - ./.env + networks: + - bridged_network +# depends_on: +# - postgres + restart: on-failure + logging: + driver: json-file + options: + max-size: 10m + +# this postgres database is only to be used for testing. It should not be used in production systems +# Leverage a production ready postgres database with HA/replicas in prod. +# postgres: +# image: postgres:latest +# environment: +# POSTGRES_DB: postgres +# POSTGRES_USER: myuser +# POSTGRES_PASSWORD: mypassword +# ports: +# - "5433:5432" +# volumes: +# - postgres_data:/var/lib/postgresql/data +# networks: +# - bridged_network + +volumes: + postgres_data: + +networks: + bridged_network: + driver: bridge \ No newline at end of file diff --git a/go.mod b/go.mod index af04e59..14fd22a 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,7 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/influxdata/tdigest v0.0.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect diff --git a/go.sum b/go.sum index 55989ca..ac58a58 100644 --- a/go.sum +++ b/go.sum @@ -46,6 +46,7 @@ github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgj github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -55,6 +56,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY= +github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -227,6 +230,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -279,6 +283,7 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -297,8 +302,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ= gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= diff --git a/internal/node_selector_service/checks/async_relay_handler.go b/internal/node_selector_service/checks/async_relay_handler.go index 3b72b6a..6772122 100644 --- a/internal/node_selector_service/checks/async_relay_handler.go +++ b/internal/node_selector_service/checks/async_relay_handler.go @@ -26,7 +26,7 @@ func SendRelaysAsync(relayer pokt_v0.PocketRelayer, nodes []*models.QosNode, pay Payload: &relayer_models.Payload{Data: payload, Method: method}, Chain: node.GetChain(), SelectedNodePubKey: node.GetPublicKey(), - Session: node.PocketSession, + Session: node.MorseSession, }) relayResponses <- &nodeRelayResponse{ Node: node, diff --git a/internal/node_selector_service/checks/error_handler.go b/internal/node_selector_service/checks/error_handler.go index c6ba4ac..cf0645e 100644 --- a/internal/node_selector_service/checks/error_handler.go +++ b/internal/node_selector_service/checks/error_handler.go @@ -15,18 +15,23 @@ const timeoutErrorPenalty = time.Second * 15 // 24 hours is analogous to indefinite const kickOutSessionPenalty = time.Hour * 24 -const ( - errPocketInvalidServicerMsg = "failed to find correct servicer PK" - errPocketInvalidBlockHeightMsg = "the block height passed is invalid" - errPocketRequestTimeoutMsg = "request timeout" - errPocketOverServiceMsg = "the max number of relays serviced for this node is exceeded" - errPocketMaximumEvidenceSealedMsg = "the evidence is sealed, either max relays reached or claim already submitted" +var ( + errsKickSession = []string{"failed to find correct servicer PK", "the max number of relays serviced for this node is exceeded", "the evidence is sealed, either max relays reached or claim already submitted"} + errsTimeout = []string{"connection refused", "the request block height is out of sync with the current block height", "no route to host", "unexpected EOF", "i/o timeout", "tls: failed to verify certificate", "no such host", "the block height passed is invalid", "request timeout"} ) -const ( - errHttpSSLExpired = "tls: failed to verify certificate" - errHttpNoSuchHostMsg = "no such host" -) +func doesErrorContains(errsSubString []string, err error) bool { + if err == nil { + return false + } + errStr := err.Error() + for _, errSubString := range errsSubString { + if strings.Contains(errStr, errSubString) { + return true + } + } + return false +} // isKickableSessionErr - determines if a node should be kicked from a session to send relays func isKickableSessionErr(err error) bool { @@ -36,10 +41,7 @@ func isKickableSessionErr(err error) bool { } // Fallback in the event the error is not parsed correctly due to node operator configurations / custom clients, resort to a simple string check // node runner cannot serve with expired ssl - if err != nil && (strings.Contains(err.Error(), errHttpSSLExpired) || strings.Contains(err.Error(), errPocketOverServiceMsg) || strings.Contains(err.Error(), errPocketMaximumEvidenceSealedMsg) || strings.Contains(err.Error(), errPocketInvalidServicerMsg)) { - return true - } - return false + return doesErrorContains(errsKickSession, err) } func isTimeoutError(err error) bool { @@ -47,12 +49,14 @@ func isTimeoutError(err error) bool { if err == relayer_models.ErrPocketCoreInvalidBlockHeight { return true } + + // Check if pocket error returns 500 pocketError, ok := err.(relayer_models.PocketRPCError) - if ok { - return pocketError.HttpCode >= 500 + if ok && pocketError.HttpCode >= 500 { + return true } // Fallback in the event the error is not parsed correctly due to node operator configurations / custom clients, resort to a simple string check - return err == fasthttp.ErrTimeout || err == fasthttp.ErrDialTimeout || err == fasthttp.ErrTLSHandshakeTimeout || err != nil && (strings.Contains(err.Error(), errHttpNoSuchHostMsg) || strings.Contains(err.Error(), errPocketRequestTimeoutMsg) || strings.Contains(err.Error(), errPocketInvalidBlockHeightMsg)) + return err == fasthttp.ErrConnectionClosed || err == fasthttp.ErrTimeout || err == fasthttp.ErrDialTimeout || err == fasthttp.ErrTLSHandshakeTimeout || doesErrorContains(errsTimeout, err) } // DefaultPunishNode generic punisher for whenever a node returns an error independent of a specific check diff --git a/internal/node_selector_service/models/qos_node.go b/internal/node_selector_service/models/qos_node.go index 9951201..e83fa5d 100644 --- a/internal/node_selector_service/models/qos_node.go +++ b/internal/node_selector_service/models/qos_node.go @@ -1,7 +1,9 @@ package models import ( + "github.com/influxdata/tdigest" "pokt_gateway_server/pkg/pokt/pokt_v0/models" + "sync" "time" ) @@ -9,6 +11,9 @@ type TimeoutReason string const ( maxErrorStr int = 100 + // we use TDigest to quickly calculate percentile while conserving memory by using TDigest and its compression properties. + // Higher compression is more accuracy + latencyCompression = 1000 ) const ( @@ -22,12 +27,38 @@ const ( NodeResponseTimeout TimeoutReason = "node_response_timeout" ) +type LatencyTracker struct { + tDigest *tdigest.TDigest + lock sync.RWMutex +} + +func (l *LatencyTracker) RecordMeasurement(time float64) { + l.lock.Lock() + defer l.lock.Unlock() + l.tDigest.Add(time, 1) +} + +func (l *LatencyTracker) GetMeasurementCount() float64 { + l.lock.RLock() + defer l.lock.RUnlock() + return l.tDigest.Count() +} + +func (l *LatencyTracker) GetP90Latency() float64 { + return l.tDigest.Quantile(.90) +} + +type SessionChainKey struct { + SessionHeight uint `json:"session_height"` + Chain string `json:"chain"` +} + // QosNode a FAT model to store the QoS information of a specific node in a session. type QosNode struct { MorseNode *models.Node - PocketSession *models.Session - AppSigner *models.Ed25519Account - p90Latency float64 + MorseSession *models.Session + MorseSigner *models.Ed25519Account + LatencyTracker *LatencyTracker timeoutUntil time.Time timeoutReason TimeoutReason lastDataIntegrityCheckTime time.Time @@ -37,6 +68,10 @@ type QosNode struct { lastHeightCheckTime time.Time } +func NewQosNode(morseNode *models.Node, pocketSession *models.Session, appSigner *models.Ed25519Account) *QosNode { + return &QosNode{MorseNode: morseNode, MorseSession: pocketSession, MorseSigner: appSigner, LatencyTracker: &LatencyTracker{tDigest: tdigest.NewWithCompression(1000)}} +} + func (n *QosNode) IsHealthy() bool { return !n.isInTimeout() && n.IsSynced() } @@ -76,7 +111,7 @@ func (n *QosNode) GetLastKnownHeight() uint64 { } func (n *QosNode) GetChain() string { - return n.PocketSession.SessionHeader.Chain + return n.MorseSession.SessionHeader.Chain } func (n *QosNode) GetPublicKey() string { @@ -84,7 +119,7 @@ func (n *QosNode) GetPublicKey() string { } func (n *QosNode) GetAppStakeSigner() *models.Ed25519Account { - return n.AppSigner + return n.MorseSigner } func (n *QosNode) GetLastDataIntegrityCheckTime() time.Time { @@ -121,3 +156,7 @@ func (n *QosNode) GetLastKnownErrorStr() string { func (n *QosNode) GetTimeoutUntil() time.Time { return n.timeoutUntil } + +func (n *QosNode) GetLatencyTracker() *LatencyTracker { + return n.LatencyTracker +} diff --git a/internal/node_selector_service/node_selector_service.go b/internal/node_selector_service/node_selector_service.go index 2aad65a..0d3f877 100644 --- a/internal/node_selector_service/node_selector_service.go +++ b/internal/node_selector_service/node_selector_service.go @@ -50,8 +50,8 @@ func NewNodeSelectorService(sessionRegistry session_registry.SessionRegistryServ func (q NodeSelectorClient) FindNode(chainId string) (*models.QosNode, bool) { - nodes, ok := q.sessionRegistry.GetNodesByChain(chainId) - if !ok { + nodes := q.sessionRegistry.GetNodesByChain(chainId) + if len(nodes) == 0 { return nil, false } @@ -69,12 +69,14 @@ func (q NodeSelectorClient) FindNode(chainId string) (*models.QosNode, bool) { return nil, false } +// filterBySessionHeightNodes - filter by session height descending. This allows node selector to send relays with +// latest session height which nodes are more likely to serve vs session rollover relays. func filterBySessionHeightNodes(nodes []*models.QosNode) ([]uint, map[uint][]*models.QosNode) { nodesBySessionHeight := map[uint][]*models.QosNode{} // Create map to retrieve nodes by session height for _, r := range nodes { - sessionHeight := r.PocketSession.SessionHeader.SessionHeight + sessionHeight := r.MorseSession.SessionHeader.SessionHeight nodesBySessionHeight[sessionHeight] = append(nodesBySessionHeight[sessionHeight], r) } @@ -91,6 +93,7 @@ func filterBySessionHeightNodes(nodes []*models.QosNode) ([]uint, map[uint][]*mo return sortedSessionHeights, nodesBySessionHeight } + func filterByHealthyNodes(nodes []*models.QosNode) []*models.QosNode { var healthyNodes []*models.QosNode @@ -110,8 +113,8 @@ func (q NodeSelectorClient) startJobChecker() { case <-ticker: for _, job := range q.checkJobs { if job.ShouldRun() { - for chain, nodes := range q.sessionRegistry.GetNodesMap() { - q.logger.Sugar().Infow("running job", "job", job.Name(), "chain", chain) + for sessionChainKey, nodes := range q.sessionRegistry.GetNodesMap() { + q.logger.Sugar().Infow("running job", "job", job.Name(), "sessionChainKey", sessionChainKey) job.SetNodes(nodes.Value()) job.Perform() } diff --git a/internal/relayer/relayer.go b/internal/relayer/relayer.go index c5497d5..2d3bf48 100644 --- a/internal/relayer/relayer.go +++ b/internal/relayer/relayer.go @@ -109,19 +109,20 @@ func (r *Relayer) sendNodeSelectorRelay(req *models.SendRelayRequest) (*models.S if !ok { return nil, errSelectNodeFail } - req.Signer = node.AppSigner - req.Session = node.PocketSession + req.Signer = node.MorseSigner + req.Session = node.MorseSession req.SelectedNodePubKey = node.GetPublicKey() if err := req.Validate(); err != nil { return nil, err } - rsp, err := r.pocketClient.SendRelay(req) + start := time.Now() + rsp, err := r.pocketClient.SendRelay(req) + node.GetLatencyTracker().RecordMeasurement(float64(time.Now().Sub(start).Milliseconds())) // Node returned an error, potentially penalize the node operator dependent on error if err != nil { checks.DefaultPunishNode(err, node, r.logger) } - return rsp, err } @@ -155,7 +156,7 @@ func (r *Relayer) sendRandomNodeRelay(req *models.SendRelayRequest) (*models.Sen requestTimeout := r.getPocketRequestTimeout(req.Chain) // populate request with session metadata - req.Session = randomNode.PocketSession + req.Session = randomNode.MorseSession req.Signer = appStake.Signer req.Timeout = &requestTimeout req.SelectedNodePubKey = randomNode.GetPublicKey() diff --git a/internal/relayer/relayer_test.go b/internal/relayer/relayer_test.go index 3bd6fbc..cd91350 100644 --- a/internal/relayer/relayer_test.go +++ b/internal/relayer/relayer_test.go @@ -74,11 +74,7 @@ func (suite *RelayerTestSuite) TestNodeSelectorRelay() { signer := &models.Ed25519Account{} node := &models.Node{PublicKey: "123"} session := &models.Session{} - suite.mockNodeSelectorService.EXPECT().FindNode("1234").Return(&qos_models.QosNode{ - AppSigner: signer, - MorseNode: node, - PocketSession: session, - }, true) + suite.mockNodeSelectorService.EXPECT().FindNode("1234").Return(qos_models.NewQosNode(node, session, signer), true) // expect sendRelay to have same parameters as find node, otherwise validation will fail suite.mockPocketService.EXPECT().SendRelay(&models.SendRelayRequest{ Payload: request.Payload, diff --git a/internal/session_registry/cached_session_registry_service.go b/internal/session_registry/cached_session_registry_service.go index f8c1a56..a70bfbc 100644 --- a/internal/session_registry/cached_session_registry_service.go +++ b/internal/session_registry/cached_session_registry_service.go @@ -26,6 +26,7 @@ var ( const ( blocksPerSession = 4 sessionPrimerInterval = time.Second * 5 + ttlCacheCleanerInterval = time.Second * 15 reasonSessionSuccessCached = "session_cached" reasonSessionSuccessColdHit = "session_cold_hit" reasonSessionFailedBackoff = "session_failed_backoff" @@ -61,42 +62,56 @@ type CachedSessionRegistryService struct { concurrentDispatchPool chan struct{} logger *zap.Logger lastPrimedSessionHeight uint - // Lock used to synchronize inserting sessions and append sessions nodes. sessionCacheLock sync.RWMutex // Consist of sessions for a given app stake+chain+height. Cache exists to prevent round trip request sessionCache ttl_cache.TTLCacheService[string, *Session] // Cache that contains all nodes by chain (chainId -> Nodes) - chainNodes ttl_cache.TTLCacheService[string, []*qos_models.QosNode] // sessionHeight -> nodes + chainNodes ttl_cache.TTLCacheService[qos_models.SessionChainKey, []*qos_models.QosNode] // sessionHeight -> nodes } -func NewCachedSessionRegistryService(poktClient pokt_v0.PocketService, appRegistry apps_registry.AppsRegistryService, sessionCache ttl_cache.TTLCacheService[string, *Session], nodeCache ttl_cache.TTLCacheService[string, []*qos_models.QosNode], logger *zap.Logger) *CachedSessionRegistryService { +func NewCachedSessionRegistryService(poktClient pokt_v0.PocketService, appRegistry apps_registry.AppsRegistryService, sessionCache ttl_cache.TTLCacheService[string, *Session], nodeCache ttl_cache.TTLCacheService[qos_models.SessionChainKey, []*qos_models.QosNode], logger *zap.Logger) *CachedSessionRegistryService { cachedRegistry := &CachedSessionRegistryService{poktClient: poktClient, appRegistry: appRegistry, sessionCache: sessionCache, lastFailure: time.Time{}, concurrentDispatchPool: make(chan struct{}, maxConcurrentDispatch), chainNodes: nodeCache, logger: logger} go sessionCache.Start() go nodeCache.Start() + cachedRegistry.startTTLCacheCleaner() cachedRegistry.startSessionUpdater() return cachedRegistry } -func (c *CachedSessionRegistryService) GetNodesByChain(chainId string) ([]*qos_models.QosNode, bool) { - c.sessionCacheLock.RLock() - defer c.sessionCacheLock.RUnlock() - nodes := c.chainNodes.Get(chainId) - if nodes == nil { - return nil, false +func (c *CachedSessionRegistryService) startTTLCacheCleaner() { + ticker := time.Tick(ttlCacheCleanerInterval) + go func() { + for { + select { + case <-ticker: + c.sessionCache.DeleteExpired() + c.chainNodes.DeleteExpired() + } + } + }() +} + +func (c *CachedSessionRegistryService) GetNodesByChain(chainId string) []*qos_models.QosNode { + items := c.GetNodesMap() + nodes := []*qos_models.QosNode{} + for sessionKey, item := range items { + if sessionKey.Chain == chainId { + nodes = append(nodes, item.Value()...) + } } - return nodes.Value(), true + return nodes } -func (c *CachedSessionRegistryService) GetNodesMap() map[string]*ttlcache.Item[string, []*qos_models.QosNode] { +func (c *CachedSessionRegistryService) GetNodesMap() map[qos_models.SessionChainKey]*ttlcache.Item[qos_models.SessionChainKey, []*qos_models.QosNode] { c.sessionCacheLock.RLock() defer c.sessionCacheLock.RUnlock() return c.chainNodes.Items() } func (c *CachedSessionRegistryService) GetSession(req *models.GetSessionRequest) (*Session, error) { - cacheKey := getSessionCacheKey(req) - cachedSession := c.sessionCache.Get(cacheKey) + sessionCacheKey := getSessionCacheKey(req) + cachedSession := c.sessionCache.Get(sessionCacheKey) isCached := cachedSession != nil && cachedSession.Value() != nil startTime := time.Now() // Measure end to end latency for send relay @@ -138,11 +153,7 @@ func (c *CachedSessionRegistryService) GetSession(req *models.GetSessionRequest) wrappedNodes := []*qos_models.QosNode{} for _, a := range response.Session.Nodes { - wrappedNodes = append(wrappedNodes, &qos_models.QosNode{ - PocketSession: response.Session, - MorseNode: a, - AppSigner: appSigner.Signer, - }) + wrappedNodes = append(wrappedNodes, qos_models.NewQosNode(a, response.Session, appSigner.Signer)) } // session with metadata @@ -153,10 +164,10 @@ func (c *CachedSessionRegistryService) GetSession(req *models.GetSessionRequest) c.sessionCacheLock.Lock() defer c.sessionCacheLock.Unlock() // Update session cache - c.sessionCache.Set(cacheKey, wrappedSession, ttlcache.DefaultTTL) + c.sessionCache.Set(sessionCacheKey, wrappedSession, ttlcache.DefaultTTL) // Update node cache - chainNodeCacheKey := req.Chain + chainNodeCacheKey := qos_models.SessionChainKey{Chain: req.Chain, SessionHeight: wrappedSession.PocketSession.SessionHeader.SessionHeight} if !c.chainNodes.Has(chainNodeCacheKey) { // No values in session and chain cache c.chainNodes.Set(chainNodeCacheKey, wrappedNodes, ttlcache.DefaultTTL) @@ -225,15 +236,14 @@ func (c *CachedSessionRegistryService) primeSessions() error { defer wg.Done() // Goroutine unbounded req := &models.GetSessionRequest{ - AppPubKey: app.NetworkApp.PublicKey, - Chain: chain, - Height: latestSessionHeight, + AppPubKey: app.NetworkApp.PublicKey, + Chain: chain, + SessionHeight: latestSessionHeight, } - rsp, err := c.GetSession(req) - // Session returned nil, or the node returned another session instead of the one requested (dispatcher is not in sync or syncing up to latest height) - if err != nil || rsp.PocketSession.SessionHeader.SessionHeight != latestSessionHeight { + _, err := c.GetSession(req) + if err != nil { errCount.Add(1) - c.logger.Sugar().Warnw("primeSessions: failed to prime session", "req", req, "err", err, "dispatcherSessionHeight", rsp.PocketSession.SessionHeader.SessionHeight, "latestSessionHeight", latestSessionHeight) + c.logger.Sugar().Warnw("primeSessions: failed to prime session", "req", req, "err", err, "latestSessionHeight", latestSessionHeight) } else { successCount.Add(1) } @@ -269,5 +279,5 @@ func (c *CachedSessionRegistryService) shouldBackoffDispatchFailure() bool { // getSessionCacheKey - used to keep track of a session for a specific app stake, height, and chain. func getSessionCacheKey(req *models.GetSessionRequest) string { - return fmt.Sprintf("%s-%s-%d", req.AppPubKey, req.Chain, req.Height) + return fmt.Sprintf("%s-%s-%d", req.AppPubKey, req.Chain, req.SessionHeight) } diff --git a/internal/session_registry/session_registry_service.go b/internal/session_registry/session_registry_service.go index 781d1f3..5dbd062 100644 --- a/internal/session_registry/session_registry_service.go +++ b/internal/session_registry/session_registry_service.go @@ -14,6 +14,6 @@ type Session struct { type SessionRegistryService interface { GetSession(req *models.GetSessionRequest) (*Session, error) - GetNodesMap() map[string]*ttlcache.Item[string, []*qos_models.QosNode] - GetNodesByChain(chainId string) ([]*qos_models.QosNode, bool) + GetNodesMap() map[qos_models.SessionChainKey]*ttlcache.Item[qos_models.SessionChainKey, []*qos_models.QosNode] + GetNodesByChain(chainId string) []*qos_models.QosNode } diff --git a/mocks/session_registry/session_registry_mock.go b/mocks/session_registry/session_registry_mock.go index da54b45..943ccaf 100644 --- a/mocks/session_registry/session_registry_mock.go +++ b/mocks/session_registry/session_registry_mock.go @@ -27,7 +27,7 @@ func (_m *SessionRegistryService) EXPECT() *SessionRegistryService_Expecter { } // GetNodesByChain provides a mock function with given fields: chainId -func (_m *SessionRegistryService) GetNodesByChain(chainId string) ([]*models.QosNode, bool) { +func (_m *SessionRegistryService) GetNodesByChain(chainId string) []*models.QosNode { ret := _m.Called(chainId) if len(ret) == 0 { @@ -35,10 +35,6 @@ func (_m *SessionRegistryService) GetNodesByChain(chainId string) ([]*models.Qos } var r0 []*models.QosNode - var r1 bool - if rf, ok := ret.Get(0).(func(string) ([]*models.QosNode, bool)); ok { - return rf(chainId) - } if rf, ok := ret.Get(0).(func(string) []*models.QosNode); ok { r0 = rf(chainId) } else { @@ -47,13 +43,7 @@ func (_m *SessionRegistryService) GetNodesByChain(chainId string) ([]*models.Qos } } - if rf, ok := ret.Get(1).(func(string) bool); ok { - r1 = rf(chainId) - } else { - r1 = ret.Get(1).(bool) - } - - return r0, r1 + return r0 } // SessionRegistryService_GetNodesByChain_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetNodesByChain' @@ -74,30 +64,30 @@ func (_c *SessionRegistryService_GetNodesByChain_Call) Run(run func(chainId stri return _c } -func (_c *SessionRegistryService_GetNodesByChain_Call) Return(_a0 []*models.QosNode, _a1 bool) *SessionRegistryService_GetNodesByChain_Call { - _c.Call.Return(_a0, _a1) +func (_c *SessionRegistryService_GetNodesByChain_Call) Return(_a0 []*models.QosNode) *SessionRegistryService_GetNodesByChain_Call { + _c.Call.Return(_a0) return _c } -func (_c *SessionRegistryService_GetNodesByChain_Call) RunAndReturn(run func(string) ([]*models.QosNode, bool)) *SessionRegistryService_GetNodesByChain_Call { +func (_c *SessionRegistryService_GetNodesByChain_Call) RunAndReturn(run func(string) []*models.QosNode) *SessionRegistryService_GetNodesByChain_Call { _c.Call.Return(run) return _c } // GetNodesMap provides a mock function with given fields: -func (_m *SessionRegistryService) GetNodesMap() map[string]*ttlcache.Item[string, []*models.QosNode] { +func (_m *SessionRegistryService) GetNodesMap() map[models.SessionChainKey]*ttlcache.Item[models.SessionChainKey, []*models.QosNode] { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetNodesMap") } - var r0 map[string]*ttlcache.Item[string, []*models.QosNode] - if rf, ok := ret.Get(0).(func() map[string]*ttlcache.Item[string, []*models.QosNode]); ok { + var r0 map[models.SessionChainKey]*ttlcache.Item[models.SessionChainKey, []*models.QosNode] + if rf, ok := ret.Get(0).(func() map[models.SessionChainKey]*ttlcache.Item[models.SessionChainKey, []*models.QosNode]); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]*ttlcache.Item[string, []*models.QosNode]) + r0 = ret.Get(0).(map[models.SessionChainKey]*ttlcache.Item[models.SessionChainKey, []*models.QosNode]) } } @@ -121,12 +111,12 @@ func (_c *SessionRegistryService_GetNodesMap_Call) Run(run func()) *SessionRegis return _c } -func (_c *SessionRegistryService_GetNodesMap_Call) Return(_a0 map[string]*ttlcache.Item[string, []*models.QosNode]) *SessionRegistryService_GetNodesMap_Call { +func (_c *SessionRegistryService_GetNodesMap_Call) Return(_a0 map[models.SessionChainKey]*ttlcache.Item[models.SessionChainKey, []*models.QosNode]) *SessionRegistryService_GetNodesMap_Call { _c.Call.Return(_a0) return _c } -func (_c *SessionRegistryService_GetNodesMap_Call) RunAndReturn(run func() map[string]*ttlcache.Item[string, []*models.QosNode]) *SessionRegistryService_GetNodesMap_Call { +func (_c *SessionRegistryService_GetNodesMap_Call) RunAndReturn(run func() map[models.SessionChainKey]*ttlcache.Item[models.SessionChainKey, []*models.QosNode]) *SessionRegistryService_GetNodesMap_Call { _c.Call.Return(run) return _c } diff --git a/mocks/ttl_cache_service/ttl_cache_service_mock.go b/mocks/ttl_cache_service/ttl_cache_service_mock.go index 9490dab..9d0a441 100644 --- a/mocks/ttl_cache_service/ttl_cache_service_mock.go +++ b/mocks/ttl_cache_service/ttl_cache_service_mock.go @@ -86,6 +86,52 @@ func (_c *TTLCacheService_Get_Call[K, V]) RunAndReturn(run func(K, ...ttlcache.O return _c } +// Has provides a mock function with given fields: key +func (_m *TTLCacheService[K, V]) Has(key K) bool { + ret := _m.Called(key) + + if len(ret) == 0 { + panic("no return value specified for Has") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(K) bool); ok { + r0 = rf(key) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// TTLCacheService_Has_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Has' +type TTLCacheService_Has_Call[K comparable, V interface{}] struct { + *mock.Call +} + +// Has is a helper method to define mock.On call +// - key K +func (_e *TTLCacheService_Expecter[K, V]) Has(key interface{}) *TTLCacheService_Has_Call[K, V] { + return &TTLCacheService_Has_Call[K, V]{Call: _e.mock.On("Has", key)} +} + +func (_c *TTLCacheService_Has_Call[K, V]) Run(run func(key K)) *TTLCacheService_Has_Call[K, V] { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(K)) + }) + return _c +} + +func (_c *TTLCacheService_Has_Call[K, V]) Return(_a0 bool) *TTLCacheService_Has_Call[K, V] { + _c.Call.Return(_a0) + return _c +} + +func (_c *TTLCacheService_Has_Call[K, V]) RunAndReturn(run func(K) bool) *TTLCacheService_Has_Call[K, V] { + _c.Call.Return(run) + return _c +} + // Items provides a mock function with given fields: func (_m *TTLCacheService[K, V]) Items() map[K]*ttlcache.Item[K, V] { ret := _m.Called() diff --git a/pkg/pokt/pokt_v0/basic_client.go b/pkg/pokt/pokt_v0/basic_client.go index 33a39e7..2426385 100644 --- a/pkg/pokt/pokt_v0/basic_client.go +++ b/pkg/pokt/pokt_v0/basic_client.go @@ -58,6 +58,13 @@ func (r BasicClient) GetSession(req *models.GetSessionRequest) (*models.GetSessi if err != nil { return nil, err } + + // The current POKT Node implementation returns the latest session height instead of what was requested. + // This can result in undesired functionality without explicit error handling (such as caching sesions, as the wrong session could become cahed) + if req.SessionHeight != 0 && sessionResponse.Session.SessionHeader.SessionHeight != req.SessionHeight { + return nil, errors.New("GetSession: failed, dispatcher returned a different session than what was requested") + } + return &sessionResponse, nil } diff --git a/pkg/pokt/pokt_v0/models/relay.go b/pkg/pokt/pokt_v0/models/relay.go index d63fa9c..40b497e 100644 --- a/pkg/pokt/pokt_v0/models/relay.go +++ b/pkg/pokt/pokt_v0/models/relay.go @@ -55,6 +55,7 @@ type RelayProof struct { } // RequestHashPayload struct holding data needed to create a request hash +// ffjson: skip type RequestHashPayload struct { Payload *Payload `json:"payload"` Metadata *RelayMeta `json:"meta"` @@ -64,6 +65,7 @@ func (a *RequestHashPayload) Hash() string { return common.Sha3_256HashHex(a) } +// ffjson: skip type RelayProofHashPayload struct { Entropy uint64 `json:"entropy"` SessionBlockHeight uint `json:"session_block_height"` diff --git a/pkg/pokt/pokt_v0/models/relay_ffjson.go b/pkg/pokt/pokt_v0/models/relay_ffjson.go index 843fb16..5714f15 100644 --- a/pkg/pokt/pokt_v0/models/relay_ffjson.go +++ b/pkg/pokt/pokt_v0/models/relay_ffjson.go @@ -8,6 +8,7 @@ import ( "encoding/json" "fmt" fflib "github.com/pquerna/ffjson/fflib/v1" + "time" ) // MarshalJSON marshal bytes to json - template @@ -1466,763 +1467,6 @@ done: return nil } -// MarshalJSON marshal bytes to json - template -func (j *RelayProofHashPayload) MarshalJSON() ([]byte, error) { - var buf fflib.Buffer - if j == nil { - buf.WriteString("null") - return buf.Bytes(), nil - } - err := j.MarshalJSONBuf(&buf) - if err != nil { - return nil, err - } - return buf.Bytes(), nil -} - -// MarshalJSONBuf marshal buff to json - template -func (j *RelayProofHashPayload) MarshalJSONBuf(buf fflib.EncodingBuffer) error { - if j == nil { - buf.WriteString("null") - return nil - } - var err error - var obj []byte - _ = obj - _ = err - buf.WriteString(`{"entropy":`) - fflib.FormatBits2(buf, uint64(j.Entropy), 10, false) - buf.WriteString(`,"session_block_height":`) - fflib.FormatBits2(buf, uint64(j.SessionBlockHeight), 10, false) - buf.WriteString(`,"servicer_pub_key":`) - fflib.WriteJsonString(buf, string(j.ServicerPubKey)) - buf.WriteString(`,"blockchain":`) - fflib.WriteJsonString(buf, string(j.Blockchain)) - buf.WriteString(`,"signature":`) - fflib.WriteJsonString(buf, string(j.Signature)) - buf.WriteString(`,"token":`) - fflib.WriteJsonString(buf, string(j.UnsignedAAT)) - buf.WriteString(`,"request_hash":`) - fflib.WriteJsonString(buf, string(j.RequestHash)) - buf.WriteByte('}') - return nil -} - -const ( - ffjtRelayProofHashPayloadbase = iota - ffjtRelayProofHashPayloadnosuchkey - - ffjtRelayProofHashPayloadEntropy - - ffjtRelayProofHashPayloadSessionBlockHeight - - ffjtRelayProofHashPayloadServicerPubKey - - ffjtRelayProofHashPayloadBlockchain - - ffjtRelayProofHashPayloadSignature - - ffjtRelayProofHashPayloadUnsignedAAT - - ffjtRelayProofHashPayloadRequestHash -) - -var ffjKeyRelayProofHashPayloadEntropy = []byte("entropy") - -var ffjKeyRelayProofHashPayloadSessionBlockHeight = []byte("session_block_height") - -var ffjKeyRelayProofHashPayloadServicerPubKey = []byte("servicer_pub_key") - -var ffjKeyRelayProofHashPayloadBlockchain = []byte("blockchain") - -var ffjKeyRelayProofHashPayloadSignature = []byte("signature") - -var ffjKeyRelayProofHashPayloadUnsignedAAT = []byte("token") - -var ffjKeyRelayProofHashPayloadRequestHash = []byte("request_hash") - -// UnmarshalJSON umarshall json - template of ffjson -func (j *RelayProofHashPayload) UnmarshalJSON(input []byte) error { - fs := fflib.NewFFLexer(input) - return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start) -} - -// UnmarshalJSONFFLexer fast json unmarshall - template ffjson -func (j *RelayProofHashPayload) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error { - var err error - currentKey := ffjtRelayProofHashPayloadbase - _ = currentKey - tok := fflib.FFTok_init - wantedTok := fflib.FFTok_init - -mainparse: - for { - tok = fs.Scan() - // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state)) - if tok == fflib.FFTok_error { - goto tokerror - } - - switch state { - - case fflib.FFParse_map_start: - if tok != fflib.FFTok_left_bracket { - wantedTok = fflib.FFTok_left_bracket - goto wrongtokenerror - } - state = fflib.FFParse_want_key - continue - - case fflib.FFParse_after_value: - if tok == fflib.FFTok_comma { - state = fflib.FFParse_want_key - } else if tok == fflib.FFTok_right_bracket { - goto done - } else { - wantedTok = fflib.FFTok_comma - goto wrongtokenerror - } - - case fflib.FFParse_want_key: - // json {} ended. goto exit. woo. - if tok == fflib.FFTok_right_bracket { - goto done - } - if tok != fflib.FFTok_string { - wantedTok = fflib.FFTok_string - goto wrongtokenerror - } - - kn := fs.Output.Bytes() - if len(kn) <= 0 { - // "" case. hrm. - currentKey = ffjtRelayProofHashPayloadnosuchkey - state = fflib.FFParse_want_colon - goto mainparse - } else { - switch kn[0] { - - case 'b': - - if bytes.Equal(ffjKeyRelayProofHashPayloadBlockchain, kn) { - currentKey = ffjtRelayProofHashPayloadBlockchain - state = fflib.FFParse_want_colon - goto mainparse - } - - case 'e': - - if bytes.Equal(ffjKeyRelayProofHashPayloadEntropy, kn) { - currentKey = ffjtRelayProofHashPayloadEntropy - state = fflib.FFParse_want_colon - goto mainparse - } - - case 'r': - - if bytes.Equal(ffjKeyRelayProofHashPayloadRequestHash, kn) { - currentKey = ffjtRelayProofHashPayloadRequestHash - state = fflib.FFParse_want_colon - goto mainparse - } - - case 's': - - if bytes.Equal(ffjKeyRelayProofHashPayloadSessionBlockHeight, kn) { - currentKey = ffjtRelayProofHashPayloadSessionBlockHeight - state = fflib.FFParse_want_colon - goto mainparse - - } else if bytes.Equal(ffjKeyRelayProofHashPayloadServicerPubKey, kn) { - currentKey = ffjtRelayProofHashPayloadServicerPubKey - state = fflib.FFParse_want_colon - goto mainparse - - } else if bytes.Equal(ffjKeyRelayProofHashPayloadSignature, kn) { - currentKey = ffjtRelayProofHashPayloadSignature - state = fflib.FFParse_want_colon - goto mainparse - } - - case 't': - - if bytes.Equal(ffjKeyRelayProofHashPayloadUnsignedAAT, kn) { - currentKey = ffjtRelayProofHashPayloadUnsignedAAT - state = fflib.FFParse_want_colon - goto mainparse - } - - } - - if fflib.EqualFoldRight(ffjKeyRelayProofHashPayloadRequestHash, kn) { - currentKey = ffjtRelayProofHashPayloadRequestHash - state = fflib.FFParse_want_colon - goto mainparse - } - - if fflib.EqualFoldRight(ffjKeyRelayProofHashPayloadUnsignedAAT, kn) { - currentKey = ffjtRelayProofHashPayloadUnsignedAAT - state = fflib.FFParse_want_colon - goto mainparse - } - - if fflib.EqualFoldRight(ffjKeyRelayProofHashPayloadSignature, kn) { - currentKey = ffjtRelayProofHashPayloadSignature - state = fflib.FFParse_want_colon - goto mainparse - } - - if fflib.EqualFoldRight(ffjKeyRelayProofHashPayloadBlockchain, kn) { - currentKey = ffjtRelayProofHashPayloadBlockchain - state = fflib.FFParse_want_colon - goto mainparse - } - - if fflib.EqualFoldRight(ffjKeyRelayProofHashPayloadServicerPubKey, kn) { - currentKey = ffjtRelayProofHashPayloadServicerPubKey - state = fflib.FFParse_want_colon - goto mainparse - } - - if fflib.EqualFoldRight(ffjKeyRelayProofHashPayloadSessionBlockHeight, kn) { - currentKey = ffjtRelayProofHashPayloadSessionBlockHeight - state = fflib.FFParse_want_colon - goto mainparse - } - - if fflib.SimpleLetterEqualFold(ffjKeyRelayProofHashPayloadEntropy, kn) { - currentKey = ffjtRelayProofHashPayloadEntropy - state = fflib.FFParse_want_colon - goto mainparse - } - - currentKey = ffjtRelayProofHashPayloadnosuchkey - state = fflib.FFParse_want_colon - goto mainparse - } - - case fflib.FFParse_want_colon: - if tok != fflib.FFTok_colon { - wantedTok = fflib.FFTok_colon - goto wrongtokenerror - } - state = fflib.FFParse_want_value - continue - case fflib.FFParse_want_value: - - if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null { - switch currentKey { - - case ffjtRelayProofHashPayloadEntropy: - goto handle_Entropy - - case ffjtRelayProofHashPayloadSessionBlockHeight: - goto handle_SessionBlockHeight - - case ffjtRelayProofHashPayloadServicerPubKey: - goto handle_ServicerPubKey - - case ffjtRelayProofHashPayloadBlockchain: - goto handle_Blockchain - - case ffjtRelayProofHashPayloadSignature: - goto handle_Signature - - case ffjtRelayProofHashPayloadUnsignedAAT: - goto handle_UnsignedAAT - - case ffjtRelayProofHashPayloadRequestHash: - goto handle_RequestHash - - case ffjtRelayProofHashPayloadnosuchkey: - err = fs.SkipField(tok) - if err != nil { - return fs.WrapErr(err) - } - state = fflib.FFParse_after_value - goto mainparse - } - } else { - goto wantedvalue - } - } - } - -handle_Entropy: - - /* handler: j.Entropy type=uint64 kind=uint64 quoted=false*/ - - { - if tok != fflib.FFTok_integer && tok != fflib.FFTok_null { - return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for uint64", tok)) - } - } - - { - - if tok == fflib.FFTok_null { - - } else { - - tval, err := fflib.ParseUint(fs.Output.Bytes(), 10, 64) - - if err != nil { - return fs.WrapErr(err) - } - - j.Entropy = uint64(tval) - - } - } - - state = fflib.FFParse_after_value - goto mainparse - -handle_SessionBlockHeight: - - /* handler: j.SessionBlockHeight type=uint kind=uint quoted=false*/ - - { - if tok != fflib.FFTok_integer && tok != fflib.FFTok_null { - return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for uint", tok)) - } - } - - { - - if tok == fflib.FFTok_null { - - } else { - - tval, err := fflib.ParseUint(fs.Output.Bytes(), 10, 64) - - if err != nil { - return fs.WrapErr(err) - } - - j.SessionBlockHeight = uint(tval) - - } - } - - state = fflib.FFParse_after_value - goto mainparse - -handle_ServicerPubKey: - - /* handler: j.ServicerPubKey type=string kind=string quoted=false*/ - - { - - { - if tok != fflib.FFTok_string && tok != fflib.FFTok_null { - return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) - } - } - - if tok == fflib.FFTok_null { - - } else { - - outBuf := fs.Output.Bytes() - - j.ServicerPubKey = string(string(outBuf)) - - } - } - - state = fflib.FFParse_after_value - goto mainparse - -handle_Blockchain: - - /* handler: j.Blockchain type=string kind=string quoted=false*/ - - { - - { - if tok != fflib.FFTok_string && tok != fflib.FFTok_null { - return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) - } - } - - if tok == fflib.FFTok_null { - - } else { - - outBuf := fs.Output.Bytes() - - j.Blockchain = string(string(outBuf)) - - } - } - - state = fflib.FFParse_after_value - goto mainparse - -handle_Signature: - - /* handler: j.Signature type=string kind=string quoted=false*/ - - { - - { - if tok != fflib.FFTok_string && tok != fflib.FFTok_null { - return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) - } - } - - if tok == fflib.FFTok_null { - - } else { - - outBuf := fs.Output.Bytes() - - j.Signature = string(string(outBuf)) - - } - } - - state = fflib.FFParse_after_value - goto mainparse - -handle_UnsignedAAT: - - /* handler: j.UnsignedAAT type=string kind=string quoted=false*/ - - { - - { - if tok != fflib.FFTok_string && tok != fflib.FFTok_null { - return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) - } - } - - if tok == fflib.FFTok_null { - - } else { - - outBuf := fs.Output.Bytes() - - j.UnsignedAAT = string(string(outBuf)) - - } - } - - state = fflib.FFParse_after_value - goto mainparse - -handle_RequestHash: - - /* handler: j.RequestHash type=string kind=string quoted=false*/ - - { - - { - if tok != fflib.FFTok_string && tok != fflib.FFTok_null { - return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok)) - } - } - - if tok == fflib.FFTok_null { - - } else { - - outBuf := fs.Output.Bytes() - - j.RequestHash = string(string(outBuf)) - - } - } - - state = fflib.FFParse_after_value - goto mainparse - -wantedvalue: - return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok)) -wrongtokenerror: - return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String())) -tokerror: - if fs.BigError != nil { - return fs.WrapErr(fs.BigError) - } - err = fs.Error.ToError() - if err != nil { - return fs.WrapErr(err) - } - panic("ffjson-generated: unreachable, please report bug.") -done: - - return nil -} - -// MarshalJSON marshal bytes to json - template -func (j *RequestHashPayload) MarshalJSON() ([]byte, error) { - var buf fflib.Buffer - if j == nil { - buf.WriteString("null") - return buf.Bytes(), nil - } - err := j.MarshalJSONBuf(&buf) - if err != nil { - return nil, err - } - return buf.Bytes(), nil -} - -// MarshalJSONBuf marshal buff to json - template -func (j *RequestHashPayload) MarshalJSONBuf(buf fflib.EncodingBuffer) error { - if j == nil { - buf.WriteString("null") - return nil - } - var err error - var obj []byte - _ = obj - _ = err - if j.Payload != nil { - buf.WriteString(`{"payload":`) - - { - - err = j.Payload.MarshalJSONBuf(buf) - if err != nil { - return err - } - - } - } else { - buf.WriteString(`{"payload":null`) - } - if j.Metadata != nil { - buf.WriteString(`,"meta":`) - - { - - err = j.Metadata.MarshalJSONBuf(buf) - if err != nil { - return err - } - - } - } else { - buf.WriteString(`,"meta":null`) - } - buf.WriteByte('}') - return nil -} - -const ( - ffjtRequestHashPayloadbase = iota - ffjtRequestHashPayloadnosuchkey - - ffjtRequestHashPayloadPayload - - ffjtRequestHashPayloadMetadata -) - -var ffjKeyRequestHashPayloadPayload = []byte("payload") - -var ffjKeyRequestHashPayloadMetadata = []byte("meta") - -// UnmarshalJSON umarshall json - template of ffjson -func (j *RequestHashPayload) UnmarshalJSON(input []byte) error { - fs := fflib.NewFFLexer(input) - return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start) -} - -// UnmarshalJSONFFLexer fast json unmarshall - template ffjson -func (j *RequestHashPayload) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error { - var err error - currentKey := ffjtRequestHashPayloadbase - _ = currentKey - tok := fflib.FFTok_init - wantedTok := fflib.FFTok_init - -mainparse: - for { - tok = fs.Scan() - // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state)) - if tok == fflib.FFTok_error { - goto tokerror - } - - switch state { - - case fflib.FFParse_map_start: - if tok != fflib.FFTok_left_bracket { - wantedTok = fflib.FFTok_left_bracket - goto wrongtokenerror - } - state = fflib.FFParse_want_key - continue - - case fflib.FFParse_after_value: - if tok == fflib.FFTok_comma { - state = fflib.FFParse_want_key - } else if tok == fflib.FFTok_right_bracket { - goto done - } else { - wantedTok = fflib.FFTok_comma - goto wrongtokenerror - } - - case fflib.FFParse_want_key: - // json {} ended. goto exit. woo. - if tok == fflib.FFTok_right_bracket { - goto done - } - if tok != fflib.FFTok_string { - wantedTok = fflib.FFTok_string - goto wrongtokenerror - } - - kn := fs.Output.Bytes() - if len(kn) <= 0 { - // "" case. hrm. - currentKey = ffjtRequestHashPayloadnosuchkey - state = fflib.FFParse_want_colon - goto mainparse - } else { - switch kn[0] { - - case 'm': - - if bytes.Equal(ffjKeyRequestHashPayloadMetadata, kn) { - currentKey = ffjtRequestHashPayloadMetadata - state = fflib.FFParse_want_colon - goto mainparse - } - - case 'p': - - if bytes.Equal(ffjKeyRequestHashPayloadPayload, kn) { - currentKey = ffjtRequestHashPayloadPayload - state = fflib.FFParse_want_colon - goto mainparse - } - - } - - if fflib.SimpleLetterEqualFold(ffjKeyRequestHashPayloadMetadata, kn) { - currentKey = ffjtRequestHashPayloadMetadata - state = fflib.FFParse_want_colon - goto mainparse - } - - if fflib.SimpleLetterEqualFold(ffjKeyRequestHashPayloadPayload, kn) { - currentKey = ffjtRequestHashPayloadPayload - state = fflib.FFParse_want_colon - goto mainparse - } - - currentKey = ffjtRequestHashPayloadnosuchkey - state = fflib.FFParse_want_colon - goto mainparse - } - - case fflib.FFParse_want_colon: - if tok != fflib.FFTok_colon { - wantedTok = fflib.FFTok_colon - goto wrongtokenerror - } - state = fflib.FFParse_want_value - continue - case fflib.FFParse_want_value: - - if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null { - switch currentKey { - - case ffjtRequestHashPayloadPayload: - goto handle_Payload - - case ffjtRequestHashPayloadMetadata: - goto handle_Metadata - - case ffjtRequestHashPayloadnosuchkey: - err = fs.SkipField(tok) - if err != nil { - return fs.WrapErr(err) - } - state = fflib.FFParse_after_value - goto mainparse - } - } else { - goto wantedvalue - } - } - } - -handle_Payload: - - /* handler: j.Payload type=models.Payload kind=struct quoted=false*/ - - { - if tok == fflib.FFTok_null { - - j.Payload = nil - - } else { - - if j.Payload == nil { - j.Payload = new(Payload) - } - - err = j.Payload.UnmarshalJSONFFLexer(fs, fflib.FFParse_want_key) - if err != nil { - return err - } - } - state = fflib.FFParse_after_value - } - - state = fflib.FFParse_after_value - goto mainparse - -handle_Metadata: - - /* handler: j.Metadata type=models.RelayMeta kind=struct quoted=false*/ - - { - if tok == fflib.FFTok_null { - - j.Metadata = nil - - } else { - - if j.Metadata == nil { - j.Metadata = new(RelayMeta) - } - - err = j.Metadata.UnmarshalJSONFFLexer(fs, fflib.FFParse_want_key) - if err != nil { - return err - } - } - state = fflib.FFParse_after_value - } - - state = fflib.FFParse_after_value - goto mainparse - -wantedvalue: - return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok)) -wrongtokenerror: - return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String())) -tokerror: - if fs.BigError != nil { - return fs.WrapErr(fs.BigError) - } - err = fs.Error.ToError() - if err != nil { - return fs.WrapErr(err) - } - panic("ffjson-generated: unreachable, please report bug.") -done: - - return nil -} - // MarshalJSON marshal bytes to json - template func (j *SendRelayRequest) MarshalJSON() ([]byte, error) { var buf fflib.Buffer @@ -2262,7 +1506,7 @@ func (j *SendRelayRequest) MarshalJSONBuf(buf fflib.EncodingBuffer) error { buf.WriteString(`{"Payload":null`) } if j.Signer != nil { - buf.WriteString(`,"signer":`) + buf.WriteString(`,"Signer":`) { @@ -2273,7 +1517,7 @@ func (j *SendRelayRequest) MarshalJSONBuf(buf fflib.EncodingBuffer) error { } } else { - buf.WriteString(`,"signer":null`) + buf.WriteString(`,"Signer":null`) } buf.WriteString(`,"Chain":`) fflib.WriteJsonString(buf, string(j.Chain)) @@ -2289,6 +1533,12 @@ func (j *SendRelayRequest) MarshalJSONBuf(buf fflib.EncodingBuffer) error { } else { buf.WriteString(`,"Session":null`) } + if j.Timeout != nil { + buf.WriteString(`,"Timeout":`) + fflib.FormatBits2(buf, uint64(*j.Timeout), 10, *j.Timeout < 0) + } else { + buf.WriteString(`,"Timeout":null`) + } buf.WriteByte('}') return nil } @@ -2306,11 +1556,13 @@ const ( ffjtSendRelayRequestSelectedNodePubKey ffjtSendRelayRequestSession + + ffjtSendRelayRequestTimeout ) var ffjKeySendRelayRequestPayload = []byte("Payload") -var ffjKeySendRelayRequestSigner = []byte("signer") +var ffjKeySendRelayRequestSigner = []byte("Signer") var ffjKeySendRelayRequestChain = []byte("Chain") @@ -2318,6 +1570,8 @@ var ffjKeySendRelayRequestSelectedNodePubKey = []byte("SelectedNodePubKey") var ffjKeySendRelayRequestSession = []byte("Session") +var ffjKeySendRelayRequestTimeout = []byte("Timeout") + // UnmarshalJSON umarshall json - template of ffjson func (j *SendRelayRequest) UnmarshalJSON(input []byte) error { fs := fflib.NewFFLexer(input) @@ -2413,6 +1667,20 @@ mainparse: goto mainparse } + case 'T': + + if bytes.Equal(ffjKeySendRelayRequestTimeout, kn) { + currentKey = ffjtSendRelayRequestTimeout + state = fflib.FFParse_want_colon + goto mainparse + } + + } + + if fflib.SimpleLetterEqualFold(ffjKeySendRelayRequestTimeout, kn) { + currentKey = ffjtSendRelayRequestTimeout + state = fflib.FFParse_want_colon + goto mainparse } if fflib.EqualFoldRight(ffjKeySendRelayRequestSession, kn) { @@ -2477,6 +1745,9 @@ mainparse: case ffjtSendRelayRequestSession: goto handle_Session + case ffjtSendRelayRequestTimeout: + goto handle_Timeout + case ffjtSendRelayRequestnosuchkey: err = fs.SkipField(tok) if err != nil { @@ -2519,7 +1790,7 @@ handle_Payload: handle_Signer: - /* handler: j.signer type=models.Ed25519Account kind=struct quoted=false*/ + /* handler: j.Signer type=models.Ed25519Account kind=struct quoted=false*/ { if tok == fflib.FFTok_null { @@ -2615,6 +1886,39 @@ handle_Session: state = fflib.FFParse_after_value goto mainparse +handle_Timeout: + + /* handler: j.Timeout type=time.Duration kind=int64 quoted=false*/ + + { + if tok != fflib.FFTok_integer && tok != fflib.FFTok_null { + return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for Duration", tok)) + } + } + + { + + if tok == fflib.FFTok_null { + + j.Timeout = nil + + } else { + + tval, err := fflib.ParseInt(fs.Output.Bytes(), 10, 64) + + if err != nil { + return fs.WrapErr(err) + } + + ttypval := time.Duration(tval) + j.Timeout = &ttypval + + } + } + + state = fflib.FFParse_after_value + goto mainparse + wantedvalue: return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok)) wrongtokenerror: diff --git a/pkg/pokt/pokt_v0/models/session.go b/pkg/pokt/pokt_v0/models/session.go index beafcb2..74eb9ca 100644 --- a/pkg/pokt/pokt_v0/models/session.go +++ b/pkg/pokt/pokt_v0/models/session.go @@ -21,7 +21,7 @@ type Session struct { } type GetSessionRequest struct { - AppPubKey string `json:"app_public_key"` - Chain string `json:"chain"` - Height uint `json:"session_height"` + AppPubKey string `json:"app_public_key"` + Chain string `json:"chain"` + SessionHeight uint `json:"session_height"` } diff --git a/pkg/pokt/pokt_v0/models/session_ffjson.go b/pkg/pokt/pokt_v0/models/session_ffjson.go index 5ebab41..9d22881 100644 --- a/pkg/pokt/pokt_v0/models/session_ffjson.go +++ b/pkg/pokt/pokt_v0/models/session_ffjson.go @@ -38,7 +38,7 @@ func (j *GetSessionRequest) MarshalJSONBuf(buf fflib.EncodingBuffer) error { buf.WriteString(`,"chain":`) fflib.WriteJsonString(buf, string(j.Chain)) buf.WriteString(`,"session_height":`) - fflib.FormatBits2(buf, uint64(j.Height), 10, false) + fflib.FormatBits2(buf, uint64(j.SessionHeight), 10, false) buf.WriteByte('}') return nil } @@ -51,14 +51,14 @@ const ( ffjtGetSessionRequestChain - ffjtGetSessionRequestHeight + ffjtGetSessionRequestSessionHeight ) var ffjKeyGetSessionRequestAppPubKey = []byte("app_public_key") var ffjKeyGetSessionRequestChain = []byte("chain") -var ffjKeyGetSessionRequestHeight = []byte("session_height") +var ffjKeyGetSessionRequestSessionHeight = []byte("session_height") // UnmarshalJSON umarshall json - template of ffjson func (j *GetSessionRequest) UnmarshalJSON(input []byte) error { @@ -139,16 +139,16 @@ mainparse: case 's': - if bytes.Equal(ffjKeyGetSessionRequestHeight, kn) { - currentKey = ffjtGetSessionRequestHeight + if bytes.Equal(ffjKeyGetSessionRequestSessionHeight, kn) { + currentKey = ffjtGetSessionRequestSessionHeight state = fflib.FFParse_want_colon goto mainparse } } - if fflib.EqualFoldRight(ffjKeyGetSessionRequestHeight, kn) { - currentKey = ffjtGetSessionRequestHeight + if fflib.EqualFoldRight(ffjKeyGetSessionRequestSessionHeight, kn) { + currentKey = ffjtGetSessionRequestSessionHeight state = fflib.FFParse_want_colon goto mainparse } @@ -188,8 +188,8 @@ mainparse: case ffjtGetSessionRequestChain: goto handle_Chain - case ffjtGetSessionRequestHeight: - goto handle_Height + case ffjtGetSessionRequestSessionHeight: + goto handle_SessionHeight case ffjtGetSessionRequestnosuchkey: err = fs.SkipField(tok) @@ -257,9 +257,9 @@ handle_Chain: state = fflib.FFParse_after_value goto mainparse -handle_Height: +handle_SessionHeight: - /* handler: j.Height type=uint kind=uint quoted=false*/ + /* handler: j.SessionHeight type=uint kind=uint quoted=false*/ { if tok != fflib.FFTok_integer && tok != fflib.FFTok_null { @@ -279,7 +279,7 @@ handle_Height: return fs.WrapErr(err) } - j.Height = uint(tval) + j.SessionHeight = uint(tval) } } diff --git a/pkg/ttl_cache/ttl_cache.go b/pkg/ttl_cache/ttl_cache.go index e687e5b..dbb550e 100644 --- a/pkg/ttl_cache/ttl_cache.go +++ b/pkg/ttl_cache/ttl_cache.go @@ -12,4 +12,5 @@ type TTLCacheService[K comparable, V any] interface { Set(key K, value V, ttl time.Duration) *ttlcache.Item[K, V] Start() Items() map[K]*ttlcache.Item[K, V] + DeleteExpired() }