@agoric/cosmos 0.35.0-u12.0 → 0.35.0-upgrade-14-dev-1eb5b91.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.
@@ -21,15 +21,13 @@ func NewMsgServerImpl(keeper Keeper) types.MsgServer {
21
21
  var _ types.MsgServer = msgServer{}
22
22
 
23
23
  type deliverInboundAction struct {
24
- Type string `json:"type"`
25
- Peer string `json:"peer"`
26
- Messages [][]interface{} `json:"messages"`
27
- Ack uint64 `json:"ack"`
28
- BlockHeight int64 `json:"blockHeight"`
29
- BlockTime int64 `json:"blockTime"`
24
+ vm.ActionHeader `actionType:"DELIVER_INBOUND"`
25
+ Peer string `json:"peer"`
26
+ Messages [][]interface{} `json:"messages"`
27
+ Ack uint64 `json:"ack"`
30
28
  }
31
29
 
32
- func (keeper msgServer) routeAction(ctx sdk.Context, msg vm.ControllerAdmissionMsg, action vm.Jsonable) error {
30
+ func (keeper msgServer) routeAction(ctx sdk.Context, msg vm.ControllerAdmissionMsg, action vm.Action) error {
33
31
  isHighPriority, err := msg.IsHighPriority(ctx, keeper)
34
32
  if err != nil {
35
33
  return err
@@ -53,12 +51,9 @@ func (keeper msgServer) DeliverInbound(goCtx context.Context, msg *types.MsgDeli
53
51
  }
54
52
 
55
53
  action := &deliverInboundAction{
56
- Type: "DELIVER_INBOUND",
57
- Peer: msg.Submitter.String(),
58
- Messages: messages,
59
- Ack: msg.Ack,
60
- BlockHeight: ctx.BlockHeight(),
61
- BlockTime: ctx.BlockTime().Unix(),
54
+ Peer: msg.Submitter.String(),
55
+ Messages: messages,
56
+ Ack: msg.Ack,
62
57
  }
63
58
 
64
59
  err := keeper.routeAction(ctx, msg, action)
@@ -70,26 +65,26 @@ func (keeper msgServer) DeliverInbound(goCtx context.Context, msg *types.MsgDeli
70
65
  }
71
66
 
72
67
  type walletAction struct {
73
- Type string `json:"type"` // WALLET_ACTION
74
- Owner string `json:"owner"`
75
- Action string `json:"action"`
76
- BlockHeight int64 `json:"blockHeight"`
77
- BlockTime int64 `json:"blockTime"`
68
+ vm.ActionHeader `actionType:"WALLET_ACTION"`
69
+ Owner string `json:"owner"`
70
+ Action string `json:"action"`
78
71
  }
79
72
 
80
73
  func (keeper msgServer) WalletAction(goCtx context.Context, msg *types.MsgWalletAction) (*types.MsgWalletActionResponse, error) {
81
74
  ctx := sdk.UnwrapSDKContext(goCtx)
82
75
 
76
+ err := keeper.provisionIfNeeded(ctx, msg.Owner)
77
+ if err != nil {
78
+ return nil, err
79
+ }
80
+
83
81
  action := &walletAction{
84
- Type: "WALLET_ACTION",
85
- Owner: msg.Owner.String(),
86
- Action: msg.Action,
87
- BlockHeight: ctx.BlockHeight(),
88
- BlockTime: ctx.BlockTime().Unix(),
82
+ Owner: msg.Owner.String(),
83
+ Action: msg.Action,
89
84
  }
90
85
  // fmt.Fprintf(os.Stderr, "Context is %+v\n", ctx)
91
86
 
92
- err := keeper.routeAction(ctx, msg, action)
87
+ err = keeper.routeAction(ctx, msg, action)
93
88
  // fmt.Fprintln(os.Stderr, "Returned from SwingSet", out, err)
94
89
  if err != nil {
95
90
  return nil, err
@@ -98,25 +93,25 @@ func (keeper msgServer) WalletAction(goCtx context.Context, msg *types.MsgWallet
98
93
  }
99
94
 
100
95
  type walletSpendAction struct {
101
- Type string `json:"type"` // WALLET_SPEND_ACTION
102
- Owner string `json:"owner"`
103
- SpendAction string `json:"spendAction"`
104
- BlockHeight int64 `json:"blockHeight"`
105
- BlockTime int64 `json:"blockTime"`
96
+ vm.ActionHeader `actionType:"WALLET_SPEND_ACTION"`
97
+ Owner string `json:"owner"`
98
+ SpendAction string `json:"spendAction"`
106
99
  }
107
100
 
108
101
  func (keeper msgServer) WalletSpendAction(goCtx context.Context, msg *types.MsgWalletSpendAction) (*types.MsgWalletSpendActionResponse, error) {
109
102
  ctx := sdk.UnwrapSDKContext(goCtx)
110
103
 
104
+ err := keeper.provisionIfNeeded(ctx, msg.Owner)
105
+ if err != nil {
106
+ return nil, err
107
+ }
108
+
111
109
  action := &walletSpendAction{
112
- Type: "WALLET_SPEND_ACTION",
113
110
  Owner: msg.Owner.String(),
114
111
  SpendAction: msg.SpendAction,
115
- BlockHeight: ctx.BlockHeight(),
116
- BlockTime: ctx.BlockTime().Unix(),
117
112
  }
118
113
  // fmt.Fprintf(os.Stderr, "Context is %+v\n", ctx)
119
- err := keeper.routeAction(ctx, msg, action)
114
+ err = keeper.routeAction(ctx, msg, action)
120
115
  if err != nil {
121
116
  return nil, err
122
117
  }
@@ -124,10 +119,42 @@ func (keeper msgServer) WalletSpendAction(goCtx context.Context, msg *types.MsgW
124
119
  }
125
120
 
126
121
  type provisionAction struct {
122
+ vm.ActionHeader `actionType:"PLEASE_PROVISION"`
127
123
  *types.MsgProvision
128
- Type string `json:"type"` // PLEASE_PROVISION
129
- BlockHeight int64 `json:"blockHeight"`
130
- BlockTime int64 `json:"blockTime"`
124
+ AutoProvision bool `json:"autoProvision"`
125
+ }
126
+
127
+ // provisionIfNeeded generates a provision action if no smart wallet is already
128
+ // provisioned for the account. This assumes that all messages for
129
+ // non-provisioned smart wallets allowed by the admission AnteHandler should
130
+ // auto-provision the smart wallet.
131
+ func (keeper msgServer) provisionIfNeeded(ctx sdk.Context, owner sdk.AccAddress) error {
132
+ // We need to generate a provision action until the smart wallet has
133
+ // been fully provisioned by the controller. This is because a provision is
134
+ // not guaranteed to succeed (e.g. lack of provision pool funds)
135
+ walletState := keeper.GetSmartWalletState(ctx, owner)
136
+ if walletState == types.SmartWalletStateProvisioned {
137
+ return nil
138
+ }
139
+
140
+ msg := &types.MsgProvision{
141
+ Address: owner,
142
+ Submitter: owner,
143
+ PowerFlags: []string{types.PowerFlagSmartWallet},
144
+ }
145
+
146
+ action := &provisionAction{
147
+ MsgProvision: msg,
148
+ AutoProvision: true,
149
+ }
150
+
151
+ err := keeper.routeAction(ctx, msg, action)
152
+ // fmt.Fprintln(os.Stderr, "Returned from SwingSet", out, err)
153
+ if err != nil {
154
+ return err
155
+ }
156
+
157
+ return nil
131
158
  }
132
159
 
133
160
  func (keeper msgServer) Provision(goCtx context.Context, msg *types.MsgProvision) (*types.MsgProvisionResponse, error) {
@@ -140,9 +167,6 @@ func (keeper msgServer) Provision(goCtx context.Context, msg *types.MsgProvision
140
167
 
141
168
  action := &provisionAction{
142
169
  MsgProvision: msg,
143
- Type: "PLEASE_PROVISION",
144
- BlockHeight: ctx.BlockHeight(),
145
- BlockTime: ctx.BlockTime().Unix(),
146
170
  }
147
171
 
148
172
  // Create the account, if it doesn't already exist.
@@ -162,10 +186,8 @@ func (keeper msgServer) Provision(goCtx context.Context, msg *types.MsgProvision
162
186
  }
163
187
 
164
188
  type installBundleAction struct {
189
+ vm.ActionHeader `actionType:"INSTALL_BUNDLE"`
165
190
  *types.MsgInstallBundle
166
- Type string `json:"type"` // INSTALL_BUNDLE
167
- BlockHeight int64 `json:"blockHeight"`
168
- BlockTime int64 `json:"blockTime"`
169
191
  }
170
192
 
171
193
  func (keeper msgServer) InstallBundle(goCtx context.Context, msg *types.MsgInstallBundle) (*types.MsgInstallBundleResponse, error) {
@@ -177,9 +199,6 @@ func (keeper msgServer) InstallBundle(goCtx context.Context, msg *types.MsgInsta
177
199
  }
178
200
  action := &installBundleAction{
179
201
  MsgInstallBundle: msg,
180
- Type: "INSTALL_BUNDLE",
181
- BlockHeight: ctx.BlockHeight(),
182
- BlockTime: ctx.BlockTime().Unix(),
183
202
  }
184
203
 
185
204
  err = keeper.routeAction(ctx, msg, action)
@@ -3,23 +3,19 @@ package keeper
3
3
  import (
4
4
  sdk "github.com/cosmos/cosmos-sdk/types"
5
5
 
6
+ "github.com/Agoric/agoric-sdk/golang/cosmos/vm"
6
7
  "github.com/Agoric/agoric-sdk/golang/cosmos/x/swingset/types"
7
8
  )
8
9
 
9
10
  type coreEvalAction struct {
10
- Type string `json:"type"` // CORE_EVAL
11
- Evals []types.CoreEval `json:"evals"`
12
- BlockHeight int64 `json:"blockHeight"`
13
- BlockTime int64 `json:"blockTime"`
11
+ vm.ActionHeader `actionType:"CORE_EVAL"`
12
+ Evals []types.CoreEval `json:"evals"`
14
13
  }
15
14
 
16
15
  // CoreEvalProposal tells SwingSet to evaluate the given JS code.
17
16
  func (k Keeper) CoreEvalProposal(ctx sdk.Context, p *types.CoreEvalProposal) error {
18
17
  action := &coreEvalAction{
19
- Type: "CORE_EVAL",
20
- Evals: p.Evals,
21
- BlockHeight: ctx.BlockHeight(),
22
- BlockTime: ctx.BlockTime().Unix(),
18
+ Evals: p.Evals,
23
19
  }
24
20
 
25
21
  return k.PushHighPriorityAction(ctx, action)
@@ -11,20 +11,24 @@ import (
11
11
  // experience if they don't.
12
12
 
13
13
  const (
14
- BeansPerFeeUnit = "feeUnit"
15
- BeansPerInboundTx = "inboundTx"
16
- BeansPerBlockComputeLimit = "blockComputeLimit"
17
- BeansPerMessage = "message"
18
- BeansPerMessageByte = "messageByte"
19
- BeansPerMinFeeDebit = "minFeeDebit"
20
- BeansPerStorageByte = "storageByte"
21
- BeansPerVatCreation = "vatCreation"
22
- BeansPerXsnapComputron = "xsnapComputron"
14
+ BeansPerFeeUnit = "feeUnit"
15
+ BeansPerInboundTx = "inboundTx"
16
+ BeansPerBlockComputeLimit = "blockComputeLimit"
17
+ BeansPerMessage = "message"
18
+ BeansPerMessageByte = "messageByte"
19
+ BeansPerMinFeeDebit = "minFeeDebit"
20
+ BeansPerStorageByte = "storageByte"
21
+ BeansPerVatCreation = "vatCreation"
22
+ BeansPerXsnapComputron = "xsnapComputron"
23
+ BeansPerSmartWalletProvision = "smartWalletProvision"
23
24
 
24
25
  // QueueSize keys.
25
26
  // Keep up-to-date with updateQueueAllowed() in packanges/cosmic-swingset/src/launch-chain.js
26
27
  QueueInbound = "inbound"
27
28
  QueueInboundMempool = "inbound_mempool"
29
+
30
+ // PowerFlags.
31
+ PowerFlagSmartWallet = "SMART_WALLET"
28
32
  )
29
33
 
30
34
  var (
@@ -43,17 +47,18 @@ var (
43
47
 
44
48
  // TODO: create the cost model we want, and update these to be more principled.
45
49
  // These defaults currently make deploying an ag-solo cost less than $1.00.
46
- DefaultBeansPerFeeUnit = sdk.NewUint(1_000_000_000_000) // $1
47
- DefaultBeansPerInboundTx = DefaultBeansPerFeeUnit.Quo(sdk.NewUint(100)) // $0.01
48
- DefaultBeansPerMessage = DefaultBeansPerFeeUnit.Quo(sdk.NewUint(1_000)) // $0.001
49
- DefaultBeansPerMessageByte = DefaultBeansPerFeeUnit.Quo(sdk.NewUint(50_000)) // $0.00002
50
- DefaultBeansPerMinFeeDebit = DefaultBeansPerFeeUnit.Quo(sdk.NewUint(5)) // $0.2
51
- DefaultBeansPerStorageByte = DefaultBeansPerFeeUnit.Quo(sdk.NewUint(500)) // $0.002
50
+ DefaultBeansPerFeeUnit = sdk.NewUint(1_000_000_000_000) // $1
51
+ DefaultBeansPerInboundTx = DefaultBeansPerFeeUnit.Quo(sdk.NewUint(100)) // $0.01
52
+ DefaultBeansPerMessage = DefaultBeansPerFeeUnit.Quo(sdk.NewUint(1_000)) // $0.001
53
+ DefaultBeansPerMessageByte = DefaultBeansPerFeeUnit.Quo(sdk.NewUint(50_000)) // $0.00002
54
+ DefaultBeansPerMinFeeDebit = DefaultBeansPerFeeUnit.Quo(sdk.NewUint(5)) // $0.2
55
+ DefaultBeansPerStorageByte = DefaultBeansPerFeeUnit.Quo(sdk.NewUint(500)) // $0.002
56
+ DefaultBeansPerSmartWalletProvision = DefaultBeansPerFeeUnit // $1
52
57
 
53
58
  DefaultBootstrapVatConfig = "@agoric/vats/decentral-core-config.json"
54
59
 
55
60
  DefaultPowerFlagFees = []PowerFlagFee{
56
- NewPowerFlagFee("SMART_WALLET", sdk.NewCoins(sdk.NewInt64Coin("ubld", 10_000_000))),
61
+ NewPowerFlagFee(PowerFlagSmartWallet, sdk.NewCoins(sdk.NewInt64Coin("ubld", 10_000_000))),
57
62
  }
58
63
 
59
64
  DefaultInboundQueueMax = int32(1_000)
@@ -75,5 +80,6 @@ func DefaultBeansPerUnit() []StringBeans {
75
80
  NewStringBeans(BeansPerStorageByte, DefaultBeansPerStorageByte),
76
81
  NewStringBeans(BeansPerVatCreation, DefaultBeansPerVatCreation),
77
82
  NewStringBeans(BeansPerXsnapComputron, DefaultBeansPerXsnapComputron),
83
+ NewStringBeans(BeansPerSmartWalletProvision, DefaultBeansPerSmartWalletProvision),
78
84
  }
79
85
  }
@@ -5,6 +5,15 @@ import (
5
5
  authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
6
6
  )
7
7
 
8
+ type SmartWalletState uint8
9
+
10
+ const (
11
+ SmartWalletStateUnspecified SmartWalletState = iota
12
+ SmartWalletStateNone
13
+ SmartWalletStatePending
14
+ SmartWalletStateProvisioned
15
+ )
16
+
8
17
  type AccountKeeper interface {
9
18
  GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI
10
19
  NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI
@@ -15,4 +24,6 @@ type SwingSetKeeper interface {
15
24
  GetBeansPerUnit(ctx sdk.Context) map[string]sdk.Uint
16
25
  ChargeBeans(ctx sdk.Context, addr sdk.AccAddress, beans sdk.Uint) error
17
26
  IsHighPriorityAddress(ctx sdk.Context, addr sdk.AccAddress) (bool, error)
27
+ GetSmartWalletState(ctx sdk.Context, addr sdk.AccAddress) SmartWalletState
28
+ ChargeForSmartWallet(ctx sdk.Context, addr sdk.AccAddress) error
18
29
  }
@@ -48,6 +48,33 @@ func chargeAdmission(ctx sdk.Context, keeper SwingSetKeeper, addr sdk.AccAddress
48
48
  return keeper.ChargeBeans(ctx, addr, beans)
49
49
  }
50
50
 
51
+ // checkSmartWalletProvisioned verifies if a smart wallet message (MsgWalletAction
52
+ // and MsgWalletSpendAction) can be delivered for the owner's address. A message
53
+ // is allowed if a smart wallet is already provisioned for the address, or if the
54
+ // provisioning fee is charged successfully.
55
+ // All messages for non-provisioned smart wallets allowed here will result in
56
+ // an auto-provision action generated by the msg server.
57
+ func checkSmartWalletProvisioned(ctx sdk.Context, keeper SwingSetKeeper, addr sdk.AccAddress) error {
58
+ walletState := keeper.GetSmartWalletState(ctx, addr)
59
+
60
+ switch walletState {
61
+ case SmartWalletStateProvisioned:
62
+ // The address already has a smart wallet
63
+ return nil
64
+ case SmartWalletStatePending:
65
+ // A provision (either explicit or automatic) may be pending execution in
66
+ // the controller, or if we ever allow multiple swingset messages per
67
+ // transaction, a previous message may have provisioned the wallet.
68
+ return nil
69
+ default:
70
+ // Charge for the smart wallet.
71
+ // This is a separate charge from the smart wallet action which triggered the check
72
+ // TODO: Currently this call does not mark the smart wallet provisioning as
73
+ // pending, resulting in multiple provisioning charges for the owner.
74
+ return keeper.ChargeForSmartWallet(ctx, addr)
75
+ }
76
+ }
77
+
51
78
  func NewMsgDeliverInbound(msgs *Messages, submitter sdk.AccAddress) *MsgDeliverInbound {
52
79
  return &MsgDeliverInbound{
53
80
  Messages: msgs.Messages,
@@ -137,6 +164,11 @@ func (msg MsgWalletAction) CheckAdmissibility(ctx sdk.Context, data interface{})
137
164
  return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "data must be a SwingSetKeeper, not a %T", data)
138
165
  }
139
166
 
167
+ err := checkSmartWalletProvisioned(ctx, keeper, msg.Owner)
168
+ if err != nil {
169
+ return err
170
+ }
171
+
140
172
  return chargeAdmission(ctx, keeper, msg.Owner, []string{msg.Action}, 0)
141
173
  }
142
174
 
@@ -204,6 +236,11 @@ func (msg MsgWalletSpendAction) CheckAdmissibility(ctx sdk.Context, data interfa
204
236
  return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "data must be a SwingSetKeeper, not a %T", data)
205
237
  }
206
238
 
239
+ err := checkSmartWalletProvisioned(ctx, keeper, msg.Owner)
240
+ if err != nil {
241
+ return err
242
+ }
243
+
207
244
  return chargeAdmission(ctx, keeper, msg.Owner, []string{msg.SpendAction}, 0)
208
245
  }
209
246
 
@@ -271,8 +308,12 @@ func (msg MsgProvision) ValidateBasic() error {
271
308
 
272
309
  // CheckAdmissibility implements the vm.ControllerAdmissionMsg interface.
273
310
  func (msg MsgProvision) CheckAdmissibility(ctx sdk.Context, data interface{}) error {
274
- // We have our own fee charging mechanism within Swingset itself,
275
- // so there are no admission restriction here.
311
+ // TODO: consider disallowing a provision message for a smart wallet if the
312
+ // smart wallet is already provisioned or pending provisioning. However we
313
+ // currently do not track whether a smart wallet is pending provisioning.
314
+
315
+ // For explicitly provisioning, swingset will take care of charging,
316
+ // so we skip admission fees.
276
317
  return nil
277
318
  }
278
319
 
@@ -163,3 +163,77 @@ func validateQueueMax(i interface{}) error {
163
163
  }
164
164
  return nil
165
165
  }
166
+
167
+ // UpdateParams appends any missing params, configuring them to their defaults,
168
+ // then returning the updated params or an error. Existing params are not
169
+ // modified, regardless of their value, and they are not removed if they no
170
+ // longer appear in the defaults.
171
+ func UpdateParams(params Params) (Params, error) {
172
+ newBpu, err := appendMissingDefaultBeansPerUnit(params.BeansPerUnit, DefaultBeansPerUnit())
173
+ if err != nil {
174
+ return params, err
175
+ }
176
+ newPff, err := appendMissingDefaultPowerFlagFees(params.PowerFlagFees, DefaultPowerFlagFees)
177
+ if err != nil {
178
+ return params, err
179
+ }
180
+ newQm, err := appendMissingDefaultQueueSize(params.QueueMax, DefaultQueueMax)
181
+ if err != nil {
182
+ return params, err
183
+ }
184
+
185
+ params.BeansPerUnit = newBpu
186
+ params.PowerFlagFees = newPff
187
+ params.QueueMax = newQm
188
+ return params, nil
189
+ }
190
+
191
+ // appendMissingDefaultBeansPerUnit appends the default beans per unit entries
192
+ // not in the list of bean costs already, returning the possibly-updated list,
193
+ // or an error.
194
+ func appendMissingDefaultBeansPerUnit(bpu []StringBeans, defaultBpu []StringBeans) ([]StringBeans, error) {
195
+ existingBpu := make(map[string]struct{}, len(bpu))
196
+ for _, ob := range bpu {
197
+ existingBpu[ob.Key] = struct{}{}
198
+ }
199
+
200
+ for _, b := range defaultBpu {
201
+ if _, exists := existingBpu[b.Key]; !exists {
202
+ bpu = append(bpu, b)
203
+ }
204
+ }
205
+ return bpu, nil
206
+ }
207
+
208
+ // appendMissingDefaultPowerFlagFees appends the default power flag fee entries
209
+ // not in the list of power flags already, returning the possibly-updated list,
210
+ // or an error.
211
+ func appendMissingDefaultPowerFlagFees(pff []PowerFlagFee, defaultPff []PowerFlagFee) ([]PowerFlagFee, error) {
212
+ existingPff := make(map[string]struct{}, len(pff))
213
+ for _, of := range pff {
214
+ existingPff[of.PowerFlag] = struct{}{}
215
+ }
216
+
217
+ for _, f := range defaultPff {
218
+ if _, exists := existingPff[f.PowerFlag]; !exists {
219
+ pff = append(pff, f)
220
+ }
221
+ }
222
+ return pff, nil
223
+ }
224
+
225
+ // appendMissingDefaultQueueSize appends the default queue size entries not in
226
+ // the list of sizes already, returning the possibly-updated list, or an error.
227
+ func appendMissingDefaultQueueSize(qs []QueueSize, defaultQs []QueueSize) ([]QueueSize, error) {
228
+ existingQs := make(map[string]struct{}, len(qs))
229
+ for _, os := range qs {
230
+ existingQs[os.Key] = struct{}{}
231
+ }
232
+
233
+ for _, s := range defaultQs {
234
+ if _, exists := existingQs[s.Key]; !exists {
235
+ qs = append(qs, s)
236
+ }
237
+ }
238
+ return qs, nil
239
+ }
@@ -0,0 +1,116 @@
1
+ package types
2
+
3
+ import (
4
+ "reflect"
5
+ "testing"
6
+
7
+ sdk "github.com/cosmos/cosmos-sdk/types"
8
+ )
9
+
10
+ type beans = StringBeans
11
+
12
+ func TestAddStorageBeanCost(t *testing.T) {
13
+ var defaultStorageCost beans
14
+ for _, b := range DefaultParams().BeansPerUnit {
15
+ if b.Key == BeansPerStorageByte {
16
+ defaultStorageCost = b
17
+ }
18
+ }
19
+ if defaultStorageCost.Key == "" {
20
+ t.Fatalf("no beans per storage byte in default params")
21
+ }
22
+
23
+ for _, tt := range []struct {
24
+ name string
25
+ in []beans
26
+ want []beans
27
+ }{
28
+ {
29
+ name: "empty",
30
+ in: []beans{},
31
+ want: []beans{defaultStorageCost},
32
+ },
33
+ {
34
+ name: "already_only_same",
35
+ in: []beans{defaultStorageCost},
36
+ want: []beans{defaultStorageCost},
37
+ },
38
+ {
39
+ name: "already_only_different",
40
+ in: []beans{NewStringBeans(BeansPerStorageByte, sdk.NewUint(123))},
41
+ want: []beans{NewStringBeans(BeansPerStorageByte, sdk.NewUint(123))},
42
+ },
43
+ {
44
+ name: "already_same",
45
+ in: []beans{
46
+ NewStringBeans("foo", sdk.NewUint(123)),
47
+ defaultStorageCost,
48
+ NewStringBeans("bar", sdk.NewUint(456)),
49
+ },
50
+ want: []beans{
51
+ NewStringBeans("foo", sdk.NewUint(123)),
52
+ defaultStorageCost,
53
+ NewStringBeans("bar", sdk.NewUint(456)),
54
+ },
55
+ },
56
+ {
57
+ name: "already_different",
58
+ in: []beans{
59
+ NewStringBeans("foo", sdk.NewUint(123)),
60
+ NewStringBeans(BeansPerStorageByte, sdk.NewUint(789)),
61
+ NewStringBeans("bar", sdk.NewUint(456)),
62
+ },
63
+ want: []beans{
64
+ NewStringBeans("foo", sdk.NewUint(123)),
65
+ NewStringBeans(BeansPerStorageByte, sdk.NewUint(789)),
66
+ NewStringBeans("bar", sdk.NewUint(456)),
67
+ },
68
+ },
69
+ {
70
+ name: "missing",
71
+ in: []beans{
72
+ NewStringBeans("foo", sdk.NewUint(123)),
73
+ NewStringBeans("bar", sdk.NewUint(456)),
74
+ },
75
+ want: []beans{
76
+ NewStringBeans("foo", sdk.NewUint(123)),
77
+ NewStringBeans("bar", sdk.NewUint(456)),
78
+ defaultStorageCost,
79
+ },
80
+ },
81
+ } {
82
+ t.Run(tt.name, func(t *testing.T) {
83
+ got, err := appendMissingDefaultBeansPerUnit(tt.in, []StringBeans{defaultStorageCost})
84
+ if err != nil {
85
+ t.Errorf("got error %v", err)
86
+ } else if !reflect.DeepEqual(got, tt.want) {
87
+ t.Errorf("want %v, got %v", tt.want, got)
88
+ }
89
+ })
90
+ }
91
+ }
92
+
93
+ func TestUpdateParams(t *testing.T) {
94
+
95
+ in := Params{
96
+ BeansPerUnit: []beans{},
97
+ BootstrapVatConfig: "baz",
98
+ FeeUnitPrice: sdk.NewCoins(sdk.NewInt64Coin("denom", 789)),
99
+ PowerFlagFees: []PowerFlagFee{},
100
+ QueueMax: []QueueSize{},
101
+ }
102
+ want := Params{
103
+ BeansPerUnit: DefaultBeansPerUnit(),
104
+ BootstrapVatConfig: "baz",
105
+ FeeUnitPrice: sdk.NewCoins(sdk.NewInt64Coin("denom", 789)),
106
+ PowerFlagFees: DefaultPowerFlagFees,
107
+ QueueMax: DefaultQueueMax,
108
+ }
109
+ got, err := UpdateParams(in)
110
+ if err != nil {
111
+ t.Fatalf("UpdateParam error %v", err)
112
+ }
113
+ if !reflect.DeepEqual(got, want) {
114
+ t.Errorf("got %v, want %v", got, want)
115
+ }
116
+ }
package/x/vbank/vbank.go CHANGED
@@ -68,15 +68,15 @@ func (vbu vbankManyBalanceUpdates) Swap(i int, j int) {
68
68
  }
69
69
 
70
70
  type vbankBalanceUpdate struct {
71
- Nonce uint64 `json:"nonce"`
72
- Type string `json:"type"`
73
- Updated vbankManyBalanceUpdates `json:"updated"`
71
+ vm.ActionHeader `actionType:"VBANK_BALANCE_UPDATE"`
72
+ Nonce uint64 `json:"nonce"`
73
+ Updated vbankManyBalanceUpdates `json:"updated"`
74
74
  }
75
75
 
76
76
  // getBalanceUpdate returns a bridge message containing the current bank balance
77
77
  // for the given addresses each for the specified denominations. Coins are used
78
78
  // only to track the set of denoms, not for the particular nonzero amounts.
79
- func getBalanceUpdate(ctx sdk.Context, keeper Keeper, addressToUpdate map[string]sdk.Coins) vm.Jsonable {
79
+ func getBalanceUpdate(ctx sdk.Context, keeper Keeper, addressToUpdate map[string]sdk.Coins) vm.Action {
80
80
  nentries := len(addressToUpdate)
81
81
  if nentries == 0 {
82
82
  return nil
@@ -84,7 +84,6 @@ func getBalanceUpdate(ctx sdk.Context, keeper Keeper, addressToUpdate map[string
84
84
 
85
85
  nonce := keeper.GetNextSequence(ctx)
86
86
  event := vbankBalanceUpdate{
87
- Type: "VBANK_BALANCE_UPDATE",
88
87
  Nonce: nonce,
89
88
  Updated: make([]vbankSingleBalanceUpdate, 0, nentries),
90
89
  }
@@ -111,7 +110,9 @@ func getBalanceUpdate(ctx sdk.Context, keeper Keeper, addressToUpdate map[string
111
110
 
112
111
  // Ensure we have a deterministic order of updates.
113
112
  sort.Sort(event.Updated)
114
- return event
113
+
114
+ // Populate the event default fields (even though event does not embed vm.ActionHeader)
115
+ return vm.PopulateAction(ctx, event)
115
116
  }
116
117
 
117
118
  func marshal(event vm.Jsonable) ([]byte, error) {
@@ -242,7 +243,7 @@ func (ch portHandler) Receive(ctx *vm.ControllerContext, str string) (ret string
242
243
  return
243
244
  }
244
245
 
245
- func (am AppModule) PushAction(ctx sdk.Context, action vm.Jsonable) error {
246
+ func (am AppModule) PushAction(ctx sdk.Context, action vm.Action) error {
246
247
  // vbank actions are not triggered by a swingset message in a transaction, so we need to
247
248
  // synthesize unique context information.
248
249
  // We use a fixed placeholder value for the txHash context, and can simply use `0` for the