evm-rs/src/lib.rs
src/lib.rsRaw
1#![allow(dead_code)]
2
3use num_bigint::BigUint;
4use std::collections::HashMap;
5pub mod opcodes;
6
7#[derive(Default)]
8pub struct Stack {
9 pub pc: usize,
10 pub calldata_i: usize,
11 pub stack: Vec<[u8; 32]>,
12 pub mem: Vec<u8>,
13 pub gas: u64,
14 pub opcodes: HashMap<u8, opcodes::Opcode>,
15}
16
17impl Stack {
18 pub fn new() -> Stack {
19 let mut s = Stack {
20 pc: 0,
21 calldata_i: 0,
22 stack: Vec::new(),
23 mem: Vec::new(),
24 gas: 10000000000,
25 opcodes: HashMap::new(),
26 };
27 s.opcodes = opcodes::new_opcodes();
28 s
29 }
30 pub fn print_stack(&self) {
31 for i in (0..self.stack.len()).rev() {
32 println!("{:x?}", &self.stack[i][28..]);
33 }
34 }
35 pub fn push(&mut self, b: [u8; 32]) {
36 self.stack.push(b);
37 }
38 // push_arbitrary performs a push, but first converting the arbitrary-length
39 // input into a 32 byte array
40 pub fn push_arbitrary(&mut self, b: &[u8]) {
41 // TODO if b.len()>32 return error
42 let mut d: [u8; 32] = [0; 32];
43 d[32 - b.len()..].copy_from_slice(b);
44 self.stack.push(d);
45 }
46 // put_arbitrary puts in the last element of the stack the value
47 pub fn put_arbitrary(&mut self, b: &[u8]) {
48 // TODO if b.len()>32 return error
49 let mut d: [u8; 32] = [0; 32];
50 d[32 - b.len()..].copy_from_slice(b);
51 let l = self.stack.len();
52 self.stack[l - 1] = d;
53 }
54 pub fn pop(&mut self) -> [u8; 32] {
55 match self.stack.pop() {
56 Some(x) => x,
57 None => panic!("err"),
58 }
59 }
60
61 pub fn execute(&mut self, code: &[u8], calldata: &[u8], debug: bool) -> Vec<u8> {
62 self.pc = 0;
63 self.calldata_i = 0;
64 let l = code.len();
65
66 while self.pc < l {
67 let opcode = code[self.pc];
68 if !self.opcodes.contains_key(&opcode) {
69 panic!("invalid opcode {:x}", opcode);
70 }
71
72 if debug {
73 println!(
74 "{:?} (0x{:x}): pc={:?} gas={:?}\nstack:",
75 self.opcodes.get(&opcode).unwrap().name,
76 opcode,
77 self.pc,
78 self.gas,
79 );
80 self.print_stack();
81 println!();
82 }
83 match opcode & 0xf0 {
84 0x00 => {
85 // arithmetic
86 match opcode {
87 0x00 => {
88 return Vec::new();
89 }
90 0x01 => self.add(),
91 0x02 => self.mul(),
92 0x03 => self.sub(),
93 0x04 => self.div(),
94 0x05 => self.sdiv(),
95 0x06 => self.modulus(),
96 0x07 => self.smod(),
97 0x08 => self.add_mod(),
98 0x09 => self.mul_mod(),
99 0x0a => self.exp(),
100 // 0x0b => self.sign_extend(),
101 _ => panic!("unimplemented {:x}", opcode),
102 }
103 self.pc += 1;
104 }
105 0x30 => {
106 match opcode {
107 0x35 => {
108 self.calldata_load(&calldata);
109 }
110 _ => panic!("unimplemented {:x}", opcode),
111 }
112 self.pc += 1;
113 }
114 0x50 => {
115 self.pc += 1;
116 match opcode {
117 0x51 => self.mload(),
118 0x52 => self.mstore(),
119 0x56 => self.jump(),
120 0x57 => self.jump_i(),
121 0x5b => self.jump_dest(),
122 _ => panic!("unimplemented {:x}", opcode),
123 }
124 }
125 0x60 | 0x70 => {
126 // push
127 let n = (opcode - 0x5f) as usize;
128 self.push_arbitrary(&code[self.pc + 1..self.pc + 1 + n]);
129 self.pc += 1 + n;
130 }
131 0x80 => {
132 // 0x8x dup
133 let l = self.stack.len();
134 if opcode > 0x7f {
135 self.stack.push(self.stack[l - (opcode - 0x7f) as usize]);
136 } else {
137 self.stack.push(self.stack[(0x7f - opcode) as usize]);
138 }
139 self.pc += 1;
140 }
141 0x90 => {
142 // 0x9x swap
143 let l = self.stack.len();
144 let pos;
145 if opcode > 0x8e {
146 pos = l - (opcode - 0x8e) as usize;
147 } else {
148 pos = (0x8e - opcode) as usize;
149 }
150 self.stack.swap(pos, l - 1);
151 self.pc += 1;
152 }
153 0xf0 => {
154 if opcode == 0xf3 {
155 let pos_to_return = u256_to_u64(self.pop()) as usize;
156 let len_to_return = u256_to_u64(self.pop()) as usize;
157 return self.mem[pos_to_return..pos_to_return + len_to_return].to_vec();
158 }
159 }
160 _ => {
161 panic!("unimplemented {:x}", opcode);
162 }
163 }
164 self.gas -= self.opcodes.get(&opcode).unwrap().gas;
165 }
166 Vec::new()
167 }
168}
169
170pub fn u256_to_u64(a: [u8; 32]) -> u64 {
171 let mut b8: [u8; 8] = [0; 8];
172 b8.copy_from_slice(&a[32 - 8..32]);
173 u64::from_be_bytes(b8)
174}
175pub fn str_to_u256(s: &str) -> [u8; 32] {
176 let bi = s.parse::<BigUint>().unwrap().to_bytes_be();
177 let mut r: [u8; 32] = [0; 32];
178 r[32 - bi.len()..].copy_from_slice(&bi[..]);
179 r
180}