Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
10 changes: 6 additions & 4 deletions fendermint/app/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,9 +589,6 @@ where
.await
.context("error running check")?;

// Update the check state.
*guard = Some(state);

let mut mpool_received_trace = MpoolReceived::default();

let response = match result {
Expand All @@ -601,11 +598,16 @@ where
Ok(Err(InvalidSignature(d))) => invalid_check_tx(AppError::InvalidSignature, d),
Ok(Ok(ret)) => {
mpool_received_trace.message = Some(Message::from(&ret.message));
to_check_tx(ret)

let priority = state.txn_priority_calculator().priority(&ret.message);
to_check_tx(ret, priority)
}
},
};

// Update the check state.
*guard = Some(state);

mpool_received_trace.accept = response.code.is_ok();
if !mpool_received_trace.accept {
mpool_received_trace.reason = Some(format!("{:?} - {}", response.code, response.info));
Expand Down
3 changes: 2 additions & 1 deletion fendermint/app/src/tmconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ pub fn to_deliver_tx(
}
}

pub fn to_check_tx(ret: FvmCheckRet) -> response::CheckTx {
pub fn to_check_tx(ret: FvmCheckRet, priority: i64) -> response::CheckTx {
// Putting the message `log` because only `log` appears in the `tx_sync` JSON-RPC response.
let message = ret
.info
Expand All @@ -144,6 +144,7 @@ pub fn to_check_tx(ret: FvmCheckRet) -> response::CheckTx {
data,
gas_wanted: ret.gas_limit.try_into().unwrap_or(i64::MAX),
sender: ret.sender.to_string(),
priority,
..Default::default()
}
}
Expand Down
4 changes: 4 additions & 0 deletions fendermint/vm/interpreter/src/fvm/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ pub struct BlockGasTracker {
}

impl BlockGasTracker {
pub fn base_fee(&self) -> &TokenAmount {
&self.base_fee
}

pub fn create<E: Executor>(executor: &mut E) -> anyhow::Result<BlockGasTracker> {
let mut ret = Self {
base_fee: Zero::zero(),
Expand Down
9 changes: 9 additions & 0 deletions fendermint/vm/interpreter/src/fvm/state/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::collections::{HashMap, HashSet};

use crate::fvm::externs::FendermintExterns;
use crate::fvm::gas::BlockGasTracker;
use crate::fvm::state::priority::TxnPriorityCalculator;
use anyhow::Ok;
use cid::Cid;
use fendermint_actors_api::gas_market::Reading;
Expand Down Expand Up @@ -114,6 +115,8 @@ where
params: FvmUpdatableParams,
/// Indicate whether the parameters have been updated.
params_dirty: bool,

txn_priority: TxnPriorityCalculator,
}

impl<DB> FvmExecState<DB>
Expand Down Expand Up @@ -150,6 +153,7 @@ where
let mut executor = DefaultExecutor::new(engine, machine)?;

let block_gas_tracker = BlockGasTracker::create(&mut executor)?;
let base_fee = block_gas_tracker.base_fee().clone();

Ok(Self {
executor,
Expand All @@ -163,6 +167,7 @@ where
power_scale: params.power_scale,
},
params_dirty: false,
txn_priority: TxnPriorityCalculator::new(base_fee),
})
}

Expand Down Expand Up @@ -267,6 +272,10 @@ where
self.params.power_scale
}

pub fn txn_priority_calculator(&self) -> &TxnPriorityCalculator {
&self.txn_priority
}

pub fn app_version(&self) -> u64 {
self.params.app_version
}
Expand Down
1 change: 1 addition & 0 deletions fendermint/vm/interpreter/src/fvm/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod snapshot;
mod check;
mod exec;
mod genesis;
mod priority;
mod query;

use std::sync::Arc;
Expand Down
77 changes: 77 additions & 0 deletions fendermint/vm/interpreter/src/fvm/state/priority.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2022-2024 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT

use crate::fvm::FvmMessage;
use fvm_shared::econ::TokenAmount;
use num_traits::ToPrimitive;

/// The transaction priority calculator. The priority calculated is used to determine the ordering
/// in the mempool.
pub struct TxnPriorityCalculator {
base_fee: TokenAmount,
}

impl TxnPriorityCalculator {
pub fn new(base_fee: TokenAmount) -> Self {
Self { base_fee }
}

pub fn priority(&self, msg: &FvmMessage) -> i64 {
if msg.gas_fee_cap < self.base_fee {
return i64::MIN;
}

let effective_premium = msg
.gas_premium
.clone()
.min(&msg.gas_fee_cap - &self.base_fee);
effective_premium.atto().to_i64().unwrap_or(i64::MAX)
}
}

#[cfg(test)]
mod tests {
use crate::fvm::state::priority::TxnPriorityCalculator;
use crate::fvm::FvmMessage;
use fvm_shared::address::Address;
use fvm_shared::bigint::BigInt;
use fvm_shared::econ::TokenAmount;

fn create_msg(fee_cap: TokenAmount, premium: TokenAmount) -> FvmMessage {
FvmMessage {
version: 0,
from: Address::new_id(10),
to: Address::new_id(12),
sequence: 0,
value: Default::default(),
method_num: 0,
params: Default::default(),
gas_limit: 0,
gas_fee_cap: fee_cap,
gas_premium: premium,
}
}

#[test]
fn priority_calculation() {
let cal = TxnPriorityCalculator::new(TokenAmount::from_atto(30));

let msg = create_msg(TokenAmount::from_atto(1), TokenAmount::from_atto(20));
assert_eq!(cal.priority(&msg), i64::MIN);

let msg = create_msg(TokenAmount::from_atto(10), TokenAmount::from_atto(20));
assert_eq!(cal.priority(&msg), i64::MIN);

let msg = create_msg(TokenAmount::from_atto(35), TokenAmount::from_atto(20));
assert_eq!(cal.priority(&msg), 5);

let msg = create_msg(TokenAmount::from_atto(50), TokenAmount::from_atto(20));
assert_eq!(cal.priority(&msg), 20);

let msg = create_msg(
TokenAmount::from_atto(BigInt::from(i128::MAX)),
TokenAmount::from_atto(BigInt::from(i128::MAX)),
);
assert_eq!(cal.priority(&msg), i64::MAX);
}
}