@@ -27,6 +27,8 @@ const GasMultiplier = 100
27
27
// MaxGas for a contract is 900 million (enforced in rust)
28
28
const MaxGas = 900_000_000
29
29
30
+ const smartQueryGasLimit = 3000000 // Todo: should be set by app.toml
31
+
30
32
// Keeper will have a reference to Wasmer with it's own data directory.
31
33
type Keeper struct {
32
34
storeKey sdk.StoreKey
@@ -37,6 +39,8 @@ type Keeper struct {
37
39
router sdk.Router
38
40
39
41
wasmer wasm.Wasmer
42
+ // queryGasLimit is the max wasm gas that can be spent on executing a query with a contract
43
+ queryGasLimit uint64
40
44
}
41
45
42
46
// NewKeeper creates a new contract Keeper instance
@@ -53,6 +57,7 @@ func NewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, accountKeeper auth.Accou
53
57
accountKeeper : accountKeeper ,
54
58
bankKeeper : bankKeeper ,
55
59
router : router ,
60
+ queryGasLimit : smartQueryGasLimit ,
56
61
}
57
62
}
58
63
@@ -132,22 +137,10 @@ func (k Keeper) Instantiate(ctx sdk.Context, creator sdk.AccAddress, codeID uint
132
137
133
138
// Execute executes the contract instance
134
139
func (k Keeper ) Execute (ctx sdk.Context , contractAddress sdk.AccAddress , caller sdk.AccAddress , coins sdk.Coins , msgs []byte ) (sdk.Result , sdk.Error ) {
135
- store := ctx .KVStore (k .storeKey )
136
-
137
- contractBz := store .Get (types .GetContractAddressKey (contractAddress ))
138
- if contractBz == nil {
139
- return sdk.Result {}, types .ErrNotFound ("contract" )
140
- }
141
- var contract types.ContractInfo
142
- k .cdc .MustUnmarshalBinaryBare (contractBz , & contract )
143
-
144
- contractInfoBz := store .Get (types .GetCodeKey (contract .CodeID ))
145
- if contractInfoBz == nil {
146
- return sdk.Result {}, types .ErrNotFound ("contract info" )
140
+ codeInfo , prefixStore , err := k .contractInstance (ctx , contractAddress )
141
+ if err != nil {
142
+ return sdk.Result {}, err
147
143
}
148
- var codeInfo types.CodeInfo
149
- k .cdc .MustUnmarshalBinaryBare (contractInfoBz , & codeInfo )
150
-
151
144
// add more funds
152
145
sdkerr := k .bankKeeper .SendCoins (ctx , caller , contractAddress , coins )
153
146
if sdkerr != nil {
@@ -156,13 +149,10 @@ func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller
156
149
contractAccount := k .accountKeeper .GetAccount (ctx , contractAddress )
157
150
params := types .NewParams (ctx , caller , coins , contractAccount )
158
151
159
- prefixStoreKey := types .GetContractStorePrefixKey (contractAddress )
160
- prefixStore := prefix .NewStore (ctx .KVStore (k .storeKey ), prefixStoreKey )
161
-
162
152
gas := gasForContract (ctx )
163
- res , err := k .wasmer .Execute (codeInfo .CodeHash , params , msgs , prefixStore , gas )
164
- if err != nil {
165
- return sdk.Result {}, types .ErrExecuteFailed (err )
153
+ res , execErr := k .wasmer .Execute (codeInfo .CodeHash , params , msgs , prefixStore , gas )
154
+ if execErr != nil {
155
+ return sdk.Result {}, types .ErrExecuteFailed (execErr )
166
156
}
167
157
consumeGas (ctx , res .GasUsed )
168
158
@@ -174,6 +164,68 @@ func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller
174
164
return types .CosmosResult (* res ), nil
175
165
}
176
166
167
+ // QuerySmart queries the smart contract itself.
168
+ func (k Keeper ) QuerySmart (ctx sdk.Context , contractAddr sdk.AccAddress , req []byte ) ([]types.Model , sdk.Error ) {
169
+ ctx = ctx .WithGasMeter (sdk .NewGasMeter (k .queryGasLimit ))
170
+
171
+ codeInfo , prefixStore , err := k .contractInstance (ctx , contractAddr )
172
+ if err != nil {
173
+ return nil , err
174
+ }
175
+ queryResult , gasUsed , qErr := k .wasmer .Query (codeInfo .CodeHash , req , prefixStore , gasForContract (ctx ))
176
+ if qErr != nil {
177
+ return nil , types .ErrExecuteFailed (qErr )
178
+ }
179
+ consumeGas (ctx , gasUsed )
180
+ models := make ([]types.Model , len (queryResult .Results ))
181
+ for i := range queryResult .Results {
182
+ models [i ] = types.Model {
183
+ Key : queryResult .Results [i ].Key ,
184
+ Value : string (queryResult .Results [i ].Value ),
185
+ }
186
+ }
187
+ return models , nil
188
+ }
189
+
190
+ // QueryRaw returns the contract's state for give key. For a `nil` key a empty slice` result is returned.
191
+ func (k Keeper ) QueryRaw (ctx sdk.Context , contractAddress sdk.AccAddress , key []byte ) []types.Model {
192
+ result := make ([]types.Model , 0 )
193
+ if key == nil {
194
+ return result
195
+ }
196
+ prefixStoreKey := types .GetContractStorePrefixKey (contractAddress )
197
+ prefixStore := prefix .NewStore (ctx .KVStore (k .storeKey ), prefixStoreKey )
198
+
199
+ if val := prefixStore .Get (key ); val != nil {
200
+ return append (result , types.Model {
201
+ Key : string (key ),
202
+ Value : string (val ),
203
+ })
204
+ }
205
+ return result
206
+ }
207
+
208
+ func (k Keeper ) contractInstance (ctx sdk.Context , contractAddress sdk.AccAddress ) (types.CodeInfo , prefix.Store , sdk.Error ) {
209
+ store := ctx .KVStore (k .storeKey )
210
+
211
+ contractBz := store .Get (types .GetContractAddressKey (contractAddress ))
212
+ if contractBz == nil {
213
+ return types.CodeInfo {}, prefix.Store {}, types .ErrNotFound ("contract" )
214
+ }
215
+ var contract types.ContractInfo
216
+ k .cdc .MustUnmarshalBinaryBare (contractBz , & contract )
217
+
218
+ contractInfoBz := store .Get (types .GetCodeKey (contract .CodeID ))
219
+ if contractInfoBz == nil {
220
+ return types.CodeInfo {}, prefix.Store {}, types .ErrNotFound ("contract info" )
221
+ }
222
+ var codeInfo types.CodeInfo
223
+ k .cdc .MustUnmarshalBinaryBare (contractInfoBz , & codeInfo )
224
+ prefixStoreKey := types .GetContractStorePrefixKey (contractAddress )
225
+ prefixStore := prefix .NewStore (ctx .KVStore (k .storeKey ), prefixStoreKey )
226
+ return codeInfo , prefixStore , nil
227
+ }
228
+
177
229
func (k Keeper ) GetContractInfo (ctx sdk.Context , contractAddress sdk.AccAddress ) * types.ContractInfo {
178
230
store := ctx .KVStore (k .storeKey )
179
231
var contract types.ContractInfo
0 commit comments