mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-19 05:43:51 +01:00
Fix verify funding sigs (#3194)
* Fix verify funding sigs * Sort funding inputs * Sort utxos in dlc signer * Other multi input fixes & tests * Fix compile error
This commit is contained in:
parent
7a5e108ff2
commit
0e701bc9d0
@ -48,10 +48,14 @@ case class DLCTxSigner(
|
||||
finalAddress == offer.pubKeys.payoutAddress,
|
||||
"Given keys do not match public key and address in offer")
|
||||
val fundingUtxosAsInputs =
|
||||
fundingUtxos.zip(offer.fundingInputs).map { case (utxo, fund) =>
|
||||
DLCFundingInput.fromInputSigningInfo(utxo, fund.inputSerialId)
|
||||
}
|
||||
require(fundingUtxosAsInputs == offer.fundingInputs,
|
||||
fundingUtxos
|
||||
.sortBy(_.outPoint.bytes)
|
||||
.zip(offer.fundingInputs.sortBy(_.outPoint.bytes))
|
||||
.map { case (utxo, fund) =>
|
||||
DLCFundingInput.fromInputSigningInfo(utxo, fund.inputSerialId)
|
||||
}
|
||||
.sortBy(_.inputSerialId)
|
||||
require(fundingUtxosAsInputs == offer.fundingInputs.sortBy(_.inputSerialId),
|
||||
"Funding ScriptSignatureParams did not match offer funding inputs")
|
||||
} else {
|
||||
require(
|
||||
@ -60,11 +64,17 @@ case class DLCTxSigner(
|
||||
"Given keys do not match public key and address in accept"
|
||||
)
|
||||
val fundingUtxosAsInputs =
|
||||
fundingUtxos.zip(accept.fundingInputs).map { case (utxo, fund) =>
|
||||
DLCFundingInput.fromInputSigningInfo(utxo, fund.inputSerialId)
|
||||
}
|
||||
require(fundingUtxosAsInputs == accept.fundingInputs,
|
||||
"Funding ScriptSignatureParams did not match accept funding inputs")
|
||||
fundingUtxos
|
||||
.sortBy(_.outPoint.bytes)
|
||||
.zip(accept.fundingInputs.sortBy(_.outPoint.bytes))
|
||||
.map { case (utxo, fund) =>
|
||||
DLCFundingInput.fromInputSigningInfo(utxo, fund.inputSerialId)
|
||||
}
|
||||
.sortBy(_.inputSerialId)
|
||||
require(
|
||||
fundingUtxosAsInputs == accept.fundingInputs.sortBy(_.inputSerialId),
|
||||
"Funding ScriptSignatureParams did not match accept funding inputs"
|
||||
)
|
||||
}
|
||||
|
||||
/** Return's this party's payout for a given oracle signature */
|
||||
|
@ -155,8 +155,8 @@ object DLCSignatureVerifier {
|
||||
|
||||
val psbt = PSBT.fromUnsignedTxWithP2SHScript(fundingTx)
|
||||
|
||||
fundingSigs.zipWithIndex
|
||||
.foldLeft(true) { case (ret, ((outPoint, witness), index)) =>
|
||||
fundingSigs
|
||||
.foldLeft(true) { case (ret, (outPoint, witness)) =>
|
||||
val serialId = serialIdMap(outPoint)
|
||||
val idx = serialIds.indexOf(serialId)
|
||||
if (ret) {
|
||||
@ -167,7 +167,13 @@ object DLCSignatureVerifier {
|
||||
false
|
||||
} else {
|
||||
Try {
|
||||
val fundingInput = remoteFundingInputs(index)
|
||||
val fundingInput =
|
||||
remoteFundingInputs.find(_.outPoint == outPoint) match {
|
||||
case Some(input) => input
|
||||
case None =>
|
||||
throw new RuntimeException(
|
||||
s"Could not find fundingInput for outpoint $outPoint")
|
||||
}
|
||||
|
||||
psbt
|
||||
.addUTXOToInput(fundingInput.prevTx, idx)
|
||||
|
@ -27,7 +27,7 @@ class DLCMultiOracleEnumExecutionTest extends BitcoinSDualWalletTest {
|
||||
val outcomes: Vector[String] = DLCTestUtil.genOutcomes(numOutcomes)
|
||||
|
||||
val (contractDescriptor, _) =
|
||||
DLCTestUtil.genContractDescriptors(outcomes, Satoshis(10000))
|
||||
DLCTestUtil.genContractDescriptors(outcomes, total)
|
||||
|
||||
val announcements: Vector[OracleAnnouncementTLV] =
|
||||
privateKeys.zip(kValues).map { case (priv, kValue) =>
|
||||
|
@ -937,7 +937,7 @@ abstract class DLCWallet
|
||||
def verifyFundingSigs(
|
||||
inputs: Vector[DLCFundingInputDb],
|
||||
sign: DLCSign): Future[Boolean] = {
|
||||
if (inputs.count(!_.isInitiator) == sign.fundingSigs.length) {
|
||||
if (inputs.count(_.isInitiator) == sign.fundingSigs.length) {
|
||||
verifierFromDb(sign.contractId).map { verifier =>
|
||||
verifier.verifyRemoteFundingSigs(sign.fundingSigs)
|
||||
}
|
||||
@ -994,16 +994,16 @@ abstract class DLCWallet
|
||||
contractData <- contractDataDAO.read(dlcDb.dlcId).map(_.get)
|
||||
offerDbOpt <- dlcOfferDAO.findByDLCId(dlcDb.dlcId)
|
||||
offerDb = offerDbOpt.get
|
||||
fundingInputDbs <- dlcInputsDAO.findByDLCId(dlcDb.dlcId)
|
||||
fundingInputDbs <- dlcInputsDAO.findByDLCId(dlcDb.dlcId,
|
||||
isInitiator = true)
|
||||
|
||||
txIds = fundingInputDbs.map(_.outPoint.txIdBE)
|
||||
remotePrevTxs <- remoteTxDAO.findByTxIdBEs(txIds)
|
||||
localPrevTxs <- transactionDAO.findByTxIdBEs(txIds)
|
||||
|
||||
(announcements, announcementData, nonceDbs) <- getDLCAnnouncementDbs(
|
||||
dlcDb.dlcId)
|
||||
|
||||
prevTxs = (remotePrevTxs ++ localPrevTxs).map(_.transaction)
|
||||
prevTxs = remotePrevTxs.map(_.transaction)
|
||||
txs = prevTxs.groupBy(_.txIdBE)
|
||||
|
||||
fundingInputs = fundingInputDbs.map(input =>
|
||||
|
@ -139,7 +139,7 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
||||
EnumMultiOracleInfo(contractDataDb.oracleThreshold,
|
||||
announcementTLVs)
|
||||
}
|
||||
ContractInfo(enum, oracleInfo)
|
||||
ContractInfo(contractDataDb.totalCollateral.satoshis, enum, oracleInfo)
|
||||
case numeric: NumericContractDescriptor =>
|
||||
val oracleInfo =
|
||||
if (announcementTLVs.size == 1) {
|
||||
@ -318,7 +318,7 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
||||
localFundingInputs = fundingInputsDb.filter(_.isInitiator)
|
||||
|
||||
prevTxs <-
|
||||
transactionDAO.findByTxIdBEs(fundingInputsDb.map(_.outPoint.txIdBE))
|
||||
transactionDAO.findByTxIdBEs(localFundingInputs.map(_.outPoint.txIdBE))
|
||||
} yield {
|
||||
val offerFundingInputs =
|
||||
matchPrevTxsWithInputs(localFundingInputs, prevTxs)
|
||||
@ -359,12 +359,12 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
||||
dlcAccept: DLCAcceptDb,
|
||||
fundingInputsDb: Vector[DLCFundingInputDb],
|
||||
contractInfo: ContractInfo): Future[DLCTxBuilder] = {
|
||||
val (offerDbFundingInputs, acceptDbFundingInputs) =
|
||||
fundingInputsDb.partition(_.isInitiator)
|
||||
val (localDbFundingInputs, remoteDbFundingInputs) = if (dlcDb.isInitiator) {
|
||||
(offerDbFundingInputs, acceptDbFundingInputs)
|
||||
(fundingInputsDb.filter(_.isInitiator),
|
||||
fundingInputsDb.filterNot(_.isInitiator))
|
||||
} else {
|
||||
(acceptDbFundingInputs, offerDbFundingInputs)
|
||||
(fundingInputsDb.filterNot(_.isInitiator),
|
||||
fundingInputsDb.filter(_.isInitiator))
|
||||
}
|
||||
|
||||
for {
|
||||
|
@ -84,7 +84,8 @@ trait BitcoinSDualWalletTest extends BitcoinSWalletTest {
|
||||
for {
|
||||
walletA <- walletAF
|
||||
walletB <- walletBF
|
||||
contractInfo = ContractInfo(Satoshis(10000), contractOraclePair)
|
||||
amt = expectedDefaultAmt / Satoshis(2)
|
||||
contractInfo = ContractInfo(amt.satoshis, contractOraclePair)
|
||||
(dlcWalletA, dlcWalletB) <-
|
||||
DLCWalletUtil.initDLC(walletA, walletB, contractInfo)
|
||||
} yield (dlcWalletA, dlcWalletB)
|
||||
|
@ -22,6 +22,7 @@ import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
import org.bitcoins.crypto._
|
||||
import org.bitcoins.dlc.wallet.DLCWallet
|
||||
import org.bitcoins.dlc.wallet.models._
|
||||
import org.bitcoins.testkit.wallet.BitcoinSWalletTest.expectedDefaultAmt
|
||||
import org.bitcoins.testkit.wallet.FundWalletUtil.FundedDLCWallet
|
||||
import org.bitcoins.testkitcore.dlc.DLCTestUtil
|
||||
import org.scalatest.Assertions.fail
|
||||
@ -48,8 +49,11 @@ object DLCWalletUtil {
|
||||
lazy val loseHash: Sha256Digest =
|
||||
CryptoUtil.sha256DLCAttestation(loseStr)
|
||||
|
||||
val total: Satoshis = (expectedDefaultAmt / Satoshis(2)).satoshis
|
||||
val half: Satoshis = (total / Satoshis(2)).satoshis
|
||||
|
||||
val sampleOutcomes: Vector[(EnumOutcome, Satoshis)] = Vector(
|
||||
EnumOutcome(winStr) -> Satoshis(10000),
|
||||
EnumOutcome(winStr) -> (expectedDefaultAmt / Satoshis(2)).satoshis,
|
||||
EnumOutcome(loseStr) -> Satoshis.zero)
|
||||
|
||||
lazy val sampleContractDescriptor: EnumContractDescriptor =
|
||||
@ -64,7 +68,7 @@ object DLCWalletUtil {
|
||||
ContractOraclePair.EnumPair(sampleContractDescriptor, sampleOracleInfo)
|
||||
|
||||
lazy val sampleContractInfo: ContractInfo =
|
||||
ContractInfo(Satoshis(10000), sampleContractOraclePair)
|
||||
ContractInfo(half, sampleContractOraclePair)
|
||||
|
||||
lazy val sampleOracleWinSig: SchnorrDigitalSignature =
|
||||
oraclePrivKey.schnorrSignWithNonce(winHash.bytes, kValue)
|
||||
@ -75,7 +79,7 @@ object DLCWalletUtil {
|
||||
val numDigits: Int = 6
|
||||
|
||||
lazy val multiNonceContractDescriptor: NumericContractDescriptor =
|
||||
DLCTestUtil.genMultiDigitContractInfo(numDigits, Satoshis(10000))._1
|
||||
DLCTestUtil.genMultiDigitContractInfo(numDigits, total)._1
|
||||
|
||||
lazy val multiNonceOracleInfo: NumericSingleOracleInfo =
|
||||
NumericSingleOracleInfo(
|
||||
@ -88,7 +92,7 @@ object DLCWalletUtil {
|
||||
}
|
||||
|
||||
lazy val multiNonceContractInfo: ContractInfo =
|
||||
ContractInfo(Satoshis(10000), multiNonceContractOraclePair)
|
||||
ContractInfo(total, multiNonceContractOraclePair)
|
||||
|
||||
lazy val dummyContractMaturity: BlockTimeStamp = BlockTimeStamp(1666335)
|
||||
lazy val dummyContractTimeout: BlockTimeStamp = BlockTimeStamp(1666337)
|
||||
@ -119,8 +123,7 @@ object DLCWalletUtil {
|
||||
val dummyPrevTx: BaseTransaction = BaseTransaction(
|
||||
TransactionConstants.validLockVersion,
|
||||
Vector.empty,
|
||||
Vector.fill(2)(
|
||||
TransactionOutput(Satoshis(5000), P2WPKHWitnessSPKV0(dummyKey))),
|
||||
Vector.fill(2)(TransactionOutput(half, P2WPKHWitnessSPKV0(dummyKey))),
|
||||
UInt32.zero)
|
||||
|
||||
val dummyFundingInputs = Vector(
|
||||
@ -143,7 +146,7 @@ object DLCWalletUtil {
|
||||
lazy val sampleDLCOffer: DLCOffer = DLCOffer(
|
||||
contractInfo = sampleContractInfo,
|
||||
pubKeys = dummyDLCKeys,
|
||||
totalCollateral = Satoshis(5000),
|
||||
totalCollateral = half,
|
||||
fundingInputs = Vector(dummyFundingInputs.head),
|
||||
changeAddress = dummyAddress,
|
||||
payoutSerialId = sampleOfferPayoutSerialId,
|
||||
@ -176,7 +179,7 @@ object DLCWalletUtil {
|
||||
Vector(sampleOfferChangeSerialId, sampleFundOutputSerialId))
|
||||
|
||||
lazy val sampleDLCAccept: DLCAccept = DLCAccept(
|
||||
totalCollateral = Satoshis(5000),
|
||||
totalCollateral = half,
|
||||
pubKeys = dummyDLCKeys,
|
||||
fundingInputs = Vector(dummyFundingInputs.last),
|
||||
changeAddress = dummyAddress,
|
||||
@ -220,7 +223,7 @@ object DLCWalletUtil {
|
||||
contractDescriptorTLV = sampleContractDescriptor.toTLV,
|
||||
contractMaturity = BlockTimeStamp(0),
|
||||
contractTimeout = BlockTimeStamp(1),
|
||||
totalCollateral = Satoshis(10000)
|
||||
totalCollateral = total
|
||||
)
|
||||
|
||||
def initDLC(
|
||||
@ -234,8 +237,8 @@ object DLCWalletUtil {
|
||||
for {
|
||||
offer <- walletA.createDLCOffer(
|
||||
contractInfo = contractInfo,
|
||||
collateral = Satoshis(5000),
|
||||
feeRateOpt = None,
|
||||
collateral = half,
|
||||
feeRateOpt = Some(SatoshisPerVirtualByte.fromLong(10)),
|
||||
locktime = dummyTimeouts.contractMaturity.toUInt32,
|
||||
refundLocktime = dummyTimeouts.contractTimeout.toUInt32
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user