-
Notifications
You must be signed in to change notification settings - Fork 249
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
refactor(types): change account id to newtype and deprecate ValidAccountId #448
Conversation
env::is_valid_account_id(account_id.as_bytes()), | ||
"Given account ID is invalid" | ||
); | ||
pub fn get_status(&self, account_id: AccountId) -> Option::<String> { |
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.
pub fn get_status(&self, account_id: AccountId) -> Option::<String> { | |
pub fn get_status(&self, account_id: AccountId) -> Option<String> { |
Or is the turbofish actually required by the macro?
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 is required, I haven't dug into why specifically it's needed yet
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's needed because of the metadata macro generation, because it calls Option::<String>::schema_container()
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.
Looks quite thorough. And I believe you'd addressed what Kladov has brought up. My only silly suggestion is to have the one error begin with Invalid
instead of In
but 🤷🏼
4a0dd74
to
d36276c
Compare
Hey-hey! Node Interfaces team is working on a similar thing in nearcore (@miraclx has it in a branch state for now: near/nearcore@master...miraclx:strict-account-id-validity) and even decided to create a separate crate out of it ( |
We can't use that implementation in its current state because it pulls in a few dependencies and uses regex for validation which is too bulky for the SDK (especially since an OKR for the last and upcoming quarter is minimizing contract size) |
Because this is such a breaking change, it'd be great to get input from others. Also, the primary remaining design decision is if we change the underlying type to |
We can definitely onboard this implementation as I also don't feel very good about pulling the whole regex machinery to validate the account ID format. Have you measured the difference of |
The size of memory is the same, not sure about the compiled code (as it depends a lot on the use case). I am also noticing when switching to the Boxed versions that |
@frol wrt above near/borsh-rs#36 which is just a benefit to borsh, but would allow these alternatives to be used here (I checked) |
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.
Looks good to me, left a whole bunch of nits, but only three serious comments:
- deriving BorshDeserialize for AccountId is wrong
- still not sure that extra conversions are worth it, but don't see anything particularly problematic there
- i don't undrestand the reason for AsRef-ing promise API
@@ -7,6 +7,7 @@ use near_sdk::{ | |||
// callback_vec, |
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.
Why do we need cross_contract_high_level.wasm and cross_contract_low_level.wasm blobs here, and why they grew by several kbs?
@@ -39,7 +39,7 @@ fn check_promise() { | |||
let (master_account, contract, _alice) = init(to_yocto("10000")); | |||
let res = view!(contract.promise_checked()); | |||
assert_eq!(res.unwrap_json::<bool>(), false); | |||
let status_id = "status".to_string(); | |||
let status_id: near_sdk::AccountId = "status".parse().unwrap(); |
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 wonder if these unwraps are to blame for additional bloat?
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'll check around the code size in a bit. Committing the wasm files was a mistake and how I built them also causes a difference on master
. Definitely want to look into making it part of the CI in some way to check differences
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.
Agreed, and as we discussed in this morning's meeting, this is capture in #465
Think I've addressed everything else, but curious why you think this is wrong? Any contract using the old |
It allows creating #[test]
fn deser_checks_validity() {
let r1 = "💩".parse::<AccountId>();
assert!(r1.is_err()); // correct, 💩 is not a valid account name
let bytes = "💩".try_to_vec().unwrap();
let r2 = AccountId::try_from_slice(&bytes);
let acc = r2.unwrap();
assert_eq!(acc.as_str(), "💩") // BUG, 💩 is treated as a valid account
} As a rule of thumb, type's invariants should be checked in every constructor, and deserialization provides an extra constructor. We shouldn't change serialization format, but we should add an extra validation to deserialization. |
Ah, of course, oops |
33e7684
to
3e24240
Compare
Definitely more involved than I would have liked and it's unclear what is the best way to initialize an
AccountId
but here is what changes:AccountId
from aString
alias to a newtype which performs the validation, JSON/borsh serialization, and other necessary interactionsValidAccountId
AccountId
for this, but it caused a lot of confusing errors linking to it instead ofAccountId
, and should probably be removed sooner than laterThis is quite a large breaking change, because using
String
is quite nested within everything, and interactions fromValidAccountId
specifically will cause breakages with existing contracts.closes #446