mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-03 10:46:42 +01:00
Add all wallet outpoints to bloom filter
This is a workaround for Bloom filters never being updated for SegWit. See comment in LockedWallet#getBloomFilter for more context.
This commit is contained in:
parent
efc1ce4405
commit
45a3e93a3d
4 changed files with 69 additions and 27 deletions
|
@ -153,12 +153,17 @@ case class SafeDatabase(config: AppConfig) extends BitcoinSLogger {
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Runs the given DB action */
|
||||||
def run[R](action: DBIOAction[R, NoStream, _])(
|
def run[R](action: DBIOAction[R, NoStream, _])(
|
||||||
implicit ec: ExecutionContext): Future[R] = {
|
implicit ec: ExecutionContext): Future[R] = {
|
||||||
val result = database.run[R](foreignKeysPragma >> action)
|
val result = database.run[R](foreignKeysPragma >> action)
|
||||||
result.recoverWith { logAndThrowError(action) }
|
result.recoverWith { logAndThrowError(action) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the given DB sequence-returning DB action
|
||||||
|
* and converts the result to a vector
|
||||||
|
*/
|
||||||
def runVec[R](action: DBIOAction[Seq[R], NoStream, _])(
|
def runVec[R](action: DBIOAction[Seq[R], NoStream, _])(
|
||||||
implicit ec: ExecutionContext): Future[Vector[R]] = {
|
implicit ec: ExecutionContext): Future[Vector[R]] = {
|
||||||
val result = database.run[Seq[R]](foreignKeysPragma >> action)
|
val result = database.run[Seq[R]](foreignKeysPragma >> action)
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
package org.bitcoins.wallet
|
||||||
|
|
||||||
|
import org.bitcoins.testkit.wallet.BitcoinSWalletTest
|
||||||
|
import org.bitcoins.wallet.api.UnlockedWalletApi
|
||||||
|
import org.scalatest.FutureOutcome
|
||||||
|
import org.bitcoins.wallet.api.UnlockWalletError._
|
||||||
|
import org.bitcoins.wallet.api.UnlockWalletSuccess
|
||||||
|
import org.bitcoins.core.util.FutureUtil
|
||||||
|
import org.bitcoins.core.currency._
|
||||||
|
import org.bitcoins.testkit.Implicits._
|
||||||
|
|
||||||
|
class WalletBloomTest extends BitcoinSWalletTest {
|
||||||
|
behavior of "Wallet bloom filter"
|
||||||
|
|
||||||
|
override type FixtureParam = WalletWithBitcoind
|
||||||
|
|
||||||
|
override def withFixture(test: OneArgAsyncTest): FutureOutcome =
|
||||||
|
withNewWalletAndBitcoind(test)
|
||||||
|
|
||||||
|
it should "generate a bloom filter that matches the pubkeys in our wallet" in {
|
||||||
|
param =>
|
||||||
|
val WalletWithBitcoind(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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: change fixture to withFundedWalletAndBitcoind once #577 goes in
|
||||||
|
// https://github.com/bitcoin-s/bitcoin-s/pull/577/files#diff-0fb6ac004fe1e550b7c13258d7d0706cR154
|
||||||
|
it should "generate a bloom filter that matches the outpoints in our wallet" in {
|
||||||
|
param =>
|
||||||
|
val WalletWithBitcoind(walletApi, bitcoind) = param
|
||||||
|
val wallet = walletApi.asInstanceOf[Wallet]
|
||||||
|
|
||||||
|
for {
|
||||||
|
address <- wallet.getNewAddress()
|
||||||
|
tx <- bitcoind
|
||||||
|
.sendToAddress(address, 5.bitcoins)
|
||||||
|
.flatMap(bitcoind.getRawTransaction(_))
|
||||||
|
_ <- wallet.processTransaction(tx.hex, confirmations = 0)
|
||||||
|
outpoints <- wallet.listOutpoints()
|
||||||
|
|
||||||
|
bloom <- wallet.getBloomFilter()
|
||||||
|
} yield {
|
||||||
|
outpoints.map { (out) =>
|
||||||
|
assert(bloom.contains(out))
|
||||||
|
}.toAssertion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -121,33 +121,6 @@ class WalletUnitTest extends BitcoinSWalletTest {
|
||||||
} yield res
|
} yield res
|
||||||
}
|
}
|
||||||
|
|
||||||
it should "generate a bloom filter" in { walletApi: UnlockedWalletApi =>
|
|
||||||
val wallet = walletApi.asInstanceOf[Wallet]
|
|
||||||
for {
|
|
||||||
_ <- FutureUtil.sequentially(0 until 10)(_ => wallet.getNewAddress())
|
|
||||||
bloom <- wallet.getBloomFilter()
|
|
||||||
pubkeys <- wallet.listPubkeys()
|
|
||||||
} yield {
|
|
||||||
pubkeys.foldLeft(succeed) { (_, pub) =>
|
|
||||||
assert(bloom.contains(pub))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
it should "lock and unlock the wallet" in { wallet: UnlockedWalletApi =>
|
|
||||||
val passphrase = wallet.passphrase
|
|
||||||
val locked = wallet.lock()
|
|
||||||
val unlocked = wallet.unlock(passphrase) match {
|
|
||||||
case MnemonicNotFound => fail(MnemonicNotFound)
|
|
||||||
case BadPassword => fail(BadPassword)
|
|
||||||
case JsonParsingError(message) => fail(message)
|
|
||||||
case UnlockWalletSuccess(unlockedWalletApi) => unlockedWalletApi
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(wallet.mnemonicCode == unlocked.mnemonicCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
it should "fail to unlock the wallet with a bad password" in {
|
it should "fail to unlock the wallet with a bad password" in {
|
||||||
wallet: UnlockedWalletApi =>
|
wallet: UnlockedWalletApi =>
|
||||||
val badpassphrase = AesPassword.fromNonEmptyString("bad")
|
val badpassphrase = AesPassword.fromNonEmptyString("bad")
|
||||||
|
|
|
@ -9,6 +9,7 @@ import scala.concurrent.Future
|
||||||
import org.bitcoins.core.protocol.transaction.Transaction
|
import org.bitcoins.core.protocol.transaction.Transaction
|
||||||
import org.bitcoins.core.crypto.DoubleSha256DigestBE
|
import org.bitcoins.core.crypto.DoubleSha256DigestBE
|
||||||
import org.bitcoins.core.protocol.transaction.TransactionOutput
|
import org.bitcoins.core.protocol.transaction.TransactionOutput
|
||||||
|
import org.bitcoins.core.protocol.transaction.TransactionOutPoint
|
||||||
|
|
||||||
case class SpendingInfoDAO()(
|
case class SpendingInfoDAO()(
|
||||||
implicit val ec: ExecutionContext,
|
implicit val ec: ExecutionContext,
|
||||||
|
@ -96,4 +97,10 @@ case class SpendingInfoDAO()(
|
||||||
|
|
||||||
database.run(query.result).map(_.toVector)
|
database.run(query.result).map(_.toVector)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Enumerates all TX outpoints in the wallet */
|
||||||
|
def findAllOutpoints(): Future[Vector[TransactionOutPoint]] = {
|
||||||
|
val query = table.map(_.outPoint)
|
||||||
|
database.runVec(query.result).map(_.toVector)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue