Skip to content

Commit

Permalink
feat: gasless sync for tx pool & execution
Browse files Browse the repository at this point in the history
  • Loading branch information
wenyuanhust committed Jan 6, 2023
1 parent 653d874 commit a9a259e
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 14 deletions.
117 changes: 113 additions & 4 deletions core/executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ use std::collections::BTreeMap;
use std::iter::FromIterator;

use arc_swap::ArcSwap;
use ethers::abi::{AbiDecode, AbiEncode};
use evm::executor::stack::{MemoryStackState, PrecompileFn, StackExecutor, StackSubstateMetadata};
use evm::CreateScheme;
use evm::{CreateScheme, ExitReason, ExitSucceed};

use common_merkle::TrieMerkle;
use protocol::codec::ProtocolCodec;
Expand All @@ -29,6 +30,10 @@ use protocol::types::{
data_gas_cost, Account, Config, ExecResp, Hasher, SignedTransaction, TransactionAction, TxResp,
ValidatorExtend, GAS_CALL_TRANSACTION, GAS_CREATE_TRANSACTION, H160, NIL_DATA, RLP_NULL, U256,
};
use system_contract::gasless::abi::sponsor_whitelist_control_abi::{
GetSponsorForGasCall, IsWhitelistedCall, SubstractSponsorBalanceCall,
};
use system_contract::gasless::abi::GASLESS_ADDRESS;

use crate::precompiles::build_precompile_set;
use crate::system_contract::{system_contract_dispatch, NativeTokenContract, SystemContract};
Expand Down Expand Up @@ -135,7 +140,7 @@ impl Executor for AxonExecutor {
// Execute a transaction, if system contract dispatch return None, means the
// transaction called EVM
let mut r = system_contract_dispatch(backend, tx)
.unwrap_or_else(|| Self::evm_exec(backend, &config, &precompiles, tx));
.unwrap_or_else(|| Self::evm_exec(self, backend, &config, &precompiles, tx));

r.logs = backend.get_logs();
gas += r.gas_used;
Expand Down Expand Up @@ -188,19 +193,99 @@ impl Executor for AxonExecutor {
}

impl AxonExecutor {
pub fn is_sponsored<B: Backend + ApplyBackend + Adapter>(
&self,
backend: &mut B,
sender: &H160,
receiver: &Option<H160>,
gas_limit: &U256,
prepay_gas: &U256,
) -> bool {
if let Some(receiver) = receiver {
// call isWhitelisted
let call_data: Vec<u8> = AbiEncode::encode(IsWhitelistedCall {
contract_addr: *receiver,
user: *sender,
});
let rsp = Self::call(
self,
backend,
gas_limit.as_u64(),
Some(*sender),
Some(GASLESS_ADDRESS),
U256::default(),
call_data,
);
let is_sponsored: bool = AbiDecode::decode(rsp.ret).unwrap();
if !is_sponsored {
return false;
}

// call getSponsoredBalanceForGas
let call_data: Vec<u8> = AbiEncode::encode(GetSponsorForGasCall {
contract_addr: *receiver,
});
let rsp = Self::call(
self,
backend,
gas_limit.as_u64(),
Some(*sender),
Some(GASLESS_ADDRESS),
U256::default(),
call_data,
);
let sponsor_balance: U256 = AbiDecode::decode(rsp.ret).unwrap();
if sponsor_balance < *prepay_gas {
return false;
}

// call getSponsoredGasFeeUpperBound
let call_data: Vec<u8> = AbiEncode::encode(GetSponsorForGasCall {
contract_addr: *receiver,
});
let rsp = Self::call(
self,
backend,
gas_limit.as_u64(),
Some(*sender),
Some(GASLESS_ADDRESS),
U256::default(),
call_data,
);
let sponsor_bound: U256 = AbiDecode::decode(rsp.ret).unwrap();
if sponsor_bound < *gas_limit {
return false;
}

true
} else {
false
}
}

pub fn evm_exec<B: Backend + ApplyBackend + Adapter>(
&self,
backend: &mut B,
config: &Config,
precompiles: &BTreeMap<H160, PrecompileFn>,
tx: &SignedTransaction,
) -> TxResp {
// Deduct pre-pay gas
let sender = tx.sender;
let mut sender = tx.sender;
let tx_gas_price = backend.gas_price();
let gas_limit = tx.transaction.unsigned.gas_limit();
let prepay_gas = tx_gas_price * gas_limit;

let mut account = backend.get_account(&sender);

let receiver = tx.transaction.unsigned.to();
let mut is_sponsored = false;
if self.is_sponsored(backend, &sender, &receiver, gas_limit, &prepay_gas) {
sender = GASLESS_ADDRESS;
account = backend.get_account(&GASLESS_ADDRESS);
is_sponsored = true;
}

account.balance = account.balance.saturating_sub(prepay_gas);
backend.save_account(&sender, &account);

Expand Down Expand Up @@ -263,13 +348,37 @@ impl AxonExecutor {
let remain_gas = U256::from(remained_gas)
.checked_mul(tx_gas_price)
.unwrap_or_else(U256::max_value);

if is_sponsored {
sender = GASLESS_ADDRESS;
account = backend.get_account(&GASLESS_ADDRESS);
let actual_used_balance = prepay_gas.saturating_sub(remain_gas);

// call substractSponsorBalance
let call_data: Vec<u8> = AbiEncode::encode(SubstractSponsorBalanceCall {
contract_addr: receiver.unwrap(),
balance: actual_used_balance,
});

let rsp = Self::call(
self,
backend,
gas_limit.as_u64(),
Some(sender),
Some(GASLESS_ADDRESS),
U256::default(),
call_data,
);
assert_eq!(rsp.exit_reason, ExitReason::Succeed(ExitSucceed::Stopped));
}

account.balance = account
.balance
.checked_add(remain_gas)
.unwrap_or_else(U256::max_value);
}

backend.save_account(&tx.sender, &account);
backend.save_account(&sender, &account);

TxResp {
exit_reason: exit,
Expand Down
4 changes: 4 additions & 0 deletions core/executor/src/system_contract/gasless/abi/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
pub mod sponsor_whitelist_control_abi;

use crate::system_contract::system_contract_address;
use protocol::types::H160;
pub const GASLESS_ADDRESS: H160 = system_contract_address(0x1);
Loading

0 comments on commit a9a259e

Please sign in to comment.