Skip to content

Commit bda0cc4

Browse files
authored
refactor: reverse trait system (#255)
* refactor: remove serde feature gate first step to refactor serde in this library. * refactor: remove unnecessary trait bonds on FeeStrat. * fix: remove optional serde to fix compilation * refactor: simplify crypto types Simplify trait bounds on TaggedElement and take direct generic on AccordantKeys and AccordandKeySet instead of nested generic. * feat: add more primitive derives * doc: fix missing link * refactor: rename accordant keys fields * feat: add serde derive on remaining types * refactor: script types to disentangle generics * refactor: new protocol mod and message generics Move protocol_message into the new protocol module. Modify the generic argument to split the context into multiple generic. Add more derives on types. This commit prepare the removing of bundles from core. They are in fact messages created inside node already. It also prepare the migration of execution logic on Alice and Bob into the new protocol module. * refactor: migrate protocol execution logic Alice and Bob logic is migrated into protocol module. * refactor(lib)!: refactor all traits in lib This huge refactor rework all the trait system used in the library to push types to the surface instead of having one context: Swap. This allows more flexibility but refactor is not completly done, some trait should be removed and some should be split, e.g. crypto::Sign, to allow less generics in protocol functions. This refactor allows proper implementation/derivation on messages that are used in node and passed over the network. * re-enable taproot module * ci: fix test unknown serde feat * chore: remove commented bundles * chore: remove commented code * fix: reimplement Encodable/Decodable on Bob
1 parent 908905b commit bda0cc4

35 files changed

Lines changed: 3298 additions & 3824 deletions

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434

3535
- uses: Swatinem/rust-cache@v1.4.0
3636

37-
- run: cargo test --features serde --verbose
37+
- run: cargo test --verbose
3838

3939
rpc-test:
4040
name: Integration tests

Cargo.toml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ rust-version = "1.56.1"
2525
rpc = []
2626
experimental = ["ecdsa_fun", "secp256kfun", "rand", "sha2", "rand_chacha", "bincode"]
2727
taproot = []
28-
serde = ["serde_crate", "bitcoin/use-serde", "monero/serde_support", "inet2_addr/serde"]
2928

3029
default = ["experimental", "taproot"]
3130

@@ -36,9 +35,9 @@ bitcoin_hashes = { version = "0.10" }
3635
bitvec = { version = "1.0" }
3736
fixed-hash = { version = "0.7", default-features = false }
3837
hex = "0.4"
39-
inet2_addr = { version = "0.6", default-features = false, features = ["tor", "strict_encoding"] }
38+
inet2_addr = { version = "0.6", default-features = false, features = ["tor", "strict_encoding", "serde"] }
4039
lightning_encoding = "0.6"
41-
serde_crate = { package = "serde", version = "1", features = ["derive"], optional = true }
40+
serde = { version = "1", features = ["derive"] }
4241
strict_encoding = "1.8"
4342
strict_encoding_derive = "1.7"
4443
thiserror = "1"
@@ -47,7 +46,7 @@ tiny-keccak = { version = "2", features = ["keccak"] }
4746
# crypto libs
4847

4948
bincode = { version = "1", optional = true }
50-
curve25519-dalek = "3"
49+
curve25519-dalek = { version = "3", features = ["serde"] }
5150
ecdsa_fun = { git = "https://github.com/farcaster-project/secp256kfun.git", branch = "secp256k1/0.22", default-features = false, features = ["all"], optional = true }
5251
rand = { version = "0.8.4", optional = true }
5352
rand_alt = { package = "rand", version = "0.7.3", features = ["std"] }
@@ -57,8 +56,8 @@ sha2 = { version = "0.9", optional = true }
5756
sha3 = "0.10"
5857

5958
# blockchain specific
60-
bitcoin = "0.28.0"
61-
monero = { version = "0.16" }
59+
bitcoin = { version = "0.28", features = ["use-serde"] }
60+
monero = { version = "0.17", features = ["serde"] }
6261

6362
[dev-dependencies]
6463
bitcoincore-rpc = "0.15"

src/bitcoin/fee.rs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use std::str::FromStr;
3232
/// An amount of Bitcoin (internally in satoshis) representing the number of satoshis per virtual
3333
/// byte a transaction must use for its fee. A [`FeeStrategy`] can use one of more of this type
3434
/// depending of its complexity (fixed, range, etc).
35-
#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Display)]
35+
#[derive(Debug, Clone, Copy, PartialOrd, PartialEq, Eq, Display)]
3636
#[display(display_sats_per_vbyte)]
3737
pub struct SatPerVByte(Amount);
3838

@@ -117,22 +117,24 @@ fn get_available_input_sat(tx: &PartiallySignedTransaction) -> Result<Amount, Fe
117117
))
118118
}
119119

120-
impl<S: Strategy> Fee for Bitcoin<S> {
120+
impl Fee for PartiallySignedTransaction {
121121
type FeeUnit = SatPerVByte;
122122

123+
type Amount = Amount;
124+
123125
/// Calculates and sets the fees on the given transaction and return the fees set
124126
fn set_fee(
125-
tx: &mut PartiallySignedTransaction,
127+
&mut self,
126128
strategy: &FeeStrategy<SatPerVByte>,
127129
politic: FeePriority,
128-
) -> Result<Amount, FeeStrategyError> {
129-
if tx.unsigned_tx.output.len() != 1 {
130+
) -> Result<Self::Amount, FeeStrategyError> {
131+
if self.unsigned_tx.output.len() != 1 {
130132
return Err(FeeStrategyError::new(
131133
transaction::Error::MultiUTXOUnsuported,
132134
));
133135
}
134136

135-
let input_sum = get_available_input_sat(tx)?;
137+
let input_sum = get_available_input_sat(self)?;
136138

137139
// FIXME This does not account for witnesses
138140
// currently the fees are wrong
@@ -142,7 +144,7 @@ impl<S: Strategy> Fee for Bitcoin<S> {
142144
// times four. For transactions with a witness, this is the non-witness
143145
// consensus-serialized size multiplied by three plus the with-witness consensus-serialized
144146
// size.
145-
let weight = tx.unsigned_tx.weight() as u64;
147+
let weight = self.unsigned_tx.weight() as u64;
146148

147149
// Compute the fee amount to set in total
148150
let fee_amount = match strategy {
@@ -155,7 +157,7 @@ impl<S: Strategy> Fee for Bitcoin<S> {
155157
.ok_or(FeeStrategyError::AmountOfFeeTooHigh)?;
156158

157159
// Apply the fee on the first output
158-
tx.unsigned_tx.output[0].value = input_sum
160+
self.unsigned_tx.output[0].value = input_sum
159161
.checked_sub(fee_amount)
160162
.ok_or(FeeStrategyError::NotEnoughAssets)?
161163
.as_sat();
@@ -165,22 +167,19 @@ impl<S: Strategy> Fee for Bitcoin<S> {
165167
}
166168

167169
/// Validates that the fees for the given transaction are set accordingly to the strategy
168-
fn validate_fee(
169-
tx: &PartiallySignedTransaction,
170-
strategy: &FeeStrategy<SatPerVByte>,
171-
) -> Result<bool, FeeStrategyError> {
172-
if tx.unsigned_tx.output.len() != 1 {
170+
fn validate_fee(&self, strategy: &FeeStrategy<SatPerVByte>) -> Result<bool, FeeStrategyError> {
171+
if self.unsigned_tx.output.len() != 1 {
173172
return Err(FeeStrategyError::new(
174173
transaction::Error::MultiUTXOUnsuported,
175174
));
176175
}
177176

178-
let input_sum = get_available_input_sat(tx)?.as_sat();
179-
let output_sum = tx.unsigned_tx.output[0].value;
177+
let input_sum = get_available_input_sat(self)?.as_sat();
178+
let output_sum = self.unsigned_tx.output[0].value;
180179
let fee = input_sum
181180
.checked_sub(output_sum)
182181
.ok_or(FeeStrategyError::AmountOfFeeTooHigh)?;
183-
let weight = tx.unsigned_tx.weight() as u64;
182+
let weight = self.unsigned_tx.weight() as u64;
184183

185184
let effective_sat_per_vbyte = SatPerVByte::from_sat(
186185
weight

src/bitcoin/segwitv0.rs

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,19 @@ use crate::bitcoin::transaction::TxInRef;
1111
use crate::bitcoin::transaction::{MetadataOutput, Tx};
1212
use crate::bitcoin::{Bitcoin, BitcoinSegwitV0, Btc, Strategy};
1313

14+
use crate::bitcoin::timelock::CSVTimelock;
1415
use crate::blockchain::Transactions;
1516
use crate::consensus::{self, CanonicalBytes};
16-
use crate::crypto::{Keys, SharedKeyId, SharedSecretKeys, Signatures};
17-
use crate::role::{Arbitrating, SwapRole};
17+
use crate::crypto::{DeriveKeys, SharedKeyId, Signatures};
18+
use crate::role::SwapRole;
1819
use crate::script::{DataLock, DataPunishableLock, DoubleKeys, ScriptPath};
1920

2021
use bitcoin::blockdata::opcodes;
2122
use bitcoin::blockdata::script::{Builder, Instruction, Script};
2223
use bitcoin::blockdata::transaction::EcdsaSighashType;
2324
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
2425
use bitcoin::secp256k1::{ecdsa::Signature, Message, PublicKey, Secp256k1, SecretKey, Signing};
26+
use bitcoin::util::psbt::PartiallySignedTransaction;
2527
use bitcoin::util::sighash::SighashCache;
2628

2729
use ecdsa_fun::adaptor::EncryptedSignature;
@@ -86,20 +88,20 @@ pub struct CoopLock {
8688
}
8789

8890
impl CoopLock {
89-
pub fn script(data: DataLock<BitcoinSegwitV0>) -> Script {
91+
pub fn script(data: DataLock<CSVTimelock, PublicKey>) -> Script {
9092
let DataLock {
9193
success: DoubleKeys { alice, bob },
9294
..
9395
} = data;
9496
Builder::new()
95-
.push_key(&bitcoin::util::key::PublicKey::new(*alice))
97+
.push_key(&bitcoin::util::key::PublicKey::new(alice))
9698
.push_opcode(opcodes::all::OP_CHECKSIGVERIFY)
97-
.push_key(&bitcoin::util::key::PublicKey::new(*bob))
99+
.push_key(&bitcoin::util::key::PublicKey::new(bob))
98100
.push_opcode(opcodes::all::OP_CHECKSIG)
99101
.into_script()
100102
}
101103

102-
pub fn v0_p2wsh(data: DataLock<BitcoinSegwitV0>) -> Script {
104+
pub fn v0_p2wsh(data: DataLock<CSVTimelock, PublicKey>) -> Script {
103105
Self::script(data).to_v0_p2wsh()
104106
}
105107

@@ -177,29 +179,29 @@ pub struct PunishLock {
177179
}
178180

179181
impl PunishLock {
180-
pub fn script(data: DataPunishableLock<BitcoinSegwitV0>) -> Script {
182+
pub fn script(data: DataPunishableLock<CSVTimelock, PublicKey>) -> Script {
181183
let DataPunishableLock {
182184
timelock,
183185
success: DoubleKeys { alice, bob },
184186
failure,
185187
} = data;
186188
Builder::new()
187189
.push_opcode(opcodes::all::OP_IF)
188-
.push_key(&bitcoin::util::key::PublicKey::new(*alice))
190+
.push_key(&bitcoin::util::key::PublicKey::new(alice))
189191
.push_opcode(opcodes::all::OP_CHECKSIGVERIFY)
190-
.push_key(&bitcoin::util::key::PublicKey::new(*bob))
192+
.push_key(&bitcoin::util::key::PublicKey::new(bob))
191193
.push_opcode(opcodes::all::OP_CHECKSIG)
192194
.push_opcode(opcodes::all::OP_ELSE)
193195
.push_int(timelock.as_u32().into())
194196
.push_opcode(opcodes::all::OP_CSV)
195197
.push_opcode(opcodes::all::OP_DROP)
196-
.push_key(&bitcoin::util::key::PublicKey::new(*failure))
198+
.push_key(&bitcoin::util::key::PublicKey::new(failure))
197199
.push_opcode(opcodes::all::OP_CHECKSIG)
198200
.push_opcode(opcodes::all::OP_ENDIF)
199201
.into_script()
200202
}
201203

202-
pub fn v0_p2wsh(data: DataPunishableLock<BitcoinSegwitV0>) -> Script {
204+
pub fn v0_p2wsh(data: DataPunishableLock<CSVTimelock, PublicKey>) -> Script {
203205
Self::script(data).to_v0_p2wsh()
204206
}
205207

@@ -336,7 +338,7 @@ impl PunishLock {
336338
}
337339
}
338340

339-
impl Arbitrating for Bitcoin<SegwitV0> {}
341+
//impl Arbitrating for Bitcoin<SegwitV0> {}
340342

341343
impl TryFrom<Btc> for Bitcoin<SegwitV0> {
342344
type Error = consensus::Error;
@@ -350,7 +352,15 @@ impl TryFrom<Btc> for Bitcoin<SegwitV0> {
350352
}
351353

352354
impl Transactions for Bitcoin<SegwitV0> {
353-
type Metadata = MetadataOutput;
355+
type Addr = bitcoin::Address;
356+
type Amt = bitcoin::Amount;
357+
type Tx = bitcoin::Transaction;
358+
type Px = PartiallySignedTransaction;
359+
type Out = MetadataOutput;
360+
type Ti = CSVTimelock;
361+
type Ms = Sha256dHash;
362+
type Pk = PublicKey;
363+
type Si = Signature;
354364

355365
type Funding = Funding;
356366
type Lock = Tx<Lock>;
@@ -360,14 +370,19 @@ impl Transactions for Bitcoin<SegwitV0> {
360370
type Punish = Tx<Punish>;
361371
}
362372

363-
impl Keys for Bitcoin<SegwitV0> {
364-
type SecretKey = SecretKey;
373+
impl DeriveKeys for Bitcoin<SegwitV0> {
365374
type PublicKey = PublicKey;
375+
type PrivateKey = SecretKey;
366376

367-
fn extra_keys() -> Vec<u16> {
377+
fn extra_public_keys() -> Vec<u16> {
368378
// No extra key
369379
vec![]
370380
}
381+
382+
fn extra_shared_private_keys() -> Vec<SharedKeyId> {
383+
// No shared key in Bitcoin, transparent ledger
384+
vec![]
385+
}
371386
}
372387

373388
impl CanonicalBytes for SecretKey {
@@ -383,28 +398,6 @@ impl CanonicalBytes for SecretKey {
383398
}
384399
}
385400

386-
impl CanonicalBytes for PublicKey {
387-
fn as_canonical_bytes(&self) -> Vec<u8> {
388-
self.serialize().as_ref().into()
389-
}
390-
391-
fn from_canonical_bytes(bytes: &[u8]) -> Result<Self, consensus::Error>
392-
where
393-
Self: Sized,
394-
{
395-
PublicKey::from_slice(bytes).map_err(consensus::Error::new)
396-
}
397-
}
398-
399-
impl SharedSecretKeys for Bitcoin<SegwitV0> {
400-
type SharedSecretKey = SecretKey;
401-
402-
fn shared_keys() -> Vec<SharedKeyId> {
403-
// No shared key in Bitcoin, transparent ledger
404-
vec![]
405-
}
406-
}
407-
408401
impl Signatures for Bitcoin<SegwitV0> {
409402
type Message = Sha256dHash;
410403
type Signature = Signature;

src/bitcoin/segwitv0/buy.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,20 @@ use std::marker::PhantomData;
33
use bitcoin::blockdata::transaction::{TxIn, TxOut};
44
use bitcoin::blockdata::witness::Witness;
55
use bitcoin::secp256k1::ecdsa::Signature;
6+
use bitcoin::secp256k1::PublicKey;
67
use bitcoin::util::ecdsa::EcdsaSig;
78
use bitcoin::util::psbt::PartiallySignedTransaction;
89
use bitcoin::Address;
10+
use bitcoin::Amount;
11+
use bitcoin::Transaction;
912

1013
use crate::role::SwapRole;
1114
use crate::script;
1215
use crate::transaction::{Buyable, Error as FError, Lockable};
1316

17+
use crate::bitcoin::segwitv0::Sha256dHash;
1418
use crate::bitcoin::segwitv0::{CoopLock, SegwitV0};
19+
use crate::bitcoin::timelock::CSVTimelock;
1520
use crate::bitcoin::transaction::{Error, MetadataOutput, SubTransaction, Tx};
1621
use crate::bitcoin::Bitcoin;
1722

@@ -53,10 +58,32 @@ impl SubTransaction for Buy {
5358
}
5459
}
5560

56-
impl Buyable<Bitcoin<SegwitV0>, MetadataOutput> for Tx<Buy> {
61+
impl
62+
Buyable<
63+
Address,
64+
Transaction,
65+
PartiallySignedTransaction,
66+
MetadataOutput,
67+
Amount,
68+
CSVTimelock,
69+
Sha256dHash,
70+
PublicKey,
71+
Signature,
72+
> for Tx<Buy>
73+
{
5774
fn initialize(
58-
prev: &impl Lockable<Bitcoin<SegwitV0>, MetadataOutput>,
59-
_lock: script::DataLock<Bitcoin<SegwitV0>>,
75+
prev: &impl Lockable<
76+
Address,
77+
Transaction,
78+
PartiallySignedTransaction,
79+
MetadataOutput,
80+
Amount,
81+
CSVTimelock,
82+
Sha256dHash,
83+
PublicKey,
84+
Signature,
85+
>,
86+
_lock: script::DataLock<CSVTimelock, PublicKey>,
6087
destination_target: Address,
6188
) -> Result<Self, FError> {
6289
let output_metadata = prev.get_consumable_output()?;

0 commit comments

Comments
 (0)