Skip to content

Commit

Permalink
List contract address without other data
Browse files Browse the repository at this point in the history
  • Loading branch information
alpe committed Apr 23, 2021
1 parent 8ef2d26 commit c377d71
Show file tree
Hide file tree
Showing 16 changed files with 212 additions and 467 deletions.
2 changes: 1 addition & 1 deletion contrib/local/02-contracts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ wasmd tx wasm instantiate "$CODE_ID" "$INIT" --admin=$(wasmd keys show validator
--from validator --amount="100ustake" --label "local0.1.0" \
--gas 1000000 -y --chain-id=testing -b block | jq

CONTRACT=$(wasmd query wasm list-contract-by-code "$CODE_ID" -o json | jq -r '.contract_infos[-1].address')
CONTRACT=$(wasmd query wasm list-contract-by-code "$CODE_ID" -o json | jq -r '.contracts[-1]')
echo "* Contract address: $CONTRACT"
echo "### Query all"
RESP=$(wasmd query wasm contract-state all "$CONTRACT" -o json)
Expand Down
16 changes: 9 additions & 7 deletions contrib/local/03-grpc-queries.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,28 @@ set -o errexit -o nounset -o pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"

echo "-----------------------"
COSMOS_SDK_DIR=${COSMOS_SDK_DIR:-$(go list -f "{{ .Dir }}" -m github.com/cosmos/cosmos-sdk)}
PROTO_THRD="$DIR/../../third_party/proto"
PROTO_WASMD="$DIR/../../proto"
PROTO_WASMD_QUERY="$PROTO_WASMD/cosmwasm/wasm/v1beta1/query.proto"

echo "### List all codes"
RESP=$(grpcurl -plaintext -import-path $COSMOS_SDK_DIR/third_party/proto -import-path $COSMOS_SDK_DIR/proto -import-path . -proto ./x/wasm/types/query.proto \
RESP=$(grpcurl -plaintext -import-path $PROTO_THRD -import-path $PROTO_WASMD -proto $PROTO_WASMD_QUERY \
localhost:9090 cosmwasm.wasm.v1beta1.Query/Codes)
echo "$RESP" | jq

CODE_ID=$(echo "$RESP" | jq -r '.codeInfos[-1].codeId')
echo "### List contract by code"
RESP=$(grpcurl -plaintext -import-path $COSMOS_SDK_DIR/third_party/proto -import-path $COSMOS_SDK_DIR/proto -import-path . -proto ./x/wasm/types/query.proto \
echo "### List contracts by code"
RESP=$(grpcurl -plaintext -import-path $PROTO_THRD -import-path $PROTO_WASMD -proto $PROTO_WASMD_QUERY \
-d "{\"codeId\": $CODE_ID}" localhost:9090 cosmwasm.wasm.v1beta1.Query/ContractsByCode )
echo $RESP | jq

echo "### Show history for contract"
CONTRACT=$(echo $RESP | jq -r ".contractInfos[-1].address")
grpcurl -plaintext -import-path $COSMOS_SDK_DIR/third_party/proto -import-path $COSMOS_SDK_DIR/proto -import-path . -proto ./x/wasm/types/query.proto \
CONTRACT=$(echo $RESP | jq -r ".contracts[-1]")
grpcurl -plaintext -import-path $PROTO_THRD -import-path $PROTO_WASMD -proto $PROTO_WASMD_QUERY \
-d "{\"address\": \"$CONTRACT\"}" localhost:9090 cosmwasm.wasm.v1beta1.Query/ContractHistory | jq

echo "### Show contract state"
grpcurl -plaintext -import-path $COSMOS_SDK_DIR/third_party/proto -import-path $COSMOS_SDK_DIR/proto -import-path . -proto ./x/wasm/types/query.proto \
grpcurl -plaintext -import-path $PROTO_THRD -import-path $PROTO_WASMD -proto $PROTO_WASMD_QUERY \
-d "{\"address\": \"$CONTRACT\"}" localhost:9090 cosmwasm.wasm.v1beta1.Query/AllContractState | jq

echo "Empty state due to 'burner' contract cleanup"
20 changes: 1 addition & 19 deletions docs/proto/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@

- [cosmwasm/wasm/v1beta1/query.proto](#cosmwasm/wasm/v1beta1/query.proto)
- [CodeInfoResponse](#cosmwasm.wasm.v1beta1.CodeInfoResponse)
- [ContractInfoWithAddress](#cosmwasm.wasm.v1beta1.ContractInfoWithAddress)
- [QueryAllContractStateRequest](#cosmwasm.wasm.v1beta1.QueryAllContractStateRequest)
- [QueryAllContractStateResponse](#cosmwasm.wasm.v1beta1.QueryAllContractStateResponse)
- [QueryCodeRequest](#cosmwasm.wasm.v1beta1.QueryCodeRequest)
Expand Down Expand Up @@ -814,23 +813,6 @@ CodeInfoResponse contains code meta data from CodeInfo



<a name="cosmwasm.wasm.v1beta1.ContractInfoWithAddress"></a>

### ContractInfoWithAddress
ContractInfoWithAddress adds the address (key) to the ContractInfo
representation


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `address` | [string](#string) | | |
| `contract_info` | [ContractInfo](#cosmwasm.wasm.v1beta1.ContractInfo) | | |






<a name="cosmwasm.wasm.v1beta1.QueryAllContractStateRequest"></a>

### QueryAllContractStateRequest
Expand Down Expand Up @@ -1020,7 +1002,7 @@ Query/ContractsByCode RPC method

| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `contract_infos` | [ContractInfoWithAddress](#cosmwasm.wasm.v1beta1.ContractInfoWithAddress) | repeated | |
| `contracts` | [string](#string) | repeated | contracts are a set of contract addresses |
| `pagination` | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. |


Expand Down
17 changes: 3 additions & 14 deletions proto/cosmwasm/wasm/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -100,23 +100,12 @@ message QueryContractsByCodeRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 2;
}

// ContractInfoWithAddress adds the address (key) to the ContractInfo
// representation
message ContractInfoWithAddress {
option (gogoproto.equal) = true;

string address = 1;
ContractInfo contract_info = 2 [
(gogoproto.embed) = true,
(gogoproto.nullable) = false,
(gogoproto.jsontag) = ""
];
}
// QueryContractsByCodeResponse is the response type for the
// Query/ContractsByCode RPC method
message QueryContractsByCodeResponse {
repeated ContractInfoWithAddress contract_infos = 1
[ (gogoproto.nullable) = false ];
// contracts are a set of contract addresses
repeated string contracts = 1;

// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
Expand Down
1 change: 0 additions & 1 deletion x/wasm/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ type (
ContractInfo = types.ContractInfo
CreatedAt = types.AbsoluteTxPosition
Config = types.WasmConfig
ContractInfoWithAddress = types.ContractInfoWithAddress
CodeInfoResponse = types.CodeInfoResponse
MessageHandler = keeper.SDKMessageHandler
BankEncoder = keeper.BankEncoder
Expand Down
21 changes: 10 additions & 11 deletions x/wasm/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,14 @@ import (
"encoding/base64"
"errors"
"fmt"
prefix2 "github.com/cosmos/cosmos-sdk/store/prefix"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"io/ioutil"
"math/rand"
"os"
"testing"
"time"

"github.com/CosmWasm/wasmd/x/wasm/types"
wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types"
"github.com/cosmos/cosmos-sdk/store"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
Expand All @@ -31,6 +25,11 @@ import (
"github.com/tendermint/tendermint/proto/tendermint/crypto"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
dbm "github.com/tendermint/tm-db"
"io/ioutil"
"math/rand"
"os"
"testing"
"time"
)

const firstCodeID = 1
Expand Down Expand Up @@ -110,9 +109,9 @@ func TestGenesisExportImport(t *testing.T) {
// reset contract code index in source DB for comparison with dest DB
wasmKeeper.IterateContractInfo(srcCtx, func(address sdk.AccAddress, info wasmTypes.ContractInfo) bool {
wasmKeeper.removeFromContractCodeSecondaryIndex(srcCtx, address, wasmKeeper.getLastContractHistoryEntry(srcCtx, address))
prefix := prefix2.NewStore(srcCtx.KVStore(wasmKeeper.storeKey), types.GetContractCodeHistoryElementPrefix(address))
for iter := prefix.Iterator(nil, nil); iter.Valid(); iter.Next() {
prefix.Delete(iter.Key())
prefixStore := prefix.NewStore(srcCtx.KVStore(wasmKeeper.storeKey), types.GetContractCodeHistoryElementPrefix(address))
for iter := prefixStore.Iterator(nil, nil); iter.Valid(); iter.Next() {
prefixStore.Delete(iter.Key())
}
x := &info
newHistory := x.ResetFromGenesis(dstCtx)
Expand Down
12 changes: 12 additions & 0 deletions x/wasm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,17 @@ func (k Keeper) removeFromContractCodeSecondaryIndex(ctx sdk.Context, contractAd
ctx.KVStore(k.storeKey).Delete(types.GetContractByCreatedSecondaryIndexKey(contractAddress, entry))
}

// IterateContractsByCode iterates over all contracts with given codeID ASC on code update time.
func (k Keeper) IterateContractsByCode(ctx sdk.Context, codeID uint64, cb func(address sdk.AccAddress) bool) {
prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.GetContractByCodeIDSecondaryIndexPrefix(codeID))
for iter := prefixStore.Iterator(nil, nil); iter.Valid(); iter.Next() {
key := iter.Key()
if cb(key[types.AbsoluteTxPositionLen:]) {
return
}
}
}

func (k Keeper) setContractAdmin(ctx sdk.Context, contractAddress, caller, newAdmin sdk.AccAddress, authZ AuthorizationPolicy) error {
contractInfo := k.GetContractInfo(ctx, contractAddress)
if contractInfo == nil {
Expand Down Expand Up @@ -562,6 +573,7 @@ func (k Keeper) GetContractHistory(ctx sdk.Context, contractAddr sdk.AccAddress)
return r
}

// getLastContractHistoryEntry returns the last element from history. To be used internally only as it panics when none exists
func (k Keeper) getLastContractHistoryEntry(ctx sdk.Context, contractAddr sdk.AccAddress) types.ContractCodeHistoryEntry {
prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.GetContractCodeHistoryElementPrefix(contractAddr))
iter := prefixStore.ReverseIterator(nil, nil)
Expand Down
41 changes: 41 additions & 0 deletions x/wasm/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,47 @@ func TestMigrateWithDispatchedMessage(t *testing.T) {
assert.Equal(t, deposit, balance)
}

func TestIterateContractsByCode(t *testing.T) {
ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
k, c := keepers.WasmKeeper, keepers.ContractKeeper
example1 := InstantiateHackatomExampleContract(t, ctx, keepers)
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
example2 := InstantiateIBCReflectContract(t, ctx, keepers)
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
initMsg := HackatomExampleInitMsg{
Verifier: RandomAccountAddress(t),
Beneficiary: RandomAccountAddress(t),
}.GetBytes(t)
contractAddr3, _, err := c.Instantiate(ctx, example1.CodeID, example1.CreatorAddr, nil, initMsg, "foo", nil)
require.NoError(t, err)
specs := map[string]struct {
codeID uint64
exp []sdk.AccAddress
}{
"multiple results": {
codeID: example1.CodeID,
exp: []sdk.AccAddress{example1.Contract, contractAddr3},
},
"single results": {
codeID: example2.CodeID,
exp: []sdk.AccAddress{example2.Contract},
},
"empty results": {
codeID: 99999,
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
var gotAddr []sdk.AccAddress
k.IterateContractsByCode(ctx, spec.codeID, func(address sdk.AccAddress) bool {
gotAddr = append(gotAddr, address)
return false
})
assert.Equal(t, spec.exp, gotAddr)
})
}
}

type sudoMsg struct {
// This is a tongue-in-check demo command. This is not the intended purpose of Sudo.
// Here we show that some priviledged Go module can make a call that should never be exposed
Expand Down
40 changes: 8 additions & 32 deletions x/wasm/keeper/legacy_querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@ package keeper

import (
"encoding/json"
"reflect"
"sort"
"strconv"
"strings"

"github.com/CosmWasm/wasmd/x/wasm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
abci "github.com/tendermint/tendermint/abci/types"
"reflect"
"strconv"
)

const (
Expand Down Expand Up @@ -47,7 +44,7 @@ func NewLegacyQuerier(keeper types.ViewKeeper, gasLimit sdk.Gas) sdk.Querier {
if err != nil {
return nil, sdkerrors.Wrapf(types.ErrInvalid, "code id: %s", err.Error())
}
rsp, err = queryContractListByCode(ctx, codeID, keeper)
rsp = queryContractListByCode(ctx, codeID, keeper)
case QueryGetContractState:
if len(path) < 3 {
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown data query endpoint")
Expand Down Expand Up @@ -145,32 +142,11 @@ func queryContractHistory(ctx sdk.Context, contractAddr sdk.AccAddress, keeper t
return history, nil
}

func queryContractListByCode(ctx sdk.Context, codeID uint64, keeper types.ViewKeeper) ([]types.ContractInfoWithAddress, error) {
var contracts []types.ContractInfoWithAddress
keeper.IterateContractInfo(ctx, func(addr sdk.AccAddress, info types.ContractInfo) bool {
if info.CodeID == codeID {
// and add the address
infoWithAddress := types.ContractInfoWithAddress{
Address: addr.String(),
ContractInfo: info,
}
contracts = append(contracts, infoWithAddress)
}
func queryContractListByCode(ctx sdk.Context, codeID uint64, keeper types.ViewKeeper) []string {
var contracts []string
keeper.IterateContractsByCode(ctx, codeID, func(addr sdk.AccAddress) bool {
contracts = append(contracts, addr.String())
return false
})

// now we sort them by AbsoluteTxPosition
sort.Slice(contracts, func(i, j int) bool {
this := contracts[i].ContractInfo.Created
other := contracts[j].ContractInfo.Created
if this.Equal(other) {
return strings.Compare(contracts[i].Address, contracts[j].Address) < 0
}
return this.LessThan(other)
})

for i := range contracts {
contracts[i].Created = nil
}
return contracts, nil
return contracts
}
9 changes: 3 additions & 6 deletions x/wasm/keeper/legacy_querier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,17 +205,14 @@ func TestLegacyQueryContractListByCodeOrdering(t *testing.T) {
res, err := q(ctx, query, data)
require.NoError(t, err)

var contracts []map[string]interface{}
var contracts []string
err = json.Unmarshal(res, &contracts)
require.NoError(t, err)

require.Equal(t, 10, len(contracts))

for i, contract := range contracts {
assert.Equal(t, fmt.Sprintf("contract %d", i), contract["label"])
assert.NotEmpty(t, contract["address"])
// ensure these are not shown
assert.Nil(t, contract["created"])
for _, contract := range contracts {
assert.NotEmpty(t, contract)
}
}

Expand Down
Loading

0 comments on commit c377d71

Please sign in to comment.