You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
8.2 KiB

#![allow(dead_code)]
use std::collections::HashMap;
pub mod opcodes;
pub mod u256;
#[derive(Default)]
pub struct Stack {
pub pc: usize,
pub calldata_i: usize,
pub calldata_size: usize,
pub stack: Vec<[u8; 32]>,
pub storage_committed: HashMap<[u8; 32], Vec<u8>>,
pub storage: HashMap<[u8; 32], Vec<u8>>,
pub mem: Vec<u8>,
pub gas: u64,
pub opcodes: HashMap<u8, opcodes::Opcode>,
}
impl Stack {
pub fn new() -> Stack {
let mut s = Stack {
pc: 0,
calldata_i: 0,
calldata_size: 32,
stack: Vec::new(),
storage_committed: HashMap::new(),
storage: HashMap::new(),
mem: Vec::new(),
gas: 10000000000,
opcodes: HashMap::new(),
};
s.opcodes = opcodes::new_opcodes();
s
}
pub fn print_stack(&self) {
println!("stack ({}):", self.stack.len());
for i in (0..self.stack.len()).rev() {
// println!("{:x}", &self.stack[i][28..]);
println!("{:?}", vec_u8_to_hex(self.stack[i].to_vec()));
}
}
pub fn print_memory(&self) {
if !self.mem.is_empty() {
println!("memory ({}):", self.mem.len());
println!("{:?}", vec_u8_to_hex(self.mem.to_vec()));
}
}
pub fn print_storage(&self) {
if !self.storage.is_empty() {
println!("storage ({}):", self.storage.len());
for (key, value) in self.storage.iter() {
println!(
"{:?}: {:?}",
vec_u8_to_hex(key.to_vec()),
vec_u8_to_hex(value.to_vec())
);
}
}
}
pub fn push(&mut self, b: [u8; 32]) {
self.stack.push(b);
}
// push_arbitrary performs a push, but first converting the arbitrary-length
// input into a 32 byte array
pub fn push_arbitrary(&mut self, b: &[u8]) {
// TODO if b.len()>32 return error
let mut d: [u8; 32] = [0; 32];
d[32 - b.len()..].copy_from_slice(b);
self.stack.push(d);
}
// put_arbitrary puts in the last element of the stack the value
pub fn put_arbitrary(&mut self, b: &[u8]) {
// TODO if b.len()>32 return error
let mut d: [u8; 32] = [0; 32];
d[0..b.len()].copy_from_slice(b); // put without left padding
let l = self.stack.len();
self.stack[l - 1] = d;
}
pub fn pop(&mut self) -> Result<[u8; 32], String> {
match self.stack.pop() {
Some(x) => Ok(x),
None => Err("pop err".to_string()), // WIP
}
}
pub fn peek(&mut self) -> Result<[u8; 32], String> {
if self.stack.is_empty() {
return Err("peek err".to_string());
}
Ok(self.stack[self.stack.len() - 1])
}
pub fn substract_gas(&mut self, val: u64) -> Result<(), String> {
if self.gas < val {
return Err("out of gas".to_string());
}
self.gas -= val;
Ok(())
}
pub fn execute(
&mut self,
code: &[u8],
calldata: &[u8],
debug: bool,
) -> Result<Vec<u8>, String> {
self.pc = 0;
self.calldata_i = 0;
let l = code.len();
while self.pc < l {
let opcode = code[self.pc];
if !self.opcodes.contains_key(&opcode) {
return Err(format!("invalid opcode {:x}", opcode));
}
if debug {
println!(
"{} (0x{:x}): pc={:?} gas={:?}",
self.opcodes.get(&opcode).unwrap().name,
opcode,
self.pc,
self.gas,
);
self.print_stack();
self.print_memory();
self.print_storage();
println!();
}
match opcode & 0xf0 {
0x00 => {
// arithmetic
match opcode {
0x00 => {
println!("0x00: STOP");
return Ok(Vec::new());
}
0x01 => self.add()?,
0x02 => self.mul()?,
0x03 => self.sub()?,
0x04 => self.div()?,
0x05 => self.sdiv()?,
0x06 => self.modulus()?,
0x07 => self.smod()?,
0x08 => self.add_mod()?,
0x09 => self.mul_mod()?,
0x0a => self.exp()?,
// 0x0b => self.sign_extend(),
_ => return Err(format!("unimplemented {:x}", opcode)),
}
self.pc += 1;
}
0x10 => {
// arithmetic
match opcode {
0x10 => self.lt()?,
0x11 => self.gt()?,
// 0x12 => self.slt()?,
// 0x13 => self.sgt()?,
0x14 => self.eq()?,
0x15 => self.is_zero()?,
0x16 => self.and()?,
0x17 => self.or()?,
0x18 => self.xor()?,
0x19 => self.not()?,
// 0x1a => self.byte()?,
_ => return Err(format!("unimplemented {:x}", opcode)),
}
self.pc += 1;
}
0x30 => {
match opcode {
0x35 => self.calldata_load(&calldata)?,
0x36 => self.calldata_size(&calldata),
0x39 => self.code_copy(&code)?,
_ => return Err(format!("unimplemented {:x}", opcode)),
}
self.pc += 1;
}
0x50 => {
self.pc += 1;
match opcode {
0x51 => self.mload()?,
0x52 => self.mstore()?,
0x55 => self.sstore()?,
0x56 => self.jump(code)?,
0x57 => self.jump_i(code)?,
0x5b => self.jump_dest()?,
_ => return Err(format!("unimplemented {:x}", opcode)),
}
}
0x60 | 0x70 => {
// push
let n = (opcode - 0x5f) as usize;
self.push_arbitrary(&code[self.pc + 1..self.pc + 1 + n]);
self.pc += 1 + n;
}
0x80 => {
// 0x8x dup
let l = self.stack.len();
if opcode > 0x7f {
self.stack.push(self.stack[l - (opcode - 0x7f) as usize]);
} else {
self.stack.push(self.stack[(0x7f - opcode) as usize]);
}
self.pc += 1;
}
0x90 => {
// 0x9x swap
let l = self.stack.len();
let pos;
if opcode > 0x8e {
pos = l - (opcode - 0x8e) as usize;
} else {
pos = (0x8e - opcode) as usize;
}
self.stack.swap(pos, l - 1);
self.pc += 1;
}
0xf0 => {
if opcode == 0xf3 {
let pos_to_return = u256::u256_to_u64(self.pop()?) as usize;
let len_to_return = u256::u256_to_u64(self.pop()?) as usize;
return Ok(self.mem[pos_to_return..pos_to_return + len_to_return].to_vec());
}
}
_ => {
return Err(format!("unimplemented {:x}", opcode));
}
}
self.substract_gas(self.opcodes.get(&opcode).unwrap().gas)?;
}
Ok(Vec::new())
}
}
pub fn vec_u8_to_hex(bytes: Vec<u8>) -> String {
let strs: Vec<String> = bytes.iter().map(|b| format!("{:02X}", b)).collect();
strs.join("")
}