Skip to content

Commit d21620d

Browse files
authored
docs: ADR 074: Msg v2 (#20618)
1 parent b9ca318 commit d21620d

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

docs/architecture/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ When writing ADRs, follow the same best practices for writing RFCs. When writing
9090
* [ADR 063: Core Module API](./adr-063-core-module-api.md)
9191
* [ADR 067: Simulator v2](./adr-067-simulator-v2.md)
9292
* [ADR 069: `x/gov` modularity, multiple choice and optimisic proposals](./adr-069-gov-improvements.md)
93+
* [ADR 074: Messages with implicit signers](./adr-074-implicit-msg-signers.md)
9394

9495
### Draft
9596

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# ADR 074: Messages with Implicit Signers
2+
3+
## Changelog
4+
5+
* 2024-06-10: Initial draft
6+
7+
## Status
8+
9+
PROPOSED Not Implemented
10+
11+
## Abstract
12+
13+
This ADR introduces a new `MsgV2` standard where the signer of the message is implied by the
14+
credentials of the party sending it, and unlike the current design not part of the message body.
15+
This can be used for both simple inter-module message passing and simpler messages in transactions.
16+
17+
## Context
18+
19+
Historically operations in the SDK have been modelled with the `sdk.Msg` interface and
20+
the account signing the message has to be explicitly extracted from the body of `Msg`s.
21+
Originally this was via a `GetSigners` method on the `sdk.Msg` interface which returned
22+
instances of `sdk.AccAddress` which itself relied on a global variable for decoding
23+
the addresses from bech32 strings. This was a messy situation. In addition, the implementation
24+
for `GetSigners` was different for each `Msg` type and clients would need to do a custom
25+
implementation for each `Msg` type. These were improved somewhat with the introduction of
26+
the `cosmos.msg.v1.signer` protobuf option which allowed for a more standardised way of
27+
defining who the signer of a message was and its implementation in the `x/tx` module which
28+
extracts signers dynamically and allowed removing the dependency on the global bech32
29+
configuration.
30+
31+
Still this design introduces a fair amount of complexity. For instance, inter-module message
32+
passing ([ADR 033](./adr-033-protobuf-inter-module-comm.md)) has been in discussion for years
33+
without much progress and one of the main blockers is figuring out how to properly authenticate
34+
messages in a performant and consistent way. With embedded message signers there will always need
35+
to be a step of extracting the signer and then checking with the module sending is actually
36+
authorized to perform the operation. With dynamic signer extraction, although the system is
37+
more consistent, more performance overhead is introduced. In any case why should an inter-module
38+
message passing system need to do so much conversion, parsing, etc. just to check if a message
39+
is authenticated? In addition, we have the complexity where modules can actually have many valid
40+
addresses. How are we to accommodate this? Should there be a lookup into `x/auth` to check if an
41+
address belongs to a module or not? All of these thorny questions are delaying the delivery of
42+
inter-module message passing because we do not want an implementation that is overly complex.
43+
There are many use cases for inter-module message passing which are still relevant, the most
44+
immediate of which is a more robust denom management system in `x/bank` `v2` which is being explored
45+
in [ADR 071](https://github.com/cosmos/cosmos-sdk/pull/20316).
46+
47+
## Alternatives
48+
49+
Alternatives that have been considered are extending the current `x/tx` signer extraction system
50+
to inter-module message passing as defined in [ADR 033](./adr-033-protobuf-inter-module-comm.md).
51+
52+
## Decision
53+
54+
We have decided to introduce a new `MsgV2` standard whereby the signer of the message is implied
55+
by the credentials of the party sending it. These messages will be distinct from the existing messages
56+
and define new semantics with the understanding that signers are implicit.
57+
58+
In the case of messages passed internally by a module or `x/account` instance, the signer of a message
59+
will simply be the main root address of the module or account sending the message. An interface for
60+
safely passing such messages to the message router will need to be defined.
61+
62+
In the case of messages passed externally in transactions, `MsgV2` instances will need to be wrapped
63+
in a `MsgV2` envelope:
64+
```protobuf
65+
message MsgV2 {
66+
string signer = 1;
67+
google.protobuf.Any msg = 2;
68+
}
69+
```
70+
71+
Because the `cosmos.msg.v1.signer` annotation is required currently, `MsgV2` types should set the message option
72+
`cosmos.msg.v2.is_msg` to `true` instead.
73+
74+
Here is an example comparing a v1 an v2 message:
75+
```protobuf
76+
// v1
77+
message MsgSendV1 {
78+
option (cosmos.msg.v1.signer) = "from_address";
79+
string from_address = 1 ;
80+
string to_address = 2;
81+
repeated Coin amount = 3;
82+
}
83+
84+
// v2
85+
message MsgSendV2 {
86+
option (cosmos.msg.v2.is_msg) = true;
87+
// from address is implied by the signer
88+
string to_address = 1;
89+
repeated Coin amount = 2;
90+
}
91+
```
92+
93+
Modules defining handlers for `MsgV2` instances will need to extract the sender from the `context.Context` that is
94+
passed in. An interface in `core` which will be present on the `appmodule.Environment` will be defined for this purpose:
95+
```go
96+
type GetSenderService interface {
97+
GetSender(ctx context.Context) []byte
98+
}
99+
```
100+
101+
Sender addresses that are returned by the service will be simple `[]byte` slices and any bech32 conversion will be
102+
done by the framework.
103+
104+
## Consequences
105+
106+
### Backwards Compatibility
107+
108+
This design does not depreciate the existing method of embedded signers in `Msg`s and is totally compatible with it.
109+
110+
### Positive
111+
112+
* Allows for a simple inter-module communication design which can be used soon for the `bank` `v2` redesign.
113+
* Allows for simpler client implementations for messages in the future.
114+
115+
### Negative
116+
117+
* There will be two message designs and developers will need to pick between them.
118+
119+
### Neutral
120+
121+
## Further Discussions
122+
123+
Two possible directions that have been proposed are:
124+
1. allowing for the omission of the `cosmos.msg.v2.is_msg` option and assuming any `Msg`s registered that do not include `cosmos.msg.v1.signer` are `MsgV2` instances. The pitfall is that this could be incorrect if `Msg` v1 behavior is actually decided but the user forgot the `cosmos.msg.v1.signer` option.
125+
2. allow `Msg` v1 instances to be wrapped in a `MsgV2` envelope as well to simplify things client-side. In this scenario we would need to either a) check that the signer in the envelope and the signer in the message are the same or b) allow the signer in the message to be empty and then set it inside the state machine before it reaches the module. While this may be easier for some clients, it may introduce unexpected behavior with Ledger signing via Amino JSON or SIGN_MODE_TEXTUAL.
126+
127+
Both of these are seem as quality of life improvements for some users, but not strictly necessary and could have some pitfalls so further discussion is needed.
128+
129+
## References
130+
131+
* [ADR 033](./adr-033-protobuf-inter-module-comm.md)

0 commit comments

Comments
 (0)