Skip to content

Commit

Permalink
Add gas payment for scheduled skip and destroy
Browse files Browse the repository at this point in the history
  • Loading branch information
anton-lisanin committed Dec 4, 2024
1 parent b685314 commit 0b5bffc
Show file tree
Hide file tree
Showing 15 changed files with 208 additions and 138 deletions.
3 changes: 2 additions & 1 deletion evm_loader/program/config/common.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ gas_limit_multiplier_no_chainid = 1000
storage_entries_in_contract_account = [64, "usize"]
treasury_pool_count = 128
treasury_pool_seed = "treasury_pool"
tree_account_timeout = 9000
tree_account_timeout = 750
tree_account_destroy_fee = 10000
6 changes: 5 additions & 1 deletion evm_loader/program/src/account/ether_balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ impl<'a> BalanceAccount<'a> {
let address = Address::from_solana_address(&pubkey);

let balance = Self::create(address, chain_id, accounts, None, rent)?;
{
if let Some(solana_address) = balance.solana_address() {
assert_eq!(solana_address, pubkey);
} else {
assert_eq!(balance.nonce(), 0);

let mut header = super::header_mut::<Header>(&balance.account);
header.solana_address = pubkey;
}
Expand Down
2 changes: 0 additions & 2 deletions evm_loader/program/src/account/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ pub use holder::{Header as HolderHeader, Holder};
pub use incinerator::Incinerator;
pub use operator::Operator;
pub use operator_balance::{OperatorBalanceAccount, OperatorBalanceValidator};
pub use signer::Signer;
pub use state::{AccountsStatus, StateAccount};
pub use state_finalized::{Header as StateFinalizedHeader, StateFinalizedAccount};
pub use transaction_tree::{
Expand All @@ -33,7 +32,6 @@ pub mod legacy;
mod operator;
mod operator_balance;
pub mod program;
mod signer;
mod state;
mod state_finalized;
pub mod token;
Expand Down
7 changes: 7 additions & 0 deletions evm_loader/program/src/account/operator_balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,13 @@ impl OperatorBalanceValidator for Option<OperatorBalanceAccount<'_>> {
return Err(Error::OperatorBalanceMissing);
}

if let Some(balance) = self {
let chain_id = trx.chain_id().unwrap_or(crate::config::DEFAULT_CHAIN_ID);
if balance.chain_id() != chain_id {
return Err(Error::OperatorBalanceInvalidChainId);
}
}

Ok(())
}

Expand Down
21 changes: 1 addition & 20 deletions evm_loader/program/src/account/program.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{Operator, Signer, Treasury};
use super::{Operator, Treasury};
use solana_program::account_info::AccountInfo;
use solana_program::program::{invoke_signed_unchecked, invoke_unchecked};
use solana_program::program_error::ProgramError;
Expand Down Expand Up @@ -207,25 +207,6 @@ impl<'a> System<'a> {
)
}

pub fn transfer_from_signer(
&self,
source: &Signer<'a>,
target: &AccountInfo<'a>,
lamports: u64,
) -> Result<(), ProgramError> {
crate::debug_print!(
"system transfer {} lamports from {} to {}",
lamports,
source.key,
target.key
);

invoke_unchecked(
&system_instruction::transfer(source.key, target.key, lamports),
&[source.info.clone(), target.clone(), self.0.clone()],
)
}

pub fn transfer_from_treasury(
&self,
source: &Treasury<'a>,
Expand Down
37 changes: 0 additions & 37 deletions evm_loader/program/src/account/signer.rs

This file was deleted.

54 changes: 38 additions & 16 deletions evm_loader/program/src/account/transaction_tree.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use std::cell::{Ref, RefMut};
use std::mem::size_of;

use super::program::System;
use super::treasury::Treasury;
use super::{
AccountHeader, AccountsDB, BalanceAccount, ACCOUNT_PREFIX_LEN, ACCOUNT_SEED_VERSION,
AccountHeader, AccountsDB, BalanceAccount, Operator, ACCOUNT_PREFIX_LEN, ACCOUNT_SEED_VERSION,
TAG_TRANSACTION_TREE,
};
use crate::config::TREE_ACCOUNT_TIMEOUT;
use crate::config::{TREE_ACCOUNT_DESTROY_FEE, TREE_ACCOUNT_TIMEOUT};
use crate::error::{Error, Result};
use crate::evm::ExitStatus;
use crate::types::{Address, Transaction, TransactionPayload};
Expand Down Expand Up @@ -128,8 +127,7 @@ impl<'a> TransactionTree<'a> {
pub fn create(
init: TreeInitializer,
account: AccountInfo<'a>,
treasury: &Treasury<'a>,
system: &System<'a>,
db: &AccountsDB<'a>,
rent: &Rent,
clock: &Clock,
) -> Result<Self> {
Expand All @@ -140,29 +138,36 @@ impl<'a> TransactionTree<'a> {
}

if account.owner != &system_program::ID {
return Err(Error::AccountInvalidOwner(*account.key, system_program::ID));
return Err(Error::TreeAccountAlreadyExists);
}

let seeds: &[&[u8]] = &[
&[ACCOUNT_SEED_VERSION],
b"TREE",
init.payer.as_bytes(),
&init.nonce.to_le_bytes(),
&[bump_seed],
];

// Validate init data
if init.max_fee_per_gas < 1_000_000_000 {
// Require at least 1 to 1 ratio to operator spending
// 1 Gwei in gas equals to 1 lamport
return Err(Error::TreeAccountInvalidMaxFeePerGas);
}

let nodes = init.nodes;
let mut parent_counts = vec![0_u16; nodes.len()];

for node in &nodes {
for (i, node) in nodes.iter().enumerate() {
if node.gas_limit < 25_000 {
// Require at least 25_000 gas limit to cover operator spending
return Err(Error::TreeAccountInvalidGasLimit);
}

if node.child == NO_CHILD_TRANSACTION {
continue;
}

if node.child as usize >= nodes.len() {
return Err(Error::TreeAccountTxInvalidChildIndex);
}
if node.child as usize <= i {
// Child transaction should be after parent transaction
return Err(Error::TreeAccountTxInvalidChildIndex);
}

parent_counts[node.child as usize] += 1;
}
Expand All @@ -174,7 +179,20 @@ impl<'a> TransactionTree<'a> {
}

// Create account
let seeds: &[&[u8]] = &[
&[ACCOUNT_SEED_VERSION],
b"TREE",
init.payer.as_bytes(),
&init.nonce.to_le_bytes(),
&[bump_seed],
];

let space = Self::required_account_size(nodes.len());

let system = db.system();
let treasury = db.treasury();
let destroy_fee_payer = db.operator();

system.create_pda_account_with_treasury_payer(
&crate::ID,
treasury,
Expand All @@ -183,6 +201,7 @@ impl<'a> TransactionTree<'a> {
space,
rent,
)?;
system.transfer(destroy_fee_payer, &account, TREE_ACCOUNT_DESTROY_FEE)?;

// Init data
super::set_tag(&crate::ID, &account, TAG_TRANSACTION_TREE, Header::VERSION)?;
Expand Down Expand Up @@ -253,13 +272,16 @@ impl<'a> TransactionTree<'a> {
self.is_complete()
}

pub fn destroy(self, treasury: &Treasury<'a>) -> Result<()> {
pub fn destroy(self, operator: &Operator, treasury: &Treasury<'a>) -> Result<()> {
let clock = Clock::get()?;

if !self.can_be_destroyed(&clock) {
return Err(Error::TreeAccountNotReadyForDestruction);
}

**operator.lamports.borrow_mut() += TREE_ACCOUNT_DESTROY_FEE;
**self.account.lamports.borrow_mut() -= TREE_ACCOUNT_DESTROY_FEE;

unsafe { super::delete_with_treasury(&self.account, treasury) }
}

Expand Down
9 changes: 9 additions & 0 deletions evm_loader/program/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,15 @@ pub enum Error {
#[error("Transaction Tree - transaction invalid status")]
TreeAccountTxInvalidStatus,

#[error("Transaction Tree - transaction requires at least 1 gwei for gas price")]
TreeAccountInvalidMaxFeePerGas,

#[error("Transaction Tree - transaction requires at least 25'000 gas limit")]
TreeAccountInvalidGasLimit,

#[error("Transaction Tree - transaction with the same nonce already exists")]
TreeAccountAlreadyExists,

// TODO reconcile with the TreeAccountTxInvalidType - potential duplicate.
#[error("Attempt to perform an operation with classic transaction, whereas scheduled transaction is expected")]
NotScheduledTransaction,
Expand Down
34 changes: 21 additions & 13 deletions evm_loader/program/src/instruction/priority_fee_txn_calculator.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::debug::log_data;
use crate::error::Error;
use crate::gasometer::LAMPORTS_PER_SIGNATURE;
use crate::types::Transaction;
use crate::types::TransactionPayload;
use crate::{error::Error, types::DynamicFeeTx};
use ethnum::U256;
use solana_program::{instruction::get_processed_sibling_instruction, pubkey, pubkey::Pubkey};
use std::convert::From;
Expand All @@ -22,22 +22,30 @@ const DEFAULT_COMPUTE_UNIT_LIMIT: u32 = 200_000;
const CONVERSION_MULTIPLIER: u64 = 1_000_000 / LAMPORTS_PER_SIGNATURE;

/// Handles priority fee:
/// - No-op for anything but DynamicFee transactions,
/// - Calculates and logs the priority fee in tokens for DynamicFee transactions.
/// - No-op for anything but DynamicFee or Scheduled transactions,
/// - Calculates and logs the priority fee in tokens.
pub fn handle_priority_fee(txn: &Transaction, gas_amount: U256) -> Result<U256, Error> {
if let TransactionPayload::DynamicFee(ref dynamic_fee_payload) = txn.transaction {
let priority_fee_in_tokens = get_priority_fee_in_tokens(dynamic_fee_payload, gas_amount)?;
log_data(&[b"PRIORITYFEE", &priority_fee_in_tokens.to_le_bytes()]);
return Ok(priority_fee_in_tokens);
}
Ok(U256::ZERO)
let (max_fee, max_priority_fee) = match txn.transaction {
TransactionPayload::DynamicFee(ref payload) => {
(payload.max_fee_per_gas, payload.max_priority_fee_per_gas)
}
TransactionPayload::Scheduled(ref payload) => {
(payload.max_fee_per_gas, payload.max_priority_fee_per_gas)
}
_ => return Ok(U256::ZERO),
};

let priority_fee_in_tokens = get_priority_fee_in_tokens(max_fee, max_priority_fee, gas_amount)?;
log_data(&[b"PRIORITYFEE", &priority_fee_in_tokens.to_le_bytes()]);
return Ok(priority_fee_in_tokens);
}

/// Returns the amount of "priority fee in tokens" that User have to pay to the Operator.
pub fn get_priority_fee_in_tokens(txn: &DynamicFeeTx, gas_amount: U256) -> Result<U256, Error> {
let max_fee = txn.max_fee_per_gas;
let max_priority_fee = txn.max_priority_fee_per_gas;

pub fn get_priority_fee_in_tokens(
max_fee: U256,
max_priority_fee: U256,
gas_amount: U256,
) -> Result<U256, Error> {
if max_priority_fee > max_fee {
return Err(Error::PriorityFeeError(
"max_priority_fee_per_gas > max_fee_per_gas".to_string(),
Expand Down
Loading

0 comments on commit 0b5bffc

Please sign in to comment.