1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::evm::opcode::*;
use crate::evm::ConcreteStack;
use crate::evm::{Evm, Stack, Stepper};
use crate::util::w256;

// ===================================================================
// Concrete EVM
// ===================================================================

#[derive(Debug, PartialEq)]
pub enum ConcreteResult<'a> {
    Continue(ConcreteEvm<'a>),
    Return { data: Vec<u8> },
    Revert { data: Vec<u8> },
}

pub type ConcreteEvm<'a> = Evm<'a, ConcreteStack<w256>>;

impl<'a> ConcreteEvm<'a> {
    /// Execute the contract to completion.
    pub fn run(mut self) -> ConcreteResult<'a> {
        // Eventually, this needs a return type.
        loop {
            let r = self.step();

            match r {
                ConcreteResult::Continue(evm) => {
                    self = evm;
                }
                _ => {
                    return r;
                }
            }
        }
    }
}

impl<'a> Stepper for ConcreteEvm<'a> {
    type Result = ConcreteResult<'a>;

    /// Execute instruction at the current `pc`.
    fn step(self) -> Self::Result {
        let opcode = self.code[self.pc];
        //
        match opcode {
            STOP => Self::Result::Return { data: Vec::new() },
            //
            ADD => {
                let lhs = self.stack.peek(1);
                let rhs = self.stack.peek(0);
                Self::Result::Continue(self.pop(2).push(lhs + rhs).next(1))
            }
            PUSH1..=PUSH32 => {
                // Determine push size
                let n = ((opcode - PUSH1) + 1) as usize;
                let pc = self.pc + 1;
                // Extract bytes
                let bytes = &self.code[pc..pc + n];
                // Convert bytes into w256 word
                let w = w256::from_be_bytes(bytes);
                // Done
                Self::Result::Continue(self.push(w.into()).next(n + 1))
            }
            //
            _ => {
                panic!("unknown instruction encountered");
            }
        }
    }
}