Skip to content

Commit 56c2695

Browse files
committed
feat: add engine-managed gas reservations to ref-fvm
1 parent 71c2f8c commit 56c2695

File tree

8 files changed

+1793
-26
lines changed

8 files changed

+1793
-26
lines changed

fvm/src/call_manager/default.rs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright 2021-2023 Protocol Labs
22
// SPDX-License-Identifier: Apache-2.0, MIT
33
use std::rc::Rc;
4+
use std::sync::{Arc, Mutex};
45

56
use anyhow::{Context, anyhow};
67
use cid::Cid;
@@ -33,6 +34,7 @@ use crate::syscalls::error::Abort;
3334
use crate::syscalls::{charge_for_exec, update_gas_available};
3435
use crate::trace::{ExecutionEvent, ExecutionTrace};
3536
use crate::{syscall_error, system_actor};
37+
use crate::executor::ReservationSession;
3638

3739
/// The default [`CallManager`] implementation.
3840
#[repr(transparent)]
@@ -77,6 +79,8 @@ pub struct InnerDefaultCallManager<M: Machine> {
7779
events: EventsAccumulator,
7880
/// The actor call stack (ActorID and entrypoint name tuple).
7981
actor_call_stack: Vec<(ActorID, &'static str)>,
82+
/// Shared reservation session ledger for the current tipset, if any.
83+
reservation_session: Arc<Mutex<ReservationSession>>,
8084
}
8185

8286
#[doc(hidden)]
@@ -111,6 +115,7 @@ where
111115
receiver_address: Address,
112116
nonce: u64,
113117
gas_premium: TokenAmount,
118+
reservation_session: Arc<Mutex<ReservationSession>>,
114119
) -> Self {
115120
let limits = machine.new_limiter();
116121
let gas_tracker =
@@ -162,6 +167,7 @@ where
162167
events: Default::default(),
163168
state_access_tracker,
164169
actor_call_stack: vec![],
170+
reservation_session,
165171
})))
166172
}
167173

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

492-
if &from_actor.balance < value {
493-
return Err(syscall_error!(InsufficientFunds; "sender does not have funds to transfer (balance {}, transfer {})", &from_actor.balance, value).into());
498+
// In reservation mode, ensure the sender cannot spend funds that are reserved for gas.
499+
// Free balance is defined as balance - reserved_remaining. To avoid negative intermediates,
500+
// we enforce the equivalent inequality: value + reserved_remaining <= balance.
501+
let (reservation_open, reserved_remaining) = {
502+
let session = self
503+
.reservation_session
504+
.lock()
505+
.expect("reservation session mutex poisoned");
506+
if session.open {
507+
let reserved = session
508+
.reservations
509+
.get(&from)
510+
.cloned()
511+
.unwrap_or_else(TokenAmount::zero);
512+
(true, reserved)
513+
} else {
514+
(false, TokenAmount::zero())
515+
}
516+
};
517+
518+
if reservation_open {
519+
let required = &reserved_remaining + value;
520+
if &from_actor.balance < &required {
521+
return Err(syscall_error!(
522+
InsufficientFunds;
523+
"sender does not have free funds to transfer (balance {}, transfer {}, reserved {})",
524+
&from_actor.balance,
525+
value,
526+
&reserved_remaining
527+
)
528+
.into());
529+
}
530+
} else if &from_actor.balance < value {
531+
return Err(syscall_error!(
532+
InsufficientFunds;
533+
"sender does not have funds to transfer (balance {}, transfer {})",
534+
&from_actor.balance,
535+
value
536+
)
537+
.into());
494538
}
495539

496540
if from == to {

fvm/src/call_manager/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// Copyright 2021-2023 Protocol Labs
22
// SPDX-License-Identifier: Apache-2.0, MIT
3+
use std::sync::{Arc, Mutex};
4+
35
use cid::Cid;
46
use fvm_ipld_encoding::{CBOR, to_vec};
57
use fvm_shared::address::Address;
@@ -13,6 +15,7 @@ use crate::engine::Engine;
1315
use crate::gas::{Gas, GasCharge, GasTimer, GasTracker, PriceList};
1416
use crate::kernel::{self, BlockRegistry, ClassifyResult, Context, Result};
1517
use crate::machine::{Machine, MachineContext};
18+
use crate::executor::ReservationSession;
1619
use crate::state_tree::ActorState;
1720

1821
pub mod backtrace;
@@ -60,6 +63,7 @@ pub trait CallManager: 'static {
6063
receiver_address: Address,
6164
nonce: u64,
6265
gas_premium: TokenAmount,
66+
reservation_session: Arc<Mutex<ReservationSession>>,
6367
) -> Self;
6468

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

0 commit comments

Comments
 (0)