mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-15 20:30:17 +01:00
2020 03 13 node md (#1229)
* Implement example of starting a neutrino node and example of adding a callback to node.md Fix port number * Clean up some names in the example * Make sure we get the correct bitcoind binary with neutrino p2p support in the example
This commit is contained in:
parent
5bb31f4951
commit
e598d4c37e
1 changed files with 143 additions and 7 deletions
|
@ -3,11 +3,147 @@ id: node
|
|||
title: Light Client
|
||||
---
|
||||
|
||||
Bitcoin-S comes bundled with a light client Bitcoin node. this client
|
||||
is capable of doing verification of some parts of the blockchain,
|
||||
and can act as a starting point for building Bitcoin applications
|
||||
that need to connect to the P2P network.
|
||||
Bitcoin-s has node module that allows you to connect to the p2p network.
|
||||
|
||||
This node 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.
|
||||
### Neutrino Node
|
||||
|
||||
Bitcoin-s has experimental support for neutrino which is a new lite client proposal on the bitcoin p2p network. You can
|
||||
read more about how neutrino works [here](https://suredbits.com/neutrino-what-is-it-and-why-we-need-it/).
|
||||
|
||||
#### 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
|
||||
so that you can be notified of the event. Let's make a easy one
|
||||
|
||||
#### Example
|
||||
|
||||
Here is an example of constructing a neutrino node and registering a callback so you can be notified of an event.
|
||||
|
||||
To run the example, we need a bitcoind binary that has neutrino support. Unforunately bitcoin core has not merged neutrino
|
||||
p2p network support yet ([pr here](https://github.com/bitcoin/bitcoin/pull/16442)) which means that we have built a custom binary and host it ourselves. You need
|
||||
to make sure to run `sbt downloadBitcoind` and then look for the `bitcoind` binary with neutrino support in
|
||||
`$HOME/.bitcoin-s/binaries/bitcoind/bitcoin-0.18.99/`. This binary is built from the open PR on bitcoin core.
|
||||
|
||||
```scala mdoc:invisible
|
||||
import akka.actor.ActorSystem
|
||||
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')
|
||||
val instance = BitcoindRpcTestUtil.instance(versionOpt = Some(BitcoindVersion.Experimental))
|
||||
val p2pPort = instance.p2pPort
|
||||
val bitcoindF = BitcoindRpcTestUtil.startedBitcoindRpcClient(instance)
|
||||
|
||||
//contains information on how to connect to bitcoin's p2p info
|
||||
val peerF = bitcoindF.map(b => NodeUnitTest.createPeer(b))
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
implicit val appConfig = BitcoinSAppConfig(datadir, config)
|
||||
implicit val chainConfig = appConfig.chainConf
|
||||
implicit val nodeConfig = appConfig.nodeConf
|
||||
|
||||
val initNodeF = nodeConfig.initialize()
|
||||
|
||||
//the node requires a chainHandler to store block information
|
||||
//use a helper method in our testkit to create the chain project
|
||||
val chainApiF = for {
|
||||
chainHandler <- ChainUnitTest.createChainHandler()
|
||||
} yield chainHandler
|
||||
|
||||
|
||||
//yay! All setup done, let's create a node and then start it!
|
||||
val nodeF = for {
|
||||
_ <- chainApiF
|
||||
peer <- peerF
|
||||
} yield {
|
||||
NeutrinoNode(nodePeer = peer,
|
||||
nodeConfig = nodeConfig,
|
||||
chainConfig = chainConfig,
|
||||
actorSystem = system)
|
||||
}
|
||||
|
||||
//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
|
||||
val blockReceivedFunc = { block: Block =>
|
||||
println(s"Received blockhash=${block.blockHeader.hashBE}")
|
||||
}
|
||||
|
||||
val nodeCallbacks = NodeCallbacks.onBlockReceived(blockReceivedFunc)
|
||||
|
||||
//ok, now we need to add this allback to our running node
|
||||
val nodeWithCallbackF = for {
|
||||
node <- startedNodeF
|
||||
withCallback = node.addCallbacks(nodeCallbacks)
|
||||
} yield withCallback
|
||||
|
||||
//let's test it out by generating a block with bitcoind!
|
||||
|
||||
val genBlockF = for {
|
||||
bitcoind <- bitcoindF
|
||||
addr <- bitcoind.getNewAddress
|
||||
hashes <- bitcoind.generateToAddress(1,addr)
|
||||
} yield ()
|
||||
|
||||
//you should see our callback print a block hash
|
||||
//when running this code
|
||||
|
||||
//cleanup
|
||||
val cleanupF = for {
|
||||
_ <- genBlockF
|
||||
bitcoind <- bitcoindF
|
||||
node <- nodeWithCallbackF
|
||||
x = NeutrinoNodeConnectedWithBitcoind(node.asInstanceOf[NeutrinoNode],bitcoind)
|
||||
_ <- NodeUnitTest.destroyNodeConnectedWithBitcoind(x)
|
||||
} yield ()
|
||||
|
||||
Await.result(cleanupF, 60.seconds)
|
||||
```
|
Loading…
Add table
Reference in a new issue