Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@

- [#6489](https://github.com/ChainSafe/forest/pull/6489): Implemented `Filecoin.EthGetBlockReceipts` for API v2.

- [#6490](https://github.com/ChainSafe/forest/pull/6490): Implemented `Filecoin.EthGetCode` for API v2.

### Changed

- [#6471](https://github.com/ChainSafe/forest/pull/6471): Moved `forest-tool state` subcommand to `forest-dev`.
Expand Down
118 changes: 78 additions & 40 deletions src/rpc/methods/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2396,6 +2396,9 @@ impl RpcMethod<2> for EthGetCode {
const PARAM_NAMES: [&'static str; 2] = ["ethAddress", "blockNumberOrHash"];
const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
const PERMISSION: Permission = Permission::Read;
const DESCRIPTION: Option<&'static str> = Some(
"Retrieves the contract code at a specific address and block state, identified by its number, hash, or a special tag.",
);

type Params = (EthAddress, BlockNumberOrHash);
type Ok = EthBytes;
Expand All @@ -2409,53 +2412,88 @@ impl RpcMethod<2> for EthGetCode {
block_param,
ResolveNullTipset::TakeOlder,
)?;
let to_address = FilecoinAddress::try_from(&eth_address)?;
let actor = ctx
.state_manager
.get_required_actor(&to_address, *ts.parent_state())?;
// Not a contract. We could try to distinguish between accounts and "native" contracts here,
// but it's not worth it.
if !is_evm_actor(&actor.code) {
return Ok(Default::default());
}
eth_get_code(&ctx, &ts, &eth_address).await
}
}

let message = Message {
from: FilecoinAddress::SYSTEM_ACTOR,
to: to_address,
method_num: METHOD_GET_BYTE_CODE,
gas_limit: BLOCK_GAS_LIMIT,
..Default::default()
};
pub enum EthGetCodeV2 {}
impl RpcMethod<2> for EthGetCodeV2 {
const NAME: &'static str = "Filecoin.EthGetCode";
const NAME_ALIAS: Option<&'static str> = Some("eth_getCode");
const PARAM_NAMES: [&'static str; 2] = ["ethAddress", "blockNumberOrHash"];
const API_PATHS: BitFlags<ApiPaths> = make_bitflags!(ApiPaths::V2);
const PERMISSION: Permission = Permission::Read;
const DESCRIPTION: Option<&'static str> = Some(
"Retrieves the contract code at a specific address and block state, identified by its number, hash, or a special tag.",
);

let (state, _) = ctx
.state_manager
.tipset_state(&ts, StateLookupPolicy::Enabled)
type Params = (EthAddress, ExtBlockNumberOrHash);
type Ok = EthBytes;

async fn handle(
ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
(eth_address, block_param): Self::Params,
) -> Result<Self::Ok, ServerError> {
let ts = tipset_by_block_number_or_hash_v2(&ctx, block_param, ResolveNullTipset::TakeOlder)
.await?;
let api_invoc_result = 'invoc: {
for ts in ts.chain(ctx.store()) {
match ctx.state_manager.call_on_state(state, &message, Some(ts)) {
Ok(res) => {
break 'invoc res;
}
Err(e) => tracing::warn!(%e),
eth_get_code(&ctx, &ts, &eth_address).await
}
}

async fn eth_get_code<DB>(
ctx: &Ctx<DB>,
ts: &Tipset,
eth_address: &EthAddress,
) -> Result<EthBytes, ServerError>
where
DB: Blockstore + Send + Sync + 'static,
{
let to_address = FilecoinAddress::try_from(eth_address)?;
let actor = ctx
.state_manager
.get_required_actor(&to_address, *ts.parent_state())?;
// Not a contract. We could try to distinguish between accounts and "native" contracts here,
// but it's not worth it.
if !is_evm_actor(&actor.code) {
return Ok(Default::default());
}

let message = Message {
from: FilecoinAddress::SYSTEM_ACTOR,
to: to_address,
method_num: METHOD_GET_BYTE_CODE,
gas_limit: BLOCK_GAS_LIMIT,
..Default::default()
};

let (state, _) = ctx
.state_manager
.tipset_state(ts, StateLookupPolicy::Enabled)
.await?;
Comment thread
sudo-shashank marked this conversation as resolved.
Outdated
let api_invoc_result = 'invoc: {
for ts in ts.clone().chain(ctx.store()) {
match ctx.state_manager.call_on_state(state, &message, Some(ts)) {
Ok(res) => {
break 'invoc res;
}
Err(e) => tracing::warn!(%e),
}
return Err(anyhow::anyhow!("Call failed").into());
};
let Some(msg_rct) = api_invoc_result.msg_rct else {
return Err(anyhow::anyhow!("no message receipt").into());
};
if !api_invoc_result.error.is_empty() {
return Err(anyhow::anyhow!("GetBytecode failed: {}", api_invoc_result.error).into());
}
return Err(anyhow::anyhow!("Call failed").into());
};
let Some(msg_rct) = api_invoc_result.msg_rct else {
return Err(anyhow::anyhow!("no message receipt").into());
};
if !api_invoc_result.error.is_empty() {
return Err(anyhow::anyhow!("GetBytecode failed: {}", api_invoc_result.error).into());
}

let get_bytecode_return: GetBytecodeReturn =
fvm_ipld_encoding::from_slice(msg_rct.return_data().as_slice())?;
if let Some(cid) = get_bytecode_return.0 {
Ok(EthBytes(ctx.store().get_required(&cid)?))
} else {
Ok(Default::default())
}
let get_bytecode_return: GetBytecodeReturn =
fvm_ipld_encoding::from_slice(msg_rct.return_data().as_slice())?;
if let Some(cid) = get_bytecode_return.0 {
Ok(EthBytes(ctx.store().get_required(&cid)?))
} else {
Ok(Default::default())
}
Comment thread
sudo-shashank marked this conversation as resolved.
}

Expand Down
1 change: 1 addition & 0 deletions src/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ macro_rules! for_each_rpc_method {
$callback!($crate::rpc::eth::EthGetBlockTransactionCountByNumber);
$callback!($crate::rpc::eth::EthGetBlockTransactionCountByNumberV2);
$callback!($crate::rpc::eth::EthGetCode);
$callback!($crate::rpc::eth::EthGetCodeV2);
$callback!($crate::rpc::eth::EthGetLogs);
$callback!($crate::rpc::eth::EthGetFilterLogs);
$callback!($crate::rpc::eth::EthGetFilterChanges);
Expand Down
22 changes: 22 additions & 0 deletions src/tool/subcommands/api_cmd/api_compare_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2147,6 +2147,28 @@ fn eth_tests_with_tipset<DB: Blockstore>(store: &Arc<DB>, shared_tipset: &Tipset
))
.unwrap(),
),
RpcTest::identity(
EthGetCodeV2::request((
// https://filfox.info/en/address/f410fpoidg73f7krlfohnla52dotowde5p2sejxnd4mq
EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
ExtBlockNumberOrHash::from_block_number(shared_tipset.epoch()),
))
.unwrap(),
),
RpcTest::basic(
EthGetCodeV2::request((
EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
ExtBlockNumberOrHash::from_predefined(ExtPredefined::Safe),
))
.unwrap(),
),
RpcTest::basic(
EthGetCodeV2::request((
EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
ExtBlockNumberOrHash::from_predefined(ExtPredefined::Finalized),
))
.unwrap(),
),
RpcTest::identity(
EthGetTransactionByBlockNumberAndIndex::request((
BlockNumberOrPredefined::BlockNumber(shared_tipset.epoch().into()),
Expand Down
3 changes: 3 additions & 0 deletions src/tool/subcommands/api_cmd/test_snapshots.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ filecoin_ethgetblocktransactioncountbynumber_v2_1769099953141937.rpcsnap.json.zs
filecoin_ethgetcode_1765803672602510.rpcsnap.json.zst # latest
filecoin_ethgetcode_1765803672604518.rpcsnap.json.zst # concrete
filecoin_ethgetcode_1765803672655291.rpcsnap.json.zst # pending
filecoin_ethgetcode_v2_1769605928230413.rpcsnap.json.zst
filecoin_ethgetcode_v2_finalized_1769605928335700.rpcsnap.json.zst
filecoin_ethgetcode_v2_safe_1769605928230488.rpcsnap.json.zst
filecoin_ethgetlogs_1759922913569082.rpcsnap.json.zst
filecoin_ethgetmessagecidbytransactionhash_1737446676697418.rpcsnap.json.zst
filecoin_ethgetstorageat_1765803742043605.rpcsnap.json.zst # latest
Expand Down
Loading