use hash::{H256, Address};
use uint::U256;
use owasm_std;
#[derive(Debug)]
pub struct Error;
mod external {
extern "C" {
pub fn ccall(
gas: i64,
address: *const u8,
val_ptr: *const u8,
input_ptr: *const u8,
input_len: u32,
result_ptr: *mut u8,
result_len: u32,
) -> i32;
pub fn dcall(
gas: i64,
address: *const u8,
input_ptr: *const u8,
input_len: u32,
result_ptr: *mut u8,
result_len: u32,
) -> i32;
pub fn scall(
gas: i64,
address: *const u8,
input_ptr: *const u8,
input_len: u32,
result_ptr: *mut u8,
result_len: u32,
) -> i32;
pub fn blockhash(number: i64, dest: *mut u8);
pub fn balance(address: *const u8, dest: *mut u8);
pub fn coinbase(dest: *mut u8);
pub fn timestamp() -> i64;
pub fn blocknumber() -> i64;
pub fn difficulty(dest: *mut u8);
pub fn gaslimit(dest: *mut u8);
#[cfg(feature = "kip6")]
pub fn gasleft() -> i64;
pub fn sender(dest: *mut u8);
pub fn address(dest: *mut u8);
pub fn value(dest: *mut u8);
pub fn origin(dest: *mut u8);
pub fn elog(
topic_ptr: *const u8,
topic_count: u32,
data_ptr: *const u8,
data_len: u32
);
pub fn create(
endowment: *const u8,
code_ptr: *const u8,
code_len: u32,
result_ptr: *mut u8
) -> i32;
#[cfg(feature = "kip4")]
pub fn create2(
endowment: *const u8,
salt: *const u8,
code_ptr: *const u8,
code_len: u32,
result_ptr: *mut u8
) -> i32;
pub fn suicide(refund: *const u8) -> !;
pub fn ret(ptr: *const u8, len: u32) -> !;
pub fn input_length() -> u32;
pub fn fetch_input(dst: *mut u8);
pub fn get_bytes(key: *const u8, result: *mut u8);
pub fn get_bytes_len(key: *const u8) -> u64;
pub fn set_bytes(key: *const u8, bytes: *const u8, bytes_len: u64);
}
}
pub fn get_bytes(key: &H256) -> Result<owasm_std::Vec<u8>, Error> {
let result_len = get_bytes_len(key)?;
let mut result: owasm_std::Vec<u8> = owasm_std::Vec::with_capacity(result_len as usize);
result.resize(result_len as usize, 0u8);
unsafe { external::get_bytes(key.as_ptr(), result.as_mut_ptr()); }
Ok(result)
}
fn get_bytes_len(key: &H256) -> Result<u32, Error> {
unsafe {
Ok(external::get_bytes_len(key.as_ptr()) as u32)
}
}
pub fn set_bytes(key: &H256, bytes: &[u8]) -> Result<(), Error> {
let len = bytes.len() as u64;
unsafe { external::set_bytes(key.as_ptr(), bytes.as_ptr(), len); }
Ok(())
}
pub fn suicide(refund: &Address) -> ! {
unsafe { external::suicide(refund.as_ptr()); }
}
pub fn balance(address: &Address) -> U256 {
unsafe { fetch_u256(|x| external::balance(address.as_ptr(), x) ) }
}
pub fn create(endowment: U256, code: &[u8]) -> Result<Address, Error> {
let mut endowment_arr = [0u8; 32];
endowment.to_big_endian(&mut endowment_arr);
let mut result = Address::new();
unsafe {
if external::create(endowment_arr.as_ptr(), code.as_ptr(), code.len() as u32, (&mut result).as_mut_ptr()) == 0 {
Ok(result)
} else {
Err(Error)
}
}
}
#[cfg(feature = "kip4")]
pub fn create2(endowment: U256, salt: H256, code: &[u8]) -> Result<Address, Error> {
let mut endowment_arr = [0u8; 32];
endowment.to_big_endian(&mut endowment_arr);
let mut result = Address::new();
unsafe {
if external::create2(endowment_arr.as_ptr(), salt.as_ptr(), code.as_ptr(), code.len() as u32, (&mut result).as_mut_ptr()) == 0 {
Ok(result)
} else {
Err(Error)
}
}
}
pub fn call(gas: u64, address: &Address, value: U256, input: &[u8], result: &mut [u8]) -> Result<(), Error> {
let mut value_arr = [0u8; 32];
value.to_big_endian(&mut value_arr);
unsafe {
match external::ccall(gas as i64, address.as_ptr(), value_arr.as_ptr(), input.as_ptr(), input.len() as u32,
result.as_mut_ptr(), result.len() as u32) {
0 => Ok(()),
_ => Err(Error),
}
}
}
pub fn call_code(gas: u64, address: &Address, input: &[u8], result: &mut [u8]) -> Result<(), Error> {
unsafe {
match external::dcall(gas as i64, address.as_ptr(), input.as_ptr(), input.len() as u32, result.as_mut_ptr(), result.len() as u32) {
0 => Ok(()),
_ => Err(Error),
}
}
}
pub fn static_call(gas: u64, address: &Address, input: &[u8], result: &mut [u8]) -> Result<(), Error> {
unsafe {
match external::scall(gas as i64, address.as_ptr(), input.as_ptr(), input.len() as u32, result.as_mut_ptr(), result.len() as u32) {
0 => Ok(()),
_ => Err(Error),
}
}
}
pub fn block_hash(block_number: u64) -> H256 {
let mut res = H256::zero();
unsafe {
external::blockhash(block_number as i64, res.as_mut_ptr())
}
res
}
pub fn coinbase() -> Address {
unsafe { fetch_address(|x| external::coinbase(x) ) }
}
pub fn timestamp() -> u64 {
unsafe { external::timestamp() as u64 }
}
pub fn block_number() -> u64 {
unsafe { external::blocknumber() as u64 }
}
pub fn difficulty() -> U256 {
unsafe { fetch_u256(|x| external::difficulty(x) ) }
}
pub fn gas_limit() -> U256 {
unsafe { fetch_u256(|x| external::gaslimit(x) ) }
}
#[cfg(feature = "kip6")]
pub fn gas_left() -> u64 {
unsafe { external::gasleft() as u64 }
}
pub fn sender() -> Address {
unsafe { fetch_address(|x| external::sender(x) ) }
}
pub fn origin() -> Address {
unsafe { fetch_address(|x| external::origin(x) ) }
}
pub fn value() -> U256 {
unsafe { fetch_u256(|x| external::value(x) ) }
}
pub fn address() -> Address {
unsafe { fetch_address(|x| external::address(x) ) }
}
pub fn log(topics: &[H256], data: &[u8]) {
unsafe { external::elog(topics.as_ptr() as *const u8, topics.len() as u32, data.as_ptr(), data.len() as u32); }
}
pub fn input() -> owasm_std::Vec<u8> {
let len = unsafe { external::input_length() };
match len {
0 => owasm_std::Vec::new(),
non_zero => {
let mut data = owasm_std::Vec::with_capacity(non_zero as usize);
unsafe {
data.set_len(non_zero as usize);
external::fetch_input(data.as_mut_ptr());
}
data
}
}
}
pub fn ret(data: &[u8]) -> ! {
unsafe { external::ret(data.as_ptr(), data.len() as u32); }
}
unsafe fn fetch_address<F>(f: F) -> Address where F: Fn(*mut u8) {
let mut res = Address::zero();
f(res.as_mut_ptr());
res
}
unsafe fn fetch_u256<F>(f: F) -> U256 where F: Fn(*mut u8) {
let mut res = [0u8; 32];
f(res.as_mut_ptr());
U256::from_big_endian(&res)
}