use secp256k1::PublicKey;
use secp256k1::SecretKey;
use crate::clarity;
use crate::clarity::Codec;
use crate::crypto::c32::Mode;
use crate::crypto::SignatureHash;
use crate::transaction::auth::AUTH_TYPE_SPONSORED;
use crate::transaction::auth::AUTH_TYPE_STANDARD;
use crate::transaction::Auth;
use crate::transaction::ChainID;
use crate::transaction::Error;
use crate::transaction::Modification;
use crate::transaction::Payload;
use crate::transaction::PostConditionMode;
use crate::transaction::PostConditions;
use crate::transaction::SpendingCondition;
use crate::transaction::TransactionVersion;
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum AnchorMode {
Strict = 0x01,
Micro = 0x02,
Any = 0x03,
}
#[derive(Debug, Clone)]
pub struct Transaction {
pub version: TransactionVersion,
pub chain_id: ChainID,
pub auth: Auth,
pub anchor_mode: AnchorMode,
pub post_condition_mode: PostConditionMode,
pub post_conditions: PostConditions,
pub payload: Box<dyn Payload>,
}
impl Transaction {
pub fn new(
version: TransactionVersion,
chain_id: ChainID,
auth: Auth,
anchor_mode: AnchorMode,
post_condition_mode: PostConditionMode,
post_conditions: PostConditions,
payload: Box<dyn Payload>,
) -> Self {
Self {
version,
chain_id,
auth,
anchor_mode,
post_condition_mode,
post_conditions,
payload,
}
}
pub fn hash(&self) -> Result<SignatureHash, Error> {
let bytes = self.encode()?;
Ok(SignatureHash::from_slice(bytes))
}
pub fn set_fee(&mut self, fee: u64) {
self.auth.set_fee(fee);
}
pub fn set_nonce(&mut self, nonce: u64) {
self.auth.set_nonce(nonce);
}
pub(crate) fn verify_origin(&self) -> Result<SignatureHash, Error> {
self.auth.verify_origin(self.initial_hash()?)
}
pub(crate) fn initial_hash(&self) -> Result<SignatureHash, Error> {
let mut tx = self.clone();
tx.auth = tx.auth.reset();
tx.hash()
}
pub(crate) fn sign_next_origin(
&mut self,
hash: SignatureHash,
pk: SecretKey,
) -> Result<SignatureHash, Error> {
Self::sign_and_append(self.auth.origin_mut(), hash, AUTH_TYPE_STANDARD, pk)
}
pub(crate) fn sign_next_sponsor(
&mut self,
hash: SignatureHash,
pk: SecretKey,
) -> Result<SignatureHash, Error> {
Self::sign_and_append(self.auth.sponsor_mut()?, hash, AUTH_TYPE_SPONSORED, pk)
}
pub(crate) fn append_next_origin(&mut self, pk: PublicKey) -> Result<(), Error> {
let origin = self.auth.origin_mut();
match origin.mode() {
Mode::P2SH | Mode::P2WSH => origin.modify(Modification::AddPublicKey(pk)),
Mode::P2PKH | Mode::P2WPKH => Err(Error::BadSpendingConditionModification),
}
}
pub(crate) fn sign_and_append(
condition: &mut dyn SpendingCondition,
hash: SignatureHash,
auth: u8,
pk: SecretKey,
) -> Result<SignatureHash, Error> {
let (sig, hash) =
SignatureHash::next_signature(hash, auth, condition.fee(), condition.nonce(), pk)?;
match condition.mode() {
Mode::P2PKH | Mode::P2WPKH => {
condition.modify(Modification::SetSignature(sig))?;
}
Mode::P2SH | Mode::P2WSH => {
condition.modify(Modification::AddSignature(sig))?;
}
}
Ok(hash)
}
}
impl Codec for Transaction {
fn encode(&self) -> Result<Vec<u8>, clarity::Error> {
let mut buffer = vec![];
buffer.push(self.version as u8);
buffer.extend_from_slice(&(self.chain_id as u32).to_be_bytes());
buffer.extend_from_slice(&self.auth.encode()?);
buffer.push(self.anchor_mode as u8);
buffer.push(self.post_condition_mode as u8);
buffer.extend_from_slice(&self.post_conditions.encode()?);
buffer.extend_from_slice(&self.payload.encode()?);
Ok(buffer)
}
#[allow(unused_variables)]
fn decode(bytes: &[u8]) -> Result<Self, clarity::Error>
where
Self: Sized,
{
unimplemented!()
}
}