2019-09-02 15:16:44 +02:00
|
|
|
---
|
|
|
|
id: node
|
2020-03-13 09:54:07 -05:00
|
|
|
title: Light Client
|
2019-09-02 15:16:44 +02:00
|
|
|
---
|
|
|
|
|
2020-03-14 08:49:39 -05:00
|
|
|
Bitcoin-s has node module that allows you to connect to the p2p network.
|
|
|
|
|
|
|
|
### Neutrino Node
|
|
|
|
|
|
|
|
Bitcoin-s has experimental support for neutrino which is a new lite client proposal on the bitcoin p2p network. You can
|
2022-01-09 18:51:59 +05:30
|
|
|
read more about how neutrino works [here](https://suredbits.com/neutrino-what-is-it-and-why-we-need-it/). At this time,
|
2020-03-18 10:11:26 -05:00
|
|
|
bitcoin-s only supports connecting to one trusted peer.
|
2020-03-14 08:49:39 -05:00
|
|
|
|
2020-12-29 14:37:25 -06:00
|
|
|
#### Limitations
|
|
|
|
|
|
|
|
Currently, the node does not have an active mempool.
|
|
|
|
It is only aware of transactions it broadcasts and ones confirmed in blocks.
|
|
|
|
|
2020-03-14 08:49:39 -05:00
|
|
|
#### Callbacks
|
|
|
|
|
|
|
|
Bitcoin-S support call backs for the following events that happen on the bitcoin p2p network:
|
|
|
|
|
|
|
|
1. onTxReceived
|
|
|
|
2. onBlockReceived
|
|
|
|
3. onMerkleBlockReceived
|
|
|
|
4. onCompactFilterReceived
|
|
|
|
|
|
|
|
That means every time one of these events happens on the p2p network, we will call your callback
|
2020-04-03 08:57:41 -05:00
|
|
|
so that you can be notified of the event. These callbacks will be run after the message has been
|
2020-08-04 12:27:21 -05:00
|
|
|
recieved and will execute sequentially. If any of them fail an error log will be output and the remainder of the callbacks will continue.
|
|
|
|
Let's make an easy one
|
2020-03-14 08:49:39 -05:00
|
|
|
|
|
|
|
#### Example
|
|
|
|
|
|
|
|
Here is an example of constructing a neutrino node and registering a callback so you can be notified of an event.
|
|
|
|
|
2020-12-29 14:34:37 -06:00
|
|
|
To run the example, we need a bitcoind binary that has neutrino support.
|
|
|
|
Bitcoin Core only has p2p neutrino support as of version 0.21.0.
|
|
|
|
You will need to use a version of Bitcoin Core at least as old as 0.21.0.
|
|
|
|
For your node to be able to service these filters you will need set
|
|
|
|
`blockfilterindex=1` and `peerblockfilters=1` in your `bitcoin.conf` file.
|
2020-03-14 08:49:39 -05:00
|
|
|
|
|
|
|
```scala mdoc:invisible
|
2024-02-22 10:26:21 -06:00
|
|
|
import org.apache.pekko.actor.ActorSystem
|
2020-03-14 08:49:39 -05:00
|
|
|
import org.bitcoins.core.protocol.blockchain.Block
|
|
|
|
import org.bitcoins.node._
|
|
|
|
import org.bitcoins.rpc.client.common.BitcoindVersion
|
|
|
|
import org.bitcoins.testkit.node._
|
|
|
|
import org.bitcoins.testkit.node.fixture._
|
|
|
|
import org.bitcoins.testkit.rpc._
|
|
|
|
import org.bitcoins.server.BitcoinSAppConfig
|
|
|
|
import org.bitcoins.testkit._
|
|
|
|
import org.bitcoins.testkit.chain._
|
|
|
|
import scala.concurrent._
|
|
|
|
import scala.concurrent.duration._
|
|
|
|
import java.nio.file.Files
|
|
|
|
import com.typesafe.config.ConfigFactory
|
|
|
|
```
|
|
|
|
|
|
|
|
```scala mdoc:compile-only
|
|
|
|
|
|
|
|
implicit val system = ActorSystem(s"node-example")
|
|
|
|
implicit val ec = system.dispatcher
|
|
|
|
|
|
|
|
//we also require a bitcoind instance to connect to
|
|
|
|
//so let's start one (make sure you ran 'sbt downloadBitcoind')
|
2022-08-08 12:48:33 -07:00
|
|
|
val instance = BitcoindRpcTestUtil.instance(versionOpt = Some(BitcoindVersion.newest))
|
2020-03-14 08:49:39 -05:00
|
|
|
val p2pPort = instance.p2pPort
|
2021-09-07 19:19:01 +05:30
|
|
|
val bitcoindF = BitcoindRpcTestUtil.startedBitcoindRpcClient(Some(instance), Vector.newBuilder)
|
2020-03-14 08:49:39 -05:00
|
|
|
|
|
|
|
//contains information on how to connect to bitcoin's p2p info
|
2021-07-13 12:27:24 -07:00
|
|
|
val peerF = bitcoindF.flatMap(b => NodeUnitTest.createPeer(b))
|
2020-03-14 08:49:39 -05:00
|
|
|
|
|
|
|
// set a data directory
|
|
|
|
val prefix = s"node-example-${System.currentTimeMillis()}"
|
|
|
|
val datadir = Files.createTempDirectory(prefix)
|
|
|
|
|
|
|
|
val tmpDir = BitcoinSTestAppConfig.tmpDir()
|
|
|
|
// set the current network to regtest
|
|
|
|
val config = ConfigFactory.parseString {
|
|
|
|
s"""
|
|
|
|
| bitcoin-s {
|
|
|
|
| network = regtest
|
|
|
|
| node {
|
|
|
|
| mode = neutrino # neutrino, spv
|
|
|
|
|
|
|
|
|
| peers = ["127.0.0.1:$p2pPort"] # a list of peer addresses in form "hostname:portnumber"
|
|
|
|
| # (e.g. "neutrino.testnet3.suredbits.com:18333")
|
|
|
|
| # Port number is optional, the default value is 8333 for mainnet,
|
|
|
|
| # 18333 for testnet and 18444 for regtest.
|
|
|
|
| }
|
|
|
|
| }
|
|
|
|
|""".stripMargin
|
|
|
|
}
|
|
|
|
|
2022-01-25 07:25:05 -06:00
|
|
|
implicit val appConfig = BitcoinSAppConfig(datadir, Vector(config))
|
2020-03-14 08:49:39 -05:00
|
|
|
implicit val chainConfig = appConfig.chainConf
|
|
|
|
implicit val nodeConfig = appConfig.nodeConf
|
|
|
|
|
2020-08-26 16:24:38 -05:00
|
|
|
val initNodeF = nodeConfig.start()
|
2020-03-14 08:49:39 -05:00
|
|
|
|
|
|
|
//yay! All setup done, let's create a node and then start it!
|
|
|
|
val nodeF = for {
|
|
|
|
peer <- peerF
|
|
|
|
} yield {
|
2023-06-13 12:07:04 -05:00
|
|
|
NeutrinoNode(
|
2022-08-23 03:35:41 +05:30
|
|
|
walletCreationTimeOpt = None, //you can set this to only sync compact filters after the timestamp
|
|
|
|
paramPeers = Vector(peer),
|
|
|
|
nodeConfig = nodeConfig,
|
|
|
|
chainConfig = chainConfig,
|
|
|
|
actorSystem = system)
|
2020-03-14 08:49:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
//let's start it
|
|
|
|
val startedNodeF = nodeF.flatMap(_.start())
|
|
|
|
|
|
|
|
//let's make a simple callback that print's the
|
|
|
|
//blockhash everytime we receive a block on the network
|
2020-06-15 17:30:08 -05:00
|
|
|
val blockReceivedFunc: OnBlockReceived = { block: Block =>
|
2020-04-03 08:57:41 -05:00
|
|
|
Future.successful(
|
|
|
|
println(s"Received blockhash=${block.blockHeader.hashBE}"))
|
2020-03-14 08:49:39 -05:00
|
|
|
}
|
|
|
|
|
2020-08-04 12:27:21 -05:00
|
|
|
// Create callback
|
2020-03-14 08:49:39 -05:00
|
|
|
val nodeCallbacks = NodeCallbacks.onBlockReceived(blockReceivedFunc)
|
|
|
|
|
2020-08-04 12:27:21 -05:00
|
|
|
// Add call to our node's config
|
|
|
|
nodeConfig.addCallbacks(nodeCallbacks)
|
2020-03-14 08:49:39 -05:00
|
|
|
|
|
|
|
//let's test it out by generating a block with bitcoind!
|
|
|
|
|
|
|
|
val genBlockF = for {
|
|
|
|
bitcoind <- bitcoindF
|
|
|
|
addr <- bitcoind.getNewAddress
|
|
|
|
hashes <- bitcoind.generateToAddress(1,addr)
|
2021-07-01 06:34:10 -05:00
|
|
|
} yield hashes
|
2020-03-14 08:49:39 -05:00
|
|
|
|
|
|
|
//you should see our callback print a block hash
|
|
|
|
//when running this code
|
|
|
|
|
|
|
|
//cleanup
|
|
|
|
val cleanupF = for {
|
|
|
|
_ <- genBlockF
|
|
|
|
bitcoind <- bitcoindF
|
2020-08-04 12:27:21 -05:00
|
|
|
node <- startedNodeF
|
2020-03-14 08:49:39 -05:00
|
|
|
x = NeutrinoNodeConnectedWithBitcoind(node.asInstanceOf[NeutrinoNode],bitcoind)
|
|
|
|
_ <- NodeUnitTest.destroyNodeConnectedWithBitcoind(x)
|
|
|
|
} yield ()
|
|
|
|
|
|
|
|
Await.result(cleanupF, 60.seconds)
|
2022-01-09 18:51:59 +05:30
|
|
|
```
|