-
Notifications
You must be signed in to change notification settings - Fork 683
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
feat: add block hash API to near_vm_logic #4256
Conversation
@@ -18,6 +18,9 @@ pub type Nonce = u64; | |||
pub type BlockHeight = u64; | |||
/// Height of the epoch. | |||
pub type EpochHeight = u64; | |||
/// Block hash. | |||
#[cfg(feature = "protocol_feature_vm_hash")] | |||
pub type BlockHash = [u8; 32]; |
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 is it a new type instead of a CryptoHash
?
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.
Right, CryptoHash
is a Newtype, and not just a normal type. I was thinking about the returns of the vm logic and how all of them are quite generalized types for primitives, and not Newtypes. So was following that.
Otherwise, I would've used CryptoHash
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 think, it is mostly a coincidence that most of the types returned by vm logic are generalized. I would use CryptoHash
here, if possible, to avoid introducing new aliases.
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.
type
in rust introduce alias, pub type BlockHash = CryptoHash
plus type CryptoHash = [u8;32]
will have equivalent semantic result as type BlockHash=[u8;32]
but more robust if some day we change CryptoHash's definition
core/primitives-core/src/types.rs
Outdated
@@ -18,6 +18,9 @@ pub type Nonce = u64; | |||
pub type BlockHeight = u64; | |||
/// Height of the epoch. | |||
pub type EpochHeight = u64; | |||
/// Block hash. | |||
#[cfg(feature = "protocol_feature_vm_hash")] |
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.
Does a type alias need a feature check? It seems that it adds more complexity than its worth.
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.
Fair point, as it shouldn't complain that it isn't being used.
/// | ||
/// `base` | ||
#[cfg(feature = "protocol_feature_vm_hash")] | ||
pub fn block_hash(&mut self) -> Result<BlockHash> { |
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'm a fan of full type path here so that you don't need the feature check at the top of the file. But again it's a personal preference.
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.
If we want to have block hashes - let's surface all the available block hashes based on the block index - e.g. 2 last epochs.
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.
Good call
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.
@ilblackdragon You are right, I do need to add in the method to get a block from an index. Ach.
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.
Please sync with @bowenwang1996 to make sure we are not attempting to surface more block hashes than what is available with GC.
I also don't think surfacing more than let's say 10 block hashes is safe. We need to be super conservative with what we are exposing to contracts, because it cannot be undone. If we surface 2 epochs worth of hashes, then we cannot ever change the length of the epoch after that because some contracts may start breaking. And we did change the length of the epoch in past. We also do not want to surface number which is too large, because who knows how aggressive we would want our GC to be in the future. But surfacing something like 10 hashes seems arbitrary. Therefore I suggest we do not surface more than one or two hashes.
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.
@nearmax I understand the concern. However, if we can't get at the last 256 hashes (needed by the EVM's BLOCKHASH
instruction), then we will not be able to go with the scheme you outlined in #3456 (comment), but will have to compute the EVM's block hashes based on the NEAR block number instead of the NEAR block hash. Sounds like that'll be the safer thing to do, despite the temporary fork concern you raised there.
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 think exposing last 256 blocks should not be a problem, although it requires more effort in the implementation to make sure that it is not expensive. @artob is there any alternative solution to exposing the last 256 block hashes?
@@ -117,6 +117,11 @@ protocol_feature_access_key_nonce_range = ["neard/protocol_feature_access_key_no | |||
protocol_feature_tx_size_limit = ["near-primitives/protocol_feature_tx_size_limit", "node-runtime/protocol_feature_tx_size_limit", "neard/protocol_feature_tx_size_limit"] | |||
protocol_feature_allow_create_account_on_delete = ["testlib/protocol_feature_allow_create_account_on_delete", "near-primitives/protocol_feature_allow_create_account_on_delete", "node-runtime/protocol_feature_allow_create_account_on_delete", "neard/protocol_feature_allow_create_account_on_delete"] | |||
protocol_feature_add_account_versions = ["near-primitives/protocol_feature_add_account_versions"] | |||
protocol_feature_vm_hash = [ | |||
"node-runtime/protocol_feature_vm_hash", |
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.
Seems like duplication
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 had realised that, but just entered them all anyways.
I'll put this on WIP for now. We are working out on an alternative solution for EVM, and there is a change that needs to be made in order to call any block hash from a given number. |
@@ -18,6 +18,9 @@ pub type Nonce = u64; | |||
pub type BlockHeight = u64; | |||
/// Height of the epoch. | |||
pub type EpochHeight = u64; | |||
/// Block hash. | |||
#[cfg(feature = "protocol_feature_vm_hash")] | |||
pub type BlockHash = [u8; 32]; |
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 think, it is mostly a coincidence that most of the types returned by vm logic are generalized. I would use CryptoHash
here, if possible, to avoid introducing new aliases.
/// | ||
/// `base` | ||
#[cfg(feature = "protocol_feature_vm_hash")] | ||
pub fn block_hash(&mut self) -> Result<BlockHash> { |
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.
Please sync with @bowenwang1996 to make sure we are not attempting to surface more block hashes than what is available with GC.
I also don't think surfacing more than let's say 10 block hashes is safe. We need to be super conservative with what we are exposing to contracts, because it cannot be undone. If we surface 2 epochs worth of hashes, then we cannot ever change the length of the epoch after that because some contracts may start breaking. And we did change the length of the epoch in past. We also do not want to surface number which is too large, because who knows how aggressive we would want our GC to be in the future. But surfacing something like 10 hashes seems arbitrary. Therefore I suggest we do not surface more than one or two hashes.
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.
Also, we need to add it to imports:
wrapped_imports! { |
Then please also add it to runtime-params estimator (if you want in a separate PR to unblock you, since it is urgent). Please check with @olonho
After calls with @nearmax, @bowenwang1996, @birchmd, and @djsatok today, the scope of this somewhat expanded. I'm reassigning to @birchmd given his previous Chain experience, and will write up an NEP detailing the current plan. |
/// | ||
/// `base` | ||
#[cfg(feature = "protocol_feature_vm_hash")] | ||
pub fn prev_block_hash(&mut self) -> Result<BlockHash> { |
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.
During discussion with nearmax, we realized that returning a BlockHash
directly might not just work. All our other APIs only return primitive types (u64 integers), that's the first case where we want to return something bigger. Looks like we need either to use an out-parameter here, or multiple return values, the latter approach being more promising imo.
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 pattern used in other examples, such as sha256
, is to use the register API, so I think we should probably stick to that for consistency. Though wasm handling multiple return values now is really cool!
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.
Ah, I somehow miss the fact that we already do use out parameters. Clearly, we should use the same design here as well.
Closing this in favour of #4273 |
The PR is relatively straight forward, it just exposes two new methods
block_hash
andprev_block_hash
to the VM logic, which may be useful.I do need clarification that they work as intended, returning the latest block hash however, and not n-1.