use std::collections::BTreeMap;
use amplify::confinement::Confined;
use amplify::Wrapper;
use bp::dbc::anchor::MergeError;
use commit_verify::{mpc, CommitmentId};
use rgb::{
Anchor, AnchoredBundle, Assign, Assignments, BundleItem, ExposedSeal, ExposedState, Extension,
Genesis, OpId, Transition, TransitionBundle, TypedAssigns,
};
#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From)]
#[display(doc_comments)]
pub enum MergeRevealError {
OperationMismatch(OpId, OpId),
#[from]
#[display(inner)]
AnchorMismatch(MergeError),
}
pub trait MergeReveal: Sized {
fn merge_reveal(self, other: Self) -> Result<Self, MergeRevealError>;
}
impl MergeReveal for Anchor<mpc::MerkleBlock> {
fn merge_reveal(self, other: Self) -> Result<Self, MergeRevealError> {
self.merge_reveal(other).map_err(MergeRevealError::from)
}
}
impl<State: ExposedState, Seal: ExposedSeal> MergeReveal for Assign<State, Seal> {
fn merge_reveal(self, other: Self) -> Result<Self, MergeRevealError> {
match (self, other) {
(_, state @ Assign::Revealed { .. }) | (state @ Assign::Revealed { .. }, _) => {
Ok(state)
}
(Assign::ConfidentialSeal { state, .. }, Assign::ConfidentialState { seal, .. }) => {
Ok(Assign::Revealed { seal, state })
}
(Assign::ConfidentialState { seal, .. }, Assign::ConfidentialSeal { state, .. }) => {
Ok(Assign::Revealed { seal, state })
}
(state @ Assign::ConfidentialState { .. }, Assign::ConfidentialState { .. }) => {
Ok(state)
}
(state @ Assign::ConfidentialSeal { .. }, Assign::ConfidentialSeal { .. }) => Ok(state),
(state, Assign::Confidential { .. }) | (Assign::Confidential { .. }, state) => {
Ok(state)
}
}
}
}
impl<Seal: ExposedSeal> MergeReveal for TypedAssigns<Seal> {
fn merge_reveal(self, other: Self) -> Result<Self, MergeRevealError> {
match (self, other) {
(TypedAssigns::Declarative(first_vec), TypedAssigns::Declarative(second_vec)) => {
let mut result = Vec::with_capacity(first_vec.len());
for (first, second) in first_vec.into_iter().zip(second_vec.into_iter()) {
result.push(first.merge_reveal(second)?);
}
Ok(TypedAssigns::Declarative(
Confined::try_from(result).expect("collection of the same size"),
))
}
(TypedAssigns::Fungible(first_vec), TypedAssigns::Fungible(second_vec)) => {
let mut result = Vec::with_capacity(first_vec.len());
for (first, second) in first_vec.into_iter().zip(second_vec.into_iter()) {
result.push(first.merge_reveal(second)?);
}
Ok(TypedAssigns::Fungible(
Confined::try_from(result).expect("collection of the same size"),
))
}
(TypedAssigns::Structured(first_vec), TypedAssigns::Structured(second_vec)) => {
let mut result = Vec::with_capacity(first_vec.len());
for (first, second) in first_vec.into_iter().zip(second_vec.into_iter()) {
result.push(first.merge_reveal(second)?);
}
Ok(TypedAssigns::Structured(
Confined::try_from(result).expect("collection of the same size"),
))
}
(TypedAssigns::Attachment(first_vec), TypedAssigns::Attachment(second_vec)) => {
let mut result = Vec::with_capacity(first_vec.len());
for (first, second) in first_vec.into_iter().zip(second_vec.into_iter()) {
result.push(first.merge_reveal(second)?);
}
Ok(TypedAssigns::Attachment(
Confined::try_from(result).expect("collection of the same size"),
))
}
_ => {
unreachable!("Assignments::consensus_commitments is broken")
}
}
}
}
impl<Seal: ExposedSeal> MergeReveal for Assignments<Seal> {
fn merge_reveal(self, other: Self) -> Result<Self, MergeRevealError> {
let mut result = BTreeMap::new();
for (first, second) in self
.into_inner()
.into_iter()
.zip(other.into_inner().into_iter())
{
debug_assert_eq!(first.0, second.0);
result.insert(first.0, first.1.merge_reveal(second.1)?);
}
Ok(Assignments::from_inner(
Confined::try_from(result).expect("collection of the same size"),
))
}
}
impl MergeReveal for BundleItem {
fn merge_reveal(mut self, other: Self) -> Result<Self, MergeRevealError> {
debug_assert_eq!(self.inputs, other.inputs);
if self.transition.is_none() {
self.transition = other.transition
}
Ok(self)
}
}
impl MergeReveal for TransitionBundle {
fn merge_reveal(self, other: Self) -> Result<Self, MergeRevealError> {
debug_assert_eq!(self.commitment_id(), other.commitment_id());
let mut result = BTreeMap::new();
for (first, second) in self
.into_inner()
.into_iter()
.zip(other.into_inner().into_iter())
{
debug_assert_eq!(first.0, second.0);
result.insert(first.0, first.1.merge_reveal(second.1)?);
}
Ok(TransitionBundle::from_inner(
Confined::try_from(result).expect("collection of the same size"),
))
}
}
impl MergeReveal for AnchoredBundle {
fn merge_reveal(self, other: Self) -> Result<Self, MergeRevealError> {
Ok(AnchoredBundle {
anchor: self.anchor, bundle: self.bundle.merge_reveal(other.bundle)?,
})
}
}
impl MergeReveal for Genesis {
fn merge_reveal(mut self, other: Self) -> Result<Self, MergeRevealError> {
let self_id = self.commitment_id();
let other_id = other.commitment_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 = self.assignments.merge_reveal(other.assignments)?;
Ok(self)
}
}
impl MergeReveal for Transition {
fn merge_reveal(mut self, other: Self) -> Result<Self, MergeRevealError> {
let self_id = self.commitment_id();
let other_id = other.commitment_id();
if self_id != other_id {
return Err(MergeRevealError::OperationMismatch(self_id, other_id));
}
self.assignments = self.assignments.merge_reveal(other.assignments)?;
Ok(self)
}
}
impl MergeReveal for Extension {
fn merge_reveal(mut self, other: Self) -> Result<Self, MergeRevealError> {
let self_id = self.commitment_id();
let other_id = other.commitment_id();
if self_id != other_id {
return Err(MergeRevealError::OperationMismatch(self_id, other_id));
}
self.assignments = self.assignments.merge_reveal(other.assignments)?;
Ok(self)
}
}