Skip to content

Commit 3f634a3

Browse files
mergify[bot]pinosu
andauthored
Add msg update contract label (backport #1640) (#1642)
* Add msg update contract label (#1640) * Add msg update contract label * fix tests (cherry picked from commit e654808) # Conflicts: # x/wasm/keeper/keeper.go # x/wasm/types/tx.pb.go * Fix conflicts --------- Co-authored-by: pinosu <[email protected]> Co-authored-by: Pino' Surace <[email protected]>
1 parent 03f3c72 commit 3f634a3

File tree

13 files changed

+913
-108
lines changed

13 files changed

+913
-108
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
@@ -27,7 +27,7 @@ service Msg {
2727
rpc ExecuteContract(MsgExecuteContract) returns (MsgExecuteContractResponse);
2828
// Migrate runs a code upgrade/ downgrade for a smart contract
2929
rpc MigrateContract(MsgMigrateContract) returns (MsgMigrateContractResponse);
30-
// UpdateAdmin sets a new admin for a smart contract
30+
// UpdateAdmin sets a new admin for a smart contract
3131
rpc UpdateAdmin(MsgUpdateAdmin) returns (MsgUpdateAdminResponse);
3232
// ClearAdmin removes any admin stored for a smart contract
3333
rpc ClearAdmin(MsgClearAdmin) returns (MsgClearAdminResponse);
@@ -76,6 +76,11 @@ service Msg {
7676
// Since: 0.42
7777
rpc StoreAndMigrateContract(MsgStoreAndMigrateContract)
7878
returns (MsgStoreAndMigrateContractResponse);
79+
// UpdateContractLabel sets a new label for a smart contract
80+
//
81+
// Since: 0.43
82+
rpc UpdateContractLabel(MsgUpdateContractLabel)
83+
returns (MsgUpdateContractLabelResponse);
7984
}
8085

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

x/wasm/client/cli/new_tx.go

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

x/wasm/client/cli/tx.go

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

x/wasm/keeper/keeper.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,25 @@ func (k Keeper) setContractAdmin(ctx sdk.Context, contractAddress, caller, newAd
630630
return nil
631631
}
632632

633+
func (k Keeper) setContractLabel(ctx sdk.Context, contractAddress, caller sdk.AccAddress, newLabel string, authZ types.AuthorizationPolicy) error {
634+
contractInfo := k.GetContractInfo(ctx, contractAddress)
635+
if contractInfo == nil {
636+
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unknown contract")
637+
}
638+
if !authZ.CanModifyContract(contractInfo.AdminAddr(), caller) {
639+
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "can not modify contract")
640+
}
641+
contractInfo.Label = newLabel
642+
k.storeContractInfo(ctx, contractAddress, contractInfo)
643+
ctx.EventManager().EmitEvent(sdk.NewEvent(
644+
types.EventTypeUpdateContractLabel,
645+
sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()),
646+
sdk.NewAttribute(types.AttributeKeyNewLabel, newLabel),
647+
))
648+
649+
return nil
650+
}
651+
633652
func (k Keeper) appendToContractHistory(ctx sdk.Context, contractAddr sdk.AccAddress, newEntries ...types.ContractCodeHistoryEntry) {
634653
store := ctx.KVStore(k.storeKey)
635654
// find last element position

x/wasm/keeper/keeper_test.go

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

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

x/wasm/keeper/msg_server.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,3 +474,27 @@ func (m msgServer) StoreAndMigrateContract(goCtx context.Context, req *types.Msg
474474
Data: data,
475475
}, nil
476476
}
477+
478+
func (m msgServer) UpdateContractLabel(goCtx context.Context, msg *types.MsgUpdateContractLabel) (*types.MsgUpdateContractLabelResponse, error) {
479+
if err := msg.ValidateBasic(); err != nil {
480+
return nil, err
481+
}
482+
483+
ctx := sdk.UnwrapSDKContext(goCtx)
484+
senderAddr, err := sdk.AccAddressFromBech32(msg.Sender)
485+
if err != nil {
486+
return nil, errorsmod.Wrap(err, "sender")
487+
}
488+
contractAddr, err := sdk.AccAddressFromBech32(msg.Contract)
489+
if err != nil {
490+
return nil, errorsmod.Wrap(err, "contract")
491+
}
492+
493+
policy := m.selectAuthorizationPolicy(ctx, msg.Sender)
494+
495+
if err := m.keeper.setContractLabel(ctx, contractAddr, senderAddr, msg.NewLabel, policy); err != nil {
496+
return nil, err
497+
}
498+
499+
return &types.MsgUpdateContractLabelResponse{}, nil
500+
}

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.NewContext(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
@@ -31,6 +31,7 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
3131
cdc.RegisterConcrete(&MsgAddCodeUploadParamsAddresses{}, "wasm/MsgAddCodeUploadParamsAddresses", nil)
3232
cdc.RegisterConcrete(&MsgRemoveCodeUploadParamsAddresses{}, "wasm/MsgRemoveCodeUploadParamsAddresses", nil)
3333
cdc.RegisterConcrete(&MsgStoreAndMigrateContract{}, "wasm/MsgStoreAndMigrateContract", nil)
34+
cdc.RegisterConcrete(&MsgUpdateContractLabel{}, "wasm/MsgUpdateContractLabel", nil)
3435

3536
cdc.RegisterConcrete(&PinCodesProposal{}, "wasm/PinCodesProposal", nil)
3637
cdc.RegisterConcrete(&UnpinCodesProposal{}, "wasm/UnpinCodesProposal", nil)
@@ -83,6 +84,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
8384
&MsgAddCodeUploadParamsAddresses{},
8485
&MsgRemoveCodeUploadParamsAddresses{},
8586
&MsgStoreAndMigrateContract{},
87+
&MsgUpdateContractLabel{},
8688
)
8789
registry.RegisterImplementations(
8890
(*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)