feat(rpc): implement debug_dbGet (#19369)

This commit is contained in:
Mablr
2025-10-29 16:45:58 +01:00
committed by GitHub
parent 30942597db
commit 66cfa9ed1a
3 changed files with 78 additions and 4 deletions

View File

@@ -222,7 +222,7 @@ pub trait DebugApi<TxReq: RpcObject> {
/// Returns the raw value of a key stored in the database.
#[method(name = "dbGet")]
async fn debug_db_get(&self, key: String) -> RpcResult<()>;
async fn debug_db_get(&self, key: String) -> RpcResult<Option<Bytes>>;
/// Retrieves the state that corresponds to the block number and returns a list of accounts
/// (including storage and code).

View File

@@ -1694,3 +1694,47 @@ async fn test_eth_fee_history_raw() {
)
.await;
}
#[tokio::test(flavor = "multi_thread")]
async fn test_debug_db_get() {
reth_tracing::init_test_tracing();
let handle = launch_http(vec![RethRpcModule::Debug]).await;
let client = handle.http_client().unwrap();
let valid_test_cases = [
"0x630000000000000000000000000000000000000000000000000000000000000000",
"c00000000000000000000000000000000",
];
for key in valid_test_cases {
DebugApiClient::<()>::debug_db_get(&client, key.into()).await.unwrap();
}
// Invalid test cases
let test_cases = [
("0x0000", "Key must be 33 bytes, got 2"),
("00", "Key must be 33 bytes, got 2"),
(
"0x000000000000000000000000000000000000000000000000000000000000000000",
"Key prefix must be 0x63",
),
("000000000000000000000000000000000", "Key prefix must be 0x63"),
("0xc0000000000000000000000000000000000000000000000000000000000000000", "Invalid hex key"),
];
let match_error_msg = |err: jsonrpsee::core::client::Error, expected: String| -> bool {
match err {
jsonrpsee::core::client::Error::Call(error_obj) => {
error_obj.code() == ErrorCode::InvalidParams.code() &&
error_obj.message() == expected
}
_ => false,
}
};
for (key, expected) in test_cases {
let err = DebugApiClient::<()>::debug_db_get(&client, key.into()).await.unwrap_err();
assert!(match_error_msg(err, expected.into()));
}
}

View File

@@ -5,7 +5,7 @@ use alloy_consensus::{
use alloy_eips::{eip2718::Encodable2718, BlockId, BlockNumberOrTag};
use alloy_evm::env::BlockEnvironment;
use alloy_genesis::ChainConfig;
use alloy_primitives::{uint, Address, Bytes, B256};
use alloy_primitives::{hex::decode, uint, Address, Bytes, B256};
use alloy_rlp::{Decodable, Encodable};
use alloy_rpc_types_debug::ExecutionWitness;
use alloy_rpc_types_eth::{
@@ -1143,8 +1143,38 @@ where
Ok(())
}
async fn debug_db_get(&self, _key: String) -> RpcResult<()> {
Ok(())
/// `debug_db_get` - database key lookup
///
/// Currently supported:
/// * Contract bytecode associated with a code hash. The key format is: `<0x63><code_hash>`
/// * Prefix byte: 0x63 (required)
/// * Code hash: 32 bytes
/// Must be provided as either:
/// * Hex string: "0x63..." (66 hex characters after 0x)
/// * Raw byte string: raw byte string (33 bytes)
/// See Geth impl: <https://github.com/ethereum/go-ethereum/blob/737ffd1bf0cbee378d0111a5b17ae4724fb2216c/core/rawdb/schema.go#L120>
async fn debug_db_get(&self, key: String) -> RpcResult<Option<Bytes>> {
let key_bytes = if key.starts_with("0x") {
decode(&key).map_err(|_| EthApiError::InvalidParams("Invalid hex key".to_string()))?
} else {
key.into_bytes()
};
if key_bytes.len() != 33 {
return Err(EthApiError::InvalidParams(format!(
"Key must be 33 bytes, got {}",
key_bytes.len()
))
.into());
}
if key_bytes[0] != 0x63 {
return Err(EthApiError::InvalidParams("Key prefix must be 0x63".to_string()).into());
}
let code_hash = B256::from_slice(&key_bytes[1..33]);
// No block ID is provided, so it defaults to the latest block
self.debug_code_by_hash(code_hash, None).await.map_err(Into::into)
}
async fn debug_dump_block(&self, _number: BlockId) -> RpcResult<()> {