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.

180 lines
5.9 KiB

#![allow(dead_code)]
use num_bigint::BigUint;
use std::collections::HashMap;
pub mod opcodes;
#[derive(Default)]
pub struct Stack {
pub pc: usize,
pub calldata_i: usize,
pub stack: Vec<[u8; 32]>,
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,
stack: Vec::new(),
mem: Vec::new(),
gas: 10000000000,
opcodes: HashMap::new(),
};
s.opcodes = opcodes::new_opcodes();
s
}
pub fn print_stack(&self) {
for i in (0..self.stack.len()).rev() {
println!("{:x?}", &self.stack[i][28..]);
}
}
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[32 - b.len()..].copy_from_slice(b);
let l = self.stack.len();
self.stack[l - 1] = d;
}
pub fn pop(&mut self) -> [u8; 32] {
match self.stack.pop() {
Some(x) => x,
None => panic!("err"),
}
}
pub fn execute(&mut self, code: &[u8], calldata: &[u8], debug: bool) -> Vec<u8> {
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) {
panic!("invalid opcode {:x}", opcode);
}
if debug {
println!(
"{:?} (0x{:x}): pc={:?} gas={:?}\nstack:",
self.opcodes.get(&opcode).unwrap().name,
opcode,
self.pc,
self.gas,
);
self.print_stack();
println!();
}
match opcode & 0xf0 {
0x00 => {
// arithmetic
match opcode {
0x00 => {
return 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(),
_ => panic!("unimplemented {:x}", opcode),
}
self.pc += 1;
}
0x30 => {
match opcode {
0x35 => {
self.calldata_load(&calldata);
}
_ => panic!("unimplemented {:x}", opcode),
}
self.pc += 1;
}
0x50 => {
self.pc += 1;
match opcode {
0x51 => self.mload(),
0x52 => self.mstore(),
0x56 => self.jump(),
0x57 => self.jump_i(),
0x5b => self.jump_dest(),
_ => panic!("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_to_u64(self.pop()) as usize;
let len_to_return = u256_to_u64(self.pop()) as usize;
return self.mem[pos_to_return..pos_to_return + len_to_return].to_vec();
}
}
_ => {
panic!("unimplemented {:x}", opcode);
}
}
self.gas -= self.opcodes.get(&opcode).unwrap().gas;
}
Vec::new()
}
}
pub fn u256_to_u64(a: [u8; 32]) -> u64 {
let mut b8: [u8; 8] = [0; 8];
b8.copy_from_slice(&a[32 - 8..32]);
u64::from_be_bytes(b8)
}
pub fn str_to_u256(s: &str) -> [u8; 32] {
let bi = s.parse::<BigUint>().unwrap().to_bytes_be();
let mut r: [u8; 32] = [0; 32];
r[32 - bi.len()..].copy_from_slice(&bi[..]);
r
}