* 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
5.1 KiB
id | title |
---|---|
node | Light Client |
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 read more about how neutrino works here. At this time, bitcoin-s only supports connecting to one trusted peer.
Limitations
Currently, the node does not have an active mempool. It is only aware of transactions it broadcasts and ones confirmed in blocks.
Callbacks
Bitcoin-S support call backs for the following events that happen on the bitcoin p2p network:
- onTxReceived
- onBlockReceived
- onMerkleBlockReceived
- 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. These callbacks will be run after the message has been 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
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.
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.
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
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, Vector.newBuilder)
//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.start()
//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,
initialSyncDone = None)
}
//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: OnBlockReceived = { block: Block =>
Future.successful(
println(s"Received blockhash=${block.blockHeader.hashBE}"))
}
// Create callback
val nodeCallbacks = NodeCallbacks.onBlockReceived(blockReceivedFunc)
// Add call to our node's config
nodeConfig.addCallbacks(nodeCallbacks)
//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 <- startedNodeF
x = NeutrinoNodeConnectedWithBitcoind(node.asInstanceOf[NeutrinoNode],bitcoind)
_ <- NodeUnitTest.destroyNodeConnectedWithBitcoind(x)
} yield ()
Await.result(cleanupF, 60.seconds)