Skip to content
Open
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
48 changes: 46 additions & 2 deletions fvm/src/call_manager/default.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2021-2023 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT
use std::rc::Rc;
use std::sync::{Arc, Mutex};

use anyhow::{Context, anyhow};
use cid::Cid;
Expand All @@ -22,6 +23,7 @@ use crate::call_manager::FinishRet;
use crate::call_manager::backtrace::Frame;
use crate::eam_actor::EAM_ACTOR_ID;
use crate::engine::Engine;
use crate::executor::ReservationSession;
use crate::gas::{Gas, GasTracker};
use crate::kernel::{
Block, BlockRegistry, ClassifyResult, ExecutionError, Kernel, Result, SyscallError,
Expand Down Expand Up @@ -77,6 +79,8 @@ pub struct InnerDefaultCallManager<M: Machine> {
events: EventsAccumulator,
/// The actor call stack (ActorID and entrypoint name tuple).
actor_call_stack: Vec<(ActorID, &'static str)>,
/// Shared reservation session ledger for the current tipset, if any.
reservation_session: Arc<Mutex<ReservationSession>>,
}

#[doc(hidden)]
Expand Down Expand Up @@ -111,6 +115,7 @@ where
receiver_address: Address,
nonce: u64,
gas_premium: TokenAmount,
reservation_session: Arc<Mutex<ReservationSession>>,
) -> Self {
let limits = machine.new_limiter();
let gas_tracker =
Expand Down Expand Up @@ -162,6 +167,7 @@ where
events: Default::default(),
state_access_tracker,
actor_call_stack: vec![],
reservation_session,
})))
}

Expand Down Expand Up @@ -489,8 +495,46 @@ where
.get_actor(from)?
.ok_or_else(||syscall_error!(InsufficientFunds; "insufficient funds to transfer {value}FIL from {from} to {to})"))?;

if &from_actor.balance < value {
return Err(syscall_error!(InsufficientFunds; "sender does not have funds to transfer (balance {}, transfer {})", &from_actor.balance, value).into());
// In reservation mode, ensure the sender cannot spend funds that are reserved for gas.
// Free balance is defined as balance - reserved_remaining. To avoid negative intermediates,
// we enforce the equivalent inequality: value + reserved_remaining <= balance.
let (reservation_open, reserved_remaining) = {
let session = self
.reservation_session
.lock()
.expect("reservation session mutex poisoned");
if session.open {
let reserved = session
.reservations
.get(&from)
.cloned()
.unwrap_or_else(TokenAmount::zero);
(true, reserved)
} else {
(false, TokenAmount::zero())
}
};

if reservation_open {
let required = &reserved_remaining + value;
if from_actor.balance < required {
return Err(syscall_error!(
InsufficientFunds;
"sender does not have free funds to transfer (balance {}, transfer {}, reserved {})",
&from_actor.balance,
value,
&reserved_remaining
)
.into());
}
} else if &from_actor.balance < value {
return Err(syscall_error!(
InsufficientFunds;
"sender does not have funds to transfer (balance {}, transfer {})",
&from_actor.balance,
value
)
.into());
}

if from == to {
Expand Down
4 changes: 4 additions & 0 deletions fvm/src/call_manager/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright 2021-2023 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT
use std::sync::{Arc, Mutex};

use cid::Cid;
use fvm_ipld_encoding::{CBOR, to_vec};
use fvm_shared::address::Address;
Expand All @@ -10,6 +12,7 @@ use fvm_shared::{ActorID, METHOD_CONSTRUCTOR, MethodNum};

use crate::Kernel;
use crate::engine::Engine;
use crate::executor::ReservationSession;
use crate::gas::{Gas, GasCharge, GasTimer, GasTracker, PriceList};
use crate::kernel::{self, BlockRegistry, ClassifyResult, Context, Result};
use crate::machine::{Machine, MachineContext};
Expand Down Expand Up @@ -60,6 +63,7 @@ pub trait CallManager: 'static {
receiver_address: Address,
nonce: u64,
gas_premium: TokenAmount,
reservation_session: Arc<Mutex<ReservationSession>>,
) -> Self;

/// Calls an actor at the given address and entrypoint. The type parameter `K` specifies the the _kernel_ on top of which the target
Expand Down
Loading
Loading