use-ink / ink

Polkadot's ink! to write smart contracts.
https://use.ink
Apache License 2.0
1.35k stars 426 forks source link

Expose blockhash in ink! #1849

Closed ltfschoen closed 1 year ago

ltfschoen commented 1 year ago

In the comments of the Stack Exchange answer here I've provided links to a Flipper Game written in Solidity where i get the previous block hash with blockhash(blockNumber - 1); and I also provide a link to the same Flipper Game written in ink!, but I don't know how to get the previous block hash using ink!

If I use a chain extension https://use.ink/macros-attributes/chain-extension/ then to get the block hash from a given block number I would have to modify the blockchain itself (which may not even be my own) through an on-chain upgrade and governance, and that might not be a permissionless process, and governance might even reject the proposal.

I'm also aware that there's an RPC endpoint here to get the block hash from a given block number, but I just want to be able to get it from the ink! smart contract itself.

So I'd like to be able to permissionlessly get the previous block hash of the chain that i've deployed an ink! smart contract on, directly from the ink! smart contract itself, like it's possible to do using Solidity.

Could anyone please provide guidance on how I could go about doing that?

ltfschoen commented 1 year ago

@PierreOssun mentioned that the environment API for ink! is here for constructor is Self::env().block_number() or self::env().block_number()

So an additional environment function in constructor could be Self::env().block_hash(Self::env().block_number - 1)

ltfschoen commented 1 year ago

For my specific use case i just realised that whilst this feature would be ideal i can get by with my existing solution, where i'm generating a source of randomness in the future from a future block hash, but only after it has occurred, and where the user provides the block hash as an argument to an ink! function set_block_for_entropy_for_market_id here, which i'm calling from a bash script at the moment here but that could become a call from a front-end.

The issue with my current solution is that whilst it provides a source of randomness, if it was used for a guessing game then i would need oracles or on-chain governance to verify that the block hash provided was a block hash that actually exists before a releasing a prize to the winner.

Another way around this to be able to access the blockhash could be to do the following, which is what i'll try next:

So this solution to getting the blockhash should already work if:

In future, when XCM is finalised then other chains that may still only support ink! WASM contracts could make cross-chain cross-contract calls to another chain that supports Solidity EVM contracts so they could get a blockhash as a source of randomness from that other chain trustlessly, or possibly even get a source of randomness from randomness precompile contracts on other chains like Moonbeam.

Or if someone works on this issue and allows ink! WASM smart contracts to access an environment function that gets the block hash for the a given current or previous block like is already possible in Solidity.

To provide some context, i was actually only getting the previous block hash here in a createGame function and that worked in Solidity, and i was using that to refer to the block hash when a guessing game started, but there's no reason why i can't just use the block number instead since it is obtained from in the Solidity function itself. i re-wrote that contract in ink! here, but did not know the equivalent way to get the block hash

ltfschoen commented 1 year ago

In the interim I've tried using XVM with Shibuya in this PR https://github.com/ltfschoen/XCMTemplate/pull/24 Still draft, i'm not yet able to deploy to Shibuya using Truffle, and i'm going to try and get randomness from a future block by incorporating and using dapps/ink-rust/rand-future https://github.com/ltfschoen/XCMTemplate/pull/23/files#diff-8204ef18b173711414617cb0ab5680e976995169b27ba1767fac9589fa950f30

SkymanOne commented 1 year ago

block_hash is not one of exposed FFI functions by pallet-contracts - https://github.com/paritytech/substrate/blob/a6b0d435995d7101e70ee0aab1707d0807024a3f/frame/contracts/src/wasm/runtime.rs#L1022C11-L1022C11 Adding this will take some time and cooperation with the substrate devs.

@athei wdyt?

ltfschoen commented 1 year ago

so to get the block hash for a given block number i gather it needs either:

or for a new or existing blockchain

SkymanOne commented 1 year ago

Overall yes, not so many blockchains actually have pallet-contracts on the mainnets, so they can just upgrade the pallet quickly if necessary. The blocker lies in the coordination with pallet-contracts devs to add the function to the FFI interface.

boyswan commented 1 year ago

A big +1 for exposing the blockhash. It seems to be the most viable approach (when used in a commit/reveal scheme) to some sort of randomness in ink!. The prospect of RNG in ink was the very first thing that lead me to use ink, but after learning the original ink env random implementation was fit not for purpose I've been searching for the best way around it since.

Oracles are always the "advised solution" to rng/entropy but it just shifts the issue elsewhere. IIRC the substrate blockhash function doesn't have the access limit of only the last 256 blockhashes like EVM, so in comparison it would be at an advantage.

SkymanOne commented 1 year ago

We should also think carefully about using block hash as a source of randomness. It is generally a not good source: https://hackingdistributed.com/2017/12/24/how-not-to-run-a-blockchain-lottery/. You should use oracle contract or chain extension. If we expose block_hash it may give a false sense of randomness to developers.

0xf333 commented 1 year ago

We should also think carefully about using block hash as a source of randomness. It is generally a not good source: https://hackingdistributed.com/2017/12/24/how-not-to-run-a-blockchain-lottery/. You should use oracle contract or chain extension. If we expose block_hash it may give a false sense of randomness to developers.

I'm wondering given the nuances of using Slot VRFs vs running hash, do you think there might be an approach that could bridge the gap? Something that Ink is ready to adopt presently, that people can look into and figure out implementation? Keen to hear your perspective...

SkymanOne commented 1 year ago

Unfortunately, I firmly believe it is up to the chain devs to expose necessary random function API to the smart contract developer. There is an ongoing issue to add support for multiple chain extensions - #1747. So perhaps it would be possible in future to ask Astar, Aleph Zero to implement the interface as a separate chain ext. AFAIK, Phala off-chain contracts allow you to bring some randomness manually since you are less restricted in resources.

We should also think carefully about using block hash as a source of randomness. It is generally a not good source: https://hackingdistributed.com/2017/12/24/how-not-to-run-a-blockchain-lottery/. You should use oracle contract or chain extension. If we expose block_hash it may give a false sense of randomness to developers.

I'm wondering given the nuances of using Slot VRFs vs running hash, do you think there might be an approach that could bridge the gap? Something that Ink is ready to adopt presently, that people can look into and figure out implementation? Keen to hear your perspective...

0xf333 commented 1 year ago

Unfortunately, I firmly believe it is up to the chain devs to expose necessary random function API to the smart contract developer. There is an ongoing issue to add support for multiple chain extensions - #1747. So perhaps it would be possible in future to ask Astar, Aleph Zero to implement the interface as a separate chain ext. AFAIK, Phala off-chain contracts allow you to bring some randomness manually since you are less restricted in resources.

Ok, thanks

SkymanOne commented 1 year ago

Please see the reply in the corresponding issue in the substrate repo: https://github.com/paritytech/substrate/issues/14724#issuecomment-1668881285

SkymanOne commented 1 year ago

I will close the issue on Wednesday unless there are other concrete use cases for exposing a block hash.