-
Notifications
You must be signed in to change notification settings - Fork 413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: ContractAuthorization (authz) #966
Conversation
Codecov Report
@@ Coverage Diff @@
## main #966 +/- ##
==========================================
- Coverage 59.36% 59.13% -0.23%
==========================================
Files 51 52 +1
Lines 6231 6299 +68
==========================================
+ Hits 3699 3725 +26
- Misses 2266 2306 +40
- Partials 266 268 +2
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for the PR and driving this forward. Very nice! I had a quick look and added some comments.
I assume the authz module ensures that the sender has permission to set the ContractAutorization. But how does it work when not called from the contract? The CLI does not have keys for the contract address. I need to 👁️ at the module but if you can point me to the code line , that would help
repeated string messages = 2; | ||
|
||
// Once specifies if the contract can only be called once | ||
bool once = 3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to have a counter to decrement instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, can be executions
?
|
||
// ValidateBasic implements Authorization.ValidateBasic. | ||
func (a ContractAuthorization) ValidateBasic() error { | ||
if len(a.Contract) == 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does not hurt but the empty string is covered by AccAddressFromBech32()
also
if len(a.Messages) == 0 { | ||
return sdkerrors.ErrInvalidRequest.Wrap("empty msg list") | ||
} | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there any constraints on the message content? Like no empty strings, no whitespaces start/end, no duplicates?
return authztypes.AcceptResponse{}, sdkerrors.ErrUnauthorized.Wrapf("cannot run %s contract", exec.Contract) | ||
} | ||
|
||
gasForDeserialization := gasDeserializationCostPerByte * uint64(len(exec.Msg)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 very nice that you have gas costs on your list. All the prices have been encapsulated into the GasRegister to make it customizable for chains via Options
.
|
||
gasForDeserialization := gasDeserializationCostPerByte * uint64(len(exec.Msg)) | ||
ctx.GasMeter().ConsumeGas(gasForDeserialization, "contract authorization") | ||
if err := IsJSONObjectWithTopLevelKey(exec.Msg, a.Messages); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The design decision was to not make assumptions about the message data other than it is valid json. I can understand that you want more fine grained control in the authorization but [{"foo":"bar"}]
is valid json as well.
Any thoughts to cover or document this?
There is also no way to grant access to all contract messages. Would it make sense to support this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think IsJSONObjectWithTopLevelKey
verifies the requirements.
string contract = 1; | ||
|
||
// Messages is the list of messages that can be executed | ||
repeated string messages = 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
messages
is a bit ambiguous. Technically they are just json object keys. Now about allowed_json_keys
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw a similarity to GenericAuthorization, it says msg
although it is only the type URL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the messages the same as "execute methods" here? Amazing work, just catching up now
option go_package = "github.com/CosmWasm/wasmd/x/wasm/types"; | ||
|
||
// ContractAuthorization defines authorization for wasm execute. | ||
message ContractAuthorization { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about ContractExecuteAuthorization
? There may be other contract authz like set permission, set admin,... in the future
|
||
// Accept implements Authorization.Accept. | ||
func (a ContractAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authztypes.AcceptResponse, error) { | ||
exec, ok := msg.(*MsgExecuteContract) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to check!
Any user can grant ContractAutorization, a contract can give an authorization using Full example: User grants the "claim" msg wasmd tx wasm grant $GRANTEE_ADDR $STAKE_CONTRACT --allow-msgs claim --from granter Grantee executes the contract wasmd tx wasm execute $STAKE_CONTRACT '{"claim":{}}' --from $GRANTER_ADDR --generate-only > claim.json
wasmd tx authz exec claim.json --from grantee |
I need to add a list in ContractAuthorization, because with the current implementation I can only give permission to a single contract per grantee. eg. I could not give permissions ContractX:claim and ContractY:swap to the same grantee. |
Thanks for the examples! This helped me to get a better picture!
Good finding. The store key is built from grantee, granter, msgType. |
@giansalex I have started a spike based on your work to model this. I may be able to push this later today or on Monday. The proto would looks like below. WDYT? // ContractExecutionAuthorization defines authorization for wasm execute.
message ContractExecutionAuthorization {
option (cosmos_proto.implements_interface) = "Authorization";
repeated ContractExecutionGrant grants = 1 [ (gogoproto.nullable) = false ];
}
// ContractExecutionGrant a granted execute permission for a single contract
message ContractExecutionGrant {
// Contract is the address of the smart contract
string contract = 1;
// Filter rules to apply
oneof filter {
AcceptedMessageKeysFilter accepted_message_keys = 2;
AllowAllWildcard allow_all_wildcard = 3;
}
// RemainingCalls specifies the number of authorized executions remaining
uint64 remaining_calls = 4;
}
// AllowAllWildcard is a wildcard to allow any type of contract execution
// message
message AllowAllWildcard {}
// AcceptedMessageKeysFilter accept specific contract message keys in the json
// object that can be executed
message AcceptedMessageKeysFilter {
// Messages is the list of unique keys
repeated string messages = 1;
} |
Yes, I was also thinking about a list.
About remaining_calls, what happens when it becomes unlimited, will 0 be used? Staking authz uses nil for unlimited max-tokens https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/x/staking/types/authz.go#L101 |
good point! IMHO it makes sense to make it explicit or do not support unlimited. I have pushed an example to: |
I am not against unlimited because authz MsgGrant has an expiration field, although with a high value in I did not see any new changes in 966_grants_spike branch |
These features will be in the next v0.30 release, maybe the version in #978 based on it. Let's work together to get some clear design we all agree on. |
closes #803
cli examples:
query grants