Skip to content

Commit e654808

Browse files
authored
Add msg update contract label (#1640)
* Add msg update contract label * fix tests
1 parent af8c491 commit e654808

File tree

13 files changed

+914
-109
lines changed

13 files changed

+914
-109
lines changed

docs/proto/proto-docs.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@
112112
- [MsgUnpinCodesResponse](#cosmwasm.wasm.v1.MsgUnpinCodesResponse)
113113
- [MsgUpdateAdmin](#cosmwasm.wasm.v1.MsgUpdateAdmin)
114114
- [MsgUpdateAdminResponse](#cosmwasm.wasm.v1.MsgUpdateAdminResponse)
115+
- [MsgUpdateContractLabel](#cosmwasm.wasm.v1.MsgUpdateContractLabel)
116+
- [MsgUpdateContractLabelResponse](#cosmwasm.wasm.v1.MsgUpdateContractLabelResponse)
115117
- [MsgUpdateInstantiateConfig](#cosmwasm.wasm.v1.MsgUpdateInstantiateConfig)
116118
- [MsgUpdateInstantiateConfigResponse](#cosmwasm.wasm.v1.MsgUpdateInstantiateConfigResponse)
117119
- [MsgUpdateParams](#cosmwasm.wasm.v1.MsgUpdateParams)
@@ -1845,6 +1847,33 @@ MsgUpdateAdminResponse returns empty data
18451847

18461848

18471849

1850+
<a name="cosmwasm.wasm.v1.MsgUpdateContractLabel"></a>
1851+
1852+
### MsgUpdateContractLabel
1853+
MsgUpdateContractLabel sets a new label for a smart contract
1854+
1855+
1856+
| Field | Type | Label | Description |
1857+
| ----- | ---- | ----- | ----------- |
1858+
| `sender` | [string](#string) | | Sender is the that actor that signed the messages |
1859+
| `new_label` | [string](#string) | | NewLabel string to be set |
1860+
| `contract` | [string](#string) | | Contract is the address of the smart contract |
1861+
1862+
1863+
1864+
1865+
1866+
1867+
<a name="cosmwasm.wasm.v1.MsgUpdateContractLabelResponse"></a>
1868+
1869+
### MsgUpdateContractLabelResponse
1870+
MsgUpdateContractLabelResponse returns empty data
1871+
1872+
1873+
1874+
1875+
1876+
18481877
<a name="cosmwasm.wasm.v1.MsgUpdateInstantiateConfig"></a>
18491878

18501879
### MsgUpdateInstantiateConfig
@@ -1946,6 +1975,9 @@ Since: 0.40 | |
19461975
| `StoreAndMigrateContract` | [MsgStoreAndMigrateContract](#cosmwasm.wasm.v1.MsgStoreAndMigrateContract) | [MsgStoreAndMigrateContractResponse](#cosmwasm.wasm.v1.MsgStoreAndMigrateContractResponse) | StoreAndMigrateContract defines a governance operation for storing and migrating the contract. The authority is defined in the keeper.
19471976

19481977
Since: 0.42 | |
1978+
| `UpdateContractLabel` | [MsgUpdateContractLabel](#cosmwasm.wasm.v1.MsgUpdateContractLabel) | [MsgUpdateContractLabelResponse](#cosmwasm.wasm.v1.MsgUpdateContractLabelResponse) | UpdateContractLabel sets a new label for a smart contract
1979+
1980+
Since: 0.43 | |
19491981

19501982
<!-- end services -->
19511983

proto/cosmwasm/wasm/v1/tx.proto

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ service Msg {
2929
rpc ExecuteContract(MsgExecuteContract) returns (MsgExecuteContractResponse);
3030
// Migrate runs a code upgrade/ downgrade for a smart contract
3131
rpc MigrateContract(MsgMigrateContract) returns (MsgMigrateContractResponse);
32-
// UpdateAdmin sets a new admin for a smart contract
32+
// UpdateAdmin sets a new admin for a smart contract
3333
rpc UpdateAdmin(MsgUpdateAdmin) returns (MsgUpdateAdminResponse);
3434
// ClearAdmin removes any admin stored for a smart contract
3535
rpc ClearAdmin(MsgClearAdmin) returns (MsgClearAdminResponse);
@@ -78,6 +78,11 @@ service Msg {
7878
// Since: 0.42
7979
rpc StoreAndMigrateContract(MsgStoreAndMigrateContract)
8080
returns (MsgStoreAndMigrateContractResponse);
81+
// UpdateContractLabel sets a new label for a smart contract
82+
//
83+
// Since: 0.43
84+
rpc UpdateContractLabel(MsgUpdateContractLabel)
85+
returns (MsgUpdateContractLabelResponse);
8186
}
8287

8388
// MsgStoreCode submit Wasm code to the system
@@ -472,4 +477,20 @@ message MsgStoreAndMigrateContractResponse {
472477
bytes checksum = 2;
473478
// Data contains bytes to returned from the contract
474479
bytes data = 3;
475-
}
480+
}
481+
482+
// MsgUpdateContractLabel sets a new label for a smart contract
483+
message MsgUpdateContractLabel {
484+
option (amino.name) = "wasm/MsgUpdateContractLabel";
485+
option (cosmos.msg.v1.signer) = "sender";
486+
487+
// Sender is the that actor that signed the messages
488+
string sender = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
489+
// NewLabel string to be set
490+
string new_label = 2;
491+
// Contract is the address of the smart contract
492+
string contract = 3 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
493+
}
494+
495+
// MsgUpdateContractLabelResponse returns empty data
496+
message MsgUpdateContractLabelResponse {}

x/wasm/client/cli/new_tx.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,31 @@ func UpdateInstantiateConfigCmd() *cobra.Command {
157157
flags.AddTxFlagsToCmd(cmd)
158158
return cmd
159159
}
160+
161+
// UpdateContractLabelCmd sets an new label for a contract
162+
func UpdateContractLabelCmd() *cobra.Command {
163+
cmd := &cobra.Command{
164+
Use: "set-contract-label [contract_addr_bech32] [new_label]",
165+
Short: "Set new label for a contract",
166+
Args: cobra.ExactArgs(2),
167+
RunE: func(cmd *cobra.Command, args []string) error {
168+
clientCtx, err := client.GetClientTxContext(cmd)
169+
if err != nil {
170+
return err
171+
}
172+
173+
msg := types.MsgUpdateContractLabel{
174+
Sender: clientCtx.GetFromAddress().String(),
175+
Contract: args[0],
176+
NewLabel: args[1],
177+
}
178+
if err = msg.ValidateBasic(); err != nil {
179+
return err
180+
}
181+
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
182+
},
183+
SilenceUsage: true,
184+
}
185+
flags.AddTxFlagsToCmd(cmd)
186+
return cmd
187+
}

x/wasm/client/cli/tx.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ func GetTxCmd() *cobra.Command {
7171
GrantCmd(),
7272
UpdateInstantiateConfigCmd(),
7373
SubmitProposalCmd(),
74+
UpdateContractLabelCmd(),
7475
)
7576
return txCmd
7677
}

x/wasm/keeper/keeper.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,26 @@ func (k Keeper) setContractAdmin(ctx context.Context, contractAddress, caller, n
653653
return nil
654654
}
655655

656+
func (k Keeper) setContractLabel(ctx context.Context, contractAddress, caller sdk.AccAddress, newLabel string, authZ types.AuthorizationPolicy) error {
657+
sdkCtx := sdk.UnwrapSDKContext(ctx)
658+
contractInfo := k.GetContractInfo(sdkCtx, contractAddress)
659+
if contractInfo == nil {
660+
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unknown contract")
661+
}
662+
if !authZ.CanModifyContract(contractInfo.AdminAddr(), caller) {
663+
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "can not modify contract")
664+
}
665+
contractInfo.Label = newLabel
666+
k.mustStoreContractInfo(sdkCtx, contractAddress, contractInfo)
667+
sdkCtx.EventManager().EmitEvent(sdk.NewEvent(
668+
types.EventTypeUpdateContractLabel,
669+
sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()),
670+
sdk.NewAttribute(types.AttributeKeyNewLabel, newLabel),
671+
))
672+
673+
return nil
674+
}
675+
656676
func (k Keeper) appendToContractHistory(ctx context.Context, contractAddr sdk.AccAddress, newEntries ...types.ContractCodeHistoryEntry) error {
657677
store := k.storeService.OpenKVStore(ctx)
658678
// find last element position

x/wasm/keeper/keeper_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2489,6 +2489,69 @@ func TestGasConsumed(t *testing.T) {
24892489
}
24902490
}
24912491

2492+
func TestSetContractLabel(t *testing.T) {
2493+
parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities)
2494+
k := keepers.WasmKeeper
2495+
example := InstantiateReflectExampleContract(t, parentCtx, keepers)
2496+
2497+
specs := map[string]struct {
2498+
newLabel string
2499+
caller sdk.AccAddress
2500+
policy types.AuthorizationPolicy
2501+
contract sdk.AccAddress
2502+
expErr bool
2503+
}{
2504+
"update label - default policy": {
2505+
newLabel: "new label",
2506+
caller: example.CreatorAddr,
2507+
policy: DefaultAuthorizationPolicy{},
2508+
contract: example.Contract,
2509+
},
2510+
"update label - gov policy": {
2511+
newLabel: "new label",
2512+
policy: GovAuthorizationPolicy{},
2513+
caller: RandomAccountAddress(t),
2514+
contract: example.Contract,
2515+
},
2516+
"update label - unauthorized": {
2517+
newLabel: "new label",
2518+
caller: RandomAccountAddress(t),
2519+
policy: DefaultAuthorizationPolicy{},
2520+
contract: example.Contract,
2521+
expErr: true,
2522+
},
2523+
"update label - unknown contract": {
2524+
newLabel: "new label",
2525+
caller: example.CreatorAddr,
2526+
policy: DefaultAuthorizationPolicy{},
2527+
contract: RandomAccountAddress(t),
2528+
expErr: true,
2529+
},
2530+
}
2531+
for name, spec := range specs {
2532+
t.Run(name, func(t *testing.T) {
2533+
ctx, _ := parentCtx.CacheContext()
2534+
em := sdk.NewEventManager()
2535+
ctx = ctx.WithEventManager(em)
2536+
gotErr := k.setContractLabel(ctx, spec.contract, spec.caller, spec.newLabel, spec.policy)
2537+
if spec.expErr {
2538+
require.Error(t, gotErr)
2539+
return
2540+
}
2541+
require.NoError(t, gotErr)
2542+
assert.Equal(t, spec.newLabel, k.GetContractInfo(ctx, spec.contract).Label)
2543+
// and event emitted
2544+
require.Len(t, em.Events(), 1)
2545+
assert.Equal(t, "update_contract_label", em.Events()[0].Type)
2546+
exp := map[string]string{
2547+
"_contract_address": spec.contract.String(),
2548+
"new_label": spec.newLabel,
2549+
}
2550+
assert.Equal(t, exp, attrsToStringMap(em.Events()[0].Attributes))
2551+
})
2552+
}
2553+
}
2554+
24922555
func attrsToStringMap(attrs []abci.EventAttribute) map[string]string {
24932556
r := make(map[string]string, len(attrs))
24942557
for _, v := range attrs {

x/wasm/keeper/msg_server.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,3 +462,26 @@ func (m msgServer) StoreAndMigrateContract(goCtx context.Context, req *types.Msg
462462
Data: data,
463463
}, nil
464464
}
465+
466+
func (m msgServer) UpdateContractLabel(ctx context.Context, msg *types.MsgUpdateContractLabel) (*types.MsgUpdateContractLabelResponse, error) {
467+
if err := msg.ValidateBasic(); err != nil {
468+
return nil, err
469+
}
470+
471+
senderAddr, err := sdk.AccAddressFromBech32(msg.Sender)
472+
if err != nil {
473+
return nil, errorsmod.Wrap(err, "sender")
474+
}
475+
contractAddr, err := sdk.AccAddressFromBech32(msg.Contract)
476+
if err != nil {
477+
return nil, errorsmod.Wrap(err, "contract")
478+
}
479+
480+
policy := m.selectAuthorizationPolicy(ctx, msg.Sender)
481+
482+
if err := m.keeper.setContractLabel(ctx, contractAddr, senderAddr, msg.NewLabel, policy); err != nil {
483+
return nil, err
484+
}
485+
486+
return &types.MsgUpdateContractLabelResponse{}, nil
487+
}

x/wasm/keeper/msg_server_integration_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,3 +1144,86 @@ func TestStoreAndMigrateContract(t *testing.T) {
11441144
})
11451145
}
11461146
}
1147+
1148+
func TestUpdateContractLabel(t *testing.T) {
1149+
wasmApp := app.Setup(t)
1150+
ctx := wasmApp.BaseApp.NewContextLegacy(false, tmproto.Header{Time: time.Now()})
1151+
1152+
var (
1153+
myAddress sdk.AccAddress = make([]byte, types.ContractAddrLen)
1154+
authority = wasmApp.WasmKeeper.GetAuthority()
1155+
_, _, otherAddr = testdata.KeyTestPubAddr()
1156+
)
1157+
1158+
specs := map[string]struct {
1159+
addr string
1160+
newLabel string
1161+
expErr bool
1162+
}{
1163+
"authority can update contract label": {
1164+
addr: authority,
1165+
newLabel: "new label",
1166+
expErr: false,
1167+
},
1168+
"admin can update contract label": {
1169+
addr: myAddress.String(),
1170+
newLabel: "new label",
1171+
expErr: false,
1172+
},
1173+
"other address cannot update contract label": {
1174+
addr: otherAddr.String(),
1175+
newLabel: "new label",
1176+
expErr: true,
1177+
},
1178+
"empty new label": {
1179+
addr: authority,
1180+
expErr: true,
1181+
},
1182+
"invalid new label": {
1183+
addr: authority,
1184+
newLabel: " start with space ",
1185+
expErr: true,
1186+
},
1187+
}
1188+
for name, spec := range specs {
1189+
t.Run(name, func(t *testing.T) {
1190+
// setup
1191+
msg := &types.MsgStoreAndInstantiateContract{
1192+
Authority: spec.addr,
1193+
WASMByteCode: wasmContract,
1194+
InstantiatePermission: &types.AllowEverybody,
1195+
Admin: myAddress.String(),
1196+
UnpinCode: false,
1197+
Label: "old label",
1198+
Msg: []byte(`{}`),
1199+
Funds: sdk.Coins{},
1200+
}
1201+
rsp, err := wasmApp.MsgServiceRouter().Handler(msg)(ctx, msg)
1202+
require.NoError(t, err)
1203+
var storeAndInstantiateResponse types.MsgStoreAndInstantiateContractResponse
1204+
require.NoError(t, wasmApp.AppCodec().Unmarshal(rsp.Data, &storeAndInstantiateResponse))
1205+
1206+
contract := storeAndInstantiateResponse.Address
1207+
contractAddr, err := sdk.AccAddressFromBech32(contract)
1208+
require.NoError(t, err)
1209+
require.Equal(t, "old label", wasmApp.WasmKeeper.GetContractInfo(ctx, contractAddr).Label)
1210+
1211+
// when
1212+
msgUpdateLabel := &types.MsgUpdateContractLabel{
1213+
Sender: spec.addr,
1214+
NewLabel: spec.newLabel,
1215+
Contract: storeAndInstantiateResponse.Address,
1216+
}
1217+
_, err = wasmApp.MsgServiceRouter().Handler(msgUpdateLabel)(ctx, msgUpdateLabel)
1218+
1219+
// then
1220+
if spec.expErr {
1221+
require.Error(t, err)
1222+
require.Equal(t, "old label", wasmApp.WasmKeeper.GetContractInfo(ctx, contractAddr).Label)
1223+
} else {
1224+
require.NoError(t, err)
1225+
require.Equal(t, spec.newLabel, wasmApp.WasmKeeper.GetContractInfo(ctx, contractAddr).Label)
1226+
}
1227+
})
1228+
}
1229+
}

x/wasm/types/codec.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
2727
cdc.RegisterConcrete(&MsgAddCodeUploadParamsAddresses{}, "wasm/MsgAddCodeUploadParamsAddresses", nil)
2828
cdc.RegisterConcrete(&MsgRemoveCodeUploadParamsAddresses{}, "wasm/MsgRemoveCodeUploadParamsAddresses", nil)
2929
cdc.RegisterConcrete(&MsgStoreAndMigrateContract{}, "wasm/MsgStoreAndMigrateContract", nil)
30+
cdc.RegisterConcrete(&MsgUpdateContractLabel{}, "wasm/MsgUpdateContractLabel", nil)
3031

3132
cdc.RegisterConcrete(&PinCodesProposal{}, "wasm/PinCodesProposal", nil)
3233
cdc.RegisterConcrete(&UnpinCodesProposal{}, "wasm/UnpinCodesProposal", nil)
@@ -79,6 +80,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
7980
&MsgAddCodeUploadParamsAddresses{},
8081
&MsgRemoveCodeUploadParamsAddresses{},
8182
&MsgStoreAndMigrateContract{},
83+
&MsgUpdateContractLabel{},
8284
)
8385
registry.RegisterImplementations(
8486
(*v1beta1.Content)(nil),

x/wasm/types/events.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const (
2424
EventTypeReply = "reply"
2525
EventTypeGovContractResult = "gov_contract_result"
2626
EventTypeUpdateContractAdmin = "update_contract_admin"
27+
EventTypeUpdateContractLabel = "update_contract_label"
2728
EventTypeUpdateCodeAccessConfig = "update_code_access_config"
2829
EventTypePacketRecv = "ibc_packet_received"
2930
// add new types to IsAcceptedEventOnRecvPacketErrorAck
@@ -61,6 +62,7 @@ const (
6162
AttributeKeyResultDataHex = "result"
6263
AttributeKeyRequiredCapability = "required_capability"
6364
AttributeKeyNewAdmin = "new_admin_address"
65+
AttributeKeyNewLabel = "new_label"
6466
AttributeKeyCodePermission = "code_permission"
6567
AttributeKeyAuthorizedAddresses = "authorized_addresses"
6668
AttributeKeyAckSuccess = "success"

0 commit comments

Comments
 (0)