use cfx_bytes::Bytes;
use crate::AddressPocket;
use cfx_types::{Address, Bloom, BloomInput, Space, U256};
use cfx_vm_types::{ActionParams, CallType, CreateType};
use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream};
use rlp_derive::{RlpDecodable, RlpEncodable};
use serde::{ser::SerializeStruct, Serialize, Serializer};
use strum_macros::EnumDiscriminants;
#[derive(Debug, Clone, PartialEq, RlpEncodable, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Call {
pub space: Space,
pub from: Address,
pub to: Address,
pub value: U256,
pub gas: U256,
pub input: Bytes,
pub call_type: CallType,
}
impl Decodable for Call {
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
match rlp.item_count()? {
6 => Ok(Call {
space: Space::Native,
from: rlp.val_at(0)?,
to: rlp.val_at(1)?,
value: rlp.val_at(2)?,
gas: rlp.val_at(3)?,
input: rlp.val_at(4)?,
call_type: rlp.val_at(5)?,
}),
7 => Ok(Call {
space: rlp.val_at(0)?,
from: rlp.val_at(1)?,
to: rlp.val_at(2)?,
value: rlp.val_at(3)?,
gas: rlp.val_at(4)?,
input: rlp.val_at(5)?,
call_type: rlp.val_at(6)?,
}),
_ => Err(DecoderError::RlpInvalidLength),
}
}
}
impl From<ActionParams> for Call {
fn from(p: ActionParams) -> Self {
match p.call_type {
CallType::DelegateCall | CallType::CallCode => Call {
space: p.space,
from: p.address,
to: p.code_address,
value: p.value.value(),
gas: p.gas,
input: p.data.unwrap_or_else(Vec::new),
call_type: p.call_type,
},
_ => Call {
space: p.space,
from: p.sender,
to: p.address,
value: p.value.value(),
gas: p.gas,
input: p.data.unwrap_or_else(Vec::new),
call_type: p.call_type,
},
}
}
}
impl Call {
pub fn bloom(&self) -> Bloom {
let mut bloom = Bloom::default();
bloom.accrue(BloomInput::Raw(self.from.as_bytes()));
bloom.accrue(BloomInput::Raw(self.to.as_bytes()));
bloom
}
}
#[derive(Debug, PartialEq, Clone, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum Outcome {
Success,
Reverted,
Fail,
}
impl Encodable for Outcome {
fn rlp_append(&self, s: &mut RlpStream) {
let v = match *self {
Outcome::Success => 0u32,
Outcome::Reverted => 1,
Outcome::Fail => 2,
};
Encodable::rlp_append(&v, s);
}
}
impl Decodable for Outcome {
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
rlp.as_val().and_then(|v| {
Ok(match v {
0u32 => Outcome::Success,
1 => Outcome::Reverted,
2 => Outcome::Fail,
_ => {
return Err(DecoderError::Custom(
"Invalid value of CallType item",
));
}
})
})
}
}
#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CallResult {
pub outcome: Outcome,
pub gas_left: U256,
pub return_data: Bytes,
}
#[derive(Debug, Clone, PartialEq, RlpEncodable, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Create {
pub space: Space,
pub from: Address,
pub value: U256,
pub gas: U256,
pub init: Bytes,
pub create_type: CreateType,
}
impl Decodable for Create {
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
match rlp.item_count()? {
5 => Ok(Create {
space: Space::Native,
from: rlp.val_at(0)?,
value: rlp.val_at(1)?,
gas: rlp.val_at(2)?,
init: rlp.val_at(3)?,
create_type: rlp.val_at(4)?,
}),
6 => Ok(Create {
space: rlp.val_at(0)?,
from: rlp.val_at(1)?,
value: rlp.val_at(2)?,
gas: rlp.val_at(3)?,
init: rlp.val_at(4)?,
create_type: rlp.val_at(5)?,
}),
_ => Err(DecoderError::RlpInvalidLength),
}
}
}
impl From<ActionParams> for Create {
fn from(p: ActionParams) -> Self {
Create {
space: p.space,
from: p.sender,
value: p.value.value(),
gas: p.gas,
init: p.code.map_or_else(Vec::new, |c| (*c).clone()),
create_type: p.create_type,
}
}
}
impl Create {
pub fn bloom(&self) -> Bloom {
BloomInput::Raw(self.from.as_bytes()).into()
}
}
#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateResult {
pub outcome: Outcome,
pub addr: Address,
pub gas_left: U256,
pub return_data: Bytes,
}
impl CreateResult {
pub fn bloom(&self) -> Bloom {
if self.outcome == Outcome::Success {
BloomInput::Raw(self.addr.as_bytes()).into()
} else {
Bloom::default()
}
}
}
#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)]
pub struct InternalTransferAction {
pub from: AddressPocket,
pub to: AddressPocket,
pub value: U256,
}
impl Serialize for InternalTransferAction {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
let mut s = serializer.serialize_struct("InternalTransferAction", 5)?;
s.serialize_field("from", &self.from.inner_address_or_default())?;
s.serialize_field("fromPocket", &*self.from.pocket())?;
s.serialize_field("fromSpace", &*self.from.space())?;
s.serialize_field("to", &self.to.inner_address_or_default())?;
s.serialize_field("toPocket", &*self.to.pocket())?;
s.serialize_field("toSpace", &*self.to.space())?;
s.serialize_field("value", &self.value)?;
s.end()
}
}
impl InternalTransferAction {
pub fn bloom(&self) -> Bloom {
let mut bloom = Bloom::default();
bloom.accrue(BloomInput::Raw(
self.from.inner_address_or_default().as_ref(),
));
bloom.accrue(BloomInput::Raw(
self.to.inner_address_or_default().as_ref(),
));
bloom
}
}
#[derive(Debug, Clone, PartialEq, EnumDiscriminants)]
#[strum_discriminants(name(ActionType))]
pub enum Action {
Call(Call),
Create(Create),
CallResult(CallResult),
CreateResult(CreateResult),
InternalTransferAction(InternalTransferAction),
}
impl Encodable for Action {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(2);
match *self {
Action::Call(ref call) => {
s.append(&0u8);
s.append(call);
}
Action::Create(ref create) => {
s.append(&1u8);
s.append(create);
}
Action::CallResult(ref call_result) => {
s.append(&2u8);
s.append(call_result);
}
Action::CreateResult(ref create_result) => {
s.append(&3u8);
s.append(create_result);
}
Action::InternalTransferAction(ref internal_action) => {
s.append(&4u8);
s.append(internal_action);
}
}
}
}
impl Decodable for Action {
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
let action_type: u8 = rlp.val_at(0)?;
match action_type {
0 => rlp.val_at(1).map(Action::Call),
1 => rlp.val_at(1).map(Action::Create),
2 => rlp.val_at(1).map(Action::CallResult),
3 => rlp.val_at(1).map(Action::CreateResult),
4 => rlp.val_at(1).map(Action::InternalTransferAction),
_ => Err(DecoderError::Custom("Invalid action type.")),
}
}
}
impl Action {
pub fn bloom(&self) -> Bloom {
match *self {
Action::Call(ref call) => call.bloom(),
Action::Create(ref create) => create.bloom(),
Action::CallResult(_) => Bloom::default(),
Action::CreateResult(ref create_result) => create_result.bloom(),
Action::InternalTransferAction(ref internal_action) => {
internal_action.bloom()
}
}
}
}