Remove Spv code (#4356)

* change node tests to neutrino

* get node test working

* merge DataMessageHandlerTest and DataMessageHandlerNeutrinoNodeTest

* delete unused files

* remove commented out spv parts

* formatting

* delete spv node

* remove merkle callback for neutrino node

* remove spv node wallet callbacks

* formatting

* remove SpvWalletApi

* replace SpvTestConfig with NeutrinoTestConfig

* more replace SpvTestConfig with NeutrinoTestConfig

* minor fix

* fix tests
This commit is contained in:
Shreyansh 2022-05-30 18:27:31 +05:30 committed by GitHub
parent b80bf4649e
commit d8fc8e588f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 190 additions and 1117 deletions

View File

@ -17,7 +17,7 @@ class AppConfigTest extends BitcoinSAsyncTest {
val networkOverride =
ConfigFactory.parseString("bitcoin-s.network = testnet3")
val config = BitcoinSTestAppConfig.getSpvTestConfig(networkOverride)
val config = BitcoinSTestAppConfig.getNeutrinoTestConfig(networkOverride)
val chainConf = config.chainConf
val walletConf = config.walletConf
val nodeConf = config.nodeConf
@ -31,7 +31,7 @@ class AppConfigTest extends BitcoinSAsyncTest {
}
it must "have the same DB path" in {
val conf = BitcoinSTestAppConfig.getSpvTestConfig()
val conf = BitcoinSTestAppConfig.getNeutrinoTestConfig()
val chainConf = conf.chainConf
val walletConf = conf.walletConf
val nodeConf = conf.nodeConf
@ -40,7 +40,7 @@ class AppConfigTest extends BitcoinSAsyncTest {
}
it must "have distinct databases" in {
val conf = BitcoinSTestAppConfig.getSpvTestConfig()
val conf = BitcoinSTestAppConfig.getNeutrinoTestConfig()
val chainConf = conf.chainConf
val walletConf = conf.walletConf
val nodeConf = conf.nodeConf

View File

@ -18,7 +18,7 @@ class CommonRoutesSpec
with MockFactory {
implicit val conf: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig()
BitcoinSTestAppConfig.getNeutrinoTestConfig()
val commonRoutes = CommonRoutes(conf.baseDatadir)
"CommonRoutes" should {

View File

@ -14,7 +14,7 @@ class CoreRoutesSpec
with MockFactory {
implicit val conf: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig()
BitcoinSTestAppConfig.getNeutrinoTestConfig()
val coreRoutes = CoreRoutes()
"Core routes" should {

View File

@ -23,7 +23,7 @@ class DLCRoutesSpec
with MockFactory {
implicit val conf: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig()
BitcoinSTestAppConfig.getNeutrinoTestConfig()
val mockWallet = mock[MockWalletApi]

View File

@ -52,7 +52,7 @@ import scala.concurrent.{ExecutionContext, Future}
class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
implicit val conf: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig()
BitcoinSTestAppConfig.getNeutrinoTestConfig()
implicit val timeout: RouteTestTimeout = RouteTestTimeout(5.seconds)

View File

@ -21,7 +21,7 @@ class WalletRoutesSpec
with MockFactory {
implicit val conf: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig()
BitcoinSTestAppConfig.getNeutrinoTestConfig()
val mockWalletApi = mock[MockWalletApi]
val walletRoutes: WalletRoutes =

View File

@ -31,7 +31,6 @@ import org.bitcoins.dlc.node.config.DLCNodeAppConfig
import org.bitcoins.dlc.wallet._
import org.bitcoins.feeprovider.MempoolSpaceTarget.HourFeeTarget
import org.bitcoins.feeprovider._
import org.bitcoins.node._
import org.bitcoins.node.config.NodeAppConfig
import org.bitcoins.rpc.BitcoindException.InWarmUp
import org.bitcoins.rpc.client.common.BitcoindRpcClient
@ -45,7 +44,7 @@ import org.bitcoins.wallet.models.SpendingInfoDAO
import java.time.Instant
import scala.concurrent.duration.DurationInt
import scala.concurrent.{Await, ExecutionContext, Future, Promise}
import scala.concurrent.{Await, Future, Promise}
class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
override val system: ActorSystem,
@ -149,12 +148,11 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
//add callbacks to our uninitialized node
val configuredNodeF = for {
node <- nodeF
wallet <- configuredWalletF
initNode <- setBloomFilter(node, wallet)
_ <- configuredWalletF
} yield {
logger.info(
s"Done configuring node, it took=${System.currentTimeMillis() - start}ms")
initNode
node
}
val dlcNodeF = for {
@ -345,23 +343,6 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
}
}
private def setBloomFilter(node: Node, wallet: Wallet)(implicit
ec: ExecutionContext): Future[Node] = {
for {
nodeWithBloomFilter <- node match {
case spvNode: SpvNode =>
for {
bloom <- wallet.getBloomFilter()
_ = logger.info(
s"Got bloom filter with ${bloom.filterSize.toInt} elements")
} yield spvNode.setBloomFilter(bloom)
case _: Node => Future.successful(node)
}
} yield {
nodeWithBloomFilter
}
}
/** This is needed for migrations V2/V3 on the chain project to re-calculate the total work for the chain */
private def runChainWorkCalc(force: Boolean)(implicit
system: ActorSystem): Future[ChainApi] = {

View File

@ -45,10 +45,6 @@ object CallbackUtil extends Logging {
}
}
nodeConf.nodeType match {
case NodeType.SpvNode =>
Future.successful(
NodeCallbacks(onTxReceived = Vector(onTx),
onBlockHeadersReceived = Vector(onHeaders)))
case NodeType.NeutrinoNode =>
Future.successful(
NodeCallbacks(onTxReceived = Vector(onTx),

View File

@ -172,9 +172,8 @@ trait DLCWalletApi { self: WalletApi =>
def findDLCContacts(alias: String): Future[Vector[DLCContactDb]]
}
/** An HDWallet that supports DLCs and both Neutrino and SPV methods of syncing */
/** An HDWallet that supports DLCs and Neutrino method of syncing */
trait AnyDLCHDWalletApi
extends HDWalletApi
with DLCWalletApi
with NeutrinoWalletApi
with SpvWalletApi

View File

@ -19,16 +19,12 @@ object NodeType extends StringFactory[NodeType] {
override def shortName: String = "neutrino"
}
final case object SpvNode extends InternalImplementationNodeType {
override def shortName: String = "spv"
}
final case object BitcoindBackend extends ExternalImplementationNodeType {
override def shortName: String = "bitcoind"
}
val all: Vector[NodeType] =
Vector(FullNode, NeutrinoNode, SpvNode, BitcoindBackend)
Vector(FullNode, NeutrinoNode, BitcoindBackend)
override def fromStringOpt(str: String): Option[NodeType] = {
all.find(state => str.toLowerCase() == state.toString.toLowerCase) match {

View File

@ -1,23 +0,0 @@
package org.bitcoins.core.api.wallet
import org.bitcoins.core.bloom.BloomFilter
import scala.concurrent.Future
/** API for the wallet project.
*
* This wallet API is BIP44 compliant.
*
* @see [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP44]]
*/
trait SpvWalletApi { self: WalletApi =>
/** Recreates the account using BIP-44 approach
*/
def rescanSPVWallet(): Future[Unit]
/** Retrieves a bloom filter that that can be sent to a P2P network node
* to get information about our transactions, pubkeys and scripts.
*/
def getBloomFilter(): Future[BloomFilter]
}

View File

@ -418,11 +418,5 @@ trait WalletApi extends StartStopAsync[WalletApi] {
/** An HDWallet that uses Neutrino to sync */
trait NeutrinoHDWalletApi extends HDWalletApi with NeutrinoWalletApi
/** An HDWallet that uses SPV to sync */
trait SpvHDWalletApi extends HDWalletApi with SpvWalletApi
/** An HDWallet that supports both Neutrino and SPV methods of syncing */
trait AnyHDWalletApi
extends HDWalletApi
with NeutrinoWalletApi
with SpvWalletApi
/** An HDWallet that supports Neutrino method of syncing */
trait AnyHDWalletApi extends HDWalletApi with NeutrinoWalletApi

View File

@ -84,7 +84,7 @@ class DBConfigTest extends BitcoinSAsyncTest {
() => None)
val mainnetConf = ConfigFactory.parseString("bitcoin-s.network = mainnet")
val chainConfig: ChainAppConfig = {
BitcoinSTestAppConfig.getSpvTestConfig(mainnetConf).chainConf
BitcoinSTestAppConfig.getNeutrinoTestConfig(mainnetConf).chainConf
}
assert(chainConfig.network == MainNet)

View File

@ -72,7 +72,7 @@ As an example, we will show you how to use the `ChainQueryApi` and bitcoind to q
implicit val system: ActorSystem = ActorSystem(s"node-api-example")
implicit val ec: ExecutionContextExecutor = system.dispatcher
implicit val walletConf: WalletAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig().walletConf
BitcoinSTestAppConfig.getNeutrinoTestConfig().walletConf
// let's use a helper method to get a v19 bitcoind
// and a ChainApi

View File

@ -49,7 +49,7 @@ As an example, we will show you how to use the `NodeApi` and bitcoind to downloa
implicit val system: ActorSystem = ActorSystem(s"node-api-example")
implicit val ec: ExecutionContextExecutor = system.dispatcher
implicit val walletConf: WalletAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig().walletConf
BitcoinSTestAppConfig.getNeutrinoTestConfig().walletConf
// let's use a helper method to get a v19 bitcoind
// and a ChainApi

View File

@ -8,7 +8,7 @@ import org.bitcoins.server.BitcoinSAppConfig
import org.bitcoins.testkit.BitcoinSTestAppConfig
import org.bitcoins.testkit.async.TestAsyncUtil
import org.bitcoins.testkit.node.NodeTestWithCachedBitcoindNewest
import org.bitcoins.testkit.node.fixture.SpvNodeConnectedWithBitcoind
import org.bitcoins.testkit.node.fixture.NeutrinoNodeConnectedWithBitcoind
import org.bitcoins.testkit.util.TorUtil
import org.scalatest.{FutureOutcome, Outcome}
@ -20,9 +20,9 @@ class BroadcastTransactionTest extends NodeTestWithCachedBitcoindNewest {
/** Wallet config with data directory set to user temp directory */
override protected def getFreshConfig: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvWithEmbeddedDbTestConfig(pgUrl, Vector.empty)
BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig(pgUrl)
override type FixtureParam = SpvNodeConnectedWithBitcoind
override type FixtureParam = NeutrinoNodeConnectedWithBitcoind
def withFixture(test: OneArgAsyncTest): FutureOutcome = {
val torClientF = if (TorUtil.torEnabled) torF else Future.unit
@ -30,7 +30,7 @@ class BroadcastTransactionTest extends NodeTestWithCachedBitcoindNewest {
val outcome: Future[Outcome] = for {
_ <- torClientF
bitcoind <- cachedBitcoindWithFundsF
outcome = withSpvNodeConnectedToBitcoindCached(test, bitcoind)(
outcome = withNeutrinoNodeConnectedToBitcoindCached(test, bitcoind)(
system,
getFreshConfig)
f <- outcome.toFuture
@ -50,7 +50,7 @@ class BroadcastTransactionTest extends NodeTestWithCachedBitcoindNewest {
}
it must "safely broadcast a transaction twice" in { param =>
val SpvNodeConnectedWithBitcoind(node, rpc) = param
val NeutrinoNodeConnectedWithBitcoind(node, rpc) = param
for {
tx <- createValidTx(rpc)
@ -66,7 +66,7 @@ class BroadcastTransactionTest extends NodeTestWithCachedBitcoindNewest {
}
it must "broadcast a transaction" in { param =>
val SpvNodeConnectedWithBitcoind(node, rpc) = param
val NeutrinoNodeConnectedWithBitcoind(node, rpc) = param
def hasSeenTx(transaction: Transaction): Future[Boolean] = {
rpc

View File

@ -10,12 +10,12 @@ import org.scalatest.FutureOutcome
class DisconnectedPeerTest extends NodeUnitTest {
override protected def getFreshConfig: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvWithEmbeddedDbTestConfig(pgUrl, Vector.empty)
BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig(pgUrl)
override type FixtureParam = SpvNode
override type FixtureParam = NeutrinoNode
def withFixture(test: OneArgAsyncTest): FutureOutcome =
withDisconnectedSpvNode(test)(system, getFreshConfig)
withDisconnectedNeutrinoNode(test)(system, getFreshConfig)
it must "fail to broadcast a transaction when disconnected" in { node =>
val tx = TransactionGenerators.transaction.sampleSome

View File

@ -1,124 +0,0 @@
package org.bitcoins.node
import akka.actor.Cancellable
import org.bitcoins.crypto.DoubleSha256DigestBE
import org.bitcoins.rpc.util.RpcUtil
import org.bitcoins.server.BitcoinSAppConfig
import org.bitcoins.testkit.BitcoinSTestAppConfig
import org.bitcoins.testkit.node.fixture.SpvNodeConnectedWithBitcoind
import org.bitcoins.testkit.node.{
NodeTestUtil,
NodeTestWithCachedBitcoindNewest
}
import org.bitcoins.testkit.util.TorUtil
import org.scalatest.{FutureOutcome, Outcome}
import scala.concurrent.Future
import scala.concurrent.duration.DurationInt
class SpvNodeTest extends NodeTestWithCachedBitcoindNewest {
/** Wallet config with data directory set to user temp directory */
override protected def getFreshConfig: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvWithEmbeddedDbTestConfig(pgUrl, Vector.empty)
override type FixtureParam = SpvNodeConnectedWithBitcoind
override def withFixture(test: OneArgAsyncTest): FutureOutcome = {
val torClientF = if (TorUtil.torEnabled) torF else Future.unit
val outcomeF: Future[Outcome] = for {
_ <- torClientF
bitcoind <- cachedBitcoindWithFundsF
outcome = withSpvNodeConnectedToBitcoindCached(test, bitcoind)(
system,
getFreshConfig)
f <- outcome.toFuture
} yield f
new FutureOutcome(outcomeF)
}
behavior of "SpvNode"
it must "receive notification that a block occurred on the p2p network" in {
spvNodeConnectedWithBitcoind: SpvNodeConnectedWithBitcoind =>
val spvNode = spvNodeConnectedWithBitcoind.node
val bitcoind = spvNodeConnectedWithBitcoind.bitcoind
val assert1F = for {
_ <- spvNode.isConnected(0).map(assert(_))
a2 <- spvNode.isInitialized(0).map(assert(_))
} yield a2
val hashF: Future[DoubleSha256DigestBE] = bitcoind.getNewAddress
.flatMap(bitcoind.generateToAddress(1, _))
.map(_.head)
//sync our spv node expecting to get that generated hash
val spvSyncF = for {
_ <- assert1F
_ <- hashF
sync <- spvNode.sync()
} yield sync
spvSyncF.flatMap { _ =>
NodeTestUtil
.awaitSync(spvNode, bitcoind)
.map(_ => succeed)
}
}
it must "stay in sync with a bitcoind instance" in {
spvNodeConnectedWithBitcoind: SpvNodeConnectedWithBitcoind =>
val spvNode = spvNodeConnectedWithBitcoind.node
val bitcoind = spvNodeConnectedWithBitcoind.bitcoind
//we need to generate 1 block for bitcoind to consider
//itself out of IBD. bitcoind will not sendheaders
//when it believes itself, or it's peer is in IBD
val gen1F =
bitcoind.getNewAddress.flatMap(bitcoind.generateToAddress(1, _))
//this needs to be called to get our peer to send us headers
//as they happen with the 'sendheaders' message
//both our spv node and our bitcoind node _should_ both be at the genesis block (regtest)
//at this point so no actual syncing is happening
val initSyncF = gen1F.flatMap { hashes =>
val syncF = spvNode.sync()
for {
_ <- syncF
_ <- NodeTestUtil.awaitBestHash(hashes.head, spvNode)
} yield ()
}
//start generating a block every 10 seconds with bitcoind
//this should result in 5 blocks
val startGenF: Future[Cancellable] = initSyncF.map { _ =>
//generate a block every 5 seconds
//until we have generated 5 total blocks
genBlockInterval(bitcoind)
}
startGenF.flatMap { cancel =>
//we should expect 5 headers have been announced to us via
//the send headers message.
val has6BlocksF = RpcUtil.retryUntilSatisfiedF(
conditionF = () =>
spvNode
.chainApiFromDb()
.flatMap(_.getBlockCount().map { count =>
count == 108
}),
interval = 250.millis)
has6BlocksF.map { _ =>
val isCanceled = cancel.cancel()
if (!isCanceled) {
logger.warn(s"Failed to cancel generating blocks on bitcoind")
}
succeed
}
}
}
}

View File

@ -1,78 +0,0 @@
package org.bitcoins.node
import org.bitcoins.asyncutil.AsyncUtil
import org.bitcoins.core.currency._
import org.bitcoins.crypto.DoubleSha256DigestBE
import org.bitcoins.server.BitcoinSAppConfig
import org.bitcoins.testkit.BitcoinSTestAppConfig
import org.bitcoins.testkit.node.{
NodeTestUtil,
NodeTestWithCachedBitcoindNewest,
SpvNodeFundedWalletBitcoind
}
import org.bitcoins.wallet.Wallet
import org.scalatest.{FutureOutcome, Outcome}
import scala.concurrent.Future
class SpvNodeWithWalletTest extends NodeTestWithCachedBitcoindNewest {
/** Wallet config with data directory set to user temp directory */
override protected def getFreshConfig: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvWithEmbeddedDbTestConfig(pgUrl, Vector.empty)
override type FixtureParam = SpvNodeFundedWalletBitcoind
def withFixture(test: OneArgAsyncTest): FutureOutcome = {
val outcomeF: Future[Outcome] = for {
bitcoind <- cachedBitcoindWithFundsF
outcome = withSpvNodeFundedWalletBitcoindCached(
test,
getBIP39PasswordOpt(),
bitcoind)(system, getFreshConfig)
f <- outcome.toFuture
} yield f
new FutureOutcome(outcomeF)
}
val amountFromBitcoind = 1.bitcoin
it must "load a bloom filter and receive information about received payments" in {
param =>
val SpvNodeFundedWalletBitcoind(spv, wallet, rpc, _) = param
for {
_ <- wallet.getBloomFilter()
address <- wallet.getNewAddress()
updatedBloom <- spv.updateBloomFilter(address).map(_.bloomFilter)
ourTxid <-
rpc
.sendToAddress(address, amountFromBitcoind)
_ <- rpc.generateToAddress(1, junkAddress)
_ <- spv.sync()
_ <- NodeTestUtil.awaitSync(spv, rpc)
ourTx <- rpc.getTransaction(ourTxid)
_ = assert(updatedBloom.isRelevant(ourTx.hex))
//wait for bitcoind to propagate us a merkle block
//and transactions associated with it
//eventually we should have the tx
//added to our wallet when this occurs
_ <- AsyncUtil.retryUntilSatisfiedF(() =>
walletContainsTx(wallet, ourTx.txid))
} yield {
succeed
}
}
private def walletContainsTx(
wallet: Wallet,
txid: DoubleSha256DigestBE): Future[Boolean] = {
val txOptF = wallet.findTransaction(txid)
for {
txOpt <- txOptF
} yield txOpt.isDefined
}
}

View File

@ -1,71 +0,0 @@
package org.bitcoins.node
import org.bitcoins.core.currency._
import org.bitcoins.server.BitcoinSAppConfig
import org.bitcoins.testkit.BitcoinSTestAppConfig
import org.bitcoins.testkit.node.{
NodeTestUtil,
NodeTestWithCachedBitcoindNewest,
SpvNodeFundedWalletBitcoind
}
import org.bitcoins.testkit.util.TorUtil
import org.scalatest.{FutureOutcome, Outcome}
import scala.concurrent.Future
class UpdateBloomFilterTest extends NodeTestWithCachedBitcoindNewest {
/** Wallet config with data directory set to user temp directory */
override protected def getFreshConfig: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvWithEmbeddedDbTestConfig(pgUrl, Vector.empty)
override type FixtureParam = SpvNodeFundedWalletBitcoind
def withFixture(test: OneArgAsyncTest): FutureOutcome = {
val torClientF = if (TorUtil.torEnabled) torF else Future.unit
val outcome: Future[Outcome] = for {
_ <- torClientF
bitcoind <- cachedBitcoindWithFundsF
outcome = withSpvNodeFundedWalletBitcoindCached(
test,
getBIP39PasswordOpt(),
bitcoind)(system, getFreshConfig)
f <- outcome.toFuture
} yield f
new FutureOutcome(outcome)
}
it must "update the bloom filter with a TX" in { param =>
val SpvNodeFundedWalletBitcoind(spv, wallet, rpc, _) = param
for {
_ <- wallet.getBloomFilter()
tx <- wallet.sendToAddress(junkAddress, 5.bitcoin, None)
updatedBloom <- spv.updateBloomFilter(tx).map(_.bloomFilter)
_ = assert(updatedBloom.contains(tx.txId))
_ <- rpc.broadcastTransaction(tx)
// this should confirm our TX
// since we updated the bloom filter
hash <- rpc.generateToAddress(1, junkAddress).map(_.head)
_ <- NodeTestUtil.awaitSync(spv, rpc)
merkleBlock <- rpc.getTxOutProof(Vector(tx.txIdBE), hash)
txs <- rpc.verifyTxOutProof(merkleBlock)
} yield assert(txs.contains(tx.txIdBE))
}
it must "update the bloom filter with an address" in { param =>
val SpvNodeFundedWalletBitcoind(spv, wallet, rpc, _) = param
for {
_ <- wallet.getBloomFilter()
address <- wallet.getNewAddress()
updatedBloom <- spv.updateBloomFilter(address).map(_.bloomFilter)
hash <- rpc.sendToAddress(address, 1.bitcoin)
tx <- rpc.getRawTransactionRaw(hash)
} yield assert(updatedBloom.isRelevant(tx))
}
}

View File

@ -1,72 +0,0 @@
package org.bitcoins.node.networking.peer
import org.bitcoins.core.currency.BitcoinsInt
import org.bitcoins.core.p2p.TransactionMessage
import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.node.{NodeCallbacks, OnTxReceived}
import org.bitcoins.server.BitcoinSAppConfig
import org.bitcoins.testkit.BitcoinSTestAppConfig
import org.bitcoins.testkit.node.{
NeutrinoNodeFundedWalletBitcoind,
NodeTestWithCachedBitcoindNewest
}
import org.scalatest.{FutureOutcome, Outcome}
import scala.concurrent.{Future, Promise}
class DataMessageHandlerNeutrinoNodesTest
extends NodeTestWithCachedBitcoindNewest {
/** Wallet config with data directory set to user temp directory */
override protected def getFreshConfig: BitcoinSAppConfig =
BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig(pgUrl)
override type FixtureParam = NeutrinoNodeFundedWalletBitcoind
def withFixture(test: OneArgAsyncTest): FutureOutcome = {
val outcomeF: Future[Outcome] = for {
bitcoind <- cachedBitcoindWithFundsF
outcome = withNeutrinoNodeFundedWalletBitcoind(
test = test,
bip39PasswordOpt = getBIP39PasswordOpt(),
bitcoind = bitcoind
)(system, getFreshConfig)
f <- outcome.toFuture
} yield f
new FutureOutcome(outcomeF)
}
it must "verify OnTxReceived callbacks are executed" in {
param: FixtureParam =>
val NeutrinoNodeFundedWalletBitcoind(node, _, bitcoind, _) = param
val resultP: Promise[Transaction] = Promise()
val callback: OnTxReceived = (tx: Transaction) => {
Future {
resultP.success(tx)
()
}
}
val sender = node.peerMsgSenders(0)
for {
txId <- bitcoind.sendToAddress(junkAddress, 1.bitcoin)
tx <- bitcoind.getRawTransactionRaw(txId)
payload = TransactionMessage(tx)
nodeCallbacks = NodeCallbacks.onTxReceived(callback)
_ = node.nodeAppConfig.addCallbacks(nodeCallbacks)
dataMessageHandler =
DataMessageHandler(genesisChainApi, None)(node.executionContext,
node.nodeAppConfig,
node.chainConfig)
_ <- dataMessageHandler.handleDataPayload(payload, sender, node)
result <- resultP.future
} yield assert(result == tx)
}
}

View File

@ -5,14 +5,14 @@ import org.bitcoins.core.currency._
import org.bitcoins.core.gcs.{FilterType, GolombFilter}
import org.bitcoins.core.p2p._
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.protocol.blockchain.{Block, BlockHeader, MerkleBlock}
import org.bitcoins.core.protocol.blockchain.{Block, BlockHeader}
import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.crypto.DoubleSha256Digest
import org.bitcoins.node._
import org.bitcoins.server.BitcoinSAppConfig
import org.bitcoins.testkit.BitcoinSTestAppConfig
import org.bitcoins.testkit.node.NodeUnitTest
import org.bitcoins.testkit.node.fixture.SpvNodeConnectedWithBitcoindV22
import org.bitcoins.testkit.node.fixture.NeutrinoNodeConnectedWithBitcoindV22
import org.bitcoins.testkit.tor.CachedTor
import org.scalatest.FutureOutcome
@ -22,24 +22,24 @@ class DataMessageHandlerTest extends NodeUnitTest with CachedTor {
/** Wallet config with data directory set to user temp directory */
override protected def getFreshConfig: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvWithEmbeddedDbTestConfig(pgUrl, Vector.empty)
BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig(pgUrl)
override type FixtureParam = SpvNodeConnectedWithBitcoindV22
override type FixtureParam = NeutrinoNodeConnectedWithBitcoindV22
override def withFixture(test: OneArgAsyncTest): FutureOutcome =
withSpvNodeConnectedToBitcoindV22(test)(system, getFreshConfig)
withNeutrinoNodeConnectedToBitcoindV22(test)(system, getFreshConfig)
it must "catch errors and not fail when processing an invalid payload" in {
param: SpvNodeConnectedWithBitcoindV22 =>
val SpvNodeConnectedWithBitcoindV22(spv, _) = param
param: NeutrinoNodeConnectedWithBitcoindV22 =>
val NeutrinoNodeConnectedWithBitcoindV22(node, _) = param
val sender = spv.peerMsgSenders(0)
val sender = node.peerMsgSenders(0)
for {
chainApi <- spv.chainApiFromDb()
chainApi <- node.chainApiFromDb()
dataMessageHandler = DataMessageHandler(chainApi, None)(
spv.executionContext,
spv.nodeAppConfig,
spv.chainConfig)
node.executionContext,
node.nodeAppConfig,
node.chainConfig)
// Use signet genesis block header, this should be invalid for regtest
invalidPayload =
@ -50,50 +50,13 @@ class DataMessageHandlerTest extends NodeUnitTest with CachedTor {
chainApi.processHeaders(invalidPayload.headers))
// Verify we handle the payload correctly
_ <- dataMessageHandler.handleDataPayload(invalidPayload, sender, spv)
_ <- dataMessageHandler.handleDataPayload(invalidPayload, sender, node)
} yield succeed
}
it must "verify OnMerkleBlock callbacks are executed" in {
param: FixtureParam =>
val SpvNodeConnectedWithBitcoindV22(spv, bitcoind) = param
val resultP: Promise[(MerkleBlock, Vector[Transaction])] = Promise()
val callback: OnMerkleBlockReceived = {
(merkle: MerkleBlock, txs: Vector[Transaction]) =>
Future {
resultP.success((merkle, txs))
()
}
}
val sender = spv.peerMsgSenders(0)
for {
txId <- bitcoind.sendToAddress(junkAddress, 1.bitcoin)
tx <- bitcoind.getRawTransactionRaw(txId)
_ <- bitcoind.generateToAddress(blocks = 1, junkAddress)
merkleBlock <- bitcoind.getTxOutProof(Vector(txId))
payload1 = MerkleBlockMessage(merkleBlock)
payload2 = TransactionMessage(tx)
nodeCallbacks = NodeCallbacks(onMerkleBlockReceived = Vector(callback))
_ = spv.nodeAppConfig.addCallbacks(nodeCallbacks)
dataMessageHandler =
DataMessageHandler(genesisChainApi, None)(spv.executionContext,
spv.nodeAppConfig,
spv.chainConfig)
_ <- dataMessageHandler.handleDataPayload(payload1, sender, spv)
_ <- dataMessageHandler.handleDataPayload(payload2, sender, spv)
result <- resultP.future
} yield assert(result == ((merkleBlock, Vector(tx))))
}
it must "verify OnBlockReceived callbacks are executed" in {
param: FixtureParam =>
val SpvNodeConnectedWithBitcoindV22(spv, bitcoind) = param
val NeutrinoNodeConnectedWithBitcoindV22(node, bitcoind) = param
val resultP: Promise[Block] = Promise()
@ -103,7 +66,7 @@ class DataMessageHandlerTest extends NodeUnitTest with CachedTor {
()
}
}
val sender = spv.peerMsgSenders(0)
val sender = node.peerMsgSenders(0)
for {
hash <- bitcoind.generateToAddress(blocks = 1, junkAddress).map(_.head)
@ -112,20 +75,20 @@ class DataMessageHandlerTest extends NodeUnitTest with CachedTor {
payload = BlockMessage(block)
nodeCallbacks = NodeCallbacks.onBlockReceived(callback)
_ = spv.nodeAppConfig.addCallbacks(nodeCallbacks)
_ = node.nodeAppConfig.addCallbacks(nodeCallbacks)
dataMessageHandler =
DataMessageHandler(genesisChainApi, None)(spv.executionContext,
spv.nodeAppConfig,
spv.chainConfig)
_ <- dataMessageHandler.handleDataPayload(payload, sender, spv)
DataMessageHandler(genesisChainApi, None)(node.executionContext,
node.nodeAppConfig,
node.chainConfig)
_ <- dataMessageHandler.handleDataPayload(payload, sender, node)
result <- resultP.future
} yield assert(result == block)
}
it must "verify OnBlockHeadersReceived callbacks are executed" in {
param: FixtureParam =>
val SpvNodeConnectedWithBitcoindV22(spv, bitcoind) = param
val NeutrinoNodeConnectedWithBitcoindV22(node, bitcoind) = param
val resultP: Promise[Vector[BlockHeader]] = Promise()
@ -138,7 +101,7 @@ class DataMessageHandlerTest extends NodeUnitTest with CachedTor {
}
}
val sender = spv.peerMsgSenders(0)
val sender = node.peerMsgSenders(0)
for {
hash <- bitcoind.generateToAddress(blocks = 1, junkAddress).map(_.head)
header <- bitcoind.getBlockHeaderRaw(hash)
@ -147,20 +110,20 @@ class DataMessageHandlerTest extends NodeUnitTest with CachedTor {
callbacks = NodeCallbacks.onBlockHeadersReceived(callback)
_ = spv.nodeAppConfig.addCallbacks(callbacks)
_ = node.nodeAppConfig.addCallbacks(callbacks)
dataMessageHandler =
DataMessageHandler(genesisChainApi, None)(spv.executionContext,
spv.nodeAppConfig,
spv.chainConfig)
DataMessageHandler(genesisChainApi, None)(node.executionContext,
node.nodeAppConfig,
node.chainConfig)
_ <- dataMessageHandler.handleDataPayload(payload, sender, spv)
_ <- dataMessageHandler.handleDataPayload(payload, sender, node)
result <- resultP.future
} yield assert(result == Vector(header))
}
it must "verify OnCompactFilterReceived callbacks are executed" in {
param: FixtureParam =>
val SpvNodeConnectedWithBitcoindV22(spv, bitcoind) = param
val NeutrinoNodeConnectedWithBitcoindV22(node, bitcoind) = param
val resultP: Promise[Vector[(DoubleSha256Digest, GolombFilter)]] =
Promise()
@ -171,7 +134,7 @@ class DataMessageHandlerTest extends NodeUnitTest with CachedTor {
()
}
}
val sender = spv.peerMsgSenders(0)
val sender = node.peerMsgSenders(0)
for {
hash <- bitcoind.generateToAddress(blocks = 1, junkAddress).map(_.head)
filter <- bitcoind.getBlockFilter(hash, FilterType.Basic)
@ -180,14 +143,47 @@ class DataMessageHandlerTest extends NodeUnitTest with CachedTor {
CompactFilterMessage(FilterType.Basic, hash.flip, filter.filter.bytes)
nodeCallbacks = NodeCallbacks.onCompactFilterReceived(callback)
_ = spv.nodeAppConfig.addCallbacks(nodeCallbacks)
_ = node.nodeAppConfig.addCallbacks(nodeCallbacks)
dataMessageHandler =
DataMessageHandler(genesisChainApi, None)(spv.executionContext,
spv.nodeAppConfig,
spv.chainConfig)
DataMessageHandler(genesisChainApi, None)(node.executionContext,
node.nodeAppConfig,
node.chainConfig)
_ <- dataMessageHandler.handleDataPayload(payload, sender, spv)
_ <- dataMessageHandler.handleDataPayload(payload, sender, node)
result <- resultP.future
} yield assert(result == Vector((hash.flip, filter.filter)))
}
it must "verify OnTxReceived callbacks are executed" in {
param: FixtureParam =>
val NeutrinoNodeConnectedWithBitcoindV22(node, bitcoind) = param
val resultP: Promise[Transaction] = Promise()
val callback: OnTxReceived = (tx: Transaction) => {
Future {
resultP.success(tx)
()
}
}
val sender = node.peerMsgSenders(0)
for {
txId <- bitcoind.sendToAddress(junkAddress, 1.bitcoin)
tx <- bitcoind.getRawTransactionRaw(txId)
payload = TransactionMessage(tx)
nodeCallbacks = NodeCallbacks.onTxReceived(callback)
_ = node.nodeAppConfig.addCallbacks(nodeCallbacks)
dataMessageHandler =
DataMessageHandler(genesisChainApi, None)(node.executionContext,
node.nodeAppConfig,
node.chainConfig)
_ <- dataMessageHandler.handleDataPayload(payload, sender, node)
result <- resultP.future
} yield assert(result == tx)
}
}

View File

@ -25,7 +25,7 @@ class PeerMessageHandlerTest
/** Wallet config with data directory set to user temp directory */
override protected def getFreshConfig: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig()
BitcoinSTestAppConfig.getNeutrinoTestConfig()
override type FixtureParam = Peer

View File

@ -1,115 +0,0 @@
package org.bitcoins.node
import akka.actor.ActorSystem
import org.bitcoins.asyncutil.AsyncUtil
import org.bitcoins.chain.config.ChainAppConfig
import org.bitcoins.core.api.chain.ChainQueryApi.FilterResponse
import org.bitcoins.core.api.node.NodeType
import org.bitcoins.core.bloom.BloomFilter
import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.core.protocol.{BitcoinAddress, BlockStamp}
import org.bitcoins.core.util.Mutable
import org.bitcoins.node.config.NodeAppConfig
import org.bitcoins.node.models.Peer
import org.bitcoins.node.networking.peer.{
ControlMessageHandler,
DataMessageHandler
}
import scala.concurrent.Future
case class SpvNode(
dataMessageHandler: DataMessageHandler,
nodeConfig: NodeAppConfig,
chainConfig: ChainAppConfig,
actorSystem: ActorSystem,
configPeersOverride: Vector[Peer] = Vector.empty)
extends Node {
require(nodeConfig.nodeType == NodeType.SpvNode,
s"We need our SPV mode enabled to be able to construct a SPV node!")
implicit override def system: ActorSystem = actorSystem
implicit override def nodeAppConfig: NodeAppConfig = nodeConfig
override def chainAppConfig: ChainAppConfig = chainConfig
private val _bloomFilter = new Mutable(BloomFilter.empty)
def bloomFilter: BloomFilter = _bloomFilter.atomicGet
val controlMessageHandler = ControlMessageHandler(this)
override def getDataMessageHandler: DataMessageHandler = dataMessageHandler
override val peerManager: PeerManager = PeerManager(this, configPeersOverride)
def setBloomFilter(bloom: BloomFilter): SpvNode = {
_bloomFilter.atomicSet(bloom)
this
}
override def updateDataMessageHandler(
dataMessageHandler: DataMessageHandler): SpvNode = {
copy(dataMessageHandler = dataMessageHandler)
}
/** Updates our bloom filter to match the given TX
*
* @return SPV node with the updated bloom filter
*/
def updateBloomFilter(transaction: Transaction): Future[SpvNode] = {
logger.info(s"Updating bloom filter with transaction=${transaction.txIdBE}")
val newBloom = _bloomFilter.atomicUpdate(transaction)(_.update(_))
// we could send filteradd messages, but we would
// then need to calculate all the new elements in
// the filter. this is easier:-)
for {
_ <- peerMsgSenders(0).sendFilterClearMessage()
_ <- peerMsgSenders(0).sendFilterLoadMessage(newBloom)
} yield this
}
/** Updates our bloom filter to match the given address
*
* @return SPV node with the updated bloom filter
*/
def updateBloomFilter(address: BitcoinAddress): Future[SpvNode] = {
logger.info(s"Updating bloom filter with address=$address")
val hash = address.hash
_bloomFilter.atomicUpdate(hash)(_.insert(_))
val sentFilterAddF = peerMsgSenders(0).sendFilterAddMessage(hash)
sentFilterAddF.map(_ => this)
}
override def start(): Future[SpvNode] = {
for {
node <- super.start()
_ <- AsyncUtil.retryUntilSatisfiedF(() => isConnected(0))
_ <- peerMsgSenders(0).sendFilterLoadMessage(bloomFilter)
} yield {
logger.info(
s"Sending bloomfilter=${bloomFilter.hex} to ${peerManager.peers(0)}")
node.asInstanceOf[SpvNode]
}
}
/** Returns the block height of the given block stamp */
override def getHeightByBlockStamp(blockStamp: BlockStamp): Future[Int] =
chainApiFromDb().flatMap(_.getHeightByBlockStamp(blockStamp))
private val cfErrMsg = "Compact filters are not supported in SPV mode"
/** Gets the number of compact filters in the database */
override def getFilterCount(): Future[Int] =
Future.failed(new RuntimeException(cfErrMsg))
override def getFiltersBetweenHeights(
startHeight: Int,
endHeight: Int): Future[Vector[FilterResponse]] =
Future.failed(new RuntimeException(cfErrMsg))
}

View File

@ -72,7 +72,7 @@ case class NodeAppConfig(baseDatadir: Path, configOverrides: Vector[Config])(
case None =>
Future.unit
}
case NodeType.SpvNode | NodeType.NeutrinoNode | NodeType.FullNode =>
case NodeType.NeutrinoNode | NodeType.FullNode =>
Future.unit
}
}
@ -170,13 +170,6 @@ object NodeAppConfig extends AppConfigFactoryActorSystem[NodeAppConfig] {
.map(handler => DataMessageHandler(handler, walletCreationTimeOpt))
nodeConf.nodeType match {
case NodeType.SpvNode =>
dmhF.map(dmh =>
SpvNode(dmh,
nodeConf,
chainConf,
system,
configPeersOverride = peers))
case NodeType.NeutrinoNode =>
dmhF.map(dmh =>
NeutrinoNode(dmh,

View File

@ -92,8 +92,6 @@ case class ControlMessageHandler(node: Node)(implicit ec: ExecutionContext)
throw new Exception("Node cannot be FullNode")
case NodeType.NeutrinoNode =>
node.peerManager.createInDb(peer).map(_ => ())
case NodeType.SpvNode =>
node.peerManager.createInDb(peer).map(_ => ())
}
case nodeType: ExternalImplementationNodeType =>
nodeType match {

View File

@ -207,12 +207,6 @@ case class DataMessageHandler(
s"Received headers=${headers.map(_.hashBE.hex).mkString("[", ",", "]")}")
val chainApiF = chainApi.processHeaders(headers)
if (appConfig.nodeType == NodeType.SpvNode) {
logger.trace(s"Requesting data for headers=${headers.length}")
peerMsgSender.sendGetDataMessage(TypeIdentifier.MsgFilteredBlock,
headers.map(_.hash): _*)
}
val getHeadersF = chainApiF
.flatMap { newApi =>
if (headers.nonEmpty) {
@ -399,10 +393,7 @@ case class DataMessageHandler(
logger.debug(s"Received inv=${invMsg}")
val getData = GetDataMessage(invMsg.inventories.flatMap {
case Inventory(TypeIdentifier.MsgBlock, hash) =>
// only request the merkle block if we are spv enabled
appConfig.nodeType match {
case NodeType.SpvNode =>
Some(Inventory(TypeIdentifier.MsgFilteredBlock, hash))
case NodeType.NeutrinoNode | NodeType.FullNode =>
if (syncing) None
else Some(Inventory(TypeIdentifier.MsgWitnessBlock, hash))

View File

@ -33,55 +33,6 @@ object BitcoinSTestAppConfig {
}
}
/** App configuration suitable for test purposes:
*
* 1) Data directory is set to user temp directory
* 2) Logging is turned down to WARN
*/
def getSpvTestConfig(config: Config*)(implicit
system: ActorSystem): BitcoinSAppConfig = {
val overrideConf = ConfigFactory.parseString {
s"""
|bitcoin-s {
| node {
| mode = spv
| }
| wallet {
| allowExternalDLCAddresses = true
| }
| proxy.enabled = $torEnabled
| tor.enabled = $torEnabled
| tor.use-random-ports = false
|}
""".stripMargin
}
BitcoinSAppConfig(tmpDir(), (overrideConf +: config).toVector)
}
def getSpvWithEmbeddedDbTestConfig(
pgUrl: () => Option[String],
config: Vector[Config])(implicit
system: ActorSystem): BitcoinSAppConfig = {
val overrideConf = ConfigFactory
.parseString {
s"""
|bitcoin-s {
| node {
| mode = spv
| }
| proxy.enabled = $torEnabled
| tor.enabled = $torEnabled
| tor.use-random-ports = false
|}
""".stripMargin
}
.withFallback(genWalletNameConf)
BitcoinSAppConfig(
tmpDir(),
(overrideConf +: configWithEmbeddedDb(project = None, pgUrl) +: config))
}
def getNeutrinoTestConfig(config: Config*)(implicit
system: ActorSystem): BitcoinSAppConfig = {
val overrideConf = ConfigFactory.parseString {
@ -91,7 +42,9 @@ object BitcoinSTestAppConfig {
| mode = neutrino
| relay = true
| }
|
| wallet {
| allowExternalDLCAddresses = true
| }
| proxy.enabled = $torEnabled
| tor.enabled = $torEnabled
| tor.use-random-ports = false

View File

@ -11,7 +11,7 @@ trait ChainDbUnitTest extends ChainUnitTest with EmbeddedPg {
val memoryDb =
BitcoinSTestAppConfig.configWithEmbeddedDb(Some(ProjectType.Chain), pgUrl)
val chainConfig: ChainAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig().chainConf
BitcoinSTestAppConfig.getNeutrinoTestConfig().chainConf
chainConfig.withOverrides(memoryDb)
}
@ -20,7 +20,7 @@ trait ChainDbUnitTest extends ChainUnitTest with EmbeddedPg {
BitcoinSTestAppConfig.configWithEmbeddedDb(Some(ProjectType.Chain), pgUrl)
val mainnetConf = ConfigFactory.parseString("bitcoin-s.network = mainnet")
val chainConfig: ChainAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig(mainnetConf).chainConf
BitcoinSTestAppConfig.getNeutrinoTestConfig(mainnetConf).chainConf
chainConfig.withOverrides(memoryDb)
}

View File

@ -48,7 +48,7 @@ trait ChainUnitTest
*/
lazy val mainnetAppConfig: ChainAppConfig = {
val mainnetConf = ConfigFactory.parseString("bitcoin-s.network = mainnet")
BitcoinSTestAppConfig.getSpvTestConfig(mainnetConf).chainConf
BitcoinSTestAppConfig.getNeutrinoTestConfig(mainnetConf).chainConf
}
override def beforeAll(): Unit = {

View File

@ -17,7 +17,7 @@ trait NodeDAOFixture extends NodeUnitTest with CachedBitcoinSAppConfig {
/** Wallet config with data directory set to user temp directory */
override protected def getFreshConfig: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvWithEmbeddedDbTestConfig(pgUrl, Vector.empty)
BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig(pgUrl)
private lazy val daos = {
val tx = BroadcastAbleTransactionDAO()

View File

@ -47,7 +47,7 @@ trait CachedChainAppConfig {
_: BitcoinSAkkaAsyncTest =>
private[this] lazy val cachedConfig: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig()
BitcoinSTestAppConfig.getNeutrinoTestConfig()
implicit protected lazy val cachedChainConf: ChainAppConfig = {
cachedConfig.chainConf

View File

@ -1,11 +1,10 @@
package org.bitcoins.testkit.node
import org.bitcoins.node.{NeutrinoNode, Node, SpvNode}
import org.bitcoins.node.{NeutrinoNode, Node}
import org.bitcoins.rpc.client.common.BitcoindRpcClient
import org.bitcoins.testkit.node.fixture.{
NeutrinoNodeConnectedWithBitcoind,
NodeConnectedWithBitcoind,
SpvNodeConnectedWithBitcoind
NodeConnectedWithBitcoind
}
import org.bitcoins.wallet.Wallet
@ -13,7 +12,7 @@ import org.bitcoins.wallet.Wallet
* 1. a funded bitcoind wallet
* 2. a funded bitcoin-s wallet
* 3. a chain handler with the appropriate tables created
* 4. a spv node that is connected to the bitcoin instance -- but not started!
* 4. a neutrino node that is connected to the bitcoin instance -- but not started!
*/
trait NodeFundedWalletBitcoind {
def node: Node
@ -25,18 +24,6 @@ trait NodeFundedWalletBitcoind {
def toNodeConnectedWithBitcoind: NodeConnectedWithBitcoind
}
case class SpvNodeFundedWalletBitcoind(
node: SpvNode,
wallet: Wallet,
bitcoindRpc: BitcoindRpcClient,
bip39PasswordOpt: Option[String])
extends NodeFundedWalletBitcoind {
override def toNodeConnectedWithBitcoind: SpvNodeConnectedWithBitcoind = {
SpvNodeConnectedWithBitcoind(node, bitcoindRpc)
}
}
case class NeutrinoNodeFundedWalletBitcoind(
node: NeutrinoNode,
wallet: Wallet,

View File

@ -5,14 +5,11 @@ import org.bitcoins.core.api.node.NodeType
import org.bitcoins.node.Node
import org.bitcoins.node.models.Peer
import org.bitcoins.rpc.client.common.BitcoindRpcClient
import org.bitcoins.rpc.client.v19.BitcoindV19RpcClient
import org.bitcoins.server.BitcoinSAppConfig
import org.bitcoins.testkit.node.NodeUnitTest.{createPeer, syncNeutrinoNode}
import org.bitcoins.testkit.node.fixture.{
NeutrinoNodeConnectedWithBitcoind,
NeutrinoNodeConnectedWithBitcoinds,
SpvNodeConnectedWithBitcoind,
SpvNodeConnectedWithBitcoindV19
NeutrinoNodeConnectedWithBitcoinds
}
import org.bitcoins.testkit.rpc.{
CachedBitcoind,
@ -34,48 +31,27 @@ import scala.concurrent.Future
trait NodeTestWithCachedBitcoind extends BaseNodeTest with CachedTor {
_: CachedBitcoind[_] =>
def withSpvNodeFundedWalletBitcoindCached(
test: OneArgAsyncTest,
bip39PasswordOpt: Option[String],
bitcoind: BitcoindRpcClient)(implicit
system: ActorSystem,
appConfig: BitcoinSAppConfig): FutureOutcome = {
makeDependentFixture[SpvNodeFundedWalletBitcoind](
build = () =>
NodeUnitTest.createSpvNodeFundedWalletFromBitcoind(
walletCallbacks = WalletCallbacks.empty,
bip39PasswordOpt = bip39PasswordOpt,
bitcoind = bitcoind)(
system, // Force V18 because Spv is disabled on versions after
appConfig),
{ x: SpvNodeFundedWalletBitcoind =>
tearDownNodeWithBitcoind(x)
}
)(test)
}
def withSpvNodeConnectedToBitcoindCached(
def withNeutrinoNodeConnectedToBitcoindCached(
test: OneArgAsyncTest,
bitcoind: BitcoindRpcClient)(implicit
system: ActorSystem,
appConfig: BitcoinSAppConfig): FutureOutcome = {
val nodeWithBitcoindBuilder: () => Future[SpvNodeConnectedWithBitcoind] = {
() =>
require(appConfig.nodeConf.nodeType == NodeType.SpvNode)
for {
peer <- createPeer(bitcoind)
node <- NodeUnitTest.createSpvNode(peer, None)(system,
appConfig.chainConf,
appConfig.nodeConf)
started <- node.start()
_ <- NodeUnitTest.syncSpvNode(started, bitcoind)
} yield SpvNodeConnectedWithBitcoind(node, bitcoind)
val nodeWithBitcoindBuilder: () => Future[
NeutrinoNodeConnectedWithBitcoind] = { () =>
require(appConfig.nodeConf.nodeType == NodeType.NeutrinoNode)
for {
peer <- createPeer(bitcoind)
node <- NodeUnitTest.createNeutrinoNode(peer, None)(system,
appConfig.chainConf,
appConfig.nodeConf)
started <- node.start()
_ <- NodeUnitTest.syncNeutrinoNode(started, bitcoind)
} yield NeutrinoNodeConnectedWithBitcoind(node, bitcoind)
}
makeDependentFixture[SpvNodeConnectedWithBitcoind](
makeDependentFixture[NeutrinoNodeConnectedWithBitcoind](
build = nodeWithBitcoindBuilder,
{ x: SpvNodeConnectedWithBitcoind =>
{ x: NeutrinoNodeConnectedWithBitcoind =>
NodeUnitTest.destroyNode(x.node)
})(test)
}
@ -205,32 +181,6 @@ trait NodeTestWithCachedBitcoindV19
extends NodeTestWithCachedBitcoind
with CachedBitcoindV19 {
def withSpvNodeConnectedToBitcoindV19Cached(
test: OneArgAsyncTest,
bitcoind: BitcoindV19RpcClient)(implicit
system: ActorSystem,
appConfig: BitcoinSAppConfig): FutureOutcome = {
val nodeWithBitcoindBuilder: () => Future[
SpvNodeConnectedWithBitcoindV19] = { () =>
require(appConfig.nodeConf.nodeType == NodeType.SpvNode)
for {
peer <- createPeer(bitcoind)
node <- NodeUnitTest.createSpvNode(peer, None)(system,
appConfig.chainConf,
appConfig.nodeConf)
started <- node.start()
_ <- NodeUnitTest.syncSpvNode(started, bitcoind)
} yield SpvNodeConnectedWithBitcoindV19(node, bitcoind)
}
makeDependentFixture[SpvNodeConnectedWithBitcoindV19](
build = nodeWithBitcoindBuilder,
{ x: SpvNodeConnectedWithBitcoindV19 =>
NodeUnitTest.destroyNode(x.node)
}
)(test)
}
override def afterAll(): Unit = {
super[CachedBitcoindV19].afterAll()
super[NodeTestWithCachedBitcoind].afterAll()

View File

@ -10,22 +10,17 @@ import org.bitcoins.node._
import org.bitcoins.node.config.NodeAppConfig
import org.bitcoins.node.models.Peer
import org.bitcoins.node.networking.peer._
import org.bitcoins.rpc.client.common.BitcoindVersion.{V18, V21, V22}
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion}
import org.bitcoins.rpc.client.v21.BitcoindV21RpcClient
import org.bitcoins.rpc.client.common.BitcoindVersion.V22
import org.bitcoins.rpc.client.v22.BitcoindV22RpcClient
import org.bitcoins.testkit.node.NodeUnitTest.createPeer
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion}
import org.bitcoins.rpc.util.RpcUtil
import org.bitcoins.server.BitcoinSAppConfig
import org.bitcoins.testkit.chain.ChainUnitTest
import org.bitcoins.testkit.fixtures.BitcoinSFixture
import org.bitcoins.testkit.node.NodeUnitTest.{
createPeer,
emptyPeer,
syncNeutrinoNode
}
import org.bitcoins.testkit.node.NodeUnitTest.{emptyPeer, syncNeutrinoNode}
import org.bitcoins.testkit.node.fixture._
import org.bitcoins.testkit.wallet.{BitcoinSWalletTest, WalletWithBitcoindRpc}
import org.bitcoins.testkitcore.node.P2PMessageTestUtil
import org.bitcoins.wallet.WalletCallbacks
import org.scalatest.FutureOutcome
@ -35,16 +30,17 @@ import scala.concurrent.{ExecutionContext, Future}
trait NodeUnitTest extends BaseNodeTest {
def withDisconnectedSpvNode(test: OneArgAsyncTest)(implicit
def withDisconnectedNeutrinoNode(test: OneArgAsyncTest)(implicit
system: ActorSystem,
appConfig: BitcoinSAppConfig): FutureOutcome = {
val nodeBuilder: () => Future[SpvNode] = { () =>
require(appConfig.nodeConf.nodeType == NodeType.SpvNode)
val nodeBuilder: () => Future[NeutrinoNode] = { () =>
require(appConfig.nodeConf.nodeType == NodeType.NeutrinoNode)
for {
node <- NodeUnitTest.createSpvNode(emptyPeer, None)(system,
appConfig.chainConf,
appConfig.nodeConf)
node <- NodeUnitTest.createNeutrinoNode(emptyPeer, None)(
system,
appConfig.chainConf,
appConfig.nodeConf)
//we aren't calling node.start(), but we need to call appConfig.start()
//to make sure migrations are run
_ <- node.chainConfig.start()
@ -64,77 +60,24 @@ trait NodeUnitTest extends BaseNodeTest {
)(test)
}
def withSpvNodeConnectedToBitcoind(
test: OneArgAsyncTest,
versionOpt: Option[BitcoindVersion] = None)(implicit
system: ActorSystem,
appConfig: BitcoinSAppConfig): FutureOutcome = {
val nodeWithBitcoindBuilder: () => Future[SpvNodeConnectedWithBitcoind] = {
() =>
require(appConfig.nodeConf.nodeType == NodeType.SpvNode)
for {
bitcoind <- BitcoinSFixture.createBitcoind(versionOpt)
peer <- createPeer(bitcoind)
node <- NodeUnitTest.createSpvNode(peer, None)(system,
appConfig.chainConf,
appConfig.nodeConf)
started <- node.start()
_ <- NodeUnitTest.syncSpvNode(started, bitcoind)
} yield SpvNodeConnectedWithBitcoind(node, bitcoind)
}
makeDependentFixture(
build = nodeWithBitcoindBuilder,
destroy = NodeUnitTest.destroyNodeConnectedWithBitcoind(
_: NodeConnectedWithBitcoind)(system, appConfig)
)(test)
}
def withSpvNodeConnectedToBitcoindV21(test: OneArgAsyncTest)(implicit
def withNeutrinoNodeConnectedToBitcoindV22(test: OneArgAsyncTest)(implicit
system: ActorSystem,
appConfig: BitcoinSAppConfig): FutureOutcome = {
val nodeWithBitcoindBuilder: () => Future[
SpvNodeConnectedWithBitcoindV21] = { () =>
require(appConfig.nodeConf.nodeType == NodeType.SpvNode)
for {
bitcoind <-
BitcoinSFixture
.createBitcoindWithFunds(Some(V21))
.map(_.asInstanceOf[BitcoindV21RpcClient])
peer <- createPeer(bitcoind)
node <- NodeUnitTest.createSpvNode(peer, None)(system,
appConfig.chainConf,
appConfig.nodeConf)
started <- node.start()
_ <- NodeUnitTest.syncSpvNode(started, bitcoind)
} yield SpvNodeConnectedWithBitcoindV21(node, bitcoind)
}
makeDependentFixture(
build = nodeWithBitcoindBuilder,
destroy = NodeUnitTest.destroyNodeConnectedWithBitcoind(
_: NodeConnectedWithBitcoind)(system, appConfig)
)(test)
}
def withSpvNodeConnectedToBitcoindV22(test: OneArgAsyncTest)(implicit
system: ActorSystem,
appConfig: BitcoinSAppConfig): FutureOutcome = {
val nodeWithBitcoindBuilder: () => Future[
SpvNodeConnectedWithBitcoindV22] = { () =>
require(appConfig.nodeConf.nodeType == NodeType.SpvNode)
NeutrinoNodeConnectedWithBitcoindV22] = { () =>
require(appConfig.nodeConf.nodeType == NodeType.NeutrinoNode)
for {
bitcoind <-
BitcoinSFixture
.createBitcoindWithFunds(Some(V22))
.map(_.asInstanceOf[BitcoindV22RpcClient])
peer <- createPeer(bitcoind)
node <- NodeUnitTest.createSpvNode(peer, None)(system,
appConfig.chainConf,
appConfig.nodeConf)
node <- NodeUnitTest.createNeutrinoNode(peer, None)(system,
appConfig.chainConf,
appConfig.nodeConf)
started <- node.start()
_ <- NodeUnitTest.syncSpvNode(started, bitcoind)
} yield SpvNodeConnectedWithBitcoindV22(node, bitcoind)
_ <- NodeUnitTest.syncNeutrinoNode(started, bitcoind)
} yield NeutrinoNodeConnectedWithBitcoindV22(node, bitcoind)
}
makeDependentFixture(
@ -170,26 +113,6 @@ trait NodeUnitTest extends BaseNodeTest {
)(test)
}
def withSpvNodeFundedWalletBitcoind(
test: OneArgAsyncTest,
bip39PasswordOpt: Option[String])(implicit
system: ActorSystem,
appConfig: BitcoinSAppConfig): FutureOutcome = {
makeDependentFixture(
build = () =>
NodeUnitTest.createSpvNodeFundedWalletBitcoind(bip39PasswordOpt =
bip39PasswordOpt,
versionOpt = Option(V18),
walletCallbacks =
WalletCallbacks.empty)(
system, // Force V18 because Spv is disabled on versions after
appConfig),
destroy = NodeUnitTest.destroyNodeFundedWalletBitcoind(
_: NodeFundedWalletBitcoind)(system, appConfig)
)(test)
}
def withNeutrinoNodeFundedWalletBitcoind(
test: OneArgAsyncTest,
bip39PasswordOpt: Option[String],
@ -324,66 +247,6 @@ object NodeUnitTest extends P2PLogger {
resultF
}
/** Creates a spv node, a funded bitcoin-s wallet, all of which are connected to bitcoind */
def createSpvNodeFundedWalletBitcoind(
walletCallbacks: WalletCallbacks,
bip39PasswordOpt: Option[String],
versionOpt: Option[BitcoindVersion] = None)(implicit
system: ActorSystem,
appConfig: BitcoinSAppConfig): Future[SpvNodeFundedWalletBitcoind] = {
import system.dispatcher
require(appConfig.nodeConf.nodeType == NodeType.SpvNode)
for {
bitcoind <- BitcoinSFixture.createBitcoindWithFunds(versionOpt)
spvNodeWithBitcoind <- createSpvNodeFundedWalletFromBitcoind(
walletCallbacks,
bip39PasswordOpt,
bitcoind)
} yield {
spvNodeWithBitcoind
}
}
/** Creates a spv node & funded wallet with the given bitcoind */
def createSpvNodeFundedWalletFromBitcoind(
walletCallbacks: WalletCallbacks,
bip39PasswordOpt: Option[String],
bitcoind: BitcoindRpcClient)(implicit
system: ActorSystem,
appConfig: BitcoinSAppConfig): Future[SpvNodeFundedWalletBitcoind] = {
import system.dispatcher
require(appConfig.nodeConf.nodeType == NodeType.SpvNode)
for {
peer <- createPeer(bitcoind)
node <- createSpvNode(peer, None)(system,
appConfig.chainConf,
appConfig.nodeConf)
fundedWallet <- BitcoinSWalletTest.fundedWalletAndBitcoind(
bitcoindRpcClient = bitcoind,
nodeApi = node,
chainQueryApi = bitcoind,
bip39PasswordOpt = bip39PasswordOpt,
walletCallbacks = walletCallbacks)
spvCallbacks =
BitcoinSWalletTest.createSpvNodeCallbacksForWallet(fundedWallet.wallet)
_ = appConfig.nodeConf.addCallbacks(spvCallbacks)
walletBloomFilter <- fundedWallet.wallet.getBloomFilter()
withBloomFilter = node.setBloomFilter(walletBloomFilter)
startedNodeWithBloomFilter <- withBloomFilter.start()
_ <- syncSpvNode(startedNodeWithBloomFilter, bitcoind)
//callbacks are executed asynchronously, which is how we fund the wallet
//so we need to wait until the wallet balances are correct
_ <- BitcoinSWalletTest.awaitWalletBalances(fundedWallet)(
appConfig.walletConf,
system)
} yield {
SpvNodeFundedWalletBitcoind(node = startedNodeWithBloomFilter,
wallet = fundedWallet.wallet,
bitcoindRpc = fundedWallet.bitcoind,
bip39PasswordOpt)
}
}
/** Creates a neutrino node, a funded bitcoin-s wallet, all of which are connected to bitcoind */
def createNeutrinoNodeFundedWalletBitcoind(
bip39PasswordOpt: Option[String],
@ -505,37 +368,8 @@ object NodeUnitTest extends P2PLogger {
Peer(id = None, socket = socket, socks5ProxyParams = None)
}
/** Creates a spv node peered with the given bitcoind client
* This does NOT start the spv node
*/
def createSpvNode(peer: Peer, walletCreationTimeOpt: Option[Instant])(implicit
system: ActorSystem,
chainAppConfig: ChainAppConfig,
nodeAppConfig: NodeAppConfig): Future[SpvNode] = {
import system.dispatcher
val checkConfigF = Future {
assert(nodeAppConfig.nodeType == NodeType.SpvNode)
}
for {
_ <- checkConfigF
_ <- nodeAppConfig.start()
chainHandler <- ChainUnitTest.createChainHandler()
} yield {
val dmh = DataMessageHandler(chainHandler, walletCreationTimeOpt)
SpvNode(
configPeersOverride = Vector(peer),
dataMessageHandler = dmh,
nodeConfig = nodeAppConfig,
chainConfig = chainAppConfig,
actorSystem = system
).setBloomFilter(P2PMessageTestUtil.emptyBloomFilter)
}
}
/** Creates a Neutrino node peered with the given bitcoind client, this method
* also calls [[org.bitcoins.node.Node.start() start]] to start the node
/** Creates a Neutrino node peered with the given bitcoind client, this does NOT
* start the neutrino node
*/
def createNeutrinoNode(
bitcoind: BitcoindRpcClient,
@ -568,8 +402,40 @@ object NodeUnitTest extends P2PLogger {
nodeF
}
/** Creates a Neutrino node peered with the given bitcoind client, this method
* also calls [[org.bitcoins.node.Node.start() start]] to start the node
/** Creates a Neutrino node peered with the given peer, this does NOT
* start the neutrino node
*/
def createNeutrinoNode(peer: Peer, walletCreationTimeOpt: Option[Instant])(
implicit
system: ActorSystem,
chainAppConfig: ChainAppConfig,
nodeAppConfig: NodeAppConfig): Future[NeutrinoNode] = {
import system.dispatcher
val checkConfigF = Future {
assert(nodeAppConfig.nodeType == NodeType.NeutrinoNode)
}
val chainApiF = for {
_ <- checkConfigF
chainHandler <- ChainUnitTest.createChainHandler()
} yield chainHandler
val nodeF = for {
_ <- nodeAppConfig.start()
chainApi <- chainApiF
} yield {
val dmh = DataMessageHandler(chainApi, walletCreationTimeOpt)
NeutrinoNode(configPeersOverride = Vector(peer),
dataMessageHandler = dmh,
nodeConfig = nodeAppConfig,
chainConfig = chainAppConfig,
actorSystem = system)
}
nodeF
}
/** Creates a Neutrino node peered with the given bitcoind client, this does NOT
* start the neutrino node
*/
def createNeutrinoNode(
bitcoinds: Vector[BitcoindRpcClient],
@ -615,15 +481,6 @@ object NodeUnitTest extends P2PLogger {
} yield node
}
def syncSpvNode(node: SpvNode, bitcoind: BitcoindRpcClient)(implicit
system: ActorSystem): Future[SpvNode] = {
import system.dispatcher
for {
_ <- node.sync()
_ <- NodeTestUtil.awaitSync(node, bitcoind)
} yield node
}
/** This is needed for postgres, we do not drop tables in between individual tests with postgres
* rather an entire test suite shares the same postgres database.
* therefore, we need to clean the database after each test, so that migrations can be applied during

View File

@ -1,37 +1,15 @@
package org.bitcoins.testkit.node.fixture
import org.bitcoins.node.{NeutrinoNode, Node, SpvNode}
import org.bitcoins.node.{NeutrinoNode, Node}
import org.bitcoins.rpc.client.common.BitcoindRpcClient
import org.bitcoins.rpc.client.v19.BitcoindV19RpcClient
import org.bitcoins.rpc.client.v21.BitcoindV21RpcClient
import org.bitcoins.rpc.client.v22.BitcoindV22RpcClient
/** Gives us a fixture that has a SPV node connected with the bitcoind instance */
/** Gives us a fixture that has a Neutrino node connected with the bitcoind instance */
trait NodeConnectedWithBitcoind {
def node: Node
def bitcoind: BitcoindRpcClient
}
case class SpvNodeConnectedWithBitcoind(
node: SpvNode,
bitcoind: BitcoindRpcClient)
extends NodeConnectedWithBitcoind
case class SpvNodeConnectedWithBitcoindV22(
node: SpvNode,
bitcoind: BitcoindV22RpcClient)
extends NodeConnectedWithBitcoind
case class SpvNodeConnectedWithBitcoindV21(
node: SpvNode,
bitcoind: BitcoindV21RpcClient)
extends NodeConnectedWithBitcoind
case class SpvNodeConnectedWithBitcoindV19(
node: SpvNode,
bitcoind: BitcoindV19RpcClient)
extends NodeConnectedWithBitcoind
case class NeutrinoNodeConnectedWithBitcoind(
node: NeutrinoNode,
bitcoind: BitcoindRpcClient)
@ -46,3 +24,8 @@ case class NeutrinoNodeConnectedWithBitcoinds(
node: NeutrinoNode,
bitcoinds: Vector[BitcoindRpcClient]
) extends NodeConnectedWithBitcoinds
case class NeutrinoNodeConnectedWithBitcoindV22(
node: NeutrinoNode,
bitcoind: BitcoindV22RpcClient)
extends NodeConnectedWithBitcoind

View File

@ -16,7 +16,7 @@ trait CachedTor {
_: BitcoinSAkkaAsyncTest =>
implicit protected lazy val torConfig: TorAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig().torConf
BitcoinSTestAppConfig.getNeutrinoTestConfig().torConf
protected val isTorStarted: AtomicBoolean = new AtomicBoolean(false)

View File

@ -141,7 +141,7 @@ object BaseWalletTest {
def getFreshConfig(pgUrl: () => Option[String], config: Vector[Config])(
implicit system: ActorSystem): BitcoinSAppConfig = {
BitcoinSTestAppConfig.getSpvWithEmbeddedDbTestConfig(pgUrl, config)
BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig(pgUrl, config: _*)
}
def getFreshWalletAppConfig(

View File

@ -21,7 +21,7 @@ trait BitcoinSDualWalletTest extends BitcoinSWalletTest {
import BitcoinSWalletTest._
implicit protected def config2: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig()
BitcoinSTestAppConfig.getNeutrinoTestConfig()
implicit protected def wallet2AppConfig: WalletAppConfig = {
config2.walletConf

View File

@ -16,7 +16,7 @@ import org.bitcoins.core.wallet.fee._
import org.bitcoins.crypto.{DoubleSha256Digest, DoubleSha256DigestBE}
import org.bitcoins.dlc.wallet.{DLCAppConfig, DLCWallet}
import org.bitcoins.node.config.NodeAppConfig
import org.bitcoins.node.{NodeCallbacks, OnMerkleBlockReceived}
import org.bitcoins.node.NodeCallbacks
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion}
import org.bitcoins.rpc.client.v19.BitcoindV19RpcClient
import org.bitcoins.server.BitcoinSAppConfig
@ -699,19 +699,6 @@ object BitcoinSWalletTest extends WalletLogger {
CallbackUtil.createNeutrinoNodeCallbacksForWallet(wallet)
}
/** Registers a callback to handle merkle blocks given to us by a spv node */
def createSpvNodeCallbacksForWallet(wallet: Wallet)(implicit
ec: ExecutionContext): NodeCallbacks = {
val onMerkleBlockReceived: OnMerkleBlockReceived = {
case (merkleBlock, txs) =>
for {
_ <- wallet.processTransactions(txs,
Some(merkleBlock.blockHeader.hashBE))
} yield ()
}
NodeCallbacks(onMerkleBlockReceived = Vector(onMerkleBlockReceived))
}
/** Makes sure our wallet is fully funded with the default amounts specified in
* [[BitcoinSWalletTest]]. This will future won't be completed until balances satisfy [[isSameWalletBalances()]]
*/

View File

@ -19,7 +19,7 @@ trait DualWalletTestCachedBitcoind
import BitcoinSWalletTest._
implicit protected def config2: BitcoinSAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig()
BitcoinSTestAppConfig.getNeutrinoTestConfig()
implicit protected def wallet2AppConfig: WalletAppConfig = {
config2.walletConf

View File

@ -224,7 +224,7 @@ class TrezorAddressTest extends BitcoinSWalletTest with EmptyFixture {
private def testAccountType(purpose: HDPurpose): Future[Assertion] = {
val confOverride = configForPurposeAndSeed(purpose)
implicit val conf: WalletAppConfig =
BitcoinSTestAppConfig.getSpvTestConfig(confOverride).walletConf
BitcoinSTestAppConfig.getNeutrinoTestConfig(confOverride).walletConf
val testVectors = purpose match {
case HDPurposes.Legacy => legacyVectors

View File

@ -1,61 +0,0 @@
package org.bitcoins.wallet
import org.bitcoins.core.util.FutureUtil
import org.bitcoins.testkitcore.Implicits._
import org.bitcoins.testkit.wallet.{
BitcoinSWalletTestCachedBitcoindNewest,
WalletWithBitcoind,
WalletWithBitcoindRpc
}
import org.scalatest.{FutureOutcome, Outcome}
import scala.concurrent.Future
class WalletBloomTest extends BitcoinSWalletTestCachedBitcoindNewest {
behavior of "Wallet bloom filter"
override type FixtureParam = WalletWithBitcoind
override def withFixture(test: OneArgAsyncTest): FutureOutcome = {
val f: Future[Outcome] = for {
bitcoind <- cachedBitcoindWithFundsF
futOutcome = withFundedWalletAndBitcoindCached(
test,
getBIP39PasswordOpt(),
bitcoind)(getFreshWalletAppConfig)
fut <- futOutcome.toFuture
} yield fut
new FutureOutcome(f)
}
it should "generate a bloom filter that matches the pubkeys in our wallet" in {
param =>
val WalletWithBitcoindRpc(walletApi, _) = param
val wallet = walletApi.asInstanceOf[Wallet]
for {
_ <- FutureUtil.sequentially(0 until 10)(_ => wallet.getNewAddress())
bloom <- wallet.getBloomFilter()
pubkeys <- wallet.listPubkeys()
} yield {
pubkeys.map { pub =>
assert(bloom.contains(pub))
}.toAssertion
}
}
it should "generate a bloom filter that matches the outpoints in our wallet" in {
param =>
val WalletWithBitcoindRpc(walletApi, _) = param
val wallet = walletApi.asInstanceOf[Wallet]
for {
outpoints <- wallet.listOutpoints()
bloom <- wallet.getBloomFilter()
} yield {
outpoints.map { out =>
assert(bloom.contains(out))
}.toAssertion
}
}
}

View File

@ -10,7 +10,6 @@ import org.bitcoins.core.api.wallet.{
BlockSyncState,
CoinSelectionAlgo
}
import org.bitcoins.core.bloom.{BloomFilter, BloomUpdateAll}
import org.bitcoins.core.config.BitcoinNetwork
import org.bitcoins.core.crypto.ExtPublicKey
import org.bitcoins.core.currency._
@ -374,45 +373,6 @@ abstract class Wallet
protected[wallet] def listOutpoints(): Future[Vector[TransactionOutPoint]] =
spendingInfoDAO.findAllOutpoints()
/** Gets the size of the bloom filter for this wallet */
private def getBloomFilterSize(
pubkeys: Seq[ECPublicKey],
outpoints: Seq[TransactionOutPoint]): Int = {
// when a public key is inserted into a filter
// both the pubkey and the hash of the pubkey
// gets inserted
pubkeys.length * 2
} + outpoints.length
// todo: insert TXIDs? need to track which txids we should
// ask for, somehow
// We add all outpoints to the bloom filter as a way
// of working around the fact that bloom filters
// was never updated to incorporate SegWit changes.
// see this mailing list thread for context:
// https://www.mail-archive.com/bitcoin-dev@lists.linuxfoundation.org/msg06950.html
// especially this email from Jim Posen:
// https://www.mail-archive.com/bitcoin-dev@lists.linuxfoundation.org/msg06952.html
override def getBloomFilter(): Future[BloomFilter] = {
for {
pubkeys <- listPubkeys()
outpoints <- listOutpoints()
} yield {
val filterSize = getBloomFilterSize(pubkeys, outpoints)
// todo: Is this the best flag to use?
val bloomFlag = BloomUpdateAll
val baseBloom =
BloomFilter(numElements = filterSize,
falsePositiveRate = walletConfig.bloomFalsePositiveRate,
flags = bloomFlag)
val withPubs = pubkeys.foldLeft(baseBloom) { _.insert(_) }
outpoints.foldLeft(withPubs) { _.insert(_) }
}
}
/** Takes a [[RawTxBuilderWithFinalizer]] for a transaction to be sent, and completes it by:
* finalizing and signing the transaction, then correctly processing and logging it
*/

View File

@ -100,10 +100,6 @@ private[wallet] trait RescanHandling extends WalletLogger {
} yield rescanState
}
/** @inheritdoc */
override def rescanSPVWallet(): Future[Unit] =
Future.failed(new RuntimeException("Rescan not implemented for SPV wallet"))
lazy val walletCreationBlockHeight: Future[BlockHeight] =
chainQueryApi
.epochSecondToBlockHeight(creationTime.getEpochSecond)