#![allow(unused)]
use crate::constants::*;
use crate::crypto::sign_ed25519::{PublicKey, Signature};
use crate::primitives::{
asset::{Asset, ItemAsset, TokenAmount},
druid::{DdeValues, DruidExpectation},
};
use crate::script::lang::Script;
use crate::script::{OpCodes, StackEntry};
use crate::utils::is_valid_amount;
use bincode::serialize;
use bytes::Bytes;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum GenesisTxHashSpec {
Create,
Default,
}
impl GenesisTxHashSpec {
pub fn get_genesis_hash(&self) -> Option<String> {
match self {
GenesisTxHashSpec::Create => None,
GenesisTxHashSpec::Default => Some(ITEM_DEFAULT_DRS_TX_HASH.to_string()),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct TxConstructor {
pub previous_out: OutPoint,
pub signatures: Vec<Signature>,
pub pub_keys: Vec<PublicKey>,
pub address_version: Option<u64>,
}
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
pub struct OutPoint {
pub t_hash: String,
pub n: i32,
}
impl fmt::Display for OutPoint {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "t_hash:{}-n:{}", self.t_hash, self.n)
}
}
impl OutPoint {
pub fn new(t_hash: String, n: i32) -> OutPoint {
OutPoint { t_hash, n }
}
}
impl Default for OutPoint {
fn default() -> Self {
Self::new(String::new(), 0)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct TxIn {
pub previous_out: Option<OutPoint>,
pub script_signature: Script,
}
impl Default for TxIn {
fn default() -> Self {
Self::new()
}
}
impl TxIn {
pub fn new() -> TxIn {
let mut script_sig = Script::new();
script_sig.stack.push(StackEntry::Op(OpCodes::OP_0));
TxIn {
previous_out: None,
script_signature: script_sig,
}
}
pub fn new_from_script(script_sig: Script) -> TxIn {
TxIn {
previous_out: None,
script_signature: script_sig,
}
}
pub fn new_from_input(previous_out: OutPoint, script_sig: Script) -> TxIn {
TxIn {
previous_out: Some(previous_out),
script_signature: script_sig,
}
}
}
#[derive(Default, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct TxOut {
pub value: Asset,
pub locktime: u64,
pub script_public_key: Option<String>,
}
impl TxOut {
pub fn new() -> TxOut {
Default::default()
}
pub fn new_token_amount(
to_address: String,
amount: TokenAmount,
locktime: Option<u64>,
) -> TxOut {
TxOut {
value: Asset::Token(amount),
locktime: locktime.unwrap_or(ZERO as u64),
script_public_key: Some(to_address),
}
}
pub fn new_item_amount(to_address: String, item: ItemAsset, locktime: Option<u64>) -> TxOut {
TxOut {
value: Asset::Item(item),
locktime: locktime.unwrap_or(ZERO as u64),
script_public_key: Some(to_address),
}
}
pub fn new_asset(to_address: String, asset: Asset, locktime: Option<u64>) -> TxOut {
match asset {
Asset::Token(amount) => TxOut::new_token_amount(to_address, amount, locktime),
Asset::Item(item) => TxOut::new_item_amount(to_address, item, locktime),
_ => panic!("Cannot create TxOut for asset of type {:?}", asset),
}
}
pub fn is_p2sh_tx_out(&self) -> bool {
if let Some(pk) = &self.script_public_key {
let pk_bytes = pk.as_bytes();
return pk_bytes[0] == P2SH_PREPEND;
}
false
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Transaction {
pub inputs: Vec<TxIn>,
pub outputs: Vec<TxOut>,
pub version: usize,
pub fees: Vec<TxOut>,
pub druid_info: Option<DdeValues>,
}
impl Default for Transaction {
fn default() -> Self {
Self::new()
}
}
impl Transaction {
pub fn new() -> Transaction {
Transaction {
inputs: Vec::new(),
outputs: Vec::new(),
fees: Vec::new(),
version: NETWORK_VERSION as usize,
druid_info: None,
}
}
pub fn get_total_size(&self) -> usize {
let bytes = match serialize(self) {
Ok(bytes) => bytes,
Err(_) => vec![],
};
bytes.len()
}
fn get_create_asset(&self) -> Option<&Asset> {
let is_create = self.inputs.len() == 1
&& self.inputs[0].previous_out.is_none()
&& self.outputs.len() == 1;
is_create.then(|| &self.outputs[0].value)
}
pub fn is_coinbase(&self) -> bool {
self.get_create_asset()
.map(|a| a.is_token())
.unwrap_or_default()
}
pub fn is_create_tx(&self) -> bool {
self.get_create_asset()
.map(|a| !a.is_token())
.unwrap_or_default()
}
pub fn is_p2sh_tx(&self) -> bool {
if self.outputs.len() != 1 {
return false;
}
if let Some(pk) = &self.outputs[0].script_public_key {
let pk_bytes = pk.as_bytes();
return pk_bytes[0] == P2SH_PREPEND;
}
false
}
}