cfx_rpc_eth_types/
transaction.rs

1// Copyright 2019-2021 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5// Copyright 2015-2020 Parity Technologies (UK) Ltd.
6// This file is part of OpenEthereum.
7
8// OpenEthereum is free software: you can redistribute it and/or modify
9// it under the terms of the GNU General Public License as published by
10// the Free Software Foundation, either version 3 of the License, or
11// (at your option) any later version.
12
13// OpenEthereum is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16// GNU General Public License for more details.
17
18// You should have received a copy of the GNU General Public License
19// along with OpenEthereum.  If not, see <http://www.gnu.org/licenses/>.
20
21use crate::{Bytes, SignedAuthorization};
22use cfx_rpc_cfx_types::Transaction as CfxTransaction;
23use cfx_types::{
24    cal_contract_address, CreateContractAddressType, H160, H256, H512, U256,
25    U64,
26};
27use primitives::{
28    transaction::eth_transaction::eip155_signature, AccessList, Action,
29    SignedTransaction,
30};
31use rlp::Encodable;
32use serde::{Deserialize, Serialize};
33
34/// Transaction
35#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
36#[serde(rename_all = "camelCase")]
37pub struct Transaction {
38    /// transaction type
39    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
40    pub transaction_type: Option<U64>,
41    /// Hash
42    pub hash: H256,
43    /// Nonce
44    pub nonce: U256,
45    /// Block hash
46    pub block_hash: Option<H256>,
47    /// Block number
48    pub block_number: Option<U256>,
49    /// Transaction Index
50    pub transaction_index: Option<U256>,
51    /// Sender
52    pub from: H160,
53    /// Recipient
54    pub to: Option<H160>,
55    /// Transferred value
56    pub value: U256,
57    /// Gas Price
58    pub gas_price: Option<U256>,
59    /// Max fee per gas
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub max_fee_per_gas: Option<U256>,
62    /// Gas
63    pub gas: U256,
64    /// Data
65    pub input: Bytes,
66    /// Creates contract
67    pub creates: Option<H160>,
68    /// Raw transaction data
69    pub raw: Option<Bytes>,
70    /// Public key of the signer.
71    pub public_key: Option<H512>,
72    /// The network id of the transaction, if any.
73    pub chain_id: Option<U64>,
74    /// The standardised V field of the signature (0 or 1). Used by legacy
75    /// transaction
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub standard_v: Option<U256>,
78    /// The standardised V field of the signature.
79    pub v: U64,
80    /// The R field of the signature.
81    pub r: U256,
82    /// The S field of the signature.
83    pub s: U256,
84    // Whether tx is success
85    pub status: Option<U64>,
86    /// Optional access list
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub access_list: Option<AccessList>,
89    /// miner bribe
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub max_priority_fee_per_gas: Option<U256>,
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub y_parity: Option<U64>,
94    /* /// Transaction activates at specified block.
95     * pub condition: Option<TransactionCondition>, */
96    /// eip7702 authorization list
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub authorization_list: Option<Vec<SignedAuthorization>>,
99}
100
101impl Transaction {
102    /// Convert `SignedTransaction` into RPC Transaction.
103    pub fn from_signed(
104        t: &SignedTransaction,
105        block_info: (Option<H256>, Option<U256>, Option<U256>),
106        exec_info: (Option<U64>, Option<H160>),
107    ) -> Transaction {
108        let signature = t.signature();
109
110        // for 2718 tx, the v should be equal to the signature.v and y_parity
111        let (v, y_parity) = if t.is_2718() {
112            (U64::from(signature.v()), Some(U64::from(signature.v())))
113        } else {
114            (
115                eip155_signature::add_chain_replay_protection(
116                    signature.v(),
117                    t.chain_id().map(|x| x as u64),
118                )
119                .into(),
120                None,
121            )
122        };
123
124        // for phantom tx, it's r and s are set to 'tx.from', which lead some
125        // txs r and s to 0 which is not valid in some ethereum tools,
126        // so we set them to chain_id
127        let mut r: U256 = signature.r().into();
128        let mut s: U256 = signature.s().into();
129        if r == U256::zero() || s == U256::zero() {
130            let chain_id = t
131                .chain_id()
132                .map(|x| U256::from(x as u64))
133                .expect("should have chain_id");
134            r = chain_id;
135            s = chain_id;
136        }
137
138        Transaction {
139            hash: t.hash(),
140            nonce: *t.nonce(),
141            block_hash: block_info.0,
142            block_number: block_info.1,
143            transaction_index: block_info.2,
144            from: t.sender().address,
145            to: match t.action() {
146                Action::Create => None,
147                Action::Call(ref address) => Some(*address),
148            },
149            value: *t.value(),
150            gas_price: Some(*t.gas_price()),
151            gas: *t.gas(),
152            input: Bytes::new(t.data().clone()),
153            creates: exec_info.1,
154            raw: Some(Bytes::new(t.transaction.transaction.rlp_bytes())),
155            public_key: t.public().map(Into::into),
156            chain_id: t.chain_id().map(|x| U64::from(x as u64)),
157            standard_v: Some(signature.v().into()),
158            v,
159            r,
160            s,
161            status: exec_info.0,
162            access_list: t.access_list().cloned(),
163            max_fee_per_gas: t.after_1559().then_some(*t.gas_price()),
164            max_priority_fee_per_gas: t
165                .after_1559()
166                .then_some(*t.max_priority_gas_price()),
167            y_parity,
168            transaction_type: Some(U64::from(t.type_id())),
169            authorization_list: t.authorization_list().map(|list| {
170                list.iter()
171                    .map(|item| SignedAuthorization::from(item.clone()))
172                    .collect()
173            }),
174        }
175    }
176
177    pub fn deployed_contract_address(t: &SignedTransaction) -> Option<H160> {
178        match t.action() {
179            Action::Create => {
180                let (new_contract_address, _) = cal_contract_address(
181                    CreateContractAddressType::FromSenderNonce,
182                    0,
183                    &t.sender().address,
184                    t.nonce(),
185                    t.data(),
186                );
187                Some(new_contract_address)
188            }
189            Action::Call(_) => None,
190        }
191    }
192}
193
194#[derive(Debug, Clone, PartialEq, Serialize)]
195#[serde(rename_all = "camelCase")]
196pub enum WrapTransaction {
197    NativeTransaction(CfxTransaction),
198    EthTransaction(Transaction),
199}