use crate::injected::SignedInjectedTransaction;
use alloc::vec::Vec;
use derive_more::{Deref, DerefMut, IntoIterator};
use gprimitives::H256;
use parity_scale_codec::{Decode, Encode};
use scale_info::TypeInfo;
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum Transaction {
AdvanceTillEthereumBlock { block_hash: H256 },
ProgressTasks { limits: ProgressTasksLimits },
ProcessQueues { limits: ProcessQueuesLimits },
Injected(SignedInjectedTransaction),
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Encode, Decode, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct ProgressTasksLimits {}
#[derive(Clone, Debug, Default, PartialEq, Eq, Encode, Decode, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct ProcessQueuesLimits {
pub gas_allowance: u64,
}
impl Transaction {
pub fn tag(&self) -> &'static str {
match self {
Self::AdvanceTillEthereumBlock { .. } => "advance-eth-block",
Self::ProgressTasks { .. } => "progress-tasks",
Self::ProcessQueues { .. } => "process-queues",
Self::Injected(_) => "injected",
}
}
}
#[derive(
Clone, Debug, Default, PartialEq, Eq, Encode, Decode, TypeInfo, Deref, DerefMut, IntoIterator,
)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct Transactions(pub Vec<Transaction>);
impl Transactions {
pub fn new(transactions: Vec<Transaction>) -> Self {
Self(transactions)
}
pub fn hash(&self) -> H256 {
gear_core::utils::hash(&self.encode()).into()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn empty_txs() -> Transactions {
Transactions::new(alloc::vec![
Transaction::ProgressTasks {
limits: ProgressTasksLimits::default(),
},
Transaction::ProcessQueues {
limits: ProcessQueuesLimits::default(),
},
])
}
#[test]
fn hash_is_deterministic_for_same_content() {
let a = empty_txs();
let b = empty_txs();
assert_eq!(a.hash(), b.hash());
}
#[test]
fn hash_changes_when_transactions_change() {
let mut a = empty_txs();
let b = empty_txs();
a.push(Transaction::AdvanceTillEthereumBlock {
block_hash: H256::from_low_u64_be(0xEB),
});
assert_ne!(a.hash(), b.hash());
}
#[test]
fn transaction_tag_distinguishes_variants() {
let advance = Transaction::AdvanceTillEthereumBlock {
block_hash: H256::zero(),
};
let progress = Transaction::ProgressTasks {
limits: ProgressTasksLimits::default(),
};
let queues = Transaction::ProcessQueues {
limits: ProcessQueuesLimits::default(),
};
assert_eq!(advance.tag(), "advance-eth-block");
assert_eq!(progress.tag(), "progress-tasks");
assert_eq!(queues.tag(), "process-queues");
}
#[test]
fn scale_round_trip_preserves_hash() {
use parity_scale_codec::Decode;
let original = Transactions::new(alloc::vec![Transaction::AdvanceTillEthereumBlock {
block_hash: H256::from_low_u64_be(0xEB)
}]);
let encoded = original.encode();
let decoded = Transactions::decode(&mut encoded.as_slice()).expect("decode");
assert_eq!(original, decoded);
assert_eq!(original.hash(), decoded.hash());
}
}