mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-23 06:45:21 +01:00
Merge pull request #2029
* Add more processing blocks tests * Add immature coinbase txo state * Test balance, add doc
This commit is contained in:
parent
1e3aee55c3
commit
3ec3b5d699
6 changed files with 76 additions and 9 deletions
|
@ -128,7 +128,8 @@ case class NestedSegwitV0SpendingInfo(
|
|||
sealed trait SpendingInfoDb extends DbRowAutoInc[SpendingInfoDb] {
|
||||
|
||||
state match {
|
||||
case TxoState.ConfirmedSpent | TxoState.ConfirmedReceived =>
|
||||
case TxoState.ConfirmedSpent | TxoState.ConfirmedReceived |
|
||||
TxoState.ImmatureCoinbase =>
|
||||
require(blockHash.isDefined,
|
||||
"Transaction cannot be confirmed without a blockHash")
|
||||
case TxoState.DoesNotExist | TxoState.PendingConfirmationsSpent |
|
||||
|
|
|
@ -14,6 +14,11 @@ object TxoState extends StringFactory[TxoState] {
|
|||
/** Means that no funds have been sent to this utxo EVER */
|
||||
final case object DoesNotExist extends TxoState
|
||||
|
||||
/** A coinbase output that has not reached maturity and cannot be spent yet.
|
||||
* https://bitcoin.stackexchange.com/questions/1991/what-is-the-block-maturation-time
|
||||
*/
|
||||
final case object ImmatureCoinbase extends TxoState
|
||||
|
||||
/** Means we have received funds to this utxo, but they are not confirmed */
|
||||
final case object PendingConfirmationsReceived extends ReceivedState
|
||||
|
||||
|
@ -43,6 +48,7 @@ object TxoState extends StringFactory[TxoState] {
|
|||
Set(PendingConfirmationsSpent, TxoState.ConfirmedSpent, Reserved)
|
||||
|
||||
val all: Vector[TxoState] = Vector(DoesNotExist,
|
||||
ImmatureCoinbase,
|
||||
PendingConfirmationsReceived,
|
||||
ConfirmedReceived,
|
||||
Reserved,
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
package org.bitcoins.wallet
|
||||
|
||||
import org.bitcoins.core.currency._
|
||||
import org.bitcoins.testkit.wallet.{BitcoinSWalletTest, WalletWithBitcoindRpc}
|
||||
import org.bitcoins.core.gcs.FilterType
|
||||
import org.bitcoins.core.util.FutureUtil
|
||||
import org.bitcoins.core.wallet.utxo.TxoState
|
||||
import org.bitcoins.testkit.wallet.{BitcoinSWalletTest, WalletWithBitcoindV19}
|
||||
import org.scalatest.FutureOutcome
|
||||
|
||||
class ProcessBlockTest extends BitcoinSWalletTest {
|
||||
|
||||
override def withFixture(test: OneArgAsyncTest): FutureOutcome =
|
||||
withNewWalletAndBitcoind(test)
|
||||
withNewWalletAndBitcoindV19(test, getBIP39PasswordOpt())
|
||||
|
||||
override type FixtureParam = WalletWithBitcoindRpc
|
||||
override type FixtureParam = WalletWithBitcoindV19
|
||||
|
||||
it must "process a block" in { param =>
|
||||
val WalletWithBitcoindRpc(wallet, bitcoind) = param
|
||||
val WalletWithBitcoindV19(wallet, bitcoind) = param
|
||||
|
||||
for {
|
||||
startingUtxos <- wallet.listUtxos()
|
||||
|
@ -36,4 +39,45 @@ class ProcessBlockTest extends BitcoinSWalletTest {
|
|||
assert(utxos.head.txid == txId)
|
||||
}
|
||||
}
|
||||
|
||||
it must "process coinbase txs" in { param =>
|
||||
val WalletWithBitcoindV19(wallet, bitcoind) = param
|
||||
for {
|
||||
startingUtxos <- wallet.listUtxos(TxoState.ImmatureCoinbase)
|
||||
startingBalance <- wallet.getBalance()
|
||||
_ = assert(startingUtxos.isEmpty)
|
||||
_ = assert(startingBalance == Satoshis.zero)
|
||||
addr <- wallet.getNewAddress()
|
||||
hashes <- bitcoind.generateToAddress(101, addr)
|
||||
blocks <- FutureUtil.sequentially(hashes)(bitcoind.getBlockRaw)
|
||||
_ <- FutureUtil.sequentially(blocks)(wallet.processBlock)
|
||||
utxos <- wallet.listUtxos(TxoState.ImmatureCoinbase)
|
||||
balance <- wallet.getBalance()
|
||||
} yield {
|
||||
assert(utxos.size == 100)
|
||||
assert(balance == Bitcoins(50))
|
||||
}
|
||||
}
|
||||
|
||||
it must "process coinbase txs using filters" in { param =>
|
||||
val WalletWithBitcoindV19(wallet, bitcoind) = param
|
||||
|
||||
for {
|
||||
startingUtxos <- wallet.listUtxos(TxoState.ImmatureCoinbase)
|
||||
startingBalance <- wallet.getBalance()
|
||||
_ = assert(startingUtxos.isEmpty)
|
||||
_ = assert(startingBalance == Satoshis.zero)
|
||||
addr <- wallet.getNewAddress()
|
||||
hashes <- bitcoind.generateToAddress(101, addr)
|
||||
filters <- FutureUtil.sequentially(hashes)(
|
||||
bitcoind.getBlockFilter(_, FilterType.Basic))
|
||||
filtersWithBlockHash = hashes.map(_.flip).zip(filters.map(_.filter))
|
||||
_ <- wallet.processCompactFilters(filtersWithBlockHash)
|
||||
utxos <- wallet.listUtxos(TxoState.ImmatureCoinbase)
|
||||
balance <- wallet.getBalance()
|
||||
} yield {
|
||||
assert(utxos.size == 100)
|
||||
assert(balance == Bitcoins(50))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -251,7 +251,8 @@ abstract class Wallet
|
|||
TxoState.ConfirmedReceived =>
|
||||
txo.output.value
|
||||
case TxoState.Reserved | TxoState.PendingConfirmationsSpent |
|
||||
TxoState.ConfirmedSpent | TxoState.DoesNotExist =>
|
||||
TxoState.ConfirmedSpent | TxoState.DoesNotExist |
|
||||
TxoState.ImmatureCoinbase =>
|
||||
CurrencyUnits.zero
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.bitcoins.wallet.internal
|
|||
|
||||
import org.bitcoins.core.api.wallet.{AddUtxoError, AddUtxoSuccess}
|
||||
import org.bitcoins.core.api.wallet.db._
|
||||
import org.bitcoins.core.consensus.Consensus
|
||||
import org.bitcoins.core.currency.CurrencyUnit
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
|
@ -226,7 +227,8 @@ private[wallet] trait TransactionProcessing extends WalletLogger {
|
|||
private def markAsPendingSpent(
|
||||
out: SpendingInfoDb): Future[Option[SpendingInfoDb]] = {
|
||||
out.state match {
|
||||
case TxoState.ConfirmedReceived | TxoState.PendingConfirmationsReceived =>
|
||||
case TxoState.ConfirmedReceived | TxoState.PendingConfirmationsReceived |
|
||||
TxoState.ImmatureCoinbase =>
|
||||
val updated =
|
||||
out.copyWithState(state = TxoState.PendingConfirmationsSpent)
|
||||
val updatedF =
|
||||
|
@ -297,7 +299,7 @@ private[wallet] trait TransactionProcessing extends WalletLogger {
|
|||
case TxoState.PendingConfirmationsReceived |
|
||||
TxoState.ConfirmedReceived |
|
||||
TxoState.PendingConfirmationsSpent | TxoState.ConfirmedSpent |
|
||||
TxoState.DoesNotExist =>
|
||||
TxoState.DoesNotExist | TxoState.ImmatureCoinbase =>
|
||||
txoWithHash
|
||||
}
|
||||
|
||||
|
@ -355,7 +357,9 @@ private[wallet] trait TransactionProcessing extends WalletLogger {
|
|||
case None =>
|
||||
TxoState.PendingConfirmationsReceived
|
||||
case Some(confs) =>
|
||||
if (confs >= walletConfig.requiredConfirmations) {
|
||||
if (transaction.isCoinbase && confs <= Consensus.coinbaseMaturity) {
|
||||
TxoState.ImmatureCoinbase
|
||||
} else if (confs >= walletConfig.requiredConfirmations) {
|
||||
TxoState.ConfirmedReceived
|
||||
} else {
|
||||
TxoState.PendingConfirmationsReceived
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.bitcoins.core.api.wallet.{
|
|||
AddUtxoSuccess
|
||||
}
|
||||
import org.bitcoins.core.compat._
|
||||
import org.bitcoins.core.consensus.Consensus
|
||||
import org.bitcoins.core.hd.HDAccount
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
|
@ -109,6 +110,16 @@ private[wallet] trait UtxoHandling extends WalletLogger {
|
|||
case Some(confs) =>
|
||||
txos.map { txo =>
|
||||
txo.state match {
|
||||
case TxoState.ImmatureCoinbase =>
|
||||
if (confs > Consensus.coinbaseMaturity) {
|
||||
if (confs >= walletConfig.requiredConfirmations) {
|
||||
txo.copyWithState(TxoState.ConfirmedReceived)
|
||||
} else {
|
||||
txo.copyWithState(TxoState.PendingConfirmationsReceived)
|
||||
}
|
||||
} else {
|
||||
txo
|
||||
}
|
||||
case TxoState.PendingConfirmationsReceived =>
|
||||
if (confs >= walletConfig.requiredConfirmations) {
|
||||
txo.copyWithState(TxoState.ConfirmedReceived)
|
||||
|
|
Loading…
Add table
Reference in a new issue