mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-19 05:43:51 +01:00
Rescan DLC Tests (#3515)
This commit is contained in:
parent
c27291a7a2
commit
621e8e9033
@ -0,0 +1,135 @@
|
||||
package org.bitcoins.dlc.wallet
|
||||
|
||||
import org.bitcoins.core.currency.Satoshis
|
||||
import org.bitcoins.core.protocol.BlockStamp.BlockHash
|
||||
import org.bitcoins.core.protocol.dlc.models.{
|
||||
ContractInfo,
|
||||
DLCState,
|
||||
EnumContractDescriptor,
|
||||
NumericContractDescriptor
|
||||
}
|
||||
import org.bitcoins.core.protocol.tlv._
|
||||
import org.bitcoins.crypto.CryptoUtil
|
||||
import org.bitcoins.rpc.client.common.BitcoindRpcClient
|
||||
import org.bitcoins.testkit.wallet.DLCWalletUtil._
|
||||
import org.bitcoins.testkit.wallet.{DLCWalletUtil, DualWalletTestCachedBitcoind}
|
||||
import org.scalatest.FutureOutcome
|
||||
|
||||
class RescanDLCTest extends DualWalletTestCachedBitcoind {
|
||||
|
||||
type FixtureParam =
|
||||
(InitializedDLCWallet, InitializedDLCWallet, BitcoindRpcClient)
|
||||
|
||||
override def withFixture(test: OneArgAsyncTest): FutureOutcome = {
|
||||
withDualDLCWallets(test, DLCWalletUtil.sampleContractOraclePair)
|
||||
}
|
||||
|
||||
behavior of "DLCWallet"
|
||||
|
||||
it must "properly rescan after a DLC as initiator" in { params =>
|
||||
val walletA = params._1
|
||||
val wallet = walletA.wallet
|
||||
val walletB = params._2
|
||||
val bitcoind = params._3
|
||||
|
||||
for {
|
||||
contractId <- getContractId(wallet)
|
||||
status <- getDLCStatus(wallet)
|
||||
(sig, _) = getSigs(status.contractInfo)
|
||||
func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sig)
|
||||
|
||||
result <- dlcExecutionTest(wallets = (walletA, walletB),
|
||||
asInitiator = true,
|
||||
func = func,
|
||||
expectedOutputs = 1)
|
||||
|
||||
_ = assert(result)
|
||||
|
||||
Vector(hash) <- bitcoind.getNewAddress.flatMap(
|
||||
bitcoind.generateToAddress(1, _))
|
||||
|
||||
_ <- wallet.rescanNeutrinoWallet(startOpt = None,
|
||||
endOpt = Some(BlockHash(hash)),
|
||||
addressBatchSize = 20,
|
||||
useCreationTime = false)
|
||||
|
||||
postStatus <- getDLCStatus(wallet)
|
||||
} yield assert(postStatus.state == DLCState.Claimed)
|
||||
}
|
||||
|
||||
it must "properly rescan after a DLC as recipient" in { params =>
|
||||
val walletA = params._1
|
||||
val walletB = params._2
|
||||
val wallet = walletB.wallet
|
||||
val bitcoind = params._3
|
||||
|
||||
for {
|
||||
contractId <- getContractId(wallet)
|
||||
status <- getDLCStatus(wallet)
|
||||
(sig, _) = getSigs(status.contractInfo)
|
||||
func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sig)
|
||||
|
||||
result <- dlcExecutionTest(wallets = (walletA, walletB),
|
||||
asInitiator = true,
|
||||
func = func,
|
||||
expectedOutputs = 1)
|
||||
|
||||
_ = assert(result)
|
||||
|
||||
Vector(hash) <- bitcoind.getNewAddress.flatMap(
|
||||
bitcoind.generateToAddress(1, _))
|
||||
|
||||
_ <- wallet.rescanNeutrinoWallet(startOpt = None,
|
||||
endOpt = Some(BlockHash(hash)),
|
||||
addressBatchSize = 20,
|
||||
useCreationTime = false)
|
||||
|
||||
postStatus <- getDLCStatus(wallet)
|
||||
} yield assert(postStatus.state == DLCState.RemoteClaimed)
|
||||
}
|
||||
|
||||
private def getSigs(contractInfo: ContractInfo): (
|
||||
OracleAttestmentTLV,
|
||||
OracleAttestmentTLV) = {
|
||||
val desc: EnumContractDescriptor = contractInfo.contractDescriptor match {
|
||||
case desc: EnumContractDescriptor => desc
|
||||
case _: NumericContractDescriptor =>
|
||||
throw new IllegalArgumentException("Unexpected Contract Info")
|
||||
}
|
||||
|
||||
// Get a hash that the initiator wins for
|
||||
val initiatorWinStr =
|
||||
desc
|
||||
.maxBy(_._2.toLong)
|
||||
._1
|
||||
.outcome
|
||||
val initiatorWinSig = DLCWalletUtil.oraclePrivKey
|
||||
.schnorrSignWithNonce(CryptoUtil
|
||||
.sha256DLCAttestation(initiatorWinStr)
|
||||
.bytes,
|
||||
DLCWalletUtil.kValue)
|
||||
|
||||
// Get a hash that the recipient wins for
|
||||
val recipientWinStr =
|
||||
desc.find(_._2 == Satoshis.zero).get._1.outcome
|
||||
val recipientWinSig = DLCWalletUtil.oraclePrivKey
|
||||
.schnorrSignWithNonce(CryptoUtil
|
||||
.sha256DLCAttestation(recipientWinStr)
|
||||
.bytes,
|
||||
DLCWalletUtil.kValue)
|
||||
|
||||
val publicKey = DLCWalletUtil.oraclePrivKey.schnorrPublicKey
|
||||
val eventId = DLCWalletUtil.sampleOracleInfo.announcement.eventTLV match {
|
||||
case v0: OracleEventV0TLV => v0.eventId
|
||||
}
|
||||
|
||||
(OracleAttestmentV0TLV(eventId,
|
||||
publicKey,
|
||||
Vector(initiatorWinSig),
|
||||
Vector(initiatorWinStr)),
|
||||
OracleAttestmentV0TLV(eventId,
|
||||
publicKey,
|
||||
Vector(recipientWinSig),
|
||||
Vector(recipientWinStr)))
|
||||
}
|
||||
}
|
@ -108,4 +108,4 @@
|
||||
<!-- get rid of "Setting level of logger" messages -->
|
||||
<logger name="ch.qos.logback" level="OFF"/>
|
||||
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
@ -309,7 +309,7 @@ object DLCWalletUtil extends Logging {
|
||||
expectedOutputs: Int)(implicit ec: ExecutionContext): Future[Boolean] = {
|
||||
for {
|
||||
contractId <- getContractId(dlcA)
|
||||
fundingTx <- dlcB.getDLCFundingTx(contractId)
|
||||
fundingTx <- dlcB.broadcastDLCFundingTx(contractId)
|
||||
tx <-
|
||||
if (asInitiator) {
|
||||
func(dlcA)
|
||||
@ -320,6 +320,7 @@ object DLCWalletUtil extends Logging {
|
||||
if (asInitiator) dlcB.processTransaction(tx, None)
|
||||
else dlcA.processTransaction(tx, None)
|
||||
}
|
||||
_ <- dlcA.broadcastTransaction(tx)
|
||||
|
||||
dlcDb <- dlcA.dlcDAO.findByContractId(contractId)
|
||||
_ <- verifyProperlySetTxIds(dlcA)
|
||||
|
@ -0,0 +1,104 @@
|
||||
package org.bitcoins.testkit.wallet
|
||||
|
||||
import org.bitcoins.commons.config.AppConfig
|
||||
import org.bitcoins.core.currency.Satoshis
|
||||
import org.bitcoins.core.protocol.dlc.models.{ContractInfo, ContractOraclePair}
|
||||
import org.bitcoins.dlc.wallet.DLCAppConfig
|
||||
import org.bitcoins.server.BitcoinSAppConfig
|
||||
import org.bitcoins.testkit.BitcoinSTestAppConfig
|
||||
import org.bitcoins.testkit.wallet.DLCWalletUtil.InitializedDLCWallet
|
||||
import org.bitcoins.testkit.wallet.FundWalletUtil.FundedDLCWallet
|
||||
import org.bitcoins.wallet.config.WalletAppConfig
|
||||
import org.scalatest.FutureOutcome
|
||||
|
||||
trait DualWalletTestCachedBitcoind
|
||||
extends BitcoinSWalletTestCachedBitcoindNewest {
|
||||
import BitcoinSWalletTest._
|
||||
|
||||
implicit protected def config2: BitcoinSAppConfig =
|
||||
BitcoinSTestAppConfig.getSpvTestConfig()
|
||||
|
||||
implicit protected def wallet2AppConfig: WalletAppConfig = {
|
||||
config2.walletConf
|
||||
}
|
||||
|
||||
implicit protected def dlc2AppConfig: DLCAppConfig = {
|
||||
config2.dlcConf
|
||||
}
|
||||
|
||||
override def beforeAll(): Unit = {
|
||||
AppConfig.throwIfDefaultDatadir(getFreshConfig.walletConf)
|
||||
AppConfig.throwIfDefaultDatadir(config2.walletConf)
|
||||
AppConfig.throwIfDefaultDatadir(getFreshConfig.dlcConf)
|
||||
AppConfig.throwIfDefaultDatadir(config2.dlcConf)
|
||||
super.beforeAll()
|
||||
}
|
||||
|
||||
/** Creates two segwit wallets that are funded with some bitcoin, these wallets are NOT
|
||||
* peered with a bitcoind so the funds in the wallets are not tied to an
|
||||
* underlying blockchain
|
||||
*/
|
||||
def withDualFundedDLCWallets(test: OneArgAsyncTest): FutureOutcome = {
|
||||
makeDependentFixture(
|
||||
build = () =>
|
||||
for {
|
||||
bitcoind <- cachedBitcoindWithFundsF
|
||||
walletA <-
|
||||
FundWalletUtil.createFundedDLCWalletWithBitcoind(
|
||||
bitcoind,
|
||||
getBIP39PasswordOpt(),
|
||||
Some(segwitWalletConf))
|
||||
walletB <- FundWalletUtil.createFundedDLCWalletWithBitcoind(
|
||||
bitcoind,
|
||||
getBIP39PasswordOpt(),
|
||||
Some(segwitWalletConf))(config2, system)
|
||||
} yield (walletA, walletB, bitcoind),
|
||||
destroy = { fundedWallets: (FundedDLCWallet, FundedDLCWallet, _) =>
|
||||
for {
|
||||
_ <- destroyDLCWallet(fundedWallets._1.wallet)
|
||||
_ <- destroyDLCWallet(fundedWallets._2.wallet)
|
||||
} yield ()
|
||||
}
|
||||
)(test)
|
||||
}
|
||||
|
||||
/** Creates 2 funded segwit wallets that have a DLC initiated */
|
||||
def withDualDLCWallets(
|
||||
test: OneArgAsyncTest,
|
||||
contractOraclePair: ContractOraclePair): FutureOutcome = {
|
||||
makeDependentFixture(
|
||||
build = () => {
|
||||
val bitcoindF = cachedBitcoindWithFundsF
|
||||
|
||||
val walletAF = bitcoindF.flatMap { bitcoind =>
|
||||
FundWalletUtil.createFundedDLCWalletWithBitcoind(
|
||||
bitcoind,
|
||||
getBIP39PasswordOpt(),
|
||||
Some(segwitWalletConf))
|
||||
}
|
||||
val walletBF = bitcoindF.flatMap { bitcoind =>
|
||||
FundWalletUtil.createFundedDLCWalletWithBitcoind(
|
||||
bitcoind,
|
||||
getBIP39PasswordOpt(),
|
||||
Some(segwitWalletConf))(config2, system)
|
||||
}
|
||||
|
||||
for {
|
||||
walletA <- walletAF
|
||||
walletB <- walletBF
|
||||
amt = expectedDefaultAmt / Satoshis(2)
|
||||
contractInfo = ContractInfo(amt.satoshis, contractOraclePair)
|
||||
(dlcWalletA, dlcWalletB) <-
|
||||
DLCWalletUtil.initDLC(walletA, walletB, contractInfo)
|
||||
bitcoind <- bitcoindF
|
||||
} yield (dlcWalletA, dlcWalletB, bitcoind)
|
||||
},
|
||||
destroy = { dlcWallets: (InitializedDLCWallet, InitializedDLCWallet, _) =>
|
||||
for {
|
||||
_ <- destroyDLCWallet(dlcWallets._1.wallet)
|
||||
_ <- destroyDLCWallet(dlcWallets._2.wallet)
|
||||
} yield ()
|
||||
}
|
||||
)(test)
|
||||
}
|
||||
}
|
@ -12,12 +12,12 @@ import org.bitcoins.core.protocol.transaction.TransactionOutput
|
||||
import org.bitcoins.crypto.DoubleSha256DigestBE
|
||||
import org.bitcoins.dlc.wallet.DLCWallet
|
||||
import org.bitcoins.rpc.client.common.BitcoindRpcClient
|
||||
import org.bitcoins.server.BitcoinSAppConfig
|
||||
import org.bitcoins.testkitcore.util.TransactionTestUtil
|
||||
import org.bitcoins.server.{BitcoinSAppConfig, BitcoindRpcBackendUtil}
|
||||
import org.bitcoins.testkit.wallet.FundWalletUtil.{
|
||||
FundedTestWallet,
|
||||
FundedWallet
|
||||
}
|
||||
import org.bitcoins.testkitcore.util.TransactionTestUtil
|
||||
import org.bitcoins.wallet.Wallet
|
||||
import org.bitcoins.wallet.config.WalletAppConfig
|
||||
|
||||
@ -71,6 +71,8 @@ trait FundWalletUtil extends Logging {
|
||||
txId <- bitcoind.sendMany(addressAmountMap)
|
||||
tx <- bitcoind.getRawTransactionRaw(txId)
|
||||
hashes <- bitcoind.getNewAddress.flatMap(bitcoind.generateToAddress(6, _))
|
||||
|
||||
_ <- wallet.processTransaction(tx, hashes.headOption)
|
||||
} yield (tx, hashes.head)
|
||||
|
||||
txAndHashF.map(_ => wallet)
|
||||
@ -183,4 +185,36 @@ object FundWalletUtil extends FundWalletUtil {
|
||||
funded <- FundWalletUtil.fundWallet(wallet)
|
||||
} yield FundedDLCWallet(funded.wallet.asInstanceOf[DLCWallet])
|
||||
}
|
||||
|
||||
def createFundedDLCWalletWithBitcoind(
|
||||
bitcoind: BitcoindRpcClient,
|
||||
bip39PasswordOpt: Option[String],
|
||||
extraConfig: Option[Config] = None)(implicit
|
||||
config: BitcoinSAppConfig,
|
||||
system: ActorSystem): Future[FundedDLCWallet] = {
|
||||
import system.dispatcher
|
||||
for {
|
||||
tmp <- BitcoinSWalletTest.createDLCWallet2Accounts(
|
||||
nodeApi = bitcoind,
|
||||
chainQueryApi = bitcoind,
|
||||
bip39PasswordOpt = bip39PasswordOpt,
|
||||
extraConfig = extraConfig)
|
||||
|
||||
wallet = BitcoindRpcBackendUtil.createDLCWalletWithBitcoindCallbacks(
|
||||
bitcoind,
|
||||
tmp)
|
||||
|
||||
funded1 <- fundAccountForWalletWithBitcoind(
|
||||
BitcoinSWalletTest.defaultAcctAmts,
|
||||
wallet.walletConfig.defaultAccount,
|
||||
wallet,
|
||||
bitcoind)
|
||||
|
||||
hdAccount1 = WalletTestUtil.getHdAccount1(wallet.walletConfig)
|
||||
funded <- fundAccountForWalletWithBitcoind(BitcoinSWalletTest.account1Amt,
|
||||
hdAccount1,
|
||||
funded1,
|
||||
bitcoind)
|
||||
} yield FundedDLCWallet(funded.asInstanceOf[DLCWallet])
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user