From 94f1adfa7c5d15c39d21fa3e8af6e8d8abb5f63f Mon Sep 17 00:00:00 2001 From: Delweng Date: Tue, 9 Jul 2024 04:39:50 +0800 Subject: [PATCH] feat(rpc/ots): implement ots_getContractCreator (#9236) Signed-off-by: jsvisa Co-authored-by: Alexey Shekhirin Co-authored-by: Matthias Seitz --- crates/rpc/rpc-builder/tests/it/http.rs | 4 +- crates/rpc/rpc/src/otterscan.rs | 81 +++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 9 deletions(-) diff --git a/crates/rpc/rpc-builder/tests/it/http.rs b/crates/rpc/rpc-builder/tests/it/http.rs index fd4a2b1db2..968280296b 100644 --- a/crates/rpc/rpc-builder/tests/it/http.rs +++ b/crates/rpc/rpc-builder/tests/it/http.rs @@ -342,9 +342,7 @@ where .err() .unwrap() )); - assert!(is_unimplemented( - OtterscanClient::get_contract_creator(client, address).await.err().unwrap() - )); + assert!(OtterscanClient::get_contract_creator(client, address).await.unwrap().is_none()); } #[tokio::test(flavor = "multi_thread")] diff --git a/crates/rpc/rpc/src/otterscan.rs b/crates/rpc/rpc/src/otterscan.rs index 7a445a7aa2..214315f8aa 100644 --- a/crates/rpc/rpc/src/otterscan.rs +++ b/crates/rpc/rpc/src/otterscan.rs @@ -4,15 +4,22 @@ use jsonrpsee::core::RpcResult; use reth_primitives::{Address, BlockId, BlockNumberOrTag, TxHash, B256}; use reth_rpc_api::{EthApiServer, OtterscanServer}; use reth_rpc_eth_api::helpers::TraceExt; +use reth_rpc_eth_types::EthApiError; use reth_rpc_server_types::result::internal_rpc_err; use reth_rpc_types::{ - trace::otterscan::{ - BlockDetails, ContractCreator, InternalOperation, OperationType, OtsBlockTransactions, - OtsReceipt, OtsTransactionReceipt, TraceEntry, TransactionsWithReceipts, + trace::{ + otterscan::{ + BlockDetails, ContractCreator, InternalOperation, OperationType, OtsBlockTransactions, + OtsReceipt, OtsTransactionReceipt, TraceEntry, TransactionsWithReceipts, + }, + parity::{Action, CreateAction, CreateOutput, TraceOutput}, }, BlockTransactions, Header, Transaction, }; -use revm_inspectors::transfer::{TransferInspector, TransferKind}; +use revm_inspectors::{ + tracing::TracingInspectorConfig, + transfer::{TransferInspector, TransferKind}, +}; use revm_primitives::ExecutionResult; const API_LEVEL: u64 = 8; @@ -208,7 +215,69 @@ where } /// Handler for `getContractCreator` - async fn get_contract_creator(&self, _address: Address) -> RpcResult> { - Err(internal_rpc_err("unimplemented")) + async fn get_contract_creator(&self, address: Address) -> RpcResult> { + if !self.has_code(address, None).await? { + return Ok(None); + } + + // use binary search from block [1, latest block number] to find the first block where the + // contract was deployed + let mut low = 1; + let mut high = self.eth.block_number()?.saturating_to::(); + let mut num = high; + + while low <= high { + let mid = (low + high) / 2; + if self.eth.get_code(address, Some(mid.into())).await?.is_empty() { + // not found in current block, need to search in the later blocks + low = mid + 1; + } else { + // found in current block, try to find a lower block + high = mid - 1; + num = mid; + } + } + + let traces = self + .eth + .trace_block_with( + num.into(), + TracingInspectorConfig::default_parity(), + |tx_info, inspector, _, _, _| { + Ok(inspector.into_parity_builder().into_localized_transaction_traces(tx_info)) + }, + ) + .await? + .map(|traces| { + traces + .into_iter() + .flatten() + .map(|tx_trace| { + let trace = tx_trace.trace; + Ok(match (trace.action, trace.result, trace.error) { + ( + Action::Create(CreateAction { from: creator, .. }), + Some(TraceOutput::Create(CreateOutput { + address: contract, .. + })), + None, + ) if contract == address => Some(ContractCreator { + hash: tx_trace + .transaction_hash + .ok_or_else(|| EthApiError::TransactionNotFound)?, + creator, + }), + _ => None, + }) + }) + .filter_map(Result::transpose) + .collect::, EthApiError>>() + }) + .transpose()?; + + // A contract maybe created and then destroyed in multiple transactions, here we + // return the first found transaction, this behavior is consistent with etherscan's + let found = traces.and_then(|traces| traces.first().cloned()); + Ok(found) } }