use rand::Rng;
use serde::{Serialize, Deserialize};
use crate::validate;
use crate::utils::*;
use crate::schema::Schema;
use crate::coin::{coin_validate, coin_order};
use crate::state::State;
use crate::error::ErrorKind;
#[derive(Debug, PartialEq)]
pub enum Type {
Transfer,
Fee,
Split,
Merge,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Transaction {
pub coin: U256,
pub addr: U256,
pub sign_r: U256,
pub sign_s: U256,
}
impl Transaction {
pub fn new(coin: U256, addr: U256, sign_r: U256, sign_s: U256) -> Self {
Self { coin, addr, sign_r, sign_s }
}
pub fn build<R: Rng>(rng: &mut R, coin: U256, addr: U256, key: &U256,
counter: u64, schema: &Schema) -> Self {
let hash = Self::calc_msg(&coin, &addr, counter);
let (sign_r, sign_s) = schema.build_signature(rng, &hash, key);
Self::new(coin, addr, sign_r, sign_s)
}
pub fn get_type(&self) -> Type {
if self.addr == U256::from(0) {
Type::Fee
} else if self.addr == U256::from(1) {
Type::Split
} else if self.addr == U256::from(2) {
Type::Merge
} else {
Type::Transfer
}
}
pub fn get_msg(&self, counter: u64) -> U256 {
Self::calc_msg(&self.coin, &self.addr, counter)
}
pub fn get_hash(&self) -> U256 {
hash_of_u256(
[&self.coin, &self.addr, &self.sign_r, &self.sign_s].into_iter()
)
}
#[deprecated(since="0.1.0", note="use precalculated sender instead")]
pub fn get_sender(&self, state: &State, schema: &Schema) -> U256 {
let counter = state.get_coin_counter(&self.coin);
schema.extract_public(
&self.get_msg(counter),
&(self.sign_r.clone(), self.sign_s.clone())
)
}
pub fn get_order(&self, state: &State, sender: &U256) -> u64 {
if let Some(coin_info) = state.get_coin_info(&self.coin) {
coin_info.order
} else {
coin_order(&self.coin, sender)
}
}
pub fn validate_coin(&self, state: &State,
sender: &U256) -> UqoinResult<()> {
if let Some(owner) = state.get_owner(&self.coin) {
validate!(owner == sender, TransactionInvalidSender)?;
} else {
coin_validate(&self.coin, sender)?;
}
Ok(())
}
pub fn calc_msg(coin: &U256, addr: &U256, counter: u64) -> U256 {
hash_of_u256([coin, addr, &U256::from(counter)].into_iter())
}
pub fn calc_senders(transactions: &[Self], state: &State,
schema: &Schema) -> Vec<U256> {
transactions.iter().map(|tr| {
let counter = state.get_coin_counter(&tr.coin);
let msg = Self::calc_msg(&tr.coin, &tr.addr, counter);
let signature = (tr.sign_r.clone(), tr.sign_s.clone());
schema.extract_public(&msg, &signature)
}).collect::<Vec<U256>>()
}
}
#[derive(Debug, Clone)]
pub struct Group(Vec<Transaction>);
impl Group {
pub fn new(transactions: Vec<Transaction>, state: &State,
senders: &[U256]) -> UqoinResult<Self> {
Self::validate_transactions(&transactions, state, senders)?;
Ok(Self(transactions))
}
pub fn from_vec(transactions: &mut Vec<Transaction>, state: &State,
senders: &[U256]) -> UqoinResult<Self> {
if transactions.is_empty() {
Err(ErrorKind::TransactionEmpty.into())
} else {
let mut size = match transactions[0].get_type() {
Type::Split => 1,
Type::Merge => 3,
Type::Transfer => 1,
_ => 0,
};
if size == 0 {
Err(ErrorKind::TransactionBrokenGroup.into())
} else {
if (size < transactions.len()) &&
(transactions[size].get_type() == Type::Fee) {
size += 1;
}
let trs = vec_split_left(transactions, size);
Self::new(trs, state, &senders[..size])
}
}
}
pub fn transactions(&self) -> &[Transaction] {
&self.0
}
pub fn get_type(&self) -> Type {
self.0[0].get_type()
}
pub fn get_sender(&self, senders: &[U256]) -> U256 {
senders[0].clone()
}
pub fn get_fee(&self) -> Option<&Transaction> {
let fee_ix = match self.0[0].get_type() {
Type::Split => 1,
Type::Merge => 3,
Type::Transfer => 1,
_ => panic!("Invalid group."),
};
self.0.get(fee_ix)
}
pub fn get_hash(&self) -> U256 {
self.0[0].get_hash()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn get_order(&self, state: &State, senders: &[U256]) -> u64 {
match self.get_type() {
Type::Split => self.0[0].get_order(state, &senders[0]),
Type::Merge => self.0[0].get_order(state, &senders[0]) + 1,
Type::Transfer => self.0[0].get_order(state, &senders[0]),
_ => panic!("Invalid transactions in the group."),
}
}
pub fn ext_size(&self) -> usize {
match self.get_type() {
Type::Split => 3,
Type::Merge => 1,
Type::Transfer => 0,
_ => panic!("Invalid transactions in the group."),
}
}
pub fn validate_transactions(transactions: &[Transaction], state: &State,
senders: &[U256]) -> UqoinResult<()> {
validate!(!transactions.is_empty(), TransactionEmpty)?;
validate!(check_unique(transactions.iter().map(|tr| &tr.coin)),
CoinNotUnique)?;
validate!(check_same(senders.iter()), TransactionInvalidSender)?;
for transaction in transactions.iter() {
transaction.validate_coin(state, &senders[0])?;
}
match transactions[0].get_type() {
Type::Fee => validate!(false, TransactionBrokenGroup)?,
Type::Split => {
if transactions.len() > 1 {
validate!(transactions.len() == 2, TransactionBrokenGroup)?;
validate!(transactions[1].get_type() == Type::Fee,
TransactionBrokenGroup)?;
}
},
Type::Merge => {
let fee_check = (transactions.len() == 3) || (
(transactions.len() == 4) &&
(transactions[3].get_type() == Type::Fee)
);
validate!(fee_check, TransactionBrokenGroup)?;
let type_check =
(transactions[1].get_type() == Type::Merge) &&
(transactions[2].get_type() == Type::Merge);
validate!(type_check, TransactionBrokenGroup)?;
let order0 = transactions[0].get_order(state, &senders[0]);
let order1 = transactions[1].get_order(state, &senders[1]);
let order2 = transactions[2].get_order(state, &senders[2]);
let order_check = (order1 + 1 == order0) &&
(order2 + 1 == order0);
validate!(order_check, TransactionBrokenGroup)?;
},
Type::Transfer => {
if transactions.len() > 1 {
validate!(transactions.len() == 2, TransactionBrokenGroup)?;
validate!(transactions[1].get_type() == Type::Fee,
TransactionBrokenGroup)?;
}
},
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct Ext(Vec<Transaction>);
impl Ext {
pub fn new(transactions: Vec<Transaction>, state: &State,
senders: &[U256]) -> UqoinResult<Self> {
Self::validate_transactions(&transactions, state, senders)?;
Ok(Self(transactions))
}
pub fn transactions(&self) -> &[Transaction] {
&self.0
}
pub fn get_type(&self) -> Type {
match self.0.len() {
0 => Type::Transfer,
1 => Type::Merge,
3 => Type::Split,
_ => panic!("Invalid size of extension."),
}
}
pub fn get_sender(&self, senders: &[U256]) -> Option<U256> {
if self.0.is_empty() {
None
} else {
Some(senders[0].clone())
}
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn get_order(&self, state: &State, senders: &[U256]) -> u64 {
match self.0.len() {
0 => 0,
1 => self.0[0].get_order(state, &senders[0]),
3 => &self.0[0].get_order(state, &senders[0]) + 1,
_ => panic!("Invalid transactions in the group."),
}
}
pub fn validate_transactions(transactions: &[Transaction], state: &State,
senders: &[U256]) -> UqoinResult<()> {
validate!(check_unique(transactions.iter().map(|tr| &tr.coin)),
CoinNotUnique)?;
validate!(check_same(senders.iter()), TransactionInvalidSender)?;
for transaction in transactions.iter() {
transaction.validate_coin(state, &senders[0])?;
}
match transactions.len() {
0 => {},
1 => validate!(transactions[0].get_type() == Type::Transfer,
TransactionBrokenExt)?,
3 => {
let addr = &transactions[0].addr;
let type_check = transactions.iter()
.all(|tr| tr.get_type() == Type::Transfer);
validate!(type_check, TransactionBrokenExt)?;
let addr_check =
(&transactions[1].addr == addr) &&
(&transactions[2].addr == addr);
validate!(addr_check, TransactionBrokenExt)?;
let order0 = transactions[0].get_order(state, &senders[0]);
let order1 = transactions[1].get_order(state, &senders[1]);
let order2 = transactions[2].get_order(state, &senders[2]);
let order_check = (order1 + 1 == order0) &&
(order2 + 1 == order0);
validate!(order_check, TransactionBrokenExt)?;
},
_ => panic!("Invalid size of extension."),
}
Ok(())
}
}
pub fn group_transactions(mut transactions: Vec<Transaction>, state: &State,
senders: &[U256]) ->
impl Iterator<Item = (usize, Group, Ext)> {
let mut offset = 0;
std::iter::from_fn(move || {
if let Ok(group) = Group::from_vec(&mut transactions, state,
&senders[offset..]) {
let group_size = group.len();
let ext_size = group.ext_size();
let ext_trs = vec_split_left(&mut transactions, ext_size);
let ext_senders = &senders[
offset + group_size .. offset + group_size + ext_size
];
if let Ok(ext) = Ext::new(ext_trs, state, ext_senders) {
let res = (offset, group, ext);
offset += group_size + ext_size;
Some(res)
} else {
None
}
} else {
None
}
})
}