Skip to content

Commit 1ce45ba

Browse files
committed
rpc: getwalletinfo, return wallet 'birthtime'
And add coverage for it
1 parent 83c6644 commit 1ce45ba

File tree

3 files changed

+30
-2
lines changed

3 files changed

+30
-2
lines changed

src/wallet/rpc/wallet.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ static RPCHelpMan getwalletinfo()
6969
{RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for scriptPubKey management"},
7070
{RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},
7171
{RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},
72+
{RPCResult::Type::NUM_TIME, "birthtime", /*optional=*/true, "The start time for blocks scanning. It could be modified by (re)importing any descriptor with an earlier timestamp."},
7273
RESULT_LAST_PROCESSED_BLOCK,
7374
}},
7475
},
@@ -132,6 +133,9 @@ static RPCHelpMan getwalletinfo()
132133
obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
133134
obj.pushKV("external_signer", pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER));
134135
obj.pushKV("blank", pwallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));
136+
if (int64_t birthtime = pwallet->GetBirthTime(); birthtime != UNKNOWN_TIME) {
137+
obj.pushKV("birthtime", birthtime);
138+
}
135139

136140
AppendLastProcessedBlock(obj, *pwallet);
137141
return obj;

src/wallet/wallet.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,9 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
884884
/* Returns true if the wallet can give out new addresses. This means it has keys in the keypool or can generate new keys */
885885
bool CanGetAddresses(bool internal = false) const;
886886

887+
/* Returns the time of the first created key or, in case of an import, it could be the time of the first received transaction */
888+
int64_t GetBirthTime() const { return m_birth_time; }
889+
887890
/**
888891
* Blocks until the wallet state is up-to-date to /at least/ the current
889892
* chain at the time this function is entered

test/functional/wallet_reindex.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,27 @@ def birthtime_test(self, node, miner_wallet):
4444
self.advance_time(node, BLOCK_TIME)
4545

4646
# Now create a new wallet, and import the descriptor
47-
node.createwallet(wallet_name='watch_only', disable_private_keys=True, blank=True, load_on_startup=True)
47+
node.createwallet(wallet_name='watch_only', disable_private_keys=True, load_on_startup=True)
4848
wallet_watch_only = node.get_wallet_rpc('watch_only')
49+
# Blank wallets don't have a birth time
50+
assert 'birthtime' not in wallet_watch_only.getwalletinfo()
4951

5052
# For a descriptors wallet: Import address with timestamp=now.
5153
# For legacy wallet: There is no way of importing a script/address with a custom time. The wallet always imports it with birthtime=1.
5254
# In both cases, disable rescan to not detect the transaction.
5355
wallet_watch_only.importaddress(wallet_addr, rescan=False)
5456
assert_equal(len(wallet_watch_only.listtransactions()), 0)
5557

58+
# Depending on the wallet type, the birth time changes.
59+
wallet_birthtime = wallet_watch_only.getwalletinfo()['birthtime']
60+
if self.options.descriptors:
61+
# As blocks were generated every 10 min, the chain MTP timestamp is node_time - 60 min.
62+
assert_equal(self.node_time - BLOCK_TIME * 6, wallet_birthtime)
63+
else:
64+
# No way of importing scripts/addresses with a custom time on a legacy wallet.
65+
# It's always set to the beginning of time.
66+
assert_equal(wallet_birthtime, 1)
67+
5668
# Rescan the wallet to detect the missing transaction
5769
wallet_watch_only.rescanblockchain()
5870
assert_equal(wallet_watch_only.gettransaction(tx_id)['confirmations'], 50)
@@ -65,7 +77,16 @@ def birthtime_test(self, node, miner_wallet):
6577

6678
# Verify the transaction is still 'confirmed' after reindex
6779
wallet_watch_only = node.get_wallet_rpc('watch_only')
68-
assert_equal(wallet_watch_only.gettransaction(tx_id)['confirmations'], 50)
80+
tx_info = wallet_watch_only.gettransaction(tx_id)
81+
assert_equal(tx_info['confirmations'], 50)
82+
83+
# Depending on the wallet type, the birth time changes.
84+
if self.options.descriptors:
85+
# For descriptors, verify the wallet updated the birth time to the transaction time
86+
assert_equal(tx_info['time'], wallet_watch_only.getwalletinfo()['birthtime'])
87+
else:
88+
# For legacy, as the birth time was set to the beginning of time, verify it did not change
89+
assert_equal(wallet_birthtime, 1)
6990

7091
wallet_watch_only.unloadwallet()
7192

0 commit comments

Comments
 (0)