11use bdk_chain:: {
22 indexed_tx_graph, keychain_txout, local_chain, tx_graph, ConfirmationBlockTime , Merge ,
33} ;
4+ use chain:: BlockId ;
45use miniscript:: { Descriptor , DescriptorPublicKey } ;
56use serde:: { Deserialize , Serialize } ;
67
@@ -110,6 +111,9 @@ pub struct ChangeSet {
110111 pub change_descriptor : Option < Descriptor < DescriptorPublicKey > > ,
111112 /// Stores the network type of the transaction data.
112113 pub network : Option < bitcoin:: Network > ,
114+ /// Stores the [`Wallet`]'s birthday, defined as the first [`Block`] which has relevant
115+ /// transactions to this [`Wallet`].
116+ pub birthday : Option < BlockId > ,
113117 /// Changes to the [`LocalChain`](local_chain::LocalChain).
114118 pub local_chain : local_chain:: ChangeSet ,
115119 /// Changes to [`TxGraph`](tx_graph::TxGraph).
@@ -145,6 +149,14 @@ impl Merge for ChangeSet {
145149 ) ;
146150 self . network = other. network ;
147151 }
152+ // TODO(@luisschwab): should merging [`ChangeSet`]s with distinct birthdays be possible?
153+ if other. birthday . is_some ( ) {
154+ debug_assert ! (
155+ self . birthday. is_none( ) || self . birthday == other. birthday,
156+ "birthday must never change"
157+ ) ;
158+ self . birthday = other. birthday ;
159+ }
148160
149161 // merge locked outpoints
150162 self . locked_outpoints . merge ( other. locked_outpoints ) ;
@@ -158,6 +170,7 @@ impl Merge for ChangeSet {
158170 self . descriptor . is_none ( )
159171 && self . change_descriptor . is_none ( )
160172 && self . network . is_none ( )
173+ && self . birthday . is_none ( )
161174 && self . local_chain . is_empty ( )
162175 && self . tx_graph . is_empty ( )
163176 && self . indexer . is_empty ( )
@@ -174,14 +187,15 @@ impl ChangeSet {
174187 /// Name of table to store wallet locked outpoints.
175188 pub const WALLET_OUTPOINT_LOCK_TABLE_NAME : & ' static str = "bdk_wallet_locked_outpoints" ;
176189
177- /// Get v0 sqlite [ChangeSet] schema
190+ /// Get v0 sqlite [` ChangeSet` ] schema.
178191 pub fn schema_v0 ( ) -> alloc:: string:: String {
179192 format ! (
180193 "CREATE TABLE {} ( \
181194 id INTEGER PRIMARY KEY NOT NULL CHECK (id = 0), \
182195 descriptor TEXT, \
183196 change_descriptor TEXT, \
184197 network TEXT \
198+ birthday TEXT \
185199 ) STRICT;",
186200 Self :: WALLET_TABLE_NAME ,
187201 )
@@ -223,7 +237,7 @@ impl ChangeSet {
223237 let mut changeset = Self :: default ( ) ;
224238
225239 let mut wallet_statement = db_tx. prepare ( & format ! (
226- "SELECT descriptor, change_descriptor, network FROM {}" ,
240+ "SELECT descriptor, change_descriptor, network, birthday FROM {}" ,
227241 Self :: WALLET_TABLE_NAME ,
228242 ) ) ?;
229243 let row = wallet_statement
@@ -234,13 +248,16 @@ impl ChangeSet {
234248 "change_descriptor" ,
235249 ) ?,
236250 row. get :: < _ , Option < Impl < bitcoin:: Network > > > ( "network" ) ?,
251+ // TODO(@luisschwab): implement `Impl FromSql` fot `BlockId` on bdk_chain
252+ row. get :: < _ , Option < Impl < BlockId > > > ( "birthday" ) ?,
237253 ) )
238254 } )
239255 . optional ( ) ?;
240- if let Some ( ( desc, change_desc, network) ) = row {
256+ if let Some ( ( desc, change_desc, network, birthday ) ) = row {
241257 changeset. descriptor = desc. map ( Impl :: into_inner) ;
242258 changeset. change_descriptor = change_desc. map ( Impl :: into_inner) ;
243259 changeset. network = network. map ( Impl :: into_inner) ;
260+ changeset. birthday = birthday. map ( Impl :: into_inner) ;
244261 }
245262
246263 // Select locked outpoints.
@@ -309,6 +326,17 @@ impl ChangeSet {
309326 } ) ?;
310327 }
311328
329+ let mut birthday_statement = db_tx. prepare_cached ( & format ! (
330+ "INSERT INTO {}(id, birthday) VALUES(:id, :birthday) ON CONFLICT(id) DO UPDATE SET birthday=:birthday" ,
331+ Self :: WALLET_TABLE_NAME ,
332+ ) ) ?;
333+ if let Some ( birthday) = self . birthday {
334+ birthday_statement. execute ( named_params ! {
335+ ":id" : 0 ,
336+ ":birthday" : Impl ( birthday) ,
337+ } ) ?;
338+ }
339+
312340 // Insert or delete locked outpoints.
313341 let mut insert_stmt = db_tx. prepare_cached ( & format ! (
314342 "INSERT OR IGNORE INTO {}(txid, vout) VALUES(:txid, :vout)" ,
0 commit comments