diff --git a/crates/rpc/rpc-types/src/eth/index.rs b/crates/rpc/rpc-types/src/eth/index.rs index 4ef83b6ceab7..7ee98abcb3cf 100644 --- a/crates/rpc/rpc-types/src/eth/index.rs +++ b/crates/rpc/rpc-types/src/eth/index.rs @@ -22,6 +22,12 @@ impl From for U256 { } } +impl From for Index { + fn from(idx: usize) -> Self { + Index(idx) + } +} + impl Serialize for Index { fn serialize(&self, serializer: S) -> Result where diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index 8bc0a92b3e46..e2d52c560555 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -166,7 +166,7 @@ where None => return Ok(None), }; - Self::build_transaction_receipt(tx, meta, receipt).map(Some) + self.build_transaction_receipt(tx, meta, receipt).await.map(Some) } } @@ -269,14 +269,21 @@ where /// Helper function for `eth_getTransactionReceipt` /// /// Returns the receipt - pub(crate) fn build_transaction_receipt( + pub(crate) async fn build_transaction_receipt( + &self, tx: TransactionSigned, meta: TransactionMeta, - mut receipt: Receipt, + receipt: Receipt, ) -> EthResult { let transaction = tx.clone().into_ecrecovered().ok_or(EthApiError::InvalidTransactionSignature)?; + // get all receipts for the block + let all_receipts = match self.client().receipts_by_block((meta.block_number).into())? { + Some(recpts) => recpts, + None => return Err(EthApiError::UnknownBlockNumber), + }; + let mut res_receipt = TransactionReceipt { transaction_hash: Some(meta.tx_hash), transaction_index: Some(U256::from(meta.index)), @@ -285,9 +292,9 @@ where from: transaction.signer(), to: None, cumulative_gas_used: U256::from(receipt.cumulative_gas_used), - gas_used: Some(U256::from(0)), + gas_used: None, contract_address: None, - logs: std::mem::take(&mut receipt.logs).into_iter().map(Log::from_primitive).collect(), + logs: vec![], effective_gas_price: U128::from(0), transaction_type: U256::from(0), // TODO: set state root after the block @@ -296,6 +303,18 @@ where status_code: if receipt.success { Some(U64::from(1)) } else { Some(U64::from(0)) }, }; + // get the previous transaction cumulative gas used + let gas_used = if meta.index == 0 { + receipt.cumulative_gas_used + } else { + let prev_tx_idx = (meta.index - 1) as usize; + all_receipts + .get(prev_tx_idx) + .map(|prev_receipt| receipt.cumulative_gas_used - prev_receipt.cumulative_gas_used) + .unwrap_or_default() + }; + res_receipt.gas_used = Some(U256::from(gas_used)); + match tx.transaction.kind() { Create => { // set contract address if creation was successful @@ -310,31 +329,47 @@ where } match tx.transaction { - PrimitiveTransaction::Legacy(TxLegacy { gas_limit, gas_price, .. }) => { - // TODO: set actual gas used - res_receipt.gas_used = Some(U256::from(gas_limit)); + PrimitiveTransaction::Legacy(TxLegacy { gas_price, .. }) => { res_receipt.transaction_type = U256::from(0); res_receipt.effective_gas_price = U128::from(gas_price); } - PrimitiveTransaction::Eip2930(TxEip2930 { gas_limit, gas_price, .. }) => { - // TODO: set actual gas used - res_receipt.gas_used = Some(U256::from(gas_limit)); + PrimitiveTransaction::Eip2930(TxEip2930 { gas_price, .. }) => { res_receipt.transaction_type = U256::from(1); res_receipt.effective_gas_price = U128::from(gas_price); } PrimitiveTransaction::Eip1559(TxEip1559 { - gas_limit, max_fee_per_gas, max_priority_fee_per_gas, .. }) => { - // TODO: set actual gas used - res_receipt.gas_used = Some(U256::from(gas_limit)); res_receipt.transaction_type = U256::from(2); res_receipt.effective_gas_price = U128::from(max_fee_per_gas + max_priority_fee_per_gas) } } + + // get number of logs in the block + let mut num_logs = 0; + for prev_receipt in all_receipts.iter().take(meta.index as usize) { + num_logs += prev_receipt.logs.len(); + } + + for (tx_log_idx, log) in receipt.logs.into_iter().enumerate() { + let rpclog = Log { + address: log.address, + topics: log.topics, + data: log.data, + block_hash: Some(meta.block_hash), + block_number: Some(U256::from(meta.block_number)), + transaction_hash: Some(meta.tx_hash), + transaction_index: Some(U256::from(meta.index)), + transaction_log_index: Some(U256::from(tx_log_idx)), + log_index: Some(U256::from(num_logs + tx_log_idx)), + removed: false, + }; + res_receipt.logs.push(rpclog); + } + Ok(res_receipt) } } diff --git a/crates/rpc/rpc/src/eth/error.rs b/crates/rpc/rpc/src/eth/error.rs index 52164596cf3d..c1a81d749738 100644 --- a/crates/rpc/rpc/src/eth/error.rs +++ b/crates/rpc/rpc/src/eth/error.rs @@ -25,6 +25,8 @@ pub enum EthApiError { PoolError(RpcPoolError), #[error("Unknown block number")] UnknownBlockNumber, + #[error("Unknown block or tx index")] + UnknownBlockOrTxIndex, #[error("Invalid block range")] InvalidBlockRange, /// An internal error where prevrandao is not set in the evm's environment @@ -77,7 +79,7 @@ impl From for RpcError { EthApiError::InvalidBlockData(_) | EthApiError::Internal(_) | EthApiError::TransactionNotFound => internal_rpc_err(error.to_string()), - EthApiError::UnknownBlockNumber => { + EthApiError::UnknownBlockNumber | EthApiError::UnknownBlockOrTxIndex => { rpc_error_with_code(EthRpcErrorCode::ResourceNotFound.code(), error.to_string()) } EthApiError::Unsupported(msg) => internal_rpc_err(msg),