2019-08-23 20:53:00 +02:00
|
|
|
---
|
2019-09-02 15:16:44 +02:00
|
|
|
title: Blockchain Verification
|
|
|
|
id: chain
|
2019-08-23 20:53:00 +02:00
|
|
|
---
|
|
|
|
|
2019-09-02 15:16:44 +02:00
|
|
|
Bitcoin-S comes bundled with a rudimentary blockchain verification
|
|
|
|
module. This module is currently only released as a library, and not as a binary.
|
|
|
|
This is because it (nor the documentation) is not deemed production
|
|
|
|
ready. Use at your own risk, and without too much money depending on it.
|
|
|
|
|
|
|
|
## Syncing and verifying block headers
|
|
|
|
|
2019-08-23 20:53:00 +02:00
|
|
|
Using the `chain` module of Bitcoin-S it's possible to
|
|
|
|
sync and verify block headers from the Bitcoin blockchain. In this document
|
|
|
|
we demonstrate how to do this, while persisting it to disk. We should be
|
|
|
|
able to read this chain on subsequent runs, assuming we are connected
|
|
|
|
to the same `bitcoind` instance.
|
|
|
|
|
2020-03-10 18:49:22 +01:00
|
|
|
```scala mdoc:invisible
|
2019-08-23 20:53:00 +02:00
|
|
|
import org.bitcoins.chain.blockchain._
|
|
|
|
import org.bitcoins.chain.blockchain.sync._
|
|
|
|
import org.bitcoins.chain.models._
|
2020-03-10 18:49:22 +01:00
|
|
|
import org.bitcoins.chain.config.ChainAppConfig
|
2021-09-07 15:49:01 +02:00
|
|
|
import org.bitcoins.rpc.config.BitcoindInstanceLocal
|
2020-03-10 18:49:22 +01:00
|
|
|
import org.bitcoins.rpc.client.common.BitcoindRpcClient
|
2019-08-23 20:53:00 +02:00
|
|
|
import org.bitcoins.testkit.chain._
|
2024-02-22 17:26:21 +01:00
|
|
|
import org.apache.pekko.actor.ActorSystem
|
2019-08-23 20:53:00 +02:00
|
|
|
import scala.concurrent._
|
2020-03-10 18:49:22 +01:00
|
|
|
import java.nio.file.Files
|
|
|
|
```
|
|
|
|
|
|
|
|
```scala mdoc:compile-only
|
2019-08-23 20:53:00 +02:00
|
|
|
|
2019-08-30 22:12:18 +02:00
|
|
|
implicit val ec = ExecutionContext.global
|
2021-09-07 15:49:01 +02:00
|
|
|
implicit val system = ActorSystem("System")
|
2019-08-23 20:53:00 +02:00
|
|
|
// We are assuming that a `bitcoind` regtest node is running the background.
|
|
|
|
// You can see our `bitcoind` guides to see how to connect
|
|
|
|
// to a local or remote `bitcoind` node.
|
|
|
|
|
2021-09-07 15:49:01 +02:00
|
|
|
val bitcoindInstance = BitcoindInstanceLocal.fromDatadir()
|
2019-08-30 22:12:18 +02:00
|
|
|
val rpcCli = BitcoindRpcClient(bitcoindInstance)
|
2019-08-23 20:53:00 +02:00
|
|
|
|
|
|
|
// Next, we need to create a way to monitor the chain:
|
|
|
|
|
2020-03-11 00:01:14 +01:00
|
|
|
val getBestBlockHash = SyncUtil.getBestBlockHashFunc(rpcCli)
|
2019-08-23 20:53:00 +02:00
|
|
|
|
2020-03-11 00:01:14 +01:00
|
|
|
val getBlockHeader = SyncUtil.getBlockHeaderFunc(rpcCli)
|
2019-08-23 20:53:00 +02:00
|
|
|
|
|
|
|
// set a data directory
|
|
|
|
val datadir = Files.createTempDirectory("bitcoin-s-test")
|
|
|
|
|
2020-03-11 00:01:14 +01:00
|
|
|
// set the current network to regtest
|
2019-08-23 20:53:00 +02:00
|
|
|
import com.typesafe.config.ConfigFactory
|
|
|
|
val config = ConfigFactory.parseString {
|
|
|
|
"""
|
|
|
|
| bitcoin-s {
|
|
|
|
| network = regtest
|
|
|
|
| }
|
|
|
|
|""".stripMargin
|
|
|
|
}
|
|
|
|
|
2022-01-25 14:25:05 +01:00
|
|
|
implicit val chainConfig = ChainAppConfig(datadir, Vector(config))
|
2019-08-23 20:53:00 +02:00
|
|
|
|
|
|
|
// Initialize the needed database tables if they don't exist:
|
2020-08-26 23:24:38 +02:00
|
|
|
val chainProjectInitF = chainConfig.start()
|
2019-08-23 20:53:00 +02:00
|
|
|
val blockHeaderDAO = BlockHeaderDAO()
|
2019-09-25 20:18:51 +02:00
|
|
|
val compactFilterHeaderDAO = CompactFilterHeaderDAO()
|
|
|
|
val compactFilterDAO = CompactFilterDAO()
|
2022-07-12 21:41:43 +02:00
|
|
|
val stateDAO = ChainStateDescriptorDAO()
|
2019-08-23 20:53:00 +02:00
|
|
|
|
2020-03-11 00:01:14 +01:00
|
|
|
|
|
|
|
//initialize the chain handler from the database
|
2022-07-12 21:41:43 +02:00
|
|
|
val chainHandler = ChainHandler.fromDatabase(blockHeaderDAO, compactFilterHeaderDAO, compactFilterDAO, stateDAO)
|
2019-08-23 20:53:00 +02:00
|
|
|
|
2020-03-11 00:01:14 +01:00
|
|
|
// Now, do the actual syncing:
|
2019-08-23 20:53:00 +02:00
|
|
|
val syncedChainApiF = for {
|
|
|
|
_ <- chainProjectInitF
|
2020-11-17 13:19:07 +01:00
|
|
|
synced <- ChainSync.sync(chainHandler, getBlockHeader, getBestBlockHash)
|
2019-08-23 20:53:00 +02:00
|
|
|
} yield synced
|
|
|
|
|
|
|
|
val syncResultF = syncedChainApiF.flatMap { chainApi =>
|
2020-11-17 13:19:07 +01:00
|
|
|
chainApi.getBlockCount().map(count => println(s"chain api blockcount=${count}"))
|
2019-08-23 20:53:00 +02:00
|
|
|
|
|
|
|
rpcCli.getBlockCount.map(count => println(s"bitcoind blockcount=${count}"))
|
|
|
|
}
|
|
|
|
|
|
|
|
syncResultF.onComplete { case result =>
|
|
|
|
println(s"Sync result=${result}")
|
|
|
|
}
|
|
|
|
```
|