Skip to content

Commit 592232d

Browse files
committed
Add Redeemer associated type to Verifier trait.
And move ugly repetitive decoding to the executive.
1 parent ec84e43 commit 592232d

File tree

5 files changed

+54
-69
lines changed

5 files changed

+54
-69
lines changed

tuxedo-core/src/executive.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,12 @@ where
7979
let mut missing_inputs = Vec::new();
8080
for input in transaction.inputs.iter() {
8181
if let Some(input_utxo) = TransparentUtxoSet::<V>::peek_utxo(&input.output_ref) {
82+
let redeemer = V::Redeemer::decode(&mut &input.redeemer[..])
83+
.map_err(|_| UtxoError::VerifierError)?;
8284
ensure!(
83-
input_utxo.verifier.verify(
84-
&stripped_encoded,
85-
Self::block_height(),
86-
&input.redeemer
87-
),
85+
input_utxo
86+
.verifier
87+
.verify(&stripped_encoded, Self::block_height(), &redeemer),
8888
UtxoError::VerifierError
8989
);
9090
input_utxos.push(input_utxo);

tuxedo-core/src/verifier.rs

+19-7
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ pub use simple_signature::{Sr25519P2PKH, Sr25519Signature};
2929
/// * An encoded redeemer supplied by the user attempting to spend the input.
3030
/// The redeemer is opaque to the trait and must be interpreted by the implementation.
3131
pub trait Verifier: Debug + Encode + Decode + Clone {
32-
fn verify(&self, simplified_tx: &[u8], block_height: u32, redeemer: &[u8]) -> bool;
32+
/// The type that will be supplied to satisfy the verifier and redeem the UTXO.
33+
type Redeemer: Decode;
34+
35+
/// Main function in the trait. Does the checks to make sure an output can be spent.
36+
fn verify(&self, simplified_tx: &[u8], block_height: u32, redeemer: &Self::Redeemer) -> bool;
3337
}
3438

3539
/// A simple verifier that allows anyone to consume an output at any time
@@ -39,7 +43,9 @@ pub trait Verifier: Debug + Encode + Decode + Clone {
3943
pub struct UpForGrabs;
4044

4145
impl Verifier for UpForGrabs {
42-
fn verify(&self, _simplified_tx: &[u8], __: u32, _: &[u8]) -> bool {
46+
type Redeemer = ();
47+
48+
fn verify(&self, _simplified_tx: &[u8], __: u32, _: &()) -> bool {
4349
true
4450
}
4551
}
@@ -54,11 +60,15 @@ impl Verifier for UpForGrabs {
5460
pub struct Unspendable;
5561

5662
impl Verifier for Unspendable {
57-
fn verify(&self, _simplified_tx: &[u8], __: u32, _: &[u8]) -> bool {
63+
type Redeemer = ();
64+
65+
fn verify(&self, _simplified_tx: &[u8], __: u32, _: &()) -> bool {
5866
false
5967
}
6068
}
6169

70+
// Idea: It could be useful to allow delay deciding whether the redemption should succeed
71+
// until spend-time. In that case you could pass it in as a verifier.
6272
/// A testing verifier that passes or depending on the enclosed
6373
/// boolean value.
6474
#[cfg(feature = "std")]
@@ -70,7 +80,9 @@ pub struct TestVerifier {
7080

7181
#[cfg(feature = "std")]
7282
impl Verifier for TestVerifier {
73-
fn verify(&self, _simplified_tx: &[u8], __: u32, _: &[u8]) -> bool {
83+
type Redeemer = ();
84+
85+
fn verify(&self, _simplified_tx: &[u8], __: u32, _: &()) -> bool {
7486
self.verifies
7587
}
7688
}
@@ -98,18 +110,18 @@ mod test {
98110

99111
#[test]
100112
fn up_for_grabs_always_verifies() {
101-
assert!(UpForGrabs.verify(&[], 0, &[]))
113+
assert!(UpForGrabs.verify(&[], 0, &()))
102114
}
103115

104116
#[test]
105117
fn test_verifier_passes() {
106-
let result = TestVerifier { verifies: true }.verify(&[], 0, &[]);
118+
let result = TestVerifier { verifies: true }.verify(&[], 0, &());
107119
assert!(result);
108120
}
109121

110122
#[test]
111123
fn test_verifier_fails() {
112-
let result = TestVerifier { verifies: false }.verify(&[], 0, &[]);
124+
let result = TestVerifier { verifies: false }.verify(&[], 0, &());
113125
assert!(!result);
114126
}
115127
}

tuxedo-core/src/verifier/htlc.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ pub struct TimeLock {
4242
}
4343

4444
impl Verifier for TimeLock {
45-
fn verify(&self, _: &[u8], block_height: u32, _: &[u8]) -> bool {
45+
type Redeemer = ();
46+
fn verify(&self, _: &[u8], block_height: u32, _: &()) -> bool {
4647
block_height >= self.unlock_block_height
4748
}
4849
}
@@ -64,8 +65,9 @@ impl BlakeTwoHashLock {
6465
}
6566

6667
impl Verifier for BlakeTwoHashLock {
67-
fn verify(&self, _: &[u8], _: u32, redeemer: &[u8]) -> bool {
68-
BlakeTwo256::hash(redeemer) == self.hash_lock
68+
type Redeemer = Vec<u8>;
69+
fn verify(&self, _: &[u8], _: u32, secret: &Self::Redeemer) -> bool {
70+
BlakeTwo256::hash(secret) == self.hash_lock
6971
}
7072
}
7173

@@ -104,11 +106,9 @@ pub enum HtlcSpendPath {
104106
}
105107

106108
impl Verifier for HashTimeLockContract {
107-
fn verify(&self, simplified_tx: &[u8], block_height: u32, redeemer: &[u8]) -> bool {
108-
let Ok(spend_path) = HtlcSpendPath::decode(&mut &redeemer[..]) else {
109-
return false;
110-
};
109+
type Redeemer = HtlcSpendPath;
111110

111+
fn verify(&self, simplified_tx: &[u8], block_height: u32, spend_path: &HtlcSpendPath) -> bool {
112112
match spend_path {
113113
HtlcSpendPath::Claim { secret, signature } => {
114114
// Claims are valid as long as the secret is correct and the receiver signature is correct.
@@ -145,23 +145,23 @@ mod test {
145145
let time_lock = TimeLock {
146146
unlock_block_height: 100,
147147
};
148-
assert!(!time_lock.verify(&[], 10, &[]));
148+
assert!(!time_lock.verify(&[], 10, &()));
149149
}
150150

151151
#[test]
152152
fn time_lock_exactly_on_time() {
153153
let time_lock = TimeLock {
154154
unlock_block_height: 100,
155155
};
156-
assert!(time_lock.verify(&[], 100, &[]));
156+
assert!(time_lock.verify(&[], 100, &()));
157157
}
158158

159159
#[test]
160160
fn time_lock_past_threshold() {
161161
let time_lock = TimeLock {
162162
unlock_block_height: 100,
163163
};
164-
assert!(time_lock.verify(&[], 200, &[]));
164+
assert!(time_lock.verify(&[], 200, &()));
165165
}
166166

167167
#[test]

tuxedo-core/src/verifier/multi_signature.rs

+8-34
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,13 @@ pub struct SignatureAndIndex {
5050
}
5151

5252
impl Verifier for ThresholdMultiSignature {
53-
fn verify(&self, simplified_tx: &[u8], _: u32, redeemer: &[u8]) -> bool {
53+
type Redeemer = Vec<SignatureAndIndex>;
54+
55+
fn verify(&self, simplified_tx: &[u8], _: u32, sigs: &Vec<SignatureAndIndex>) -> bool {
5456
if self.has_duplicate_signatories() {
5557
return false;
5658
}
5759

58-
let sigs = match Vec::<SignatureAndIndex>::decode(&mut &redeemer[..]) {
59-
Ok(s) => s,
60-
Err(_) => return false,
61-
};
62-
6360
if sigs.len() < self.threshold.into() {
6461
return false;
6562
}
@@ -121,13 +118,12 @@ mod test {
121118
})
122119
.collect();
123120

124-
let redeemer: &[u8] = &sigs.encode()[..];
125121
let threshold_multisig = ThresholdMultiSignature {
126122
threshold,
127123
signatories,
128124
};
129125

130-
assert!(threshold_multisig.verify(simplified_tx, 0, redeemer));
126+
assert!(threshold_multisig.verify(simplified_tx, 0, &sigs));
131127
}
132128

133129
#[test]
@@ -148,13 +144,12 @@ mod test {
148144
})
149145
.collect();
150146

151-
let redeemer: &[u8] = &sigs.encode()[..];
152147
let threshold_multisig = ThresholdMultiSignature {
153148
threshold,
154149
signatories,
155150
};
156151

157-
assert!(!threshold_multisig.verify(simplified_tx, 0, redeemer));
152+
assert!(!threshold_multisig.verify(simplified_tx, 0, &sigs));
158153
}
159154

160155
#[test]
@@ -174,13 +169,12 @@ mod test {
174169
})
175170
.collect();
176171

177-
let redeemer: &[u8] = &sigs.encode()[..];
178172
let threshold_multisig = ThresholdMultiSignature {
179173
threshold,
180174
signatories,
181175
};
182176

183-
assert!(threshold_multisig.verify(simplified_tx, 0, redeemer));
177+
assert!(threshold_multisig.verify(simplified_tx, 0, &sigs));
184178
}
185179

186180
#[test]
@@ -203,13 +197,12 @@ mod test {
203197
},
204198
];
205199

206-
let redeemer: &[u8] = &sigs.encode()[..];
207200
let threshold_multisig = ThresholdMultiSignature {
208201
threshold,
209202
signatories,
210203
};
211204

212-
assert!(!threshold_multisig.verify(simplified_tx, 0, redeemer));
205+
assert!(!threshold_multisig.verify(simplified_tx, 0, &sigs));
213206
}
214207

215208
#[test]
@@ -230,31 +223,12 @@ mod test {
230223
index: i.try_into().unwrap(),
231224
})
232225
.collect();
233-
let redeemer: &[u8] = &sigs.encode()[..];
234226

235227
let threshold_multisig = ThresholdMultiSignature {
236228
threshold,
237229
signatories,
238230
};
239231

240-
assert!(!threshold_multisig.verify(simplified_tx, 0, redeemer));
241-
}
242-
243-
#[test]
244-
fn threshold_multisig_bogus_redeemer_encoding_fails() {
245-
use crate::dynamic_typing::testing::Bogus;
246-
247-
let bogus = Bogus;
248-
249-
let threshold_multisig = ThresholdMultiSignature {
250-
threshold: 3,
251-
signatories: vec![],
252-
};
253-
254-
assert!(!threshold_multisig.verify(
255-
b"bogus_message".as_slice(),
256-
0,
257-
bogus.encode().as_slice()
258-
))
232+
assert!(!threshold_multisig.verify(simplified_tx, 0, &sigs));
259233
}
260234
}

tuxedo-core/src/verifier/simple_signature.rs

+12-13
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,10 @@ impl Sr25519Signature {
4343
}
4444

4545
impl Verifier for Sr25519Signature {
46-
fn verify(&self, simplified_tx: &[u8], _: u32, redeemer: &[u8]) -> bool {
47-
let sig = match Signature::try_from(redeemer) {
48-
Ok(s) => s,
49-
Err(_) => return false,
50-
};
46+
type Redeemer = Signature;
5147

52-
sp_io::crypto::sr25519_verify(&sig, simplified_tx, &Public::from_h256(self.owner_pubkey))
48+
fn verify(&self, simplified_tx: &[u8], _: u32, sig: &Signature) -> bool {
49+
sp_io::crypto::sr25519_verify(sig, simplified_tx, &Public::from_h256(self.owner_pubkey))
5350
}
5451
}
5552

@@ -66,9 +63,9 @@ pub struct Sr25519P2PKH {
6663
}
6764

6865
impl Verifier for Sr25519P2PKH {
69-
fn verify(&self, simplified_tx: &[u8], _: u32, redeemer: &[u8]) -> bool {
70-
//TODO verifier trait should have associated type for decoding the redeemer. Otherwise each and every redeemer impl has to do it.
71-
// Decode the redeemer and expect to find both a pubkey and a signature.
66+
type Redeemer = (Public, Signature);
67+
68+
fn verify(&self, simplified_tx: &[u8], _: u32, (pubkey, signature): &Self::Redeemer) -> bool {
7269
// Check that the hash stored matches the pubkey given.
7370
// Check that the signature given is valid over the tx from the pubkey given.
7471
todo!()
@@ -85,24 +82,26 @@ mod test {
8582
let pair = Pair::from_seed(&[0u8; 32]);
8683
let simplified_tx = b"hello world".as_slice();
8784
let sig = pair.sign(simplified_tx);
88-
let redeemer: &[u8] = sig.as_ref();
8985

9086
let sr25519_signature = Sr25519Signature {
9187
owner_pubkey: pair.public().into(),
9288
};
9389

94-
assert!(sr25519_signature.verify(simplified_tx, 0, redeemer));
90+
assert!(sr25519_signature.verify(simplified_tx, 0, &sig));
9591
}
9692

9793
#[test]
9894
fn sr25519_signature_with_bad_sig() {
9995
let simplified_tx = b"hello world".as_slice();
100-
let redeemer = b"bogus_signature".as_slice();
96+
let bad_sig = Signature::from_slice(
97+
b"bogus_signature_bogus_signature_bogus_signature_bogus_signature!".as_slice(),
98+
)
99+
.expect("Should be able to create a bogus signature.");
101100

102101
let sr25519_signature = Sr25519Signature {
103102
owner_pubkey: H256::zero(),
104103
};
105104

106-
assert!(!sr25519_signature.verify(simplified_tx, 0, redeemer));
105+
assert!(!sr25519_signature.verify(simplified_tx, 0, &bad_sig));
107106
}
108107
}

0 commit comments

Comments
 (0)