use cfx_types::{U128, U256, U512};
use cfx_vm_types::{Context, Error, GasLeft, Result, ReturnData};
use std::{cmp, fmt, ops};
#[derive(Debug)]
pub struct FinalizationResult {
pub gas_left: U256,
pub apply_state: bool,
pub return_data: ReturnData,
}
pub trait Finalize {
fn finalize<C: Context>(self, context: C) -> Result<FinalizationResult>;
}
impl Finalize for Result<GasLeft> {
fn finalize<C: Context>(self, context: C) -> Result<FinalizationResult> {
match self {
Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult {
gas_left,
apply_state: true,
return_data: ReturnData::empty(),
}),
Ok(GasLeft::NeedsReturn {
gas_left,
data,
apply_state,
}) => context.ret(&gas_left, &data, apply_state).map(|gas_left| {
FinalizationResult {
gas_left,
apply_state,
return_data: data,
}
}),
Err(err) => Err(err),
}
}
}
impl Finalize for Error {
fn finalize<C: Context>(self, _context: C) -> Result<FinalizationResult> {
Err(self)
}
}
pub trait CostType:
Sized
+ From<usize>
+ Copy
+ Send
+ ops::Mul<Output = Self>
+ ops::Div<Output = Self>
+ ops::Add<Output = Self>
+ ops::Sub<Output = Self>
+ ops::Shr<usize, Output = Self>
+ ops::Shl<usize, Output = Self>
+ cmp::Ord
+ fmt::Debug
{
fn as_u256(&self) -> U256;
fn from_u256(val: U256) -> Result<Self>;
fn as_usize(&self) -> usize;
fn overflow_add(self, other: Self) -> (Self, bool);
fn overflow_mul(self, other: Self) -> (Self, bool);
fn overflow_mul_shr(self, other: Self, shr: usize) -> (Self, bool);
}
impl CostType for U256 {
fn as_u256(&self) -> U256 { *self }
fn from_u256(val: U256) -> Result<Self> { Ok(val) }
fn as_usize(&self) -> usize { self.as_u64() as usize }
fn overflow_add(self, other: Self) -> (Self, bool) {
self.overflowing_add(other)
}
fn overflow_mul(self, other: Self) -> (Self, bool) {
self.overflowing_mul(other)
}
fn overflow_mul_shr(self, other: Self, shr: usize) -> (Self, bool) {
let x = self.full_mul(other);
let U512(parts) = x;
let overflow = (parts[4] | parts[5] | parts[6] | parts[7]) > 0;
let U512(parts) = x >> shr;
(U256([parts[0], parts[1], parts[2], parts[3]]), overflow)
}
}
impl CostType for usize {
fn as_u256(&self) -> U256 { U256::from(*self) }
fn from_u256(val: U256) -> Result<Self> {
let res = val.low_u64() as usize;
if U256::from(res) != val {
return Err(Error::OutOfGas);
}
Ok(res)
}
fn as_usize(&self) -> usize { *self }
fn overflow_add(self, other: Self) -> (Self, bool) {
self.overflowing_add(other)
}
fn overflow_mul(self, other: Self) -> (Self, bool) {
self.overflowing_mul(other)
}
fn overflow_mul_shr(self, other: Self, shr: usize) -> (Self, bool) {
let (c, o) = U128::from(self).overflowing_mul(U128::from(other));
let U128(parts) = c;
let overflow = o | (parts[1] > 0);
let U128(parts) = c >> shr;
let result = parts[0] as usize;
let overflow = overflow | (parts[0] > result as u64);
(result, overflow)
}
}
#[cfg(test)]
mod tests {
use super::CostType;
use cfx_types::U256;
#[test]
fn should_calculate_overflow_mul_shr_without_overflow() {
let num = 1048576;
let (res1, o1) = U256::from(num).overflow_mul_shr(U256::from(num), 20);
let (res2, o2) = num.overflow_mul_shr(num, 20);
assert_eq!(res1, U256::from(num));
assert!(!o1);
assert_eq!(res2, num);
assert!(!o2);
}
#[test]
fn should_calculate_overflow_mul_shr_with_overflow() {
let max = u64::max_value();
let num1 = U256([max, max, max, max]);
let num2 = usize::max_value();
let (res1, o1) = num1.overflow_mul_shr(num1, 256);
let (res2, o2) = num2.overflow_mul_shr(num2, 64);
assert_eq!(res2, num2 - 1);
assert!(o2);
assert_eq!(res1, !U256::zero() - U256::one());
assert!(o1);
}
#[test]
fn should_validate_u256_to_usize_conversion() {
let v = U256::from(usize::max_value()) + U256::from(1);
let res = usize::from_u256(v);
assert!(res.is_err());
}
}