@agoric/cosmos 0.35.0-upgrade-14-dev-c8f9e7b.0 → 0.35.0-upgrade-16a-dev-fb592e4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +121 -77
- package/MAINTAINERS.md +3 -0
- package/Makefile +36 -26
- package/ante/ante.go +7 -9
- package/ante/inbound_test.go +3 -2
- package/ante/vm_admission.go +2 -1
- package/app/app.go +212 -140
- package/app/upgrade.go +76 -0
- package/cmd/agd/agvm.go +42 -0
- package/cmd/agd/main.go +130 -11
- package/cmd/libdaemon/main.go +64 -53
- package/cmd/libdaemon/main_test.go +2 -1
- package/daemon/cmd/root.go +171 -74
- package/daemon/cmd/root_test.go +189 -1
- package/daemon/main.go +4 -2
- package/e2e_test/Makefile +29 -0
- package/e2e_test/README.md +100 -0
- package/e2e_test/go.mod +217 -0
- package/e2e_test/go.sum +1323 -0
- package/e2e_test/ibc_conformance_test.go +56 -0
- package/e2e_test/pfm_test.go +613 -0
- package/e2e_test/util.go +271 -0
- package/git-revision.txt +1 -1
- package/go.mod +22 -11
- package/go.sum +17 -13
- package/package.json +9 -5
- package/proto/agoric/swingset/genesis.proto +4 -0
- package/proto/agoric/swingset/swingset.proto +1 -1
- package/proto/agoric/vlocalchain/.clang-format +7 -0
- package/proto/agoric/vlocalchain/vlocalchain.proto +31 -0
- package/proto/agoric/vtransfer/genesis.proto +18 -0
- package/scripts/protocgen.sh +7 -8
- package/types/kv_entry_helpers.go +42 -0
- package/upgradegaia.sh +8 -8
- package/vm/action.go +5 -4
- package/vm/action_test.go +31 -11
- package/vm/client.go +113 -0
- package/vm/client_test.go +182 -0
- package/vm/controller.go +17 -40
- package/vm/core_proposals.go +22 -2
- package/vm/jsonrpcconn/jsonrpcconn.go +160 -0
- package/vm/jsonrpcconn/jsonrpcconn_test.go +126 -0
- package/vm/proto_json.go +38 -0
- package/vm/proto_json_test.go +103 -0
- package/vm/server.go +124 -0
- package/x/swingset/abci.go +10 -10
- package/x/swingset/alias.go +2 -0
- package/x/swingset/client/cli/tx.go +4 -0
- package/x/swingset/genesis.go +84 -24
- package/x/swingset/handler.go +2 -1
- package/x/swingset/keeper/extension_snapshotter.go +2 -2
- package/x/swingset/keeper/keeper.go +13 -25
- package/x/swingset/keeper/msg_server.go +18 -18
- package/x/swingset/keeper/proposal.go +3 -3
- package/x/swingset/keeper/querier.go +12 -11
- package/x/swingset/keeper/swing_store_exports_handler.go +21 -6
- package/x/swingset/keeper/test_utils.go +16 -0
- package/x/swingset/module.go +7 -7
- package/x/swingset/proposal_handler.go +2 -1
- package/x/swingset/testing/queue.go +17 -0
- package/x/swingset/types/default-params.go +1 -1
- package/x/swingset/types/expected_keepers.go +3 -2
- package/x/swingset/types/genesis.pb.go +78 -25
- package/x/swingset/types/msgs.go +44 -24
- package/x/swingset/types/params.go +2 -1
- package/x/swingset/types/proposal.go +5 -4
- package/x/swingset/types/swingset.pb.go +1 -1
- package/x/vbank/genesis.go +0 -2
- package/x/vbank/handler.go +2 -1
- package/x/vbank/keeper/querier.go +4 -3
- package/x/vbank/module.go +0 -5
- package/x/vbank/types/msgs.go +0 -12
- package/x/vbank/vbank.go +9 -9
- package/x/vbank/vbank_test.go +2 -2
- package/x/vibc/alias.go +3 -0
- package/x/vibc/handler.go +16 -9
- package/x/vibc/keeper/keeper.go +102 -65
- package/x/vibc/keeper/triggers.go +101 -0
- package/x/vibc/module.go +5 -8
- package/x/vibc/types/expected_keepers.go +13 -0
- package/x/vibc/types/ibc_module.go +336 -0
- package/x/vibc/types/receiver.go +170 -0
- package/x/vlocalchain/alias.go +19 -0
- package/x/vlocalchain/handler.go +21 -0
- package/x/vlocalchain/keeper/keeper.go +279 -0
- package/x/vlocalchain/keeper/keeper_test.go +97 -0
- package/x/vlocalchain/types/codec.go +34 -0
- package/x/vlocalchain/types/key.go +27 -0
- package/x/vlocalchain/types/msgs.go +16 -0
- package/x/vlocalchain/types/vlocalchain.pb.go +1072 -0
- package/x/vlocalchain/vlocalchain.go +114 -0
- package/x/vlocalchain/vlocalchain_test.go +434 -0
- package/x/vstorage/handler.go +2 -1
- package/x/vstorage/keeper/grpc_query.go +0 -1
- package/x/vstorage/keeper/keeper.go +13 -20
- package/x/vstorage/keeper/querier.go +6 -5
- package/x/vstorage/keeper/querier_test.go +4 -3
- package/x/vstorage/module.go +0 -5
- package/x/vstorage/testing/queue.go +27 -0
- package/x/vtransfer/alias.go +13 -0
- package/x/vtransfer/genesis.go +39 -0
- package/x/vtransfer/genesis_test.go +12 -0
- package/x/vtransfer/handler.go +20 -0
- package/x/vtransfer/ibc_middleware.go +186 -0
- package/x/vtransfer/ibc_middleware_test.go +448 -0
- package/x/vtransfer/keeper/keeper.go +281 -0
- package/x/vtransfer/module.go +124 -0
- package/x/vtransfer/types/expected_keepers.go +38 -0
- package/x/vtransfer/types/genesis.pb.go +327 -0
- package/x/vtransfer/types/key.go +9 -0
- package/x/vtransfer/types/msgs.go +9 -0
- package/ante/fee.go +0 -96
- package/proto/agoric/lien/genesis.proto +0 -25
- package/proto/agoric/lien/lien.proto +0 -25
- package/x/lien/alias.go +0 -17
- package/x/lien/genesis.go +0 -58
- package/x/lien/genesis_test.go +0 -101
- package/x/lien/keeper/account.go +0 -290
- package/x/lien/keeper/keeper.go +0 -255
- package/x/lien/keeper/keeper_test.go +0 -623
- package/x/lien/lien.go +0 -205
- package/x/lien/lien_test.go +0 -533
- package/x/lien/module.go +0 -115
- package/x/lien/spec/01_concepts.md +0 -146
- package/x/lien/spec/02_messages.md +0 -96
- package/x/lien/types/accountkeeper.go +0 -81
- package/x/lien/types/accountstate.go +0 -27
- package/x/lien/types/expected_keepers.go +0 -18
- package/x/lien/types/genesis.pb.go +0 -567
- package/x/lien/types/key.go +0 -25
- package/x/lien/types/lien.pb.go +0 -403
- package/x/vibc/ibc.go +0 -394
- /package/{src/index.cjs → index.cjs} +0 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
package vlocalchain
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"fmt"
|
|
7
|
+
|
|
8
|
+
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
9
|
+
|
|
10
|
+
"github.com/Agoric/agoric-sdk/golang/cosmos/vm"
|
|
11
|
+
"github.com/Agoric/agoric-sdk/golang/cosmos/x/vlocalchain/keeper"
|
|
12
|
+
"github.com/Agoric/agoric-sdk/golang/cosmos/x/vlocalchain/types"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
var _ vm.PortHandler = (*portHandler)(nil)
|
|
16
|
+
|
|
17
|
+
type portHandler struct {
|
|
18
|
+
keeper keeper.Keeper
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type portMessage struct {
|
|
22
|
+
Type string `json:"type"`
|
|
23
|
+
Address string `json:"address,omitempty"`
|
|
24
|
+
Messages json.RawMessage `json:"messages,omitempty"`
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
func NewReceiver(keeper keeper.Keeper) portHandler {
|
|
28
|
+
return portHandler{keeper: keeper}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
func (h portHandler) Receive(cctx context.Context, str string) (ret string, err error) {
|
|
32
|
+
var msg portMessage
|
|
33
|
+
err = json.Unmarshal([]byte(str), &msg)
|
|
34
|
+
if err != nil {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
switch msg.Type {
|
|
39
|
+
case "VLOCALCHAIN_ALLOCATE_ADDRESS":
|
|
40
|
+
addr := h.keeper.AllocateAddress(cctx)
|
|
41
|
+
var bz []byte
|
|
42
|
+
if bz, err = json.Marshal(addr.String()); err != nil {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
ret = string(bz)
|
|
46
|
+
|
|
47
|
+
case "VLOCALCHAIN_QUERY_MANY":
|
|
48
|
+
// Copy the JSON messages string into a CosmosTx object so we can
|
|
49
|
+
// deserialize it with just proto3 JSON.
|
|
50
|
+
cosmosTxBz := []byte(`{"messages":` + string(msg.Messages) + `}`)
|
|
51
|
+
|
|
52
|
+
var qms []types.QueryRequest
|
|
53
|
+
qms, err = h.keeper.DeserializeRequests(cosmosTxBz)
|
|
54
|
+
if err != nil {
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
var errs []error
|
|
59
|
+
resps := make([]interface{}, len(qms))
|
|
60
|
+
for i, qm := range qms {
|
|
61
|
+
var qr *types.QueryResponse
|
|
62
|
+
qr, err = h.keeper.Query(cctx, qm)
|
|
63
|
+
if err == nil {
|
|
64
|
+
// Only fill out the response if the query was successful.
|
|
65
|
+
resps[i] = qr
|
|
66
|
+
} else {
|
|
67
|
+
errs = append(errs, err) // Accumulate errors
|
|
68
|
+
resps[i] = &types.QueryResponse{Error: err.Error()}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
bz, err := vm.ProtoJSONMarshalSlice(resps)
|
|
73
|
+
if err != nil {
|
|
74
|
+
return "", err
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
switch len(errs) {
|
|
78
|
+
case 0:
|
|
79
|
+
err = nil
|
|
80
|
+
case 1:
|
|
81
|
+
err = errs[0]
|
|
82
|
+
case len(resps):
|
|
83
|
+
err = fmt.Errorf("all queries in batch failed: %v", errs)
|
|
84
|
+
default:
|
|
85
|
+
// Let them inspect the individual errors manually.
|
|
86
|
+
}
|
|
87
|
+
return string(bz), err
|
|
88
|
+
|
|
89
|
+
case "VLOCALCHAIN_EXECUTE_TX":
|
|
90
|
+
origCtx := sdk.UnwrapSDKContext(cctx)
|
|
91
|
+
|
|
92
|
+
// Copy the JSON messages string into a CosmosTx object so we can
|
|
93
|
+
// deserialize it with just proto3 JSON.
|
|
94
|
+
cosmosTxBz := []byte(`{"messages":` + string(msg.Messages) + `}`)
|
|
95
|
+
|
|
96
|
+
var msgs []sdk.Msg
|
|
97
|
+
if msgs, err = h.keeper.DeserializeTxMessages(cosmosTxBz); err != nil {
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
var resps []interface{}
|
|
102
|
+
resps, err = h.keeper.ExecuteTx(origCtx, msg.Address, msgs)
|
|
103
|
+
if err != nil {
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Marshal the responses to proto3 JSON.
|
|
108
|
+
bz, e := vm.ProtoJSONMarshalSlice(resps)
|
|
109
|
+
return string(bz), e
|
|
110
|
+
default:
|
|
111
|
+
err = fmt.Errorf("unrecognized message type %s", msg.Type)
|
|
112
|
+
}
|
|
113
|
+
return
|
|
114
|
+
}
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
package vlocalchain_test
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"strings"
|
|
7
|
+
"testing"
|
|
8
|
+
"time"
|
|
9
|
+
|
|
10
|
+
"github.com/Agoric/agoric-sdk/golang/cosmos/app/params"
|
|
11
|
+
"github.com/Agoric/agoric-sdk/golang/cosmos/vm"
|
|
12
|
+
"github.com/Agoric/agoric-sdk/golang/cosmos/x/vlocalchain"
|
|
13
|
+
"github.com/Agoric/agoric-sdk/golang/cosmos/x/vlocalchain/types"
|
|
14
|
+
|
|
15
|
+
"github.com/cosmos/cosmos-sdk/baseapp"
|
|
16
|
+
"github.com/cosmos/cosmos-sdk/store"
|
|
17
|
+
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
|
18
|
+
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
19
|
+
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
|
20
|
+
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
|
21
|
+
transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"
|
|
22
|
+
"github.com/tendermint/tendermint/libs/log"
|
|
23
|
+
|
|
24
|
+
"github.com/gogo/protobuf/jsonpb"
|
|
25
|
+
"github.com/gogo/protobuf/proto"
|
|
26
|
+
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
|
27
|
+
dbm "github.com/tendermint/tm-db"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
var (
|
|
31
|
+
vlocalchainStoreKey = sdk.NewKVStoreKey(types.StoreKey)
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
const (
|
|
35
|
+
firstAddr = "cosmos1uupflqrldlpkktssnzgp3r03ff6kz4u4kzd92pjgsfddye7grrlqt9rmmt"
|
|
36
|
+
msgAllocateAddress = `{"type":"VLOCALCHAIN_ALLOCATE_ADDRESS"}`
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
type mockBank struct {
|
|
40
|
+
banktypes.UnimplementedQueryServer
|
|
41
|
+
banktypes.UnimplementedMsgServer
|
|
42
|
+
balances map[string]sdk.Coins
|
|
43
|
+
failToSend error
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
var _ banktypes.QueryServer = (*mockBank)(nil)
|
|
47
|
+
var _ banktypes.MsgServer = (*mockBank)(nil)
|
|
48
|
+
|
|
49
|
+
func (b *mockBank) AllBalances(cctx context.Context, req *banktypes.QueryAllBalancesRequest) (*banktypes.QueryAllBalancesResponse, error) {
|
|
50
|
+
addr, err := sdk.AccAddressFromBech32(req.Address)
|
|
51
|
+
if err != nil {
|
|
52
|
+
return nil, err
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
var resp banktypes.QueryAllBalancesResponse
|
|
56
|
+
resp.Balances = sdk.Coins{}
|
|
57
|
+
if coins, ok := b.balances[addr.String()]; ok {
|
|
58
|
+
resp.Balances = coins
|
|
59
|
+
}
|
|
60
|
+
return &resp, nil
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
func (b *mockBank) Send(cctx context.Context, req *banktypes.MsgSend) (*banktypes.MsgSendResponse, error) {
|
|
64
|
+
if b.failToSend != nil {
|
|
65
|
+
return nil, b.failToSend
|
|
66
|
+
}
|
|
67
|
+
return &banktypes.MsgSendResponse{}, nil
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
type mockTransfer struct {
|
|
71
|
+
transfertypes.UnimplementedQueryServer
|
|
72
|
+
transfertypes.UnimplementedMsgServer
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
var _ transfertypes.QueryServer = (*mockTransfer)(nil)
|
|
76
|
+
var _ transfertypes.MsgServer = (*mockTransfer)(nil)
|
|
77
|
+
|
|
78
|
+
func (t *mockTransfer) Transfer(cctx context.Context, msg *transfertypes.MsgTransfer) (*transfertypes.MsgTransferResponse, error) {
|
|
79
|
+
return &transfertypes.MsgTransferResponse{Sequence: 1}, nil
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
type mockStaking struct {
|
|
83
|
+
stakingtypes.UnimplementedMsgServer
|
|
84
|
+
stakingtypes.UnimplementedQueryServer
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
var _ stakingtypes.MsgServer = (*mockStaking)(nil)
|
|
88
|
+
var _ stakingtypes.QueryServer = (*mockStaking)(nil)
|
|
89
|
+
|
|
90
|
+
func (s *mockStaking) Undelegate(cctx context.Context, msg *stakingtypes.MsgUndelegate) (*stakingtypes.MsgUndelegateResponse, error) {
|
|
91
|
+
return &stakingtypes.MsgUndelegateResponse{CompletionTime: time.Now().UTC()}, nil
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
func (s *mockStaking) UnbondingDelegation(cctx context.Context, req *stakingtypes.QueryUnbondingDelegationRequest) (*stakingtypes.QueryUnbondingDelegationResponse, error) {
|
|
95
|
+
unbondingDelegation := stakingtypes.UnbondingDelegation{
|
|
96
|
+
DelegatorAddress: req.DelegatorAddr,
|
|
97
|
+
ValidatorAddress: "cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj",
|
|
98
|
+
Entries: []stakingtypes.UnbondingDelegationEntry{
|
|
99
|
+
{
|
|
100
|
+
CreationHeight: 100,
|
|
101
|
+
CompletionTime: time.Now().UTC().Add(time.Hour * 24 * 7),
|
|
102
|
+
InitialBalance: sdk.NewInt(1000),
|
|
103
|
+
Balance: sdk.NewInt(500),
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
}
|
|
107
|
+
return &stakingtypes.QueryUnbondingDelegationResponse{Unbond: unbondingDelegation}, nil
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// makeTestKit creates a minimal Keeper and Context for use in testing.
|
|
111
|
+
func makeTestKit(bank *mockBank, transfer *mockTransfer, staking *mockStaking) (vm.PortHandler, context.Context) {
|
|
112
|
+
encodingConfig := params.MakeEncodingConfig()
|
|
113
|
+
cdc := encodingConfig.Marshaler
|
|
114
|
+
|
|
115
|
+
txRouter := baseapp.NewMsgServiceRouter()
|
|
116
|
+
txRouter.SetInterfaceRegistry(encodingConfig.InterfaceRegistry)
|
|
117
|
+
queryRouter := baseapp.NewGRPCQueryRouter()
|
|
118
|
+
queryRouter.SetInterfaceRegistry(encodingConfig.InterfaceRegistry)
|
|
119
|
+
|
|
120
|
+
banktypes.RegisterInterfaces(encodingConfig.InterfaceRegistry)
|
|
121
|
+
banktypes.RegisterMsgServer(txRouter, bank)
|
|
122
|
+
banktypes.RegisterQueryServer(queryRouter, bank)
|
|
123
|
+
transfertypes.RegisterInterfaces(encodingConfig.InterfaceRegistry)
|
|
124
|
+
transfertypes.RegisterMsgServer(txRouter, transfer)
|
|
125
|
+
transfertypes.RegisterQueryServer(queryRouter, transfer)
|
|
126
|
+
stakingtypes.RegisterInterfaces(encodingConfig.InterfaceRegistry)
|
|
127
|
+
stakingtypes.RegisterMsgServer(txRouter, staking)
|
|
128
|
+
stakingtypes.RegisterQueryServer(queryRouter, staking)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
// create a new Keeper
|
|
132
|
+
keeper := vlocalchain.NewKeeper(cdc, vlocalchainStoreKey, txRouter, queryRouter)
|
|
133
|
+
|
|
134
|
+
db := dbm.NewMemDB()
|
|
135
|
+
ms := store.NewCommitMultiStore(db)
|
|
136
|
+
ms.MountStoreWithDB(vlocalchainStoreKey, storetypes.StoreTypeIAVL, db)
|
|
137
|
+
err := ms.LoadLatestVersion()
|
|
138
|
+
if err != nil {
|
|
139
|
+
panic(err)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// create a new SDK Context
|
|
143
|
+
ctx := sdk.NewContext(ms, tmproto.Header{}, false, log.NewNopLogger()).WithBlockHeight(998)
|
|
144
|
+
|
|
145
|
+
handler := vm.NewProtectedPortHandler(vlocalchain.NewReceiver(keeper))
|
|
146
|
+
|
|
147
|
+
// create a new Go context
|
|
148
|
+
cctx := sdk.WrapSDKContext(ctx)
|
|
149
|
+
return handler, cctx
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
func TestAllocateAddress(t *testing.T) {
|
|
153
|
+
bank := &mockBank{}
|
|
154
|
+
transfer := &mockTransfer{}
|
|
155
|
+
staking := &mockStaking{}
|
|
156
|
+
handler, cctx := makeTestKit(bank, transfer, staking)
|
|
157
|
+
|
|
158
|
+
addrs := map[string]bool{
|
|
159
|
+
firstAddr: false,
|
|
160
|
+
"cosmos1yj40fakym8kf4wvgz9tky7k9f3v9msm3t7frscrmkjsdkxkpsfkqgeczkg": false,
|
|
161
|
+
"cosmos1s76vryj7m8k8nm9le65a4plhf5rym5sumtt2n0vwnk5l6k4cwuhsj56ujj": false,
|
|
162
|
+
"cosmos1c5hplwyxk5jr2dsygjqepzfqvfukwduq9c4660aah76krf99m6gs0k7hvl": false,
|
|
163
|
+
"cosmos1ys3a7mtna3cad0wxcs4ddukn37stexjdvns8jfdn4uerlr95y4xqnrypf6": false,
|
|
164
|
+
}
|
|
165
|
+
numToTest := len(addrs)
|
|
166
|
+
for i := 0; i < numToTest; i++ {
|
|
167
|
+
// receive the message
|
|
168
|
+
ret, err := handler.Receive(cctx, msgAllocateAddress)
|
|
169
|
+
if err != nil {
|
|
170
|
+
t.Fatalf("unexpected error[%d]: %v", i, err)
|
|
171
|
+
}
|
|
172
|
+
if ret == "" {
|
|
173
|
+
t.Fatalf("expected non-empty address[%d]", i)
|
|
174
|
+
}
|
|
175
|
+
var addr string
|
|
176
|
+
if err := json.Unmarshal([]byte(ret), &addr); err != nil {
|
|
177
|
+
t.Fatalf("unexpected error unmarshalling address string[%d]: %v: %v", i, ret, err)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
already, ok := addrs[addr]
|
|
181
|
+
if !ok {
|
|
182
|
+
t.Fatalf("unexpected address[%d]: %v", i, addr)
|
|
183
|
+
}
|
|
184
|
+
if already {
|
|
185
|
+
t.Fatalf("unexpected duplicate address[%d]: %v", i, addr)
|
|
186
|
+
}
|
|
187
|
+
addrs[addr] = true
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
func TestQuery(t *testing.T) {
|
|
192
|
+
alreadyAddr := sdk.MustBech32ifyAddressBytes("cosmos", []byte("already"))
|
|
193
|
+
nonexistentAddr := sdk.MustBech32ifyAddressBytes("cosmos", []byte("nonexistent"))
|
|
194
|
+
bank := &mockBank{balances: map[string]sdk.Coins{
|
|
195
|
+
firstAddr: []sdk.Coin{sdk.NewCoin("fresh", sdk.NewInt(123))},
|
|
196
|
+
alreadyAddr: []sdk.Coin{sdk.NewCoin("stale", sdk.NewInt(321))},
|
|
197
|
+
}}
|
|
198
|
+
transfer := &mockTransfer{}
|
|
199
|
+
staking := &mockStaking{}
|
|
200
|
+
handler, cctx := makeTestKit(bank, transfer, staking)
|
|
201
|
+
|
|
202
|
+
// get balances
|
|
203
|
+
testCases := []struct {
|
|
204
|
+
name string
|
|
205
|
+
addr string
|
|
206
|
+
failure string
|
|
207
|
+
expected sdk.Coins
|
|
208
|
+
}{
|
|
209
|
+
{"nonexistent", nonexistentAddr, "", sdk.Coins{}},
|
|
210
|
+
{"already", alreadyAddr, "", bank.balances[alreadyAddr]},
|
|
211
|
+
{"first", firstAddr, "", bank.balances[firstAddr]},
|
|
212
|
+
{"badaddr", "cosmos11111111111", "decoding bech32 failed: invalid separator index 16", sdk.Coins{}},
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
for _, tc := range testCases {
|
|
216
|
+
tc := tc
|
|
217
|
+
ctx := sdk.UnwrapSDKContext(cctx)
|
|
218
|
+
t.Run(tc.name, func(t *testing.T) {
|
|
219
|
+
msgGetBalances := `{"type":"VLOCALCHAIN_QUERY_MANY","messages":[{"@type":"/cosmos.bank.v1beta1.QueryAllBalancesRequest","address":"` + tc.addr + `"}]}`
|
|
220
|
+
t.Logf("query request: %v", msgGetBalances)
|
|
221
|
+
ret, err := handler.Receive(cctx, msgGetBalances)
|
|
222
|
+
t.Logf("query response: %v", ret)
|
|
223
|
+
if tc.failure != "" {
|
|
224
|
+
if err == nil {
|
|
225
|
+
t.Fatalf("expected error %v, not nil with return %v", tc.failure, ret)
|
|
226
|
+
} else if err.Error() != tc.failure {
|
|
227
|
+
t.Fatalf("expected error %v, not %v", tc.failure, err)
|
|
228
|
+
}
|
|
229
|
+
return
|
|
230
|
+
}
|
|
231
|
+
if err != nil {
|
|
232
|
+
t.Fatalf("unexpected error: %v", err)
|
|
233
|
+
}
|
|
234
|
+
if err == nil && ret == "" {
|
|
235
|
+
t.Fatalf("expected non-empty json")
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Unmarshal the responses.
|
|
239
|
+
s := `{"responses":` + ret + `}`
|
|
240
|
+
|
|
241
|
+
unmarshaler := jsonpb.Unmarshaler{}
|
|
242
|
+
var qrs types.QueryResponses
|
|
243
|
+
if err = unmarshaler.Unmarshal(strings.NewReader(s), &qrs); err != nil {
|
|
244
|
+
t.Fatalf("unexpected error unmarshalling reply: %v: %v", ret, err)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
resps := qrs.Responses
|
|
248
|
+
if len(resps) != 1 {
|
|
249
|
+
t.Fatalf("expected responses length 1, got %v", len(resps))
|
|
250
|
+
}
|
|
251
|
+
if resps[0].Error != "" {
|
|
252
|
+
t.Fatalf("unexpected error response: %v", resps[0].Error)
|
|
253
|
+
}
|
|
254
|
+
if resps[0].Height != ctx.BlockHeight() {
|
|
255
|
+
t.Fatalf("expected height %v, got %v", ctx.BlockHeight(), resps[0].Height)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Unmarshal the Any.
|
|
259
|
+
var pb banktypes.QueryAllBalancesResponse
|
|
260
|
+
if err = proto.Unmarshal(resps[0].Reply.Value, &pb); err != nil {
|
|
261
|
+
t.Fatalf("unexpected error unmarshalling reply: %v: %v", ret, err)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if !pb.Balances.IsEqual(tc.expected) {
|
|
265
|
+
t.Errorf("unexpected balance: expected %v, got %v", tc.expected, pb.Balances)
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
t.Run("UnbondingDelegation", func(t *testing.T) {
|
|
271
|
+
// create a new message
|
|
272
|
+
msg := `{"type":"VLOCALCHAIN_QUERY_MANY","messages":[{"@type":"/cosmos.staking.v1beta1.QueryUnbondingDelegationRequest","delegator_addr":"` + firstAddr + `","validator_addr":"cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj"}]}`
|
|
273
|
+
t.Logf("query request: %v", msg)
|
|
274
|
+
ret, err := handler.Receive(cctx, msg)
|
|
275
|
+
t.Logf("query response: %v", ret)
|
|
276
|
+
if err != nil {
|
|
277
|
+
t.Fatalf("unexpected error: %v", err)
|
|
278
|
+
}
|
|
279
|
+
if ret == "" {
|
|
280
|
+
t.Fatalf("expected non-empty json")
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Unmarshal the JSON response
|
|
284
|
+
var respJSON []map[string]interface{}
|
|
285
|
+
if err := json.Unmarshal([]byte(ret), &respJSON); err != nil {
|
|
286
|
+
t.Fatalf("unexpected error unmarshalling JSON response: %v", err)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Check the response fields
|
|
290
|
+
if len(respJSON) != 1 {
|
|
291
|
+
t.Fatalf("expected 1 response, got %d", len(respJSON))
|
|
292
|
+
}
|
|
293
|
+
resp := respJSON[0]
|
|
294
|
+
|
|
295
|
+
replyAny, ok := resp["reply"].(map[string]interface{})
|
|
296
|
+
if !ok {
|
|
297
|
+
t.Fatalf("expected reply field to be a map, got %v", resp["reply"])
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
unbond, ok := replyAny["unbond"].(map[string]interface{})
|
|
301
|
+
if !ok {
|
|
302
|
+
t.Fatalf("expected unbond field to be a map, got %v", replyAny["unbond"])
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Check the field names and values
|
|
306
|
+
if unbond["delegatorAddress"] != firstAddr {
|
|
307
|
+
t.Errorf("expected delegatorAddress %s, got %v", firstAddr, unbond["delegator_address"])
|
|
308
|
+
}
|
|
309
|
+
if unbond["validatorAddress"] != "cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj" {
|
|
310
|
+
t.Errorf("expected validatorAddress cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj, got %v", unbond["validator_address"])
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
entries, ok := unbond["entries"].([]interface{})
|
|
314
|
+
if !ok || len(entries) != 1 {
|
|
315
|
+
t.Fatalf("expected 1 unbonding delegation entry, got %v", entries)
|
|
316
|
+
}
|
|
317
|
+
entry, ok := entries[0].(map[string]interface{})
|
|
318
|
+
if !ok {
|
|
319
|
+
t.Fatalf("expected unbonding delegation entry to be a map, got %v", entries[0])
|
|
320
|
+
}
|
|
321
|
+
if entry["creationHeight"] != "100" {
|
|
322
|
+
t.Errorf("expected creationHeight \"100\", got %v", entry["creation_height"])
|
|
323
|
+
}
|
|
324
|
+
if entry["balance"] != "500" {
|
|
325
|
+
t.Errorf("expected balance \"500\", got %v", entry["balance"])
|
|
326
|
+
}
|
|
327
|
+
if _, ok := entry["completionTime"]; !ok {
|
|
328
|
+
t.Error("expected completionTime field in the response")
|
|
329
|
+
}
|
|
330
|
+
})
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
func TestExecuteTx(t *testing.T) {
|
|
334
|
+
alreadyAddr := sdk.MustBech32ifyAddressBytes("cosmos", []byte("already"))
|
|
335
|
+
bank := &mockBank{balances: map[string]sdk.Coins{
|
|
336
|
+
firstAddr: []sdk.Coin{sdk.NewCoin("fresh", sdk.NewInt(123))},
|
|
337
|
+
alreadyAddr: []sdk.Coin{sdk.NewCoin("stale", sdk.NewInt(321))},
|
|
338
|
+
}}
|
|
339
|
+
transfer := &mockTransfer{}
|
|
340
|
+
staking := &mockStaking{}
|
|
341
|
+
handler, cctx := makeTestKit(bank, transfer, staking)
|
|
342
|
+
|
|
343
|
+
// create a new message
|
|
344
|
+
msg := `{"type":"VLOCALCHAIN_ALLOCATE_ADDRESS"}`
|
|
345
|
+
ret, err := handler.Receive(cctx, msg)
|
|
346
|
+
if err != nil {
|
|
347
|
+
t.Fatalf("unexpected error: %s", err)
|
|
348
|
+
}
|
|
349
|
+
if ret == "" {
|
|
350
|
+
t.Fatalf("expected non-empty json")
|
|
351
|
+
}
|
|
352
|
+
var addr string
|
|
353
|
+
if err := json.Unmarshal([]byte(ret), &addr); err != nil {
|
|
354
|
+
t.Fatalf("unexpected error unmarshalling address string: %v: %s", ret, err)
|
|
355
|
+
}
|
|
356
|
+
if addr != firstAddr {
|
|
357
|
+
t.Fatalf("expected address %v, got %v", firstAddr, addr)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
testCases := []struct {
|
|
361
|
+
name string
|
|
362
|
+
signerAddress string
|
|
363
|
+
fromAddress string
|
|
364
|
+
toAddress string
|
|
365
|
+
failure string
|
|
366
|
+
}{
|
|
367
|
+
{"valid", addr, addr, alreadyAddr, ""},
|
|
368
|
+
{"parse error", `"` + addr, firstAddr, alreadyAddr, "invalid character 'c' after object key:value pair"},
|
|
369
|
+
{"invalid address", addr, alreadyAddr, alreadyAddr, "required signer cosmos1v9k8yetpv3us7src8u does not match actual signer"},
|
|
370
|
+
{"unauth", alreadyAddr, addr, alreadyAddr, "required signer cosmos1uupflqrldlpkktssnzgp3r03ff6kz4u4kzd92pjgsfddye7grrlqt9rmmt does not match actual signer"},
|
|
371
|
+
}
|
|
372
|
+
for _, tc := range testCases {
|
|
373
|
+
tc := tc
|
|
374
|
+
t.Run(tc.name, func(t *testing.T) {
|
|
375
|
+
|
|
376
|
+
// create a new message
|
|
377
|
+
msg := `{"type":"VLOCALCHAIN_EXECUTE_TX","address":"` + tc.signerAddress +
|
|
378
|
+
`","messages":[{"@type":"/cosmos.bank.v1beta1.MsgSend","from_address":"` +
|
|
379
|
+
tc.fromAddress + `","to_address":"` + tc.toAddress +
|
|
380
|
+
`","amount":[{"denom":"fresh","amount":"100"}]}]}`
|
|
381
|
+
|
|
382
|
+
ret, err = handler.Receive(cctx, msg)
|
|
383
|
+
if tc.failure != "" {
|
|
384
|
+
if err == nil {
|
|
385
|
+
t.Fatalf("expected error %v, not nil with return %v", tc.failure, ret)
|
|
386
|
+
}
|
|
387
|
+
if err.Error() != tc.failure {
|
|
388
|
+
t.Fatalf("expected error %v, not %v", tc.failure, err)
|
|
389
|
+
}
|
|
390
|
+
return
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if err != nil {
|
|
394
|
+
t.Fatalf("unexpected error: %s", err)
|
|
395
|
+
}
|
|
396
|
+
if ret == "" {
|
|
397
|
+
t.Fatalf("expected non-empty json")
|
|
398
|
+
}
|
|
399
|
+
if ret != "[{}]" {
|
|
400
|
+
t.Fatalf("expected response [{}], not %v", ret)
|
|
401
|
+
}
|
|
402
|
+
})
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
t.Run("MsgUndelegate", func(t *testing.T) {
|
|
406
|
+
// create a new message
|
|
407
|
+
msg := `{"type":"VLOCALCHAIN_EXECUTE_TX","address":"` + addr +
|
|
408
|
+
`","messages":[{"@type":"/cosmos.staking.v1beta1.MsgUndelegate","delegatorAddress":"` +
|
|
409
|
+
addr + `","validatorAddress":"cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj","amount":{"denom":"stake","amount":"100"}}]}`
|
|
410
|
+
|
|
411
|
+
ret, err := handler.Receive(cctx, msg)
|
|
412
|
+
if err != nil {
|
|
413
|
+
t.Fatalf("unexpected error: %s", err)
|
|
414
|
+
}
|
|
415
|
+
if ret == "" {
|
|
416
|
+
t.Fatalf("expected non-empty json")
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Unmarshal the response
|
|
420
|
+
var resp []map[string]interface{}
|
|
421
|
+
if err := json.Unmarshal([]byte(ret), &resp); err != nil {
|
|
422
|
+
t.Fatalf("unexpected error unmarshalling response: %v", err)
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Check the response fields
|
|
426
|
+
if len(resp) != 1 {
|
|
427
|
+
t.Fatalf("expected 1 response, got %d", len(resp))
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if _, ok := resp[0]["completionTime"]; !ok {
|
|
431
|
+
t.Error("expected 'completionTime' field in response")
|
|
432
|
+
}
|
|
433
|
+
})
|
|
434
|
+
}
|
package/x/vstorage/handler.go
CHANGED
|
@@ -3,6 +3,7 @@ package vstorage
|
|
|
3
3
|
import (
|
|
4
4
|
"fmt"
|
|
5
5
|
|
|
6
|
+
sdkioerrors "cosmossdk.io/errors"
|
|
6
7
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
7
8
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
8
9
|
)
|
|
@@ -11,6 +12,6 @@ import (
|
|
|
11
12
|
func NewHandler(k Keeper) sdk.Handler {
|
|
12
13
|
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
|
|
13
14
|
errMsg := fmt.Sprintf("Unrecognized vstorage Msg type: %T", msg)
|
|
14
|
-
return nil,
|
|
15
|
+
return nil, sdkioerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg)
|
|
15
16
|
}
|
|
16
17
|
}
|
|
@@ -94,7 +94,6 @@ var capDataRemotableValueFormats = map[string]string{
|
|
|
94
94
|
// }
|
|
95
95
|
//
|
|
96
96
|
// ```
|
|
97
|
-
// cf. https://github.com/Agoric/agoric-sdk/blob/6e5b422b80e47c4dac151404f43faea5ab41e9b0/scripts/get-flattened-publication.sh
|
|
98
97
|
func flatten(input interface{}, output map[string]interface{}, key string, top bool) error {
|
|
99
98
|
// Act on the raw representation of a Remotable.
|
|
100
99
|
if remotable, ok := input.(*capdata.CapdataRemotable); ok {
|
|
@@ -10,6 +10,7 @@ import (
|
|
|
10
10
|
"strconv"
|
|
11
11
|
"strings"
|
|
12
12
|
|
|
13
|
+
sdkmath "cosmossdk.io/math"
|
|
13
14
|
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
|
14
15
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
15
16
|
db "github.com/tendermint/tm-db"
|
|
@@ -21,8 +22,8 @@ import (
|
|
|
21
22
|
// StreamCell is an envelope representing a sequence of values written at a path in a single block.
|
|
22
23
|
// It is persisted to storage as a { "blockHeight": "<digits>", "values": ["...", ...] } JSON text
|
|
23
24
|
// that off-chain consumers rely upon.
|
|
24
|
-
// Many of those consumers *also* rely upon the strings of "values" being valid JSON text
|
|
25
|
-
//
|
|
25
|
+
// Many of those consumers *also* rely upon the strings of "values" being valid JSON text,
|
|
26
|
+
// but we do not enforce that in this package.
|
|
26
27
|
type StreamCell struct {
|
|
27
28
|
BlockHeight string `json:"blockHeight"`
|
|
28
29
|
Values []string `json:"values"`
|
|
@@ -51,14 +52,6 @@ var _ ChangeManager = (*BatchingChangeManager)(nil)
|
|
|
51
52
|
// 2 ** 256 - 1
|
|
52
53
|
var MaxSDKInt = sdk.NewIntFromBigInt(new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1)))
|
|
53
54
|
|
|
54
|
-
// TODO: Use bytes.CutPrefix once we can rely upon go >= 1.20.
|
|
55
|
-
func cutPrefix(s, prefix []byte) (after []byte, found bool) {
|
|
56
|
-
if !bytes.HasPrefix(s, prefix) {
|
|
57
|
-
return s, false
|
|
58
|
-
}
|
|
59
|
-
return s[len(prefix):], true
|
|
60
|
-
}
|
|
61
|
-
|
|
62
55
|
// Keeper maintains the link to data storage and exposes getter/setter methods
|
|
63
56
|
// for the various parts of the state machine
|
|
64
57
|
type Keeper struct {
|
|
@@ -163,7 +156,7 @@ func (k Keeper) ExportStorageFromPrefix(ctx sdk.Context, pathPrefix string) []*t
|
|
|
163
156
|
if !strings.HasPrefix(path, pathPrefix) {
|
|
164
157
|
continue
|
|
165
158
|
}
|
|
166
|
-
value, hasPrefix :=
|
|
159
|
+
value, hasPrefix := bytes.CutPrefix(rawValue, types.EncodedDataPrefix)
|
|
167
160
|
if !hasPrefix {
|
|
168
161
|
panic(fmt.Errorf("value at path %q starts with unexpected prefix", path))
|
|
169
162
|
}
|
|
@@ -265,7 +258,7 @@ func (k Keeper) GetEntry(ctx sdk.Context, path string) agoric.KVEntry {
|
|
|
265
258
|
if bytes.Equal(rawValue, types.EncodedNoDataValue) {
|
|
266
259
|
return agoric.NewKVEntryWithNoValue(path)
|
|
267
260
|
}
|
|
268
|
-
value, hasPrefix :=
|
|
261
|
+
value, hasPrefix := bytes.CutPrefix(rawValue, types.EncodedDataPrefix)
|
|
269
262
|
if !hasPrefix {
|
|
270
263
|
panic(fmt.Errorf("value at path %q starts with unexpected prefix", path))
|
|
271
264
|
}
|
|
@@ -428,7 +421,7 @@ func (k Keeper) GetNoDataValue() []byte {
|
|
|
428
421
|
return types.EncodedNoDataValue
|
|
429
422
|
}
|
|
430
423
|
|
|
431
|
-
func (k Keeper)
|
|
424
|
+
func (k Keeper) GetIntValue(ctx sdk.Context, path string) (sdkmath.Int, error) {
|
|
432
425
|
indexEntry := k.GetEntry(ctx, path)
|
|
433
426
|
if !indexEntry.HasValue() {
|
|
434
427
|
return sdk.NewInt(0), nil
|
|
@@ -441,14 +434,14 @@ func (k Keeper) getIntValue(ctx sdk.Context, path string) (sdk.Int, error) {
|
|
|
441
434
|
return index, nil
|
|
442
435
|
}
|
|
443
436
|
|
|
444
|
-
func (k Keeper) GetQueueLength(ctx sdk.Context, queuePath string) (
|
|
445
|
-
head, err := k.
|
|
437
|
+
func (k Keeper) GetQueueLength(ctx sdk.Context, queuePath string) (sdkmath.Int, error) {
|
|
438
|
+
head, err := k.GetIntValue(ctx, queuePath+".head")
|
|
446
439
|
if err != nil {
|
|
447
|
-
return
|
|
440
|
+
return sdkmath.NewInt(0), err
|
|
448
441
|
}
|
|
449
|
-
tail, err := k.
|
|
442
|
+
tail, err := k.GetIntValue(ctx, queuePath+".tail")
|
|
450
443
|
if err != nil {
|
|
451
|
-
return
|
|
444
|
+
return sdkmath.NewInt(0), err
|
|
452
445
|
}
|
|
453
446
|
// The tail index is exclusive
|
|
454
447
|
return tail.Sub(head), nil
|
|
@@ -457,12 +450,12 @@ func (k Keeper) GetQueueLength(ctx sdk.Context, queuePath string) (sdk.Int, erro
|
|
|
457
450
|
func (k Keeper) PushQueueItem(ctx sdk.Context, queuePath string, value string) error {
|
|
458
451
|
// Get the current queue tail, defaulting to zero if its vstorage doesn't exist.
|
|
459
452
|
// The `tail` is the value of the next index to be inserted
|
|
460
|
-
tail, err := k.
|
|
453
|
+
tail, err := k.GetIntValue(ctx, queuePath+".tail")
|
|
461
454
|
if err != nil {
|
|
462
455
|
return err
|
|
463
456
|
}
|
|
464
457
|
|
|
465
|
-
if tail.
|
|
458
|
+
if tail.GTE(MaxSDKInt) {
|
|
466
459
|
return errors.New(queuePath + " overflow")
|
|
467
460
|
}
|
|
468
461
|
nextTail := tail.Add(sdk.NewInt(1))
|