From e615e76bdf9b9ac314f7b217985d5bfaa6445b14 Mon Sep 17 00:00:00 2001 From: poltao Date: Sun, 8 Dec 2024 20:42:19 +0800 Subject: [PATCH] feat(example): tests for properties --- examples/properties.rs | 62 +++++++++++++++++++++------------- zink/src/primitives/address.rs | 2 +- zink/src/storage/mod.rs | 6 ++++ zink/zint/src/evm.rs | 27 ++++++++++++++- 4 files changed, 71 insertions(+), 26 deletions(-) diff --git a/examples/properties.rs b/examples/properties.rs index a86972e35..c39e35f91 100644 --- a/examples/properties.rs +++ b/examples/properties.rs @@ -6,38 +6,52 @@ extern crate zink; use zink::primitives::{properties, Bytes32}; #[zink::external] -pub fn blockhash(block_number: u64) -> Bytes32 { - properties::blockhash(block_number) +pub fn number() -> u64 { + properties::number() } #[zink::external] -pub fn number() -> u64 { - properties::number() +pub fn blockhash(number: u64) -> Bytes32 { + properties::blockhash(number) } #[cfg(not(target_arch = "wasm32"))] fn main() {} -#[test] -fn test_block_properties() -> anyhow::Result<()> { +#[cfg(test)] +mod tests { use zint::{Bytes32, Contract, EVM}; - let mut evm = EVM::default().commit(true); - let contract = Contract::search("properties")?.compile()?; - let raw_info = evm.deploy(&contract.bytecode()?)?; - - let info = evm - .calldata(&contract.encode(&[b"number()".to_vec()])?) - .call(raw_info.address)?; - assert_eq!(info.ret, 0u64.to_bytes32(), "{info:?}"); - - let info = evm - .calldata(&contract.encode(&[ - b"blockhash(uint64)".to_vec(), - 599423545u64.to_bytes32().to_vec(), - ])?) - .call(raw_info.address)?; - assert_eq!(info.ret, 0u64.to_bytes32(), "{info:?}"); - - Ok(()) + fn get_block_attr() -> ([u8; 32], [u8; 32]) { + let mut block_number = 599423545u64.to_bytes32(); + block_number.reverse(); + let hash_bytes = + hex::decode("29045A592007D0C246EF02C2223570DA9522D0CF0F73282C79A1BC8F0BB2C238") + .unwrap(); + let mut block_hash = [0; 32]; + block_hash.copy_from_slice(&hash_bytes); + (block_number, block_hash) + } + + #[test] + fn test_block_properties() -> anyhow::Result<()> { + let (block_number, block_hash) = get_block_attr(); + let mut evm = EVM::default() + .block_number(block_number) + .block_hash(block_hash) + .commit(false); + let contract = Contract::search("properties")?.compile()?; + let address = evm.deploy(&contract.bytecode()?)?.address; + + let info = evm + .calldata(&contract.encode(["number()".as_bytes()])?) + .call(address)?; + assert_eq!(info.ret, block_number, "{info:?}"); + + let info = evm + .calldata(&contract.encode(["blockhash(uint64)".as_bytes(), &block_number])?) + .call(address)?; + assert_eq!(info.ret, 0u64.to_bytes32(), "{info:?}"); + Ok(()) + } } diff --git a/zink/src/primitives/address.rs b/zink/src/primitives/address.rs index 27629a3d9..e54ad4d94 100644 --- a/zink/src/primitives/address.rs +++ b/zink/src/primitives/address.rs @@ -16,7 +16,7 @@ impl Address { Address(Bytes20::empty()) } - /// Returns empty address + /// Returns the caller address #[inline(always)] pub fn caller() -> Self { unsafe { ffi::evm::caller() } diff --git a/zink/src/storage/mod.rs b/zink/src/storage/mod.rs index 3d16da345..d8c3db4d5 100644 --- a/zink/src/storage/mod.rs +++ b/zink/src/storage/mod.rs @@ -35,6 +35,12 @@ impl StorageValue for u32 { } } +impl StorageValue for u64 { + fn sload() -> Self { + unsafe { ffi::asm::sload_u64() } + } +} + impl TransientStorageValue for i32 { fn tload() -> Self { unsafe { ffi::asm::tload_i32() } diff --git a/zink/zint/src/evm.rs b/zink/zint/src/evm.rs index 93342c6b2..e958003e8 100644 --- a/zink/zint/src/evm.rs +++ b/zink/zint/src/evm.rs @@ -25,6 +25,10 @@ pub struct EVM<'e> { inner: Revm<'e, (), InMemoryDB>, /// Caller for the execution pub caller: [u8; 20], + /// The block’s number + pub block_number: [u8; 32], + /// The block's hash + pub block_hash: [u8; 32], /// If commit changes commit: bool, } @@ -38,6 +42,8 @@ impl<'e> Default for EVM<'e> { Self { inner: evm, caller: [0; 20], + block_number: [0; 32], + block_hash: [0; 32], commit: false, } } @@ -72,6 +78,18 @@ impl EVM<'_> { self } + /// Set block number + pub fn block_number(mut self, number: [u8; 32]) -> Self { + self.block_number = number; + self + } + + /// Set block hash + pub fn block_hash(mut self, hash: [u8; 32]) -> Self { + self.block_hash = hash; + self + } + /// Send transaction to the provided address. pub fn call(&mut self, to: [u8; 20]) -> Result { let to = TransactTo::Call(to.into()); @@ -79,6 +97,13 @@ impl EVM<'_> { self.inner.tx_mut().transact_to = to; self.inner.tx_mut().caller = self.caller.into(); + let block_number = U256::from_be_bytes(self.block_number); + self.inner.block_mut().number = block_number; + self.inner + .db_mut() + .block_hashes + .insert(block_number, self.block_hash.into()); + if self.commit { self.inner.transact_commit()?.try_into() } else { @@ -147,7 +172,7 @@ impl TryFrom for Info { gas: result.gas_used(), ..Default::default() }; - + println!("{:?}", result); match result { ExecutionResult::Success { logs,