@@ -33,14 +33,15 @@ import (
33
33
epochtypes "github.com/osmosis-labs/osmosis/x/epochs/types"
34
34
)
35
35
36
- // stargateWhitelist keeps whitelist and its deterministic
36
+ // stargateResponsePools keeps whitelist and its deterministic
37
37
// response binding for stargate queries.
38
38
// CONTRACT: since results of queries go into blocks, queries being added here should always be
39
39
// deterministic or can cause non-determinism in the state machine.
40
40
//
41
- // The query can be multi-thread, so we have to use
42
- // thread safe sync.Map.
43
- var stargateWhitelist sync.Map
41
+ // The query is multi-threaded so we're using a sync.Pool
42
+ // to manage the allocation and de-allocation of newly created
43
+ // pb objects.
44
+ var stargateResponsePools = make (map [string ]* sync.Pool )
44
45
45
46
// Note: When adding a migration here, we should also add it to the Async ICQ params in the upgrade.
46
47
// In the future we may want to find a better way to keep these in sync
@@ -184,34 +185,57 @@ func init() {
184
185
setWhitelistedQuery ("/osmosis.concentratedliquidity.v1beta1.Query/CFMMPoolIdLinkFromConcentratedPoolId" , & concentratedliquidityquery.CFMMPoolIdLinkFromConcentratedPoolIdResponse {})
185
186
}
186
187
187
- // GetWhitelistedQuery returns the whitelisted query at the provided path.
188
+ // IsWhitelistedQuery returns if the query is not whitelisted.
189
+ func IsWhitelistedQuery (queryPath string ) error {
190
+ _ , isWhitelisted := stargateResponsePools [queryPath ]
191
+ if ! isWhitelisted {
192
+ return wasmvmtypes.UnsupportedRequest {Kind : fmt .Sprintf ("'%s' path is not allowed from the contract" , queryPath )}
193
+ }
194
+ return nil
195
+ }
196
+
197
+ // getWhitelistedQuery returns the whitelisted query at the provided path.
188
198
// If the query does not exist, or it was setup wrong by the chain, this returns an error.
189
- func GetWhitelistedQuery (queryPath string ) (codec.ProtoMarshaler , error ) {
190
- protoResponseAny , isWhitelisted := stargateWhitelist .Load (queryPath )
199
+ // CONTRACT: must call returnStargateResponseToPool in order to avoid pointless allocs.
200
+ func getWhitelistedQuery (queryPath string ) (codec.ProtoMarshaler , error ) {
201
+ protoResponseAny , isWhitelisted := stargateResponsePools [queryPath ]
191
202
if ! isWhitelisted {
192
203
return nil , wasmvmtypes.UnsupportedRequest {Kind : fmt .Sprintf ("'%s' path is not allowed from the contract" , queryPath )}
193
204
}
194
- protoResponseType , ok := protoResponseAny .(codec.ProtoMarshaler )
205
+ protoMarshaler , ok := protoResponseAny . Get () .(codec.ProtoMarshaler )
195
206
if ! ok {
196
- return nil , wasmvmtypes. Unknown {}
207
+ return nil , fmt . Errorf ( "failed to assert type to codec.ProtoMarshaler" )
197
208
}
198
- return protoResponseType , nil
209
+ return protoMarshaler , nil
199
210
}
200
211
201
- func setWhitelistedQuery (queryPath string , protoType codec.ProtoMarshaler ) {
202
- stargateWhitelist .Store (queryPath , protoType )
212
+ type protoTypeG [T any ] interface {
213
+ * T
214
+ codec.ProtoMarshaler
215
+ }
216
+
217
+ // setWhitelistedQuery sets the whitelisted query at the provided path.
218
+ // This method also creates a sync.Pool for the provided protoMarshaler.
219
+ // We use generics so we can properly instantiate an object that the
220
+ // queryPath expects as a response.
221
+ func setWhitelistedQuery [T any , PT protoTypeG [T ]](queryPath string , _ PT ) {
222
+ stargateResponsePools [queryPath ] = & sync.Pool {
223
+ New : func () any {
224
+ return PT (new (T ))
225
+ },
226
+ }
227
+ }
228
+
229
+ // returnStargateResponseToPool returns the provided protoMarshaler to the appropriate pool based on it's query path.
230
+ func returnStargateResponseToPool (queryPath string , pb codec.ProtoMarshaler ) {
231
+ stargateResponsePools [queryPath ].Put (pb )
203
232
}
204
233
205
234
func GetStargateWhitelistedPaths () (keys []string ) {
206
235
// Iterate over the map and collect the keys
207
- stargateWhitelist .Range (func (key , value interface {}) bool {
208
- keyStr , ok := key .(string )
209
- if ! ok {
210
- panic ("key is not a string" )
211
- }
212
- keys = append (keys , keyStr )
213
- return true
214
- })
215
-
236
+ keys = make ([]string , 0 , len (stargateResponsePools ))
237
+ for k := range stargateResponsePools {
238
+ keys = append (keys , k )
239
+ }
216
240
return keys
217
241
}
0 commit comments