use get_size2::GetSize;
use neptune_primitives::mast_hash::MastHash;
use neptune_primitives::network::Network;
use serde::Deserialize;
use serde::Serialize;
use tasm_lib::prelude::Digest;
use crate::consensus_rule_set::ConsensusRuleSet;
use crate::proof_abstractions::verifier::verify;
use crate::transaction::validity::neptune_proof::NeptuneProof;
use crate::transaction::validity::single_proof::single_proof_claim;
use crate::transaction::BFieldCodec;
use crate::transaction::PrimitiveWitness;
use crate::transaction::ProofCollection;
#[derive(Clone, Debug, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, strum::Display)]
#[cfg_attr(any(test, feature = "arbitrary-impls"), derive(arbitrary::Arbitrary))]
#[repr(u8)]
pub enum TransactionProofType {
PrimitiveWitness = 0,
ProofCollection = 2,
SingleProof = 3,
}
impl From<&TransactionProof> for TransactionProofType {
fn from(proof: &TransactionProof) -> Self {
proof.proof_type()
}
}
impl TransactionProofType {
pub fn executes_in_vm(&self) -> bool {
matches!(self, Self::ProofCollection | Self::SingleProof)
}
pub fn is_single_proof(&self) -> bool {
*self == TransactionProofType::SingleProof
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, GetSize, BFieldCodec)]
pub enum TransactionProof {
Witness(PrimitiveWitness),
SingleProof(NeptuneProof),
ProofCollection(ProofCollection),
}
impl TransactionProof {
pub fn is_witness(&self) -> bool {
matches!(self, Self::Witness(_))
}
pub fn is_proof_collection(&self) -> bool {
matches!(self, Self::ProofCollection(_))
}
pub fn is_single_proof(&self) -> bool {
matches!(self, Self::SingleProof(_))
}
pub fn into_single_proof(self) -> NeptuneProof {
match self {
TransactionProof::SingleProof(proof) => proof,
TransactionProof::Witness(_) => {
panic!("Expected SingleProof, got Witness")
}
TransactionProof::ProofCollection(_) => {
panic!("Expected SingleProof, got ProofCollection")
}
}
}
pub fn as_single_proof(&self) -> Option<NeptuneProof> {
match self {
TransactionProof::Witness(_) => None,
TransactionProof::ProofCollection(_) => None,
TransactionProof::SingleProof(neptune_proof) => Some(neptune_proof.to_owned()),
}
}
pub fn into_primitive_witness(self) -> PrimitiveWitness {
match self {
TransactionProof::Witness(primitive_witness) => primitive_witness,
TransactionProof::SingleProof(_) => {
panic!("Expected primitive witness, got SingleProof")
}
TransactionProof::ProofCollection(_) => {
panic!("Expected primitive witness, got ProofCollection")
}
}
}
pub fn proof_type(&self) -> TransactionProofType {
match self {
TransactionProof::Witness(_) => TransactionProofType::PrimitiveWitness,
TransactionProof::ProofCollection(_) => TransactionProofType::ProofCollection,
TransactionProof::SingleProof(_) => TransactionProofType::SingleProof,
}
}
pub async fn verify(
&self,
kernel_mast_hash: Digest,
network: Network,
consensus_rule_set: ConsensusRuleSet,
) -> bool {
match self {
TransactionProof::Witness(primitive_witness) => {
primitive_witness.validate().await.is_ok()
&& primitive_witness.kernel.mast_hash() == kernel_mast_hash
}
TransactionProof::SingleProof(single_proof) => {
let claim = single_proof_claim(kernel_mast_hash, consensus_rule_set);
verify(claim, single_proof.clone(), network).await
}
TransactionProof::ProofCollection(proof_collection) => {
proof_collection.verify(kernel_mast_hash, network).await
}
}
}
}
#[derive(Debug, Copy, Clone)]
pub enum TransactionProofError {
CannotUpdateProofVariant,
CannotUpdatePrimitiveWitness,
CannotUpdateSingleProof,
ProverLockWasTaken,
}
#[cfg(feature = "mock-rpc")]
impl rand::distr::Distribution<TransactionProofType> for rand::distr::StandardUniform {
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> TransactionProofType {
match rng.random_range(0..3) {
0 => TransactionProofType::PrimitiveWitness,
1 => TransactionProofType::ProofCollection,
2 => TransactionProofType::SingleProof,
_ => unreachable!(),
}
}
}
#[cfg(any(test, feature = "test-helpers"))]
mod test_support {
use tasm_lib::twenty_first::bfe_vec;
use tasm_lib::twenty_first::math::b_field_element::BFieldElement;
use super::*;
impl TransactionProof {
pub fn invalid() -> Self {
Self::SingleProof(NeptuneProof::from(vec![]))
}
pub fn invalid_single_proof_of_size(size: usize) -> Self {
Self::SingleProof(NeptuneProof::from(bfe_vec![0; size]))
}
pub fn into_proof_collection(self) -> ProofCollection {
match self {
TransactionProof::Witness(_primitive_witness) => {
panic!("Expected ProofCollection, got Witness")
}
TransactionProof::SingleProof(_proof) => {
panic!("Expected ProofCollection, got SingleProof")
}
TransactionProof::ProofCollection(proof_collection) => proof_collection,
}
}
}
impl TransactionProofType {
pub fn invalid(self) -> TransactionProof {
match self {
TransactionProofType::PrimitiveWitness => {
TransactionProof::Witness(PrimitiveWitness::invalid())
}
TransactionProofType::ProofCollection => {
TransactionProof::ProofCollection(ProofCollection::invalid())
}
TransactionProofType::SingleProof => {
TransactionProof::SingleProof(NeptuneProof::from(vec![]))
}
}
}
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {}