|
| 1 | +//! Example for Block and Transaction Properties. |
| 2 | +#![cfg_attr(target_arch = "wasm32", no_std)] |
| 3 | +#![cfg_attr(target_arch = "wasm32", no_main)] |
| 4 | + |
| 5 | +extern crate zink; |
| 6 | +use zink::primitives::{properties, Address, Bytes32}; |
| 7 | + |
| 8 | +#[zink::external] |
| 9 | +pub fn chainid() -> u64 { |
| 10 | + properties::chainid() |
| 11 | +} |
| 12 | + |
| 13 | +#[zink::external] |
| 14 | +pub fn number() -> u64 { |
| 15 | + properties::number() |
| 16 | +} |
| 17 | + |
| 18 | +#[zink::external] |
| 19 | +pub fn blockhash(number: u64) -> Bytes32 { |
| 20 | + properties::blockhash(number) |
| 21 | +} |
| 22 | + |
| 23 | +#[zink::external] |
| 24 | +pub fn blobhash(index: u64) -> Bytes32 { |
| 25 | + properties::blobhash(index) |
| 26 | +} |
| 27 | + |
| 28 | +#[zink::external] |
| 29 | +pub fn basefee() -> u64 { |
| 30 | + properties::basefee() |
| 31 | +} |
| 32 | + |
| 33 | +#[zink::external] |
| 34 | +pub fn gasprice() -> u64 { |
| 35 | + properties::gasprice() |
| 36 | +} |
| 37 | + |
| 38 | +#[zink::external] |
| 39 | +pub fn blobbasefee() -> u64 { |
| 40 | + properties::blobbasefee() |
| 41 | +} |
| 42 | + |
| 43 | +#[zink::external] |
| 44 | +pub fn gaslimit() -> Bytes32 { |
| 45 | + properties::gaslimit() |
| 46 | +} |
| 47 | + |
| 48 | +#[zink::external] |
| 49 | +pub fn coinbase() -> Address { |
| 50 | + properties::coinbase() |
| 51 | +} |
| 52 | + |
| 53 | +#[zink::external] |
| 54 | +pub fn prevrandao() -> Bytes32 { |
| 55 | + properties::prevrandao() |
| 56 | +} |
| 57 | + |
| 58 | +#[zink::external] |
| 59 | +pub fn timestamp() -> u64 { |
| 60 | + properties::timestamp() |
| 61 | +} |
| 62 | + |
| 63 | +#[zink::external] |
| 64 | +pub fn gasleft() -> Bytes32 { |
| 65 | + properties::gasleft() |
| 66 | +} |
| 67 | + |
| 68 | +#[cfg(not(target_arch = "wasm32"))] |
| 69 | +fn main() {} |
| 70 | + |
| 71 | +#[cfg(test)] |
| 72 | +#[cfg(not(target_arch = "wasm32"))] |
| 73 | +mod tests { |
| 74 | + use zint::{Bytes32, Contract, EVM}; |
| 75 | + |
| 76 | + fn hash_to_bytes32(data: &str) -> [u8; 32] { |
| 77 | + let hash_bytes = hex::decode(data).unwrap(); |
| 78 | + let mut hash = [0; 32]; |
| 79 | + hash.copy_from_slice(&hash_bytes); |
| 80 | + hash |
| 81 | + } |
| 82 | + |
| 83 | + fn u64_to_bytes32(value: u64) -> Vec<u8> { |
| 84 | + let bytes = value.to_be_bytes(); |
| 85 | + let mut bytes32 = [0; 32]; |
| 86 | + bytes32[32 - bytes.len()..].copy_from_slice(&bytes); |
| 87 | + bytes32.to_vec() |
| 88 | + } |
| 89 | + |
| 90 | + #[test] |
| 91 | + fn test_block_properties() -> anyhow::Result<()> { |
| 92 | + let data = "29045A592007D0C246EF02C2223570DA9522D0CF0F73282C79A1BC8F0BB2C238"; |
| 93 | + let mut evm = EVM::default() |
| 94 | + .chain_id(1) |
| 95 | + .block_number(599423555) |
| 96 | + .block_hash(599423545, hash_to_bytes32(data)) |
| 97 | + .commit(true); |
| 98 | + let contract = Contract::search("properties")?.compile()?; |
| 99 | + let info = evm.deploy(&contract.bytecode()?)?; |
| 100 | + let address = info.address; |
| 101 | + |
| 102 | + let info = evm |
| 103 | + .calldata(&contract.encode(["chainid()".as_bytes()])?) |
| 104 | + .call(address)?; |
| 105 | + assert_eq!(info.ret, 1u64.to_bytes32(), "{info:?}"); |
| 106 | + |
| 107 | + let info = evm |
| 108 | + .calldata(&contract.encode(["number()".as_bytes()])?) |
| 109 | + .call(address)?; |
| 110 | + assert_eq!(info.ret, u64_to_bytes32(599423555), "{info:?}"); |
| 111 | + |
| 112 | + let info = evm |
| 113 | + .calldata( |
| 114 | + &contract.encode(["blockhash(uint64)".as_bytes(), &u64_to_bytes32(599423545)])?, |
| 115 | + ) |
| 116 | + .call(address)?; |
| 117 | + assert_eq!(info.ret, hash_to_bytes32(data), "{info:?}"); |
| 118 | + Ok(()) |
| 119 | + } |
| 120 | + |
| 121 | + #[test] |
| 122 | + fn test_blob_properties() -> anyhow::Result<()> { |
| 123 | + let blobhash = |
| 124 | + hash_to_bytes32("0100000000000000000000000000000000000000000000000000000000000001"); |
| 125 | + let mut evm = EVM::default().blob_hashes(vec![blobhash]).commit(true); |
| 126 | + let contract = Contract::search("properties")?.compile()?; |
| 127 | + let info = evm.deploy(&contract.bytecode()?)?; |
| 128 | + let address = info.address; |
| 129 | + |
| 130 | + let info = evm |
| 131 | + .calldata(&contract.encode(["blobhash(uint64)".as_bytes(), &u64_to_bytes32(0)])?) |
| 132 | + .call(address)?; |
| 133 | + assert_eq!(info.ret, blobhash, "{info:?}"); |
| 134 | + |
| 135 | + let info = evm |
| 136 | + .calldata(&contract.encode(["blobhash(uint64)".as_bytes(), &u64_to_bytes32(1)])?) |
| 137 | + .call(address)?; |
| 138 | + assert_eq!(info.ret, 0u64.to_bytes32(), "{info:?}"); |
| 139 | + Ok(()) |
| 140 | + } |
| 141 | + |
| 142 | + #[test] |
| 143 | + fn test_fee_properties() -> anyhow::Result<()> { |
| 144 | + let mut evm = EVM::default() |
| 145 | + .basefee(100, 200) |
| 146 | + .blob_basefee(50) |
| 147 | + .commit(true); |
| 148 | + let contract = Contract::search("properties")?.compile()?; |
| 149 | + let info = evm.deploy(&contract.bytecode()?)?; |
| 150 | + let address = info.address; |
| 151 | + |
| 152 | + let info = evm |
| 153 | + .calldata(&contract.encode(["basefee()".as_bytes()])?) |
| 154 | + .call(address)?; |
| 155 | + assert_eq!(info.ret, 100u64.to_bytes32(), "{info:?}"); |
| 156 | + |
| 157 | + let info = evm |
| 158 | + .calldata(&contract.encode(["gasprice()".as_bytes()])?) |
| 159 | + .call(address)?; |
| 160 | + assert_eq!(info.ret, 200u64.to_bytes32(), "{info:?}"); |
| 161 | + |
| 162 | + let info = evm |
| 163 | + .calldata(&contract.encode(["blobbasefee()".as_bytes()])?) |
| 164 | + .call(address)?; |
| 165 | + assert_eq!(info.ret, evm.get_blob_basefee(), "{info:?}"); |
| 166 | + |
| 167 | + let info = evm |
| 168 | + .calldata(&contract.encode(["gaslimit()".as_bytes()])?) |
| 169 | + .call(address)?; |
| 170 | + assert_eq!(info.ret, [255; 32], "{info:?}"); |
| 171 | + Ok(()) |
| 172 | + } |
| 173 | + |
| 174 | + #[test] |
| 175 | + fn test_coinbase() -> anyhow::Result<()> { |
| 176 | + let data = "29045A592007D0C246EF02C2223570DA9522D0CF0F73282C79A1BC8F0BB2C238"; |
| 177 | + let mut evm = EVM::default() |
| 178 | + .coinbase([1; 20]) |
| 179 | + .prevrandao(hash_to_bytes32(data)) |
| 180 | + .timestamp(27) |
| 181 | + .commit(false); |
| 182 | + let contract = Contract::search("properties")?.compile()?; |
| 183 | + let info = evm.deploy(&contract.bytecode()?)?; |
| 184 | + let address = info.address; |
| 185 | + |
| 186 | + let info = evm |
| 187 | + .calldata(&contract.encode(["coinbase()".as_bytes()])?) |
| 188 | + .call(address)?; |
| 189 | + assert_eq!(info.ret, [1; 20].to_bytes32(), "{info:?}"); |
| 190 | + |
| 191 | + let info = evm |
| 192 | + .calldata(&contract.encode(["prevrandao()".as_bytes()])?) |
| 193 | + .call(address)?; |
| 194 | + assert_eq!(info.ret, hash_to_bytes32(data), "{info:?}"); |
| 195 | + |
| 196 | + let info = evm |
| 197 | + .calldata(&contract.encode(["timestamp()".as_bytes()])?) |
| 198 | + .call(address)?; |
| 199 | + assert_eq!(info.ret, 27u64.to_bytes32(), "{info:?}"); |
| 200 | + Ok(()) |
| 201 | + } |
| 202 | + |
| 203 | + #[test] |
| 204 | + fn test_gas_left() -> anyhow::Result<()> { |
| 205 | + let contract = Contract::search("properties")?.compile()?; |
| 206 | + |
| 207 | + let mut evm1 = EVM::default().tx_gas_limit(50000).commit(true); |
| 208 | + let info1 = evm1.deploy(&contract.bytecode()?)?; |
| 209 | + let info1 = evm1 |
| 210 | + .calldata(&contract.encode(["gasleft()".as_bytes()])?) |
| 211 | + .call(info1.address)?; |
| 212 | + let gasleft1 = u64::from_be_bytes(info1.ret[24..].try_into().unwrap()); |
| 213 | + let gas1 = 50000 - gasleft1; |
| 214 | + |
| 215 | + let mut evm2 = EVM::default().tx_gas_limit(70000).commit(true); |
| 216 | + let info2 = evm2.deploy(&contract.bytecode()?)?; |
| 217 | + let info2 = evm2 |
| 218 | + .calldata(&contract.encode(["gasleft()".as_bytes()])?) |
| 219 | + .call(info2.address)?; |
| 220 | + let gasleft2 = u64::from_be_bytes(info2.ret[24..].try_into().unwrap()); |
| 221 | + let gas2 = 70000 - gasleft2; |
| 222 | + assert_eq!(gas1, gas2); |
| 223 | + Ok(()) |
| 224 | + } |
| 225 | +} |
0 commit comments