Skip to content
Merged
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
71 changes: 50 additions & 21 deletions src/rpc/methods/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ use crate::state_manager::{ExecutedMessage, ExecutedTipset, StateManager, Tipset
use crate::utils::cache::SizeTrackingCache;
use crate::utils::db::BlockstoreExt as _;
use crate::utils::encoding::from_slice_with_fallback;
use crate::utils::get_size::big_int_heap_size_helper;
use crate::utils::misc::env::env_or_default;
use crate::utils::multihash::prelude::*;
use ahash::{HashMap, HashSet};
Expand All @@ -69,7 +68,7 @@ use fvm_ipld_encoding::{CBOR, DAG_CBOR, IPLD_RAW, RawBytes};
use get_size2::GetSize;
use ipld_core::ipld::Ipld;
use nonzero_ext::nonzero;
use num::{BigInt, Zero as _};
use num::BigInt;
use nunny::Vec as NonEmpty;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -114,8 +113,6 @@ const EMPTY_ROOT: &str = "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc00162
/// The address used in messages to actors that have since been deleted.
const REVERTED_ETH_ADDRESS: &str = "0xff0000000000000000000000ffffffffffffffff";

// TODO(forest): https://github.com/ChainSafe/forest/issues/4436
// use ethereum_types::U256 or use lotus_json::big_int
#[derive(
Eq,
Hash,
Expand All @@ -125,20 +122,39 @@ const REVERTED_ETH_ADDRESS: &str = "0xff0000000000000000000000ffffffffffffffff";
Serialize,
Default,
Clone,
Copy,
JsonSchema,
GetSize,
derive_more::From,
derive_more::Into,
derive_more::Deref,
)]
pub struct EthBigInt(
#[serde(with = "crate::lotus_json::hexify")]
// `ethereum_types::U256` serializes as a `0x`-prefixed, leading-zero-trimmed hex string,
// which matches the Ethereum JSON-RPC wire format used by Lotus.
#[schemars(with = "String")]
pub BigInt,
#[get_size(ignore)]
ethereum_types::U256,
);
lotus_json_with_self!(EthBigInt);

impl GetSize for EthBigInt {
fn get_heap_size_with_tracker<T: get_size2::GetSizeTracker>(&self, tracker: T) -> (usize, T) {
(big_int_heap_size_helper(&self.0), tracker)
impl From<BigInt> for EthBigInt {
fn from(value: BigInt) -> Self {
(&value).into()
}
}

impl From<&BigInt> for EthBigInt {
fn from(value: &BigInt) -> Self {
// Eth values are non-negative, so the sign is dropped.
let (_sign, bytes) = value.to_bytes_be();
Self(ethereum_types::U256::from_big_endian(&bytes))
}
}

impl From<u64> for EthBigInt {
fn from(value: u64) -> Self {
Self(value.into())
}
}

Expand All @@ -150,7 +166,20 @@ impl From<TokenAmount> for EthBigInt {

impl From<&TokenAmount> for EthBigInt {
fn from(amount: &TokenAmount) -> Self {
Self(amount.atto().to_owned())
amount.atto().into()
}
}

impl From<EthBigInt> for BigInt {
fn from(value: EthBigInt) -> Self {
// Eth values are non-negative, so the sign is always positive.
BigInt::from_bytes_be(num_bigint::Sign::Plus, &value.to_big_endian())
}
}

impl From<EthBigInt> for TokenAmount {
fn from(value: EthBigInt) -> Self {
TokenAmount::from_atto(value)
}
}

Expand Down Expand Up @@ -860,7 +889,7 @@ impl RpcMethod<0> for EthBaseFee {
_: &http::Extensions,
) -> Result<Self::Ok, ServerError> {
let base_fee = Self::get_base_fee(&ctx, &ctx.chain_store().heaviest_tipset())?;
Ok(EthBigInt(base_fee.atto().clone()))
Ok(base_fee.atto().into())
}
}

Expand Down Expand Up @@ -889,7 +918,7 @@ impl RpcMethod<1> for BaseFeeByHeight {
ResolveNullTipset::TakeOlder,
)?;
let base_fee = EthBaseFee::get_base_fee(&ctx, &ts)?;
Ok(EthBigInt(base_fee.atto().clone()))
Ok(base_fee.atto().into())
}
}

Expand Down Expand Up @@ -979,7 +1008,7 @@ impl RpcMethod<0> for EthGasPrice {
.await
.map(|gas_premium| gas_premium.atto().to_owned())
.unwrap_or_default();
Ok(EthBigInt(base_fee + tip))
Ok((base_fee + tip).into())
}
}

Expand Down Expand Up @@ -1015,7 +1044,7 @@ async fn eth_get_balance(ctx: &Ctx, address: &EthAddress, ts: &Tipset) -> Result
let TipsetState { state_root, .. } = ctx.state_manager.load_tipset_state(ts).await?;
let state_tree = ctx.state_manager.get_state_tree(&state_root)?;
match state_tree.get_actor(&fil_addr)? {
Some(actor) => Ok(EthBigInt(actor.balance.atto().clone())),
Some(actor) => Ok(actor.balance.atto().into()),
None => Ok(EthBigInt::default()), // Balance is 0 if the actor doesn't exist
}
}
Expand Down Expand Up @@ -1343,8 +1372,8 @@ async fn new_eth_tx_receipt(
msg_receipt.gas_used(),
tx.gas.into(),
&tipset.block_headers().first().parent_base_fee,
&gas_fee_cap.0.into(),
&gas_premium.0.into(),
&gas_fee_cap.into(),
&gas_premium.into(),
);
let total_spent: BigInt = gas_outputs.total_spent().into();

Expand Down Expand Up @@ -2105,7 +2134,7 @@ fn calculate_rewards_and_gas_used(
let gas_used_total = tx_gas_rewards.iter().map(|i| i.gas_used).sum();
let mut rewards = reward_percentiles
.iter()
.map(|_| EthBigInt(MIN_GAS_PREMIUM.into()))
.map(|_| EthBigInt::from(MIN_GAS_PREMIUM))
.collect_vec();
if !tx_gas_rewards.is_empty() {
tx_gas_rewards.sort_by(|a, b| a.premium.cmp(&b.premium));
Expand Down Expand Up @@ -2381,8 +2410,8 @@ impl RpcMethod<0> for EthMaxPriorityFeePerGas {
_: &http::Extensions,
) -> Result<Self::Ok, ServerError> {
match gas::estimate_gas_premium(&ctx, 0, &ApiTipsetKey(None)).await {
Ok(gas_premium) => Ok(EthBigInt(gas_premium.atto().clone())),
Err(_) => Ok(EthBigInt(num_bigint::BigInt::zero())),
Ok(gas_premium) => Ok(gas_premium.atto().into()),
Err(_) => Ok(EthBigInt::default()),
}
}
}
Expand Down Expand Up @@ -4102,11 +4131,11 @@ mod test {

#[quickcheck]
fn gas_price_result_serde_roundtrip(i: u128) {
let r = EthBigInt(i.into());
let r = EthBigInt(ethereum_types::U256::from(i));
let encoded = serde_json::to_string(&r).unwrap();
assert_eq!(encoded, format!("\"{i:#x}\""));
let decoded: EthBigInt = serde_json::from_str(&encoded).unwrap();
assert_eq!(r.0, decoded.0);
assert_eq!(r, decoded);
}

/// `transactionPosition` must be 0-indexed and system-actor messages must
Expand Down
19 changes: 9 additions & 10 deletions src/rpc/methods/eth/trace/geth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ fn build_account_snapshot_from_entries<DB: Blockstore>(
};

Ok(Some(super::types::AccountState {
balance: Some(EthBigInt(actor.balance.atto().clone())),
balance: Some(EthBigInt::from(actor.balance.atto())),
code,
nonce,
storage,
Expand Down Expand Up @@ -267,7 +267,6 @@ mod tests {
use super::super::types::{PreStateConfig, PreStateFrame};
use super::*;
use crate::rpc::eth::{EthBigInt, EthUint64};
use num::BigInt;

#[test]
fn test_build_prestate_frame_default_mode_empty() {
Expand Down Expand Up @@ -318,7 +317,7 @@ mod tests {
assert_eq!(mode.0.len(), 1);
let snap = mode.0.get(&actor_addr).unwrap();
// Default mode returns pre-state
assert_eq!(snap.balance, Some(EthBigInt(BigInt::from(1000))));
assert_eq!(snap.balance, Some(EthBigInt::from(1000)));
assert_eq!(snap.nonce, Some(EthUint64(5)));
}
_ => panic!("Expected Default mode"),
Expand Down Expand Up @@ -354,12 +353,12 @@ mod tests {

// Pre should contain the original state
let pre_snap = diff.pre.get(&addr).unwrap();
assert_eq!(pre_snap.balance, Some(EthBigInt(BigInt::from(1000))));
assert_eq!(pre_snap.balance, Some(EthBigInt::from(1000)));
assert_eq!(pre_snap.nonce, Some(EthUint64(5)));

// Post should only contain changed fields
let post_snap = diff.post.get(&addr).unwrap();
assert_eq!(post_snap.balance, Some(EthBigInt(BigInt::from(2000))));
assert_eq!(post_snap.balance, Some(EthBigInt::from(2000)));
assert_eq!(post_snap.nonce, Some(EthUint64(6)));
}
_ => panic!("Expected Diff mode"),
Expand Down Expand Up @@ -427,7 +426,7 @@ mod tests {
// Created accounts should only appear in post
assert!(!diff.pre.contains_key(&addr));
let post_snap = diff.post.get(&addr).unwrap();
assert_eq!(post_snap.balance, Some(EthBigInt(BigInt::from(5000))));
assert_eq!(post_snap.balance, Some(EthBigInt::from(5000)));
assert_eq!(post_snap.nonce, Some(EthUint64(0)));
}
_ => panic!("Expected Diff mode"),
Expand Down Expand Up @@ -461,7 +460,7 @@ mod tests {
let addr = create_masked_id_eth_address(actor_id);
// Deleted accounts should only appear in pre
let pre_snap = diff.pre.get(&addr).unwrap();
assert_eq!(pre_snap.balance, Some(EthBigInt(BigInt::from(3000))));
assert_eq!(pre_snap.balance, Some(EthBigInt::from(3000)));
assert_eq!(pre_snap.nonce, Some(EthUint64(10)));
assert!(!diff.post.contains_key(&addr));
}
Expand Down Expand Up @@ -499,10 +498,10 @@ mod tests {
let pre_snap = diff.pre.get(&addr).unwrap();
let post_snap = diff.post.get(&addr).unwrap();
// Balance/nonce reflect actual values, storage skipped
assert_eq!(pre_snap.balance, Some(EthBigInt(BigInt::from(1000))));
assert_eq!(pre_snap.balance, Some(EthBigInt::from(1000)));
assert_eq!(pre_snap.nonce, Some(EthUint64(5)));
assert!(pre_snap.storage.is_empty());
assert_eq!(post_snap.balance, Some(EthBigInt(BigInt::from(2000))));
assert_eq!(post_snap.balance, Some(EthBigInt::from(2000)));
assert_eq!(post_snap.nonce, Some(EthUint64(6)));
assert!(post_snap.storage.is_empty());
}
Expand Down Expand Up @@ -538,7 +537,7 @@ mod tests {
PreStateFrame::Default(mode) => {
assert_eq!(mode.0.len(), 1);
let snap = mode.0.get(&actor_addr).unwrap();
assert_eq!(snap.balance, Some(EthBigInt(BigInt::from(1000))));
assert_eq!(snap.balance, Some(EthBigInt::from(1000)));
assert_eq!(snap.nonce, Some(EthUint64(5)));
assert!(snap.storage.is_empty());
}
Expand Down
33 changes: 16 additions & 17 deletions src/rpc/methods/eth/trace/state_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ fn build_account_diff<DB: Blockstore>(
let mut diff = AccountDiff::default();

// Compare balance
let pre_balance = pre_actor.map(|a| EthBigInt(a.balance.atto().clone()));
let post_balance = post_actor.map(|a| EthBigInt(a.balance.atto().clone()));
let pre_balance = pre_actor.map(|a| EthBigInt::from(a.balance.atto()));
let post_balance = post_actor.map(|a| EthBigInt::from(a.balance.atto()));
diff.balance = Delta::from_comparison(pre_balance, post_balance);

// Compare nonce
Expand Down Expand Up @@ -277,7 +277,6 @@ mod tests {
use crate::rpc::eth::types::EthBytes;
use crate::shim::address::Address as FilecoinAddress;
use crate::shim::state_tree::StateTreeVersion;
use num::BigInt;

#[test]
fn test_build_state_diff_empty_touched_addresses() {
Expand Down Expand Up @@ -319,8 +318,8 @@ mod tests {
let diff = state_diff.0.get(&eth_addr).unwrap();
match &diff.balance {
Delta::Changed(change) => {
assert_eq!(change.from.0, BigInt::from(1000));
assert_eq!(change.to.0, BigInt::from(2000));
assert_eq!(change.from, EthBigInt::from(1000));
assert_eq!(change.to, EthBigInt::from(2000));
}
_ => panic!("Expected Delta::Changed for balance"),
}
Expand All @@ -343,8 +342,8 @@ mod tests {
let diff = state_diff.0.get(&eth_addr).unwrap();
match &diff.balance {
Delta::Changed(change) => {
assert_eq!(change.from.0, BigInt::from(5000));
assert_eq!(change.to.0, BigInt::from(3000));
assert_eq!(change.from, EthBigInt::from(5000));
assert_eq!(change.to, EthBigInt::from(3000));
}
_ => panic!("Expected Delta::Changed for balance"),
}
Expand Down Expand Up @@ -391,8 +390,8 @@ mod tests {
let diff = state_diff.0.get(&eth_addr).unwrap();
match &diff.balance {
Delta::Changed(change) => {
assert_eq!(change.from.0, BigInt::from(10000));
assert_eq!(change.to.0, BigInt::from(9000));
assert_eq!(change.from, EthBigInt::from(10000));
assert_eq!(change.to, EthBigInt::from(9000));
}
_ => panic!("Expected Delta::Changed for balance"),
}
Expand Down Expand Up @@ -420,7 +419,7 @@ mod tests {
let diff = state_diff.0.get(&eth_addr).unwrap();
match &diff.balance {
Delta::Added(balance) => {
assert_eq!(balance.0, BigInt::from(5000));
assert_eq!(balance, &EthBigInt::from(5000));
}
_ => panic!("Expected Delta::Added for balance"),
}
Expand All @@ -447,7 +446,7 @@ mod tests {
let diff = state_diff.0.get(&eth_addr).unwrap();
match &diff.balance {
Delta::Removed(balance) => {
assert_eq!(balance.0, BigInt::from(3000));
assert_eq!(balance, &EthBigInt::from(3000));
}
_ => panic!("Expected Delta::Removed for balance"),
}
Expand Down Expand Up @@ -546,8 +545,8 @@ mod tests {
pre: Some((1000, 5, Some(bytecode1))),
post: Some((2000, 5, Some(bytecode1))),
expected_balance: Delta::Changed(ChangedType {
from: EthBigInt(BigInt::from(1000)),
to: EthBigInt(BigInt::from(2000)),
from: EthBigInt::from(1000),
to: EthBigInt::from(2000),
}),
expected_nonce: Delta::Unchanged,
expected_code: Delta::Unchanged,
Expand Down Expand Up @@ -579,8 +578,8 @@ mod tests {
pre: Some((1000, 5, Some(bytecode1))),
post: Some((2000, 6, Some(bytecode1))),
expected_balance: Delta::Changed(ChangedType {
from: EthBigInt(BigInt::from(1000)),
to: EthBigInt(BigInt::from(2000)),
from: EthBigInt::from(1000),
to: EthBigInt::from(2000),
}),
expected_nonce: Delta::Changed(ChangedType {
from: EthUint64(5),
Expand All @@ -592,15 +591,15 @@ mod tests {
name: "Creation",
pre: None,
post: Some((5000, 0, Some(bytecode1))),
expected_balance: Delta::Added(EthBigInt(BigInt::from(5000))),
expected_balance: Delta::Added(EthBigInt::from(5000)),
expected_nonce: Delta::Added(EthUint64(0)),
expected_code: Delta::Added(EthBytes(bytecode1.to_vec())),
},
TestCase {
name: "Deletion",
pre: Some((3000, 10, Some(bytecode1))),
post: None,
expected_balance: Delta::Removed(EthBigInt(BigInt::from(3000))),
expected_balance: Delta::Removed(EthBigInt::from(3000)),
expected_nonce: Delta::Removed(EthUint64(10)),
expected_code: Delta::Removed(EthBytes(bytecode1.to_vec())),
},
Expand Down
Loading
Loading