-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapplication.go
More file actions
176 lines (155 loc) · 5.28 KB
/
application.go
File metadata and controls
176 lines (155 loc) · 5.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package sdk
import (
"context"
"errors"
"fmt"
"slices"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
query "github.com/cosmos/cosmos-sdk/types/query"
"github.com/pokt-network/poktroll/pkg/crypto/rings"
"github.com/pokt-network/poktroll/x/application/types"
"github.com/pokt-network/ring-go"
)
// ApplicationRing groups the application and helper required to construct a *ring.Ring.
type ApplicationRing struct {
types.Application
PublicKeyFetcher
}
func NewApplicationRing(
app types.Application,
publicKeyFetcher PublicKeyFetcher,
) *ApplicationRing {
return &ApplicationRing{
Application: app,
PublicKeyFetcher: publicKeyFetcher,
}
}
// ApplicationClient is the interface to interact with the on-chain application-module.
//
// - Used to get the list of applications and the details of a specific application
// - Uses the gRPC query client of the application module
// - QueryClient is public for future interface abstraction (see: https://go.dev/wiki/CodeReviewComments#interfaces)
// - Could be extended to use caching, but cache must be invalidated by events (e.g. MsgStakeApplication, MsgUnstakeApplication)
//
// Implements sdk.ApplicationClient interface.
type ApplicationClient struct {
// TODO_TECHDEBT: Replace QueryClient with a PoktNodeAccountFetcher interface.
types.QueryClient
}
// ------------------------- Methods -------------------------
// GetAllApplications returns all applications in the network.
//
// - Returns error if context deadline is exceeded
// - TODO_TECHDEBT(@adshmh): Support pagination if/when onchain application count grows
// - TODO_TECHDEBT: Add filtering options when supported by on-chain module
func (ac *ApplicationClient) GetAllApplications(
ctx context.Context,
) ([]types.Application, error) {
var (
fetchedApps []types.Application
fetchErr error
doneCh = make(chan struct{}) // Signals completion of app fetch
)
go func() {
defer close(doneCh)
req := &types.QueryAllApplicationsRequest{
Pagination: &query.PageRequest{
Limit: query.PaginationMaxLimit,
},
}
res, err := ac.AllApplications(ctx, req)
if err != nil {
fetchErr = err
return
}
fetchedApps = res.Applications
}()
select {
case <-doneCh:
return fetchedApps, fetchErr
case <-ctx.Done():
return []types.Application{}, ctx.Err()
}
}
// GetApplication returns the details of the application with the given address.
//
// - Returns error if context deadline is exceeded
func (ac *ApplicationClient) GetApplication(
ctx context.Context,
appAddress string,
) (types.Application, error) {
var (
fetchedApp types.Application
fetchErr error
doneCh = make(chan struct{}) // Signals completion of app fetch
)
go func() {
defer close(doneCh)
req := &types.QueryGetApplicationRequest{Address: appAddress}
// TODO_TECHDEBT(@adshmh): Consider increasing default response size (e.g. grpc MaxCallRecvMsgSize)
res, err := ac.Application(ctx, req)
if err != nil {
fetchErr = err
return
}
fetchedApp = res.Application
}()
select {
case <-doneCh:
return fetchedApp, fetchErr
case <-ctx.Done():
return types.Application{}, ctx.Err()
}
}
// GetApplicationsDelegatingToGateway returns the application addresses that are
// delegating to the given gateway address.
//
// - Inefficient: fetches all applications, then filters by delegation
// - TODO_TECHDEBT: Use filtering query once https://github.com/pokt-network/poktroll/issues/767 is implemented
func (ac *ApplicationClient) GetApplicationsDelegatingToGateway(
ctx context.Context,
gatewayAddress string,
sessionEndHeight uint64,
) ([]string, error) {
allApplications, err := ac.GetAllApplications(ctx)
if err != nil {
return nil, fmt.Errorf("GetApplicationsDelegatingToGateway: error getting all applications: %w", err)
}
gatewayDelegatingApplications := make([]string, 0)
for _, application := range allApplications {
gatewaysDelegatedTo := rings.GetRingAddressesAtSessionEndHeight(&application, sessionEndHeight)
if slices.Contains(gatewaysDelegatedTo, gatewayAddress) {
gatewayDelegatingApplications = append(gatewayDelegatingApplications, application.Address)
}
}
return gatewayDelegatingApplications, nil
}
// GetRing returns the ring for the application until the current session end height.
//
// - Ring is created using the application's public key and the public keys of gateways currently delegated from the application
// - Returns error if PublicKeyFetcher is not set or any pubkey fetch fails
func (a ApplicationRing) GetRing(
ctx context.Context,
sessionEndHeight uint64,
) (addressRing *ring.Ring, err error) {
if a.PublicKeyFetcher == nil {
return nil, errors.New("GetRing: Public Key Fetcher not set")
}
currentGatewayAddresses := rings.GetRingAddressesAtSessionEndHeight(&a.Application, sessionEndHeight)
ringAddresses := make([]string, 0)
ringAddresses = append(ringAddresses, a.Address)
if len(currentGatewayAddresses) == 0 {
ringAddresses = append(ringAddresses, a.Address)
} else {
ringAddresses = append(ringAddresses, currentGatewayAddresses...)
}
ringPubKeys := make([]cryptotypes.PubKey, 0, len(ringAddresses))
for _, address := range ringAddresses {
pubKey, err := a.GetPubKeyFromAddress(ctx, address)
if err != nil {
return nil, err
}
ringPubKeys = append(ringPubKeys, pubKey)
}
return rings.GetRingFromPubKeys(ringPubKeys)
}