Rescan DLC Tests (#3515)

This commit is contained in:
benthecarman 2021-08-11 07:29:33 -05:00 committed by GitHub
parent c27291a7a2
commit 621e8e9033
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 278 additions and 4 deletions

View File

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

View File

@ -108,4 +108,4 @@
<!-- get rid of "Setting level of logger" messages -->
<logger name="ch.qos.logback" level="OFF"/>
</configuration>
</configuration>

View File

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

View File

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

View File

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