refactor(swap-db): Extract intermediate Alice/Bob storage state machine type (#636)

This commit is contained in:
Mohan 2025-10-21 21:15:52 +02:00 committed by GitHub
parent 3eaeeede45
commit 22dd8dd052
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 111 additions and 62 deletions

20
swap-db/Cargo.toml Normal file
View file

@ -0,0 +1,20 @@
[package]
name = "swap-db"
version = "0.1.0"
edition = "2024"
[dependencies]
# Our crates
swap-core = { path = "../swap-core" }
swap-machine = { path = "../swap-machine" }
swap-serde = { path = "../swap-serde" }
# Crypto
bitcoin = { workspace = true }
# Serialization
serde = { workspace = true }
strum = { workspace = true, features = ["derive"] }
[lints]
workspace = true

347
swap-db/src/alice.rs Normal file
View file

@ -0,0 +1,347 @@
use serde::{Deserialize, Serialize};
use std::fmt;
use swap_core::bitcoin::EncryptedSignature;
use swap_core::monero;
use swap_core::monero::{BlockHeight, TransferProof};
use swap_machine::alice;
use swap_machine::alice::AliceState;
// Large enum variant is fine because this is only used for database
// and is dropped once written in DB.
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub enum Alice {
Started {
state3: alice::State3,
},
BtcLockTransactionSeen {
state3: alice::State3,
},
BtcLocked {
state3: alice::State3,
},
XmrLockTransactionSent {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
XmrLocked {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
XmrLockTransferProofSent {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
EncSigLearned {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
encrypted_signature: EncryptedSignature,
state3: alice::State3,
},
BtcRedeemTransactionPublished {
state3: alice::State3,
transfer_proof: TransferProof,
},
CancelTimelockExpired {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
BtcCancelled {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
BtcPunishable {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
BtcEarlyRefundable {
state3: alice::State3,
},
BtcRefunded {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
#[serde(with = "swap_serde::monero::private_key")]
spend_key: monero::PrivateKey,
},
Done(AliceEndState),
}
#[derive(Clone, strum::Display, Debug, Deserialize, Serialize, PartialEq)]
pub enum AliceEndState {
SafelyAborted,
BtcRedeemed,
XmrRefunded,
BtcEarlyRefunded {
state3: alice::State3,
},
BtcPunished {
state3: alice::State3,
transfer_proof: TransferProof,
},
}
impl From<AliceState> for Alice {
fn from(alice_state: AliceState) -> Self {
match alice_state {
AliceState::Started { state3 } => Alice::Started {
state3: state3.as_ref().clone(),
},
AliceState::BtcLockTransactionSeen { state3 } => Alice::BtcLockTransactionSeen {
state3: state3.as_ref().clone(),
},
AliceState::BtcLocked { state3 } => Alice::BtcLocked {
state3: state3.as_ref().clone(),
},
AliceState::XmrLockTransactionSent {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => Alice::XmrLockTransactionSent {
monero_wallet_restore_blockheight,
transfer_proof,
state3: state3.as_ref().clone(),
},
AliceState::XmrLocked {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => Alice::XmrLocked {
monero_wallet_restore_blockheight,
transfer_proof,
state3: state3.as_ref().clone(),
},
AliceState::XmrLockTransferProofSent {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => Alice::XmrLockTransferProofSent {
monero_wallet_restore_blockheight,
transfer_proof,
state3: state3.as_ref().clone(),
},
AliceState::EncSigLearned {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
encrypted_signature,
} => Alice::EncSigLearned {
monero_wallet_restore_blockheight,
transfer_proof,
state3: state3.as_ref().clone(),
encrypted_signature: encrypted_signature.as_ref().clone(),
},
AliceState::BtcRedeemTransactionPublished {
state3,
transfer_proof,
} => Alice::BtcRedeemTransactionPublished {
state3: state3.as_ref().clone(),
transfer_proof,
},
AliceState::BtcRedeemed => Alice::Done(AliceEndState::BtcRedeemed),
AliceState::BtcCancelled {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => Alice::BtcCancelled {
monero_wallet_restore_blockheight,
transfer_proof,
state3: state3.as_ref().clone(),
},
AliceState::BtcRefunded {
monero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3,
} => Alice::BtcRefunded {
monero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3: state3.as_ref().clone(),
},
AliceState::BtcEarlyRefundable { state3 } => Alice::BtcEarlyRefundable {
state3: state3.as_ref().clone(),
},
AliceState::BtcEarlyRefunded(state3) => Alice::Done(AliceEndState::BtcEarlyRefunded {
state3: state3.as_ref().clone(),
}),
AliceState::BtcPunishable {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => Alice::BtcPunishable {
monero_wallet_restore_blockheight,
transfer_proof,
state3: state3.as_ref().clone(),
},
AliceState::XmrRefunded => Alice::Done(AliceEndState::XmrRefunded),
AliceState::CancelTimelockExpired {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => Alice::CancelTimelockExpired {
monero_wallet_restore_blockheight,
transfer_proof,
state3: state3.as_ref().clone(),
},
AliceState::BtcPunished {
state3,
transfer_proof,
} => Alice::Done(AliceEndState::BtcPunished {
state3: state3.as_ref().clone(),
transfer_proof,
}),
AliceState::SafelyAborted => Alice::Done(AliceEndState::SafelyAborted),
}
}
}
impl From<Alice> for AliceState {
fn from(db_state: Alice) -> Self {
match db_state {
Alice::Started { state3 } => AliceState::Started {
state3: Box::new(state3),
},
Alice::BtcLockTransactionSeen { state3 } => AliceState::BtcLockTransactionSeen {
state3: Box::new(state3),
},
Alice::BtcLocked { state3 } => AliceState::BtcLocked {
state3: Box::new(state3),
},
Alice::XmrLockTransactionSent {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::XmrLockTransactionSent {
monero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::XmrLocked {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::XmrLocked {
monero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::XmrLockTransferProofSent {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::XmrLockTransferProofSent {
monero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::EncSigLearned {
monero_wallet_restore_blockheight,
transfer_proof,
state3: state,
encrypted_signature,
} => AliceState::EncSigLearned {
monero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state),
encrypted_signature: Box::new(encrypted_signature),
},
Alice::BtcRedeemTransactionPublished {
state3,
transfer_proof,
} => AliceState::BtcRedeemTransactionPublished {
state3: Box::new(state3),
transfer_proof,
},
Alice::CancelTimelockExpired {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::CancelTimelockExpired {
monero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::BtcCancelled {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::BtcCancelled {
monero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::BtcPunishable {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::BtcPunishable {
monero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::BtcRefunded {
monero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3,
} => AliceState::BtcRefunded {
monero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3: Box::new(state3),
},
Alice::BtcEarlyRefundable { state3 } => AliceState::BtcEarlyRefundable {
state3: Box::new(state3),
},
Alice::Done(end_state) => match end_state {
AliceEndState::SafelyAborted => AliceState::SafelyAborted,
AliceEndState::BtcRedeemed => AliceState::BtcRedeemed,
AliceEndState::XmrRefunded => AliceState::XmrRefunded,
AliceEndState::BtcPunished {
state3,
transfer_proof,
} => AliceState::BtcPunished {
state3: Box::new(state3),
transfer_proof,
},
AliceEndState::BtcEarlyRefunded { state3 } => {
AliceState::BtcEarlyRefunded(Box::new(state3))
}
},
}
}
}
impl fmt::Display for Alice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Alice::Started { .. } => write!(f, "Started"),
Alice::BtcLockTransactionSeen { .. } => {
write!(f, "Bitcoin lock transaction in mempool")
}
Alice::BtcLocked { .. } => f.write_str("Bitcoin locked"),
Alice::XmrLockTransactionSent { .. } => f.write_str("Monero lock transaction sent"),
Alice::XmrLocked { .. } => f.write_str("Monero locked"),
Alice::XmrLockTransferProofSent { .. } => {
f.write_str("Monero lock transfer proof sent")
}
Alice::EncSigLearned { .. } => f.write_str("Encrypted signature learned"),
Alice::BtcRedeemTransactionPublished { .. } => {
f.write_str("Bitcoin redeem transaction published")
}
Alice::CancelTimelockExpired { .. } => f.write_str("Cancel timelock is expired"),
Alice::BtcCancelled { .. } => f.write_str("Bitcoin cancel transaction published"),
Alice::BtcPunishable { .. } => f.write_str("Bitcoin punishable"),
Alice::BtcRefunded { .. } => f.write_str("Monero refundable"),
Alice::BtcEarlyRefundable { .. } => f.write_str("Bitcoin early refundable"),
Alice::Done(end_state) => write!(f, "Done: {}", end_state),
}
}
}

194
swap-db/src/bob.rs Normal file
View file

@ -0,0 +1,194 @@
use serde::{Deserialize, Serialize};
use std::fmt;
use swap_core::monero::{BlockHeight, TransferProof};
use swap_machine::bob;
use swap_machine::bob::BobState;
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub enum Bob {
Started {
#[serde(with = "::bitcoin::amount::serde::as_sat")]
btc_amount: bitcoin::Amount,
#[serde(with = "swap_serde::bitcoin::address_serde")]
change_address: bitcoin::Address,
tx_lock_fee: bitcoin::Amount,
},
ExecutionSetupDone {
state2: bob::State2,
},
BtcLockReadyToPublish {
btc_lock_tx_signed: bitcoin::Transaction,
state3: bob::State3,
monero_wallet_restore_blockheight: BlockHeight,
},
BtcLocked {
state3: bob::State3,
monero_wallet_restore_blockheight: BlockHeight,
},
XmrLockProofReceived {
state: bob::State3,
lock_transfer_proof: TransferProof,
monero_wallet_restore_blockheight: BlockHeight,
},
XmrLocked {
state4: bob::State4,
},
EncSigSent {
state4: bob::State4,
},
BtcPunished {
state: bob::State6,
tx_lock_id: bitcoin::Txid,
},
BtcRedeemed(bob::State5),
CancelTimelockExpired(bob::State6),
BtcCancelled(bob::State6),
BtcRefundPublished(bob::State6),
BtcEarlyRefundPublished(bob::State6),
Done(BobEndState),
}
#[derive(Clone, strum::Display, Debug, Deserialize, Serialize, PartialEq)]
pub enum BobEndState {
SafelyAborted,
XmrRedeemed { tx_lock_id: bitcoin::Txid },
BtcRefunded(Box<bob::State6>),
BtcEarlyRefunded(Box<bob::State6>),
}
impl From<BobState> for Bob {
fn from(bob_state: BobState) -> Self {
match bob_state {
BobState::Started {
btc_amount,
change_address,
tx_lock_fee,
} => Bob::Started {
btc_amount,
change_address,
tx_lock_fee,
},
BobState::SwapSetupCompleted(state2) => Bob::ExecutionSetupDone { state2 },
BobState::BtcLockReadyToPublish {
btc_lock_tx_signed,
state3,
monero_wallet_restore_blockheight,
} => Bob::BtcLockReadyToPublish {
btc_lock_tx_signed,
state3,
monero_wallet_restore_blockheight,
},
BobState::BtcLocked {
state3,
monero_wallet_restore_blockheight,
} => Bob::BtcLocked {
state3,
monero_wallet_restore_blockheight,
},
BobState::XmrLockProofReceived {
state,
lock_transfer_proof,
monero_wallet_restore_blockheight,
} => Bob::XmrLockProofReceived {
state,
lock_transfer_proof,
monero_wallet_restore_blockheight,
},
BobState::XmrLocked(state4) => Bob::XmrLocked { state4 },
BobState::EncSigSent(state4) => Bob::EncSigSent { state4 },
BobState::BtcRedeemed(state5) => Bob::BtcRedeemed(state5),
BobState::CancelTimelockExpired(state6) => Bob::CancelTimelockExpired(state6),
BobState::BtcCancelled(state6) => Bob::BtcCancelled(state6),
BobState::BtcRefundPublished(state6) => Bob::BtcRefundPublished(state6),
BobState::BtcEarlyRefundPublished(state6) => Bob::BtcEarlyRefundPublished(state6),
BobState::BtcPunished { state, tx_lock_id } => Bob::BtcPunished { state, tx_lock_id },
BobState::BtcRefunded(state6) => Bob::Done(BobEndState::BtcRefunded(Box::new(state6))),
BobState::XmrRedeemed { tx_lock_id } => {
Bob::Done(BobEndState::XmrRedeemed { tx_lock_id })
}
BobState::BtcEarlyRefunded(state6) => {
Bob::Done(BobEndState::BtcEarlyRefunded(Box::new(state6)))
}
BobState::SafelyAborted => Bob::Done(BobEndState::SafelyAborted),
}
}
}
impl From<Bob> for BobState {
fn from(db_state: Bob) -> Self {
match db_state {
Bob::Started {
btc_amount,
change_address,
tx_lock_fee,
} => BobState::Started {
btc_amount,
change_address,
tx_lock_fee,
},
Bob::ExecutionSetupDone { state2 } => BobState::SwapSetupCompleted(state2),
Bob::BtcLockReadyToPublish {
btc_lock_tx_signed,
state3,
monero_wallet_restore_blockheight,
} => BobState::BtcLockReadyToPublish {
btc_lock_tx_signed,
state3,
monero_wallet_restore_blockheight,
},
Bob::BtcLocked {
state3,
monero_wallet_restore_blockheight,
} => BobState::BtcLocked {
state3,
monero_wallet_restore_blockheight,
},
Bob::XmrLockProofReceived {
state,
lock_transfer_proof,
monero_wallet_restore_blockheight,
} => BobState::XmrLockProofReceived {
state,
lock_transfer_proof,
monero_wallet_restore_blockheight,
},
Bob::XmrLocked { state4 } => BobState::XmrLocked(state4),
Bob::EncSigSent { state4 } => BobState::EncSigSent(state4),
Bob::BtcRedeemed(state5) => BobState::BtcRedeemed(state5),
Bob::CancelTimelockExpired(state6) => BobState::CancelTimelockExpired(state6),
Bob::BtcCancelled(state6) => BobState::BtcCancelled(state6),
Bob::BtcRefundPublished(state6) => BobState::BtcRefundPublished(state6),
Bob::BtcEarlyRefundPublished(state6) => BobState::BtcEarlyRefundPublished(state6),
Bob::BtcPunished { state, tx_lock_id } => BobState::BtcPunished { state, tx_lock_id },
Bob::Done(end_state) => match end_state {
BobEndState::SafelyAborted => BobState::SafelyAborted,
BobEndState::XmrRedeemed { tx_lock_id } => BobState::XmrRedeemed { tx_lock_id },
BobEndState::BtcRefunded(state6) => BobState::BtcRefunded(*state6),
BobEndState::BtcEarlyRefunded(state6) => BobState::BtcEarlyRefunded(*state6),
},
}
}
}
impl fmt::Display for Bob {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Bob::Started { .. } => write!(f, "Started"),
Bob::ExecutionSetupDone { .. } => f.write_str("Execution setup done"),
Bob::BtcLockReadyToPublish { .. } => f.write_str("Bitcoin lock ready to publish"),
Bob::BtcLocked { .. } => f.write_str("Bitcoin locked"),
Bob::XmrLockProofReceived { .. } => {
f.write_str("XMR lock transaction transfer proof received")
}
Bob::XmrLocked { .. } => f.write_str("Monero locked"),
Bob::CancelTimelockExpired(_) => f.write_str("Cancel timelock is expired"),
Bob::BtcCancelled(_) => f.write_str("Bitcoin refundable"),
Bob::BtcRefundPublished { .. } => f.write_str("Bitcoin refund published"),
Bob::BtcEarlyRefundPublished { .. } => f.write_str("Bitcoin early refund published"),
Bob::BtcRedeemed(_) => f.write_str("Monero redeemable"),
Bob::Done(end_state) => write!(f, "Done: {}", end_state),
Bob::EncSigSent { .. } => f.write_str("Encrypted signature sent"),
Bob::BtcPunished { .. } => f.write_str("Bitcoin punished"),
}
}
}

2
swap-db/src/lib.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod alice;
pub mod bob;