From 279baf08562d3036ce3b3bef648725f530a04c22 Mon Sep 17 00:00:00 2001 From: poltao Date: Tue, 10 Dec 2024 16:10:14 +0800 Subject: [PATCH] feat(example): tests for properties --- examples/properties.rs | 127 ++++++++++++++++++++++++++---- zink/src/ffi/evm.rs | 8 +- zink/src/primitives/properties.rs | 12 ++- zink/zint/src/evm.rs | 75 +++++++++++++----- 4 files changed, 185 insertions(+), 37 deletions(-) diff --git a/examples/properties.rs b/examples/properties.rs index c39e35f91..a30a98caa 100644 --- a/examples/properties.rs +++ b/examples/properties.rs @@ -5,6 +5,11 @@ extern crate zink; use zink::primitives::{properties, Bytes32}; +#[zink::external] +pub fn chainid() -> u64 { + properties::chainid() +} + #[zink::external] pub fn number() -> u64 { properties::number() @@ -15,6 +20,31 @@ pub fn blockhash(number: u64) -> Bytes32 { properties::blockhash(number) } +#[zink::external] +pub fn blobhash(index: u64) -> Bytes32 { + properties::blobhash(index) +} + +#[zink::external] +pub fn basefee() -> u64 { + properties::basefee() +} + +#[zink::external] +pub fn gasprice() -> u64 { + properties::gasprice() +} + +#[zink::external] +pub fn blobbasefee() -> u64 { + properties::blobbasefee() +} + +#[zink::external] +pub fn gaslimit() -> Bytes32 { + properties::gaslimit() +} + #[cfg(not(target_arch = "wasm32"))] fn main() {} @@ -22,36 +52,101 @@ fn main() {} mod tests { use zint::{Bytes32, Contract, EVM}; - 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) + fn hash_to_bytes32(data: &str) -> [u8; 32] { + let hash_bytes = hex::decode(data).unwrap(); + let mut hash = [0; 32]; + hash.copy_from_slice(&hash_bytes); + hash + } + + fn u64_to_bytes32(value: u64) -> Vec { + let bytes = value.to_be_bytes(); + let mut bytes32 = [0; 32]; + bytes32[32 - bytes.len()..].copy_from_slice(&bytes); + bytes32.to_vec() } #[test] fn test_block_properties() -> anyhow::Result<()> { - let (block_number, block_hash) = get_block_attr(); + let data = "29045A592007D0C246EF02C2223570DA9522D0CF0F73282C79A1BC8F0BB2C238"; let mut evm = EVM::default() - .block_number(block_number) - .block_hash(block_hash) - .commit(false); + .chain_id(1) + .block_number(599423555) + .block_hash(599423545, hash_to_bytes32(data)) + .commit(true); let contract = Contract::search("properties")?.compile()?; - let address = evm.deploy(&contract.bytecode()?)?.address; + let info = evm.deploy(&contract.bytecode()?)?; + let address = info.address; + + let info = evm + .calldata(&contract.encode(["chainid()".as_bytes()])?) + .call(address)?; + assert_eq!(info.ret, 1u64.to_bytes32(), "{info:?}"); let info = evm .calldata(&contract.encode(["number()".as_bytes()])?) .call(address)?; - assert_eq!(info.ret, block_number, "{info:?}"); + assert_eq!(info.ret, u64_to_bytes32(599423555), "{info:?}"); + + let info = evm + .calldata( + &contract.encode(["blockhash(uint64)".as_bytes(), &u64_to_bytes32(599423545)])?, + ) + .call(address)?; + assert_eq!(info.ret, hash_to_bytes32(data), "{info:?}"); + Ok(()) + } + + #[test] + fn test_blob_properties() -> anyhow::Result<()> { + let blobhash = + hash_to_bytes32("0100000000000000000000000000000000000000000000000000000000000001"); + let mut evm = EVM::default().blob_hashes(vec![blobhash]).commit(true); + let contract = Contract::search("properties")?.compile()?; + let info = evm.deploy(&contract.bytecode()?)?; + let address = info.address; let info = evm - .calldata(&contract.encode(["blockhash(uint64)".as_bytes(), &block_number])?) + .calldata(&contract.encode(["blobhash(uint64)".as_bytes(), &u64_to_bytes32(0)])?) + .call(address)?; + assert_eq!(info.ret, blobhash, "{info:?}"); + + let info = evm + .calldata(&contract.encode(["blobhash(uint64)".as_bytes(), &u64_to_bytes32(1)])?) .call(address)?; assert_eq!(info.ret, 0u64.to_bytes32(), "{info:?}"); Ok(()) } + + #[test] + fn test_fee_properties() -> anyhow::Result<()> { + let mut evm = EVM::default() + .basefee(100, 200) + .blob_basefee(50) + .commit(true); + let contract = Contract::search("properties")?.compile()?; + let info = evm.deploy(&contract.bytecode()?)?; + let address = info.address; + + let info = evm + .calldata(&contract.encode(["basefee()".as_bytes()])?) + .call(address)?; + assert_eq!(info.ret, 100u64.to_bytes32(), "{info:?}"); + + let info = evm + .calldata(&contract.encode(["gasprice()".as_bytes()])?) + .call(address)?; + assert_eq!(info.ret, 200u64.to_bytes32(), "{info:?}"); + + let info = evm + .calldata(&contract.encode(["blobbasefee()".as_bytes()])?) + .call(address)?; + assert_eq!(info.ret, evm.get_blob_basefee(), "{info:?}"); + + let info = evm + .calldata(&contract.encode(["gaslimit()".as_bytes()])?) + .call(address)?; + assert_eq!(info.ret, [255; 32], "{info:?}"); + Ok(()) + } } diff --git a/zink/src/ffi/evm.rs b/zink/src/ffi/evm.rs index b3c625fdf..1a3ea1a8c 100644 --- a/zink/src/ffi/evm.rs +++ b/zink/src/ffi/evm.rs @@ -180,8 +180,14 @@ extern "C" { pub fn prevrandao() -> Bytes32; /// Get the current block gaslimit. - pub fn gaslimit() -> u64; + pub fn gaslimit() -> Bytes32; + + /// Get the amount of available gas. + pub fn gas() -> u64; /// Get the block’s timestamp. pub fn timestamp() -> u64; + + /// Get the gas price of the transaction. + pub fn gasprice() -> u64; } diff --git a/zink/src/primitives/properties.rs b/zink/src/primitives/properties.rs index 19d790c01..962551118 100644 --- a/zink/src/primitives/properties.rs +++ b/zink/src/primitives/properties.rs @@ -42,11 +42,21 @@ pub fn prevrandao() -> Bytes32 { } /// Get the current block gaslimit. -pub fn gaslimit() -> u64 { +pub fn gaslimit() -> Bytes32 { unsafe { ffi::evm::gaslimit() } } +/// Get the amount of available gas. +pub fn gas() -> u64 { + unsafe { ffi::evm::gas() } +} + /// Get the block’s timestamp. pub fn timestamp() -> u64 { unsafe { ffi::evm::timestamp() } } + +/// Get the gas price of the transaction. +pub fn gasprice() -> u64 { + unsafe { ffi::evm::gasprice() } +} diff --git a/zink/zint/src/evm.rs b/zink/zint/src/evm.rs index e958003e8..255657477 100644 --- a/zink/zint/src/evm.rs +++ b/zink/zint/src/evm.rs @@ -5,7 +5,7 @@ use revm::{ db::EmptyDB, primitives::{ AccountInfo, Bytecode, Bytes, ExecutionResult, HaltReason, Log, Output, ResultAndState, - SuccessReason, TransactTo, TxKind, U256, + SuccessReason, TransactTo, TxKind, B256, U256, }, Database, Evm as Revm, InMemoryDB, }; @@ -25,10 +25,8 @@ 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], + /// Blob hashes + pub blob_hashes: Option>, /// If commit changes commit: bool, } @@ -42,8 +40,7 @@ impl<'e> Default for EVM<'e> { Self { inner: evm, caller: [0; 20], - block_number: [0; 32], - block_hash: [0; 32], + blob_hashes: None, commit: false, } } @@ -78,31 +75,71 @@ impl EVM<'_> { self } + /// Set chain id + pub fn chain_id(mut self, id: u64) -> Self { + self.inner.tx_mut().chain_id = Some(id); + self + } + /// Set block number - pub fn block_number(mut self, number: [u8; 32]) -> Self { - self.block_number = number; + pub fn block_number(mut self, number: u64) -> Self { + self.inner.block_mut().number = U256::from(number); self } /// Set block hash - pub fn block_hash(mut self, hash: [u8; 32]) -> Self { - self.block_hash = hash; + pub fn block_hash(mut self, number: u64, hash: [u8; 32]) -> Self { + self.inner + .db_mut() + .block_hashes + .insert(U256::from(number), hash.into()); self } + /// Set blob hashes + pub fn blob_hashes(mut self, blob_hashes: Vec<[u8; 32]>) -> Self { + let blob_hashes = blob_hashes.into_iter().map(Into::into).collect(); + self.blob_hashes = Some(blob_hashes); + self + } + + /// Set block basefee + pub fn basefee(mut self, basefee: u64, gas_price: u64) -> Self { + self.inner.block_mut().basefee = U256::from(basefee); + self.inner.tx_mut().gas_price = U256::from(gas_price); + self + } + + /// Set block’s blob basefee + pub fn blob_basefee(mut self, excess_blob_gas: u64) -> Self { + self.inner + .block_mut() + .set_blob_excess_gas_and_price(excess_blob_gas); + self + } + + /// Get block’s blob basefee + pub fn get_blob_basefee(&self) -> [u8; 32] { + let basefee = self.inner.block().get_blob_gasprice(); + let basefee = match basefee { + Some(fee) => fee.to_be_bytes(), + None => [0; 16], + }; + let mut blob_basefee = [0; 32]; + blob_basefee[16..].copy_from_slice(&basefee); + blob_basefee + } + /// Send transaction to the provided address. pub fn call(&mut self, to: [u8; 20]) -> Result { let to = TransactTo::Call(to.into()); self.inner.tx_mut().gas_limit = GAS_LIMIT; 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 let Some(hashes) = &self.blob_hashes { + self.inner.tx_mut().max_fee_per_blob_gas = Some(U256::from(1)); + self.inner.tx_mut().blob_hashes = hashes.clone(); + } if self.commit { self.inner.transact_commit()?.try_into() @@ -172,7 +209,7 @@ impl TryFrom for Info { gas: result.gas_used(), ..Default::default() }; - println!("{:?}", result); + match result { ExecutionResult::Success { logs,