use blockifier::transaction::account_transaction::AccountTransaction;
use blockifier::transaction::errors::{TransactionExecutionError, TransactionPreValidationError};
use blockifier::transaction::transaction_execution::Transaction;
use cairo_vm::vm::runners::cairo_runner::ExecutionResources;
use frame_support::traits::EnsureOrigin;
use mp_transactions::execution::Validate;
use super::*;
pub enum RawOrigin {
StarknetTransaction,
}
pub fn ensure_starknet_transaction<OuterOrigin>(o: OuterOrigin) -> Result<(), &'static str>
where
OuterOrigin: Into<Result<RawOrigin, OuterOrigin>>,
{
match o.into() {
Ok(RawOrigin::StarknetTransaction) => Ok(()),
_ => Err("bad origin: expected to be an Starknet transaction"),
}
}
pub struct EnsureStarknetTransaction;
impl<OuterOrigin: Into<Result<RawOrigin, OuterOrigin>> + From<RawOrigin>> EnsureOrigin<OuterOrigin>
for EnsureStarknetTransaction
{
type Success = ();
fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
o.into().map(|o| match o {
RawOrigin::StarknetTransaction => (),
})
}
#[cfg(feature = "runtime-benchmarks")]
fn try_successful_origin() -> Result<OuterOrigin, ()> {
Ok(OuterOrigin::from(RawOrigin::StarknetTransaction))
}
}
impl<T: Config> Pallet<T> {
pub fn pre_validate_unsigned_tx(transaction: &Transaction) -> Result<(), InvalidTransaction> {
match transaction {
Transaction::AccountTransaction(transaction) => {
let mut state = BlockifierStateAdapter::<T>::default();
let block_context = Self::get_block_context();
let charge_fee = !<T as Config>::DisableTransactionFee::get();
let tx_context = Arc::new(block_context.to_tx_context(transaction));
let string_nonce_checking = false;
match transaction {
AccountTransaction::Declare(transaction) => {
Validate::perform_pre_validation_stage::<T::DeclareTransactionFilter>(transaction, &mut state, tx_context, string_nonce_checking, charge_fee)
}
AccountTransaction::DeployAccount(transaction) => {
Validate::perform_pre_validation_stage::<T::DeployAccountTransactionFilter>(transaction, &mut state, tx_context, string_nonce_checking, charge_fee)
}
AccountTransaction::Invoke(transaction) => {
Validate::perform_pre_validation_stage::<T::InvokeTransactionFilter>(transaction, &mut state, tx_context, string_nonce_checking, charge_fee)
}
}
.map_err(|e| {
log!(debug, "Error in pre_validate_unsigned_tx: {:?}", e);
InvalidTransaction::BadProof
})
}
Transaction::L1HandlerTransaction(transaction) => {
Self::ensure_l1_message_not_executed(&transaction.tx.nonce)
}
}
}
pub fn validate_unsigned_tx(transaction: &Transaction) -> Result<(), InvalidTransaction> {
let _call_info = match transaction {
Transaction::AccountTransaction(transaction) => {
let mut state: BlockifierStateAdapter<T> = BlockifierStateAdapter::<T>::default();
let block_context = Self::get_block_context();
let mut inital_gas = block_context.versioned_constants().tx_initial_gas();
let mut resources = ExecutionResources::default();
let validation_result = match transaction {
AccountTransaction::Declare(tx) => {
let tx_context = Arc::new(block_context.to_tx_context(tx));
tx.run_validate_entrypoint(&mut state, tx_context, &mut resources, &mut inital_gas, true)
}
AccountTransaction::DeployAccount(_) => return Ok(()),
AccountTransaction::Invoke(tx) => {
let tx_context = Arc::new(block_context.to_tx_context(tx));
tx.run_validate_entrypoint(&mut state, tx_context, &mut resources, &mut inital_gas, true)
}
};
if let Err(TransactionExecutionError::TransactionPreValidationError(
TransactionPreValidationError::InvalidNonce { address, account_nonce, incoming_tx_nonce },
)) = validation_result
{
let sender_address = match transaction {
AccountTransaction::Declare(tx) => tx.tx.sender_address(),
AccountTransaction::DeployAccount(tx) => tx.contract_address,
AccountTransaction::Invoke(tx) => tx.tx.sender_address(),
};
if address == sender_address
&& account_nonce == Nonce(StarkFelt::ZERO)
&& incoming_tx_nonce == Nonce(StarkFelt::ONE)
{
Ok(None)
} else {
validation_result
}
} else {
validation_result
}
}
Transaction::L1HandlerTransaction(tx) => {
if tx.paid_fee_on_l1 == Fee(0) {
return Err(InvalidTransaction::Payment);
}
Ok(None)
}
}
.map_err(|e| {
log!(debug, "Error in validate_unsigned_tx: {:?}", e);
InvalidTransaction::BadProof
})?;
Ok(())
}
pub fn ensure_l1_message_not_executed(nonce: &Nonce) -> Result<(), InvalidTransaction> {
if L1Messages::<T>::get().contains(nonce) { Err(InvalidTransaction::Stale) } else { Ok(()) }
}
}