populate dlc/contact mapping automatically

This commit is contained in:
rorp 2022-05-25 11:23:47 -07:00
parent fdfe96ed65
commit f77ad289b2
15 changed files with 216 additions and 68 deletions

View file

@ -44,6 +44,7 @@ import org.scalatest.wordspec.AnyWordSpec
import scodec.bits.ByteVector
import ujson._
import java.net.InetSocketAddress
import java.time.{ZoneId, ZonedDateTime}
import scala.collection.mutable
import scala.concurrent.duration.DurationInt
@ -989,6 +990,7 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
_: Option[SatoshisPerVirtualByte],
_: UInt32,
_: UInt32,
_: Option[InetSocketAddress],
_: Option[BitcoinAddress],
_: Option[BitcoinAddress]
)
@ -1000,6 +1002,7 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
UInt32(contractMaturity),
UInt32(contractTimeout),
None,
None,
None
)
.returning(Future.successful(offer))
@ -1059,9 +1062,10 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
"accept a dlc offer" in {
(mockWalletApi
.acceptDLCOffer(_: DLCOfferTLV,
_: Option[InetSocketAddress],
_: Option[BitcoinAddress],
_: Option[BitcoinAddress]))
.expects(offer.toTLV, None, None)
.expects(offer.toTLV, None, None, None)
.returning(Future.successful(accept))
val route = walletRoutes.handleCommand(

View file

@ -15,11 +15,9 @@ import org.bitcoins.core.protocol.tlv._
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionOutPoint}
import org.bitcoins.core.protocol.{BitcoinAddress, BlockStamp}
import org.bitcoins.core.psbt.PSBT
import org.bitcoins.core.util.NetworkUtil
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
import org.bitcoins.core.wallet.utxo.AddressLabelTag
import org.bitcoins.crypto._
import org.bitcoins.server.GetDLC.nullToOpt
import scodec.bits.ByteVector
import ujson._
@ -658,10 +656,7 @@ object GetDLCs extends ServerJsonModels {
jsArr.arr.toList match {
case addressJs :: Nil =>
Try {
val address = {
val uri = new URI(s"tcp://${addressJs.str}")
InetSocketAddress.createUnresolved(uri.getHost, uri.getPort)
}
val address = jsToInetSocketAddress(addressJs)
GetDLCs(Some(address))
}
case Nil =>
@ -702,7 +697,8 @@ case class CreateDLCOffer(
locktimeOpt: Option[UInt32],
refundLocktime: UInt32,
externalPayoutAddressOpt: Option[BitcoinAddress],
externalChangeAddressOpt: Option[BitcoinAddress])
externalChangeAddressOpt: Option[BitcoinAddress],
peerAddressOpt: Option[InetSocketAddress])
object CreateDLCOffer extends ServerJsonModels {
@ -715,7 +711,8 @@ object CreateDLCOffer extends ServerJsonModels {
locktimeJs: Value,
refundLTJs: Value,
payoutAddressJs: Value,
changeAddressJs: Value) = Try {
changeAddressJs: Value,
peerAddressJs: Value) = Try {
val contractInfoTLV = jsToContractInfoTLV(contractInfoJs)
val collateral = jsToSatoshis(collateralJs)
val feeRate = jsToSatoshisPerVirtualByteOpt(feeRateOptJs)
@ -728,13 +725,17 @@ object CreateDLCOffer extends ServerJsonModels {
val changeAddressJsOpt = nullToOpt(changeAddressJs)
val changeAddressOpt =
changeAddressJsOpt.map(js => jsToBitcoinAddress(js))
val peerAddressJsOpt = nullToOpt(peerAddressJs)
val peerAddressOpt = peerAddressJsOpt.map(js => jsToInetSocketAddress(js))
CreateDLCOffer(contractInfoTLV,
collateral,
feeRate,
locktimeOpt,
refundLT,
payoutAddressOpt,
changeAddressOpt)
changeAddressOpt,
peerAddressOpt)
}
jsArr.arr.toList match {
@ -745,6 +746,7 @@ object CreateDLCOffer extends ServerJsonModels {
locktimeJs,
refundLTJs,
Null,
Null,
Null)
case contractInfoJs :: collateralJs :: feeRateOptJs :: locktimeJs :: refundLTJs :: payoutAddressJs :: Nil =>
parseParameters(contractInfoJs,
@ -753,6 +755,7 @@ object CreateDLCOffer extends ServerJsonModels {
locktimeJs,
refundLTJs,
payoutAddressJs,
Null,
Null)
case contractInfoJs :: collateralJs :: feeRateOptJs :: locktimeJs :: refundLTJs :: payoutAddressJs :: changeAddressJs :: Nil =>
parseParameters(contractInfoJs,
@ -761,7 +764,17 @@ object CreateDLCOffer extends ServerJsonModels {
locktimeJs,
refundLTJs,
payoutAddressJs,
changeAddressJs)
changeAddressJs,
Null)
case contractInfoJs :: collateralJs :: feeRateOptJs :: locktimeJs :: refundLTJs :: payoutAddressJs :: changeAddressJs :: peerAddressJs :: Nil =>
parseParameters(contractInfoJs,
collateralJs,
feeRateOptJs,
locktimeJs,
refundLTJs,
payoutAddressJs,
changeAddressJs,
peerAddressJs)
case other =>
Failure(
new IllegalArgumentException(
@ -929,7 +942,8 @@ object DecodeAttestations extends ServerJsonModels {
case class AcceptDLCOffer(
offer: LnMessage[DLCOfferTLV],
externalPayoutAddressOpt: Option[BitcoinAddress],
externalChangeAddressOpt: Option[BitcoinAddress])
externalChangeAddressOpt: Option[BitcoinAddress],
peerAddress: Option[InetSocketAddress])
object AcceptDLCOffer extends ServerJsonModels {
@ -937,7 +951,8 @@ object AcceptDLCOffer extends ServerJsonModels {
def parseParameters(
offerJs: Value,
payoutAddressJs: Value,
changeAddressJs: Value) = Try {
changeAddressJs: Value,
peerAddressJs: Value) = Try {
val offer = LnMessageFactory(DLCOfferTLV).fromHex(offerJs.str)
val payoutAddressJsOpt = nullToOpt(payoutAddressJs)
val payoutAddressOpt =
@ -945,16 +960,23 @@ object AcceptDLCOffer extends ServerJsonModels {
val changeAddressJsOpt = nullToOpt(changeAddressJs)
val changeAddressOpt =
changeAddressJsOpt.map(js => jsToBitcoinAddress(js))
AcceptDLCOffer(offer, payoutAddressOpt, changeAddressOpt)
val peerAddressJsOpt = nullToOpt(peerAddressJs)
val peerAddress = peerAddressJsOpt.map(js => jsToInetSocketAddress(js))
AcceptDLCOffer(offer, payoutAddressOpt, changeAddressOpt, peerAddress)
}
jsArr.arr.toList match {
case offerJs :: Nil =>
parseParameters(offerJs, Null, Null)
parseParameters(offerJs, Null, Null, Null)
case offerJs :: payoutAddressJs :: Nil =>
parseParameters(offerJs, payoutAddressJs, Null)
parseParameters(offerJs, payoutAddressJs, Null, Null)
case offerJs :: payoutAddressJs :: changeAddressJs :: Nil =>
parseParameters(offerJs, payoutAddressJs, changeAddressJs)
parseParameters(offerJs, payoutAddressJs, changeAddressJs, Null)
case offerJs :: payoutAddressJs :: changeAddressJs :: peerAddressJs :: Nil =>
parseParameters(offerJs,
payoutAddressJs,
changeAddressJs,
peerAddressJs)
case Nil =>
Failure(new IllegalArgumentException("Missing offer argument"))
@ -987,9 +1009,7 @@ object AcceptDLC extends ServerJsonModels {
case Failure(_) => LnMessage(DLCOfferTLV.fromHex(offerJs.str))
}
val uri = new URI("tcp://" + addrJs.str)
val peerAddr =
InetSocketAddress.createUnresolved(uri.getHost, uri.getPort)
val peerAddr = jsToInetSocketAddress(addrJs)
val payoutAddressJsOpt = nullToOpt(payoutAddressJs)
val payoutAddressOpt =
payoutAddressJsOpt.map(js => jsToBitcoinAddress(js))
@ -1415,7 +1435,7 @@ case class OfferAdd(
peer: Option[String],
message: Option[String])
object OfferAdd {
object OfferAdd extends ServerJsonModels {
def fromJsArr(arr: ujson.Arr): Try[OfferAdd] = {
arr.arr.toList match {
@ -1459,14 +1479,13 @@ case class OfferSend(
message: String,
offerE: Either[DLCOfferTLV, Sha256Digest])
object OfferSend {
object OfferSend extends ServerJsonModels {
def fromJsArr(arr: ujson.Arr): Try[OfferSend] = {
arr.arr.toList match {
case offerJs :: peerAddressJs :: messageJs :: Nil =>
Try {
val peerAddress =
NetworkUtil.parseInetSocketAddress(peerAddressJs.str, 2862)
val peerAddress = jsToInetSocketAddress(peerAddressJs, 2862)
val message = messageJs.str
val offerE =
Try(LnMessageFactory(DLCOfferTLV).fromHex(offerJs.str).tlv)
@ -1622,4 +1641,17 @@ trait ServerJsonModels {
js.arr.foldLeft(Vector.empty[OracleAttestmentTLV])((vec, tlv) =>
vec :+ jsToOracleAttestmentTLV(tlv))
}
def jsToInetSocketAddress(
js: Value,
defaultPort: Int = -1): InetSocketAddress = {
js match {
case str: Str =>
val uri = new URI("tcp://" + str.str)
val port = if (uri.getPort >= 0) uri.getPort else defaultPort
InetSocketAddress.createUnresolved(uri.getHost, port)
case _: Value =>
throw Value.InvalidData(js, "Expected a host address")
}
}
}

View file

@ -355,7 +355,8 @@ case class WalletRoutes(wallet: AnyDLCHDWalletApi)(implicit
locktimeOpt,
refundLT,
payoutAddressOpt,
changeAddressOpt)) =>
changeAddressOpt,
peerAddressOpt)) =>
complete {
val announcements = contractInfo.oracleInfo match {
case OracleInfoV0TLV(announcement) => Vector(announcement)
@ -376,6 +377,7 @@ case class WalletRoutes(wallet: AnyDLCHDWalletApi)(implicit
feeRateOpt,
locktime,
refundLT,
peerAddressOpt,
payoutAddressOpt,
changeAddressOpt)
case None =>
@ -384,6 +386,7 @@ case class WalletRoutes(wallet: AnyDLCHDWalletApi)(implicit
collateral,
feeRateOpt,
refundLT,
peerAddressOpt,
payoutAddressOpt,
changeAddressOpt)
}
@ -399,10 +402,16 @@ case class WalletRoutes(wallet: AnyDLCHDWalletApi)(implicit
case Failure(exception) =>
complete(Server.httpBadRequest(exception))
case Success(
AcceptDLCOffer(offer, payoutAddressOpt, changeAddressOpt)) =>
AcceptDLCOffer(offer,
payoutAddressOpt,
changeAddressOpt,
peerAddressOpt)) =>
complete {
wallet
.acceptDLCOffer(offer.tlv, payoutAddressOpt, changeAddressOpt)
.acceptDLCOffer(offer.tlv,
peerAddressOpt,
payoutAddressOpt,
changeAddressOpt)
.map { accept =>
Server.httpSuccess(accept.toMessage.hex)
}
@ -426,6 +435,7 @@ case class WalletRoutes(wallet: AnyDLCHDWalletApi)(implicit
wallet
.acceptDLCOffer(offerMessage.tlv,
None,
payoutAddressOpt,
changeAddressOpt)
.map { accept =>

View file

@ -28,6 +28,7 @@ trait DLCWalletApi { self: WalletApi =>
collateral: Satoshis,
feeRateOpt: Option[SatoshisPerVirtualByte],
refundLT: UInt32,
peerAddressOpt: Option[java.net.InetSocketAddress],
externalPayoutAddressOpt: Option[BitcoinAddress],
externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCOffer] = {
val contractInfo = ContractInfo.fromTLV(contractInfoTLV)
@ -35,6 +36,7 @@ trait DLCWalletApi { self: WalletApi =>
collateral,
feeRateOpt,
refundLT,
peerAddressOpt,
externalPayoutAddressOpt,
externalChangeAddressOpt)
}
@ -45,6 +47,7 @@ trait DLCWalletApi { self: WalletApi =>
feeRateOpt: Option[SatoshisPerVirtualByte],
locktime: UInt32,
refundLT: UInt32,
peerAddressOpt: Option[java.net.InetSocketAddress],
externalPayoutAddressOpt: Option[BitcoinAddress],
externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCOffer] = {
val contractInfo = ContractInfo.fromTLV(contractInfoTLV)
@ -53,6 +56,7 @@ trait DLCWalletApi { self: WalletApi =>
feeRateOpt,
locktime,
refundLT,
peerAddressOpt,
externalPayoutAddressOpt,
externalChangeAddressOpt)
}
@ -62,6 +66,7 @@ trait DLCWalletApi { self: WalletApi =>
collateral: Satoshis,
feeRateOpt: Option[SatoshisPerVirtualByte],
refundLT: UInt32,
peerAddressOpt: Option[java.net.InetSocketAddress],
externalPayoutAddressOpt: Option[BitcoinAddress],
externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCOffer]
@ -71,32 +76,24 @@ trait DLCWalletApi { self: WalletApi =>
feeRateOpt: Option[SatoshisPerVirtualByte],
locktime: UInt32,
refundLT: UInt32,
peerAddressOpt: Option[java.net.InetSocketAddress],
externalPayoutAddressOpt: Option[BitcoinAddress],
externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCOffer]
def registerDLCOffer(dlcOffer: DLCOffer): Future[DLCOffer] = {
createDLCOffer(
dlcOffer.contractInfo,
dlcOffer.collateral,
Some(dlcOffer.feeRate),
dlcOffer.timeouts.contractMaturity.toUInt32,
dlcOffer.timeouts.contractTimeout.toUInt32,
None,
None
)
}
def acceptDLCOffer(
dlcOfferTLV: DLCOfferTLV,
peerAddress: Option[InetSocketAddress],
externalPayoutAddressOpt: Option[BitcoinAddress],
externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCAccept] = {
acceptDLCOffer(DLCOffer.fromTLV(dlcOfferTLV),
peerAddress,
externalPayoutAddressOpt,
externalChangeAddressOpt)
}
def acceptDLCOffer(
dlcOffer: DLCOffer,
peerAddress: Option[InetSocketAddress],
externalPayoutAddressOpt: Option[BitcoinAddress],
externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCAccept]

View file

@ -56,8 +56,9 @@ class DLCNegotiationTest extends BitcoinSDualWalletTest {
UInt32.zero,
UInt32.one,
None,
None,
None)
accept <- walletA.acceptDLCOffer(offer, None, None)
accept <- walletA.acceptDLCOffer(offer, None, None, None)
// Send accept message to begin p2p
_ = handler ! DLCDataHandler.Received(accept.toMessage)
@ -108,6 +109,7 @@ class DLCNegotiationTest extends BitcoinSDualWalletTest {
UInt32.zero,
UInt32.one,
None,
None,
None)
tlv = SendOfferTLV(peer = "peer", message = "msg", offer = offer.toTLV)

View file

@ -37,6 +37,7 @@ class DLCNodeTest extends BitcoinSDLCNodeTest {
UInt32.zero,
UInt32.one,
None,
None,
None)
_ <- nodeB.acceptDLCOffer(addrA, offer.toMessage, None, None)

View file

@ -66,6 +66,7 @@ case class DLCNode(wallet: DLCWalletApi)(implicit
for {
handler <- connectToPeer(peerAddress)
accept <- wallet.acceptDLCOffer(dlcOffer.tlv,
Some(peerAddress),
externalPayoutAddress,
externalChangeAddress)
} yield {

View file

@ -371,6 +371,7 @@ class DLCExecutionTest extends BitcoinSDualWalletTest {
feeRateOpt = feeRateOpt,
locktime = UInt32.zero,
refundLT = UInt32.one,
peerAddressOpt = None,
externalPayoutAddressOpt = None,
externalChangeAddressOpt = None
)
@ -424,6 +425,7 @@ class DLCExecutionTest extends BitcoinSDualWalletTest {
UInt32.zero,
UInt32.one,
None,
None,
None)
_ <- walletA.listDLCs()
@ -481,10 +483,11 @@ class DLCExecutionTest extends BitcoinSDualWalletTest {
feeRateOpt = Some(SatoshisPerVirtualByte.fromLong(10)),
locktime = dummyTimeouts.contractMaturity.toUInt32,
refundLocktime = dummyTimeouts.contractTimeout.toUInt32,
peerAddressOpt = None,
externalPayoutAddressOpt = None,
externalChangeAddressOpt = None
)
accept <- walletB.acceptDLCOffer(offer, None, None)
accept <- walletB.acceptDLCOffer(offer, None, None, None)
sign <- walletA.signDLC(accept)
contractId = sign.contractId
(_, sig) = DLCWalletUtil.getSigs(contractInfo)

View file

@ -53,6 +53,7 @@ class MultiWalletDLCTest extends BitcoinSWalletTest {
UInt32.zero,
UInt32.one,
None,
None,
None)
dlcsA <- walletA.listDLCs()
dlcsB <- walletB.listDLCs()
@ -76,6 +77,7 @@ class MultiWalletDLCTest extends BitcoinSWalletTest {
feeRateOpt = Some(SatoshisPerVirtualByte.one),
locktime = UInt32.zero,
refundLocktime = UInt32.one,
peerAddressOpt = None,
externalPayoutAddressOpt = None,
externalChangeAddressOpt = None
)

View file

@ -1,5 +1,6 @@
package org.bitcoins.dlc.wallet
import org.bitcoins.core.api.dlc.wallet.db.DLCContactDb
import org.bitcoins.core.currency._
import org.bitcoins.core.number.{UInt32, UInt64}
import org.bitcoins.core.protocol.BitcoinAddress
@ -20,6 +21,7 @@ import org.bitcoins.testkit.wallet.FundWalletUtil.FundedDLCWallet
import org.bitcoins.testkit.wallet.{BitcoinSDualWalletTest, DLCWalletUtil}
import org.scalatest.{Assertion, FutureOutcome}
import java.net.InetSocketAddress
import scala.concurrent.Future
import scala.reflect.ClassTag
@ -47,6 +49,7 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
offerData.timeouts.contractTimeout.toUInt32,
None,
None,
None
)
dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint))
@ -64,7 +67,7 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
assert(offer.changeAddress.value.nonEmpty)
}
accept <- walletB.acceptDLCOffer(offer, None, None)
accept <- walletB.acceptDLCOffer(offer, None, None, None)
dlcB1Opt <- walletB.dlcDAO.read(dlcId)
_ = {
assert(dlcB1Opt.isDefined)
@ -189,11 +192,12 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
offerData.timeouts.contractTimeout.toUInt32,
None,
None,
None
)
dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint))
accept <- walletB.acceptDLCOffer(offer, None, None)
accept <- walletB.acceptDLCOffer(offer, None, None, None)
// reorder dlc inputs in wallets
_ <- reorderInputDbs(walletA, dlcId)
@ -248,11 +252,12 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
offerData.timeouts.contractTimeout.toUInt32,
None,
None,
None
)
dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint))
accept <- walletB.acceptDLCOffer(offer.toTLV, None, None)
accept <- walletB.acceptDLCOffer(offer.toTLV, None, None, None)
// reorder dlc inputs in wallets
_ <- reorderInputDbs(walletA, dlcId)
@ -279,6 +284,7 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
offerData.timeouts.contractTimeout.toUInt32,
None,
None,
None
)
dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint))
@ -295,7 +301,7 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
assert(offer.changeAddress.value.nonEmpty)
}
accept <- walletB.acceptDLCOffer(offer.toTLV, None, None)
accept <- walletB.acceptDLCOffer(offer.toTLV, None, None, None)
dlcB1Opt <- walletB.dlcDAO.read(dlcId)
_ = {
assert(dlcB1Opt.isDefined)
@ -374,10 +380,11 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
offerData.timeouts.contractTimeout.toUInt32,
None,
None,
None
)
accept <- walletB.acceptDLCOffer(offer, None, None)
accept <- walletB.acceptDLCOffer(offer, None, None, None)
} yield accept
}
@ -520,6 +527,7 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
offerData.timeouts.contractTimeout.toUInt32,
None,
None,
None
)
@ -565,9 +573,10 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
offerData.timeouts.contractTimeout.toUInt32,
None,
None,
None
)
_ <- walletB.acceptDLCOffer(offer, None, None)
_ <- walletB.acceptDLCOffer(offer, None, None, None)
dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint))
@ -608,9 +617,10 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
offerData.timeouts.contractTimeout.toUInt32,
None,
None,
None
)
accept <- walletB.acceptDLCOffer(offer, None, None)
accept <- walletB.acceptDLCOffer(offer, None, None, None)
sign <- walletA.signDLC(accept)
_ <- walletB.addDLCSigs(sign)
@ -652,9 +662,10 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
offerData.timeouts.contractTimeout.toUInt32,
None,
None,
None
)
accept <- walletB.acceptDLCOffer(offer, None, None)
accept <- walletB.acceptDLCOffer(offer, None, None, None)
sign <- walletA.signDLC(accept)
_ <- walletB.addDLCSigs(sign)
@ -687,9 +698,10 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
UInt32.max,
None,
None,
None
)
accept <- walletB.acceptDLCOffer(offer, None, None)
accept <- walletB.acceptDLCOffer(offer, None, None, None)
sign <- walletA.signDLC(accept)
_ <- walletB.addDLCSigs(sign)
@ -754,6 +766,7 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
offerData.timeouts.contractTimeout.toUInt32,
None,
None,
None
)
_ = {
@ -768,7 +781,7 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint))
accept <- walletB.acceptDLCOffer(offer, None, None)
accept <- walletB.acceptDLCOffer(offer, None, None, None)
_ = {
assert(accept.fundingInputs.nonEmpty)
assert(accept.collateral == offer.contractInfo.max - offer.collateral)
@ -851,6 +864,7 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
feeRateOpt = feeRateOpt,
locktime = UInt32.zero,
refundLT = UInt32.one,
peerAddressOpt = None,
externalPayoutAddressOpt = None,
externalChangeAddressOpt = None
)
@ -860,8 +874,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerA <- makeOffer(contractInfoA)
offerB <- makeOffer(contractInfoB)
_ <- walletB.acceptDLCOffer(offerA, None, None)
_ <- walletB.acceptDLCOffer(offerB, None, None)
_ <- walletB.acceptDLCOffer(offerA, None, None, None)
_ <- walletB.acceptDLCOffer(offerB, None, None, None)
} yield succeed
}
@ -899,6 +913,7 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
feeRateOpt = feeRateOpt,
locktime = UInt32.zero,
refundLT = UInt32.one,
peerAddressOpt = None,
externalPayoutAddressOpt = None,
externalChangeAddressOpt = None
)
@ -906,8 +921,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
for {
offer <- makeOffer(contractInfoA)
accept1F = walletB.acceptDLCOffer(offer, None, None)
accept2F = walletB.acceptDLCOffer(offer, None, None)
accept1F = walletB.acceptDLCOffer(offer, None, None, None)
accept2F = walletB.acceptDLCOffer(offer, None, None, None)
_ <- recoverToSucceededIf[DuplicateOfferException](
Future.sequence(Seq(accept1F, accept2F)))
} yield {
@ -930,6 +945,7 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
feeRateOpt = feeRateOpt,
locktime = UInt32.zero,
refundLT = UInt32.one,
peerAddressOpt = None,
externalPayoutAddressOpt = None,
externalChangeAddressOpt = None
)
@ -937,8 +953,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
for {
offer <- makeOffer(contractInfoA)
accept1 <- walletB.acceptDLCOffer(offer, None, None)
accept2 <- walletB.acceptDLCOffer(offer, None, None)
accept1 <- walletB.acceptDLCOffer(offer, None, None, None)
accept2 <- walletB.acceptDLCOffer(offer, None, None, None)
} yield {
assert(accept1 == accept2)
}
@ -958,9 +974,10 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
UInt32.max,
None,
None,
None
)
accept <- walletB.acceptDLCOffer(offer, None, None)
accept <- walletB.acceptDLCOffer(offer, None, None, None)
res <- recoverToSucceededIf[IllegalArgumentException](
walletB.signDLC(accept))
} yield res
@ -981,6 +998,7 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
UInt32.max,
None,
None,
None
))
} yield {
@ -1006,12 +1024,13 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
feeRateOpt = feeRateOpt,
locktime = UInt32.zero,
refundLT = UInt32.one,
peerAddressOpt = None,
externalPayoutAddressOpt = None,
externalChangeAddressOpt = None
)
invalidOffer = offer.copy(contractInfo = invalidContractInfo)
res <- recoverToSucceededIf[InvalidAnnouncementSignature](
walletB.acceptDLCOffer(invalidOffer, None, None))
walletB.acceptDLCOffer(invalidOffer, None, None, None))
} yield {
res
}
@ -1042,31 +1061,58 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
Some(BitcoinAddress.fromString("2MsM67NLa71fHvTUBqNENW15P68nHB2vVXb"))
val changeAddressBOpt =
Some(BitcoinAddress.fromString("2N4YXTxKEso3yeYXNn5h42Vqu3FzTTQ8Lq5"))
val peerAddressOpt1 =
Some(InetSocketAddress.createUnresolved("127.0.0.1", 1))
val peerAddressOpt2 =
Some(InetSocketAddress.createUnresolved("127.0.0.1", 2))
val peerAddressOpt3 =
Some(InetSocketAddress.createUnresolved("127.0.0.1", 3))
val contactA = DLCContactDb("A", peerAddressOpt1.get, "memo")
val contactB = DLCContactDb("B", peerAddressOpt2.get, "memo")
for {
_ <- walletA.contactDAO.create(contactA)
_ <- walletB.contactDAO.create(contactB)
offer <- walletA.createDLCOffer(
contractInfoTLV = contractInfo,
collateral = totalCollateral,
feeRateOpt = feeRateOpt,
locktime = UInt32.zero,
refundLT = UInt32.one,
peerAddressOpt = peerAddressOpt1,
externalPayoutAddressOpt = payoutAddressAOpt,
externalChangeAddressOpt = changeAddressAOpt
)
dlcContactA <- walletA.dlcContactMappingDAO.read(offer.dlcId)
accept <- walletB.acceptDLCOffer(offer,
peerAddressOpt2,
payoutAddressBOpt,
changeAddressBOpt)
dlcContactB <- walletB.dlcContactMappingDAO.read(offer.dlcId)
offer1 <- walletA.createDLCOffer(
contractInfoTLV = contractInfo1,
collateral = totalCollateral1,
feeRateOpt = feeRateOpt1,
locktime = UInt32.zero,
refundLT = UInt32.one,
peerAddressOpt = peerAddressOpt3,
externalPayoutAddressOpt = None,
externalChangeAddressOpt = None
)
accept1 <- walletB.acceptDLCOffer(offer1, None, None)
dlcContactA1 <- walletA.dlcContactMappingDAO.read(offer1.dlcId)
accept1 <- walletB.acceptDLCOffer(offer1, peerAddressOpt3, None, None)
dlcContactB1 <- walletB.dlcContactMappingDAO.read(offer1.dlcId)
} yield {
assert(dlcContactA.nonEmpty)
assert(dlcContactA.get.contactId == contactA.address)
assert(dlcContactA1.isEmpty)
assert(dlcContactB.nonEmpty)
assert(dlcContactB.get.contactId == contactB.address)
assert(dlcContactB1.isEmpty)
assert(offer)
assert(offer.pubKeys.payoutAddress == payoutAddressAOpt.get)
assert(offer.changeAddress == changeAddressAOpt.get)
assert(accept.pubKeys.payoutAddress == payoutAddressBOpt.get)
@ -1101,10 +1147,11 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
offerData.timeouts.contractTimeout.toUInt32,
None,
None,
None
)
//accept it for the first time using the inputs
_ <- walletB.acceptDLCOffer(offer1.toTLV, None, None)
_ <- walletB.acceptDLCOffer(offer1.toTLV, None, None, None)
//cancel the offer
_ <- walletA.cancelDLC(dlcId = offer1.dlcId)
@ -1115,9 +1162,10 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
offerData2.timeouts.contractMaturity.toUInt32,
offerData2.timeouts.contractTimeout.toUInt32,
None,
None,
None
)
_ <- walletB.acceptDLCOffer(offer2.toTLV, None, None)
_ <- walletB.acceptDLCOffer(offer2.toTLV, None, None, None)
} yield succeed
}
}

View file

@ -33,9 +33,10 @@ class DLCDataManagementTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
offerData.timeouts.contractTimeout.toUInt32,
None,
None,
None
)
accept <- walletB.acceptDLCOffer(offer1, None, None)
accept <- walletB.acceptDLCOffer(offer1, None, None, None)
contractId = DLCUtil.calcContractId(offer1, accept)
acceptDbStateOpt <- walletB.dlcDataManagement.getDLCFundingData(
contractId,
@ -62,9 +63,10 @@ class DLCDataManagementTest extends BitcoinSDualWalletTest {
offerData.timeouts.contractMaturity.toUInt32,
offerData.timeouts.contractTimeout.toUInt32,
None,
None,
None
)
accept <- walletB.acceptDLCOffer(offer1, None, None)
accept <- walletB.acceptDLCOffer(offer1, None, None, None)
sign <- walletA.signDLC(accept)
signDbStateOpt <- walletA.dlcDataManagement.getDLCFundingData(

View file

@ -277,6 +277,7 @@ abstract class DLCWallet
collateral: Satoshis,
feeRateOpt: Option[SatoshisPerVirtualByte],
refundLT: UInt32,
peerAddressOpt: Option[java.net.InetSocketAddress],
externalPayoutAddressOpt: Option[BitcoinAddress],
externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCOffer] = {
chainQueryApi.getBestHashBlockHeight().flatMap { height =>
@ -285,6 +286,7 @@ abstract class DLCWallet
feeRateOpt,
locktime = UInt32(height),
refundLT,
peerAddressOpt,
externalPayoutAddressOpt,
externalChangeAddressOpt)
}
@ -301,6 +303,7 @@ abstract class DLCWallet
feeRateOpt: Option[SatoshisPerVirtualByte],
locktime: UInt32,
refundLocktime: UInt32,
peerAddressOpt: Option[java.net.InetSocketAddress],
externalPayoutAddressOpt: Option[BitcoinAddress],
externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCOffer] = {
logger.info("Creating DLC Offer")
@ -478,6 +481,11 @@ abstract class DLCWallet
dlcOfferDb = dlcOfferDb)
_ <- safeDatabase.run(offerActions)
_ <- peerAddressOpt match {
case Some(a) =>
dlcContactMappingDAO.createIfContactExists(dlcDb.dlcId, a)
case None => Future.successful(None)
}
status <- findDLC(dlcId)
_ <- dlcConfig.walletCallbacks.executeOnDLCStateChange(logger, status.get)
} yield offer
@ -666,6 +674,7 @@ abstract class DLCWallet
*/
override def acceptDLCOffer(
offer: DLCOffer,
peerAddressOpt: Option[java.net.InetSocketAddress],
externalPayoutAddressOpt: Option[BitcoinAddress],
externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCAccept] = {
logger.debug("Calculating relevant wallet data for DLC Accept")
@ -697,6 +706,7 @@ abstract class DLCWallet
case None =>
createNewDLCAccept(collateral,
offer,
peerAddressOpt,
externalPayoutAddressOpt,
externalChangeAddressOpt)
}
@ -748,6 +758,7 @@ abstract class DLCWallet
private def createNewDLCAccept(
collateral: CurrencyUnit,
offer: DLCOffer,
peerAddressOpt: Option[java.net.InetSocketAddress],
externalPayoutAddressOpt: Option[BitcoinAddress],
externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCAccept] =
Future {
@ -802,6 +813,11 @@ abstract class DLCWallet
isExternalAddress <- addressDAO
.findAddress(initializedAccept.pubKeys.payoutAddress)
.map(_.isEmpty)
contactOpt <- peerAddressOpt match {
case Some(a) =>
dlcContactMappingDAO.createIfContactExists(offer.dlcId, a)
case None => Future.successful(None)
}
status = DLCStatusBuilder.buildInProgressDLCStatus(
dlcDb = initializedAccept.dlc,
contractInfo = offer.contractInfo,
@ -810,7 +826,7 @@ abstract class DLCWallet
payoutAddress = Some(
PayoutAddress(initializedAccept.pubKeys.payoutAddress,
isExternalAddress)),
contactOpt = None
contactOpt = contactOpt
)
_ = dlcConfig.walletCallbacks.executeOnDLCStateChange(logger, status)
cetSigs <- signer.createCETSigsAsync()

View file

@ -61,6 +61,32 @@ case class DLCContactMappingDAO()(implicit
create(DLCContactMappingDb(dlcId, contactId))
}
def createIfContactExists(
dlcId: Sha256Digest,
contactId: InetSocketAddress): Future[Option[DLCContactDb]] = {
val action = for {
contactOpt <- contactTable
.filter(_.address === contactId)
.result
.headOption
res <-
if (contactOpt.nonEmpty) {
val db = DLCContactMappingDb(dlcId, contactId)
(table += db).map(_ => contactOpt)
} else {
DBIO.successful(None)
}
} yield res
safeDatabase.run(action)
}
def upsert(
dlcId: Sha256Digest,
contactId: InetSocketAddress): Future[DLCContactMappingDb] = {
upsert(DLCContactMappingDb(dlcId, contactId))
}
def delete(dlcId: Sha256Digest): Future[Unit] = {
safeDatabase.run(table.filter(_.dlcId === dlcId).delete).map(_ => ())
}

View file

@ -262,15 +262,17 @@ the `-p 9999:9999` port mapping on the docker container to adjust for this.
- `collateral` - Satoshis to fund your side of the DLC
- `feerate` - Fee rate for both funding and closing transactions, in sats/vbytes
- `refundlocktime` - Locktime of the refund transaction
- `--cetlocktime <value>` - Should not be set unless you know what you are doing. Locktime of the contract execution transactions (defaults to current height)
- `cetlocktime <value>` - Should not be set unless you know what you are doing. Locktime of the contract execution transactions (defaults to current height)
- `peer` - Peer's network address
- `acceptdlc` `offer` `peer` - Accepts a DLC offer given from another party
- `offer` - Hex encoded dlc offer message
- `peer` - Peer's network address
- `acceptdlcoffer` `offer` - Accepts a DLC offer given from another party
- `offer` - Hex encoded offer message
- `peer` - Peer's network address
- `acceptdlcofferfromfile` `path` `[destination]` - Accepts a DLC offer given from another party
- `path` - Path to dlc offer file
- `destination` - Path to write dlc accept message
- `path` - Path to dlc offer file
- `destination` - Path to write dlc accept message
- `contact-add` `alias` `address` `memo`
- `alias` - alias for the address like a name
- `address` - the tor address for the peer

View file

@ -310,10 +310,12 @@ object DLCWalletUtil extends Logging {
feeRateOpt = Some(SatoshisPerVirtualByte.fromLong(10)),
locktime = dummyTimeouts.contractMaturity.toUInt32,
refundLocktime = dummyTimeouts.contractTimeout.toUInt32,
peerAddressOpt = None,
externalPayoutAddressOpt = payoutAddressAOpt,
externalChangeAddressOpt = changeAddressAOpt
)
accept <- walletB.acceptDLCOffer(offer,
None,
payoutAddressBOpt,
changeAddressBOpt)
sigs <- walletA.signDLC(accept)