use core::ops::AddAssign;
use std::collections::{HashMap, HashSet};
use std::fmt::{self, Display, Formatter};
use aluvm::library::LibId;
use amplify::num::u24;
use bitcoin::{OutPoint, Txid};
use strict_types::{SemId, Ty};
use crate::commit_verify::mpc::InvalidProof;
use crate::schema::{self, SchemaId};
use crate::seals::txout::CloseMethod;
use crate::validation::OpoutsDagData;
use crate::vm::WitnessOrd;
use crate::{
BundleId, ChainNet, ContractId, OccurrencesMismatch, OpFullType, OpId, Opout,
SealClosingStrategy, StateType,
};
pub type UnsafeHistoryMap = HashMap<u32, HashSet<Txid>>;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Display)]
#[repr(u8)]
pub enum Validity {
#[display("is valid")]
Valid,
#[display("valid, with warnings")]
Warnings,
}
#[derive(Clone, Debug, Default)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename_all = "camelCase")
)]
pub struct Status {
pub warnings: Vec<Warning>,
pub info: Vec<Info>,
pub tx_ord_map: HashMap<Txid, WitnessOrd>,
pub dag_data_opt: Option<OpoutsDagData>,
}
impl Display for Status {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if f.alternate() {
writeln!(f, "Consignment {}", self.validity())?;
}
if !self.warnings.is_empty() {
f.write_str("Validation warnings:\n")?;
for warn in &self.warnings {
writeln!(f, "- {warn}")?;
}
}
if !self.info.is_empty() {
f.write_str("Validation info:\n")?;
for info in &self.info {
writeln!(f, "- {info}")?;
}
}
Ok(())
}
}
impl AddAssign for Status {
fn add_assign(&mut self, rhs: Self) {
self.warnings.extend(rhs.warnings);
self.info.extend(rhs.info);
}
}
impl Status {
pub fn new() -> Self { Self::default() }
pub fn add_warning(&mut self, warning: impl Into<Warning>) -> &Self {
self.warnings.push(warning.into());
self
}
pub fn add_info(&mut self, info: impl Into<Info>) -> &Self {
self.info.push(info.into());
self
}
pub fn validity(&self) -> Validity {
if !self.warnings.is_empty() {
Validity::Warnings
} else {
Validity::Valid
}
}
}
#[derive(Clone, PartialEq, Eq, Debug, Display, From)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename_all = "camelCase")
)]
#[display(doc_comments)]
pub enum Failure {
ContractChainNetMismatch(ChainNet),
ResolverChainNetMismatch(ChainNet),
SchemaMismatch {
expected: SchemaId,
actual: SchemaId,
},
TypeSystemMismatch(SemId, Box<Option<Ty<SemId>>>, Box<Ty<SemId>>),
SchemaGlobalSemIdUnknown(schema::GlobalStateType, SemId),
SchemaOwnedSemIdUnknown(schema::AssignmentType, SemId),
SchemaMetaSemIdUnknown(schema::MetaType, SemId),
SchemaOpEmptyInputs(OpFullType),
SchemaOpMetaTypeUnknown(OpFullType, schema::MetaType),
SchemaOpGlobalTypeUnknown(OpFullType, schema::GlobalStateType),
SchemaOpAssignmentTypeUnknown(OpFullType, schema::AssignmentType),
SchemaUnknownTransitionType(OpId, schema::TransitionType),
SchemaUnknownMetaType(OpId, schema::MetaType),
SchemaUnknownGlobalStateType(OpId, schema::GlobalStateType),
SchemaUnknownAssignmentType(OpId, schema::AssignmentType),
SchemaUnknownSealClosingStrategy(OpId, SealClosingStrategy),
SchemaGlobalStateOccurrences(OpId, schema::GlobalStateType, OccurrencesMismatch),
SchemaGlobalStateLimit(OpId, schema::GlobalStateType, u16, u24),
SchemaNoMetadata(OpId, schema::MetaType),
SchemaInvalidMetadata(OpId, SemId),
SchemaInvalidGlobalValue(OpId, schema::GlobalStateType, SemId),
SchemaInvalidOwnedValue(OpId, schema::AssignmentType, SemId),
SchemaInputOccurrences(OpId, schema::AssignmentType, OccurrencesMismatch),
SchemaAssignmentOccurrences(OpId, schema::AssignmentType, OccurrencesMismatch),
CyclicGraph(Opout),
ContractMismatch(OpId, ContractId),
TransitionIdMismatch(OpId, OpId),
WitnessMissingInput(BundleId, OutPoint, Txid),
InputMapTransitionMismatch(BundleId, OpId, Opout),
NoPrevState(OpId, Opout),
SealNoPubWitness(BundleId, Txid),
SealsInvalid(BundleId, Txid, String),
MpcInvalid(BundleId, Txid, Box<InvalidProof>),
NoDbcOutput(Txid),
InvalidProofType(Txid, CloseMethod),
StateTypeMismatch {
opid: OpId,
state_type: schema::AssignmentType,
expected: StateType,
found: StateType,
},
FungibleTypeMismatch {
opid: OpId,
state_type: schema::AssignmentType,
expected: schema::FungibleType,
found: schema::FungibleType,
},
ScriptFailure(OpId, Option<u8>, Option<String>),
ContractStateFilled(OpId),
MissingScript(OpId, LibId),
ScriptIDMismatch(OpId, LibId, LibId),
#[display(inner)]
Custom(String),
}
#[derive(Clone, PartialEq, Eq, Debug, Display, From)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename_all = "camelCase")
)]
#[display(doc_comments)]
pub enum Warning {
UnsafeHistory(UnsafeHistoryMap),
#[display(inner)]
Custom(String),
}
#[derive(Clone, PartialEq, Eq, Debug, Display, From)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename_all = "camelCase")
)]
#[display(doc_comments)]
pub enum Info {
#[display(inner)]
Custom(String),
}