Skip to content

Commit

Permalink
feat(example): tests for properties
Browse files Browse the repository at this point in the history
  • Loading branch information
poltao committed Dec 20, 2024
1 parent db3d39f commit 279baf0
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 37 deletions.
127 changes: 111 additions & 16 deletions examples/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -15,43 +20,133 @@ 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() {}

#[cfg(test)]
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<u8> {
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(())
}
}
8 changes: 7 additions & 1 deletion zink/src/ffi/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
12 changes: 11 additions & 1 deletion zink/src/primitives/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() }
}
75 changes: 56 additions & 19 deletions zink/zint/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand All @@ -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<Vec<B256>>,
/// If commit changes
commit: bool,
}
Expand All @@ -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,
}
}
Expand Down Expand Up @@ -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<Info> {
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()
Expand Down Expand Up @@ -172,7 +209,7 @@ impl TryFrom<ExecutionResult> for Info {
gas: result.gas_used(),
..Default::default()
};
println!("{:?}", result);

match result {
ExecutionResult::Success {
logs,
Expand Down

0 comments on commit 279baf0

Please sign in to comment.