Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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 @@ -43,6 +43,8 @@

- [#6103](https://github.com/ChainSafe/forest/pull/6103) Fixed `eth_getTransactionCount` to return the nonce of the requested tipset and not its parent.

- [#6118](https://github.com/ChainSafe/forest/pull/6118) Fixed `eth_getCode` and `eth_getStorageAt` so that they return the code and storage of the requested tipset and not its parent.

## Forest v0.30.1 "Laurelin"

Mandatory release for mainnet node operators. It sets the NV27 _Golden Week_ network upgrade to epoch `5_348_280` which corresponds to `Wed 24 Sep 23:00:00 UTC 2025`. It also includes a few improvements that help with snapshot generation and inspection.
Expand Down
11 changes: 5 additions & 6 deletions src/rpc/methods/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2122,9 +2122,10 @@ impl RpcMethod<2> for EthGetCode {
..Default::default()
};

let (state, _) = ctx.state_manager.tipset_state(&ts).await?;
let api_invoc_result = 'invoc: {
for ts in ts.chain_arc(ctx.store()) {
match ctx.state_manager.call(&message, Some(ts)) {
match ctx.state_manager.call_on_state(state, &message, Some(ts)) {
Ok(res) => {
break 'invoc res;
}
Expand Down Expand Up @@ -2173,10 +2174,8 @@ impl RpcMethod<3> for EthGetStorageAt {
ResolveNullTipset::TakeOlder,
)?;
let to_address = FilecoinAddress::try_from(&eth_address)?;
let Some(actor) = ctx
.state_manager
.get_actor(&to_address, *ts.parent_state())?
else {
let (state, _) = ctx.state_manager.tipset_state(&ts).await?;
let Some(actor) = ctx.state_manager.get_actor(&to_address, state)? else {
return Ok(make_empty_result());
};

Expand All @@ -2195,7 +2194,7 @@ impl RpcMethod<3> for EthGetStorageAt {
};
let api_invoc_result = 'invoc: {
for ts in ts.chain_arc(ctx.store()) {
match ctx.state_manager.call(&message, Some(ts)) {
match ctx.state_manager.call_on_state(state, &message, Some(ts)) {
Ok(res) => {
break 'invoc res;
}
Expand Down
22 changes: 18 additions & 4 deletions src/state_manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,13 +521,14 @@ where
#[instrument(skip(self, rand))]
fn call_raw(
self: &Arc<Self>,
state_cid: Option<Cid>,
msg: &Message,
rand: ChainRand<DB>,
tipset: &Arc<Tipset>,
) -> Result<ApiInvocResult, Error> {
let mut msg = msg.clone();

let state_cid = tipset.parent_state();
let state_cid = state_cid.unwrap_or(*tipset.parent_state());

let tipset_messages = self
.chain_store()
Expand All @@ -545,14 +546,14 @@ where
let mut vm = VM::new(
ExecutionContext {
heaviest_tipset: Arc::clone(tipset),
state_tree_root: *state_cid,
state_tree_root: state_cid,
epoch: height,
rand: Box::new(rand),
base_fee: tipset.block_headers().first().parent_base_fee.clone(),
circ_supply: genesis_info.get_vm_circulating_supply(
height,
&self.blockstore_owned(),
state_cid,
&state_cid,
)?,
chain_config: self.chain_config().clone(),
chain_index: self.chain_index().clone(),
Expand Down Expand Up @@ -603,7 +604,20 @@ where
) -> Result<ApiInvocResult, Error> {
let ts = tipset.unwrap_or_else(|| self.cs.heaviest_tipset());
let chain_rand = self.chain_rand(Arc::clone(&ts));
self.call_raw(message, chain_rand, &ts)
self.call_raw(None, message, chain_rand, &ts)
}

/// Same as [`StateManager::call`] but runs the message on the given state and not
/// on the parent state of the tipset.
pub fn call_on_state(
self: &Arc<Self>,
state_cid: Cid,
message: &Message,
tipset: Option<Arc<Tipset>>,
) -> Result<ApiInvocResult, Error> {
let ts = tipset.unwrap_or_else(|| self.cs.heaviest_tipset());
let chain_rand = self.chain_rand(Arc::clone(&ts));
self.call_raw(Some(state_cid), message, chain_rand, &ts)
}

pub async fn apply_on_state_with_gas(
Expand Down
Loading