Wallet Sync
High level wallet state
Our wallet infrastructure has a specific table called state_descriptors
.
This tracks chain state for our wallet.
Here is an example of the contents of this table
sqlite> select * from state_descriptors; SyncHeight|0000000000000000000134aa9e949ea1d053042b8dfa59bdc73b0322a88f009e 665741
If you look carefully in the second column, you will see a string encoding indicating what the wallet state is. In this case, the last block hash seen by the wallet is
0000000000000000000134aa9e949ea1d053042b8dfa59bdc73b0322a88f009e
and height
665741
If you have access to a wallet, you can call
wallet.getSyncDescriptorOpt
to get access to this information
Wallet state from the cli
Alternatively, you can retrieve this information with bitcoin-s-cli
./bitcoin-s-cli walletinfo
{
"wallet": {
"keymanager": {
"rootXpub": "..."
},
"xpub": "...",
"hdPath": "...",
"height": 1906239,
"blockHash": "00000000dcf1066b8cd764a6104a9b5e95a55cd31adf9107974b2581ac90fdb9"
}
}
Syncing a wallet
Bitcoin-s provides a utility object called WalletSync
that provides useful utilities for syncing a bitcoin-s wallet.
Syncing wallet for with access to full blocks
Inside of WalletSync
we have a method called WalletSync.syncFullBlocks
This method takes 4 parameters
- a Wallet to sync
getBlockHeaderFunc
is a function to retrieve a block header based on a blockHashgetBestBlockHashFunc
is a function to retrieve the best block hash for our blockchaingetBlockFunc
is a function to retrieve a fullBlock
that corresponds to a block hash
Given these for things, we can use WalletSync.syncFullBlocks
to sync our entire wallet.
Here is a code example
implicit val system: ActorSystem = ActorSystem(s"wallet-sync-example")
implicit val ec: ExecutionContext = system.dispatcher
// this reads authentication credentials and
// connection details from the default data
// directory on your platform
val client = BitcoindRpcClient.fromDatadir(binary=new File("/path/to/bitcoind"), datadir=new File("/path/to/bitcoind-datadir"))
//yay! Now we have a started bitcoind.
//We will use this as our datasource for syncing our wallet
val bitcoindRpcClientF: Future[BitcoindRpcClient] = client.start()
//wait for bitcoind to get started
val bitcoind = Await.result(bitcoindRpcClientF, 10.seconds)
val getBestBlockHashFunc = () => bitcoind.getBestBlockHash
val getBlockHeaderFunc = { (hash: DoubleSha256DigestBE) => bitcoind.getBlockHeaderRaw(hash) }
val getBlockFunc = { (hash: DoubleSha256DigestBE) => bitcoind.getBlockRaw(hash) }
val genesisHashBEF = bitcoind.getBlockHash(0)
//yay! We are now all setup. Using our 3 functions above and a wallet, we can now sync
//a fresh wallet
implicit val walletAppConfig: WalletAppConfig = WalletAppConfig.fromDefaultDatadir()
val feeRateProvider: FeeRateApi = MempoolSpaceProvider.fromBlockTarget(6, proxyParams = None)
val wallet = Wallet(bitcoind, bitcoind, feeRateProvider)
//yay! we have a synced wallet
val syncedWalletF = genesisHashBEF.flatMap { genesisHash =>
WalletSync.syncFullBlocks(wallet,
getBlockHeaderFunc,
getBestBlockHashFunc,
getBlockFunc,
genesisHash)
}