mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-26 21:42:48 +01:00
2022 01 14 DLCDataManagement
refactor (#3982)
* WIP * Finish refactor, get unit tests working * Remove log
This commit is contained in:
parent
214213b59d
commit
ee0d62c5b8
11 changed files with 415 additions and 227 deletions
|
@ -100,7 +100,6 @@ case class ChainAppConfig(
|
|||
logger.info(s"Applied ${numMigrations} to chain project")
|
||||
()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override def stop(): Future[Unit] = {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.bitcoins.core.protocol.tlv
|
||||
|
||||
import org.bitcoins.crypto.StringFactory
|
||||
|
||||
/** We have various binary serializations in our codebase currently.
|
||||
* This is a product of trying to release a DLC wallet before the
|
||||
* spec was finalized. Some of the binary level serialization for DLCs
|
||||
|
@ -7,7 +9,7 @@ package org.bitcoins.core.protocol.tlv
|
|||
*/
|
||||
sealed trait DLCSerializationVersion
|
||||
|
||||
object DLCSerializationVersion {
|
||||
object DLCSerializationVersion extends StringFactory[DLCSerializationVersion] {
|
||||
|
||||
/** This format existed in our wallet before we merged support for this PR
|
||||
* on the DLC spec repo. See the diff below
|
||||
|
@ -20,4 +22,19 @@ object DLCSerializationVersion {
|
|||
* @see [[https://github.com/discreetlogcontracts/dlcspecs/pull/144]]
|
||||
*/
|
||||
case object Beta extends DLCSerializationVersion
|
||||
|
||||
private val all = Vector(Alpha, Beta)
|
||||
|
||||
override def fromString(str: String): DLCSerializationVersion = {
|
||||
fromStringOpt(str) match {
|
||||
case Some(version) => version
|
||||
case None =>
|
||||
sys.error(
|
||||
s"Could not find DLC serialization version associated with str=$str")
|
||||
}
|
||||
}
|
||||
|
||||
override def fromStringOpt(str: String): Option[DLCSerializationVersion] = {
|
||||
all.find(_.toString.toLowerCase == str.toLowerCase)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -489,4 +489,11 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) {
|
|||
MappedColumnType.base[ExtKeyPubVersion, String](_.hex,
|
||||
ExtKeyPubVersion.fromHex)
|
||||
}
|
||||
|
||||
implicit val dlcSerializationVersion: BaseColumnType[
|
||||
DLCSerializationVersion] = {
|
||||
MappedColumnType.base[DLCSerializationVersion, String](
|
||||
_.toString,
|
||||
DLCSerializationVersion.fromString)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.bitcoins.core.protocol.tlv._
|
|||
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
import org.bitcoins.core.wallet.utxo.TxoState
|
||||
import org.bitcoins.crypto._
|
||||
import org.bitcoins.dlc.wallet.internal.DLCDataManagement
|
||||
import org.bitcoins.testkit.wallet.DLCWalletUtil._
|
||||
import org.bitcoins.testkit.wallet.FundWalletUtil.FundedDLCWallet
|
||||
import org.bitcoins.testkit.wallet.{BitcoinSDualWalletTest, DLCWalletUtil}
|
||||
|
@ -31,7 +32,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
|||
offerData: DLCOffer): Future[Assertion] = {
|
||||
val walletA = fundedDLCWallets._1.wallet
|
||||
val walletB = fundedDLCWallets._2.wallet
|
||||
|
||||
val walletADLCManagement = DLCDataManagement(walletA.dlcWalletDAOs)
|
||||
val walletBDLCManagement = DLCDataManagement(walletB.dlcWalletDAOs)
|
||||
for {
|
||||
offer <- walletA.createDLCOffer(
|
||||
offerData.contractInfo,
|
||||
|
@ -91,17 +93,19 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
|||
walletBChange <- walletB.addressDAO.read(accept.changeAddress)
|
||||
walletBFinal <- walletB.addressDAO.read(accept.pubKeys.payoutAddress)
|
||||
|
||||
(announcementsA, announcementDataA, nonceDbsA) <- walletA
|
||||
(announcementsA, announcementDataA, nonceDbsA) <- walletADLCManagement
|
||||
.getDLCAnnouncementDbs(dlcDb.dlcId)
|
||||
announcementTLVsA = walletA.getOracleAnnouncements(announcementsA,
|
||||
announcementDataA,
|
||||
nonceDbsA)
|
||||
announcementTLVsA = walletADLCManagement.getOracleAnnouncements(
|
||||
announcementsA,
|
||||
announcementDataA,
|
||||
nonceDbsA)
|
||||
|
||||
(announcementsB, announcementDataB, nonceDbsB) <- walletA
|
||||
(announcementsB, announcementDataB, nonceDbsB) <- walletADLCManagement
|
||||
.getDLCAnnouncementDbs(dlcDb.dlcId)
|
||||
announcementTLVsB = walletB.getOracleAnnouncements(announcementsB,
|
||||
announcementDataB,
|
||||
nonceDbsB)
|
||||
announcementTLVsB = walletBDLCManagement.getOracleAnnouncements(
|
||||
announcementsB,
|
||||
announcementDataB,
|
||||
nonceDbsB)
|
||||
} yield {
|
||||
assert(dlcDb.contractIdOpt.get == sign.contractId)
|
||||
|
||||
|
|
|
@ -29,7 +29,11 @@ import org.bitcoins.crypto._
|
|||
import org.bitcoins.db.SafeDatabase
|
||||
import org.bitcoins.dlc.wallet.internal._
|
||||
import org.bitcoins.dlc.wallet.models._
|
||||
import org.bitcoins.dlc.wallet.util.{DLCActionBuilder, DLCStatusBuilder}
|
||||
import org.bitcoins.dlc.wallet.util.{
|
||||
DLCActionBuilder,
|
||||
DLCStatusBuilder,
|
||||
DLCTxUtil
|
||||
}
|
||||
import org.bitcoins.wallet.config.WalletAppConfig
|
||||
import org.bitcoins.wallet.{Wallet, WalletLogger}
|
||||
import scodec.bits.ByteVector
|
||||
|
@ -41,7 +45,6 @@ import scala.concurrent.{ExecutionContext, Future}
|
|||
abstract class DLCWallet
|
||||
extends Wallet
|
||||
with AnyDLCHDWalletApi
|
||||
with DLCDataManagement
|
||||
with DLCTransactionProcessing {
|
||||
|
||||
implicit val dlcConfig: DLCAppConfig
|
||||
|
@ -63,18 +66,23 @@ abstract class DLCWallet
|
|||
private[bitcoins] val dlcRefundSigDAO: DLCRefundSigsDAO = DLCRefundSigsDAO()
|
||||
private[bitcoins] val remoteTxDAO: DLCRemoteTxDAO = DLCRemoteTxDAO()
|
||||
|
||||
private[wallet] val dlcWalletDAOs = DLCWalletDAOs(
|
||||
dlcDAO,
|
||||
contractDataDAO,
|
||||
dlcAnnouncementDAO,
|
||||
dlcInputsDAO,
|
||||
dlcOfferDAO,
|
||||
dlcAcceptDAO,
|
||||
dlcSigsDAO,
|
||||
dlcRefundSigDAO,
|
||||
oracleNonceDAO,
|
||||
announcementDAO
|
||||
)
|
||||
|
||||
private val dlcDataManagement = DLCDataManagement(dlcWalletDAOs)
|
||||
|
||||
protected lazy val actionBuilder: DLCActionBuilder = {
|
||||
DLCActionBuilder(
|
||||
dlcDAO = dlcDAO,
|
||||
contractDataDAO = contractDataDAO,
|
||||
dlcAnnouncementDAO = dlcAnnouncementDAO,
|
||||
dlcInputsDAO = dlcInputsDAO,
|
||||
dlcOfferDAO = dlcOfferDAO,
|
||||
dlcAcceptDAO = dlcAcceptDAO,
|
||||
dlcSigsDAO = dlcSigsDAO,
|
||||
dlcRefundSigDAO = dlcRefundSigDAO,
|
||||
oracleNonceDAO = oracleNonceDAO
|
||||
)
|
||||
DLCActionBuilder(dlcWalletDAOs)
|
||||
}
|
||||
|
||||
private lazy val safeDatabase: SafeDatabase = dlcDAO.safeDatabase
|
||||
|
@ -578,7 +586,8 @@ abstract class DLCWallet
|
|||
outcomeSigsDbs <- dlcSigsDAO.findByDLCId(dlcId)
|
||||
refundSigsDb <- dlcRefundSigDAO.read(dlcId)
|
||||
} yield {
|
||||
val inputRefs = matchPrevTxsWithInputs(fundingInputs, prevTxs)
|
||||
val inputRefs =
|
||||
DLCTxUtil.matchPrevTxsWithInputs(fundingInputs, prevTxs)
|
||||
|
||||
dlcAcceptDb.toDLCAccept(offer.tempContractId,
|
||||
inputRefs,
|
||||
|
@ -850,19 +859,20 @@ abstract class DLCWallet
|
|||
transactionDAO.findByTxIdBEs(offerInputs.map(_.outPoint.txIdBE))
|
||||
|
||||
contractData <- contractDataDAO.read(dlcId).map(_.get)
|
||||
(announcements, announcementData, nonceDbs) <- getDLCAnnouncementDbs(
|
||||
dlcId)
|
||||
(announcements, announcementData, nonceDbs) <- dlcDataManagement
|
||||
.getDLCAnnouncementDbs(dlcId)
|
||||
|
||||
contractInfo = getContractInfo(contractData,
|
||||
announcements,
|
||||
announcementData,
|
||||
nonceDbs)
|
||||
contractInfo = dlcDataManagement.getContractInfo(contractData,
|
||||
announcements,
|
||||
announcementData,
|
||||
nonceDbs)
|
||||
|
||||
offer =
|
||||
offerDb.toDLCOffer(contractInfo,
|
||||
matchPrevTxsWithInputs(offerInputs, prevTxs),
|
||||
dlc,
|
||||
contractData)
|
||||
offerDb.toDLCOffer(
|
||||
contractInfo,
|
||||
DLCTxUtil.matchPrevTxsWithInputs(offerInputs, prevTxs),
|
||||
dlc,
|
||||
contractData)
|
||||
|
||||
dlcDb <- updateDLCContractIds(offer, accept)
|
||||
|
||||
|
@ -904,7 +914,7 @@ abstract class DLCWallet
|
|||
Future.failed(new RuntimeException(
|
||||
s"No DLC found with corresponding tempContractId ${tempId.hex}, this wallet did not create the corresponding offer"))
|
||||
}
|
||||
contractInfo <- getContractInfo(dlcDb.dlcId)
|
||||
contractInfo <- dlcDataManagement.getContractInfo(dlcDb.dlcId)
|
||||
|
||||
accept =
|
||||
DLCAccept.fromTLV(acceptTLV, walletConfig.network, contractInfo)
|
||||
|
@ -922,7 +932,14 @@ abstract class DLCWallet
|
|||
// .get should be safe now
|
||||
contractId = dlc.contractIdOpt.get
|
||||
dlcId = dlc.dlcId
|
||||
signer <- signerFromDb(dlc.dlcId)
|
||||
fundingInputs <- dlcInputsDAO.findByDLCId(dlcId)
|
||||
scriptSigParams <- getScriptSigParams(dlc, fundingInputs)
|
||||
signer <- dlcDataManagement.signerFromDb(dlcId = dlc.dlcId,
|
||||
transactionDAO = transactionDAO,
|
||||
remoteTxDAO = remoteTxDAO,
|
||||
fundingUtxoScriptSigParams =
|
||||
scriptSigParams,
|
||||
keyManager = keyManager)
|
||||
|
||||
mySigs <- dlcSigsDAO.findByDLCId(dlc.dlcId)
|
||||
refundSigsDb <- dlcRefundSigDAO.findByDLCId(dlc.dlcId).map(_.head)
|
||||
|
@ -977,29 +994,42 @@ abstract class DLCWallet
|
|||
}
|
||||
|
||||
def verifyCETSigs(accept: DLCAccept): Future[Boolean] = {
|
||||
verifierFromAccept(accept).flatMap(
|
||||
_.verifyCETSigs(accept.cetSigs.indexedOutcomeSigs))
|
||||
val verifierAcceptF =
|
||||
dlcDataManagement.verifierFromAccept(accept, transactionDAO)
|
||||
verifierAcceptF.flatMap(_.verifyCETSigs(accept.cetSigs.indexedOutcomeSigs))
|
||||
}
|
||||
|
||||
def verifyCETSigs(sign: DLCSign): Future[Boolean] = {
|
||||
verifierFromDb(sign.contractId).flatMap(
|
||||
_.verifyCETSigs(sign.cetSigs.indexedOutcomeSigs))
|
||||
val verifierF = dlcDataManagement.verifierFromDb(sign.contractId,
|
||||
transactionDAO,
|
||||
remoteTxDAO)
|
||||
verifierF.flatMap(_.verifyCETSigs(sign.cetSigs.indexedOutcomeSigs))
|
||||
}
|
||||
|
||||
def verifyRefundSig(accept: DLCAccept): Future[Boolean] = {
|
||||
verifierFromAccept(accept).map(_.verifyRefundSig(accept.cetSigs.refundSig))
|
||||
val verifierF = dlcDataManagement.verifierFromAccept(accept, transactionDAO)
|
||||
|
||||
verifierF.map(_.verifyRefundSig(accept.cetSigs.refundSig))
|
||||
}
|
||||
|
||||
def verifyRefundSig(sign: DLCSign): Future[Boolean] = {
|
||||
verifierFromDb(sign.contractId).map(
|
||||
_.verifyRefundSig(sign.cetSigs.refundSig))
|
||||
val verifierF = dlcDataManagement.verifierFromDb(
|
||||
contractId = sign.contractId,
|
||||
transactionDAO = transactionDAO,
|
||||
remoteTxDAO = remoteTxDAO)
|
||||
|
||||
verifierF.map(_.verifyRefundSig(sign.cetSigs.refundSig))
|
||||
}
|
||||
|
||||
def verifyFundingSigs(
|
||||
inputs: Vector[DLCFundingInputDb],
|
||||
sign: DLCSign): Future[Boolean] = {
|
||||
if (inputs.count(_.isInitiator) == sign.fundingSigs.length) {
|
||||
verifierFromDb(sign.contractId).map { verifier =>
|
||||
val verifierF = dlcDataManagement.verifierFromDb(
|
||||
contractId = sign.contractId,
|
||||
transactionDAO = transactionDAO,
|
||||
remoteTxDAO = remoteTxDAO)
|
||||
verifierF.map { verifier =>
|
||||
verifier.verifyRemoteFundingSigs(sign.fundingSigs)
|
||||
}
|
||||
} else {
|
||||
|
@ -1054,13 +1084,17 @@ abstract class DLCWallet
|
|||
s"No DLC found with corresponding contractId ${contractId.toHex}"))
|
||||
}
|
||||
(_, contractData, dlcOffer, dlcAccept, fundingInputs, contractInfo) <-
|
||||
getDLCFundingData(dlcDb.dlcId)
|
||||
builder <- builderFromDbData(dlcDb,
|
||||
contractData,
|
||||
dlcOffer,
|
||||
dlcAccept,
|
||||
fundingInputs,
|
||||
contractInfo)
|
||||
dlcDataManagement.getDLCFundingData(dlcDb.dlcId)
|
||||
builder <- dlcDataManagement.builderFromDbData(
|
||||
dlcDb = dlcDb,
|
||||
contractDataDb = contractData,
|
||||
dlcOffer = dlcOffer,
|
||||
dlcAccept = dlcAccept,
|
||||
fundingInputsDb = fundingInputs,
|
||||
contractInfo = contractInfo,
|
||||
transactionDAO = transactionDAO,
|
||||
remoteTxDAO = remoteTxDAO
|
||||
)
|
||||
|
||||
sign = DLCSign.fromTLV(signTLV, builder.offer)
|
||||
result <- addDLCSigs(sign)
|
||||
|
@ -1127,17 +1161,44 @@ abstract class DLCWallet
|
|||
}
|
||||
}
|
||||
|
||||
private[wallet] def getScriptSigParams(
|
||||
dlcDb: DLCDb,
|
||||
fundingInputs: Vector[DLCFundingInputDb]): Future[
|
||||
Vector[ScriptSignatureParams[InputInfo]]] = {
|
||||
val outPoints =
|
||||
fundingInputs.filter(_.isInitiator == dlcDb.isInitiator).map(_.outPoint)
|
||||
val utxosF = listUtxos(outPoints)
|
||||
for {
|
||||
utxos <- utxosF
|
||||
scriptSigParams <-
|
||||
FutureUtil.foldLeftAsync(Vector.empty[ScriptSignatureParams[InputInfo]],
|
||||
utxos) { (accum, utxo) =>
|
||||
transactionDAO
|
||||
.findByOutPoint(utxo.outPoint)
|
||||
.map(txOpt =>
|
||||
utxo.toUTXOInfo(keyManager, txOpt.get.transaction) +: accum)
|
||||
}
|
||||
} yield scriptSigParams
|
||||
}
|
||||
|
||||
override def getDLCFundingTx(contractId: ByteVector): Future[Transaction] = {
|
||||
for {
|
||||
(dlcDb, contractData, dlcOffer, dlcAccept, fundingInputs, contractInfo) <-
|
||||
getDLCFundingData(contractId)
|
||||
dlcDataManagement.getDLCFundingData(contractId)
|
||||
|
||||
signer <- signerFromDb(dlcDb,
|
||||
contractData,
|
||||
dlcOffer,
|
||||
dlcAccept,
|
||||
fundingInputs,
|
||||
contractInfo)
|
||||
scriptSigParams <- getScriptSigParams(dlcDb, fundingInputs)
|
||||
signer <- dlcDataManagement.signerFromDb(
|
||||
dlcDb = dlcDb,
|
||||
contractDataDb = contractData,
|
||||
dlcOffer = dlcOffer,
|
||||
dlcAccept = dlcAccept,
|
||||
fundingInputsDb = fundingInputs,
|
||||
fundingUtxoScriptSigParams = scriptSigParams,
|
||||
contractInfo = contractInfo,
|
||||
transactionDAO = transactionDAO,
|
||||
remoteTxDAO = remoteTxDAO,
|
||||
keyManager = keyManager
|
||||
)
|
||||
fundingTx <-
|
||||
if (dlcDb.isInitiator) {
|
||||
transactionDAO.findByTxId(signer.builder.buildFundingTx.txIdBE).map {
|
||||
|
@ -1219,12 +1280,13 @@ abstract class DLCWallet
|
|||
for {
|
||||
dlcDb <- dlcDAO.findByContractId(contractId).map(_.get)
|
||||
|
||||
(announcements, announcementData, nonceDbs) <- getDLCAnnouncementDbs(
|
||||
dlcDb.dlcId)
|
||||
(announcements, announcementData, nonceDbs) <- dlcDataManagement
|
||||
.getDLCAnnouncementDbs(dlcDb.dlcId)
|
||||
|
||||
announcementTLVs = getOracleAnnouncements(announcements,
|
||||
announcementData,
|
||||
nonceDbs)
|
||||
announcementTLVs = dlcDataManagement.getOracleAnnouncements(
|
||||
announcements,
|
||||
announcementData,
|
||||
nonceDbs)
|
||||
|
||||
oracleSigs =
|
||||
sigs.foldLeft(Vector.empty[OracleSignatures]) { (acc, sig) =>
|
||||
|
@ -1272,9 +1334,16 @@ abstract class DLCWallet
|
|||
contractId: ByteVector,
|
||||
oracleSigs: Vector[OracleSignatures]): Future[Transaction] = {
|
||||
require(oracleSigs.nonEmpty, "Must provide at least one oracle signature")
|
||||
val executorWithSetupOptF = executorAndSetupFromDb(contractId)
|
||||
for {
|
||||
executorWithSetupOpt <- executorWithSetupOptF
|
||||
(dlcDb, _, _, _, fundingInputs, _) <-
|
||||
dlcDataManagement.getDLCFundingData(contractId)
|
||||
scriptSigParams <- getScriptSigParams(dlcDb, fundingInputs)
|
||||
executorWithSetupOpt <- dlcDataManagement.executorAndSetupFromDb(
|
||||
contractId = contractId,
|
||||
transactionDAO = transactionDAO,
|
||||
remoteTxDAO = remoteTxDAO,
|
||||
fundingUtxoScriptSigParams = scriptSigParams,
|
||||
keyManager = keyManager)
|
||||
tx <- {
|
||||
executorWithSetupOpt match {
|
||||
case Some(executorWithSetup) =>
|
||||
|
@ -1359,7 +1428,13 @@ abstract class DLCWallet
|
|||
s"Refund transaction is not valid yet, current time: $currentTime, refund valid at time $time")
|
||||
}
|
||||
|
||||
executor <- executorFromDb(dlcDb.dlcId)
|
||||
fundingInputs <- dlcInputsDAO.findByDLCId(dlcDb.dlcId)
|
||||
scriptSigParams <- getScriptSigParams(dlcDb, fundingInputs)
|
||||
executor <- dlcDataManagement.executorFromDb(dlcDb.dlcId,
|
||||
transactionDAO,
|
||||
remoteTxDAO,
|
||||
scriptSigParams,
|
||||
keyManager)
|
||||
refundSigsDbOpt <- dlcRefundSigDAO.findByDLCId(dlcDb.dlcId)
|
||||
|
||||
refundSig =
|
||||
|
@ -1462,18 +1537,20 @@ abstract class DLCWallet
|
|||
val aggregatedF: Future[(
|
||||
Vector[DLCAnnouncementDb],
|
||||
Vector[OracleAnnouncementDataDb],
|
||||
Vector[OracleNonceDb])] = getDLCAnnouncementDbs(dlcDb.dlcId)
|
||||
Vector[OracleNonceDb])] =
|
||||
dlcDataManagement.getDLCAnnouncementDbs(dlcDb.dlcId)
|
||||
|
||||
val contractInfoAndAnnouncementsF: Future[
|
||||
(ContractInfo, Vector[(OracleAnnouncementV0TLV, Long)])] = {
|
||||
aggregatedF.map { case (announcements, announcementData, nonceDbs) =>
|
||||
val contractInfo = getContractInfo(contractData,
|
||||
announcements,
|
||||
announcementData,
|
||||
nonceDbs)
|
||||
val announcementsWithId = getOracleAnnouncementsWithId(announcements,
|
||||
announcementData,
|
||||
nonceDbs)
|
||||
val contractInfo = dlcDataManagement.getContractInfo(contractData,
|
||||
announcements,
|
||||
announcementData,
|
||||
nonceDbs)
|
||||
val announcementsWithId =
|
||||
dlcDataManagement.getOracleAnnouncementsWithId(announcements,
|
||||
announcementData,
|
||||
nonceDbs)
|
||||
(contractInfo, announcementsWithId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.bitcoins.dlc.wallet.internal
|
||||
|
||||
import org.bitcoins.core.api.dlc.wallet.db.DLCDb
|
||||
import org.bitcoins.core.api.wallet.db.TransactionDb
|
||||
import org.bitcoins.core.hd._
|
||||
import org.bitcoins.core.protocol.dlc.build.DLCTxBuilder
|
||||
import org.bitcoins.core.protocol.dlc.execution._
|
||||
|
@ -11,19 +10,35 @@ import org.bitcoins.core.protocol.dlc.sign.DLCTxSigner
|
|||
import org.bitcoins.core.protocol.dlc.verify.DLCSignatureVerifier
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.tlv._
|
||||
import org.bitcoins.core.util.FutureUtil
|
||||
import org.bitcoins.core.util.sorted.{OrderedAnnouncements, OrderedNonces}
|
||||
import org.bitcoins.core.wallet.utxo._
|
||||
import org.bitcoins.crypto.Sha256Digest
|
||||
import org.bitcoins.dlc.wallet.DLCWallet
|
||||
import org.bitcoins.dlc.wallet.models._
|
||||
import org.bitcoins.dlc.wallet.util.{DLCActionBuilder, DLCTxUtil}
|
||||
import org.bitcoins.keymanager.bip39.BIP39KeyManager
|
||||
import org.bitcoins.wallet.models.TransactionDAO
|
||||
import scodec.bits._
|
||||
import slick.dbio.{DBIOAction, Effect, NoStream}
|
||||
|
||||
import scala.concurrent._
|
||||
|
||||
/** Handles fetching and constructing different DLC datastructures from the database */
|
||||
private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
||||
case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit
|
||||
ec: ExecutionContext) {
|
||||
private val dlcDAO = dlcWalletDAOs.dlcDAO
|
||||
private val dlcAnnouncementDAO = dlcWalletDAOs.dlcAnnouncementDAO
|
||||
//private val dlcInputsDAO = dlcWalletDAOs.dlcInputsDAO
|
||||
// private val dlcOfferDAO = dlcWalletDAOs.dlcOfferDAO
|
||||
private val contractDataDAO = dlcWalletDAOs.contractDataDAO
|
||||
private val dlcAcceptDAO = dlcWalletDAOs.dlcAcceptDAO
|
||||
private val dlcSigsDAO = dlcWalletDAOs.dlcSigsDAO
|
||||
private val dlcRefundSigDAO = dlcWalletDAOs.dlcRefundSigDAO
|
||||
private val announcementDAO = dlcWalletDAOs.oracleAnnouncementDAO
|
||||
private val oracleNonceDAO = dlcWalletDAOs.oracleNonceDAO
|
||||
|
||||
private val actionBuilder: DLCActionBuilder = {
|
||||
DLCActionBuilder(dlcWalletDAOs)
|
||||
}
|
||||
private lazy val safeDatabase = dlcDAO.safeDatabase
|
||||
|
||||
private[wallet] def getDLCAnnouncementDbs(dlcId: Sha256Digest): Future[(
|
||||
|
@ -322,28 +337,9 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
|||
}
|
||||
}
|
||||
|
||||
private[wallet] def fundingUtxosFromDb(
|
||||
dlcDb: DLCDb,
|
||||
fundingInputs: Vector[DLCFundingInputDb]): Future[
|
||||
Vector[ScriptSignatureParams[InputInfo]]] = {
|
||||
val outPoints =
|
||||
fundingInputs.filter(_.isInitiator == dlcDb.isInitiator).map(_.outPoint)
|
||||
|
||||
for {
|
||||
utxos <- listUtxos(outPoints)
|
||||
scriptSigParams <-
|
||||
FutureUtil.foldLeftAsync(Vector.empty[ScriptSignatureParams[InputInfo]],
|
||||
utxos) { (accum, utxo) =>
|
||||
transactionDAO
|
||||
.findByOutPoint(utxo.outPoint)
|
||||
.map(txOpt =>
|
||||
utxo.toUTXOInfo(keyManager, txOpt.get.transaction) +: accum)
|
||||
}
|
||||
} yield scriptSigParams
|
||||
}
|
||||
|
||||
private[wallet] def verifierFromAccept(
|
||||
accept: DLCAccept): Future[DLCSignatureVerifier] = {
|
||||
accept: DLCAccept,
|
||||
transactionDAO: TransactionDAO): Future[DLCSignatureVerifier] = {
|
||||
for {
|
||||
dlcDbOpt <- dlcDAO.findByTempContractId(accept.tempContractId)
|
||||
dlcDb = dlcDbOpt.get
|
||||
|
@ -356,7 +352,7 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
|||
transactionDAO.findByTxIdBEs(localFundingInputs.map(_.outPoint.txIdBE))
|
||||
} yield {
|
||||
val offerFundingInputs =
|
||||
matchPrevTxsWithInputs(localFundingInputs, prevTxs)
|
||||
DLCTxUtil.matchPrevTxsWithInputs(localFundingInputs, prevTxs)
|
||||
val offer = dlcOffer.toDLCOffer(contractInfo,
|
||||
offerFundingInputs,
|
||||
dlcDb,
|
||||
|
@ -369,7 +365,9 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
|||
}
|
||||
|
||||
private[wallet] def verifierFromDb(
|
||||
contractId: ByteVector): Future[DLCSignatureVerifier] = {
|
||||
contractId: ByteVector,
|
||||
transactionDAO: TransactionDAO,
|
||||
remoteTxDAO: DLCRemoteTxDAO): Future[DLCSignatureVerifier] = {
|
||||
getDLCFundingData(contractId).flatMap {
|
||||
case (dlcDb,
|
||||
contractData,
|
||||
|
@ -377,12 +375,16 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
|||
dlcAccept,
|
||||
fundingInputsDb,
|
||||
contractInfo) =>
|
||||
verifierFromDbData(dlcDb,
|
||||
contractData,
|
||||
dlcOffer,
|
||||
dlcAccept,
|
||||
fundingInputsDb,
|
||||
contractInfo)
|
||||
verifierFromDbData(
|
||||
dlcDb = dlcDb,
|
||||
contractData = contractData,
|
||||
dlcOffer = dlcOffer,
|
||||
dlcAccept = dlcAccept,
|
||||
fundingInputsDb = fundingInputsDb,
|
||||
contractInfo = contractInfo,
|
||||
transactionDAO = transactionDAO,
|
||||
remoteTxDAO = remoteTxDAO
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -392,7 +394,9 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
|||
dlcOffer: DLCOfferDb,
|
||||
dlcAccept: DLCAcceptDb,
|
||||
fundingInputsDb: Vector[DLCFundingInputDb],
|
||||
contractInfo: ContractInfo): Future[DLCTxBuilder] = {
|
||||
contractInfo: ContractInfo,
|
||||
transactionDAO: TransactionDAO,
|
||||
remoteTxDAO: DLCRemoteTxDAO): Future[DLCTxBuilder] = {
|
||||
val (localDbFundingInputs, remoteDbFundingInputs) = if (dlcDb.isInitiator) {
|
||||
(fundingInputsDb.filter(_.isInitiator),
|
||||
fundingInputsDb.filterNot(_.isInitiator))
|
||||
|
@ -407,13 +411,13 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
|||
remotePrevTxs <-
|
||||
remoteTxDAO.findByTxIdBEs(remoteDbFundingInputs.map(_.outPoint.txIdBE))
|
||||
} yield {
|
||||
val localFundingInputs = matchPrevTxsWithInputs(inputs =
|
||||
localDbFundingInputs,
|
||||
prevTxs = localPrevTxs)
|
||||
val localFundingInputs = DLCTxUtil.matchPrevTxsWithInputs(
|
||||
inputs = localDbFundingInputs,
|
||||
prevTxs = localPrevTxs)
|
||||
|
||||
val remoteFundingInputs = matchPrevTxsWithInputs(inputs =
|
||||
remoteDbFundingInputs,
|
||||
prevTxs = remotePrevTxs)
|
||||
val remoteFundingInputs = DLCTxUtil.matchPrevTxsWithInputs(
|
||||
inputs = remoteDbFundingInputs,
|
||||
prevTxs = remotePrevTxs)
|
||||
|
||||
val (offerFundingInputs, acceptFundingInputs) = if (dlcDb.isInitiator) {
|
||||
(localFundingInputs, remoteFundingInputs)
|
||||
|
@ -434,42 +438,36 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
|||
}
|
||||
}
|
||||
|
||||
/** Takes in a list of inputs to fund DLCs, and pairs them with the full funding transaction for this input
|
||||
* and then converts the input tx pair to a [[DLCFundingInput]]
|
||||
* @throws NoSuchElementException when we have an input we cannot find the funding transaction for
|
||||
*/
|
||||
private[wallet] def matchPrevTxsWithInputs(
|
||||
inputs: Vector[DLCFundingInputDb],
|
||||
prevTxs: Vector[TransactionDb]): Vector[DLCFundingInput] = {
|
||||
inputs.sortBy(_.index).map { i =>
|
||||
prevTxs.find(_.txId == i.outPoint.txId) match {
|
||||
case Some(txDb) => i.toFundingInput(txDb.transaction)
|
||||
case None =>
|
||||
throw new NoSuchElementException(
|
||||
s"Could not find previous transaction with txIdBE=${i.outPoint.txId.flip.hex}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private[wallet] def verifierFromDbData(
|
||||
dlcDb: DLCDb,
|
||||
contractData: DLCContractDataDb,
|
||||
dlcOffer: DLCOfferDb,
|
||||
dlcAccept: DLCAcceptDb,
|
||||
fundingInputsDb: Vector[DLCFundingInputDb],
|
||||
contractInfo: ContractInfo): Future[DLCSignatureVerifier] = {
|
||||
contractInfo: ContractInfo,
|
||||
transactionDAO: TransactionDAO,
|
||||
remoteTxDAO: DLCRemoteTxDAO): Future[DLCSignatureVerifier] = {
|
||||
val builderF =
|
||||
builderFromDbData(dlcDb,
|
||||
contractData,
|
||||
dlcOffer,
|
||||
dlcAccept,
|
||||
fundingInputsDb,
|
||||
contractInfo)
|
||||
builderFromDbData(
|
||||
dlcDb = dlcDb,
|
||||
contractDataDb = contractData,
|
||||
dlcOffer = dlcOffer,
|
||||
dlcAccept = dlcAccept,
|
||||
fundingInputsDb = fundingInputsDb,
|
||||
contractInfo = contractInfo,
|
||||
transactionDAO = transactionDAO,
|
||||
remoteTxDAO = remoteTxDAO
|
||||
)
|
||||
|
||||
builderF.map(DLCSignatureVerifier(_, dlcDb.isInitiator))
|
||||
}
|
||||
|
||||
private[wallet] def signerFromDb(dlcId: Sha256Digest): Future[DLCTxSigner] = {
|
||||
private[wallet] def signerFromDb(
|
||||
dlcId: Sha256Digest,
|
||||
transactionDAO: TransactionDAO,
|
||||
remoteTxDAO: DLCRemoteTxDAO,
|
||||
fundingUtxoScriptSigParams: Vector[ScriptSignatureParams[InputInfo]],
|
||||
keyManager: BIP39KeyManager): Future[DLCTxSigner] = {
|
||||
for {
|
||||
(dlcDb,
|
||||
contractData,
|
||||
|
@ -478,12 +476,18 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
|||
fundingInputsDb,
|
||||
contractInfo) <-
|
||||
getDLCFundingData(dlcId)
|
||||
signer <- signerFromDb(dlcDb,
|
||||
contractData,
|
||||
dlcOffer,
|
||||
dlcAccept,
|
||||
fundingInputsDb,
|
||||
contractInfo)
|
||||
signer <- signerFromDb(
|
||||
dlcDb = dlcDb,
|
||||
contractDataDb = contractData,
|
||||
dlcOffer = dlcOffer,
|
||||
dlcAccept = dlcAccept,
|
||||
fundingInputsDb = fundingInputsDb,
|
||||
fundingUtxoScriptSigParams = fundingUtxoScriptSigParams,
|
||||
contractInfo = contractInfo,
|
||||
transactionDAO = transactionDAO,
|
||||
remoteTxDAO = remoteTxDAO,
|
||||
keyManager = keyManager
|
||||
)
|
||||
} yield signer
|
||||
}
|
||||
|
||||
|
@ -493,15 +497,22 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
|||
dlcOffer: DLCOfferDb,
|
||||
dlcAccept: DLCAcceptDb,
|
||||
fundingInputsDb: Vector[DLCFundingInputDb],
|
||||
contractInfo: ContractInfo): Future[DLCTxSigner] = {
|
||||
fundingUtxoScriptSigParams: Vector[ScriptSignatureParams[InputInfo]],
|
||||
contractInfo: ContractInfo,
|
||||
transactionDAO: TransactionDAO,
|
||||
remoteTxDAO: DLCRemoteTxDAO,
|
||||
keyManager: BIP39KeyManager): Future[DLCTxSigner] = {
|
||||
for {
|
||||
fundingUtxos <- fundingUtxosFromDb(dlcDb, fundingInputsDb)
|
||||
builder <- builderFromDbData(dlcDb = dlcDb,
|
||||
contractDataDb = contractDataDb,
|
||||
dlcOffer = dlcOffer,
|
||||
dlcAccept = dlcAccept,
|
||||
fundingInputsDb = fundingInputsDb,
|
||||
contractInfo = contractInfo)
|
||||
builder <- builderFromDbData(
|
||||
dlcDb = dlcDb,
|
||||
contractDataDb = contractDataDb,
|
||||
dlcOffer = dlcOffer,
|
||||
dlcAccept = dlcAccept,
|
||||
fundingInputsDb = fundingInputsDb,
|
||||
contractInfo = contractInfo,
|
||||
transactionDAO = transactionDAO,
|
||||
remoteTxDAO = remoteTxDAO
|
||||
)
|
||||
} yield {
|
||||
val (fundingKey, payoutAddress) = if (dlcDb.isInitiator) {
|
||||
(dlcOffer.fundingKey, dlcOffer.payoutAddress)
|
||||
|
@ -523,7 +534,7 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
|||
isInitiator = dlcDb.isInitiator,
|
||||
fundingKey = fundingPrivKey,
|
||||
finalAddress = payoutAddress,
|
||||
fundingUtxos = fundingUtxos)
|
||||
fundingUtxos = fundingUtxoScriptSigParams)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -533,25 +544,47 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
|||
dlcOffer: DLCOfferDb,
|
||||
dlcAccept: DLCAcceptDb,
|
||||
fundingInputsDb: Vector[DLCFundingInputDb],
|
||||
contractInfo: ContractInfo): Future[DLCExecutor] = {
|
||||
signerFromDb(dlcDb,
|
||||
contractDataDb,
|
||||
dlcOffer,
|
||||
dlcAccept,
|
||||
fundingInputsDb,
|
||||
contractInfo).map(DLCExecutor.apply)
|
||||
fundingUtxoScriptSigParams: Vector[ScriptSignatureParams[InputInfo]],
|
||||
contractInfo: ContractInfo,
|
||||
transactionDAO: TransactionDAO,
|
||||
remoteTxDAO: DLCRemoteTxDAO,
|
||||
keyManager: BIP39KeyManager): Future[DLCExecutor] = {
|
||||
signerFromDb(
|
||||
dlcDb = dlcDb,
|
||||
contractDataDb = contractDataDb,
|
||||
dlcOffer = dlcOffer,
|
||||
dlcAccept = dlcAccept,
|
||||
fundingInputsDb = fundingInputsDb,
|
||||
fundingUtxoScriptSigParams = fundingUtxoScriptSigParams,
|
||||
contractInfo = contractInfo,
|
||||
transactionDAO = transactionDAO,
|
||||
remoteTxDAO = remoteTxDAO,
|
||||
keyManager = keyManager
|
||||
).map(DLCExecutor.apply)
|
||||
}
|
||||
|
||||
private[wallet] def executorFromDb(
|
||||
dlcId: Sha256Digest): Future[DLCExecutor] = {
|
||||
signerFromDb(dlcId).map(DLCExecutor.apply)
|
||||
dlcId: Sha256Digest,
|
||||
transactionDAO: TransactionDAO,
|
||||
remoteTxDAO: DLCRemoteTxDAO,
|
||||
fundingUtxoScriptSigParams: Vector[ScriptSignatureParams[InputInfo]],
|
||||
keyManager: BIP39KeyManager): Future[DLCExecutor] = {
|
||||
signerFromDb(dlcId = dlcId,
|
||||
transactionDAO = transactionDAO,
|
||||
remoteTxDAO = remoteTxDAO,
|
||||
fundingUtxoScriptSigParams = fundingUtxoScriptSigParams,
|
||||
keyManager = keyManager).map(DLCExecutor.apply)
|
||||
}
|
||||
|
||||
/** Builds an [[DLCExecutor]] and [[SetupDLC]] for a given contract id
|
||||
* @return the executor and setup if we still have CET signatures else return None
|
||||
*/
|
||||
private[wallet] def executorAndSetupFromDb(
|
||||
contractId: ByteVector): Future[Option[DLCExecutorWithSetup]] = {
|
||||
contractId: ByteVector,
|
||||
transactionDAO: TransactionDAO,
|
||||
remoteTxDAO: DLCRemoteTxDAO,
|
||||
fundingUtxoScriptSigParams: Vector[ScriptSignatureParams[InputInfo]],
|
||||
keyManager: BIP39KeyManager): Future[Option[DLCExecutorWithSetup]] = {
|
||||
getAllDLCData(contractId).flatMap {
|
||||
case (dlcDb,
|
||||
contractData,
|
||||
|
@ -563,14 +596,20 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
|||
outcomeSigsDbsOpt) =>
|
||||
outcomeSigsDbsOpt match {
|
||||
case Some(outcomeSigsDbs) =>
|
||||
executorAndSetupFromDb(dlcDb,
|
||||
contractData,
|
||||
dlcOffer,
|
||||
dlcAccept,
|
||||
refundSigs,
|
||||
contractInfo,
|
||||
fundingInputsDb,
|
||||
outcomeSigsDbs).map(Some(_))
|
||||
executorAndSetupFromDb(
|
||||
dlcDb = dlcDb,
|
||||
contractDataDb = contractData,
|
||||
dlcOffer = dlcOffer,
|
||||
dlcAccept = dlcAccept,
|
||||
refundSigsDb = refundSigs,
|
||||
contractInfo = contractInfo,
|
||||
fundingInputs = fundingInputsDb,
|
||||
outcomeSigsDbs = outcomeSigsDbs,
|
||||
transactionDAO = transactionDAO,
|
||||
remoteTxDAO = remoteTxDAO,
|
||||
fundingUtxoScriptSigParams = fundingUtxoScriptSigParams,
|
||||
keyManager = keyManager
|
||||
).map(Some(_))
|
||||
case None =>
|
||||
//means we cannot re-create messages because
|
||||
//we don't have the cets in the database anymore
|
||||
|
@ -589,15 +628,24 @@ private[bitcoins] trait DLCDataManagement { self: DLCWallet =>
|
|||
refundSigsDb: DLCRefundSigsDb,
|
||||
contractInfo: ContractInfo,
|
||||
fundingInputs: Vector[DLCFundingInputDb],
|
||||
outcomeSigsDbs: Vector[DLCCETSignaturesDb]): Future[
|
||||
DLCExecutorWithSetup] = {
|
||||
outcomeSigsDbs: Vector[DLCCETSignaturesDb],
|
||||
transactionDAO: TransactionDAO,
|
||||
remoteTxDAO: DLCRemoteTxDAO,
|
||||
fundingUtxoScriptSigParams: Vector[ScriptSignatureParams[InputInfo]],
|
||||
keyManager: BIP39KeyManager): Future[DLCExecutorWithSetup] = {
|
||||
|
||||
val dlcExecutorF = executorFromDb(dlcDb,
|
||||
contractDataDb,
|
||||
dlcOffer,
|
||||
dlcAccept,
|
||||
fundingInputs,
|
||||
contractInfo)
|
||||
val dlcExecutorF = executorFromDb(
|
||||
dlcDb = dlcDb,
|
||||
contractDataDb = contractDataDb,
|
||||
dlcOffer = dlcOffer,
|
||||
dlcAccept = dlcAccept,
|
||||
fundingInputsDb = fundingInputs,
|
||||
fundingUtxoScriptSigParams = fundingUtxoScriptSigParams,
|
||||
contractInfo = contractInfo,
|
||||
transactionDAO = transactionDAO,
|
||||
remoteTxDAO = remoteTxDAO,
|
||||
keyManager = keyManager
|
||||
)
|
||||
|
||||
dlcExecutorF.flatMap { executor =>
|
||||
// Filter for only counterparty's outcome sigs
|
||||
|
|
|
@ -26,15 +26,28 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing {
|
|||
import dlcDAO.profile.api._
|
||||
private lazy val safeDatabase: SafeDatabase = dlcDAO.safeDatabase
|
||||
|
||||
private lazy val dlcDataManagement: DLCDataManagement = DLCDataManagement(
|
||||
dlcWalletDAOs)
|
||||
|
||||
/** Calculates the new state of the DLCDb based on the closing transaction,
|
||||
* will delete old CET sigs that are no longer needed after execution
|
||||
*/
|
||||
def calculateAndSetState(dlcDb: DLCDb): Future[DLCDb] = {
|
||||
(dlcDb.contractIdOpt, dlcDb.closingTxIdOpt) match {
|
||||
case (Some(id), Some(txId)) =>
|
||||
val executorWithSetupOptF = executorAndSetupFromDb(id)
|
||||
executorWithSetupOptF.flatMap { case executorWithSetupOpt =>
|
||||
executorWithSetupOpt match {
|
||||
val fundingInputsF = dlcInputsDAO.findByDLCId(dlcDb.dlcId)
|
||||
val scriptSigParamsF =
|
||||
fundingInputsF.flatMap(inputs => getScriptSigParams(dlcDb, inputs))
|
||||
|
||||
for {
|
||||
scriptSigParams <- scriptSigParamsF
|
||||
executorWithSetupOpt <- dlcDataManagement.executorAndSetupFromDb(
|
||||
id,
|
||||
transactionDAO,
|
||||
remoteTxDAO,
|
||||
scriptSigParams,
|
||||
keyManager)
|
||||
updatedDlcDb <- executorWithSetupOpt match {
|
||||
case Some(exeutorWithSetup) =>
|
||||
calculateAndSetStateWithSetupDLC(exeutorWithSetup.setup,
|
||||
dlcDb,
|
||||
|
@ -44,7 +57,7 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing {
|
|||
//just return the dlcdb given to us
|
||||
Future.successful(dlcDb)
|
||||
}
|
||||
}
|
||||
} yield updatedDlcDb
|
||||
case (None, None) | (None, Some(_)) | (Some(_), None) =>
|
||||
Future.successful(dlcDb)
|
||||
}
|
||||
|
@ -101,13 +114,13 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing {
|
|||
|
||||
for {
|
||||
(_, contractData, offerDb, acceptDb, fundingInputDbs, _) <-
|
||||
getDLCFundingData(dlcId)
|
||||
dlcDataManagement.getDLCFundingData(dlcId)
|
||||
txIds = fundingInputDbs.map(_.outPoint.txIdBE)
|
||||
remotePrevTxs <- remoteTxDAO.findByTxIdBEs(txIds)
|
||||
localPrevTxs <- transactionDAO.findByTxIdBEs(txIds)
|
||||
(sigDbs, refundSigsDb) <- getCetAndRefundSigs(dlcId)
|
||||
(announcements, announcementData, nonceDbs) <- getDLCAnnouncementDbs(
|
||||
dlcDb.dlcId)
|
||||
(sigDbs, refundSigsDb) <- dlcDataManagement.getCetAndRefundSigs(dlcId)
|
||||
(announcements, announcementData, nonceDbs) <- dlcDataManagement
|
||||
.getDLCAnnouncementDbs(dlcDb.dlcId)
|
||||
|
||||
cet <-
|
||||
transactionDAO
|
||||
|
@ -127,10 +140,10 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing {
|
|||
val acceptRefundSigOpt = refundSigsDb.map(_.accepterSig)
|
||||
|
||||
val contractInfo =
|
||||
getContractInfo(contractData,
|
||||
announcements,
|
||||
announcementData,
|
||||
nonceDbs)
|
||||
dlcDataManagement.getContractInfo(contractData,
|
||||
announcements,
|
||||
announcementData,
|
||||
nonceDbs)
|
||||
|
||||
val offer =
|
||||
offerDb.toDLCOffer(contractInfo, fundingInputs, dlcDb, contractData)
|
||||
|
@ -176,9 +189,10 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing {
|
|||
noncesByAnnouncement = nonceDbs
|
||||
.groupBy(_.announcementId)
|
||||
|
||||
announcementsWithId = getOracleAnnouncementsWithId(announcements,
|
||||
announcementData,
|
||||
nonceDbs)
|
||||
announcementsWithId = dlcDataManagement.getOracleAnnouncementsWithId(
|
||||
announcements,
|
||||
announcementData,
|
||||
nonceDbs)
|
||||
|
||||
usedIds = announcementsWithId
|
||||
.filter(t => oracleInfos.exists(_.announcement == t._1))
|
||||
|
|
|
@ -158,7 +158,7 @@ case class DLCDAO()(implicit
|
|||
def aggregateSignatureOpt: Rep[Option[SchnorrDigitalSignature]] = column(
|
||||
"aggregate_signature")
|
||||
|
||||
def * : ProvenShape[DLCDb] =
|
||||
override def * : ProvenShape[DLCDb] =
|
||||
(dlcId,
|
||||
tempContractId,
|
||||
contractId,
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package org.bitcoins.dlc.wallet.models
|
||||
|
||||
case class DLCWalletDAOs(
|
||||
dlcDAO: DLCDAO,
|
||||
contractDataDAO: DLCContractDataDAO,
|
||||
dlcAnnouncementDAO: DLCAnnouncementDAO,
|
||||
dlcInputsDAO: DLCFundingInputDAO,
|
||||
dlcOfferDAO: DLCOfferDAO,
|
||||
dlcAcceptDAO: DLCAcceptDAO,
|
||||
dlcSigsDAO: DLCCETSignaturesDAO,
|
||||
dlcRefundSigDAO: DLCRefundSigsDAO,
|
||||
oracleNonceDAO: OracleNonceDAO,
|
||||
oracleAnnouncementDAO: OracleAnnouncementDataDAO)
|
|
@ -2,42 +2,25 @@ package org.bitcoins.dlc.wallet.util
|
|||
|
||||
import org.bitcoins.core.api.dlc.wallet.db.DLCDb
|
||||
import org.bitcoins.crypto.{SchnorrDigitalSignature, SchnorrNonce, Sha256Digest}
|
||||
import org.bitcoins.dlc.wallet.models.{
|
||||
DLCAcceptDAO,
|
||||
DLCAcceptDb,
|
||||
DLCAnnouncementDAO,
|
||||
DLCAnnouncementDb,
|
||||
DLCCETSignaturesDAO,
|
||||
DLCCETSignaturesDb,
|
||||
DLCContractDataDAO,
|
||||
DLCContractDataDb,
|
||||
DLCDAO,
|
||||
DLCFundingInputDAO,
|
||||
DLCFundingInputDb,
|
||||
DLCOfferDAO,
|
||||
DLCOfferDb,
|
||||
DLCRefundSigsDAO,
|
||||
DLCRefundSigsDb,
|
||||
OracleNonceDAO,
|
||||
OracleNonceDb
|
||||
}
|
||||
import org.bitcoins.dlc.wallet.models._
|
||||
|
||||
import scala.concurrent.ExecutionContext
|
||||
|
||||
/** Utility class to help build actions to insert things into our DLC tables */
|
||||
case class DLCActionBuilder(
|
||||
dlcDAO: DLCDAO,
|
||||
contractDataDAO: DLCContractDataDAO,
|
||||
dlcAnnouncementDAO: DLCAnnouncementDAO,
|
||||
dlcInputsDAO: DLCFundingInputDAO,
|
||||
dlcOfferDAO: DLCOfferDAO,
|
||||
dlcAcceptDAO: DLCAcceptDAO,
|
||||
dlcSigsDAO: DLCCETSignaturesDAO,
|
||||
dlcRefundSigDAO: DLCRefundSigsDAO,
|
||||
oracleNonceDAO: OracleNonceDAO) {
|
||||
case class DLCActionBuilder(dlcWalletDAOs: DLCWalletDAOs) {
|
||||
|
||||
private val dlcDAO = dlcWalletDAOs.dlcDAO
|
||||
private val dlcAnnouncementDAO = dlcWalletDAOs.dlcAnnouncementDAO
|
||||
private val dlcInputsDAO = dlcWalletDAOs.dlcInputsDAO
|
||||
private val dlcOfferDAO = dlcWalletDAOs.dlcOfferDAO
|
||||
private val contractDataDAO = dlcWalletDAOs.contractDataDAO
|
||||
private val dlcAcceptDAO = dlcWalletDAOs.dlcAcceptDAO
|
||||
private val dlcSigsDAO = dlcWalletDAOs.dlcSigsDAO
|
||||
private val dlcRefundSigDAO = dlcWalletDAOs.dlcRefundSigDAO
|
||||
private val oracleNonceDAO = dlcWalletDAOs.oracleNonceDAO
|
||||
|
||||
//idk if it matters which profile api i import, but i need access to transactionally
|
||||
import dlcDAO.profile.api._
|
||||
import dlcWalletDAOs.dlcDAO.profile.api._
|
||||
|
||||
/** Builds an offer in our database, adds relevant information to the global table,
|
||||
* contract data, announcements, funding inputs, and the actual offer itself
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package org.bitcoins.dlc.wallet.util
|
||||
|
||||
import org.bitcoins.core.api.wallet.db.TransactionDb
|
||||
import org.bitcoins.core.protocol.dlc.models.DLCFundingInput
|
||||
import org.bitcoins.dlc.wallet.models.DLCFundingInputDb
|
||||
|
||||
object DLCTxUtil {
|
||||
|
||||
/** Takes in a list of inputs to fund DLCs, and pairs them with the full funding transaction for this input
|
||||
* and then converts the input tx pair to a [[DLCFundingInput]]
|
||||
* @throws NoSuchElementException when we have an input we cannot find the funding transaction for
|
||||
*/
|
||||
def matchPrevTxsWithInputs(
|
||||
inputs: Vector[DLCFundingInputDb],
|
||||
prevTxs: Vector[TransactionDb]): Vector[DLCFundingInput] = {
|
||||
inputs.sortBy(_.index).map { i =>
|
||||
prevTxs.find(_.txId == i.outPoint.txId) match {
|
||||
case Some(txDb) => i.toFundingInput(txDb.transaction)
|
||||
case None =>
|
||||
throw new NoSuchElementException(
|
||||
s"Could not find previous transaction with txIdBE=${i.outPoint.txId.flip.hex}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue