snapshot before rebranding

This commit is contained in:
2025-12-14 07:37:21 +03:00
parent 5520d491a5
commit 09735eb97a
1752 changed files with 58116 additions and 15986 deletions
@@ -0,0 +1,280 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use crate::{
error::Error,
fake_transaction::{FakeHash, FakeTransaction},
fake_transaction_sink::FakeTransactionsSink,
helpers::StreamOf,
runner::DefaultTxTask,
subxt_transaction::{
build_subxt_tx, EthPayloadBuilderFn, EthRuntimeConfig, EthTransaction, EthTransactionsSink,
HashOf, SubPayloadBuilderFn, SubstrateTransaction, SubstrateTransactionsSink,
},
};
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::any::Any;
use subxt::{tx::TxStatus, OnlineClient, PolkadotConfig};
use subxt_core::config::Hash as BlockHash;
/// Parameters for building a transaction.
pub(crate) struct BuildTransactionParams<'a> {
pub account: &'a str,
pub nonce: &'a Option<u128>,
pub mortality: &'a Option<u64>,
pub tip: u128,
}
/// Interface for transaction building.
#[async_trait]
pub(crate) trait TransactionBuilder {
type HashType: BlockHash;
type Transaction: Transaction<HashType = Self::HashType>;
type Sink: TransactionsSink<Self::HashType>;
type PayloadBuilder: Send + Sync;
async fn build_transaction<'a>(
&self,
watched: bool,
params: BuildTransactionParams<'a>,
sink: &Self::Sink,
payload_builder: &Self::PayloadBuilder,
) -> DefaultTxTask<Self::Transaction>;
}
/// Substrate transactions builder.
#[derive(Default)]
pub(crate) struct SubstrateTransactionBuilder {}
#[async_trait]
impl TransactionBuilder for SubstrateTransactionBuilder {
type HashType = HashOf<PolkadotConfig>;
type Transaction = SubstrateTransaction;
type Sink = SubstrateTransactionsSink;
type PayloadBuilder = SubPayloadBuilderFn;
async fn build_transaction<'a>(
&self,
watched: bool,
params: BuildTransactionParams<'a>,
sink: &Self::Sink,
payload_builder: &Self::PayloadBuilder,
) -> DefaultTxTask<Self::Transaction> {
let tx = build_subxt_tx(&params, sink, &**payload_builder).await;
if watched {
DefaultTxTask::<Self::Transaction>::new_watched(tx)
} else {
DefaultTxTask::<Self::Transaction>::new_unwatched(tx)
}
}
}
/// Ethereum transactions builder.
#[derive(Default)]
pub(crate) struct EthTransactionBuilder {}
#[async_trait]
impl TransactionBuilder for EthTransactionBuilder {
type HashType = HashOf<EthRuntimeConfig>;
type Transaction = EthTransaction;
type Sink = EthTransactionsSink;
type PayloadBuilder = EthPayloadBuilderFn;
async fn build_transaction<'a>(
&self,
watched: bool,
params: BuildTransactionParams<'a>,
sink: &Self::Sink,
payload_builder: &Self::PayloadBuilder,
) -> DefaultTxTask<Self::Transaction> {
let tx = build_subxt_tx(&params, sink, &**payload_builder).await;
if watched {
DefaultTxTask::<Self::Transaction>::new_watched(tx)
} else {
DefaultTxTask::<Self::Transaction>::new_unwatched(tx)
}
}
}
#[allow(dead_code)]
#[derive(Default)]
/// A transaction builder sink that's used as mock for logic relying on a transaction builder.
pub(crate) struct FakeTransactionBuilder;
#[async_trait]
impl TransactionBuilder for FakeTransactionBuilder {
type HashType = FakeHash;
type Transaction = FakeTransaction;
type Sink = FakeTransactionsSink;
type PayloadBuilder = ();
async fn build_transaction<'a>(
&self,
watched: bool,
params: BuildTransactionParams<'a>,
sink: &Self::Sink,
_payload_builder: &Self::PayloadBuilder,
) -> DefaultTxTask<Self::Transaction> {
if watched {
todo!()
};
let mut nonces = sink.nonces.write();
let nonce = if let Some(nonce) = nonces.get_mut(&hex::encode(params.account)) {
*nonce += 1;
*nonce
} else {
nonces.insert(hex::encode(params.account), 0);
0
};
let id = params.account.parse::<u32>().ok();
if let Some(i) = id {
DefaultTxTask::<FakeTransaction>::new_watched(FakeTransaction::new_multiple(
i,
nonce,
vec![],
))
} else {
DefaultTxTask::<FakeTransaction>::new_watched(FakeTransaction::new_with_keyring(
"alice".to_string(),
nonce,
vec![],
))
}
}
}
/// What account was used to sign transaction
#[derive(Default, PartialEq, Debug, Clone, Serialize, Deserialize)]
pub enum AccountMetadata {
/// Holds index used for account derivation
#[default]
None,
Derived(u32),
KeyRing(String),
}
/// Type of transaction logic.
#[derive(Clone)]
pub enum TransactionCall {
Transfer,
Remark(u32),
}
#[derive(Clone)]
/// Type of transaction to execute.
pub struct TransactionRecipe {
pub(crate) call: TransactionCall,
}
impl TransactionRecipe {
pub fn transfer() -> Self {
Self { call: TransactionCall::Transfer }
}
pub fn remark(size: u32) -> Self {
Self { call: TransactionCall::Remark(size) }
}
}
/// Interface that asks for logic to decide if a transaction is done.
pub(crate) trait TransactionStatusIsDone {
fn is_terminal(&self) -> bool;
fn is_finalized(&self) -> bool;
fn is_error(&self) -> bool;
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub enum TransactionStatus<H> {
Validated,
Broadcasted,
InBlock(H),
NoLongerInBestBlock,
Finalized(H),
Dropped(String),
Invalid(String),
Error(String),
}
impl<H> TransactionStatus<H> {
pub(crate) fn get_letter(&self) -> char {
match self {
TransactionStatus::Validated => 'V',
TransactionStatus::Broadcasted => 'b',
TransactionStatus::InBlock(..) => 'B',
TransactionStatus::Finalized(..) => 'F',
TransactionStatus::Error { .. } => 'E',
TransactionStatus::Invalid { .. } => 'I',
TransactionStatus::Dropped { .. } => 'D',
TransactionStatus::NoLongerInBestBlock => 'N',
}
}
}
impl<H: BlockHash + std::fmt::Debug> TransactionStatus<H> {}
impl<C: subxt::Config> From<TxStatus<C, OnlineClient<C>>> for TransactionStatus<HashOf<C>> {
fn from(value: TxStatus<C, OnlineClient<C>>) -> Self {
match value {
TxStatus::Validated => TransactionStatus::Validated,
TxStatus::Broadcasted => TransactionStatus::Broadcasted,
TxStatus::InBestBlock(tx) => TransactionStatus::InBlock(tx.block_hash()),
TxStatus::InFinalizedBlock(tx) => TransactionStatus::Finalized(tx.block_hash()),
TxStatus::Error { message } => TransactionStatus::Error(message),
TxStatus::Invalid { message } => TransactionStatus::Invalid(message),
TxStatus::Dropped { message } => TransactionStatus::Dropped(message),
TxStatus::NoLongerInBestBlock => TransactionStatus::NoLongerInBestBlock,
}
}
}
impl<H: BlockHash> TransactionStatusIsDone for TransactionStatus<H> {
fn is_terminal(&self) -> bool {
matches!(self, Self::Finalized(_) | Self::Dropped(_) | Self::Invalid(_) | Self::Error(_))
}
fn is_finalized(&self) -> bool {
matches!(self, Self::Finalized(_))
}
fn is_error(&self) -> bool {
matches!(self, Self::Dropped(_) | Self::Invalid(_) | Self::Error(_))
}
}
/// Interface for a multi-chain transaction abstraction.
pub trait Transaction: Send + Sync {
type HashType: BlockHash + 'static;
fn hash(&self) -> Self::HashType;
fn as_any(&self) -> &dyn Any;
fn nonce(&self) -> u128;
fn valid_until(&self) -> &Option<u64>;
fn account_metadata(&self) -> AccountMetadata;
}
/// Interface for monitoring transaction state.
#[async_trait]
pub trait TransactionMonitor<H: BlockHash> {
/// Wait for the transaction to finalize.
///
/// An optional block number is given to be considered for waiting when needed.
async fn wait(&self, tx_hash: H, until: Option<u64>) -> Result<H, Error>;
}
/// Abstraction for RPC client
#[async_trait]
pub trait TransactionsSink<H: BlockHash>: Send + Sync {
async fn submit_and_watch(
&self,
tx: &dyn Transaction<HashType = H>,
) -> Result<StreamOf<TransactionStatus<H>>, Error>;
async fn submit(&self, tx: &dyn Transaction<HashType = H>) -> Result<H, Error>;
///Current count of transactions being processed by sink
async fn pending_extrinsics(&self) -> usize;
fn transaction_monitor(&self) -> Option<&dyn TransactionMonitor<H>>;
}