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:
Torkel Rogstad 2019-07-10 17:31:10 +02:00
parent efc1ce4405
commit 45a3e93a3d
4 changed files with 69 additions and 27 deletions

View file

@ -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)

View file

@ -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
}
}
}

View file

@ -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")

View file

@ -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)
}
} }