use amplify::confinement::Confined;
use amplify::Wrapper;
use rgb::bitcoin::Txid;
use rgb::commit_verify::{mpc, Conceal};
use rgb::{
Assign, Assignments, BundleId, ExposedSeal, ExposedState, Genesis, OpId, Operation, Transition,
TransitionBundle, TypedAssigns,
};
#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From)]
#[display(doc_comments)]
pub enum MergeRevealError {
OperationMismatch(OpId, OpId),
SignatureMismatch(OpId),
ChainMismatch { bitcoin: Txid, liquid: Txid },
TxidMismatch(Txid, Txid),
AnchorsNonEqual(BundleId),
AssignmentsDifferentKeys,
#[from(mpc::InvalidProof)]
#[from(mpc::LeafNotKnown)]
ContractMismatch,
}
pub trait MergeReveal {
fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError>;
}
impl<State: ExposedState, Seal: ExposedSeal> MergeReveal for Assign<State, Seal> {
fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError> {
debug_assert_eq!(self.conceal(), other.conceal());
if let Assign::Revealed { .. } = other {
*self = other.clone();
}
Ok(())
}
}
impl<Seal: ExposedSeal> MergeReveal for TypedAssigns<Seal> {
fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError> {
match (self, other) {
(TypedAssigns::Declarative(first_vec), TypedAssigns::Declarative(second_vec)) => {
for (first, second) in first_vec.iter_mut().zip(second_vec.as_ref()) {
first.merge_reveal(second)?;
}
}
(TypedAssigns::Fungible(first_vec), TypedAssigns::Fungible(second_vec)) => {
for (first, second) in first_vec.iter_mut().zip(second_vec.as_ref()) {
first.merge_reveal(second)?;
}
}
(TypedAssigns::Structured(first_vec), TypedAssigns::Structured(second_vec)) => {
for (first, second) in first_vec.iter_mut().zip(second_vec.as_ref()) {
first.merge_reveal(second)?;
}
}
_ => {
unreachable!("Assignments::consensus_commitments is broken")
}
};
Ok(())
}
}
impl<Seal: ExposedSeal> MergeReveal for Assignments<Seal> {
fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError> {
for (ass_type, other_typed_assigns) in other.as_inner().iter() {
let typed_assigns = self
.get_mut(ass_type)
.ok_or(MergeRevealError::AssignmentsDifferentKeys)?;
typed_assigns.merge_reveal(other_typed_assigns)?;
}
Ok(())
}
}
impl MergeReveal for TransitionBundle {
fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError> {
debug_assert_eq!(self.bundle_id(), other.bundle_id());
let mut self_transitions = self.known_transitions.to_unconfined();
for other in &other.known_transitions {
if let Some(kt) = self_transitions.iter_mut().find(|kt| kt.opid == other.opid) {
kt.transition.merge_reveal(&other.transition)?;
} else {
self_transitions.push(other.clone());
}
}
self.known_transitions = Confined::from_checked(self_transitions);
Ok(())
}
}
impl MergeReveal for Genesis {
fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError> {
let self_id = self.id();
let other_id = other.id();
if self_id != other_id {
return Err(MergeRevealError::OperationMismatch(
OpId::from_inner(self_id.into_inner()),
OpId::from_inner(other_id.into_inner()),
));
}
self.assignments.merge_reveal(&other.assignments)?;
Ok(())
}
}
impl MergeReveal for Transition {
fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError> {
let self_id = self.id();
let other_id = other.id();
if self_id != other_id {
return Err(MergeRevealError::OperationMismatch(self_id, other_id));
}
self.assignments.merge_reveal(&other.assignments)?;
match (self.signature.take(), other.signature.as_ref()) {
(None, None) => {}
(Some(sig), None) => {
self.signature = Some(sig);
}
(None, Some(sig)) => {
self.signature = Some(sig.clone());
}
(Some(sig1), Some(sig2)) if sig1 == *sig2 => {
self.signature = Some(sig1);
}
_ => {
return Err(MergeRevealError::SignatureMismatch(self_id));
}
};
Ok(())
}
}