3
3
use libfuzzer_sys:: fuzz_target;
4
4
use std:: collections:: { BTreeMap , VecDeque } ;
5
5
6
- use bdk_wallet:: { bitcoin:: Network , chain:: TxUpdate , CreateParams , KeychainKind , Update , Wallet } ;
7
- use bdk_wallet_fuzz:: utils:: * ;
8
-
9
- // testnet descriptors
6
+ use bdk_wallet:: {
7
+ bitcoin:: { Network , Txid } ,
8
+ chain:: TxUpdate ,
9
+ descriptor:: DescriptorError ,
10
+ KeychainKind , Update , Wallet ,
11
+ } ;
12
+ use bdk_wallet_fuzz:: fuzz_utils:: * ;
13
+
14
+ // descriptors
10
15
const INTERNAL_DESCRIPTOR : & str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)" ;
11
16
const EXTERNAL_DESCRIPTOR : & str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)" ;
12
17
13
- // mainnet descriptors
14
- // const INTERNAL_DESCRIPTOR: &str = "wpkh(xprv9y5m1SxNcjAY8DJPHqXM67ETRFwpjsacG9xGBiTBMj5A2KupsjuNJuFuFJAzoQJb7fjp3jz78TsmDmqpaTtCBzAKEuqE1NMC3Net5Ma2hY6/84'/1'/0'/0/*)";
15
- // const EXTERNAL_DESCRIPTOR: &str = "wpkh(xprv9y5m1SxNcjAY8DJPHqXM67ETRFwpjsacG9xGBiTBMj5A2KupsjuNJuFuFJAzoQJb7fjp3jz78TsmDmqpaTtCBzAKEuqE1NMC3Net5Ma2hY6/84'/1'/0'/1/*)";
16
-
17
- // testnet
18
+ // network
18
19
const NETWORK : Network = Network :: Testnet ;
19
20
20
- // mainnet
21
- // const NETWORK = Network::Testnet;
22
-
23
21
fuzz_target ! ( |data: & [ u8 ] | {
24
- // let data_iter = data.iter();
25
- let params = CreateParams :: new( INTERNAL_DESCRIPTOR , EXTERNAL_DESCRIPTOR ) . network( NETWORK ) ;
26
- let mut wallet = match Wallet :: create_with_params( params) {
22
+ // creates initial wallet.
23
+ let wallet: Result <Wallet , DescriptorError > =
24
+ Wallet :: create( INTERNAL_DESCRIPTOR , EXTERNAL_DESCRIPTOR )
25
+ . network( NETWORK )
26
+ . create_wallet_no_persist( ) ;
27
+
28
+ // asserts that the wallet creation did not fail.
29
+ let mut wallet = match wallet {
27
30
Ok ( wallet) => wallet,
28
- Err ( _) => panic! ( ) ,
31
+ Err ( _) => return ,
29
32
} ;
30
33
31
- let mut unconfirmed_txids = VecDeque :: new( ) ;
32
-
33
- // fuzzed code goes here
34
+ // fuzzed code goes here.
35
+ let mut new_data = data;
34
36
35
- // fuzz test wallet updates
37
+ // generated fuzzed keychain indices.
38
+ // let keychain = wallet.keychains().map(|(k, _)| k).collect();
39
+ let internal_indices = consume_keychain_indices( & mut new_data, KeychainKind :: Internal ) ;
40
+ let external_indices = consume_keychain_indices( & mut new_data, KeychainKind :: External ) ;
41
+ let mut last_active_indices: BTreeMap <KeychainKind , u32 > = BTreeMap :: new( ) ;
42
+ last_active_indices. extend( internal_indices) ;
43
+ last_active_indices. extend( external_indices) ;
36
44
37
- // start with active indices.
38
- let mut last_active_indices = BTreeMap :: new( ) ;
39
- last_active_indices. extend( get_last_active_indices( data, KeychainKind :: Internal ) ) ;
40
- last_active_indices. extend( get_last_active_indices( data, KeychainKind :: External ) ) ;
45
+ // generate fuzzed tx update.
46
+ let txs = consume_txs( data, & mut wallet) ;
41
47
42
- // generate the txs for the tx graph
43
- let txs = get_txs( data, & mut wallet) ;
44
- let _ = txs
45
- . iter( )
46
- . map( |tx| unconfirmed_txids. push_back( tx. compute_txid( ) ) ) ;
48
+ let unconfirmed_txids: VecDeque <Txid > = txs. iter( ) . map( |tx| tx. compute_txid( ) ) . collect( ) ;
47
49
48
- let txouts = get_txouts( data) ;
49
-
50
- let anchors = get_anchors( data, unconfirmed_txids. clone( ) ) ;
51
- // if let Some(txid) = unconfirmed_txids.pop_front() {
52
- // anchors.insert((anchor, txid));
53
- // };
54
-
55
- let seen_ats = get_seen_ats( data, unconfirmed_txids. clone( ) ) ;
56
- let evicted_ats = get_evicted_ats( data, unconfirmed_txids) ;
50
+ let txouts = consume_txouts( data) ;
51
+ let anchors = consume_anchors( data, unconfirmed_txids. clone( ) ) ;
52
+ let seen_ats = consume_seen_ats( data, unconfirmed_txids. clone( ) ) ;
53
+ let evicted_ats = consume_evicted_ats( data, unconfirmed_txids. clone( ) ) ;
57
54
58
55
// build the tx update with fuzzed data
59
56
let mut tx_update = TxUpdate :: default ( ) ;
@@ -63,108 +60,15 @@ fuzz_target!(|data: &[u8]| {
63
60
tx_update. seen_ats = seen_ats;
64
61
tx_update. evicted_ats = evicted_ats;
65
62
66
- // generate the chain/checkpoints
67
-
68
- let chain = get_checkpoint( data) ;
63
+ // generate fuzzed chain.
64
+ let chain = consume_checkpoint( data, & mut wallet) ;
69
65
66
+ // apply fuzzed update.
70
67
let update = Update {
71
68
last_active_indices,
72
- tx_update: tx_update ,
73
- chain: chain,
69
+ tx_update,
70
+ chain: Some ( chain) ,
74
71
} ;
75
72
76
- match wallet. apply_update( update. clone( ) ) {
77
- Ok ( _result) => {
78
- // println!("{:#?}", update);
79
- // println!("successfully updated wallet")
80
- }
81
- Err ( e) => {
82
- // println!("{:#?}", update)
83
- }
84
- } ;
73
+ wallet. apply_update( update) . unwrap( ) ;
85
74
} ) ;
86
-
87
- // let txouts_count = *next_or_return!(data_iter) as usize;
88
- // let mut txouts = BTreeMap::new();
89
- // for _ in 0..txouts_count {
90
- // let outpoint = bitcoin::OutPoint::new(
91
- // unique_hash.get_txid(),
92
- // *next_or_return!(data_iter) as u32,
93
- // );
94
- // let amount = *next_or_return!(data_iter) as u64 * 1_000;
95
- // let value = bitcoin::Amount::from_sat(amount);
96
- // txouts.insert(
97
- // outpoint,
98
- // bitcoin::TxOut {
99
- // value,
100
- // script_pubkey: Default::default(),
101
- // },
102
- // );
103
- // }
104
-
105
- // let mut anchors = BTreeSet::new();
106
- // while next_or_return!(data_iter) & 0x01 == 0x01 {
107
- // let height = scale(*next_or_return!(data_iter));
108
- // let hash = unique_hash.get_block_hash();
109
- // let block_id = BlockId { height, hash };
110
- // let confirmation_time = scale_u64(*next_or_return!(data_iter));
111
- // let anchor = ConfirmationBlockTime {
112
- // block_id,
113
- // confirmation_time,
114
- // };
115
- // // FIXME: inserting anchors for transactions not in the tx graph will fail the
116
- // // SQLite persistence.
117
- // //let txid = unconfirmed_txids
118
- // //.pop_front()
119
- // //.unwrap_or(unique_hash.get_txid());
120
- // if let Some(txid) = unconfirmed_txids.pop_front() {
121
- // anchors.insert((anchor, txid));
122
- // } else {
123
- // break;
124
- // }
125
- // }
126
-
127
- // let mut seen_ats = HashMap::new();
128
- // while next_or_return!(data_iter) & 0x01 == 0x01 {
129
- // let time = cmp::min(scale_u64(*next_or_return!(data_iter)), i64::MAX as u64 - 1);
130
- // let txid = unconfirmed_txids
131
- // .pop_front()
132
- // .unwrap_or(unique_hash.get_txid());
133
- // seen_ats.insert(txid, time);
134
- // }
135
-
136
- // let tx_update = TxUpdate {
137
- // txs,
138
- // txouts,
139
- // anchors,
140
- // seen_ats,
141
- // };
142
-
143
- // // Finally, do the chain update.
144
- // // TODO: sometimes generate invalid updates, reorgs, etc.
145
- // let chain = if next_or_return!(data_iter) & 0x01 == 0x01 {
146
- // let mut tip = wallet.latest_checkpoint();
147
- // let tip_height = tip.height();
148
- // let blocks_count = *next_or_return!(data_iter) as u32;
149
- // for i in 1..blocks_count + 1 {
150
- // tip = tip
151
- // .push(BlockId {
152
- // height: tip_height + i,
153
- // hash: unique_hash.get_block_hash(),
154
- // })
155
- // .unwrap();
156
- // }
157
- // Some(tip)
158
- // } else {
159
- // None
160
- // };
161
-
162
- // // The Wallet update should never fail as we only ever create a consistent chain.
163
- // let update = WalletUpdate {
164
- // last_active_indices,
165
- // tx_update,
166
- // chain,
167
- // };
168
- // wallet.apply_update(update).unwrap();
169
- // }
170
- // // Assert the wallet roundtrips to persistence and check some invariants.
0 commit comments