use crate::{
cost::Cost,
util::{arithmetic::PrimeField, Itertools},
};
use std::{
io::Write,
iter,
process::{Command, Stdio},
};
#[cfg(feature = "revm")]
pub use executor::deploy_and_call;
pub use ruint::aliases::{B160 as Address, B256, U256, U512};
#[cfg(feature = "revm")]
pub(crate) mod executor;
#[derive(Debug)]
pub struct MemoryChunk {
ptr: usize,
len: usize,
}
impl MemoryChunk {
pub(crate) fn new(ptr: usize) -> Self {
Self { ptr, len: 0 }
}
pub(crate) fn ptr(&self) -> usize {
self.ptr
}
pub(crate) fn len(&self) -> usize {
self.len
}
pub(crate) fn end(&self) -> usize {
self.ptr + self.len
}
pub(crate) fn reset(&mut self, ptr: usize) {
self.ptr = ptr;
self.len = 0;
}
pub(crate) fn extend(&mut self, size: usize) {
self.len += size;
}
}
pub fn fe_to_u256<F>(f: F) -> U256
where
F: PrimeField<Repr = [u8; 32]>,
{
U256::from_le_bytes(f.to_repr())
}
pub fn u256_to_fe<F>(value: U256) -> F
where
F: PrimeField<Repr = [u8; 32]>,
{
let value = value % modulus::<F>();
F::from_repr(value.to_le_bytes::<32>()).unwrap()
}
pub fn modulus<F>() -> U256
where
F: PrimeField<Repr = [u8; 32]>,
{
U256::from_le_bytes((-F::ONE).to_repr()) + U256::from(1)
}
pub fn encode_calldata<F>(instances: &[Vec<F>], proof: &[u8]) -> Vec<u8>
where
F: PrimeField<Repr = [u8; 32]>,
{
iter::empty()
.chain(
instances
.iter()
.flatten()
.flat_map(|value| value.to_repr().as_ref().iter().rev().cloned().collect_vec()),
)
.chain(proof.iter().cloned())
.collect()
}
pub fn estimate_gas(cost: Cost) -> usize {
let proof_size = cost.num_commitment * 64 + (cost.num_evaluation + cost.num_instance) * 32;
let intrinsic_cost = 21000;
let calldata_cost = (proof_size as f64 * 15.25).ceil() as usize;
let ec_operation_cost = (45100 + cost.num_pairing * 34000) + (cost.num_msm - 2) * 6350;
intrinsic_cost + calldata_cost + ec_operation_cost
}
pub fn compile_solidity(code: &str) -> Vec<u8> {
let mut cmd = Command::new("solc")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.arg("--bin")
.arg("-")
.spawn()
.unwrap();
cmd.stdin.take().unwrap().write_all(code.as_bytes()).unwrap();
let output = cmd.wait_with_output().unwrap().stdout;
let binary = *split_by_ascii_whitespace(&output).last().unwrap();
assert!(!binary.is_empty());
hex::decode(binary).unwrap()
}
fn split_by_ascii_whitespace(bytes: &[u8]) -> Vec<&[u8]> {
let mut split = Vec::new();
let mut start = None;
for (idx, byte) in bytes.iter().enumerate() {
if byte.is_ascii_whitespace() {
if let Some(start) = start.take() {
split.push(&bytes[start..idx]);
}
} else if start.is_none() {
start = Some(idx);
}
}
if let Some(last) = start {
split.push(&bytes[last..]);
}
split
}
#[test]
fn test_split_by_ascii_whitespace_1() {
let bytes = b" \x01 \x02 \x03";
let split = split_by_ascii_whitespace(bytes);
assert_eq!(split, [b"\x01", b"\x02", b"\x03"]);
}
#[test]
fn test_split_by_ascii_whitespace_2() {
let bytes = b"123456789abc";
let split = split_by_ascii_whitespace(bytes);
assert_eq!(split, [b"123456789abc"]);
}