mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-19 09:52:09 +01:00
Add ordering of funding inputs to DLC Wallet (#3647)
* Add ordering of funding inputs to DLC Wallet * Fix tests
This commit is contained in:
parent
5089e901bb
commit
099e4469b4
@ -82,13 +82,13 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg {
|
||||
val result = dlcDbManagement.migrate()
|
||||
dlcAppConfig.driver match {
|
||||
case SQLite =>
|
||||
val expected = 3
|
||||
val expected = 4
|
||||
assert(result == expected)
|
||||
val flywayInfo = dlcAppConfig.info()
|
||||
assert(flywayInfo.applied().length == expected)
|
||||
assert(flywayInfo.pending().length == 0)
|
||||
case PostgreSQL =>
|
||||
val expected = 3
|
||||
val expected = 4
|
||||
assert(result == expected)
|
||||
val flywayInfo = dlcAppConfig.info()
|
||||
|
||||
|
@ -74,6 +74,7 @@ class DLCDAOTest extends BitcoinSWalletTest with DLCDAOFixture {
|
||||
val input = DLCFundingInputDb(
|
||||
dlcId = dlcId,
|
||||
isInitiator = true,
|
||||
index = 0,
|
||||
inputSerialId = UInt64.zero,
|
||||
outPoint = TransactionOutPoint(testBlockHash, UInt32.zero),
|
||||
output = TransactionOutput(Satoshis.one, EmptyScriptPubKey),
|
||||
@ -95,6 +96,7 @@ class DLCDAOTest extends BitcoinSWalletTest with DLCDAOFixture {
|
||||
DLCFundingInputDb(
|
||||
dlcId = dlcId,
|
||||
isInitiator = true,
|
||||
index = 0,
|
||||
inputSerialId = UInt64.zero,
|
||||
outPoint = TransactionOutPoint(testBlockHash, UInt32.zero),
|
||||
output = TransactionOutput(Satoshis.one, EmptyScriptPubKey),
|
||||
@ -106,6 +108,7 @@ class DLCDAOTest extends BitcoinSWalletTest with DLCDAOFixture {
|
||||
DLCFundingInputDb(
|
||||
dlcId = dlcId,
|
||||
isInitiator = false,
|
||||
index = 0,
|
||||
inputSerialId = UInt64.one,
|
||||
outPoint = TransactionOutPoint(testBlockHash, UInt32.one),
|
||||
output = TransactionOutput(Satoshis.one, EmptyScriptPubKey),
|
||||
@ -117,6 +120,7 @@ class DLCDAOTest extends BitcoinSWalletTest with DLCDAOFixture {
|
||||
DLCFundingInputDb(
|
||||
dlcId = dlcId,
|
||||
isInitiator = true,
|
||||
index = 1,
|
||||
inputSerialId = UInt64(2),
|
||||
outPoint = TransactionOutPoint(testBlockHash, UInt32(3)),
|
||||
output = TransactionOutput(Satoshis.one, EmptyScriptPubKey),
|
||||
|
@ -1,6 +1,6 @@
|
||||
package org.bitcoins.dlc.wallet
|
||||
|
||||
import org.bitcoins.core.currency.Satoshis
|
||||
import org.bitcoins.core.currency._
|
||||
import org.bitcoins.core.number.{UInt32, UInt64}
|
||||
import org.bitcoins.core.protocol.dlc.models.DLCMessage._
|
||||
import org.bitcoins.core.protocol.dlc.models._
|
||||
@ -75,7 +75,7 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
||||
_ = {
|
||||
assert(dlcA2Opt.isDefined)
|
||||
assert(dlcA2Opt.get.state == DLCState.Signed)
|
||||
assert(sign.fundingSigs.length == offerData.fundingInputs.size)
|
||||
assert(sign.fundingSigs.length == offer.fundingInputs.size)
|
||||
}
|
||||
|
||||
dlcDb <- walletB.addDLCSigs(sign)
|
||||
@ -136,6 +136,120 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
||||
testNegotiate(fundedDLCWallets, DLCWalletUtil.sampleMultiNonceDLCOffer)
|
||||
}
|
||||
|
||||
// This could happen inputs can end up in different orders when
|
||||
// using postgres or using different coin selection algos
|
||||
it must "correctly negotiate a dlc with reordered inputs" in {
|
||||
fundedDLCWallets: (FundedDLCWallet, FundedDLCWallet) =>
|
||||
// construct a contract info that uses many inputs
|
||||
val totalCol = Bitcoins(11).satoshis
|
||||
val col = totalCol / Satoshis(2)
|
||||
|
||||
val outcomes: Vector[(EnumOutcome, Satoshis)] =
|
||||
Vector(EnumOutcome(winStr) -> totalCol,
|
||||
EnumOutcome(loseStr) -> Satoshis.zero)
|
||||
|
||||
val oraclePair: ContractOraclePair.EnumPair =
|
||||
ContractOraclePair.EnumPair(EnumContractDescriptor(outcomes),
|
||||
sampleOracleInfo)
|
||||
|
||||
val contractInfo: ContractInfo = ContractInfo(totalCol, oraclePair)
|
||||
|
||||
val offerData =
|
||||
sampleDLCOffer.copy(contractInfo = contractInfo,
|
||||
totalCollateral = col.satoshis)
|
||||
|
||||
val walletA = fundedDLCWallets._1.wallet
|
||||
val walletB = fundedDLCWallets._2.wallet
|
||||
|
||||
def reorderInputDbs(
|
||||
wallet: DLCWallet,
|
||||
dlcId: Sha256Digest): Future[Unit] = {
|
||||
for {
|
||||
inputDbs <- wallet.dlcInputsDAO.findByDLCId(dlcId)
|
||||
_ <- wallet.dlcInputsDAO.deleteByDLCId(dlcId)
|
||||
_ <- wallet.dlcInputsDAO.createAll(inputDbs.reverse)
|
||||
} yield ()
|
||||
}
|
||||
|
||||
for {
|
||||
offer <- walletA.createDLCOffer(
|
||||
offerData.contractInfo,
|
||||
offerData.totalCollateral,
|
||||
Some(offerData.feeRate),
|
||||
offerData.timeouts.contractMaturity.toUInt32,
|
||||
offerData.timeouts.contractTimeout.toUInt32
|
||||
)
|
||||
dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint))
|
||||
|
||||
accept <- walletB.acceptDLCOffer(offer)
|
||||
|
||||
// reorder dlc inputs in wallets
|
||||
_ <- reorderInputDbs(walletA, dlcId)
|
||||
_ <- reorderInputDbs(walletB, dlcId)
|
||||
|
||||
sign <- walletA.signDLC(accept)
|
||||
|
||||
dlcDb <- walletB.addDLCSigs(sign)
|
||||
} yield assert(dlcDb.state == DLCState.Signed)
|
||||
}
|
||||
|
||||
// This could happen inputs can end up in different orders when
|
||||
// using postgres or using different coin selection algos
|
||||
it must "correctly negotiate a dlc with tlvs & with reordered inputs" in {
|
||||
fundedDLCWallets: (FundedDLCWallet, FundedDLCWallet) =>
|
||||
// construct a contract info that uses many inputs
|
||||
val totalCol = Bitcoins(11).satoshis
|
||||
val col = totalCol / Satoshis(2)
|
||||
|
||||
val outcomes: Vector[(EnumOutcome, Satoshis)] =
|
||||
Vector(EnumOutcome(winStr) -> totalCol,
|
||||
EnumOutcome(loseStr) -> Satoshis.zero)
|
||||
|
||||
val oraclePair: ContractOraclePair.EnumPair =
|
||||
ContractOraclePair.EnumPair(EnumContractDescriptor(outcomes),
|
||||
sampleOracleInfo)
|
||||
|
||||
val contractInfo: ContractInfo = ContractInfo(totalCol, oraclePair)
|
||||
|
||||
val offerData =
|
||||
sampleDLCOffer.copy(contractInfo = contractInfo,
|
||||
totalCollateral = col.satoshis)
|
||||
|
||||
val walletA = fundedDLCWallets._1.wallet
|
||||
val walletB = fundedDLCWallets._2.wallet
|
||||
|
||||
def reorderInputDbs(
|
||||
wallet: DLCWallet,
|
||||
dlcId: Sha256Digest): Future[Unit] = {
|
||||
for {
|
||||
inputDbs <- wallet.dlcInputsDAO.findByDLCId(dlcId)
|
||||
_ <- wallet.dlcInputsDAO.deleteByDLCId(dlcId)
|
||||
_ <- wallet.dlcInputsDAO.createAll(inputDbs.reverse)
|
||||
} yield ()
|
||||
}
|
||||
|
||||
for {
|
||||
offer <- walletA.createDLCOffer(
|
||||
offerData.contractInfo,
|
||||
offerData.totalCollateral,
|
||||
Some(offerData.feeRate),
|
||||
offerData.timeouts.contractMaturity.toUInt32,
|
||||
offerData.timeouts.contractTimeout.toUInt32
|
||||
)
|
||||
dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint))
|
||||
|
||||
accept <- walletB.acceptDLCOffer(offer.toTLV)
|
||||
|
||||
// reorder dlc inputs in wallets
|
||||
_ <- reorderInputDbs(walletA, dlcId)
|
||||
_ <- reorderInputDbs(walletB, dlcId)
|
||||
|
||||
sign <- walletA.signDLC(accept.toTLV)
|
||||
|
||||
dlcDb <- walletB.addDLCSigs(sign.toTLV)
|
||||
} yield assert(dlcDb.state == DLCState.Signed)
|
||||
}
|
||||
|
||||
it must "correctly negotiate a dlc using TLVs" in {
|
||||
fundedDLCWallets: (FundedDLCWallet, FundedDLCWallet) =>
|
||||
val walletA = fundedDLCWallets._1.wallet
|
||||
@ -185,7 +299,7 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
||||
_ = {
|
||||
assert(dlcA2Opt.isDefined)
|
||||
assert(dlcA2Opt.get.state == DLCState.Signed)
|
||||
assert(sign.fundingSigs.length == offerData.fundingInputs.size)
|
||||
assert(sign.fundingSigs.length == offer.fundingInputs.size)
|
||||
}
|
||||
|
||||
dlcDb <- walletB.addDLCSigs(sign.toTLV)
|
||||
|
@ -0,0 +1,2 @@
|
||||
ALTER TABLE "funding_inputs"
|
||||
ADD COLUMN "index" INTEGER NOT NULL DEFAULT 0;
|
@ -0,0 +1,2 @@
|
||||
ALTER TABLE "funding_inputs"
|
||||
ADD COLUMN "index" INTEGER NOT NULL DEFAULT 0;
|
@ -422,18 +422,20 @@ abstract class DLCWallet
|
||||
_ <- dlcAnnouncementDAO.createAll(dlcAnnouncementDbs)
|
||||
dlcOfferDb = DLCOfferDbHelper.fromDLCOffer(dlcId, offer)
|
||||
|
||||
dlcInputs = spendingInfos.zip(utxos).map { case (utxo, fundingInput) =>
|
||||
DLCFundingInputDb(
|
||||
dlcId = dlcId,
|
||||
isInitiator = true,
|
||||
inputSerialId = fundingInput.inputSerialId,
|
||||
outPoint = utxo.outPoint,
|
||||
output = utxo.output,
|
||||
nSequence = fundingInput.sequence,
|
||||
maxWitnessLength = fundingInput.maxWitnessLen.toLong,
|
||||
redeemScriptOpt = InputInfo.getRedeemScript(utxo.inputInfo),
|
||||
witnessScriptOpt = InputInfo.getScriptWitness(utxo.inputInfo)
|
||||
)
|
||||
dlcInputs = spendingInfos.zip(utxos).zipWithIndex.map {
|
||||
case ((utxo, fundingInput), idx) =>
|
||||
DLCFundingInputDb(
|
||||
dlcId = dlcId,
|
||||
isInitiator = true,
|
||||
index = idx,
|
||||
inputSerialId = fundingInput.inputSerialId,
|
||||
outPoint = utxo.outPoint,
|
||||
output = utxo.output,
|
||||
nSequence = fundingInput.sequence,
|
||||
maxWitnessLength = fundingInput.maxWitnessLen.toLong,
|
||||
redeemScriptOpt = InputInfo.getRedeemScript(utxo.inputInfo),
|
||||
witnessScriptOpt = InputInfo.getScriptWitness(utxo.inputInfo)
|
||||
)
|
||||
}
|
||||
|
||||
_ = logger.info(
|
||||
@ -685,35 +687,40 @@ abstract class DLCWallet
|
||||
|
||||
dlcOfferDb = DLCOfferDbHelper.fromDLCOffer(dlc.dlcId, offer)
|
||||
|
||||
offerInputs = offer.fundingInputs.map(funding =>
|
||||
DLCFundingInputDb(
|
||||
dlcId = dlc.dlcId,
|
||||
isInitiator = true,
|
||||
inputSerialId = funding.inputSerialId,
|
||||
outPoint = funding.outPoint,
|
||||
output = funding.output,
|
||||
nSequence = funding.sequence,
|
||||
maxWitnessLength = funding.maxWitnessLen.toLong,
|
||||
redeemScriptOpt = funding.redeemScriptOpt,
|
||||
witnessScriptOpt = None
|
||||
))
|
||||
offerInputs = offer.fundingInputs.zipWithIndex.map {
|
||||
case (funding, idx) =>
|
||||
DLCFundingInputDb(
|
||||
dlcId = dlc.dlcId,
|
||||
isInitiator = true,
|
||||
index = idx,
|
||||
inputSerialId = funding.inputSerialId,
|
||||
outPoint = funding.outPoint,
|
||||
output = funding.output,
|
||||
nSequence = funding.sequence,
|
||||
maxWitnessLength = funding.maxWitnessLen.toLong,
|
||||
redeemScriptOpt = funding.redeemScriptOpt,
|
||||
witnessScriptOpt = None
|
||||
)
|
||||
}
|
||||
|
||||
offerPrevTxs = offer.fundingInputs.map(funding =>
|
||||
TransactionDbHelper.fromTransaction(funding.prevTx,
|
||||
blockHashOpt = None))
|
||||
|
||||
acceptInputs = spendingInfos.zip(utxos).map { case (utxo, fundingInput) =>
|
||||
DLCFundingInputDb(
|
||||
dlcId = dlc.dlcId,
|
||||
isInitiator = false,
|
||||
inputSerialId = fundingInput.inputSerialId,
|
||||
outPoint = utxo.outPoint,
|
||||
output = utxo.output,
|
||||
nSequence = fundingInput.sequence,
|
||||
maxWitnessLength = fundingInput.maxWitnessLen.toLong,
|
||||
redeemScriptOpt = InputInfo.getRedeemScript(utxo.inputInfo),
|
||||
witnessScriptOpt = InputInfo.getScriptWitness(utxo.inputInfo)
|
||||
)
|
||||
acceptInputs = spendingInfos.zip(utxos).zipWithIndex.map {
|
||||
case ((utxo, fundingInput), idx) =>
|
||||
DLCFundingInputDb(
|
||||
dlcId = dlc.dlcId,
|
||||
isInitiator = false,
|
||||
index = idx,
|
||||
inputSerialId = fundingInput.inputSerialId,
|
||||
outPoint = utxo.outPoint,
|
||||
output = utxo.output,
|
||||
nSequence = fundingInput.sequence,
|
||||
maxWitnessLength = fundingInput.maxWitnessLen.toLong,
|
||||
redeemScriptOpt = InputInfo.getRedeemScript(utxo.inputInfo),
|
||||
witnessScriptOpt = InputInfo.getScriptWitness(utxo.inputInfo)
|
||||
)
|
||||
}
|
||||
|
||||
accept =
|
||||
@ -772,18 +779,21 @@ abstract class DLCWallet
|
||||
|
||||
val dlcId = dlc.dlcId
|
||||
lazy val dlcAcceptDb = DLCAcceptDbHelper.fromDLCAccept(dlcId, accept)
|
||||
lazy val acceptInputs = accept.fundingInputs.map(funding =>
|
||||
DLCFundingInputDb(
|
||||
dlcId = dlcId,
|
||||
isInitiator = false,
|
||||
inputSerialId = funding.inputSerialId,
|
||||
outPoint = funding.outPoint,
|
||||
output = funding.output,
|
||||
nSequence = funding.sequence,
|
||||
maxWitnessLength = funding.maxWitnessLen.toLong,
|
||||
redeemScriptOpt = funding.redeemScriptOpt,
|
||||
witnessScriptOpt = None
|
||||
))
|
||||
lazy val acceptInputs = accept.fundingInputs.zipWithIndex.map {
|
||||
case (funding, idx) =>
|
||||
DLCFundingInputDb(
|
||||
dlcId = dlcId,
|
||||
isInitiator = false,
|
||||
index = idx,
|
||||
inputSerialId = funding.inputSerialId,
|
||||
outPoint = funding.outPoint,
|
||||
output = funding.output,
|
||||
nSequence = funding.sequence,
|
||||
maxWitnessLength = funding.maxWitnessLen.toLong,
|
||||
redeemScriptOpt = funding.redeemScriptOpt,
|
||||
witnessScriptOpt = None
|
||||
)
|
||||
}
|
||||
|
||||
lazy val acceptPrevTxs = accept.fundingInputs.map { funding =>
|
||||
TransactionDbHelper.fromTransaction(funding.prevTx,
|
||||
@ -933,13 +943,20 @@ abstract class DLCWallet
|
||||
_ = logger.info(s"Creating funding sigs for ${contractId.toHex}")
|
||||
fundingSigs <- Future.fromTry(signer.signFundingTx())
|
||||
|
||||
// order fundingSigs by index
|
||||
inputDbs <- dlcInputsDAO.findByDLCId(dlc.dlcId, isInitiator = true)
|
||||
sortedSigVec = inputDbs.sortBy(_.index).map { db =>
|
||||
val sig = fundingSigs(db.outPoint)
|
||||
(db.outPoint, sig)
|
||||
}
|
||||
|
||||
updatedRefundSigsDb = refundSigsDb.copy(initiatorSig =
|
||||
Some(cetSigs.refundSig))
|
||||
_ <- dlcRefundSigDAO.update(updatedRefundSigsDb)
|
||||
|
||||
_ <- updateDLCState(dlc.contractIdOpt.get, DLCState.Signed)
|
||||
_ = logger.info(s"DLC ${contractId.toHex} is signed")
|
||||
} yield DLCSign(cetSigs, fundingSigs, contractId)
|
||||
} yield DLCSign(cetSigs, FundingSignatures(sortedSigVec), contractId)
|
||||
}
|
||||
|
||||
def verifyCETSigs(accept: DLCAccept): Future[Boolean] = {
|
||||
@ -981,7 +998,7 @@ abstract class DLCWallet
|
||||
def addFundingSigs(sign: DLCSign): Future[Vector[DLCFundingInputDb]] = {
|
||||
for {
|
||||
dlc <- dlcDAO.findByContractId(sign.contractId).map(_.get)
|
||||
inputs <- dlcInputsDAO.findByDLCId(dlc.dlcId)
|
||||
inputs <- dlcInputsDAO.findByDLCId(dlc.dlcId).map(_.sortBy(_.index))
|
||||
|
||||
_ = logger.info(
|
||||
s"Verifying ${sign.fundingSigs.length} funding sigs for contract ${sign.contractId.toHex}")
|
||||
@ -1019,36 +1036,16 @@ abstract class DLCWallet
|
||||
Future.failed(new RuntimeException(
|
||||
s"No DLC found with corresponding contractId ${contractId.toHex}"))
|
||||
}
|
||||
// .get should be safe now
|
||||
contractData <- contractDataDAO.read(dlcDb.dlcId).map(_.get)
|
||||
offerDbOpt <- dlcOfferDAO.findByDLCId(dlcDb.dlcId)
|
||||
offerDb = offerDbOpt.get
|
||||
fundingInputDbs <- dlcInputsDAO.findByDLCId(dlcDb.dlcId,
|
||||
isInitiator = true)
|
||||
(_, contractData, dlcOffer, dlcAccept, fundingInputs, contractInfo) <-
|
||||
getDLCFundingData(dlcDb.dlcId)
|
||||
builder <- builderFromDbData(dlcDb,
|
||||
contractData,
|
||||
dlcOffer,
|
||||
dlcAccept,
|
||||
fundingInputs,
|
||||
contractInfo)
|
||||
|
||||
txIds = fundingInputDbs.map(_.outPoint.txIdBE)
|
||||
remotePrevTxs <- remoteTxDAO.findByTxIdBEs(txIds)
|
||||
|
||||
(announcements, announcementData, nonceDbs) <- getDLCAnnouncementDbs(
|
||||
dlcDb.dlcId)
|
||||
|
||||
prevTxs = remotePrevTxs.map(_.transaction)
|
||||
txs = prevTxs.groupBy(_.txIdBE)
|
||||
|
||||
fundingInputs = fundingInputDbs.map(input =>
|
||||
input.toFundingInput(txs(input.outPoint.txIdBE).head))
|
||||
|
||||
contractInfo = getContractInfo(contractData,
|
||||
announcements,
|
||||
announcementData,
|
||||
nonceDbs)
|
||||
|
||||
offer = offerDb.toDLCOffer(contractInfo,
|
||||
fundingInputs,
|
||||
dlcDb,
|
||||
contractData)
|
||||
|
||||
sign = DLCSign.fromTLV(signTLV, offer)
|
||||
sign = DLCSign.fromTLV(signTLV, builder.offer)
|
||||
result <- addDLCSigs(sign)
|
||||
} yield result
|
||||
}
|
||||
|
@ -219,7 +219,9 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
||||
announcements,
|
||||
announcementData,
|
||||
nonceDbs)
|
||||
} yield (dlcDb, contractData, dlcOffer, fundingInputs, contractInfo)
|
||||
|
||||
sortedInputs = fundingInputs.sortBy(_.index)
|
||||
} yield (dlcDb, contractData, dlcOffer, sortedInputs, contractInfo)
|
||||
}
|
||||
|
||||
private[wallet] def getDLCFundingData(dlcId: Sha256Digest): Future[
|
||||
@ -421,7 +423,7 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
||||
private[wallet] def matchPrevTxsWithInputs(
|
||||
inputs: Vector[DLCFundingInputDb],
|
||||
prevTxs: Vector[TransactionDb]): Vector[DLCFundingInput] = {
|
||||
inputs.map { i =>
|
||||
inputs.sortBy(_.index).map { i =>
|
||||
prevTxs.find(_.txId == i.outPoint.txId) match {
|
||||
case Some(txDb) => i.toFundingInput(txDb.transaction)
|
||||
case None =>
|
||||
|
@ -79,7 +79,9 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing {
|
||||
contractData <- contractDataDAO.read(dlcId).map(_.get)
|
||||
offerDbOpt <- dlcOfferDAO.findByDLCId(dlcId)
|
||||
acceptDbOpt <- dlcAcceptDAO.findByDLCId(dlcId)
|
||||
fundingInputDbs <- dlcInputsDAO.findByDLCId(dlcId)
|
||||
fundingInputDbs <- dlcInputsDAO
|
||||
.findByDLCId(dlcId)
|
||||
.map(_.sortBy(_.index))
|
||||
txIds = fundingInputDbs.map(_.outPoint.txIdBE)
|
||||
remotePrevTxs <- remoteTxDAO.findByTxIdBEs(txIds)
|
||||
localPrevTxs <- transactionDAO.findByTxIdBEs(txIds)
|
||||
@ -154,7 +156,7 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing {
|
||||
|
||||
DLCStatus.calculateOutcomeAndSig(isInit, offer, accept, sign, cet).get
|
||||
}
|
||||
(outcomes, oracleInfos) = getOutcomeDbInfo(outcome)
|
||||
(_, oracleInfos) = getOutcomeDbInfo(outcome)
|
||||
|
||||
noncesByAnnouncement = nonceDbs
|
||||
.groupBy(_.announcementId)
|
||||
|
@ -85,6 +85,8 @@ case class DLCFundingInputDAO()(implicit
|
||||
|
||||
def inputSerialId: Rep[UInt64] = column("input_serial_id")
|
||||
|
||||
def index: Rep[Int] = column("index")
|
||||
|
||||
def isInitiator: Rep[Boolean] = column("is_initiator")
|
||||
|
||||
def output: Rep[TransactionOutput] = column("output")
|
||||
@ -101,6 +103,7 @@ case class DLCFundingInputDAO()(implicit
|
||||
def * : ProvenShape[DLCFundingInputDb] =
|
||||
(dlcId,
|
||||
isInitiator,
|
||||
index,
|
||||
inputSerialId,
|
||||
outPoint,
|
||||
output,
|
||||
|
@ -12,6 +12,7 @@ import org.bitcoins.crypto.Sha256Digest
|
||||
case class DLCFundingInputDb(
|
||||
dlcId: Sha256Digest,
|
||||
isInitiator: Boolean,
|
||||
index: Int,
|
||||
inputSerialId: UInt64,
|
||||
outPoint: TransactionOutPoint,
|
||||
output: TransactionOutput,
|
||||
|
Loading…
Reference in New Issue
Block a user