2022 01 31 issue 4030 (#4066)

* WIP

* WIP

* Get basic unit test passing for new adaptor sig states

* Fix compile
This commit is contained in:
Chris Stewart 2022-02-09 13:15:44 -06:00 committed by GitHub
parent f253b5055e
commit 9de4b0272a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 267 additions and 44 deletions

View file

@ -819,6 +819,28 @@ object Picklers {
)
}
implicit val acceptedComputingAdaptorSigsW: Writer[
AcceptedComputingAdaptorSigs] = writer[Obj].comap { accepted =>
import accepted._
Obj(
"state" -> Str(statusString),
"dlcId" -> Str(dlcId.hex),
"isInitiator" -> Bool(isInitiator),
"lastUpdated" -> Str(iso8601ToString(lastUpdated)),
"tempContractId" -> Str(tempContractId.hex),
"contractId" -> Str(contractId.toHex),
"contractInfo" -> Str(contractInfo.hex),
"contractMaturity" -> Num(
timeouts.contractMaturity.toUInt32.toLong.toDouble),
"contractTimeout" -> Num(
timeouts.contractTimeout.toUInt32.toLong.toDouble),
"feeRate" -> Num(feeRate.toLong.toDouble),
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
"remoteCollateral" -> Num(remoteCollateral.satoshis.toLong.toDouble)
)
}
implicit val acceptedW: Writer[Accepted] = writer[Obj].comap { accepted =>
import accepted._
Obj(
@ -840,6 +862,29 @@ object Picklers {
)
}
implicit val signedComputingAdaptorSigsW: Writer[SignedComputingAdaptorSigs] =
writer[Obj].comap { signed =>
import signed._
Obj(
"state" -> Str(statusString),
"dlcId" -> Str(dlcId.hex),
"isInitiator" -> Bool(isInitiator),
"lastUpdated" -> Str(iso8601ToString(lastUpdated)),
"tempContractId" -> Str(tempContractId.hex),
"contractId" -> Str(contractId.toHex),
"contractInfo" -> Str(contractInfo.hex),
"contractMaturity" -> Num(
timeouts.contractMaturity.toUInt32.toLong.toDouble),
"contractTimeout" -> Num(
timeouts.contractTimeout.toUInt32.toLong.toDouble),
"feeRate" -> Num(feeRate.toLong.toDouble),
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
"remoteCollateral" -> Num(remoteCollateral.satoshis.toLong.toDouble),
"fundingTxId" -> Str(fundingTxId.hex)
)
}
implicit val signedW: Writer[Signed] = writer[Obj].comap { signed =>
import signed._
Obj(
@ -1023,8 +1068,12 @@ object Picklers {
implicit val dlcStatusW: Writer[DLCStatus] = writer[Value].comap {
case o: Offered =>
writeJs(o)(offeredW)
case a: AcceptedComputingAdaptorSigs =>
writeJs(a)(acceptedComputingAdaptorSigsW)
case a: Accepted =>
writeJs(a)(acceptedW)
case s: SignedComputingAdaptorSigs =>
writeJs(s)(signedComputingAdaptorSigsW)
case s: Signed =>
writeJs(s)(signedW)
case b: Broadcasted =>
@ -1110,6 +1159,19 @@ object Picklers {
totalCollateral,
localCollateral
)
case DLCState.AcceptComputingAdaptorSigs =>
AcceptedComputingAdaptorSigs(
dlcId,
isInitiator,
lastUpdated,
tempContractId,
contractId,
ContractInfo.fromTLV(contractInfoTLV),
DLCTimeouts(contractMaturity, contractTimeout),
feeRate,
totalCollateral,
localCollateral
)
case DLCState.Accepted =>
Accepted(
dlcId,
@ -1123,6 +1185,20 @@ object Picklers {
totalCollateral,
localCollateral
)
case DLCState.SignComputingAdaptorSigs =>
SignedComputingAdaptorSigs(
dlcId,
isInitiator,
lastUpdated,
tempContractId,
contractId,
ContractInfo.fromTLV(contractInfoTLV),
DLCTimeouts(contractMaturity, contractTimeout),
feeRate,
totalCollateral,
localCollateral,
fundingTxId
)
case DLCState.Signed =>
Signed(
dlcId,

View file

@ -245,7 +245,9 @@ class DLCPaneModel(pane: DLCPane)(implicit ec: ExecutionContext)
val eventId = status.eventIds.head
val confirmed = status.state match {
case DLCState.Offered | DLCState.Accepted =>
case DLCState.Offered | DLCState.Accepted |
DLCState.AcceptComputingAdaptorSigs |
DLCState.SignComputingAdaptorSigs =>
new Alert(AlertType.Confirmation) {
initOwner(owner)
headerText = "Confirm Canceling DLC"

View file

@ -218,7 +218,9 @@ class DLCTableView(model: DLCPaneModel) {
row.item.onChange { (_, _, newContent) =>
if (newContent != null) {
cancelDLCItem.disable = row.item.value.state match {
case DLCState.Offered | DLCState.Accepted | DLCState.Signed =>
case DLCState.Offered | DLCState.Accepted | DLCState.Signed |
DLCState.AcceptComputingAdaptorSigs |
DLCState.SignComputingAdaptorSigs =>
false
case DLCState.Confirmed | DLCState.Broadcasted |
DLCState.Claimed | DLCState.Refunded |
@ -230,7 +232,9 @@ class DLCTableView(model: DLCPaneModel) {
false
case DLCState.Offered | DLCState.Accepted | DLCState.Signed |
DLCState.Claimed | DLCState.Refunded |
DLCState.RemoteClaimed =>
DLCState.RemoteClaimed |
DLCState.AcceptComputingAdaptorSigs |
DLCState.SignComputingAdaptorSigs =>
true
}
refundDLCItem.disable = disableRefundExecute

View file

@ -13,6 +13,12 @@ object DLCState extends StringFactory[DLCState] {
/** Means that someone has attempted to claim the DLC */
sealed abstract class ClosedState extends DLCState
/** A state meant to represent we are computing adaptor sigs.
* Computing adaptor signatures can take awhile on certain hardware
* (raspberry pi) which is why we model this state
*/
sealed abstract class AdaptorSigComputationState extends InProgressState
/** A state that requires an oracle outcome to be valid */
sealed trait ClosedViaOracleOutcomeState extends ClosedState
@ -20,14 +26,22 @@ object DLCState extends StringFactory[DLCState] {
* accept message has yet been created/received.
*/
final case object Offered extends InProgressState {
val order: Int = 0
override val order: Int = 0
}
case object AcceptComputingAdaptorSigs extends AdaptorSigComputationState {
override val order: Int = 1
}
/** The state where an offer has been accepted but
* no sign message has yet been created/received.
*/
final case object Accepted extends InProgressState {
val order: Int = 1
override val order: Int = 2
}
case object SignComputingAdaptorSigs extends AdaptorSigComputationState {
override val order: Int = 3
}
/** The state where the initiating party has created
@ -36,7 +50,7 @@ object DLCState extends StringFactory[DLCState] {
* broadcasted to the network.
*/
final case object Signed extends InProgressState {
val order: Int = 2
override val order: Int = 4
}
/** The state where the accepting (non-initiating)
@ -44,7 +58,7 @@ object DLCState extends StringFactory[DLCState] {
* to the blockchain, and it has not yet been confirmed.
*/
final case object Broadcasted extends InProgressState {
val order: Int = 3
override val order: Int = 5
}
/** The state where the DLC funding transaction has been
@ -52,32 +66,34 @@ object DLCState extends StringFactory[DLCState] {
* initiated.
*/
final case object Confirmed extends InProgressState {
val order: Int = 4
override val order: Int = 6
}
/** The state where one of the CETs has been accepted by the network
* and executed by ourselves.
*/
final case object Claimed extends ClosedViaOracleOutcomeState {
val order: Int = 4
override val order: Int = 7
}
/** The state where one of the CETs has been accepted by the network
* and executed by a remote party.
*/
final case object RemoteClaimed extends ClosedViaOracleOutcomeState {
val order: Int = 5
override val order: Int = 7
}
/** The state where the DLC refund transaction has been
* accepted by the network.
*/
final case object Refunded extends ClosedState {
val order: Int = 6
val order: Int = 7
}
val all: Vector[DLCState] = Vector(Offered,
AcceptComputingAdaptorSigs,
Accepted,
SignComputingAdaptorSigs,
Signed,
Broadcasted,
Confirmed,
@ -85,7 +101,7 @@ object DLCState extends StringFactory[DLCState] {
RemoteClaimed,
Refunded)
def fromString(str: String): DLCState = {
override def fromString(str: String): DLCState = {
all.find(state => str.toLowerCase() == state.toString.toLowerCase) match {
case Some(state) => state
case None =>

View file

@ -92,6 +92,23 @@ object DLCStatus {
override val state: DLCState.Offered.type = DLCState.Offered
}
case class AcceptedComputingAdaptorSigs(
dlcId: Sha256Digest,
isInitiator: Boolean,
lastUpdated: Instant,
tempContractId: Sha256Digest,
contractId: ByteVector,
contractInfo: ContractInfo,
timeouts: DLCTimeouts,
feeRate: FeeUnit,
totalCollateral: CurrencyUnit,
localCollateral: CurrencyUnit)
extends AcceptedDLCStatus {
override val state: DLCState.AcceptComputingAdaptorSigs.type =
DLCState.AcceptComputingAdaptorSigs
}
case class Accepted(
dlcId: Sha256Digest,
isInitiator: Boolean,
@ -107,6 +124,24 @@ object DLCStatus {
override val state: DLCState.Accepted.type = DLCState.Accepted
}
case class SignedComputingAdaptorSigs(
dlcId: Sha256Digest,
isInitiator: Boolean,
lastUpdated: Instant,
tempContractId: Sha256Digest,
contractId: ByteVector,
contractInfo: ContractInfo,
timeouts: DLCTimeouts,
feeRate: FeeUnit,
totalCollateral: CurrencyUnit,
localCollateral: CurrencyUnit,
fundingTxId: DoubleSha256DigestBE)
extends SignedDLCStatus {
override val state: DLCState.SignComputingAdaptorSigs.type =
DLCState.SignComputingAdaptorSigs
}
case class Signed(
dlcId: Sha256Digest,
isInitiator: Boolean,
@ -230,7 +265,8 @@ object DLCStatus {
status match {
case status: SignedDLCStatus =>
Some(status.fundingTxId)
case _: Offered | _: Accepted | _: Signed =>
case _: Offered | _: Accepted | _: Signed |
_: AcceptedComputingAdaptorSigs =>
None
}
}
@ -249,7 +285,8 @@ object DLCStatus {
status match {
case claimed: ClaimedDLCStatus =>
Some(claimed.oracleSigs)
case _: Offered | _: Accepted | _: SignedDLCStatus | _: Refunded =>
case _: Offered | _: Accepted | _: AcceptedComputingAdaptorSigs |
_: SignedDLCStatus | _: Refunded =>
None
}
}

View file

@ -26,7 +26,9 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest {
val walletA: DLCWallet = wallets._1.wallet
val walletB: DLCWallet = wallets._2.wallet
val offerP: Promise[DLCStatus] = Promise()
val acceptedSignComputingAdaptorSigsP: Promise[DLCStatus] = Promise()
val acceptP: Promise[DLCStatus] = Promise()
val signedComputingAdaptorSigsP: Promise[DLCStatus] = Promise()
val signedP: Promise[DLCStatus] = Promise()
val broadcastP: Promise[DLCStatus] = Promise()
@ -39,6 +41,8 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest {
status.state match {
case DLCState.Offered =>
Future.successful(offerP.success(status))
case DLCState.SignComputingAdaptorSigs =>
Future.successful(signedComputingAdaptorSigsP.success(status))
case DLCState.Signed =>
Future.successful(signedP.success(status))
case DLCState.Confirmed =>
@ -48,8 +52,8 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest {
case DLCState.Broadcasted =>
//ignore broadcast from this wallet
Future.unit
case x @ (DLCState.Accepted | DLCState.RemoteClaimed |
DLCState.Refunded) =>
case x @ (DLCState.Accepted | DLCState.AcceptComputingAdaptorSigs |
DLCState.RemoteClaimed | DLCState.Refunded) =>
sys.error(s"Shouldn't receive state=$x for callback")
}
@ -57,19 +61,21 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest {
val walletBCallback: OnDLCStateChange = { case status: DLCStatus =>
status.state match {
case DLCState.AcceptComputingAdaptorSigs =>
Future.successful(acceptedSignComputingAdaptorSigsP.success(status))
case DLCState.Accepted =>
Future.successful(acceptP.success(status))
case DLCState.Broadcasted =>
Future.successful(broadcastP.success(status))
case DLCState.RemoteClaimed =>
Future.successful(remoteClaimedP.success(status))
case x @ (DLCState.Offered | DLCState.Signed) =>
case x @ (DLCState.Offered | DLCState.Signed |
DLCState.SignComputingAdaptorSigs) =>
sys.error(s"Shouldn't receive state=$x for callback")
case DLCState.Confirmed | DLCState.Claimed | DLCState.Refunded =>
//do nothing, we are doing assertions for these on walletACallback
Future.unit
}
}
val walletACallbacks = DLCWalletCallbacks.onDLCStateChange(walletACallback)
@ -107,7 +113,9 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest {
for {
_ <- initF
offer <- offerP.future
acceptedComputingAdaptorSigs <- acceptedSignComputingAdaptorSigsP.future
accept <- acceptP.future
signComputingAdaptorSigs <- signedComputingAdaptorSigsP.future
sign <- signedP.future
broadcast <- broadcastP.future
_ <- executeF
@ -116,7 +124,11 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest {
remoteClaimed <- remoteClaimedP.future
} yield {
assert(offer.state == DLCState.Offered)
assert(
acceptedComputingAdaptorSigs.state == DLCState.AcceptComputingAdaptorSigs)
assert(accept.state == DLCState.Accepted)
assert(
signComputingAdaptorSigs.state == DLCState.SignComputingAdaptorSigs)
assert(sign.state == DLCState.Signed)
assert(broadcast.state == DLCState.Broadcasted)
assert(confirmed.state == DLCState.Confirmed)
@ -129,7 +141,9 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest {
val walletA: DLCWallet = wallets._1.wallet
val walletB: DLCWallet = wallets._2.wallet
val offerP: Promise[DLCStatus] = Promise()
val acceptedComputingAdaptorSigsP: Promise[DLCStatus] = Promise()
val acceptP: Promise[DLCStatus] = Promise()
val signedComputingAdaptorSigsP: Promise[DLCStatus] = Promise()
val signedP: Promise[DLCStatus] = Promise()
val broadcastP: Promise[DLCStatus] = Promise()
val refundedP: Promise[DLCStatus] = Promise()
@ -138,6 +152,8 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest {
status.state match {
case DLCState.Offered =>
Future.successful(offerP.success(status))
case DLCState.SignComputingAdaptorSigs =>
Future.successful(signedComputingAdaptorSigsP.success(status))
case DLCState.Signed =>
Future.successful(signedP.success(status))
case DLCState.Broadcasted | DLCState.Confirmed =>
@ -145,8 +161,8 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest {
Future.unit
case DLCState.Refunded =>
Future.successful(refundedP.success(status))
case x @ (DLCState.Claimed | DLCState.Accepted |
DLCState.RemoteClaimed | DLCState.Refunded) =>
case x @ (DLCState.Claimed | DLCState.AcceptComputingAdaptorSigs |
DLCState.Accepted | DLCState.RemoteClaimed | DLCState.Refunded) =>
sys.error(s"Shouldn't receive state=$x for callback")
}
@ -154,11 +170,14 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest {
val walletBCallback: OnDLCStateChange = { case status: DLCStatus =>
status.state match {
case DLCState.AcceptComputingAdaptorSigs =>
Future.successful(acceptedComputingAdaptorSigsP.success(status))
case DLCState.Accepted =>
Future.successful(acceptP.success(status))
case DLCState.Broadcasted =>
Future.successful(broadcastP.success(status))
case x @ (DLCState.Refunded | DLCState.Offered | DLCState.Signed) =>
case x @ (DLCState.Refunded | DLCState.Offered |
DLCState.SignComputingAdaptorSigs | DLCState.Signed) =>
sys.error(s"Shouldn't receive state=$x for callback")
case DLCState.Confirmed | DLCState.Claimed | DLCState.RemoteClaimed =>
//do nothing, we are doing assertions for these on walletACallback

View file

@ -435,19 +435,25 @@ abstract class DLCWallet
/** Retrieves the [[DLCDb]] and [[AccountDb]] for the given tempContractId
* else returns None
*/
private def getDlcDbOfferDb(
tempContractId: Sha256Digest): Future[Option[(DLCDb, DLCOfferDb)]] = {
val result: Future[Option[(DLCDb, DLCOfferDb)]] = for {
private def getDlcDbOfferDbContractDataDb(
tempContractId: Sha256Digest): Future[
Option[(DLCDb, DLCOfferDb, DLCContractDataDb)]] = {
val result: Future[Option[(DLCDb, DLCOfferDb, DLCContractDataDb)]] = for {
dlcDbOpt <- dlcDAO.findByTempContractId(tempContractId)
dlcOfferDbOpt <- dlcDbOpt match {
case Some(dlcDb) => dlcOfferDAO.findByDLCId(dlcDb.dlcId)
case None => Future.successful(None)
}
contractDataDbOpt <- dlcDbOpt match {
case Some(dlcDb) => contractDataDAO.findByDLCId(dlcDb.dlcId)
case None => Future.successful(None)
}
} yield {
for {
dlcDb <- dlcDbOpt
dlcOfferDb <- dlcOfferDbOpt
} yield (dlcDb, dlcOfferDb)
contractDataDb <- contractDataDbOpt
} yield (dlcDb, dlcOfferDb, contractDataDb)
}
result
@ -455,7 +461,7 @@ abstract class DLCWallet
private def initDLCForAccept(
offer: DLCOffer,
account: AccountDb): Future[(DLCDb, DLCOfferDb)] = {
account: AccountDb): Future[(DLCDb, DLCOfferDb, DLCContractDataDb)] = {
logger.info(
s"Initializing DLC from received offer with tempContractId ${offer.tempContractId.hex}")
val dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint))
@ -472,9 +478,9 @@ abstract class DLCWallet
groupByExistingAnnouncements(announcements)
}
getDlcDbOfferDb(offer.tempContractId).flatMap {
case Some((dlcDb, dlcOffer)) =>
Future.successful((dlcDb, dlcOffer))
getDlcDbOfferDbContractDataDb(offer.tempContractId).flatMap {
case Some((dlcDb, dlcOffer, contractDataDb)) =>
Future.successful((dlcDb, dlcOffer, contractDataDb))
case None =>
for {
nextIndex <- getNextAvailableIndex(account, chainType)
@ -500,11 +506,12 @@ abstract class DLCWallet
dlcDb <- dlcDbAction
ann <- createdAnnouncementsAction
//we don't need the contract data db, so don't return it
_ <- contractAction
contractDataDb <- contractAction
offer <- dlcOfferAction
} yield (dlcDb, ann, offer)
} yield (dlcDb, ann, offer, contractDataDb)
}
(writtenDLC, createdDbs, offerDb) <- safeDatabase.run(zipped)
(writtenDLC, createdDbs, offerDb, contractDataDb) <- safeDatabase.run(
zipped)
announcementDataDbs =
createdDbs ++ groupedAnnouncements.existingAnnouncements
@ -534,7 +541,7 @@ abstract class DLCWallet
_ <- safeDatabase.run(
DBIOAction.seq(createNonceAction, createAnnouncementAction))
} yield (writtenDLC, offerDb)
} yield (writtenDLC, offerDb, contractDataDb)
}
}
@ -599,16 +606,16 @@ abstract class DLCWallet
val accountF = getDefaultAccountForType(AddressType.SegWit)
val dlcDbOfferDbF: Future[(DLCDb, DLCOfferDb)] = {
val dlcDbOfferDbF: Future[(DLCDb, DLCOfferDb, DLCContractDataDb)] = {
for {
accountDb <- accountF
(dlcDb, offerDb) <- initDLCForAccept(offer, accountDb)
} yield (dlcDb, offerDb)
(dlcDb, offerDb, contractDataDb) <- initDLCForAccept(offer, accountDb)
} yield (dlcDb, offerDb, contractDataDb)
}
val fundingPrivKeyF: Future[AdaptorSign] = {
for {
(dlc, _) <- dlcDbOfferDbF
(dlc, _, _) <- dlcDbOfferDbF
account <- accountF
bip32Path = BIP32Path(
account.hdAccount.path ++ Vector(BIP32Node(0, hardened = false),
@ -619,7 +626,7 @@ abstract class DLCWallet
}
for {
(dlc, _) <- dlcDbOfferDbF
(dlc, offerDb, contractDataDb) <- dlcDbOfferDbF
account <- accountF
(txBuilder, spendingInfos) <- fundDLCAcceptMsg(offer = offer,
collateral = collateral,
@ -639,6 +646,8 @@ abstract class DLCWallet
contractId = builder.calcContractId
dlcDbWithContractId = dlc.copy(contractIdOpt = Some(contractId))
signer = DLCTxSigner(builder = builder,
isInitiator = false,
fundingKey = fundingPrivKey,
@ -652,8 +661,14 @@ abstract class DLCWallet
case Some(_) => Future.unit
case None => scriptPubKeyDAO.create(spkDb)
}
_ = logger.info(s"Creating CET Sigs for ${contractId.toHex}")
//emit websocket event that we are now computing adaptor signatures
status = DLCStatusBuilder.buildInProgressDLCStatus(
dlcDb = dlcDbWithContractId,
contractInfo = offer.contractInfo,
contractData = contractDataDb,
offerDb = offerDb)
_ = dlcConfig.walletCallbacks.executeOnDLCStateChange(logger, status)
cetSigs <- signer.createCETSigsAsync()
refundSig = signer.signRefundTx
_ = logger.debug(
@ -726,11 +741,13 @@ abstract class DLCWallet
_ <- remoteTxDAO.upsertAll(offerPrevTxs)
actions = actionBuilder.buildCreateAcceptAction(
dlcDb = dlcDbWithContractId.updateState(DLCState.Accepted),
dlcAcceptDb = dlcAcceptDb,
offerInputs = offerInputs,
acceptInputs = acceptInputs,
cetSigsDb = sigsDbs,
refundSigsDb = refundSigsDb)
refundSigsDb = refundSigsDb
)
_ <- safeDatabase.run(actions)
dlcDb <- updateDLCContractIds(offer, accept)
_ = logger.info(
@ -918,6 +935,7 @@ abstract class DLCWallet
signerOpt match {
case Some(signer) =>
val cetSigsF = getCetSigs(signer = signer,
dlcDb = dlc,
contractId = contractId,
cetSigsDbs = cetSigsDbs,
mySigs = mySigs)
@ -972,12 +990,20 @@ abstract class DLCWallet
private def getCetSigs(
signer: DLCTxSigner,
dlcDb: DLCDb,
contractId: ByteVector,
cetSigsDbs: Vector[DLCCETSignaturesDb],
mySigs: Vector[DLCCETSignaturesDb]): Future[CETSignatures] = {
if (mySigs.forall(_.initiatorSig.isEmpty)) {
logger.info(s"Creating CET Sigs for contract ${contractId.toHex}")
val dlcDbSignComputingAdaptorSigs =
dlcDb.updateState(DLCState.SignComputingAdaptorSigs)
val updatedF = dlcDAO.update(dlcDbSignComputingAdaptorSigs)
for {
_ <- updatedF
status <- findDLC(dlcDb.dlcId)
_ <- dlcConfig.walletCallbacks.executeOnDLCStateChange(logger,
status.get)
sigs <- signer.createCETSigsAsync()
sigsDbs: Vector[DLCCETSignaturesDb] = sigs.outcomeSigs
@ -1145,6 +1171,10 @@ abstract class DLCWallet
Future.failed(
new RuntimeException(
"Cannot add sigs to a DLC before it has been accepted"))
case _: AdaptorSigComputationState =>
val err = new RuntimeException(
s"Cannot add sigs to a DLC while adaptor sigs are being computed, contractId=${sign.contractId.toHex}")
Future.failed(err)
case Accepted =>
logger.info(
s"Verifying CET Signatures for contract ${sign.contractId.toHex}")
@ -1304,7 +1334,8 @@ abstract class DLCWallet
dlcDb.state match {
case DLCState.Broadcasted | DLCState.Signed => dlcDb
case state @ (DLCState.Offered | DLCState.Confirmed | DLCState.Accepted |
DLCState.Claimed | DLCState.RemoteClaimed | DLCState.Refunded) =>
DLCState.Claimed | DLCState.RemoteClaimed | DLCState.Refunded |
_: DLCState.AdaptorSigComputationState) =>
sys.error(
s"Cannot broadcast the dlc when it is in the state=${state} contractId=${dlcDb.contractIdOpt}")
}

View file

@ -114,7 +114,8 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing {
.deleteByDLCId(updated.dlcId)
.map(_ => ())
case DLCState.Offered | DLCState.Accepted | DLCState.Signed |
DLCState.Broadcasted | DLCState.Confirmed =>
DLCState.Broadcasted | DLCState.Confirmed |
_: DLCState.AdaptorSigComputationState =>
FutureUtil.unit
}
}
@ -255,6 +256,10 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing {
if (blockHashOpt.isDefined)
dlcDb.updateState(DLCState.Confirmed)
else dlcDb.copy(state = DLCState.Broadcasted)
case _: DLCState.AdaptorSigComputationState =>
val contractIdOpt = dlcDb.contractIdOpt.map(_.toHex)
throw new IllegalStateException(
s"Cannot be settling a DLC when we are computing adaptor sigs! contractId=${contractIdOpt}")
case DLCState.Confirmed | DLCState.Claimed |
DLCState.RemoteClaimed | DLCState.Refunded =>
dlcDb

View file

@ -108,7 +108,7 @@ object DLCAcceptUtil extends Logging {
tempContractId = offer.tempContractId,
contractIdOpt = None,
protocolVersion = 0,
state = DLCState.Accepted,
state = DLCState.AcceptComputingAdaptorSigs,
isInitiator = false,
account = account.hdAccount,
changeIndex = chainType,

View file

@ -55,6 +55,7 @@ case class DLCActionBuilder(dlcWalletDAOs: DLCWalletDAOs) {
* offer table, accept table, cet sigs table, inputs table, and refund table
*/
def buildCreateAcceptAction(
dlcDb: DLCDb,
dlcAcceptDb: DLCAcceptDb,
offerInputs: Vector[DLCFundingInputDb],
acceptInputs: Vector[DLCFundingInputDb],
@ -63,11 +64,16 @@ case class DLCActionBuilder(dlcWalletDAOs: DLCWalletDAOs) {
Unit,
NoStream,
Effect.Write with Effect.Transactional] = {
val dlcDbAction = dlcDAO.updateAction(dlcDb)
val inputAction = dlcInputsDAO.createAllAction(offerInputs ++ acceptInputs)
val acceptAction = dlcAcceptDAO.createAction(dlcAcceptDb)
val sigsAction = dlcSigsDAO.createAllAction(cetSigsDb)
val refundSigAction = dlcRefundSigDAO.createAction(refundSigsDb)
val actions = Vector(inputAction, acceptAction, sigsAction, refundSigAction)
val actions = Vector(dlcDbAction,
inputAction,
acceptAction,
sigsAction,
refundSigAction)
val allActions = DBIO
.sequence(actions)

View file

@ -45,6 +45,19 @@ object DLCStatusBuilder {
totalCollateral,
localCollateral
)
case DLCState.AcceptComputingAdaptorSigs =>
AcceptedComputingAdaptorSigs(
dlcId = dlcId,
isInitiator = dlcDb.isInitiator,
lastUpdated = dlcDb.lastUpdated,
tempContractId = dlcDb.tempContractId,
contractId = dlcDb.contractIdOpt.get,
contractInfo = contractInfo,
timeouts = contractData.dlcTimeouts,
feeRate = dlcDb.feeRate,
totalCollateral = totalCollateral,
localCollateral = localCollateral
)
case DLCState.Accepted =>
Accepted(
dlcId,
@ -58,6 +71,20 @@ object DLCStatusBuilder {
totalCollateral,
localCollateral
)
case DLCState.SignComputingAdaptorSigs =>
SignedComputingAdaptorSigs(
dlcId = dlcId,
isInitiator = dlcDb.isInitiator,
lastUpdated = dlcDb.lastUpdated,
tempContractId = dlcDb.tempContractId,
contractId = dlcDb.contractIdOpt.get,
contractInfo = contractInfo,
timeouts = contractData.dlcTimeouts,
feeRate = dlcDb.feeRate,
totalCollateral = totalCollateral,
localCollateral = localCollateral,
dlcDb.fundingTxIdOpt.get
)
case DLCState.Signed =>
Signed(
dlcId,