-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Explicitly note that existing AccountIdConversion
is truncating and add fallible try_into...
#10719
Explicitly note that existing AccountIdConversion
is truncating and add fallible try_into...
#10719
Conversation
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.
A test that the truncating works is missing. I can do that later if you are not at it already.
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.
Added some comment and what should be fixed.
I'm not really convinced that this will help in tests, because people will still not get the relation between the input and a short account id. However, it should make the code more correct 👍
primitives/runtime/src/traits.rs
Outdated
if b.len() > T::max_encoded_len() { | ||
return None | ||
}; | ||
let account = T::decode(&mut TrailingZeroInput(b)) |
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.
IMO the check above is wrong, because if you for example have an enum max_encoded_len
returns you the length of the biggest enum variant. This is wrong here, just imagine you are decoding the shortest variant and then you would not have consumed all bytes.
If you want to make it correct, you need to extend TrailingZeroInput
to be able to check if the given input was consumed completely after having the type decoded.
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 AccountId
type has constant length, but in general I see that it does not work for all T
.
So my proposal of adding a const_encoded_len
could also fix this, right?
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 do you know that the AccountId
has a constant length? AccountId
is some generic value that could be anything (one of the reasons for this pr). Just because Polkadot uses AccountId32
, it doesn't mean that everyone uses this or is required to use 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.
Yes therefore we could add a FixEncodedLen
trait analogous to MaxEncodedLen
that requires a type to always have the same encoding len.
PS: Probably still better to make it work even for non FixEncodedLen
types 😄
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.
+1 using MaxEncodedLen
is IMO also wrong. Ideally, you just decode, and check how many bytes where actually used for decoding.
Maybe one trick here could be to decode, then re-encode, and see if we go back to the same bytes. A bit hacky and also assumes reversible encode/decode.
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 did something like what @kianenigma suggested. I check the length of the bytes used for the seed, and check that the length of bytes of the account is greater or equal to, otherwise, we know some bytes were truncated.
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. I also tried my luck on this but could not create a test that the function actually returns Some()
. The AccountId
type is u64, so an overflow is very likely anyway.
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.
You can just create a mock environment where account id is 32 bytes?
Hey, is anyone still working on this? Due to the inactivity this issue has been automatically marked as stale. It will be closed if no further activity occurs. Thank you for your contributions. |
This is still useful |
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 am a huge fan of this PR and have hit this wall in the past, but I think https://github.com/paritytech/substrate/pull/10719/files#r810890249 should be resolved first.
bot merge |
Error: "Check reviews" status is not passing for paritytech/polkadot#4947 |
bot merge |
Error: "Check reviews" status is not passing for paritytech/cumulus#1262 |
bot merge |
Error: Github API says paritytech/polkadot#4947 is not mergeable |
bot merge |
Error: "Check reviews" status is not passing for paritytech/polkadot#4947 |
bot merge |
We should have a https://github.com/paritytech/parity-scale-codec/blob/master/src/decode_all.rs#L22 |
… add fallible `try_into...` (paritytech#10719) * note truncating, add fallible try_into * fmt * migrate all to `truncating` * typo * uno mas * Update primitives/runtime/src/traits.rs Co-authored-by: Kian Paimani <[email protected]> * check the bytes before and after are sensible * fmt * Update lib.rs * Update primitives/runtime/src/traits.rs Co-authored-by: Bastian Köcher <[email protected]> Co-authored-by: Kian Paimani <[email protected]> Co-authored-by: Bastian Köcher <[email protected]>
… add fallible `try_into...` (paritytech#10719) * note truncating, add fallible try_into * fmt * migrate all to `truncating` * typo * uno mas * Update primitives/runtime/src/traits.rs Co-authored-by: Kian Paimani <[email protected]> * check the bytes before and after are sensible * fmt * Update lib.rs * Update primitives/runtime/src/traits.rs Co-authored-by: Bastian Köcher <[email protected]> Co-authored-by: Kian Paimani <[email protected]> Co-authored-by: Bastian Köcher <[email protected]>
… add fallible `try_into...` (paritytech#10719) * note truncating, add fallible try_into * fmt * migrate all to `truncating` * typo * uno mas * Update primitives/runtime/src/traits.rs Co-authored-by: Kian Paimani <[email protected]> * check the bytes before and after are sensible * fmt * Update lib.rs * Update primitives/runtime/src/traits.rs Co-authored-by: Bastian Köcher <[email protected]> Co-authored-by: Kian Paimani <[email protected]> Co-authored-by: Bastian Köcher <[email protected]>
Closes: #8564
closes: #10812
Tired of running into this problem accidentally when writing tests.
The behavior of
AccountIdConversion
may occasionally lead to duplicate accounts if the seed provided to generate the account is bigger than the encodedAccountId
type. In tests, where accounts are oftenu64
, this can happen, and actually lead to hard to debug behaviors with account balances, and stuff like that.This updates the API so that the existing behavior is explicitly mentioned, and also provides an alternative
try_into...
function which can handle such a truncation problem, and explicitly return an error when an infallible operation is not needed.BREAKS API!
Migration is simple:
Whenever you use
into_account
orinto_sub_account
, you must now explicitly choose betweeninto_account_truncating
ortry_into_account
, and if you use the latter, handle the situation where we may returnNone
.Polkadot companion: paritytech/polkadot#4947
cumulus companion: paritytech/cumulus#1262