mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-12 17:31:02 +00:00
implement block.number and block.timestamp
Signed-off-by: xermicus <cyrill@parity.io>
This commit is contained in:
@@ -15,6 +15,7 @@ env_logger = { workspace = true }
|
||||
revive-solidity = { path = "../solidity" }
|
||||
revive-differential = { path = "../differential" }
|
||||
revive-llvm-context = { path = "../llvm-context" }
|
||||
revive-common = { path = "../common" }
|
||||
|
||||
[dev-dependencies]
|
||||
sha1 = { workspace = true }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"ERC20": 53171,
|
||||
"Baseline": 3912,
|
||||
"Flipper": 4353,
|
||||
"Fibonacci": 5971,
|
||||
"Computation": 7380
|
||||
"Baseline": 3917,
|
||||
"Computation": 7363,
|
||||
"ERC20": 52714,
|
||||
"Fibonacci": 5965,
|
||||
"Flipper": 4336
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
contract Block {
|
||||
function timestamp() public view returns (uint ret) {
|
||||
ret = block.timestamp;
|
||||
}
|
||||
|
||||
function number() public view returns (uint ret) {
|
||||
ret = block.number;
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,14 @@ sol!(
|
||||
}
|
||||
);
|
||||
|
||||
sol!(
|
||||
contract Block {
|
||||
function timestamp() public view returns (uint ret);
|
||||
|
||||
function number() public view returns (uint ret);
|
||||
}
|
||||
);
|
||||
|
||||
impl Contract {
|
||||
pub fn baseline() -> Self {
|
||||
let code = include_str!("../contracts/Baseline.sol");
|
||||
@@ -166,12 +174,34 @@ impl Contract {
|
||||
calldata: IERC20::totalSupplyCall::new(()).abi_encode(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn block_number() -> Self {
|
||||
let code = include_str!("../contracts/Block.sol");
|
||||
let name = "Block";
|
||||
|
||||
Self {
|
||||
evm_runtime: crate::compile_evm_bin_runtime(name, code),
|
||||
pvm_runtime: crate::compile_blob(name, code),
|
||||
calldata: Block::numberCall::new(()).abi_encode(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn block_timestamp() -> Self {
|
||||
let code = include_str!("../contracts/Block.sol");
|
||||
let name = "Block";
|
||||
|
||||
Self {
|
||||
evm_runtime: crate::compile_evm_bin_runtime(name, code),
|
||||
pvm_runtime: crate::compile_blob(name, code),
|
||||
calldata: Block::timestampCall::new(()).abi_encode(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde::{de::Deserialize, Serialize};
|
||||
use std::{collections::HashMap, fs::File};
|
||||
use std::{collections::BTreeMap, fs::File};
|
||||
|
||||
use super::Contract;
|
||||
|
||||
@@ -181,14 +211,14 @@ mod tests {
|
||||
|
||||
let existing = File::open(path)
|
||||
.map(|file| {
|
||||
HashMap::<String, usize>::deserialize(&mut serde_json::Deserializer::from_reader(
|
||||
BTreeMap::<String, usize>::deserialize(&mut serde_json::Deserializer::from_reader(
|
||||
file,
|
||||
))
|
||||
.expect("should be able to deserialze codesize data")
|
||||
})
|
||||
.ok();
|
||||
|
||||
let sizes = HashMap::from([
|
||||
let sizes = BTreeMap::from([
|
||||
("Baseline", Contract::baseline().pvm_runtime.len()),
|
||||
("Flipper", Contract::flipper().pvm_runtime.len()),
|
||||
("Computation", Contract::odd_product(0).pvm_runtime.len()),
|
||||
|
||||
@@ -33,6 +33,9 @@ impl Default for CallOutput {
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub const BLOCK_NUMBER: u64 = 123;
|
||||
pub const BLOCK_TIMESTAMP: u64 = 456;
|
||||
|
||||
pub fn new(input: Vec<u8>) -> Self {
|
||||
Self {
|
||||
input,
|
||||
@@ -88,8 +91,12 @@ fn link_host_functions(engine: &Engine) -> Linker<State> {
|
||||
|caller: Caller<State>, out_ptr: u32, out_len_ptr: u32| -> Result<(), Trap> {
|
||||
let (mut caller, state) = caller.split();
|
||||
|
||||
let out_len = caller.read_u32(out_len_ptr)?;
|
||||
assert_eq!(out_len, 16, "spurious output buffer size: {out_len}");
|
||||
let out_len = caller.read_u32(out_len_ptr)? as usize;
|
||||
assert_eq!(
|
||||
out_len,
|
||||
revive_common::BYTE_LENGTH_VALUE,
|
||||
"spurious output buffer size: {out_len}"
|
||||
);
|
||||
|
||||
let value = state.value.to_le_bytes();
|
||||
|
||||
@@ -126,8 +133,16 @@ fn link_host_functions(engine: &Engine) -> Linker<State> {
|
||||
-> Result<u32, Trap> {
|
||||
let (caller, state) = caller.split();
|
||||
|
||||
assert_eq!(key_len, 32, "storage key must be 32 bytes");
|
||||
assert_eq!(value_len, 32, "storage value must be 32 bytes");
|
||||
assert_eq!(
|
||||
key_len as usize,
|
||||
revive_common::BYTE_LENGTH_WORD,
|
||||
"storage key must be 32 bytes"
|
||||
);
|
||||
assert_eq!(
|
||||
value_len as usize,
|
||||
revive_common::BYTE_LENGTH_WORD,
|
||||
"storage value must be 32 bytes"
|
||||
);
|
||||
|
||||
let key = caller.read_memory_into_vec(key_ptr, key_len)?;
|
||||
let value = caller.read_memory_into_vec(value_ptr, value_len)?;
|
||||
@@ -154,8 +169,12 @@ fn link_host_functions(engine: &Engine) -> Linker<State> {
|
||||
let (mut caller, state) = caller.split();
|
||||
|
||||
let key = caller.read_memory_into_vec(key_ptr, key_len)?;
|
||||
let out_len = caller.read_u32(out_len_ptr)?;
|
||||
assert_eq!(out_len, 32, "spurious output buffer size: {out_len}");
|
||||
let out_len = caller.read_u32(out_len_ptr)? as usize;
|
||||
assert_eq!(
|
||||
out_len,
|
||||
revive_common::BYTE_LENGTH_WORD,
|
||||
"spurious output buffer size: {out_len}"
|
||||
);
|
||||
|
||||
let value = state
|
||||
.storage
|
||||
@@ -192,6 +211,48 @@ fn link_host_functions(engine: &Engine) -> Linker<State> {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
linker
|
||||
.func_wrap(
|
||||
runtime_api::NOW,
|
||||
|caller: Caller<State>, out_ptr: u32, out_len_ptr: u32| {
|
||||
let (mut caller, _) = caller.split();
|
||||
|
||||
let out_len = caller.read_u32(out_len_ptr)? as usize;
|
||||
assert_eq!(
|
||||
out_len,
|
||||
revive_common::BYTE_LENGTH_BLOCK_TIMESTAMP,
|
||||
"spurious output buffer size: {out_len}"
|
||||
);
|
||||
|
||||
caller.write_memory(out_ptr, &State::BLOCK_TIMESTAMP.to_le_bytes())?;
|
||||
caller.write_memory(out_len_ptr, &64u32.to_le_bytes())?;
|
||||
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
linker
|
||||
.func_wrap(
|
||||
runtime_api::BLOCK_NUMBER,
|
||||
|caller: Caller<State>, out_ptr: u32, out_len_ptr: u32| {
|
||||
let (mut caller, _) = caller.split();
|
||||
|
||||
let out_len = caller.read_u32(out_len_ptr)? as usize;
|
||||
assert_eq!(
|
||||
out_len,
|
||||
revive_common::BYTE_LENGTH_BLOCK_NUMBER,
|
||||
"spurious output buffer size: {out_len}"
|
||||
);
|
||||
|
||||
caller.write_memory(out_ptr, &State::BLOCK_NUMBER.to_le_bytes())?;
|
||||
caller.write_memory(out_len_ptr, &64u32.to_le_bytes())?;
|
||||
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
linker
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ fn transferred_value() {
|
||||
);
|
||||
let code = crate::compile_blob("Value", include_str!("../contracts/Value.sol"));
|
||||
let mut state = State::new(Value::valueCall::SELECTOR.to_vec());
|
||||
state.value = 0x1;
|
||||
state.value = 123;
|
||||
|
||||
let (mut instance, export) = mock_runtime::prepare(&code, None);
|
||||
let state = crate::mock_runtime::call(state, &mut instance, export);
|
||||
@@ -264,3 +264,19 @@ fn sha1() {
|
||||
let received = FixedBytes::<20>::from_slice(&state.output.data[..20]);
|
||||
assert_eq!(received, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_number() {
|
||||
let state = assert_success(Contract::block_number(), true);
|
||||
let received = U256::from_be_bytes::<32>(state.output.data.try_into().unwrap());
|
||||
let expected = U256::from(mock_runtime::State::BLOCK_NUMBER);
|
||||
assert_eq!(received, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_timestamp() {
|
||||
let state = assert_success(Contract::block_timestamp(), true);
|
||||
let received = U256::from_be_bytes::<32>(state.output.data.try_into().unwrap());
|
||||
let expected = U256::from(mock_runtime::State::BLOCK_TIMESTAMP);
|
||||
assert_eq!(received, expected);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user