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_types::{
23    cal_contract_address, CreateContractAddressType, H160, H256, H512, U256,
24    U64,
25};
26use primitives::{
27    transaction::eth_transaction::eip155_signature, AccessList, Action,
28    SignedTransaction,
29};
30use rlp::Encodable;
31use serde::{Deserialize, Serialize};
32
33/// Transaction
34#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
35#[serde(rename_all = "camelCase")]
36pub struct Transaction {
37    /// transaction type
38    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
39    pub transaction_type: Option<U64>,
40    /// Hash
41    pub hash: H256,
42    /// Nonce
43    pub nonce: U256,
44    /// Block hash
45    pub block_hash: Option<H256>,
46    /// Block number
47    pub block_number: Option<U256>,
48    /// Transaction Index
49    pub transaction_index: Option<U256>,
50    /// Sender
51    pub from: H160,
52    /// Recipient
53    pub to: Option<H160>,
54    /// Transferred value
55    pub value: U256,
56    /// Gas Price
57    pub gas_price: Option<U256>,
58    /// Max fee per gas
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub max_fee_per_gas: Option<U256>,
61    /// Gas
62    pub gas: U256,
63    /// Data
64    pub input: Bytes,
65    /// Creates contract
66    pub creates: Option<H160>,
67    /// Raw transaction data
68    pub raw: Option<Bytes>,
69    /// Public key of the signer.
70    pub public_key: Option<H512>,
71    /// The network id of the transaction, if any.
72    pub chain_id: Option<U64>,
73    /// The standardised V field of the signature (0 or 1). Used by legacy
74    /// transaction
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub standard_v: Option<U256>,
77    /// The standardised V field of the signature.
78    pub v: U64,
79    /// The R field of the signature.
80    pub r: U256,
81    /// The S field of the signature.
82    pub s: U256,
83    // Whether tx is success
84    pub status: Option<U64>,
85    /// Optional access list
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub access_list: Option<AccessList>,
88    /// miner bribe
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub max_priority_fee_per_gas: Option<U256>,
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub y_parity: Option<U64>,
93    /* /// Transaction activates at specified block.
94     * pub condition: Option<TransactionCondition>, */
95    /// eip7702 authorization list
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub authorization_list: Option<Vec<SignedAuthorization>>,
98}
99
100impl Transaction {
101    /// Convert `SignedTransaction` into RPC Transaction.
102    pub fn from_signed(
103        t: &SignedTransaction,
104        block_info: (Option<H256>, Option<U256>, Option<U256>),
105        exec_info: (Option<U64>, Option<H160>),
106    ) -> Transaction {
107        let signature = t.signature();
108
109        // for 2718 tx, the v should be equal to the signature.v and y_parity
110        let (v, y_parity) = if t.is_2718() {
111            (U64::from(signature.v()), Some(U64::from(signature.v())))
112        } else {
113            (
114                eip155_signature::add_chain_replay_protection(
115                    signature.v(),
116                    t.chain_id().map(|x| x as u64),
117                )
118                .into(),
119                None,
120            )
121        };
122
123        // for phantom tx, it's r and s are set to 'tx.from', which lead some
124        // txs r and s to 0 which is not valid in some ethereum tools,
125        // so we set them to chain_id
126        let mut r: U256 = signature.r().into();
127        let mut s: U256 = signature.s().into();
128        if r == U256::zero() || s == U256::zero() {
129            let chain_id = t
130                .chain_id()
131                .map(|x| U256::from(x as u64))
132                .expect("should have chain_id");
133            r = chain_id;
134            s = chain_id;
135        }
136
137        Transaction {
138            hash: t.hash(),
139            nonce: *t.nonce(),
140            block_hash: block_info.0,
141            block_number: block_info.1,
142            transaction_index: block_info.2,
143            from: t.sender().address,
144            to: match t.action() {
145                Action::Create => None,
146                Action::Call(ref address) => Some(*address),
147            },
148            value: *t.value(),
149            gas_price: Some(*t.gas_price()),
150            gas: *t.gas(),
151            input: Bytes::new(t.data().clone()),
152            creates: exec_info.1,
153            raw: Some(Bytes::new(t.transaction.transaction.rlp_bytes())),
154            public_key: t.public().map(Into::into),
155            chain_id: t.chain_id().map(|x| U64::from(x as u64)),
156            standard_v: Some(signature.v().into()),
157            v,
158            r,
159            s,
160            status: exec_info.0,
161            access_list: t.access_list().cloned(),
162            max_fee_per_gas: t.after_1559().then_some(*t.gas_price()),
163            max_priority_fee_per_gas: t
164                .after_1559()
165                .then_some(*t.max_priority_gas_price()),
166            y_parity,
167            transaction_type: Some(U64::from(t.type_id())),
168            authorization_list: t.authorization_list().map(|list| {
169                list.iter()
170                    .map(|item| SignedAuthorization::from(item.clone()))
171                    .collect()
172            }),
173        }
174    }
175
176    pub fn deployed_contract_address(t: &SignedTransaction) -> Option<H160> {
177        match t.action() {
178            Action::Create => {
179                let (new_contract_address, _) = cal_contract_address(
180                    CreateContractAddressType::FromSenderNonce,
181                    0,
182                    &t.sender().address,
183                    t.nonce(),
184                    t.data(),
185                );
186                Some(new_contract_address)
187            }
188            Action::Call(_) => None,
189        }
190    }
191}