cfx_vm_interpreter/
evm.rs

1// Copyright 2015-2018 Parity Technologies (UK) Ltd.
2// This file is part of Parity.
3
4// Parity is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
16
17// Copyright 2019 Conflux Foundation. All rights reserved.
18// Conflux is free software and distributed under GNU General Public License.
19// See http://www.gnu.org/licenses/
20
21//! Evm interface.
22use cfx_types::{U128, U256, U512};
23use cfx_vm_types::{Context, Error, GasLeft, Result, ReturnData};
24use std::{cmp, fmt, ops};
25
26/// Finalization result. Gas Left: either it is a known value, or it needs to
27/// be computed by processing a return instruction.
28#[derive(Debug)]
29pub struct FinalizationResult {
30    /// Final amount of gas left.
31    pub gas_left: U256,
32    /// Apply execution state changes or revert them.
33    pub apply_state: bool,
34    /// Return data buffer.
35    pub return_data: ReturnData,
36}
37
38/// Types that can be "finalized" using an EVM.
39///
40/// In practice, this is just used to define an inherent impl on
41/// `Reult<GasLeft<'a>>`.
42pub trait Finalize {
43    /// Consume the context, call return if necessary, and produce call
44    /// result.
45    fn finalize<C: Context>(self, context: C) -> Result<FinalizationResult>;
46}
47
48impl Finalize for Result<GasLeft> {
49    fn finalize<C: Context>(self, context: C) -> Result<FinalizationResult> {
50        match self {
51            Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult {
52                gas_left,
53                apply_state: true,
54                return_data: ReturnData::empty(),
55            }),
56            Ok(GasLeft::NeedsReturn {
57                gas_left,
58                data,
59                apply_state,
60            }) => context.ret(&gas_left, &data, apply_state).map(|gas_left| {
61                FinalizationResult {
62                    gas_left,
63                    apply_state,
64                    return_data: data,
65                }
66            }),
67            Err(err) => Err(err),
68        }
69    }
70}
71
72impl Finalize for Error {
73    fn finalize<C: Context>(self, _context: C) -> Result<FinalizationResult> {
74        Err(self)
75    }
76}
77
78/// Cost calculation type. For low-gas usage we calculate costs using usize
79/// instead of U256
80pub trait CostType:
81    Sized
82    + From<usize>
83    + Copy
84    + Send
85    + ops::Mul<Output = Self>
86    + ops::Div<Output = Self>
87    + ops::Add<Output = Self>
88    + ops::Sub<Output = Self>
89    + ops::Shr<usize, Output = Self>
90    + ops::Shl<usize, Output = Self>
91    + ops::AddAssign
92    + ops::SubAssign
93    + cmp::Ord
94    + fmt::Debug
95{
96    /// Converts this cost into `U256`
97    fn as_u256(&self) -> U256;
98    /// Tries to fit `U256` into this `Cost` type
99    fn from_u256(val: U256) -> Result<Self>;
100    /// Convert to usize (may panic)
101    fn as_usize(&self) -> usize;
102    /// Add with overflow
103    fn overflow_add(self, other: Self) -> (Self, bool);
104    /// Multiple with overflow
105    fn overflow_mul(self, other: Self) -> (Self, bool);
106    /// Single-step full multiplication and shift: `(self*other) >> shr`
107    /// Should not overflow on intermediate steps
108    fn overflow_mul_shr(self, other: Self, shr: usize) -> (Self, bool);
109}
110
111impl CostType for U256 {
112    fn as_u256(&self) -> U256 { *self }
113
114    fn from_u256(val: U256) -> Result<Self> { Ok(val) }
115
116    fn as_usize(&self) -> usize { self.as_u64() as usize }
117
118    fn overflow_add(self, other: Self) -> (Self, bool) {
119        self.overflowing_add(other)
120    }
121
122    fn overflow_mul(self, other: Self) -> (Self, bool) {
123        self.overflowing_mul(other)
124    }
125
126    fn overflow_mul_shr(self, other: Self, shr: usize) -> (Self, bool) {
127        let x = self.full_mul(other);
128        let U512(parts) = x;
129        let overflow = (parts[4] | parts[5] | parts[6] | parts[7]) > 0;
130        let U512(parts) = x >> shr;
131        (U256([parts[0], parts[1], parts[2], parts[3]]), overflow)
132    }
133}
134
135impl CostType for usize {
136    fn as_u256(&self) -> U256 { U256::from(*self) }
137
138    fn from_u256(val: U256) -> Result<Self> {
139        let res = val.low_u64() as usize;
140
141        // validate if value fits into usize
142        if U256::from(res) != val {
143            return Err(Error::OutOfGas);
144        }
145
146        Ok(res)
147    }
148
149    fn as_usize(&self) -> usize { *self }
150
151    fn overflow_add(self, other: Self) -> (Self, bool) {
152        self.overflowing_add(other)
153    }
154
155    fn overflow_mul(self, other: Self) -> (Self, bool) {
156        self.overflowing_mul(other)
157    }
158
159    fn overflow_mul_shr(self, other: Self, shr: usize) -> (Self, bool) {
160        let (c, o) = U128::from(self).overflowing_mul(U128::from(other));
161        let U128(parts) = c;
162        let overflow = o | (parts[1] > 0);
163        let U128(parts) = c >> shr;
164        let result = parts[0] as usize;
165        let overflow = overflow | (parts[0] > result as u64);
166        (result, overflow)
167    }
168}
169
170#[cfg(test)]
171mod tests {
172    use super::CostType;
173    use cfx_types::U256;
174
175    #[test]
176    fn should_calculate_overflow_mul_shr_without_overflow() {
177        // given
178        let num = 1048576;
179
180        // when
181        let (res1, o1) = U256::from(num).overflow_mul_shr(U256::from(num), 20);
182        let (res2, o2) = num.overflow_mul_shr(num, 20);
183
184        // then
185        assert_eq!(res1, U256::from(num));
186        assert!(!o1);
187        assert_eq!(res2, num);
188        assert!(!o2);
189    }
190
191    #[test]
192    fn should_calculate_overflow_mul_shr_with_overflow() {
193        // given
194        let max = u64::max_value();
195        let num1 = U256([max, max, max, max]);
196        let num2 = usize::max_value();
197
198        // when
199        let (res1, o1) = num1.overflow_mul_shr(num1, 256);
200        let (res2, o2) = num2.overflow_mul_shr(num2, 64);
201
202        // then
203        assert_eq!(res2, num2 - 1);
204        assert!(o2);
205
206        assert_eq!(res1, !U256::zero() - U256::one());
207        assert!(o1);
208    }
209
210    #[test]
211    fn should_validate_u256_to_usize_conversion() {
212        // given
213        let v = U256::from(usize::max_value()) + U256::from(1);
214
215        // when
216        let res = usize::from_u256(v);
217
218        // then
219        assert!(res.is_err());
220    }
221}