Skip to content
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

Closed
wants to merge 7 commits into from

Conversation

joshuajbouw
Copy link
Member

@joshuajbouw joshuajbouw commented Apr 27, 2021

The PR is relatively straight forward, it just exposes two new methods block_hash and prev_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.

@joshuajbouw joshuajbouw added C-enhancement Category: An issue proposing an enhancement or a PR with one. A-EVM Area: Native EVM implementation and support labels Apr 27, 2021
@joshuajbouw joshuajbouw changed the title feat: add block hash API to near_vm_logic Feat: Add block hash API to near_vm_logic Apr 27, 2021
@joshuajbouw joshuajbouw changed the title Feat: Add block hash API to near_vm_logic feat: add block hash API to near_vm_logic Apr 27, 2021
@@ -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];
Copy link
Collaborator

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?

Copy link
Member Author

@joshuajbouw joshuajbouw Apr 27, 2021

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

Copy link
Contributor

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.

Copy link
Member

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

@@ -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")]
Copy link
Contributor

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.

Copy link
Member Author

@joshuajbouw joshuajbouw Apr 27, 2021

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> {
Copy link
Contributor

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.

Copy link
Member

@ilblackdragon ilblackdragon Apr 27, 2021

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call

Copy link
Member Author

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.

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Collaborator

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",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like duplication

Copy link
Member Author

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.

@joshuajbouw
Copy link
Member Author

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.

@joshuajbouw joshuajbouw marked this pull request as draft April 27, 2021 14:57
@@ -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];
Copy link
Contributor

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> {
Copy link
Contributor

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.

Copy link
Contributor

@maxzaver maxzaver left a 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:

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

@artob artob assigned birchmd and unassigned joshuajbouw Apr 27, 2021
@artob
Copy link
Contributor

artob commented Apr 27, 2021

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> {
Copy link
Contributor

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.

Copy link
Contributor

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!

Copy link
Contributor

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.

@birchmd
Copy link
Contributor

birchmd commented May 4, 2021

Closing this in favour of #4273

@birchmd birchmd closed this May 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-EVM Area: Native EVM implementation and support C-enhancement Category: An issue proposing an enhancement or a PR with one.
Projects
None yet
Development

Successfully merging this pull request may close these issues.