urma-runtime 0.2.0

URMA publication planning, network transports and recovery
Documentation
use crate::error::{Context, Error, ensure};
use crate::reveal;
use crate::transaction::transaction;
use bitcoin::{
    Amount, OutPoint, ScriptBuf, Transaction, TxOut,
    secp256k1::{Keypair, Secp256k1},
    taproot::TaprootSpendInfo,
};
use rand::{CryptoRng, RngCore};
use urma_core::envelope;

pub(crate) struct PreparedReveal {
    signer: Keypair,
    script: ScriptBuf,
    info: TaprootSpendInfo,
    pub fee: u64,
    retained: u64,
}
impl PreparedReveal {
    pub fn new<R: RngCore + CryptoRng>(
        record: &[u8],
        payout: &ScriptBuf,
        rate: u64,
        retained: u64,
        rng: &mut R,
    ) -> Result<Self, Error> {
        let signer = Keypair::new(&Secp256k1::new(), rng);
        let (script, info) = envelope::build(record, &signer)?;
        let preview = reveal::preview(
            TxOut {
                value: Amount::from_sat(retained),
                script_pubkey: payout.clone(),
            },
            &script,
            &info,
        )?;
        let fee = reveal::fee(&preview, rate)?;
        Ok(Self {
            signer,
            script,
            info,
            fee,
            retained,
        })
    }
    pub fn output(&self) -> TxOut {
        TxOut {
            value: Amount::from_sat(self.retained + self.fee),
            script_pubkey: ScriptBuf::new_p2tr_tweaked(self.info.output_key()),
        }
    }
    pub fn sign(
        self,
        commit: &Transaction,
        vout: u32,
        payout: &ScriptBuf,
    ) -> Result<Transaction, Error> {
        let output = commit
            .output
            .get(usize::try_from(vout)?)
            .context("missing commit output")?;
        ensure!(
            *output == self.output(),
            "commit output changed before signing"
        );
        let mut tx = transaction(
            OutPoint {
                txid: commit.compute_txid(),
                vout,
            },
            TxOut {
                value: Amount::from_sat(self.retained),
                script_pubkey: payout.clone(),
            },
        );
        let signature = Secp256k1::new()
            .sign_schnorr_no_aux_rand(&reveal::digest(&tx, output, &self.script)?, &self.signer);
        tx.input[0].witness = envelope::witness(signature.as_ref(), &self.script, &self.info)?;
        Ok(tx)
    }
}