|
| 1 | +use crate::rpc::types::{ |
| 2 | + cfx::{ |
| 3 | + block::{Block, BlockTransactions, Header}, |
| 4 | + transaction::PackedOrExecuted, |
| 5 | + RpcAddress, |
| 6 | + }, |
| 7 | + Receipt, Transaction, |
| 8 | +}; |
| 9 | +use cfx_addr::Network; |
| 10 | +use cfx_types::{Space, H256, U256, U64}; |
| 11 | +use cfxcore::{ |
| 12 | + block_data_manager::{BlockDataManager, DataVersionTuple}, |
| 13 | + consensus::ConsensusGraphInner, |
| 14 | + pow, ConsensusGraph, SharedConsensusGraph, |
| 15 | +}; |
| 16 | +use primitives::{ |
| 17 | + Block as PrimitiveBlock, BlockHeader as PrimitiveBlockHeader, |
| 18 | + TransactionIndex, TransactionStatus, |
| 19 | +}; |
| 20 | +use std::sync::Arc; |
| 21 | + |
| 22 | +pub fn build_block( |
| 23 | + b: &PrimitiveBlock, network: Network, consensus: &ConsensusGraph, |
| 24 | + consensus_inner: &ConsensusGraphInner, data_man: &Arc<BlockDataManager>, |
| 25 | + include_txs: bool, tx_space_filter: Option<Space>, |
| 26 | +) -> Result<Block, String> { |
| 27 | + let block_hash = b.block_header.hash(); |
| 28 | + |
| 29 | + let epoch_number = consensus_inner |
| 30 | + .get_block_epoch_number(&block_hash) |
| 31 | + .or_else(|| data_man.block_epoch_number(&block_hash)) |
| 32 | + .map(Into::into); |
| 33 | + |
| 34 | + let block_number = consensus.get_block_number(&block_hash)?.map(Into::into); |
| 35 | + |
| 36 | + // get the block.gas_used |
| 37 | + let tx_len = b.transactions.len(); |
| 38 | + |
| 39 | + let (gas_used, transactions) = { |
| 40 | + let maybe_results = consensus_inner.block_execution_results_by_hash( |
| 41 | + &b.hash(), |
| 42 | + false, /* update_cache */ |
| 43 | + ); |
| 44 | + |
| 45 | + // calculate block gasUsed according block.execution_result and |
| 46 | + // tx_space_filter |
| 47 | + let gas_used_sum = match maybe_results { |
| 48 | + Some(DataVersionTuple(_, ref execution_result)) => { |
| 49 | + match tx_space_filter { |
| 50 | + Some(space_filter) => { |
| 51 | + let mut total_gas_used = U256::zero(); |
| 52 | + let mut prev_acc_gas_used = U256::zero(); |
| 53 | + for (idx, tx) in b.transactions.iter().enumerate() { |
| 54 | + let ref receipt = |
| 55 | + execution_result.block_receipts.receipts[idx]; |
| 56 | + if tx.space() == space_filter { |
| 57 | + total_gas_used += receipt.accumulated_gas_used |
| 58 | + - prev_acc_gas_used; |
| 59 | + } |
| 60 | + prev_acc_gas_used = receipt.accumulated_gas_used; |
| 61 | + } |
| 62 | + Some(total_gas_used) |
| 63 | + } |
| 64 | + None => Some( |
| 65 | + execution_result.block_receipts.receipts[tx_len - 1] |
| 66 | + .accumulated_gas_used, |
| 67 | + ), |
| 68 | + } |
| 69 | + } |
| 70 | + None => None, |
| 71 | + }; |
| 72 | + |
| 73 | + // prepare the transaction array according include_txs, |
| 74 | + // execution_result, tx_space_filter |
| 75 | + let transactions = match include_txs { |
| 76 | + false => BlockTransactions::Hashes( |
| 77 | + b.transaction_hashes(Some(Space::Native)), |
| 78 | + ), |
| 79 | + true => { |
| 80 | + let tx_vec = match maybe_results { |
| 81 | + Some(DataVersionTuple(_, ref execution_result)) => { |
| 82 | + let maybe_state_root = |
| 83 | + data_man.get_executed_state_root(&b.hash()); |
| 84 | + |
| 85 | + b.transactions |
| 86 | + .iter() |
| 87 | + .enumerate() |
| 88 | + .filter(|(_idx, tx)| { |
| 89 | + tx_space_filter.is_none() |
| 90 | + || tx.space() == tx_space_filter.unwrap() |
| 91 | + }) |
| 92 | + .enumerate() |
| 93 | + .map(|(new_index, (original_index, tx))| { |
| 94 | + let receipt = execution_result |
| 95 | + .block_receipts |
| 96 | + .receipts |
| 97 | + .get(original_index) |
| 98 | + .unwrap(); |
| 99 | + let prior_gas_used = if original_index == 0 { |
| 100 | + U256::zero() |
| 101 | + } else { |
| 102 | + execution_result.block_receipts.receipts |
| 103 | + [original_index - 1] |
| 104 | + .accumulated_gas_used |
| 105 | + }; |
| 106 | + match receipt.outcome_status { |
| 107 | + TransactionStatus::Success |
| 108 | + | TransactionStatus::Failure => { |
| 109 | + let tx_index = TransactionIndex { |
| 110 | + block_hash: b.hash(), |
| 111 | + real_index: original_index, |
| 112 | + is_phantom: false, |
| 113 | + rpc_index: Some(new_index), |
| 114 | + }; |
| 115 | + let tx_exec_error_msg = |
| 116 | + &execution_result |
| 117 | + .block_receipts |
| 118 | + .tx_execution_error_messages |
| 119 | + [original_index]; |
| 120 | + Transaction::from_signed( |
| 121 | + tx, |
| 122 | + Some(PackedOrExecuted::Executed( |
| 123 | + Receipt::new( |
| 124 | + (**tx).clone(), |
| 125 | + receipt.clone(), |
| 126 | + tx_index, |
| 127 | + prior_gas_used, |
| 128 | + epoch_number, |
| 129 | + execution_result |
| 130 | + .block_receipts |
| 131 | + .block_number, |
| 132 | + b.block_header.base_price(), |
| 133 | + maybe_state_root, |
| 134 | + if tx_exec_error_msg |
| 135 | + .is_empty() |
| 136 | + { |
| 137 | + None |
| 138 | + } else { |
| 139 | + Some( |
| 140 | + tx_exec_error_msg |
| 141 | + .clone(), |
| 142 | + ) |
| 143 | + }, |
| 144 | + network, |
| 145 | + false, |
| 146 | + false, |
| 147 | + )?, |
| 148 | + )), |
| 149 | + network, |
| 150 | + ) |
| 151 | + } |
| 152 | + TransactionStatus::Skipped => { |
| 153 | + Transaction::from_signed( |
| 154 | + tx, None, network, |
| 155 | + ) |
| 156 | + } |
| 157 | + } |
| 158 | + }) |
| 159 | + .collect::<Result<_, _>>()? |
| 160 | + } |
| 161 | + None => b |
| 162 | + .transactions |
| 163 | + .iter() |
| 164 | + .filter(|tx| { |
| 165 | + tx_space_filter.is_none() |
| 166 | + || tx.space() == tx_space_filter.unwrap() |
| 167 | + }) |
| 168 | + .map(|x| Transaction::from_signed(x, None, network)) |
| 169 | + .collect::<Result<_, _>>()?, |
| 170 | + }; |
| 171 | + BlockTransactions::Full(tx_vec) |
| 172 | + } |
| 173 | + }; |
| 174 | + |
| 175 | + (gas_used_sum, transactions) |
| 176 | + }; |
| 177 | + |
| 178 | + let base_fee_per_gas: Option<U256> = |
| 179 | + b.block_header.base_price().map(|x| x[Space::Native]).into(); |
| 180 | + |
| 181 | + // if a block is 1559 block(has base_fee_per_gas) then it's |
| 182 | + // block.gas_limit is 90% of the actual block.gas_limit |
| 183 | + let gas_limit: U256 = b.block_header.core_space_gas_limit(); |
| 184 | + |
| 185 | + Ok(Block { |
| 186 | + hash: H256::from(block_hash), |
| 187 | + parent_hash: H256::from(b.block_header.parent_hash().clone()), |
| 188 | + height: b.block_header.height().into(), |
| 189 | + miner: RpcAddress::try_from_h160(*b.block_header.author(), network)?, |
| 190 | + deferred_state_root: H256::from( |
| 191 | + b.block_header.deferred_state_root().clone(), |
| 192 | + ), |
| 193 | + deferred_receipts_root: H256::from( |
| 194 | + b.block_header.deferred_receipts_root().clone(), |
| 195 | + ), |
| 196 | + deferred_logs_bloom_hash: H256::from( |
| 197 | + b.block_header.deferred_logs_bloom_hash().clone(), |
| 198 | + ), |
| 199 | + blame: U64::from(b.block_header.blame()), |
| 200 | + transactions_root: H256::from( |
| 201 | + b.block_header.transactions_root().clone(), |
| 202 | + ), |
| 203 | + // PrimitiveBlock does not contain this information |
| 204 | + epoch_number: epoch_number.map(|e| U256::from(e)), |
| 205 | + block_number, |
| 206 | + // fee system |
| 207 | + gas_used, |
| 208 | + gas_limit, |
| 209 | + base_fee_per_gas, |
| 210 | + timestamp: b.block_header.timestamp().into(), |
| 211 | + difficulty: b.block_header.difficulty().clone().into(), |
| 212 | + pow_quality: b |
| 213 | + .block_header |
| 214 | + .pow_hash |
| 215 | + .map(|h| pow::pow_hash_to_quality(&h, &b.block_header.nonce())), |
| 216 | + adaptive: b.block_header.adaptive(), |
| 217 | + referee_hashes: b |
| 218 | + .block_header |
| 219 | + .referee_hashes() |
| 220 | + .iter() |
| 221 | + .map(|x| H256::from(*x)) |
| 222 | + .collect(), |
| 223 | + nonce: b.block_header.nonce().into(), |
| 224 | + transactions, |
| 225 | + custom: b |
| 226 | + .block_header |
| 227 | + .custom() |
| 228 | + .clone() |
| 229 | + .into_iter() |
| 230 | + .map(Into::into) |
| 231 | + .collect(), |
| 232 | + size: Some(b.size().into()), |
| 233 | + pos_reference: b.block_header.pos_reference().clone(), |
| 234 | + }) |
| 235 | +} |
| 236 | + |
| 237 | +pub fn build_header( |
| 238 | + h: &PrimitiveBlockHeader, network: Network, consensus: SharedConsensusGraph, |
| 239 | +) -> Result<Header, String> { |
| 240 | + let hash = h.hash(); |
| 241 | + |
| 242 | + let epoch_number = consensus |
| 243 | + .get_block_epoch_number(&hash) |
| 244 | + .or_else(|| consensus.data_manager().block_epoch_number(&hash)) |
| 245 | + .map(Into::into); |
| 246 | + |
| 247 | + let block_number = consensus.get_block_number(&hash)?.map(Into::into); |
| 248 | + |
| 249 | + let base_fee_per_gas: Option<U256> = |
| 250 | + h.base_price().map(|x| x[Space::Native]).into(); |
| 251 | + |
| 252 | + let referee_hashes = |
| 253 | + h.referee_hashes().iter().map(|x| H256::from(*x)).collect(); |
| 254 | + |
| 255 | + Ok(Header { |
| 256 | + hash: H256::from(hash), |
| 257 | + parent_hash: H256::from(*h.parent_hash()), |
| 258 | + height: h.height().into(), |
| 259 | + miner: RpcAddress::try_from_h160(*h.author(), network)?, |
| 260 | + deferred_state_root: H256::from(*h.deferred_state_root()), |
| 261 | + deferred_receipts_root: H256::from(*h.deferred_receipts_root()), |
| 262 | + deferred_logs_bloom_hash: H256::from(*h.deferred_logs_bloom_hash()), |
| 263 | + blame: U64::from(h.blame()), |
| 264 | + transactions_root: H256::from(*h.transactions_root()), |
| 265 | + epoch_number, |
| 266 | + block_number, |
| 267 | + gas_limit: h.gas_limit().into(), |
| 268 | + base_fee_per_gas, |
| 269 | + timestamp: h.timestamp().into(), |
| 270 | + difficulty: h.difficulty().into(), |
| 271 | + adaptive: h.adaptive(), |
| 272 | + referee_hashes, |
| 273 | + nonce: h.nonce().into(), |
| 274 | + pow_quality: h |
| 275 | + .pow_hash |
| 276 | + .map(|pow_hash| pow::pow_hash_to_quality(&pow_hash, &h.nonce())), |
| 277 | + pos_reference: *h.pos_reference(), |
| 278 | + custom: h.custom().clone().into_iter().map(Into::into).collect(), |
| 279 | + }) |
| 280 | +} |
0 commit comments