As many of you know, the ICRC-1 interface was received very well and accepted: Internet Computer Network Status. If you want to learn more about the design principles behind the standard and the future steps, I wrote a medium post on this topic.
We also realized that WG discussions are less productive than they could be. One reason is that the meeting agenda is usually unknown before the meeting starts. We hope that advertising the topic in advance might increase participation and productivity.
The next WG meeting is tomorrow; weāll finalize the textual encoding and discuss the acceptance test suite and the transaction log specs.
Are there meeting minutes of the WG meeting for those who werenāt able to attend?
What was the outcome?
Regarding the textual encoding: no objections to the encoding with explicit subaccount length and ānot a principalā marker. Everyone agreed that having short subaccounts with automatic padding might be useful. We can specify that encoders are allowed to do such space optimizations, and decoders must respect them.
Ok, so encoders can use the abbreviation with automatic padding or can choose not to? That means there is no uniqueness, or, more precisely, we can have anywhere between 1-33 different encodings for the same account (because the encoder can choose to abbreviate any number of trailing zero bytes).
Yes, but the encoding is already non-unique in the presence of default subaccounts. The WG agreed that we should be flexible in encodings that we accept and advice applications not to use textual representations as keys (in a map/database, etc), but rather decode the strings and normalize them. Thatās what the ledger has to do as well.
Yes, Iāve talked to @bjoern about it before the WG meeting and he was cool with that. Iāll prepare a spec change.
Is that so easy? Thinking for example about a block explorer where you paste in the account identifier and then get back all transactions of it. So then I would paste in one encoding but in the transaction list that I see it may then appear in a different encoding? Or does it appear in a completely different way, as a pair with the subaccount id bytes exposed? Might be confusing. Whether the pair is exposed or the textual encoding is shown can be easily solved with a toggle. But not the same way between different textual encodings.
I also started thinking about block explorers and how users might be confused because some app didnāt apply an optimization, but another did.
Then we have to enforce optimizations on the spec level and reject unoptimized encodings from the very start. This will give use uniqueness, but will break some natural properties, such as
ā a ā Account : decodeAccount(encodeAccount(a)) = a
Iām think that not a huge problem, but would be nice to listen to more opinions, e.g., from @bogdanwarinschi.
The pair is (principal, opt blob). Optimizing (principal, opt DEFAULT) to (principal, null) is required for uniqueness, unless we remove the requirement that (principal, opt DEFAULT) is the same is (principal, null) (which will be incompatible with the ICP ledger).
Maybe I donāt understand. The problem with the default account was always there, wasnāt it? What changes with respect to it?
I am trying to understand the statement:
Why does enforcing an optimization break a property that held before? The problem was already there without the optimization, or?
We would basically have to say that (principal, 32*0x00) is not a valid account, only (principal, null) is. If you want to have the cited property, the encoder has to reject (principal, 32*0x00).
But maybe Iām misunderstanding something. What does (principal, opt DEFAULT) stand for by the way?
If we want uniqueness property, we have to enforce all optimizations, including the substitution of (principal, 32*0x00) for (principal, null). So decode(encode(principal, 32*0x00)) is equal to (principal, null), which is semantically equivalent to (principal, 32*0x00), but structurally different (all programming languages will consider these two objects non-equal). I think we can live with that, but thatās what I meant by breaking a natural property. In the original proposal, decode(encode(principal, 32*0x00)) = (principal, 32*0x00).
Then we lose another natural property that encoding is a total function.
Well, within candid types and Motoko types it is not total anyway because blob/Blob doesnāt limit the size to 32 bytes. So encode will always reject some things that passes as correct type. So we could also reject 32*0x00.
Anyway, remind me why we want account type to be (principal, opt blob) rather than (principal, blob)? Is it just more convenient to make calls by hand with dfx in the null case? Or does it make client code look nicer when dealing with default accounts?
Both of these + the fact that most of users donāt need to care about subaccounts.
And the killer feature IMO is that this way each principal can be a valid account.
Ok, I think I see your point. You propose that we make the form (principal, blob) as a canonical form so blob always has to be specified in the Ledger interface, but the ledger and the client libraries can take liberties in how they store the ādefaultā value?
I see the null case as a space and usability optimization for the most common case. We can live without it, but itās a bit hard to go back and change ICRC-1 to make subaccounts required.
Alternatively, I think it also acceptable to tell the users that all zeros isnāt a valid subaccount. They can either use the default account or they can specify a non-zero subaccount. It makes sense and the worry that a function isnāt total seems minor. What the internal representation does with that is up to the developer. They can represent the default by all-zeros or in some other way. That is not visible to the user. But the encode and decode functions have to throw an error if you feed in what would result in an all-zero subaccount.