use crate::{DbcId, DbcTransaction, Error, Hash, Result, Signature, Token};
use custom_debug::Debug;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialOrd, Ord)]
pub struct SignedSpend {
pub spend: Spend,
#[debug(skip)]
pub derived_key_sig: Signature,
}
impl SignedSpend {
pub fn dbc_id(&self) -> &DbcId {
&self.spend.dbc_id
}
pub fn spent_tx_hash(&self) -> Hash {
self.spend.spent_tx.hash()
}
pub fn spent_tx(&self) -> DbcTransaction {
self.spend.spent_tx.clone()
}
pub fn dbc_creation_tx_hash(&self) -> Hash {
self.spend.dbc_creation_tx.hash()
}
pub fn token(&self) -> &Token {
&self.spend.token
}
pub fn reason(&self) -> Hash {
self.spend.reason
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes: Vec<u8> = Default::default();
bytes.extend(self.spend.to_bytes());
bytes.extend(self.derived_key_sig.to_bytes());
bytes
}
pub fn verify(&self, spent_tx_hash: Hash) -> Result<()> {
if spent_tx_hash != self.spent_tx_hash() {
return Err(Error::InvalidTransactionHash);
}
if self
.spend
.dbc_id
.verify(&self.derived_key_sig, self.spend.to_bytes())
{
Ok(())
} else {
Err(Error::InvalidSpendSignature(*self.dbc_id()))
}
}
}
impl PartialEq for SignedSpend {
fn eq(&self, other: &Self) -> bool {
self.spend == other.spend && self.derived_key_sig == other.derived_key_sig
}
}
impl Eq for SignedSpend {}
impl std::hash::Hash for SignedSpend {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let bytes = self.to_bytes();
bytes.hash(state);
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Spend {
pub dbc_id: DbcId,
#[debug(skip)]
pub spent_tx: DbcTransaction,
#[debug(skip)]
pub reason: Hash,
#[debug(skip)]
pub token: Token,
#[debug(skip)]
pub dbc_creation_tx: DbcTransaction,
}
impl Spend {
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes: Vec<u8> = Default::default();
bytes.extend(self.dbc_id.to_bytes());
bytes.extend(self.spent_tx.hash().as_ref());
bytes.extend(self.reason.as_ref());
bytes.extend(self.token.to_bytes());
bytes.extend(self.dbc_creation_tx.hash().as_ref());
bytes
}
pub fn hash(&self) -> Hash {
Hash::hash(&self.to_bytes())
}
}
impl PartialOrd for Spend {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Spend {
fn cmp(&self, other: &Self) -> Ordering {
self.dbc_id.cmp(&other.dbc_id)
}
}