I tried to find evidence from the old forum thread, working group minutes and other material as to how the switch from account ids to principal.subaccount pairs came to be. Unfortunately, I couldn’t find the transition point. At some point in May 2022 the topic of which one to use is still completely open between the two options. Then the discussion switched to a Discord channel to which I have no access or which may not exist anymore. And at some point in June it had been decided that the principal.subaccount pairs are being used and the discussion from thereon is about other aspects. I can’t tell which argument was responsible for the shift.
Comparing the two options and looking for advantages of each we should should look at only the bare standard which ends at the ledger interface. We should ignore the encoding of the account identifier which is really just an exchange format for sending a payment destination to another user. For example, to illustrate the difference: one could have defined the textual representation that we now have for ICRC-1 accounts, which looks like this h5boe-vqaaa-aaaam-ac36q-cai-ckw43vy.6867bf53ffcaa0cd11f3bb59be8e4d9e71b20d096cc822a5dffecc7561b026ce
, as an exchange format, not requiring any new ledger standard, and could have used it for making payments on the original account id based ledger.
So if we focus on the differences between the two standards, ending at the ledger interface, then we see:
- account ids are shorter, 32 bytes (or without checksum 28 bytes)
- principal.subaccount pairs are longer but contain more information, most importantly the principal who controls the account
The first difference is important because 32 bytes is often an important barrier, so ICRC-1 gives something up here and account ids have an advantage.
Let’s leave the privacy issue out of the discussion and leave it for another day.
Slight advantage of the principal.subaccount pair at this point is that it requires less tooling/dependencies on the client side because you don’t need to have the code to calculate the hash correctly.
What other advantage can principal.subaccount have, if any? It depends on what the ledger does with that information. For example, does it need the information because it’s internal balance database requires it? Or does it need it to write the information into the generated blockchain?
Let’s discuss the database first. In a single-canister implementation the internal database layout is irrelevant. Whether it is keyed on account ids or keyed on the explicit principal.subaccount pair, or keyed in a hierarchical way on principal first, then subaccount, makes no difference. All ways are possible to get a functional ICRC-1 compliant ledger. In a sharded ledger on the other hand, there could be some advantage to keeping accounts that belong to the same principal on the same shard. But I somehow doubt that sharding was a consideration in the discussion.
Writing the information to the blockchain is the only reason left and that was for sure a goal of ICRC-1. It wanted the explicit principal.subaccount pairs in the blockchain. And it wanted all of them in the blockchain, not only some on an opt-in basis. Because for the opt-in basis the solution would have been to keep the account id interface in place and to extend it with another interface that users who opt-in can use. The reason must have been transparency.
That’s basically the entire trade off here: giving up the <= 32 byte length for transparency and slightly simpler client code.
The weird thing is that ICRC-1 specification does not mention the blockchain and the fact that the full principal.subaccount information is to be written into it. So the real intention of the standard is not mentioned in its specification. I have been critical in the past of the ICRC-1 spec as being underspecified in the sense that it does not talk about semantics, only about the interface. A standard has to include semantics or it’s not a standard. This is another example of this fact. The spec should say that the ledger MUST maintain a blockchain and MUST write the principal.subaccount pair of every transaction into it. For, if it wasn’t like that, then we could have just used the account id based ledger and defined principal.subaccount pairs as an exchange format.
Regarding the trade-off mentioned above, I can understand the trade-off because I can make a lot of arguments for transparency and find that feature very useful. Whether if it is was really worth making a new standard for it after the account ids were already out in the wild is another question.