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
|
2020-03-18 10:11:26 -05:00
|
|
|
read more about how neutrino works [here](https://suredbits.com/neutrino-what-is-it-and-why-we-need-it/). At this time,
|
|
|
|
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
|
|
|
|
import akka.actor.ActorSystem
|
|
|
|
import org.bitcoins.core.protocol.blockchain.Block
|
|
|
|
import org.bitcoins.node._
|
2021-04-27 15:54:44 -05:00
|
|
|
import org.bitcoins.node.networking.peer._
|
2020-03-14 08:49:39 -05:00
|
|
|
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
|
Implement caching of bitcoind in the walletTest,nodeTest, and partially bitcoindRpcTest project (#2792)
* Create CachedBitcoind, implement it in FundTransactionHandlingTest
* Add BaseWalletTest, extend it with BitcoinSWalletTest & BitcoinSWalletTestCachedBitcoind, add CachedBitcoinV19 and use it RescanHandlingTest
* Make ProcessBlockTest work with cached bitcoind
* Make trait for CachedBitcoindNewest for the newest version of bitcoind
* Make UTXOLifeCycleTest use cached bitcoind
* Add WalletBloom, WalletSyncTest to use cached bitcoinds
* Add WalletIntegrationTest
* Rework beforeAll() and afterAll() into the super trait like BaseWalletTest
* Add standlone BitcoindFixtures, use it in BitcoindBackendTest
* Use new BitcoindFixtures in BitcoindBlockPollingTest
* Introduce BaseNodeTest, start implementing the usage of cached bitcoinds in the nodeTest project
* Use cached bitcoind's with SpvNodeTest & SpvNodeWithWalletTest
* Fix bug on postgres with reusing database, upsert the genesis header rather than create it
* Get NeutrinoNode tests workign with cached bitcoinds
* Fix NeutrinoNodeWithWallet by destroying wallet state for Postgres
* Add teardown helper method for bitcoind
* Teardown chain project when using node fixtures since node is dependent upon the chain project.
* Turn off parallelExecution again
* Switch the parallelExecution flag to only be set on CI, so we can get better performance when running locally
* Start implementing BitcoindFixtures, use BitcoindFixturesCachedTriple on TestUtilRpcTest
* Fix compiler errors, begin implementing NodePair
* Refactor TestRpcUtilTest to use 2 bitcoinds rather than 2
* Reduce the number of bitcoinds that MultiWalletRpcTest needs from 3 -> 1
* Reduce number of bitcoinds used in WalletRpcTest from 3 -> 2
* Add some documentation
* Try to re-add parallelExecution
* Reduce the number of bitcoinds used in PsbtRpcTest from 3 -> 2
* Disable parallelExecution in Test again
* Make BitcoindV21RpcClientTest & BitcoindV20RpcClientTest reduce bitcoind usage from 2 -> 1
* Make BitcoindV19RpcClienttest reduce bitcoind usage from 2 -> 1
* Rework MempoolRpcTest to use fixtures, add BitcoindVersion to CachedBitcoindCollection
* Make sure clientAccumm has to be specified as a paramter now rather than filling in by default
* Begin parameterizing NodePair/NodeTriple to retain type information for the specific version of bitcoind that was used
* Don't implement version in super trait
* Fix docs
* Fix async issue in V21 test suite
* Append to vectors in CachedBitcoinCollection rather than replace
* Fix rebase issues
* Add scaladocs
* Fix BitcoindV18RpcClient address info test
* Implement fixtures in BitcoindV17RpcClientTest fixtures
* Cleanup v17 PsbtRpcTest
* Reduce bitcoind usage from 3 -> 1 in BitcoindV18RpcClientTest
* Remove abandon transaction test, this allows us to reduce the number of bitcoind's used in MempoolRpcTest from 3 -> 2
* Remove the requirement to inject BitcoinSAsyncFixtureTest, add it in the test traits explicitly to make things easier. Also add explicit afterAll() method to tear down both the CachedBitcoind & BitcoinSAsyncFixtureTest
* Fix missing Await.result() in BitcoindRpcTest.afterAll()
* Rework MultiWalletRpcTest to use a NodePair
* Rework BlockchainRpcTest to use fixtures
* Rework Client start()/stop() methods. Now use an AtomicBoolean to indicate when a user has requested a client to start/stop rather than sending pings to bitcoind that can fail because the conneciton pool has been shutdown in test cases
* Try my luck with turning on parallelExecution in CI again
* Revert parallelExecution, now testes do not run in parallel on CI
* Only turn off parallelExecution for bitcoindRpcTest
* Adjust build to only have bitcoindRpcTest NOT in run parallel on mac, reduce number of blocks used in BitcoindRpcTestUtil.createNodeSequence
* Run less tests in the rpc test suite as that takes the longest, move them over to node/wallet/dlc test suite on mac osx CI
* Don't run eclair tests in parallel either
* Remove CachedBitcoind from BitcoinSWalletTest
* Fix async bug in test case
* Push to github to force re-run of CI
* Push to github to force re-run of CI
* Push to github to force re-run of CI
2021-03-19 06:37:53 -05:00
|
|
|
val bitcoindF = BitcoindRpcTestUtil.startedBitcoindRpcClient(instance, Vector.newBuilder)
|
2020-03-14 08:49:39 -05:00
|
|
|
|
|
|
|
//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
|
|
|
|
|
2020-08-26 16:24:38 -05:00
|
|
|
val initNodeF = nodeConfig.start()
|
2020-03-14 08:49:39 -05:00
|
|
|
|
|
|
|
//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 {
|
2021-04-27 15:54:44 -05:00
|
|
|
chainApi <- chainApiF
|
2020-03-14 08:49:39 -05:00
|
|
|
peer <- peerF
|
|
|
|
} yield {
|
2021-04-27 15:54:44 -05:00
|
|
|
val dataMessageHandler = DataMessageHandler(chainApi)
|
2020-03-14 08:49:39 -05:00
|
|
|
NeutrinoNode(nodePeer = peer,
|
2021-04-27 15:54:44 -05:00
|
|
|
dataMessageHandler = dataMessageHandler,
|
2020-03-14 08:49:39 -05:00
|
|
|
nodeConfig = nodeConfig,
|
|
|
|
chainConfig = chainConfig,
|
2021-04-27 15:54:44 -05:00
|
|
|
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)
|
2021-04-27 15:54:44 -05:00
|
|
|
```
|