@agoric/cosmos 0.35.0-upgrade-14-dev-0169c7e.0 → 0.35.0-upgrade-16-dev-07b0130.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.
Files changed (169) hide show
  1. package/CHANGELOG.md +121 -77
  2. package/MAINTAINERS.md +3 -0
  3. package/Makefile +49 -26
  4. package/ante/ante.go +11 -11
  5. package/ante/inbound_test.go +3 -2
  6. package/ante/vm_admission.go +2 -1
  7. package/app/app.go +260 -175
  8. package/app/export.go +13 -6
  9. package/app/upgrade.go +76 -0
  10. package/cmd/agd/agvm.go +42 -0
  11. package/cmd/agd/main.go +132 -11
  12. package/cmd/libdaemon/main.go +67 -53
  13. package/cmd/libdaemon/main_test.go +2 -1
  14. package/daemon/cmd/genaccounts.go +13 -9
  15. package/daemon/cmd/root.go +186 -73
  16. package/daemon/cmd/root_test.go +190 -2
  17. package/daemon/cmd/testnet.go +17 -6
  18. package/daemon/main.go +6 -3
  19. package/e2e_test/Makefile +29 -0
  20. package/e2e_test/README.md +100 -0
  21. package/e2e_test/go.mod +217 -0
  22. package/e2e_test/go.sum +1323 -0
  23. package/e2e_test/ibc_conformance_test.go +56 -0
  24. package/e2e_test/pfm_test.go +613 -0
  25. package/e2e_test/util.go +271 -0
  26. package/git-revision.txt +1 -1
  27. package/go.mod +110 -68
  28. package/go.sum +601 -248
  29. package/package.json +9 -5
  30. package/proto/agoric/swingset/genesis.proto +4 -0
  31. package/proto/agoric/swingset/swingset.proto +1 -1
  32. package/proto/agoric/vlocalchain/.clang-format +7 -0
  33. package/proto/agoric/vlocalchain/vlocalchain.proto +31 -0
  34. package/proto/agoric/vstorage/query.proto +53 -1
  35. package/proto/agoric/vtransfer/genesis.proto +18 -0
  36. package/scripts/protocgen.sh +16 -6
  37. package/third_party/proto/buf.yaml +1 -0
  38. package/third_party/proto/cosmos/base/query/v1beta1/pagination.proto +4 -1
  39. package/third_party/proto/cosmos/base/v1beta1/coin.proto +7 -4
  40. package/third_party/proto/cosmos/upgrade/v1beta1/upgrade.proto +16 -6
  41. package/third_party/proto/cosmos_proto/cosmos.proto +97 -0
  42. package/third_party/proto/google/api/annotations.proto +1 -1
  43. package/third_party/proto/google/api/http.proto +181 -120
  44. package/third_party/proto/google/api/httpbody.proto +9 -6
  45. package/third_party/proto/google/protobuf/any.proto +1 -7
  46. package/third_party/proto/ibc/core/channel/v1/channel.proto +15 -1
  47. package/third_party/proto/ibc/core/client/v1/client.proto +9 -6
  48. package/types/kv_entry_helpers.go +42 -0
  49. package/upgradegaia.sh +21 -12
  50. package/vm/action.go +28 -24
  51. package/vm/action_test.go +36 -16
  52. package/vm/client.go +113 -0
  53. package/vm/client_test.go +182 -0
  54. package/vm/controller.go +18 -42
  55. package/vm/core_proposals.go +22 -2
  56. package/vm/jsonrpcconn/jsonrpcconn.go +160 -0
  57. package/vm/jsonrpcconn/jsonrpcconn_test.go +126 -0
  58. package/vm/proto_json.go +38 -0
  59. package/vm/proto_json_test.go +103 -0
  60. package/vm/server.go +124 -0
  61. package/x/swingset/abci.go +10 -10
  62. package/x/swingset/alias.go +2 -0
  63. package/x/swingset/client/cli/query.go +2 -2
  64. package/x/swingset/client/cli/tx.go +52 -33
  65. package/x/swingset/client/proposal_handler.go +2 -17
  66. package/x/swingset/genesis.go +84 -24
  67. package/x/swingset/handler.go +2 -1
  68. package/x/swingset/keeper/extension_snapshotter.go +2 -2
  69. package/x/swingset/keeper/keeper.go +21 -36
  70. package/x/swingset/keeper/keeper_test.go +1 -1
  71. package/x/swingset/keeper/msg_server.go +20 -22
  72. package/x/swingset/keeper/proposal.go +13 -3
  73. package/x/swingset/keeper/querier.go +23 -14
  74. package/x/swingset/keeper/swing_store_exports_handler.go +21 -6
  75. package/x/swingset/keeper/test_utils.go +16 -0
  76. package/x/swingset/module.go +7 -7
  77. package/x/swingset/proposal_handler.go +5 -4
  78. package/x/swingset/swingset.go +4 -2
  79. package/x/swingset/testing/queue.go +17 -0
  80. package/x/swingset/types/codec.go +2 -2
  81. package/x/swingset/types/default-params.go +1 -1
  82. package/x/swingset/types/expected_keepers.go +3 -2
  83. package/x/swingset/types/genesis.pb.go +78 -25
  84. package/x/swingset/types/msgs.go +44 -24
  85. package/x/swingset/types/msgs.pb.go +16 -16
  86. package/x/swingset/types/params.go +2 -1
  87. package/x/swingset/types/proposal.go +10 -9
  88. package/x/swingset/types/swingset.pb.go +1 -1
  89. package/x/swingset/types/types.go +30 -28
  90. package/x/vbank/genesis.go +0 -2
  91. package/x/vbank/handler.go +2 -1
  92. package/x/vbank/keeper/keeper.go +3 -2
  93. package/x/vbank/keeper/querier.go +9 -4
  94. package/x/vbank/keeper/rewards.go +1 -1
  95. package/x/vbank/module.go +0 -5
  96. package/x/vbank/types/msgs.go +0 -12
  97. package/x/vbank/vbank.go +20 -19
  98. package/x/vbank/vbank_test.go +10 -10
  99. package/x/vibc/alias.go +3 -0
  100. package/x/vibc/handler.go +16 -9
  101. package/x/vibc/keeper/keeper.go +112 -74
  102. package/x/vibc/keeper/triggers.go +101 -0
  103. package/x/vibc/module.go +5 -8
  104. package/x/vibc/types/expected_keepers.go +26 -5
  105. package/x/vibc/types/ibc_module.go +336 -0
  106. package/x/vibc/types/msgs.go +1 -1
  107. package/x/vibc/types/msgs.pb.go +1 -1
  108. package/x/vibc/types/receiver.go +170 -0
  109. package/x/vlocalchain/alias.go +19 -0
  110. package/x/vlocalchain/handler.go +21 -0
  111. package/x/vlocalchain/keeper/keeper.go +279 -0
  112. package/x/vlocalchain/keeper/keeper_test.go +97 -0
  113. package/x/vlocalchain/types/codec.go +34 -0
  114. package/x/vlocalchain/types/key.go +27 -0
  115. package/x/vlocalchain/types/msgs.go +16 -0
  116. package/x/vlocalchain/types/vlocalchain.pb.go +1072 -0
  117. package/x/vlocalchain/vlocalchain.go +114 -0
  118. package/x/vlocalchain/vlocalchain_test.go +434 -0
  119. package/x/vstorage/README.md +138 -0
  120. package/x/vstorage/capdata/capdata.go +298 -0
  121. package/x/vstorage/capdata/capdata_test.go +352 -0
  122. package/x/vstorage/client/cli/query.go +51 -4
  123. package/x/vstorage/handler.go +2 -1
  124. package/x/vstorage/keeper/grpc_query.go +220 -0
  125. package/x/vstorage/keeper/keeper.go +16 -22
  126. package/x/vstorage/keeper/keeper_grpc_test.go +300 -0
  127. package/x/vstorage/keeper/keeper_test.go +1 -1
  128. package/x/vstorage/keeper/querier.go +11 -6
  129. package/x/vstorage/keeper/querier_test.go +4 -3
  130. package/x/vstorage/module.go +0 -5
  131. package/x/vstorage/testing/queue.go +27 -0
  132. package/x/vstorage/types/query.pb.go +646 -36
  133. package/x/vstorage/types/query.pb.gw.go +119 -0
  134. package/x/vstorage/vstorage.go +16 -15
  135. package/x/vstorage/vstorage_test.go +5 -5
  136. package/x/vtransfer/alias.go +13 -0
  137. package/x/vtransfer/genesis.go +39 -0
  138. package/x/vtransfer/genesis_test.go +12 -0
  139. package/x/vtransfer/handler.go +20 -0
  140. package/x/vtransfer/ibc_middleware.go +186 -0
  141. package/x/vtransfer/ibc_middleware_test.go +448 -0
  142. package/x/vtransfer/keeper/keeper.go +281 -0
  143. package/x/vtransfer/module.go +124 -0
  144. package/x/vtransfer/types/expected_keepers.go +38 -0
  145. package/x/vtransfer/types/genesis.pb.go +327 -0
  146. package/x/vtransfer/types/key.go +9 -0
  147. package/x/vtransfer/types/msgs.go +9 -0
  148. package/ante/fee.go +0 -96
  149. package/proto/agoric/lien/genesis.proto +0 -25
  150. package/proto/agoric/lien/lien.proto +0 -25
  151. package/x/lien/alias.go +0 -17
  152. package/x/lien/genesis.go +0 -58
  153. package/x/lien/genesis_test.go +0 -101
  154. package/x/lien/keeper/account.go +0 -290
  155. package/x/lien/keeper/keeper.go +0 -254
  156. package/x/lien/keeper/keeper_test.go +0 -623
  157. package/x/lien/lien.go +0 -203
  158. package/x/lien/lien_test.go +0 -529
  159. package/x/lien/module.go +0 -115
  160. package/x/lien/spec/01_concepts.md +0 -146
  161. package/x/lien/spec/02_messages.md +0 -96
  162. package/x/lien/types/accountkeeper.go +0 -81
  163. package/x/lien/types/accountstate.go +0 -27
  164. package/x/lien/types/expected_keepers.go +0 -18
  165. package/x/lien/types/genesis.pb.go +0 -567
  166. package/x/lien/types/key.go +0 -25
  167. package/x/lien/types/lien.pb.go +0 -403
  168. package/x/vibc/ibc.go +0 -393
  169. /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
+ }
@@ -0,0 +1,138 @@
1
+ # Virtual Storage
2
+
3
+ This module manages "[IAVL](https://github.com/cosmos/iavl)" chain storage data with a hierarchical keyspace in which each key is a "[path](./types/path_keys.go)" composed of zero or more dot-separated nonempty segments in a restricted alphabet. It exposes gRPC endpoints to arbitrary external clients for reading data, and internal read/write interfaces for use by SwingSet (which itself manages further subtree-scoped attenuation).
4
+
5
+ ## Internal Go interface
6
+
7
+ [Keeper](./keeper/keeper.go)
8
+ * generic
9
+ * GetChildren
10
+ * GetEntry
11
+ * HasEntry
12
+ * HasStorage
13
+ * SetStorage[AndNotify]
14
+ * StreamCell-oriented (a StreamCell captures a block height and an array of values)
15
+ * AppendStorageValue[AndNotify]
16
+ * queue-oriented (a queue stores items at paths like "$prefix.$n", documenting
17
+ the n for the next item to be consumed at "$prefix.head" and the n for the next
18
+ next item to be pushed at "$prefix.tail" such that the queue is empty when both
19
+ head and tail store the same n)
20
+ * GetQueueLength
21
+ * PushQueueItem
22
+
23
+ ## Internal JSON interface
24
+
25
+ This is used by the SwingSet "bridge".
26
+
27
+ [Receive](./vstorage.go) with input `{ "method": "...", "args": [...] }`
28
+ * generic
29
+ * method "entries", args path
30
+ * method "get"/"has", args path
31
+ * method "set"/"setWithoutNotify", args [[path, value?], ...]
32
+ * method "children", args path
33
+ * method "values", args path (returns values for children in the same order as method "children")
34
+ * method "size", args path (returns the count of children)
35
+ * StreamCell-oriented
36
+ * method "append", args [[path, value?], ...]
37
+
38
+ ## CLI
39
+
40
+ A blockchain node may be interrogated by RPC using `agd [--node $url] query vstorage path` via [client/cli](./client/cli/query.go). (See command help for options and variants `data` and `children`.)
41
+
42
+ Examples:
43
+ ```sh
44
+ $ agd --node https://main.rpc.agoric.net:443/ query vstorage path published.reserve.
45
+ children:
46
+ - governance
47
+ - metrics
48
+ pagination: null
49
+
50
+ $ agd --node https://main.rpc.agoric.net:443/ query vstorage path -o json published.reserve.
51
+ {"children":["governance","metrics"],"pagination":null}
52
+
53
+ $ agd --node https://main.rpc.agoric.net:443/ query vstorage path published.reserve.metrics
54
+ value: '{"blockHeight":"11030240","values":["{\"body\":\"#{\\\"allocations\\\":{\\\"Fee\\\":{\\\"brand\\\":\\\"$0.Alleged:
55
+ IST brand\\\",\\\"value\\\":\\\"+20053582387\\\"}},\\\"shortfallBalance\\\":{\\\"brand\\\":\\\"$0\\\",\\\"value\\\":\\\"+0\\\"},\\\"totalFeeBurned\\\":{\\\"brand\\\":\\\"$0\\\",\\\"value\\\":\\\"+0\\\"},\\\"totalFeeMinted\\\":{\\\"brand\\\":\\\"$0\\\",\\\"value\\\":\\\"+0\\\"}}\",\"slots\":[\"board0257\"]}"]}'
56
+ ```
57
+
58
+ ## External protobuf interface
59
+
60
+ RPC via [Querier](./keeper/grpc_query.go),
61
+ and [CometBFT method "abci_query"](https://docs.cometbft.com/main/rpc/#/ABCI/abci_query)
62
+ with params `path` "/agoric.vstorage.Query/..."
63
+ and `data` \<serialized protobuf per [vstorage/query.proto](../../proto/agoric/vstorage/query.proto)>
64
+ (also via [Querier](./keeper/grpc_query.go))
65
+ * /agoric.vstorage.Query/CapData
66
+ * /agoric.vstorage.Query/Children
67
+ * /agoric.vstorage.Query/Data
68
+
69
+ Example:
70
+ ```sh
71
+ $ curl -sS 'https://main.rpc.agoric.net/' -H 'Content-Type: application/json' -X POST --data "$(
72
+ jq -n --arg queryChildrenRequestHex 0a147075626c69736865642e636f6d6d697474656573 '{
73
+ id: 1,
74
+ method: "abci_query",
75
+ params: { path: "/agoric.vstorage.Query/Children", data: $queryChildrenRequestHex }
76
+ }' | \
77
+ tee /dev/stderr \
78
+ )" | \
79
+ jq . | \
80
+ tee /dev/stderr | \
81
+ jq -r '.result.response.value' | \
82
+ base64 -d | \
83
+ protoc -I golang/cosmos/proto/agoric/vstorage/ -I golang/cosmos/third_party/proto/ \
84
+ --decode=agoric.vstorage.QueryChildrenResponse golang/cosmos/proto/agoric/vstorage/query.proto
85
+ {
86
+ "id": 1,
87
+ "method": "abci_query",
88
+ "params": {
89
+ "path": "/agoric.vstorage.Query/Children",
90
+ "data": "0a147075626c69736865642e636f6d6d697474656573"
91
+ }
92
+ }
93
+ {
94
+ "jsonrpc": "2.0",
95
+ "id": 1,
96
+ "result": {
97
+ "response": {
98
+ "code": 0,
99
+ "log": "",
100
+ "info": "",
101
+ "index": "0",
102
+ "key": null,
103
+ "value": "ChJFY29ub21pY19Db21taXR0ZWUKCWtyZWFkLWdvdg==",
104
+ "proofOps": null,
105
+ "height": "12222836",
106
+ "codespace": ""
107
+ }
108
+ }
109
+ }
110
+ children: "Economic_Committee"
111
+ children: "kread-gov"
112
+ ```
113
+
114
+ ## External JSON interface
115
+
116
+ As described at [Cosmos SDK: Using the REST Endpoints](https://docs.cosmos.network/main/run-node/interact-node#using-the-rest-endpoints), a blockchain node whose [`app.toml` configuration](https://docs.cosmos.network/main/run-node/run-node#configuring-the-node-using-apptoml-and-configtoml) enables the "REST" API server uses [gRPC-Gateway](https://grpc-ecosystem.github.io/grpc-gateway/) and `google.api.http` annotations in [vstorage/query.proto](../../proto/agoric/vstorage/query.proto) to automatically translate the protobuf-based RPC endpoints into URL paths that accept query parameters and emit JSON.
117
+ * /agoric/vstorage/capdata/$path?remotableValueFormat={object,string}[&mediaType=JSON%20Lines][&itemFormat=flat]
118
+ * /agoric/vstorage/children/$path
119
+ * /agoric/vstorage/data/$path
120
+
121
+ Example:
122
+ ```sh
123
+ $ curl -sS 'https://main.api.agoric.net/agoric/vstorage/children/published.committees'
124
+ {
125
+ "children": [
126
+ "Economic_Committee"
127
+ ],
128
+ "pagination": null
129
+ }
130
+ ```
131
+
132
+ ## Arbitrary-response HTTP interface
133
+
134
+ This depends upon appModule `LegacyQuerierHandler` functionality that is [removed from cosmos-sdk as of v0.47](https://github.com/cosmos/cosmos-sdk/blob/fa4d87ef7e6d87aaccc94c337ffd2fe90fcb7a9d/CHANGELOG.md#api-breaking-changes-3)
135
+
136
+ [legacy querier](./keeper/querier.go)
137
+ * /custom/vstorage/children/$path
138
+ * /custom/vstorage/data/$path