use super::{
keys::{PublicKey, Signature, SignatureShare},
money::Money,
utils, Error, Result,
};
use crdts::Dot;
use serde::{Deserialize, Serialize};
use std::fmt::{self, Debug, Display, Formatter};
use threshold_crypto::PublicKeySet;
use tiny_keccak::sha3_256;
pub type DebitId = Dot<PublicKey>;
pub type CreditId = [u8; 256 / 8];
pub type Msg = String;
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct WalletInfo {
pub replicas: PublicKeySet,
pub history: ActorHistory,
}
#[derive(Clone, Hash, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Debug)]
pub struct Transfer {
pub amount: Money,
pub to: PublicKey,
pub debit_id: DebitId,
pub msg: Msg,
}
impl Transfer {
pub fn debit(&self) -> Debit {
Debit {
id: self.debit_id,
amount: self.amount,
}
}
pub fn credit(&self) -> Result<Credit> {
Ok(Credit {
id: self.debit().credit_id()?,
amount: self.amount,
recipient: self.to,
msg: self.msg.to_string(),
})
}
}
#[derive(Clone, Hash, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Debug)]
pub struct Debit {
pub id: DebitId,
pub amount: Money,
}
impl Debit {
pub fn id(&self) -> DebitId {
self.id
}
pub fn amount(&self) -> Money {
self.amount
}
pub fn sender(&self) -> PublicKey {
self.id.actor
}
pub fn credit_id(&self) -> Result<CreditId> {
Ok(sha3_256(&utils::serialise(&self.id)?))
}
}
#[derive(Clone, Hash, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Debug)]
pub struct Credit {
pub id: CreditId,
pub amount: Money,
pub recipient: PublicKey,
pub msg: Msg,
}
impl Credit {
pub fn id(&self) -> &CreditId {
&self.id
}
pub fn amount(&self) -> Money {
self.amount
}
pub fn recipient(&self) -> PublicKey {
self.recipient
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct ActorHistory {
pub credits: Vec<CreditAgreementProof>,
pub debits: Vec<TransferAgreementProof>,
}
impl ActorHistory {
pub fn empty() -> Self {
Self {
credits: vec![],
debits: vec![],
}
}
pub fn is_empty(&self) -> bool {
self.credits.is_empty() && self.debits.is_empty()
}
pub fn len(&self) -> usize {
self.credits.len() + self.debits.len()
}
}
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct CreditAgreementProof {
pub signed_credit: SignedCredit,
pub debiting_replicas_sig: Signature,
pub debiting_replicas_keys: ReplicaPublicKeySet,
}
impl Debug for CreditAgreementProof {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "CreditAgreementProof::")?;
write!(formatter, "Credit({})", self.signed_credit.amount())?;
write!(formatter, "ActorSignature::")?;
Debug::fmt(&self.signed_credit.actor_signature, formatter)?;
write!(formatter, "ReplicaSignature::")?;
Debug::fmt(&self.debiting_replicas_sig, formatter)
}
}
impl Display for CreditAgreementProof {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
Debug::fmt(self, formatter)
}
}
impl CreditAgreementProof {
pub fn id(&self) -> &CreditId {
self.signed_credit.id()
}
pub fn amount(&self) -> Money {
self.signed_credit.amount()
}
pub fn recipient(&self) -> PublicKey {
self.signed_credit.recipient()
}
pub fn replica_keys(&self) -> ReplicaPublicKeySet {
self.debiting_replicas_keys.clone()
}
}
#[derive(Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Debug)]
pub struct TransferAgreementProof {
pub signed_debit: SignedDebit,
pub signed_credit: SignedCredit,
pub debit_sig: Signature,
pub credit_sig: Signature,
pub debiting_replicas_keys: ReplicaPublicKeySet,
}
impl TransferAgreementProof {
pub fn id(&self) -> DebitId {
self.signed_debit.id()
}
pub fn amount(&self) -> Money {
self.signed_debit.amount()
}
pub fn sender(&self) -> PublicKey {
self.signed_debit.sender()
}
pub fn recipient(&self) -> PublicKey {
self.signed_credit.recipient()
}
pub fn replica_keys(&self) -> ReplicaPublicKeySet {
self.debiting_replicas_keys.clone()
}
pub fn credit_proof(&self) -> CreditAgreementProof {
CreditAgreementProof {
signed_credit: self.signed_credit.clone(),
debiting_replicas_sig: self.credit_sig.clone(),
debiting_replicas_keys: self.replica_keys(),
}
}
}
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
pub struct SignedTransfer {
pub debit: SignedDebit,
pub credit: SignedCredit,
}
impl SignedTransfer {
pub fn id(&self) -> DebitId {
self.debit.id()
}
pub fn amount(&self) -> Money {
self.debit.amount()
}
pub fn sender(&self) -> PublicKey {
self.debit.id().actor
}
pub fn credit_id(&self) -> Result<CreditId> {
self.debit.credit_id()
}
}
#[derive(Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Debug)]
pub struct SignedDebit {
pub debit: Debit,
pub actor_signature: Signature,
}
impl SignedDebit {
pub fn id(&self) -> DebitId {
self.debit.id()
}
pub fn amount(&self) -> Money {
self.debit.amount()
}
pub fn sender(&self) -> PublicKey {
self.debit.sender()
}
pub fn credit_id(&self) -> Result<CreditId> {
self.debit.credit_id()
}
pub fn as_share(&self) -> Result<SignedDebitShare> {
if let Signature::BlsShare(share) = self.actor_signature.clone() {
Ok(SignedDebitShare {
debit: self.debit.clone(),
actor_signature: share,
})
} else {
Err(Error::InvalidSignature)
}
}
}
#[derive(Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Debug)]
pub struct SignedCredit {
pub credit: Credit,
pub actor_signature: Signature,
}
impl SignedCredit {
pub fn id(&self) -> &CreditId {
self.credit.id()
}
pub fn amount(&self) -> Money {
self.credit.amount
}
pub fn recipient(&self) -> PublicKey {
self.credit.recipient()
}
pub fn as_share(&self) -> Result<SignedCreditShare> {
if let Signature::BlsShare(share) = self.actor_signature.clone() {
Ok(SignedCreditShare {
credit: self.credit.clone(),
actor_signature: share,
})
} else {
Err(Error::InvalidSignature)
}
}
}
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
pub struct SignedTransferShare {
debit: SignedDebitShare,
credit: SignedCreditShare,
actors: PublicKeySet,
}
impl SignedTransferShare {
pub fn new(
debit: SignedDebitShare,
credit: SignedCreditShare,
actors: PublicKeySet,
) -> Result<Self> {
if debit.amount() != credit.amount() {
return Err(Error::InvalidOperation);
}
if debit.credit_id()? != *credit.id() {
return Err(Error::InvalidOperation);
}
let debit_sig_index = debit.actor_signature.index;
let credit_sig_index = credit.actor_signature.index;
if debit_sig_index != credit_sig_index {
return Err(Error::InvalidOperation);
}
Ok(Self {
debit,
credit,
actors,
})
}
pub fn id(&self) -> DebitId {
self.debit.id()
}
pub fn amount(&self) -> Money {
self.debit.amount()
}
pub fn sender(&self) -> PublicKey {
self.debit.id().actor
}
pub fn credit_id(&self) -> Result<CreditId> {
self.debit.credit_id()
}
pub fn debit(&self) -> &SignedDebitShare {
&self.debit
}
pub fn credit(&self) -> &SignedCreditShare {
&self.credit
}
pub fn share_index(&self) -> usize {
self.debit.actor_signature.index
}
pub fn actors(&self) -> &PublicKeySet {
&self.actors
}
}
#[derive(Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Debug)]
pub struct SignedDebitShare {
pub debit: Debit,
pub actor_signature: SignatureShare,
}
impl SignedDebitShare {
pub fn id(&self) -> DebitId {
self.debit.id()
}
pub fn amount(&self) -> Money {
self.debit.amount()
}
pub fn sender(&self) -> PublicKey {
self.debit.sender()
}
pub fn credit_id(&self) -> Result<CreditId> {
self.debit.credit_id()
}
pub fn share_index(&self) -> usize {
self.actor_signature.index
}
}
#[derive(Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Debug)]
pub struct SignedCreditShare {
pub credit: Credit,
pub actor_signature: SignatureShare,
}
impl SignedCreditShare {
pub fn id(&self) -> &CreditId {
self.credit.id()
}
pub fn amount(&self) -> Money {
self.credit.amount
}
pub fn recipient(&self) -> PublicKey {
self.credit.recipient()
}
pub fn share_index(&self) -> usize {
self.actor_signature.index
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
pub enum ReplicaEvent {
TransferValidationProposed(TransferValidationProposed),
TransferValidated(TransferValidated),
TransferRegistered(TransferRegistered),
TransferPropagated(TransferPropagated),
}
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
pub struct TransferValidationProposed {
pub signed_debit: SignedDebitShare,
pub signed_credit: SignedCreditShare,
pub agreed_transfer: Option<SignedTransfer>,
}
impl TransferValidationProposed {
pub fn id(&self) -> DebitId {
self.signed_debit.id()
}
pub fn amount(&self) -> Money {
self.signed_debit.amount()
}
pub fn sender(&self) -> PublicKey {
self.signed_debit.sender()
}
pub fn recipient(&self) -> PublicKey {
self.signed_credit.recipient()
}
}
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
pub struct TransferValidated {
pub signed_debit: SignedDebit,
pub signed_credit: SignedCredit,
pub replica_debit_sig: SignatureShare,
pub replica_credit_sig: SignatureShare,
pub replicas: PublicKeySet,
}
impl TransferValidated {
pub fn id(&self) -> DebitId {
self.signed_debit.id()
}
pub fn amount(&self) -> Money {
self.signed_debit.amount()
}
pub fn sender(&self) -> PublicKey {
self.signed_debit.sender()
}
pub fn recipient(&self) -> PublicKey {
self.signed_credit.recipient()
}
}
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
pub struct TransferRegistered {
pub transfer_proof: TransferAgreementProof,
}
impl TransferRegistered {
pub fn id(&self) -> DebitId {
self.transfer_proof.id()
}
pub fn amount(&self) -> Money {
self.transfer_proof.amount()
}
pub fn sender(&self) -> PublicKey {
self.transfer_proof.sender()
}
pub fn recipient(&self) -> PublicKey {
self.transfer_proof.recipient()
}
}
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
pub struct TransferPropagated {
pub credit_proof: CreditAgreementProof,
pub crediting_replica_sig: SignatureShare,
pub crediting_replica_keys: PublicKey,
}
impl TransferPropagated {
pub fn id(&self) -> &CreditId {
self.credit_proof.id()
}
pub fn amount(&self) -> Money {
self.credit_proof.amount()
}
pub fn recipient(&self) -> PublicKey {
self.credit_proof.recipient()
}
}
pub type ReplicaPublicKeySet = PublicKeySet;
#[derive(Clone, Hash, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Debug)]
pub struct KnownGroupAdded {
pub group: PublicKeySet,
}
#[derive(Eq, PartialEq, Clone, Serialize, Deserialize, Debug)]
pub struct CreditNotification(pub CreditAgreementProof);