@agoric/cosmos 0.34.2-upgrade-16-fi-dev-8879538.0 → 0.34.2-upgrade-16-dev-24665a9.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 (44) hide show
  1. package/app/app.go +121 -46
  2. package/cmd/agd/main.go +4 -4
  3. package/cmd/libdaemon/main.go +6 -6
  4. package/daemon/cmd/root.go +3 -7
  5. package/daemon/main.go +3 -2
  6. package/git-revision.txt +1 -1
  7. package/go.mod +3 -0
  8. package/go.sum +2 -2
  9. package/package.json +2 -2
  10. package/proto/agoric/vtransfer/genesis.proto +18 -0
  11. package/vm/client_test.go +6 -8
  12. package/vm/controller.go +3 -0
  13. package/vm/proto_json.go +38 -0
  14. package/vm/proto_json_test.go +103 -0
  15. package/x/swingset/alias.go +2 -0
  16. package/x/swingset/keeper/keeper.go +8 -20
  17. package/x/swingset/keeper/test_utils.go +16 -0
  18. package/x/swingset/module.go +7 -2
  19. package/x/swingset/testing/queue.go +17 -0
  20. package/x/swingset/types/msgs.go +19 -0
  21. package/x/vbank/genesis.go +0 -2
  22. package/x/vbank/types/msgs.go +0 -12
  23. package/x/vbank/vbank.go +6 -6
  24. package/x/vbank/vbank_test.go +2 -2
  25. package/x/vibc/alias.go +1 -1
  26. package/x/vibc/types/receiver.go +17 -7
  27. package/x/vlocalchain/handler.go +2 -1
  28. package/x/vlocalchain/keeper/keeper_test.go +66 -1
  29. package/x/vlocalchain/vlocalchain.go +26 -21
  30. package/x/vlocalchain/vlocalchain_test.go +133 -4
  31. package/x/vstorage/keeper/keeper.go +5 -5
  32. package/x/vstorage/testing/queue.go +27 -0
  33. package/x/vtransfer/alias.go +13 -0
  34. package/x/vtransfer/genesis.go +39 -0
  35. package/x/vtransfer/genesis_test.go +12 -0
  36. package/x/vtransfer/handler.go +20 -0
  37. package/x/vtransfer/ibc_middleware.go +186 -0
  38. package/x/vtransfer/ibc_middleware_test.go +448 -0
  39. package/x/vtransfer/keeper/keeper.go +281 -0
  40. package/x/vtransfer/module.go +124 -0
  41. package/x/vtransfer/types/expected_keepers.go +38 -0
  42. package/x/vtransfer/types/genesis.pb.go +327 -0
  43. package/x/vtransfer/types/key.go +9 -0
  44. package/x/vtransfer/types/msgs.go +9 -0
@@ -0,0 +1,38 @@
1
+ package vm
2
+
3
+ import (
4
+ "encoding/json"
5
+
6
+ "github.com/gogo/protobuf/jsonpb"
7
+ "github.com/gogo/protobuf/proto"
8
+ )
9
+
10
+ // We need jsonpb for its access to the global registry.
11
+ var marshaller = jsonpb.Marshaler{EmitDefaults: true}
12
+
13
+ func ProtoJSONMarshal(val interface{}) ([]byte, error) {
14
+ if pm, ok := val.(proto.Message); ok {
15
+ var s string
16
+ s, err := marshaller.MarshalToString(pm)
17
+ return []byte(s), err
18
+ }
19
+
20
+ // Marshal a non-proto value to JSON.
21
+ return json.Marshal(val)
22
+ }
23
+
24
+ // ProtoJSONMarshalSlice marshals a slice of proto messages and non-proto values to
25
+ // a single JSON byte slice.
26
+ func ProtoJSONMarshalSlice(vals []interface{}) ([]byte, error) {
27
+ var err error
28
+ jsonSlice := make([]json.RawMessage, len(vals))
29
+ for i, val := range vals {
30
+ jsonSlice[i], err = ProtoJSONMarshal(val)
31
+ if err != nil {
32
+ return nil, err
33
+ }
34
+ }
35
+
36
+ // Marshal the JSON array to a single JSON byte slice.
37
+ return json.Marshal(jsonSlice)
38
+ }
@@ -0,0 +1,103 @@
1
+ package vm_test
2
+
3
+ import (
4
+ "bytes"
5
+ "strings"
6
+ "testing"
7
+
8
+ "github.com/Agoric/agoric-sdk/golang/cosmos/vm"
9
+
10
+ sdk "github.com/cosmos/cosmos-sdk/types"
11
+
12
+ banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
13
+ stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
14
+ )
15
+
16
+ func TestProtoJSONMarshal(t *testing.T) {
17
+ accAddr, err := sdk.AccAddressFromHexUnsafe("0123456789")
18
+ if err != nil {
19
+ panic(err)
20
+ }
21
+ valAddr, err := sdk.ValAddressFromHex("9876543210")
22
+ if err != nil {
23
+ panic(err)
24
+ }
25
+ coin := sdk.NewInt64Coin("uatom", 1234567)
26
+
27
+ testCases := []struct {
28
+ name string
29
+ create func() interface{}
30
+ expected string
31
+ }{
32
+ {
33
+ "nil",
34
+ func() interface{} {
35
+ return nil
36
+ },
37
+ `null`,
38
+ },
39
+ {
40
+ "primitive number",
41
+ func() interface{} {
42
+ return 12345
43
+ },
44
+ `12345`,
45
+ },
46
+ {
47
+ "MsgDelegate",
48
+ func() interface{} {
49
+ return stakingtypes.NewMsgDelegate(accAddr, valAddr, coin)
50
+ },
51
+ `{"delegatorAddress":"cosmos1qy352eufjjmc9c","validatorAddress":"cosmosvaloper1npm9gvss52mlmk","amount":{"denom":"uatom","amount":"1234567"}}`,
52
+ },
53
+ {
54
+ "QueryDenomOwnersResponse",
55
+ func() interface{} {
56
+ return &banktypes.QueryDenomOwnersResponse{
57
+ DenomOwners: []*banktypes.DenomOwner{
58
+ {
59
+ Address: accAddr.String(),
60
+ Balance: coin,
61
+ },
62
+ {
63
+ Address: valAddr.String(),
64
+ Balance: coin.Add(coin),
65
+ },
66
+ },
67
+ }
68
+ },
69
+ `{"denomOwners":[{"address":"cosmos1qy352eufjjmc9c","balance":{"denom":"uatom","amount":"1234567"}},{"address":"cosmosvaloper1npm9gvss52mlmk","balance":{"denom":"uatom","amount":"2469134"}}],"pagination":null}`,
70
+ },
71
+ }
72
+
73
+ for _, tc := range testCases {
74
+ t.Run(tc.name, func(t *testing.T) {
75
+ val := tc.create()
76
+ bz, err := vm.ProtoJSONMarshal(val)
77
+ if err != nil {
78
+ t.Errorf("ProtoJSONMarshal of %q failed %v", val, err)
79
+ }
80
+ if !bytes.Equal(bz, []byte(tc.expected)) {
81
+ t.Errorf("ProtoJSONMarshal of %q returned %q, expected %q", val, string(bz), tc.expected)
82
+ }
83
+ })
84
+ }
85
+
86
+ t.Run("all in a slice", func(t *testing.T) {
87
+ vals := make([]interface{}, len(testCases))
88
+ expectedJson := make([]string, len(testCases))
89
+ for i, tc := range testCases {
90
+ vals[i] = tc.create()
91
+ expectedJson[i] = tc.expected
92
+ }
93
+ bz, err := vm.ProtoJSONMarshalSlice(vals)
94
+ if err != nil {
95
+ t.Errorf("ProtoJSONMarshalSlice of %q failed %v", vals, err)
96
+ }
97
+
98
+ expected := "[" + strings.Join(expectedJson, ",") + "]"
99
+ if !bytes.Equal(bz, []byte(expected)) {
100
+ t.Errorf("ProtoJSONMarshalSlice of %q returned %q, expected %q", vals, string(bz), expected)
101
+ }
102
+ })
103
+ }
@@ -24,6 +24,8 @@ type (
24
24
  Keeper = keeper.Keeper
25
25
  SwingStoreExportsHandler = keeper.SwingStoreExportsHandler
26
26
  ExtensionSnapshotter = keeper.ExtensionSnapshotter
27
+ ActionContext = types.ActionContext
28
+ InboundQueueRecord = types.InboundQueueRecord
27
29
  Egress = types.Egress
28
30
  MsgDeliverInbound = types.MsgDeliverInbound
29
31
  MsgProvision = types.MsgProvision
@@ -51,25 +51,6 @@ const (
51
51
  swingStoreKeyPrefix = "swingStore."
52
52
  )
53
53
 
54
- // Contextual information about the message source of an action on an inbound queue.
55
- // This context should be unique per inboundQueueRecord.
56
- type actionContext struct {
57
- // The block height in which the corresponding action was enqueued
58
- BlockHeight int64 `json:"blockHeight"`
59
- // The hash of the cosmos transaction that included the message
60
- // If the action didn't result from a transaction message, a substitute value
61
- // may be used. For example the VBANK_BALANCE_UPDATE actions use `x/vbank`.
62
- TxHash string `json:"txHash"`
63
- // The index of the message within the transaction. If the action didn't
64
- // result from a cosmos transaction, a number should be chosen to make the
65
- // actionContext unique. (for example a counter per block and source module).
66
- MsgIdx int `json:"msgIdx"`
67
- }
68
- type inboundQueueRecord struct {
69
- Action vm.Jsonable `json:"action"`
70
- Context actionContext `json:"context"`
71
- }
72
-
73
54
  // Keeper maintains the link to data vstorage and exposes getter/setter methods for the various parts of the state machine
74
55
  type Keeper struct {
75
56
  storeKey storetypes.StoreKey
@@ -144,7 +125,14 @@ func (k Keeper) pushAction(ctx sdk.Context, inboundQueuePath string, action vm.A
144
125
  if !txHashOk || !msgIdxOk {
145
126
  stdlog.Printf("error while extracting context for action %q\n", action)
146
127
  }
147
- record := inboundQueueRecord{Action: action, Context: actionContext{BlockHeight: ctx.BlockHeight(), TxHash: txHash, MsgIdx: msgIdx}}
128
+ record := types.InboundQueueRecord{
129
+ Action: action,
130
+ Context: types.ActionContext{
131
+ BlockHeight: ctx.BlockHeight(),
132
+ TxHash: txHash,
133
+ MsgIdx: msgIdx,
134
+ },
135
+ }
148
136
  bz, err := json.Marshal(record)
149
137
  if err != nil {
150
138
  return err
@@ -0,0 +1,16 @@
1
+ package keeper
2
+
3
+ import (
4
+ "testing"
5
+
6
+ "github.com/Agoric/agoric-sdk/golang/cosmos/x/vstorage"
7
+ )
8
+
9
+ // GetVstorageKeeper returns the vstorage keeper from the swingset keeper
10
+ // for testing purposes.
11
+ func GetVstorageKeeper(t *testing.T, k Keeper) vstorage.Keeper {
12
+ if t == nil {
13
+ panic("this function is reserved for testing")
14
+ }
15
+ return k.vstorageKeeper
16
+ }
@@ -99,6 +99,11 @@ func (AppModule) Name() string {
99
99
  return ModuleName
100
100
  }
101
101
 
102
+ // For testing purposes
103
+ func (am *AppModule) SetSwingStoreExportDir(dir string) {
104
+ am.swingStoreExportDir = dir
105
+ }
106
+
102
107
  func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {}
103
108
 
104
109
  func (am AppModule) Route() sdk.Route {
@@ -149,9 +154,9 @@ func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.V
149
154
  return []abci.ValidatorUpdate{}
150
155
  }
151
156
 
152
- func (am AppModule) checkSwingStoreExportSetup() {
157
+ func (am *AppModule) checkSwingStoreExportSetup() {
153
158
  if am.swingStoreExportDir == "" {
154
- panic(fmt.Errorf("SwingStore export dir not set"))
159
+ am.swingStoreExportDir = "/tmp/swingset_export"
155
160
  }
156
161
  }
157
162
 
@@ -0,0 +1,17 @@
1
+ package testing
2
+
3
+ import (
4
+ "testing"
5
+
6
+ "github.com/Agoric/agoric-sdk/golang/cosmos/x/swingset/keeper"
7
+ vstoragetesting "github.com/Agoric/agoric-sdk/golang/cosmos/x/vstorage/testing"
8
+ sdk "github.com/cosmos/cosmos-sdk/types"
9
+ )
10
+
11
+ // GetActionQueueRecords returns the records in the action queue.
12
+ // This is a testing utility function.
13
+ func GetActionQueueRecords(t *testing.T, ctx sdk.Context, swingsetKeeper keeper.Keeper) ([]string, error) {
14
+ vstorageKeeper := keeper.GetVstorageKeeper(t, swingsetKeeper)
15
+ actionQueueName := keeper.StoragePathActionQueue
16
+ return vstoragetesting.GetQueueItems(ctx, vstorageKeeper, actionQueueName)
17
+ }
@@ -29,6 +29,25 @@ var (
29
29
  _ vm.ControllerAdmissionMsg = &MsgWalletSpendAction{}
30
30
  )
31
31
 
32
+ // Contextual information about the message source of an action on an inbound queue.
33
+ // This context should be unique per inboundQueueRecord.
34
+ type ActionContext struct {
35
+ // The block height in which the corresponding action was enqueued
36
+ BlockHeight int64 `json:"blockHeight"`
37
+ // The hash of the cosmos transaction that included the message
38
+ // If the action didn't result from a transaction message, a substitute value
39
+ // may be used. For example the VBANK_BALANCE_UPDATE actions use `x/vbank`.
40
+ TxHash string `json:"txHash"`
41
+ // The index of the message within the transaction. If the action didn't
42
+ // result from a cosmos transaction, a number should be chosen to make the
43
+ // actionContext unique. (for example a counter per block and source module).
44
+ MsgIdx int `json:"msgIdx"`
45
+ }
46
+ type InboundQueueRecord struct {
47
+ Action vm.Jsonable `json:"action"`
48
+ Context ActionContext `json:"context"`
49
+ }
50
+
32
51
  const (
33
52
  // bundleUncompressedSizeLimit is the (exclusive) limit on uncompressed bundle size.
34
53
  // We must ensure there is an exclusive int64 limit in order to detect an underflow.
@@ -1,8 +1,6 @@
1
1
  package vbank
2
2
 
3
3
  import (
4
- // "fmt"
5
-
6
4
  "fmt"
7
5
 
8
6
  "github.com/Agoric/agoric-sdk/golang/cosmos/x/vbank/types"
@@ -1,15 +1,3 @@
1
1
  package types
2
2
 
3
3
  const RouterKey = ModuleName // this was defined in your key.go file
4
-
5
- type VbankSingleBalanceUpdate struct {
6
- Address string `json:"address"`
7
- Denom string `json:"denom"`
8
- Amount string `json:"amount"`
9
- }
10
-
11
- type VbankBalanceUpdate struct {
12
- Nonce uint64 `json:"nonce"`
13
- Type string `json:"type"`
14
- Updated []VbankSingleBalanceUpdate `json:"updated"`
15
- }
package/x/vbank/vbank.go CHANGED
@@ -34,14 +34,14 @@ func NewPortHandler(am AppModule, keeper Keeper) portHandler {
34
34
  }
35
35
  }
36
36
 
37
- type vbankSingleBalanceUpdate struct {
37
+ type VbankSingleBalanceUpdate struct {
38
38
  Address string `json:"address"`
39
39
  Denom string `json:"denom"`
40
40
  Amount string `json:"amount"`
41
41
  }
42
42
 
43
43
  // Make vbankManyBalanceUpdates sortable
44
- type vbankManyBalanceUpdates []vbankSingleBalanceUpdate
44
+ type vbankManyBalanceUpdates []VbankSingleBalanceUpdate
45
45
 
46
46
  var _ sort.Interface = vbankManyBalanceUpdates{}
47
47
 
@@ -67,7 +67,7 @@ func (vbu vbankManyBalanceUpdates) Swap(i int, j int) {
67
67
  vbu[i], vbu[j] = vbu[j], vbu[i]
68
68
  }
69
69
 
70
- type vbankBalanceUpdate struct {
70
+ type VbankBalanceUpdate struct {
71
71
  *vm.ActionHeader `actionType:"VBANK_BALANCE_UPDATE"`
72
72
  Nonce uint64 `json:"nonce"`
73
73
  Updated vbankManyBalanceUpdates `json:"updated"`
@@ -83,9 +83,9 @@ func getBalanceUpdate(ctx sdk.Context, keeper Keeper, addressToUpdate map[string
83
83
  }
84
84
 
85
85
  nonce := keeper.GetNextSequence(ctx)
86
- event := vbankBalanceUpdate{
86
+ event := VbankBalanceUpdate{
87
87
  Nonce: nonce,
88
- Updated: make([]vbankSingleBalanceUpdate, 0, nentries),
88
+ Updated: make([]VbankSingleBalanceUpdate, 0, nentries),
89
89
  }
90
90
 
91
91
  // Note that Golang randomises the order of iteration, so we have to sort
@@ -99,7 +99,7 @@ func getBalanceUpdate(ctx sdk.Context, keeper Keeper, addressToUpdate map[string
99
99
  for _, coin := range coins {
100
100
  // generate an update even when the current balance is zero
101
101
  balance := keeper.GetBalance(ctx, account, coin.Denom)
102
- update := vbankSingleBalanceUpdate{
102
+ update := VbankSingleBalanceUpdate{
103
103
  Address: address,
104
104
  Denom: coin.Denom,
105
105
  Amount: balance.Amount.String(),
@@ -71,7 +71,7 @@ func newBalances(opts ...balancesOption) balances {
71
71
  return bal
72
72
  }
73
73
 
74
- func validateBalanceUpdate(vbu vbankBalanceUpdate) error {
74
+ func validateBalanceUpdate(vbu VbankBalanceUpdate) error {
75
75
  if vbu.Type != "VBANK_BALANCE_UPDATE" {
76
76
  return fmt.Errorf("bad balance update type: %s", vbu.Type)
77
77
  }
@@ -89,7 +89,7 @@ func decodeBalances(encoded []byte) (balances, uint64, error) {
89
89
  if encoded == nil {
90
90
  return nil, 0, nil
91
91
  }
92
- balanceUpdate := vbankBalanceUpdate{}
92
+ balanceUpdate := VbankBalanceUpdate{}
93
93
  err := json.Unmarshal(encoded, &balanceUpdate)
94
94
  if err != nil {
95
95
  return nil, 0, err
package/x/vibc/alias.go CHANGED
@@ -22,6 +22,6 @@ var (
22
22
 
23
23
  type (
24
24
  Keeper = keeper.Keeper
25
- ScopedKeeper = types.ScopedKeeper
25
+ ScopedKeeper = types.ScopedKeeper
26
26
  MsgSendPacket = types.MsgSendPacket
27
27
  )
@@ -14,7 +14,7 @@ import (
14
14
  )
15
15
 
16
16
  var (
17
- _ vm.PortHandler = Receiver{}
17
+ _ vm.PortHandler = (*Receiver)(nil)
18
18
  _ exported.Acknowledgement = (*rawAcknowledgement)(nil)
19
19
  )
20
20
 
@@ -83,18 +83,28 @@ func (r rawAcknowledgement) Success() bool {
83
83
  return true
84
84
  }
85
85
 
86
- func (ir Receiver) Receive(cctx context.Context, str string) (ret string, err error) {
86
+ // Receive implements vm.PortHandler. It unmarshals the string as JSON text
87
+ // representing an IBC portMessage object. If the resulting type is
88
+ // "IBC_METHOD" it dispatches on method ("sendPacket"/"receiveExecuted"/etc.)
89
+ // and calls the corresponding method of the wrapped ReceiverImpl.
90
+ //
91
+ // Otherwise, it requires the wrapped ReceiverImpl to be a vm.PortHandler
92
+ // and delegates to the Receive method of that PortHandler.
93
+ func (ir Receiver) Receive(cctx context.Context, jsonRequest string) (jsonReply string, err error) {
87
94
  ctx := sdk.UnwrapSDKContext(cctx)
88
95
  impl := ir.impl
89
96
 
90
97
  msg := new(portMessage)
91
- err = json.Unmarshal([]byte(str), &msg)
98
+ err = json.Unmarshal([]byte(jsonRequest), &msg)
92
99
  if err != nil {
93
100
  return "", err
94
101
  }
95
102
 
96
103
  if msg.Type != "IBC_METHOD" {
97
- return "", fmt.Errorf(`channel handler only accepts messages of "type": "IBC_METHOD"`)
104
+ if receiver, ok := impl.(vm.PortHandler); ok {
105
+ return receiver.Receive(cctx, jsonRequest)
106
+ }
107
+ return "", fmt.Errorf(`channel handler only accepts messages of "type": "IBC_METHOD"; got %q`, msg.Type)
98
108
  }
99
109
 
100
110
  switch msg.Method {
@@ -116,7 +126,7 @@ func (ir Receiver) Receive(cctx context.Context, str string) (ret string, err er
116
126
  packet.Sequence = seq
117
127
  bytes, err := json.Marshal(&packet)
118
128
  if err == nil {
119
- ret = string(bytes)
129
+ jsonReply = string(bytes)
120
130
  }
121
131
  }
122
132
 
@@ -153,8 +163,8 @@ func (ir Receiver) Receive(cctx context.Context, str string) (ret string, err er
153
163
  err = fmt.Errorf("unrecognized method %s", msg.Method)
154
164
  }
155
165
 
156
- if ret == "" && err == nil {
157
- ret = "true"
166
+ if jsonReply == "" && err == nil {
167
+ jsonReply = "true"
158
168
  }
159
169
  return
160
170
  }
@@ -3,6 +3,7 @@ package vlocalchain
3
3
  import (
4
4
  "fmt"
5
5
 
6
+ sdkioerrors "cosmossdk.io/errors"
6
7
  "github.com/Agoric/agoric-sdk/golang/cosmos/x/vlocalchain/keeper"
7
8
  sdk "github.com/cosmos/cosmos-sdk/types"
8
9
  sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -14,7 +15,7 @@ func NewHandler(keeper keeper.Keeper) sdk.Handler {
14
15
  switch msg := msg.(type) {
15
16
  default:
16
17
  errMsg := fmt.Sprintf("Unrecognized vlocalchain Msg type: %T", msg)
17
- return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg)
18
+ return nil, sdkioerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg)
18
19
  }
19
20
  }
20
21
  }
@@ -1,6 +1,15 @@
1
1
  package keeper
2
2
 
3
- import "testing"
3
+ import (
4
+ "testing"
5
+
6
+ "github.com/stretchr/testify/require"
7
+
8
+ "github.com/Agoric/agoric-sdk/golang/cosmos/app/params"
9
+ sdk "github.com/cosmos/cosmos-sdk/types"
10
+ banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
11
+ )
12
+
4
13
 
5
14
  func TestKeeper_ParseRequestTypeURL(t *testing.T) {
6
15
  testCases := []struct {
@@ -30,3 +39,59 @@ func TestKeeper_ParseRequestTypeURL(t *testing.T) {
30
39
  })
31
40
  }
32
41
  }
42
+
43
+ func TestKeeper_DeserializeTxMessages(t *testing.T) {
44
+ encodingConfig := params.MakeEncodingConfig()
45
+ cdc := encodingConfig.Marshaler
46
+
47
+ banktypes.RegisterInterfaces(encodingConfig.InterfaceRegistry)
48
+
49
+ keeper := NewKeeper(cdc, nil, nil, nil)
50
+
51
+ expectedMsgSend := []sdk.Msg{
52
+ &banktypes.MsgSend{
53
+ FromAddress: "cosmos1abc",
54
+ ToAddress: "cosmos1xyz",
55
+ Amount: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))),
56
+ },
57
+ }
58
+
59
+ testCases := []struct {
60
+ name string
61
+ json string
62
+ expected []sdk.Msg
63
+ wantErr bool
64
+ }{
65
+ {
66
+ name: "camelCase keys",
67
+ json: `{"messages":[{"@type":"/cosmos.bank.v1beta1.MsgSend","fromAddress":"cosmos1abc","toAddress":"cosmos1xyz","amount":[{"denom":"stake","amount":"100"}]}]}`,
68
+ expected: expectedMsgSend,
69
+ wantErr: false,
70
+ },
71
+ {
72
+ name: "snake_case keys",
73
+ json: `{"messages":[{"@type":"/cosmos.bank.v1beta1.MsgSend","from_address":"cosmos1abc","to_address":"cosmos1xyz","amount":[{"denom":"stake","amount":"100"}]}]}`,
74
+ expected: expectedMsgSend,
75
+ wantErr: false,
76
+ },
77
+ {
78
+ name: "misspelled key",
79
+ json: `{"messages":[{"@type":"/cosmos.bank.v1beta1.MsgSend","from_addresss":"cosmos1abc","to_address":"cosmos1xyz","amount":[{"denom":"stake","amount":"100"}]}]}`,
80
+ expected: expectedMsgSend,
81
+ wantErr: true,
82
+ },
83
+ }
84
+
85
+ for _, tc := range testCases {
86
+ t.Run(tc.name, func(t *testing.T) {
87
+ msgs, err := keeper.DeserializeTxMessages([]byte(tc.json))
88
+
89
+ if tc.wantErr {
90
+ require.Error(t, err)
91
+ } else {
92
+ require.NoError(t, err)
93
+ require.Equal(t, tc.expected, msgs)
94
+ }
95
+ })
96
+ }
97
+ }
@@ -6,7 +6,6 @@ import (
6
6
  "fmt"
7
7
 
8
8
  sdk "github.com/cosmos/cosmos-sdk/types"
9
- "github.com/gogo/protobuf/jsonpb"
10
9
 
11
10
  "github.com/Agoric/agoric-sdk/golang/cosmos/vm"
12
11
  "github.com/Agoric/agoric-sdk/golang/cosmos/x/vlocalchain/keeper"
@@ -56,28 +55,36 @@ func (h portHandler) Receive(cctx context.Context, str string) (ret string, err
56
55
  return
57
56
  }
58
57
 
59
- // We need jsonpb for its access to the global registry.
60
- marshaller := jsonpb.Marshaler{EmitDefaults: true, OrigName: true}
61
-
62
- var s string
63
- resps := make([]json.RawMessage, len(qms))
58
+ var errs []error
59
+ resps := make([]interface{}, len(qms))
64
60
  for i, qm := range qms {
65
61
  var qr *types.QueryResponse
66
62
  qr, err = h.keeper.Query(cctx, qm)
67
- if err != nil {
68
- return
69
- }
70
- if s, err = marshaller.MarshalToString(qr); err != nil {
71
- return
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()}
72
69
  }
73
- resps[i] = []byte(s)
74
70
  }
75
71
 
76
- var bz []byte
77
- if bz, err = json.Marshal(resps); err != nil {
78
- return
72
+ bz, err := vm.ProtoJSONMarshalSlice(resps)
73
+ if err != nil {
74
+ return "", err
79
75
  }
80
- ret = string(bz)
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
81
88
 
82
89
  case "VLOCALCHAIN_EXECUTE_TX":
83
90
  origCtx := sdk.UnwrapSDKContext(cctx)
@@ -97,11 +104,9 @@ func (h portHandler) Receive(cctx context.Context, str string) (ret string, err
97
104
  return
98
105
  }
99
106
 
100
- var bz []byte
101
- if bz, err = json.Marshal(resps); err != nil {
102
- return
103
- }
104
- ret = string(bz)
107
+ // Marshal the responses to proto3 JSON.
108
+ bz, e := vm.ProtoJSONMarshalSlice(resps)
109
+ return string(bz), e
105
110
  default:
106
111
  err = fmt.Errorf("unrecognized message type %s", msg.Type)
107
112
  }