Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rpc): implement Filecoin.EthGetStorageAt #4340

Merged
merged 7 commits into from
Jun 5, 2024
Merged

Conversation

hanabi1224
Copy link
Contributor

@hanabi1224 hanabi1224 commented May 17, 2024

Summary of changes

Changes introduced in this pull request:

  • Implement RPC method implement Filecoin.EthGetStorageAt
  • API compare tests
     Running `target/quick/forest-tool api compare /home/me/fr/snapshots/calibnet/forest_snapshot_calibnet_2024-05-17_height_1620369.forest.car.zst --filter EthGetStorageAt`
| RPC Method                    | Forest | Lotus |
|-------------------------------|--------|-------|
| Filecoin.EthGetStorageAt (10) | Valid  | Valid |

Reference issue to close (if applicable)

Closes #4341

Other information and links

Change checklist

  • I have performed a self-review of my own code,
  • I have made corresponding changes to the documentation,
  • I have added tests that prove my fix is effective or that my feature works (if possible),
  • I have made sure the CHANGELOG is up-to-date. All user-facing changes should be reflected in this document.

@hanabi1224 hanabi1224 marked this pull request as ready for review May 17, 2024 09:34
@hanabi1224 hanabi1224 requested a review from a team as a code owner May 17, 2024 09:34
@hanabi1224 hanabi1224 requested review from lemmih and sudo-shashank and removed request for a team May 17, 2024 09:34
params,
..Default::default()
};
let mut api_invoc_result = None;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could be done withoutmut.

let api_invoice_result = {
  for ts in ... {
     match {
     Ok(res) -> return Some(res)
  }
  None
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return clause works for the function instead of the scope unless the scope is converted to a lambda. I was thinking about break Some(res); syntax just like in some other languages but it does not work in rust.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to avoid mut here, you still could use labelled blocks, e.g.:

let api_invoc_result = 'block: {
    for ts in ts.chain_arc(ctx.store()) {
        match ctx.state_manager.call(&message, Some(ts)) {
            Ok(res) => {
                break 'block res;
            }
            Err(e) => tracing::warn!(%e),
        }
    }
    return Err(anyhow::anyhow!("Call failed").into());
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elmattic Didn't know about this. This is great, thanks!

let mut with_padding = vec![0; 32_usize.saturating_sub(ret.len())];
with_padding.append(&mut ret);
Ok(EthBytes(with_padding))
} else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: return early on if, then there is no need for else.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I feel using early returns here is not Rustic given rust is expression-based

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it boils down to personal preference, however if .. else nesting here does not read very well.
Imagine if every if in this method would have an else. Non-blocking.

Err(e) => tracing::warn!(%e),
}
}
let Some(api_invoc_result) = api_invoc_result else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this more I'm thinking: why do we need Option for api_invoc_result? It would be much easier to use Result. Then there is no need for let Some..

Something like:

  for ... {
    match {
       Ok(res) -> return Ok(res)
    } 
  }
  return Err(err)

  and then just do `api_invoc_result?`
  

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the return clause works this way. #4340 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

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() {
Copy link
Contributor

@ruseinov ruseinov May 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It it actually possible for !api_invoc_result.error.is_empty when msg_rct is Some?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logically yes, in practice, I'm not sure. I think it does not hurt to check both and make the logic look more robust

let mut ret = fvm_ipld_encoding::from_slice::<RawBytes>(msg_rct.return_data().as_slice())?
.bytes()
.to_vec();
if ret.len() < 32 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you mean to pad on an EVM word boundary, you can use the EVM_WORD_LENGTH constant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
(eth_address, position, block_number_or_hash): Self::Params,
) -> Result<Self::Ok, ServerError> {
let make_empty_result = || EthBytes(vec![0; 32]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you mean to return a zeroed EVM word, you could use the EVM_WORD_LENGTH constant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@ruseinov ruseinov self-requested a review June 5, 2024 10:31
for ts in ts.chain_arc(ctx.store()) {
match ctx.state_manager.call(&message, Some(ts)) {
Ok(res) => {
break 'invoc res;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The loop label here is unnecessary. Non-blocking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate? I can compile the code without the loop label

error[E0571]: `break` with value from a `for` loop
    --> src/rpc/methods/eth.rs:1298:25
     |
1295 |             for ts in ts.chain_arc(ctx.store()) {
     |             ----------------------------------- you can't `break` with a value in a `for` loop
...
1298 |                         break res;
     |                         ^^^^^^^^^ can only break with a value inside `loop` or breakable block
     |
help: use `break` on its own without a value inside this `for` loop
     |
1298 |                         break;
     |                         ~~~~~

@hanabi1224 hanabi1224 added this pull request to the merge queue Jun 5, 2024
Merged via the queue into main with commit 333b78a Jun 5, 2024
27 checks passed
@hanabi1224 hanabi1224 deleted the hm/EthGetStorageAt branch June 5, 2024 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Filecoin.EthGetStorageAt
4 participants