mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-21 06:22:21 +01:00
Restructure Contract and Oracle Info (#2488)
* Rewrote all oracle and contract info code * Fixed src compilation * For real this time * Tests compiling (except for Lloyd example) * Fixed all non-json dlc tests * Regenerated test vectors * Fix dlc wallet * Fix TLV verfiy sig func for Oracle Tests * Fix migrations tests Co-authored-by: benthecarman <benthecarman@live.com>
This commit is contained in:
parent
f06dcbb160
commit
d8b0c21f20
51 changed files with 3363 additions and 3263 deletions
app-commons/src/main/scala/org/bitcoins/commons/serializers
app
cli/src/main/scala/org/bitcoins/cli
gui/src/main/scala/org/bitcoins/gui/dlc
server-test/src/test/scala/org/bitcoins/server
server/src/main/scala/org/bitcoins/server
core-test/src/test/scala/org/bitcoins/core/protocol/dlc
core/src/main/scala/org/bitcoins/core/protocol
db-commons-test/src/test/scala/org/bitcoins/db
db-commons/src/main/scala/org/bitcoins/db
dlc-test/src/test/scala/org/bitcoins/dlc
dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet
dlc-wallet/src/main
resources
postgresql/dlc/migration
sqlite/dlc/migration
scala/org/bitcoins/dlc/wallet
dlc/src/main/scala/org/bitcoins/dlc
builder
execution
sign
testgen
DLCParsingTestVector.scalaDLCParsingTestVectorGen.scalaDLCTLVGen.scalaDLCTestUtil.scalaDLCTestVector.scalaDLCTxGen.scalaTestDLCClient.scaladlc_message_test.jsondlc_test.jsondlc_tx_test.json
verify
testkit/src/main/scala/org/bitcoins/testkit
|
@ -101,8 +101,8 @@ object Picklers {
|
|||
implicit val contractInfoPickler: ReadWriter[ContractInfo] =
|
||||
readwriter[String].bimap(_.hex, ContractInfo.fromHex)
|
||||
|
||||
implicit val contractInfoTLVPickler: ReadWriter[ContractInfoTLV] =
|
||||
readwriter[String].bimap(_.hex, ContractInfoTLV.fromHex)
|
||||
implicit val contractInfoTLVPickler: ReadWriter[ContractInfoV0TLV] =
|
||||
readwriter[String].bimap(_.hex, ContractInfoV0TLV.fromHex)
|
||||
|
||||
implicit val schnorrDigitalSignaturePickler: ReadWriter[
|
||||
SchnorrDigitalSignature] =
|
||||
|
@ -164,7 +164,6 @@ object Picklers {
|
|||
"paramHash" -> Str(paramHash.hex),
|
||||
"isInitiator" -> Bool(isInitiator),
|
||||
"tempContractId" -> Str(tempContractId.hex),
|
||||
"oracleInfo" -> Str(oracleInfo.hex),
|
||||
"contractInfo" -> Str(contractInfo.hex),
|
||||
"contractMaturity" -> Num(
|
||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
||||
|
@ -185,7 +184,6 @@ object Picklers {
|
|||
"isInitiator" -> Bool(isInitiator),
|
||||
"tempContractId" -> Str(tempContractId.hex),
|
||||
"contractId" -> Str(contractId.toHex),
|
||||
"oracleInfo" -> Str(oracleInfo.hex),
|
||||
"contractInfo" -> Str(contractInfo.hex),
|
||||
"contractMaturity" -> Num(
|
||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
||||
|
@ -206,7 +204,6 @@ object Picklers {
|
|||
"isInitiator" -> Bool(isInitiator),
|
||||
"tempContractId" -> Str(tempContractId.hex),
|
||||
"contractId" -> Str(contractId.toHex),
|
||||
"oracleInfo" -> Str(oracleInfo.hex),
|
||||
"contractInfo" -> Str(contractInfo.hex),
|
||||
"contractMaturity" -> Num(
|
||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
||||
|
@ -228,7 +225,6 @@ object Picklers {
|
|||
"isInitiator" -> Bool(isInitiator),
|
||||
"tempContractId" -> Str(tempContractId.hex),
|
||||
"contractId" -> Str(contractId.toHex),
|
||||
"oracleInfo" -> Str(oracleInfo.hex),
|
||||
"contractInfo" -> Str(contractInfo.hex),
|
||||
"contractMaturity" -> Num(
|
||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
||||
|
@ -251,7 +247,6 @@ object Picklers {
|
|||
"isInitiator" -> Bool(isInitiator),
|
||||
"tempContractId" -> Str(tempContractId.hex),
|
||||
"contractId" -> Str(contractId.toHex),
|
||||
"oracleInfo" -> Str(oracleInfo.hex),
|
||||
"contractInfo" -> Str(contractInfo.hex),
|
||||
"contractMaturity" -> Num(
|
||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
||||
|
@ -280,7 +275,6 @@ object Picklers {
|
|||
"isInitiator" -> Bool(isInitiator),
|
||||
"tempContractId" -> Str(tempContractId.hex),
|
||||
"contractId" -> Str(contractId.toHex),
|
||||
"oracleInfo" -> Str(oracleInfo.hex),
|
||||
"contractInfo" -> Str(contractInfo.hex),
|
||||
"contractMaturity" -> Num(
|
||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
||||
|
@ -313,7 +307,6 @@ object Picklers {
|
|||
"isInitiator" -> Bool(isInitiator),
|
||||
"tempContractId" -> Str(tempContractId.hex),
|
||||
"contractId" -> Str(contractId.toHex),
|
||||
"oracleInfo" -> Str(oracleInfo.hex),
|
||||
"contractInfo" -> Str(contractInfo.hex),
|
||||
"contractMaturity" -> Num(
|
||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
||||
|
@ -338,7 +331,6 @@ object Picklers {
|
|||
"isInitiator" -> Bool(isInitiator),
|
||||
"tempContractId" -> Str(tempContractId.hex),
|
||||
"contractId" -> Str(contractId.toHex),
|
||||
"oracleInfo" -> Str(oracleInfo.hex),
|
||||
"contractInfo" -> Str(contractInfo.hex),
|
||||
"contractMaturity" -> Num(
|
||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
||||
|
@ -367,8 +359,7 @@ object Picklers {
|
|||
val state = DLCState.fromString(obj("state").str)
|
||||
val isInitiator = obj("isInitiator").bool
|
||||
val tempContractId = Sha256Digest(obj("tempContractId").str)
|
||||
val oracleInfo = OracleInfo(obj("oracleInfo").str)
|
||||
val contractInfoTLV = ContractInfoTLV(obj("contractInfo").str)
|
||||
val contractInfoTLV = ContractInfoV0TLV(obj("contractInfo").str)
|
||||
val contractMaturity =
|
||||
BlockStamp(UInt32(obj("contractMaturity").num.toLong))
|
||||
val contractTimeout = BlockStamp(UInt32(obj("contractTimeout").num.toLong))
|
||||
|
@ -398,7 +389,6 @@ object Picklers {
|
|||
paramHash,
|
||||
isInitiator,
|
||||
tempContractId,
|
||||
oracleInfo,
|
||||
ContractInfo.fromTLV(contractInfoTLV),
|
||||
DLCTimeouts(contractMaturity, contractTimeout),
|
||||
feeRate,
|
||||
|
@ -411,7 +401,6 @@ object Picklers {
|
|||
isInitiator,
|
||||
tempContractId,
|
||||
contractId,
|
||||
oracleInfo,
|
||||
ContractInfo.fromTLV(contractInfoTLV),
|
||||
DLCTimeouts(contractMaturity, contractTimeout),
|
||||
feeRate,
|
||||
|
@ -424,7 +413,6 @@ object Picklers {
|
|||
isInitiator,
|
||||
tempContractId,
|
||||
contractId,
|
||||
oracleInfo,
|
||||
ContractInfo.fromTLV(contractInfoTLV),
|
||||
DLCTimeouts(contractMaturity, contractTimeout),
|
||||
feeRate,
|
||||
|
@ -437,7 +425,6 @@ object Picklers {
|
|||
isInitiator,
|
||||
tempContractId,
|
||||
contractId,
|
||||
oracleInfo,
|
||||
ContractInfo.fromTLV(contractInfoTLV),
|
||||
DLCTimeouts(contractMaturity, contractTimeout),
|
||||
feeRate,
|
||||
|
@ -451,7 +438,6 @@ object Picklers {
|
|||
isInitiator,
|
||||
tempContractId,
|
||||
contractId,
|
||||
oracleInfo,
|
||||
ContractInfo.fromTLV(contractInfoTLV),
|
||||
DLCTimeouts(contractMaturity, contractTimeout),
|
||||
feeRate,
|
||||
|
@ -465,7 +451,6 @@ object Picklers {
|
|||
isInitiator,
|
||||
tempContractId,
|
||||
contractId,
|
||||
oracleInfo,
|
||||
ContractInfo.fromTLV(contractInfoTLV),
|
||||
DLCTimeouts(contractMaturity, contractTimeout),
|
||||
feeRate,
|
||||
|
@ -484,7 +469,6 @@ object Picklers {
|
|||
isInitiator,
|
||||
tempContractId,
|
||||
contractId,
|
||||
oracleInfo,
|
||||
ContractInfo.fromTLV(contractInfoTLV),
|
||||
DLCTimeouts(contractMaturity, contractTimeout),
|
||||
feeRate,
|
||||
|
@ -501,7 +485,6 @@ object Picklers {
|
|||
isInitiator,
|
||||
tempContractId,
|
||||
contractId,
|
||||
oracleInfo,
|
||||
ContractInfo.fromTLV(contractInfoTLV),
|
||||
DLCTimeouts(contractMaturity, contractTimeout),
|
||||
feeRate,
|
||||
|
|
|
@ -176,10 +176,10 @@ object CliReaders {
|
|||
val reads: String => ContractInfo = ContractInfo.fromHex
|
||||
}
|
||||
|
||||
implicit val contractInfoTLVReads: Read[ContractInfoTLV] =
|
||||
new Read[ContractInfoTLV] {
|
||||
implicit val contractInfoTLVReads: Read[ContractInfoV0TLV] =
|
||||
new Read[ContractInfoV0TLV] {
|
||||
val arity: Int = 1
|
||||
val reads: String => ContractInfoTLV = ContractInfoTLV.fromHex
|
||||
val reads: String => ContractInfoV0TLV = ContractInfoV0TLV.fromHex
|
||||
}
|
||||
|
||||
implicit val blockStampReads: Read[BlockStamp] =
|
||||
|
|
|
@ -6,7 +6,6 @@ import java.time.Instant
|
|||
import org.bitcoins.cli.CliCommand._
|
||||
import org.bitcoins.cli.CliReaders._
|
||||
import org.bitcoins.commons.jsonmodels.bitcoind.RpcOpts.LockUnspentOutputParameter
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage._
|
||||
import org.bitcoins.commons.serializers.Picklers._
|
||||
import org.bitcoins.core.api.wallet.CoinSelectionAlgo
|
||||
import org.bitcoins.core.config.NetworkParameters
|
||||
|
@ -164,23 +163,14 @@ object ConsoleCli {
|
|||
cmd("createdlcoffer")
|
||||
.action((_, conf) =>
|
||||
conf.copy(
|
||||
command = CreateDLCOffer(OracleAnnouncementV0TLV.dummy,
|
||||
ContractInfo.empty.toTLV,
|
||||
command = CreateDLCOffer(ContractInfoV0TLV.dummy,
|
||||
Satoshis.zero,
|
||||
None,
|
||||
UInt32.zero,
|
||||
UInt32.zero)))
|
||||
.text("Creates a DLC offer that another party can accept")
|
||||
.children(
|
||||
arg[OracleAnnouncementTLV]("oracle")
|
||||
.required()
|
||||
.action((oracle, conf) =>
|
||||
conf.copy(command = conf.command match {
|
||||
case offer: CreateDLCOffer =>
|
||||
offer.copy(oracle = oracle)
|
||||
case other => other
|
||||
})),
|
||||
arg[ContractInfoTLV]("contractInfo")
|
||||
arg[ContractInfoV0TLV]("contractInfo")
|
||||
.required()
|
||||
.action((info, conf) =>
|
||||
conf.copy(command = conf.command match {
|
||||
|
@ -1381,8 +1371,7 @@ object ConsoleCli {
|
|||
case GetDLCs => RequestParam("getdlcs")
|
||||
case GetDLC(paramHash) =>
|
||||
RequestParam("getdlc", Seq(up.writeJs(paramHash)))
|
||||
case CreateDLCOffer(oracle,
|
||||
contractInfo,
|
||||
case CreateDLCOffer(contractInfo,
|
||||
collateral,
|
||||
feeRateOpt,
|
||||
locktime,
|
||||
|
@ -1390,7 +1379,6 @@ object ConsoleCli {
|
|||
RequestParam(
|
||||
"createdlcoffer",
|
||||
Seq(
|
||||
up.writeJs(oracle),
|
||||
up.writeJs(contractInfo),
|
||||
up.writeJs(collateral),
|
||||
up.writeJs(feeRateOpt),
|
||||
|
@ -1712,8 +1700,7 @@ object CliCommand {
|
|||
|
||||
// DLC
|
||||
case class CreateDLCOffer(
|
||||
oracle: OracleAnnouncementTLV,
|
||||
contractInfo: ContractInfoTLV,
|
||||
contractInfo: ContractInfoV0TLV,
|
||||
collateral: Satoshis,
|
||||
feeRateOpt: Option[SatoshisPerVirtualByte],
|
||||
locktime: UInt32,
|
||||
|
|
|
@ -4,7 +4,7 @@ import org.bitcoins.cli.CliCommand._
|
|||
import org.bitcoins.cli.{CliCommand, Config, ConsoleCli}
|
||||
import org.bitcoins.commons.serializers.Picklers._
|
||||
import org.bitcoins.core.config.MainNet
|
||||
import org.bitcoins.core.number.{Int32, UInt16, UInt32}
|
||||
import org.bitcoins.core.currency.Satoshis
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage._
|
||||
import org.bitcoins.core.protocol.dlc.DLCStatus
|
||||
import org.bitcoins.core.protocol.tlv._
|
||||
|
@ -118,65 +118,51 @@ class DLCPaneModel(resultArea: TextArea, oracleInfoArea: TextArea) {
|
|||
}
|
||||
|
||||
result match {
|
||||
case Some(contractInfo) =>
|
||||
case Some(contractDescriptor) =>
|
||||
val builder = new StringBuilder()
|
||||
|
||||
builder.append(s"Serialized Contract Info:\n${contractInfo.hex}\n\n")
|
||||
|
||||
val privKey = ECPrivateKey.freshPrivateKey
|
||||
val pubKey = privKey.schnorrPublicKey
|
||||
val (kValues, rValues, oracleInfo) = contractInfo match {
|
||||
case SingleNonceContractInfo(_) =>
|
||||
val (kValues, oracleInfo) = contractDescriptor match {
|
||||
case EnumContractDescriptor(events) =>
|
||||
val kValue = ECPrivateKey.freshPrivateKey
|
||||
val rValue = kValue.schnorrNonce
|
||||
val oracleInfo = SingleNonceOracleInfo(pubKey, rValue)
|
||||
val oracleInfo = EnumSingleOracleInfo(
|
||||
OracleAnnouncementV0TLV
|
||||
.dummyForEventsAndKeys(privKey, rValue, events.map(_._1)))
|
||||
|
||||
(Vector(kValue), Vector(rValue), oracleInfo)
|
||||
case MultiNonceContractInfo(_, _, numDigits, _, _) =>
|
||||
(Vector(kValue), oracleInfo)
|
||||
case (_, NumericContractDescriptor(_, numDigits, _)) =>
|
||||
val kValues =
|
||||
0.until(numDigits).map(_ => ECPrivateKey.freshPrivateKey).toVector
|
||||
val rValues = kValues.map(_.schnorrNonce)
|
||||
val oracleInfo = MultiNonceOracleInfo(pubKey, rValues)
|
||||
val oracleInfo = NumericSingleOracleInfo(
|
||||
OracleAnnouncementV0TLV.dummyForKeys(privKey, rValues))
|
||||
|
||||
(kValues, rValues, oracleInfo)
|
||||
(kValues, oracleInfo)
|
||||
}
|
||||
|
||||
val contractInfo = contractDescriptor match {
|
||||
case descriptor: EnumContractDescriptor =>
|
||||
ContractInfo(descriptor, oracleInfo.asInstanceOf[EnumOracleInfo])
|
||||
case (totalCollateral: Satoshis,
|
||||
descriptor: NumericContractDescriptor) =>
|
||||
ContractInfo(totalCollateral, descriptor, oracleInfo)
|
||||
}
|
||||
|
||||
builder.append(s"Serialized Contract Info:\n${contractInfo.hex}\n\n")
|
||||
|
||||
if (GlobalData.network != MainNet) {
|
||||
|
||||
val descriptor = contractInfo match {
|
||||
case SingleNonceContractInfo(outcomeValueMap) =>
|
||||
EnumEventDescriptorV0TLV(outcomeValueMap.map(_._1.outcome))
|
||||
case MultiNonceContractInfo(_, base, numDigits, _, _) =>
|
||||
UnsignedDigitDecompositionEventDescriptor(UInt16(base),
|
||||
UInt16(numDigits),
|
||||
"units",
|
||||
Int32.zero)
|
||||
}
|
||||
|
||||
val oracleEvent = OracleEventV0TLV(oracleInfo.nonces,
|
||||
UInt32.zero,
|
||||
descriptor,
|
||||
"dummy oracle")
|
||||
|
||||
val announcementSig =
|
||||
privKey.schnorrSign(
|
||||
CryptoUtil
|
||||
.sha256DLCAnnouncement(oracleEvent.bytes)
|
||||
.bytes)
|
||||
|
||||
val announcement =
|
||||
OracleAnnouncementV0TLV(announcementSig, pubKey, oracleEvent)
|
||||
builder.append(
|
||||
s"Oracle Public Key: ${oracleInfo.publicKey.hex}\nEvent R values: ${oracleInfo.nonces.map(_.hex).mkString(",")}\n\n")
|
||||
|
||||
builder.append(
|
||||
s"Oracle Public Key: ${pubKey.hex}\nEvent R values: ${rValues.map(_.hex).mkString(",")}\n\n")
|
||||
s"Serialized Oracle Announcement: ${oracleInfo.announcement.hex}\n\n")
|
||||
|
||||
builder.append(
|
||||
s"Serialized Oracle Announcement: ${announcement.hex}\n\n")
|
||||
|
||||
contractInfo match {
|
||||
case contractInfo: SingleNonceContractInfo =>
|
||||
contractInfo.contractDescriptor match {
|
||||
case descriptor: EnumContractDescriptor =>
|
||||
builder.append("Outcomes and oracle sigs in order of entry:\n")
|
||||
contractInfo.keys.foreach { outcome =>
|
||||
descriptor.keys.foreach { outcome =>
|
||||
val bytes = outcome.serialized.head
|
||||
val hash = CryptoUtil
|
||||
.sha256DLCAttestation(bytes)
|
||||
|
@ -184,10 +170,10 @@ class DLCPaneModel(resultArea: TextArea, oracleInfoArea: TextArea) {
|
|||
val sig = privKey.schnorrSignWithNonce(hash, kValues.head)
|
||||
builder.append(s"$outcome - ${sig.hex}\n")
|
||||
}
|
||||
case contractInfo: MultiNonceContractInfo =>
|
||||
case _: NumericContractDescriptor =>
|
||||
builder.append("Oracle sigs:\n")
|
||||
|
||||
val sortedOutcomes = contractInfo.outcomeVec.sortBy(_._2)
|
||||
val sortedOutcomes = contractInfo.outcomeVecOpt.get.sortBy(_._2)
|
||||
|
||||
val max = UnsignedNumericOutcome(sortedOutcomes.last._1)
|
||||
val middle = UnsignedNumericOutcome(
|
||||
|
@ -231,7 +217,7 @@ class DLCPaneModel(resultArea: TextArea, oracleInfoArea: TextArea) {
|
|||
builder.append(s"remote win sigs - $minSigsStr")
|
||||
}
|
||||
|
||||
GlobalDLCData.lastOracleAnnouncement = announcement.hex
|
||||
GlobalDLCData.lastOracleAnnouncement = oracleInfo.announcement.hex
|
||||
}
|
||||
|
||||
GlobalDLCData.lastContractInfo = contractInfo.hex
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package org.bitcoins.gui.dlc
|
||||
|
||||
import org.bitcoins.core.protocol.dlc.{AcceptedDLCStatus, DLCStatus}
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.SingleOracleInfo
|
||||
import org.bitcoins.core.protocol.dlc.DLCStatus._
|
||||
import org.bitcoins.core.protocol.dlc.{AcceptedDLCStatus, DLCStatus}
|
||||
import scalafx.beans.property.StringProperty
|
||||
import scalafx.geometry.Insets
|
||||
import scalafx.scene.control.{ContextMenu, MenuItem, TableColumn, TableView}
|
||||
|
@ -68,7 +69,11 @@ class DLCTableView(model: DLCPaneModel) {
|
|||
text = "Oracle"
|
||||
prefWidth = 150
|
||||
cellValueFactory = { status =>
|
||||
new StringProperty(status, "Oracle", status.value.oracleInfo.pubKey.hex)
|
||||
new StringProperty(
|
||||
status,
|
||||
"Oracle",
|
||||
status.value.oracleInfo.asInstanceOf[SingleOracleInfo].publicKey.hex
|
||||
) // FIXME
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,10 +81,14 @@ class DLCTableView(model: DLCPaneModel) {
|
|||
text = "Event"
|
||||
prefWidth = 150
|
||||
cellValueFactory = { status =>
|
||||
new StringProperty(
|
||||
status,
|
||||
"Event",
|
||||
status.value.oracleInfo.nonces.map(_.hex).mkString(""))
|
||||
new StringProperty(status,
|
||||
"Event",
|
||||
status.value.oracleInfo
|
||||
.asInstanceOf[SingleOracleInfo]
|
||||
.nonces
|
||||
.map(_.hex)
|
||||
.mkString("")
|
||||
) // FIXME
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.bitcoins.gui.dlc.dialog
|
||||
|
||||
import org.bitcoins.cli.CliCommand._
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.OracleInfo
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.{OracleInfo, SingleOracleInfo}
|
||||
import org.bitcoins.core.protocol.tlv._
|
||||
import scalafx.scene.Node
|
||||
import scalafx.scene.control.Alert.AlertType
|
||||
|
@ -30,8 +30,8 @@ class AcceptDLCDialog
|
|||
def validateMatchingAnnouncement(
|
||||
offer: LnMessage[DLCOfferTLV],
|
||||
announcement: OracleAnnouncementTLV): Boolean = {
|
||||
val fromOffer = OracleInfo.fromTLV(offer.tlv.oracleInfo)
|
||||
val fromAnnouncement = OracleInfo.fromOracleAnnouncement(announcement)
|
||||
val fromOffer = OracleInfo.fromTLV(offer.tlv.contractInfo.oracleInfo)
|
||||
val fromAnnouncement = SingleOracleInfo(announcement)
|
||||
|
||||
fromOffer == fromAnnouncement
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.bitcoins.gui.dlc.dialog
|
||||
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.SingleNonceContractInfo
|
||||
import org.bitcoins.core.currency.Satoshis
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.EnumContractDescriptor
|
||||
import org.bitcoins.core.protocol.tlv.EnumOutcome
|
||||
import org.bitcoins.gui.GlobalData
|
||||
import org.bitcoins.gui.util.GUIUtil.setNumericInput
|
||||
|
@ -15,9 +15,9 @@ import scala.collection._
|
|||
|
||||
object InitEnumContractDialog {
|
||||
|
||||
def showAndWait(parentWindow: Window): Option[SingleNonceContractInfo] = {
|
||||
def showAndWait(parentWindow: Window): Option[EnumContractDescriptor] = {
|
||||
val dialog =
|
||||
new Dialog[Option[SingleNonceContractInfo]]() {
|
||||
new Dialog[Option[EnumContractDescriptor]]() {
|
||||
initOwner(parentWindow)
|
||||
title = "Initialize Demo Oracle"
|
||||
headerText = "Enter contract outcomes and their outcome values"
|
||||
|
@ -87,13 +87,13 @@ object InitEnumContractDialog {
|
|||
EnumOutcome(str) -> Satoshis(BigInt(value))
|
||||
}.toVector
|
||||
|
||||
Some(SingleNonceContractInfo(contractMap))
|
||||
Some(EnumContractDescriptor(contractMap))
|
||||
} else None
|
||||
|
||||
val result = dialog.showAndWait()
|
||||
|
||||
result match {
|
||||
case Some(Some(contractInfo: SingleNonceContractInfo)) =>
|
||||
case Some(Some(contractInfo: EnumContractDescriptor)) =>
|
||||
Some(contractInfo)
|
||||
case Some(_) | None => None
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.bitcoins.gui.dlc.dialog
|
||||
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.MultiNonceContractInfo
|
||||
import org.bitcoins.core.currency.Satoshis
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.NumericContractDescriptor
|
||||
import org.bitcoins.core.protocol.dlc.{
|
||||
DLCPayoutCurve,
|
||||
OutcomePayoutPoint,
|
||||
|
@ -22,9 +22,10 @@ import scala.util.{Failure, Success, Try}
|
|||
|
||||
object InitNumericContractDialog {
|
||||
|
||||
def showAndWait(parentWindow: Window): Option[MultiNonceContractInfo] = {
|
||||
def showAndWait(
|
||||
parentWindow: Window): Option[(Satoshis, NumericContractDescriptor)] = {
|
||||
val dialog =
|
||||
new Dialog[Option[MultiNonceContractInfo]]() {
|
||||
new Dialog[Option[(Satoshis, NumericContractDescriptor)]]() {
|
||||
initOwner(parentWindow)
|
||||
title = "Initialize Demo Oracle"
|
||||
headerText = "Enter contract interpolation points"
|
||||
|
@ -151,9 +152,8 @@ object InitNumericContractDialog {
|
|||
onAction = _ => addRoundingRow()
|
||||
}
|
||||
|
||||
def getContractInfo: Try[MultiNonceContractInfo] = {
|
||||
def getContractInfo: Try[(Satoshis, NumericContractDescriptor)] = {
|
||||
Try {
|
||||
val base = baseTF.text.value.toInt
|
||||
val numDigits = numDigitsTF.text.value.toInt
|
||||
val totalCollateral = Satoshis(totalCollateralTF.text.value.toLong)
|
||||
|
||||
|
@ -186,11 +186,10 @@ object InitNumericContractDialog {
|
|||
require(sorted == outcomesValuePoints, "Must be sorted by outcome")
|
||||
|
||||
val func = DLCPayoutCurve(outcomesValuePoints)
|
||||
MultiNonceContractInfo(func,
|
||||
base,
|
||||
numDigits,
|
||||
totalCollateral,
|
||||
RoundingIntervals(roundingIntervalsStarts))
|
||||
(totalCollateral,
|
||||
NumericContractDescriptor(func,
|
||||
numDigits,
|
||||
RoundingIntervals(roundingIntervalsStarts)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,13 +273,12 @@ object InitNumericContractDialog {
|
|||
onAction = _ => {
|
||||
getContractInfo match {
|
||||
case Failure(_) => ()
|
||||
case Success(contractInfo) =>
|
||||
DLCPlotUtil.plotCETsWithOriginalCurve(
|
||||
contractInfo.base,
|
||||
contractInfo.numDigits,
|
||||
contractInfo.outcomeValueFunc,
|
||||
contractInfo.totalCollateral,
|
||||
getRoundingIntervals)
|
||||
case Success((totalCollateral, descriptor)) =>
|
||||
DLCPlotUtil.plotCETsWithOriginalCurve(base = 2,
|
||||
descriptor.numDigits,
|
||||
descriptor.outcomeValueFunc,
|
||||
totalCollateral,
|
||||
getRoundingIntervals)
|
||||
()
|
||||
}
|
||||
}
|
||||
|
@ -314,8 +312,11 @@ object InitNumericContractDialog {
|
|||
} else None
|
||||
|
||||
dialog.showAndWait() match {
|
||||
case Some(Some(contractInfo: MultiNonceContractInfo)) =>
|
||||
Some(contractInfo)
|
||||
case Some(
|
||||
Some(
|
||||
(totalCollateral: Satoshis,
|
||||
descriptor: NumericContractDescriptor))) =>
|
||||
Some((totalCollateral, descriptor))
|
||||
case Some(_) | None => None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,10 +26,8 @@ class OfferDLCDialog
|
|||
}
|
||||
|
||||
CreateDLCOffer(
|
||||
oracle = OracleAnnouncementV0TLV.fromHex(
|
||||
readStringFromNode(inputs(oracleAnnouncementStr))),
|
||||
contractInfo =
|
||||
ContractInfoTLV.fromHex(readStringFromNode(inputs(contractInfoStr))),
|
||||
ContractInfoV0TLV.fromHex(readStringFromNode(inputs(contractInfoStr))),
|
||||
collateral = Satoshis(BigInt(readStringFromNode(inputs(collateralStr)))),
|
||||
feeRateOpt = feeRate,
|
||||
locktime = UInt32(BigInt(readStringFromNode(inputs(locktimeStr)))),
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package org.bitcoins.gui.dlc.dialog
|
||||
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.{
|
||||
MultiNonceContractInfo,
|
||||
SingleNonceContractInfo
|
||||
EnumContractDescriptor,
|
||||
NumericContractDescriptor
|
||||
}
|
||||
import org.bitcoins.core.protocol.dlc.{DLCPayoutCurve, DLCStatus}
|
||||
import org.bitcoins.gui.GlobalData
|
||||
|
@ -184,28 +184,27 @@ object ViewDLCDialog {
|
|||
add(node, columnIndex = 1, rowIndex = row)
|
||||
|
||||
row += 1
|
||||
status.contractInfo match {
|
||||
case _: SingleNonceContractInfo => ()
|
||||
case MultiNonceContractInfo(outcomeValueFunc,
|
||||
base,
|
||||
numDigits,
|
||||
totalCollateral,
|
||||
roundingIntervals) =>
|
||||
status.contractInfo.contractDescriptor match {
|
||||
case _: EnumContractDescriptor => ()
|
||||
case NumericContractDescriptor(outcomeValueFunc,
|
||||
numDigits,
|
||||
roundingIntervals) =>
|
||||
val previewGraphButton: Button = new Button("Preview Graph") {
|
||||
onAction = _ => {
|
||||
|
||||
val payoutCurve = if (status.isInitiator) {
|
||||
outcomeValueFunc
|
||||
} else {
|
||||
DLCPayoutCurve(outcomeValueFunc.points.map { point =>
|
||||
point.copy(payout = totalCollateral.toLong - point.payout)
|
||||
point.copy(payout =
|
||||
status.totalCollateral.satoshis.toLong - point.payout)
|
||||
})
|
||||
}
|
||||
DLCPlotUtil.plotCETsWithOriginalCurve(base,
|
||||
numDigits,
|
||||
payoutCurve,
|
||||
totalCollateral,
|
||||
roundingIntervals)
|
||||
DLCPlotUtil.plotCETsWithOriginalCurve(
|
||||
base = 2,
|
||||
numDigits,
|
||||
payoutCurve,
|
||||
status.contractInfo.totalCollateral,
|
||||
roundingIntervals)
|
||||
()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -806,14 +806,12 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
|
|||
Vector("ffbbcde836cee437a2fa4ef7db1ea3d79ca71c0c821d2a197dda51bc6534f562",
|
||||
"e770f42c578084a4a096ce1085f7fe508f8d908d2c5e6e304b2c3eab9bc973ea")
|
||||
|
||||
val contractInfo = SingleNonceContractInfo.fromStringVec(
|
||||
val contractDesc = EnumContractDescriptor.fromStringVec(
|
||||
Vector(
|
||||
(contractInfoDigests.head, Satoshis(5)),
|
||||
(contractInfoDigests.last, Satoshis(4))
|
||||
))
|
||||
|
||||
val contractInfoTLV = contractInfo.toTLV
|
||||
|
||||
val contractMaturity = 1580323752
|
||||
val contractTimeout = 1581323752
|
||||
|
||||
|
@ -859,11 +857,13 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
|
|||
val announcementTLV = OracleAnnouncementV0TLV(
|
||||
"fdd8249426cbca0e5366f6688fd837a83d3fe34d103f8d88a3bdc40d648e47e43c6f70a7e65fb85d5de46779604b541ebe74d06b3c316446a6f97fcd23d6de8e1d7b9451f74577f8cab8361962ce642a8da4b1f48f8813ed243203cb50ebba45c789abf0fdd8223000015b0fb6b85a9badee0a826349822db7412f79c71efdd903eac94a10ee10d6e4425fe3da00fdd80604000101620161")
|
||||
|
||||
val oracleInfo = SingleNonceOracleInfo(announcementTLV.publicKey,
|
||||
announcementTLV.eventTLV.nonces.head)
|
||||
val oracleInfo = EnumSingleOracleInfo(announcementTLV)
|
||||
|
||||
val contractInfo = ContractInfo(contractDesc, oracleInfo)
|
||||
val contractInfoTLV = contractInfo.toTLV
|
||||
|
||||
val offer = DLCOffer(
|
||||
OracleAndContractInfo(oracleInfo, contractInfo),
|
||||
contractInfo,
|
||||
dummyDLCKeys,
|
||||
Satoshis(2500),
|
||||
Vector(fundingInput, fundingInput),
|
||||
|
@ -874,14 +874,12 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
|
|||
|
||||
"create a dlc offer" in {
|
||||
(mockWalletApi
|
||||
.createDLCOffer(_: OracleInfo,
|
||||
_: ContractInfoTLV,
|
||||
.createDLCOffer(_: ContractInfoV0TLV,
|
||||
_: Satoshis,
|
||||
_: Option[FeeUnit],
|
||||
_: UInt32,
|
||||
_: UInt32))
|
||||
.expects(
|
||||
oracleInfo,
|
||||
contractInfoTLV,
|
||||
Satoshis(2500),
|
||||
Some(SatoshisPerVirtualByte(Satoshis.one)),
|
||||
|
@ -894,7 +892,6 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
|
|||
ServerCommand(
|
||||
"createdlcoffer",
|
||||
Arr(
|
||||
Str(announcementTLV.hex),
|
||||
Str(contractInfoTLV.hex),
|
||||
Num(2500),
|
||||
Num(1),
|
||||
|
|
|
@ -628,8 +628,7 @@ object GetDLC extends ServerJsonModels {
|
|||
}
|
||||
|
||||
case class CreateDLCOffer(
|
||||
announcement: OracleAnnouncementTLV,
|
||||
contractInfoTLV: ContractInfoTLV,
|
||||
contractInfoTLV: ContractInfoV0TLV,
|
||||
collateral: Satoshis,
|
||||
feeRateOpt: Option[SatoshisPerVirtualByte],
|
||||
locktime: UInt32,
|
||||
|
@ -640,16 +639,14 @@ object CreateDLCOffer extends ServerJsonModels {
|
|||
def fromJsArr(jsArr: ujson.Arr): Try[CreateDLCOffer] = {
|
||||
|
||||
jsArr.arr.toList match {
|
||||
case announcementJs :: contractInfoJs :: collateralJs :: feeRateOptJs :: locktimeJs :: refundLTJs :: Nil =>
|
||||
case contractInfoJs :: collateralJs :: feeRateOptJs :: locktimeJs :: refundLTJs :: Nil =>
|
||||
Try {
|
||||
val announcement = jsToOracleAnnouncementTLV(announcementJs)
|
||||
val contractInfoTLV = jsToContractInfoTLV(contractInfoJs)
|
||||
val collateral = jsToSatoshis(collateralJs)
|
||||
val feeRate = jsToSatoshisPerVirtualByteOpt(feeRateOptJs)
|
||||
val locktime = jsToUInt32(locktimeJs)
|
||||
val refundLT = jsToUInt32(refundLTJs)
|
||||
CreateDLCOffer(announcement,
|
||||
contractInfoTLV,
|
||||
CreateDLCOffer(contractInfoTLV,
|
||||
collateral,
|
||||
feeRate,
|
||||
locktime,
|
||||
|
@ -1215,10 +1212,10 @@ trait ServerJsonModels {
|
|||
"Expected an OracleAnnouncementTLV as a hex string")
|
||||
}
|
||||
|
||||
def jsToContractInfoTLV(js: Value): ContractInfoTLV =
|
||||
def jsToContractInfoTLV(js: Value): ContractInfoV0TLV =
|
||||
js match {
|
||||
case str: Str =>
|
||||
ContractInfoTLV(str.value)
|
||||
ContractInfoV0TLV(str.value)
|
||||
case _: Value =>
|
||||
throw Value.InvalidData(js, "Expected a ContractInfo as a hex string")
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import org.bitcoins.commons.serializers.Picklers._
|
|||
import org.bitcoins.core.api.wallet.db.SpendingInfoDb
|
||||
import org.bitcoins.core.currency._
|
||||
import org.bitcoins.core.protocol.tlv._
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.OracleInfo
|
||||
import org.bitcoins.core.protocol.transaction.Transaction
|
||||
import org.bitcoins.core.wallet.utxo.{AddressLabelTagType, TxoState}
|
||||
import org.bitcoins.crypto.NetworkElement
|
||||
|
@ -19,10 +18,8 @@ import org.bitcoins.wallet.config.WalletAppConfig
|
|||
import ujson._
|
||||
import upickle.default._
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
import java.nio.file.Files
|
||||
|
||||
import java.time.Instant
|
||||
import scala.concurrent.Future
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
|
@ -263,23 +260,25 @@ case class WalletRoutes(wallet: AnyDLCHDWalletApi)(implicit
|
|||
case Failure(exception) =>
|
||||
reject(ValidationRejection("failure", Some(exception)))
|
||||
case Success(
|
||||
CreateDLCOffer(announcement,
|
||||
contractInfo,
|
||||
CreateDLCOffer(contractInfo,
|
||||
collateral,
|
||||
feeRateOpt,
|
||||
locktime,
|
||||
refundLT)) =>
|
||||
complete {
|
||||
if (!announcement.validateSignature) {
|
||||
val announcements = contractInfo.oracleInfo match {
|
||||
case OracleInfoV0TLV(announcement) => Vector(announcement)
|
||||
case OracleInfoV1TLV(announcements) => announcements
|
||||
case OracleInfoV2TLV(announcements, _) => announcements
|
||||
}
|
||||
if (!announcements.forall(_.validateSignature)) {
|
||||
throw new RuntimeException(
|
||||
s"Received Oracle announcement with invalid signature! ${announcement.hex}")
|
||||
s"Received Oracle announcement with invalid signature! ${announcements
|
||||
.map(_.hex)}")
|
||||
}
|
||||
|
||||
val oracleInfo = OracleInfo.fromOracleAnnouncement(announcement)
|
||||
|
||||
wallet
|
||||
.createDLCOffer(oracleInfo,
|
||||
contractInfo,
|
||||
.createDLCOffer(contractInfo,
|
||||
collateral,
|
||||
feeRateOpt,
|
||||
locktime,
|
||||
|
|
|
@ -37,7 +37,7 @@ class DLCMessageTest extends BitcoinSAsyncTest {
|
|||
it must "not allow a negative collateral for a DLCOffer" in {
|
||||
assertThrows[IllegalArgumentException](
|
||||
DLCOffer(
|
||||
OracleAndContractInfo(OracleInfo.dummy, ContractInfo.empty),
|
||||
ContractInfo.dummy,
|
||||
DLCPublicKeys(dummyPubKey, dummyAddress),
|
||||
Satoshis(-1),
|
||||
Vector.empty,
|
||||
|
|
|
@ -21,7 +21,6 @@ class DLCStatusTest extends BitcoinSAsyncTest {
|
|||
DLCStatus.Offered(offer.paramHash,
|
||||
isInit,
|
||||
offer.tempContractId,
|
||||
offer.oracleInfo,
|
||||
offer.contractInfo,
|
||||
offer.timeouts,
|
||||
offer.feeRate,
|
||||
|
@ -48,7 +47,6 @@ class DLCStatusTest extends BitcoinSAsyncTest {
|
|||
isInit,
|
||||
offer.tempContractId,
|
||||
contractId,
|
||||
offer.oracleInfo,
|
||||
offer.contractInfo,
|
||||
offer.timeouts,
|
||||
offer.feeRate,
|
||||
|
@ -76,7 +74,6 @@ class DLCStatusTest extends BitcoinSAsyncTest {
|
|||
isInit,
|
||||
offer.tempContractId,
|
||||
contractId,
|
||||
offer.oracleInfo,
|
||||
offer.contractInfo,
|
||||
offer.timeouts,
|
||||
offer.feeRate,
|
||||
|
@ -105,7 +102,6 @@ class DLCStatusTest extends BitcoinSAsyncTest {
|
|||
isInit,
|
||||
offer.tempContractId,
|
||||
contractId,
|
||||
offer.oracleInfo,
|
||||
offer.contractInfo,
|
||||
offer.timeouts,
|
||||
offer.feeRate,
|
||||
|
@ -135,7 +131,6 @@ class DLCStatusTest extends BitcoinSAsyncTest {
|
|||
isInit,
|
||||
offer.tempContractId,
|
||||
contractId,
|
||||
offer.oracleInfo,
|
||||
offer.contractInfo,
|
||||
offer.timeouts,
|
||||
offer.feeRate,
|
||||
|
@ -173,7 +168,6 @@ class DLCStatusTest extends BitcoinSAsyncTest {
|
|||
isInit,
|
||||
offer.tempContractId,
|
||||
contractId,
|
||||
offer.oracleInfo,
|
||||
offer.contractInfo,
|
||||
offer.timeouts,
|
||||
offer.feeRate,
|
||||
|
@ -214,7 +208,6 @@ class DLCStatusTest extends BitcoinSAsyncTest {
|
|||
isInit,
|
||||
offer.tempContractId,
|
||||
contractId,
|
||||
offer.oracleInfo,
|
||||
offer.contractInfo,
|
||||
offer.timeouts,
|
||||
offer.feeRate,
|
||||
|
@ -250,7 +243,6 @@ class DLCStatusTest extends BitcoinSAsyncTest {
|
|||
isInit,
|
||||
offer.tempContractId,
|
||||
contractId,
|
||||
offer.oracleInfo,
|
||||
offer.contractInfo,
|
||||
offer.timeouts,
|
||||
offer.feeRate,
|
||||
|
|
|
@ -19,19 +19,38 @@ sealed trait DLCMessage
|
|||
object DLCMessage {
|
||||
|
||||
def calcParamHash(
|
||||
oracleInfo: OracleInfo,
|
||||
contractInfo: ContractInfo,
|
||||
timeouts: DLCTimeouts): Sha256DigestBE = {
|
||||
CryptoUtil
|
||||
.sha256(oracleInfo.bytes ++ contractInfo.bytes ++ timeouts.bytes)
|
||||
.sha256(contractInfo.bytes ++ timeouts.bytes)
|
||||
.flip
|
||||
}
|
||||
|
||||
sealed trait OracleInfo extends TLVSerializable[OracleInfoTLV] {
|
||||
def pubKey: SchnorrPublicKey
|
||||
sealed trait OracleInfo extends TLVSerializable[OracleInfoTLV]
|
||||
|
||||
sealed trait EnumOracleInfo extends OracleInfo
|
||||
sealed trait NumericOracleInfo extends OracleInfo
|
||||
|
||||
object OracleInfo
|
||||
extends TLVDeserializable[OracleInfoTLV, OracleInfo](OracleInfoTLV) {
|
||||
|
||||
override def fromTLV(tlv: OracleInfoTLV): OracleInfo = {
|
||||
tlv match {
|
||||
case tlv: OracleInfoV0TLV => SingleOracleInfo.fromTLV(tlv)
|
||||
case tlv: OracleInfoV1TLV => ExactMultiOracleInfo.fromTLV(tlv)
|
||||
case tlv: OracleInfoV2TLV => NumericMultiOracleInfo.fromTLV(tlv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait SingleOracleInfo
|
||||
extends OracleInfo
|
||||
with TLVSerializable[OracleInfoV0TLV] {
|
||||
def announcement: OracleAnnouncementTLV
|
||||
def publicKey: SchnorrPublicKey = announcement.publicKey
|
||||
|
||||
/** The oracle's pre-committed nonces, in the correct order */
|
||||
def nonces: Vector[SchnorrNonce]
|
||||
def nonces: Vector[SchnorrNonce] = announcement.eventTLV.nonces
|
||||
|
||||
/** The order of the given sigs should correspond to the given outcome. */
|
||||
def verifySigs(
|
||||
|
@ -42,16 +61,42 @@ object DLCMessage {
|
|||
* This point is used for adaptor signing.
|
||||
*/
|
||||
def sigPoint(outcome: DLCOutcomeType): ECPublicKey = {
|
||||
pubKey.computeSigPoint(outcome.serialized, nonces)
|
||||
publicKey.computeSigPoint(outcome.serialized, nonces)
|
||||
}
|
||||
|
||||
override def toTLV: OracleInfoV0TLV = OracleInfoV0TLV(announcement)
|
||||
}
|
||||
|
||||
object SingleOracleInfo
|
||||
extends TLVDeserializable[OracleInfoV0TLV, SingleOracleInfo](
|
||||
OracleInfoV0TLV) {
|
||||
|
||||
def apply(announcement: OracleAnnouncementTLV): SingleOracleInfo = {
|
||||
announcement.eventTLV.eventDescriptor match {
|
||||
case _: EnumEventDescriptorV0TLV =>
|
||||
EnumSingleOracleInfo(announcement)
|
||||
case _: NumericEventDescriptorTLV =>
|
||||
NumericSingleOracleInfo(announcement)
|
||||
}
|
||||
}
|
||||
|
||||
def apply(tlv: OracleInfoV0TLV): SingleOracleInfo = {
|
||||
SingleOracleInfo(tlv.announcement)
|
||||
}
|
||||
|
||||
override def fromTLV(tlv: OracleInfoV0TLV): SingleOracleInfo = {
|
||||
SingleOracleInfo(tlv)
|
||||
}
|
||||
}
|
||||
|
||||
case class SingleNonceOracleInfo(
|
||||
pubKey: SchnorrPublicKey,
|
||||
rValue: SchnorrNonce)
|
||||
extends OracleInfo
|
||||
with TLVSerializable[OracleInfoV0TLV] {
|
||||
override def nonces: Vector[SchnorrNonce] = Vector(rValue)
|
||||
case class EnumSingleOracleInfo(announcement: OracleAnnouncementTLV)
|
||||
extends SingleOracleInfo
|
||||
with EnumOracleInfo {
|
||||
require(announcement.eventTLV.eventDescriptor
|
||||
.isInstanceOf[EnumEventDescriptorV0TLV],
|
||||
s"Enum OracleInfo requires EnumEventDescriptor, $announcement")
|
||||
|
||||
val nonce: SchnorrNonce = announcement.eventTLV.nonces.head
|
||||
|
||||
override def verifySigs(
|
||||
outcome: DLCOutcomeType,
|
||||
|
@ -61,39 +106,45 @@ object DLCMessage {
|
|||
if (sigs.length != 1) {
|
||||
throw new IllegalArgumentException(
|
||||
s"Expected one signature, got $sigs")
|
||||
} else if (sigs.head.rx != rValue) {
|
||||
} else if (sigs.head.rx != nonce) {
|
||||
throw new IllegalArgumentException(
|
||||
s"Expected R value of $rValue, got ${sigs.head}")
|
||||
s"Expected R value of $nonce, got ${sigs.head}")
|
||||
} else {
|
||||
pubKey.verify(CryptoUtil
|
||||
.sha256DLCAttestation(outcome)
|
||||
.bytes,
|
||||
sigs.head)
|
||||
publicKey.verify(CryptoUtil.sha256DLCAttestation(outcome).bytes,
|
||||
sigs.head)
|
||||
}
|
||||
case UnsignedNumericOutcome(_) =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Expected EnumOutcome, got $outcome")
|
||||
}
|
||||
}
|
||||
|
||||
override def toTLV: OracleInfoV0TLV = OracleInfoV0TLV(pubKey, rValue)
|
||||
}
|
||||
|
||||
object SingleNonceOracleInfo
|
||||
extends TLVDeserializable[OracleInfoV0TLV, SingleNonceOracleInfo](
|
||||
object EnumSingleOracleInfo
|
||||
extends TLVDeserializable[OracleInfoV0TLV, EnumSingleOracleInfo](
|
||||
OracleInfoV0TLV) {
|
||||
|
||||
override def fromTLV(tlv: OracleInfoV0TLV): SingleNonceOracleInfo = {
|
||||
SingleNonceOracleInfo(tlv.pubKey, tlv.rValue)
|
||||
def dummyForKeys(
|
||||
privKey: ECPrivateKey,
|
||||
nonce: SchnorrNonce,
|
||||
events: Vector[EnumOutcome]): EnumSingleOracleInfo = {
|
||||
EnumSingleOracleInfo(
|
||||
OracleAnnouncementV0TLV
|
||||
.dummyForEventsAndKeys(privKey, nonce, events))
|
||||
}
|
||||
|
||||
override def fromTLV(tlv: OracleInfoV0TLV): EnumSingleOracleInfo = {
|
||||
EnumSingleOracleInfo(tlv.announcement)
|
||||
}
|
||||
}
|
||||
|
||||
case class MultiNonceOracleInfo(
|
||||
pubKey: SchnorrPublicKey,
|
||||
nonces: Vector[SchnorrNonce])
|
||||
extends OracleInfo
|
||||
with TLVSerializable[OracleInfoV1TLV] {
|
||||
require(nonces.nonEmpty, "Must contain positive number of nonces.")
|
||||
case class NumericSingleOracleInfo(announcement: OracleAnnouncementTLV)
|
||||
extends SingleOracleInfo
|
||||
with NumericOracleInfo {
|
||||
require(
|
||||
announcement.eventTLV.eventDescriptor
|
||||
.isInstanceOf[NumericEventDescriptorTLV],
|
||||
s"Numeric OracleInfo requires NumericEventDescriptor, $announcement")
|
||||
|
||||
override def verifySigs(
|
||||
outcome: DLCOutcomeType,
|
||||
|
@ -116,55 +167,117 @@ object DLCMessage {
|
|||
sig.rx == nonce,
|
||||
s"Unexpected nonce in ${sig.hex}, expected ${nonce.hex}")
|
||||
|
||||
result && pubKey.verify(CryptoUtil
|
||||
.sha256DLCAttestation(digit.toString)
|
||||
.bytes,
|
||||
sig)
|
||||
result && publicKey.verify(
|
||||
CryptoUtil.sha256DLCAttestation(digit.toString).bytes,
|
||||
sig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def toTLV: OracleInfoV1TLV = OracleInfoV1TLV(pubKey, nonces)
|
||||
}
|
||||
|
||||
object MultiNonceOracleInfo
|
||||
extends TLVDeserializable[OracleInfoV1TLV, MultiNonceOracleInfo](
|
||||
OracleInfoV1TLV) {
|
||||
object NumericSingleOracleInfo {
|
||||
|
||||
override def fromTLV(tlv: OracleInfoV1TLV): MultiNonceOracleInfo = {
|
||||
MultiNonceOracleInfo(tlv.pubKey, tlv.nonces)
|
||||
def dummyForKeys(
|
||||
privKey: ECPrivateKey,
|
||||
nonces: Vector[SchnorrNonce]): NumericSingleOracleInfo = {
|
||||
NumericSingleOracleInfo(
|
||||
OracleAnnouncementV0TLV.dummyForKeys(privKey, nonces))
|
||||
}
|
||||
}
|
||||
|
||||
object OracleInfo
|
||||
extends TLVDeserializable[OracleInfoTLV, OracleInfo](OracleInfoTLV) {
|
||||
sealed trait MultiOracleInfo[+T <: SingleOracleInfo]
|
||||
extends OracleInfo
|
||||
with TLVSerializable[MultiOracleInfoTLV] {
|
||||
def announcements: Vector[OracleAnnouncementTLV]
|
||||
|
||||
val dummy: OracleInfo = SingleNonceOracleInfo(
|
||||
ECPublicKey.freshPublicKey.schnorrPublicKey,
|
||||
ECPublicKey.freshPublicKey.schnorrNonce)
|
||||
// Override this with a val to invoke requirements
|
||||
def singleOracleInfos: Vector[T]
|
||||
}
|
||||
|
||||
def fromOracleAnnouncement(
|
||||
announcement: OracleAnnouncementTLV): OracleInfo = {
|
||||
announcement.eventTLV.eventDescriptor match {
|
||||
case _: EnumEventDescriptorV0TLV | _: RangeEventDescriptorV0TLV =>
|
||||
require(announcement.eventTLV.nonces.size == 1)
|
||||
SingleNonceOracleInfo(announcement.publicKey,
|
||||
announcement.eventTLV.nonces.head)
|
||||
case _: DigitDecompositionEventDescriptorV0TLV =>
|
||||
MultiNonceOracleInfo(announcement.publicKey,
|
||||
announcement.eventTLV.nonces)
|
||||
sealed trait ExactMultiOracleInfo[+T <: SingleOracleInfo]
|
||||
extends MultiOracleInfo[T]
|
||||
with TLVSerializable[OracleInfoV1TLV] {
|
||||
override def toTLV: OracleInfoV1TLV = OracleInfoV1TLV(announcements)
|
||||
}
|
||||
|
||||
object ExactMultiOracleInfo
|
||||
extends TLVDeserializable[
|
||||
OracleInfoV1TLV,
|
||||
ExactMultiOracleInfo[SingleOracleInfo]](OracleInfoV1TLV) {
|
||||
|
||||
def apply(tlv: OracleInfoV1TLV): ExactMultiOracleInfo[SingleOracleInfo] = {
|
||||
tlv.oracles.head.eventTLV.eventDescriptor match {
|
||||
case _: EnumEventDescriptorV0TLV => EnumMultiOracleInfo(tlv.oracles)
|
||||
case _: NumericEventDescriptorTLV =>
|
||||
NumericExactMultiOracleInfo(tlv.oracles)
|
||||
}
|
||||
}
|
||||
|
||||
override def fromTLV(tlv: OracleInfoTLV): OracleInfo = {
|
||||
tlv match {
|
||||
case tlv: OracleInfoV0TLV => SingleNonceOracleInfo.fromTLV(tlv)
|
||||
case tlv: OracleInfoV1TLV => MultiNonceOracleInfo.fromTLV(tlv)
|
||||
}
|
||||
override def fromTLV(
|
||||
tlv: OracleInfoV1TLV): ExactMultiOracleInfo[SingleOracleInfo] = {
|
||||
ExactMultiOracleInfo(tlv)
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait ContractInfo extends TLVSerializable[ContractInfoTLV] {
|
||||
case class EnumMultiOracleInfo(announcements: Vector[OracleAnnouncementTLV])
|
||||
extends ExactMultiOracleInfo[EnumSingleOracleInfo]
|
||||
with EnumOracleInfo {
|
||||
|
||||
override val singleOracleInfos: Vector[EnumSingleOracleInfo] =
|
||||
announcements.map(EnumSingleOracleInfo.apply)
|
||||
}
|
||||
|
||||
case class NumericExactMultiOracleInfo(
|
||||
announcements: Vector[OracleAnnouncementTLV])
|
||||
extends ExactMultiOracleInfo[NumericSingleOracleInfo]
|
||||
with NumericOracleInfo {
|
||||
|
||||
val singleOracleInfos: Vector[NumericSingleOracleInfo] =
|
||||
announcements.map(NumericSingleOracleInfo.apply)
|
||||
}
|
||||
|
||||
case class NumericMultiOracleInfo(
|
||||
announcements: Vector[OracleAnnouncementTLV],
|
||||
maxErrorExp: Int,
|
||||
minFailExp: Int,
|
||||
maximizeCoverage: Boolean)
|
||||
extends MultiOracleInfo[NumericSingleOracleInfo]
|
||||
with TLVSerializable[OracleInfoV2TLV]
|
||||
with NumericOracleInfo {
|
||||
|
||||
override val singleOracleInfos: Vector[NumericSingleOracleInfo] =
|
||||
announcements.map(NumericSingleOracleInfo.apply)
|
||||
|
||||
override def toTLV: OracleInfoV2TLV = {
|
||||
OracleInfoV2TLV(
|
||||
announcements,
|
||||
OracleParamsV0TLV(maxErrorExp, minFailExp, maximizeCoverage))
|
||||
}
|
||||
}
|
||||
|
||||
object NumericMultiOracleInfo
|
||||
extends TLVDeserializable[OracleInfoV2TLV, NumericMultiOracleInfo](
|
||||
OracleInfoV2TLV) {
|
||||
|
||||
def apply(
|
||||
announcements: Vector[OracleAnnouncementTLV],
|
||||
params: OracleParamsTLV): NumericMultiOracleInfo = {
|
||||
params match {
|
||||
case OracleParamsV0TLV(maxErrorExp, minFailExp, maximizeCoverage) =>
|
||||
NumericMultiOracleInfo(announcements,
|
||||
maxErrorExp,
|
||||
minFailExp,
|
||||
maximizeCoverage)
|
||||
}
|
||||
}
|
||||
|
||||
override def fromTLV(tlv: OracleInfoV2TLV): NumericMultiOracleInfo = {
|
||||
NumericMultiOracleInfo(tlv.oracles, tlv.params)
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait ContractDescriptor
|
||||
extends TLVSerializable[ContractDescriptorTLV] {
|
||||
|
||||
/** Returns the counter-party's ContractInfo corresponding to this one.
|
||||
*
|
||||
|
@ -176,32 +289,30 @@ object DLCMessage {
|
|||
* could lead to an off-by-one after rounding so that the sum above gives TC-1.
|
||||
* In this example, only the offerer's ContractInfo should be used.
|
||||
*/
|
||||
def flip(totalCollateral: Satoshis): ContractInfo
|
||||
def allOutcomes: Vector[DLCOutcomeType]
|
||||
def apply(outcome: DLCOutcomeType): Satoshis
|
||||
|
||||
/** Returns the maximum payout this party could win from this contract */
|
||||
def max: Satoshis
|
||||
def flip(totalCollateral: Satoshis): ContractDescriptor
|
||||
}
|
||||
|
||||
case class SingleNonceContractInfo(
|
||||
outcomeValueMap: Vector[(EnumOutcome, Satoshis)])
|
||||
extends ContractInfo
|
||||
with TLVSerializable[ContractInfoV0TLV]
|
||||
with SeqWrapper[(EnumOutcome, Satoshis)] {
|
||||
object ContractDescriptor
|
||||
extends TLVDeserializable[ContractDescriptorTLV, ContractDescriptor](
|
||||
ContractDescriptorTLV) {
|
||||
|
||||
override def apply(outcome: DLCOutcomeType): Satoshis = {
|
||||
outcome match {
|
||||
case outcome: EnumOutcome =>
|
||||
outcomeValueMap
|
||||
.find(_._1 == outcome)
|
||||
.map(_._2)
|
||||
.getOrElse(throw new IllegalArgumentException(
|
||||
s"No value found for key $outcome"))
|
||||
case UnsignedNumericOutcome(_) =>
|
||||
throw new IllegalArgumentException(s"Expected EnumOutcome: $outcome")
|
||||
val empty: ContractDescriptor = EnumContractDescriptor(
|
||||
Vector(EnumOutcome("") -> Satoshis.zero))
|
||||
|
||||
override def fromTLV(tlv: ContractDescriptorTLV): ContractDescriptor = {
|
||||
tlv match {
|
||||
case tlv: ContractDescriptorV0TLV => EnumContractDescriptor.fromTLV(tlv)
|
||||
case tlv: ContractDescriptorV1TLV =>
|
||||
NumericContractDescriptor.fromTLV(tlv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class EnumContractDescriptor(
|
||||
outcomeValueMap: Vector[(EnumOutcome, Satoshis)])
|
||||
extends ContractDescriptor
|
||||
with TLVSerializable[ContractDescriptorV0TLV]
|
||||
with SeqWrapper[(EnumOutcome, Satoshis)] {
|
||||
|
||||
override def wrapped: Vector[(EnumOutcome, Satoshis)] = outcomeValueMap
|
||||
|
||||
|
@ -209,34 +320,32 @@ object DLCMessage {
|
|||
|
||||
def values: Vector[Satoshis] = outcomeValueMap.map(_._2)
|
||||
|
||||
override def allOutcomes: Vector[DLCOutcomeType] = keys
|
||||
|
||||
override def max: Satoshis = values.maxBy(_.toLong)
|
||||
|
||||
override def toTLV: ContractInfoV0TLV =
|
||||
ContractInfoV0TLV(outcomeValueMap.map {
|
||||
override def toTLV: ContractDescriptorV0TLV =
|
||||
ContractDescriptorV0TLV(outcomeValueMap.map {
|
||||
case (outcome, amt) => outcome.outcome -> amt
|
||||
})
|
||||
|
||||
override def flip(totalCollateral: Satoshis): SingleNonceContractInfo = {
|
||||
SingleNonceContractInfo(outcomeValueMap.map {
|
||||
override def flip(totalCollateral: Satoshis): EnumContractDescriptor = {
|
||||
EnumContractDescriptor(outcomeValueMap.map {
|
||||
case (hash, amt) => (hash, (totalCollateral - amt).satoshis)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
object SingleNonceContractInfo
|
||||
extends TLVDeserializable[ContractInfoV0TLV, SingleNonceContractInfo](
|
||||
ContractInfoV0TLV) {
|
||||
object EnumContractDescriptor
|
||||
extends TLVDeserializable[
|
||||
ContractDescriptorV0TLV,
|
||||
EnumContractDescriptor](ContractDescriptorV0TLV) {
|
||||
|
||||
def fromStringVec(
|
||||
vec: Vector[(String, Satoshis)]): SingleNonceContractInfo = {
|
||||
SingleNonceContractInfo(vec.map {
|
||||
vec: Vector[(String, Satoshis)]): EnumContractDescriptor = {
|
||||
EnumContractDescriptor(vec.map {
|
||||
case (str, amt) => EnumOutcome(str) -> amt
|
||||
})
|
||||
}
|
||||
|
||||
override def fromTLV(tlv: ContractInfoV0TLV): SingleNonceContractInfo = {
|
||||
override def fromTLV(
|
||||
tlv: ContractDescriptorV0TLV): EnumContractDescriptor = {
|
||||
fromStringVec(tlv.outcomes)
|
||||
}
|
||||
}
|
||||
|
@ -244,145 +353,124 @@ object DLCMessage {
|
|||
/** Contains a deterministically compressed set of outcomes computed from
|
||||
* a given payout curve.
|
||||
*/
|
||||
case class MultiNonceContractInfo(
|
||||
case class NumericContractDescriptor(
|
||||
outcomeValueFunc: DLCPayoutCurve,
|
||||
base: Int,
|
||||
numDigits: Int,
|
||||
totalCollateral: Satoshis,
|
||||
roundingIntervals: RoundingIntervals)
|
||||
extends ContractInfo
|
||||
with TLVSerializable[ContractInfoV1TLV] {
|
||||
extends ContractDescriptor
|
||||
with TLVSerializable[ContractDescriptorV1TLV] {
|
||||
|
||||
/** Vector is always the most significant digits */
|
||||
lazy val outcomeVec: Vector[(Vector[Int], Satoshis)] =
|
||||
CETCalculator.computeCETs(base,
|
||||
numDigits,
|
||||
outcomeValueFunc,
|
||||
totalCollateral,
|
||||
roundingIntervals)
|
||||
|
||||
override def apply(outcome: DLCOutcomeType): Satoshis = {
|
||||
outcome match {
|
||||
case UnsignedNumericOutcome(digits) =>
|
||||
CETCalculator.searchForPrefix(digits, outcomeVec)(_._1) match {
|
||||
case Some((_, amt)) => amt
|
||||
case None =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Unrecognized outcome: $digits")
|
||||
}
|
||||
case EnumOutcome(_) =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Expected UnsignedNumericOutcome: $outcome")
|
||||
}
|
||||
}
|
||||
|
||||
override lazy val allOutcomes: Vector[DLCOutcomeType] =
|
||||
outcomeVec.map { case (outcome, _) => UnsignedNumericOutcome(outcome) }
|
||||
|
||||
override val max: Satoshis = totalCollateral
|
||||
|
||||
override def flip(totalCollateral: Satoshis): MultiNonceContractInfo = {
|
||||
require(
|
||||
totalCollateral == this.totalCollateral,
|
||||
s"Input total collateral ($totalCollateral) did not match ${this.totalCollateral}")
|
||||
override def flip(totalCollateral: Satoshis): NumericContractDescriptor = {
|
||||
|
||||
val flippedFunc = DLCPayoutCurve(outcomeValueFunc.points.map { point =>
|
||||
point.copy(payout = totalCollateral.toLong - point.payout)
|
||||
})
|
||||
|
||||
MultiNonceContractInfo(
|
||||
NumericContractDescriptor(
|
||||
flippedFunc,
|
||||
base,
|
||||
numDigits,
|
||||
totalCollateral,
|
||||
roundingIntervals
|
||||
)
|
||||
}
|
||||
|
||||
override lazy val toTLV: ContractInfoV1TLV = {
|
||||
ContractInfoV1TLV(base,
|
||||
numDigits,
|
||||
totalCollateral,
|
||||
outcomeValueFunc.toTLV,
|
||||
roundingIntervals.toTLV)
|
||||
override def toTLV: ContractDescriptorV1TLV = {
|
||||
ContractDescriptorV1TLV(numDigits,
|
||||
outcomeValueFunc.toTLV,
|
||||
roundingIntervals.toTLV)
|
||||
}
|
||||
}
|
||||
|
||||
object MultiNonceContractInfo
|
||||
extends TLVDeserializable[ContractInfoV1TLV, MultiNonceContractInfo](
|
||||
ContractInfoV1TLV) {
|
||||
object NumericContractDescriptor
|
||||
extends TLVDeserializable[
|
||||
ContractDescriptorV1TLV,
|
||||
NumericContractDescriptor](ContractDescriptorV1TLV) {
|
||||
|
||||
override def fromTLV(tlv: ContractInfoV1TLV): MultiNonceContractInfo = {
|
||||
MultiNonceContractInfo(DLCPayoutCurve.fromTLV(tlv.payoutFunction),
|
||||
tlv.base,
|
||||
tlv.numDigits,
|
||||
tlv.totalCollateral,
|
||||
RoundingIntervals.fromTLV(tlv.roundingIntervals))
|
||||
override def fromTLV(
|
||||
tlv: ContractDescriptorV1TLV): NumericContractDescriptor = {
|
||||
NumericContractDescriptor(
|
||||
DLCPayoutCurve.fromTLV(tlv.payoutFunction),
|
||||
tlv.numDigits,
|
||||
RoundingIntervals.fromTLV(tlv.roundingIntervals)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
object ContractInfo
|
||||
extends TLVDeserializable[ContractInfoTLV, ContractInfo](
|
||||
ContractInfoTLV) {
|
||||
case class ContractDescriptorWithCollateral(
|
||||
totalCollateral: Satoshis,
|
||||
contractDescriptor: ContractDescriptor) {
|
||||
|
||||
val empty: ContractInfo = SingleNonceContractInfo(
|
||||
Vector(EnumOutcome("") -> Satoshis.zero))
|
||||
/** Vector is always the most significant digits */
|
||||
lazy val outcomeVecOpt: Option[Vector[(Vector[Int], Satoshis)]] = {
|
||||
contractDescriptor match {
|
||||
case _: EnumContractDescriptor => None
|
||||
case descriptor: NumericContractDescriptor =>
|
||||
val outcomeVec = CETCalculator.computeCETs(
|
||||
base = 2,
|
||||
descriptor.numDigits,
|
||||
descriptor.outcomeValueFunc,
|
||||
totalCollateral,
|
||||
descriptor.roundingIntervals)
|
||||
|
||||
override def fromTLV(tlv: ContractInfoTLV): ContractInfo = {
|
||||
tlv match {
|
||||
case tlv: ContractInfoV0TLV => SingleNonceContractInfo.fromTLV(tlv)
|
||||
case tlv: ContractInfoV1TLV => MultiNonceContractInfo.fromTLV(tlv)
|
||||
Some(outcomeVec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class OracleAndContractInfo(
|
||||
oracleInfo: OracleInfo,
|
||||
offerContractInfo: ContractInfo,
|
||||
totalCollateral: Satoshis) {
|
||||
(oracleInfo, offerContractInfo) match {
|
||||
case (_: SingleNonceOracleInfo, info: SingleNonceContractInfo) =>
|
||||
require(
|
||||
info.max <= totalCollateral,
|
||||
s"Cannot have payout larger than totalCollateral ($totalCollateral): $info")
|
||||
case (_: MultiNonceOracleInfo, info: MultiNonceContractInfo) =>
|
||||
require(
|
||||
info.totalCollateral == totalCollateral,
|
||||
s"Expected total collateral of $totalCollateral, got ${info.totalCollateral}")
|
||||
case (_: OracleInfo, _: ContractInfo) =>
|
||||
throw new IllegalArgumentException(
|
||||
s"All infos must be for the same kind of outcome: $this")
|
||||
}
|
||||
|
||||
def verifySigs(
|
||||
outcome: DLCOutcomeType,
|
||||
sigs: Vector[SchnorrDigitalSignature]): Boolean = {
|
||||
oracleInfo.verifySigs(outcome, sigs)
|
||||
}
|
||||
|
||||
def findOutcome(
|
||||
sigs: Vector[SchnorrDigitalSignature]): Option[DLCOutcomeType] = {
|
||||
offerContractInfo match {
|
||||
case SingleNonceContractInfo(_) =>
|
||||
allOutcomes.find(verifySigs(_, sigs))
|
||||
case MultiNonceContractInfo(_, base, _, _, _) =>
|
||||
val digitsSigned = sigs.map { sig =>
|
||||
(0 until base)
|
||||
.find { possibleDigit =>
|
||||
oracleInfo.pubKey.verify(
|
||||
CryptoUtil
|
||||
.sha256DLCAttestation(possibleDigit.toString)
|
||||
.bytes,
|
||||
sig)
|
||||
}
|
||||
.getOrElse(throw new IllegalArgumentException(
|
||||
s"Signature $sig does not match any digit 0-${base - 1}"))
|
||||
lazy val allOutcomes: Vector[DLCOutcomeType] = {
|
||||
contractDescriptor match {
|
||||
case descriptor: EnumContractDescriptor => descriptor.keys
|
||||
case _: NumericContractDescriptor =>
|
||||
outcomeVecOpt.get.map {
|
||||
case (outcome, _) => UnsignedNumericOutcome(outcome)
|
||||
}
|
||||
|
||||
CETCalculator.searchForNumericOutcome(digitsSigned, allOutcomes)
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the maximum payout this party could win from this contract */
|
||||
val max: Satoshis = contractDescriptor match {
|
||||
case descriptor: EnumContractDescriptor =>
|
||||
descriptor.values.maxBy(_.toLong)
|
||||
case _: NumericContractDescriptor => totalCollateral
|
||||
}
|
||||
}
|
||||
|
||||
case class ContractInfo(
|
||||
totalCollateral: Satoshis,
|
||||
contractDescriptor: ContractDescriptor,
|
||||
oracleInfo: OracleInfo)
|
||||
extends TLVSerializable[ContractInfoV0TLV] {
|
||||
|
||||
override def toTLV: ContractInfoV0TLV = {
|
||||
ContractInfoV0TLV(totalCollateral,
|
||||
contractDescriptor.toTLV,
|
||||
oracleInfo.toTLV)
|
||||
}
|
||||
|
||||
val descriptorWithCollateral: ContractDescriptorWithCollateral =
|
||||
ContractDescriptorWithCollateral(totalCollateral, contractDescriptor)
|
||||
|
||||
def outcomeVecOpt: Option[Vector[(Vector[Int], Satoshis)]] =
|
||||
descriptorWithCollateral.outcomeVecOpt
|
||||
|
||||
def allOutcomes: Vector[DLCOutcomeType] =
|
||||
descriptorWithCollateral.allOutcomes
|
||||
|
||||
def max: Satoshis = descriptorWithCollateral.max
|
||||
|
||||
val descriptorAndInfo: Either[
|
||||
(EnumContractDescriptor, EnumOracleInfo),
|
||||
(NumericContractDescriptor, NumericOracleInfo)] =
|
||||
(contractDescriptor, oracleInfo) match {
|
||||
case (contractDescriptor: EnumContractDescriptor,
|
||||
oracleInfo: EnumOracleInfo) =>
|
||||
Left((contractDescriptor, oracleInfo))
|
||||
case (contractDescriptor: NumericContractDescriptor,
|
||||
oracleInfo: NumericOracleInfo) =>
|
||||
Right((contractDescriptor, oracleInfo))
|
||||
case (_: ContractDescriptor, _: OracleInfo) =>
|
||||
throw new IllegalArgumentException(
|
||||
s"All infos must be for the same kind of outcome: $this")
|
||||
}
|
||||
|
||||
lazy val outcomeMap: Map[
|
||||
DLCOutcomeType,
|
||||
(ECPublicKey, Satoshis, Satoshis)] = {
|
||||
|
@ -390,15 +478,83 @@ object DLCMessage {
|
|||
HashMap.newBuilder[DLCOutcomeType, (ECPublicKey, Satoshis, Satoshis)]
|
||||
|
||||
allOutcomes.foreach { msg =>
|
||||
val offerPayout = offerContractInfo(msg)
|
||||
val offerPayout = apply(msg)
|
||||
val acceptPayout = (totalCollateral - offerPayout).satoshis
|
||||
val adaptorPoint =
|
||||
oracleInfo.asInstanceOf[SingleOracleInfo].sigPoint(msg) // FIXME
|
||||
|
||||
builder.+=(msg -> (oracleInfo.sigPoint(msg), offerPayout, acceptPayout))
|
||||
builder.+=(msg -> (adaptorPoint, offerPayout, acceptPayout))
|
||||
}
|
||||
|
||||
builder.result()
|
||||
}
|
||||
|
||||
def apply(outcome: DLCOutcomeType): Satoshis = {
|
||||
descriptorAndInfo match {
|
||||
case Left((EnumContractDescriptor(outcomeValueMap), _)) =>
|
||||
outcome match {
|
||||
case outcome: EnumOutcome =>
|
||||
outcomeValueMap
|
||||
.find(_._1 == outcome)
|
||||
.map(_._2)
|
||||
.getOrElse(throw new IllegalArgumentException(
|
||||
s"No value found for key $outcome"))
|
||||
case UnsignedNumericOutcome(_) =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Expected EnumOutcome: $outcome")
|
||||
}
|
||||
case Right((_, _)) =>
|
||||
outcome match {
|
||||
case UnsignedNumericOutcome(digits) =>
|
||||
CETCalculator.searchForPrefix(digits, outcomeVecOpt.get)(
|
||||
_._1) match {
|
||||
case Some((_, amt)) => amt
|
||||
case None =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Unrecognized outcome: $digits")
|
||||
}
|
||||
case EnumOutcome(_) =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Expected UnsignedNumericOutcome: $outcome")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def verifySigs(
|
||||
outcome: DLCOutcomeType,
|
||||
sigs: Vector[SchnorrDigitalSignature]): Boolean = {
|
||||
oracleInfo
|
||||
.asInstanceOf[SingleOracleInfo]
|
||||
.verifySigs(outcome, sigs) // FIXME
|
||||
}
|
||||
|
||||
def findOutcome(
|
||||
sigs: Vector[SchnorrDigitalSignature]): Option[DLCOutcomeType] = {
|
||||
contractDescriptor match {
|
||||
case _: EnumContractDescriptor =>
|
||||
allOutcomes.find(verifySigs(_, sigs))
|
||||
case _: NumericContractDescriptor =>
|
||||
val base = 2
|
||||
val digitsSigned = sigs.map { sig =>
|
||||
(0 until base)
|
||||
.find { possibleDigit =>
|
||||
// FIXME
|
||||
oracleInfo
|
||||
.asInstanceOf[SingleOracleInfo]
|
||||
.publicKey
|
||||
.verify(CryptoUtil
|
||||
.sha256DLCAttestation(possibleDigit.toString)
|
||||
.bytes,
|
||||
sig)
|
||||
}
|
||||
.getOrElse(throw new IllegalArgumentException(
|
||||
s"Signature $sig does not match any digit 0-${base - 1}"))
|
||||
}
|
||||
|
||||
CETCalculator.searchForNumericOutcome(digitsSigned, allOutcomes)
|
||||
}
|
||||
}
|
||||
|
||||
def resultOfOutcome(
|
||||
outcome: DLCOutcomeType): (ECPublicKey, Satoshis, Satoshis) = {
|
||||
outcomeMap(outcome)
|
||||
|
@ -408,9 +564,6 @@ object DLCMessage {
|
|||
resultOfOutcome(outcome)._1
|
||||
}
|
||||
|
||||
lazy val allOutcomes: Vector[DLCOutcomeType] =
|
||||
offerContractInfo.allOutcomes
|
||||
|
||||
/** Returns the payouts for the signature as (toOffer, toAccept) */
|
||||
def getPayouts(
|
||||
sigs: Vector[SchnorrDigitalSignature]): (Satoshis, Satoshis) = {
|
||||
|
@ -432,40 +585,51 @@ object DLCMessage {
|
|||
|
||||
def updateOnAccept(
|
||||
newTotalCollateral: Satoshis,
|
||||
negotiationFields: DLCAccept.NegotiationFields): OracleAndContractInfo = {
|
||||
negotiationFields: DLCAccept.NegotiationFields): ContractInfo = {
|
||||
if (newTotalCollateral == totalCollateral) {
|
||||
this
|
||||
} else {
|
||||
offerContractInfo match {
|
||||
case _: SingleNonceContractInfo =>
|
||||
contractDescriptor match {
|
||||
case _: EnumContractDescriptor =>
|
||||
if (negotiationFields != DLCAccept.NoNegotiationFields) {
|
||||
throw new IllegalArgumentException(
|
||||
s"Cannot have rounding intervals for single nonce contract: $negotiationFields")
|
||||
}
|
||||
this.copy(totalCollateral = newTotalCollateral)
|
||||
case info: MultiNonceContractInfo =>
|
||||
case descriptor: NumericContractDescriptor =>
|
||||
val newRoundingIntervals = negotiationFields match {
|
||||
case DLCAccept.NegotiationFieldsV1(acceptRoundingIntervals) =>
|
||||
info.roundingIntervals.minRoundingWith(acceptRoundingIntervals)
|
||||
case DLCAccept.NoNegotiationFields => info.roundingIntervals
|
||||
descriptor.roundingIntervals.minRoundingWith(
|
||||
acceptRoundingIntervals)
|
||||
case DLCAccept.NoNegotiationFields => descriptor.roundingIntervals
|
||||
}
|
||||
this.copy(offerContractInfo =
|
||||
info.copy(totalCollateral = newTotalCollateral,
|
||||
roundingIntervals = newRoundingIntervals),
|
||||
totalCollateral = newTotalCollateral)
|
||||
this.copy(
|
||||
totalCollateral = newTotalCollateral,
|
||||
contractDescriptor =
|
||||
descriptor.copy(roundingIntervals = newRoundingIntervals))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object OracleAndContractInfo {
|
||||
object ContractInfo
|
||||
extends TLVDeserializable[ContractInfoV0TLV, ContractInfo](
|
||||
ContractInfoV0TLV) {
|
||||
|
||||
lazy val dummy: ContractInfo = fromTLV(ContractInfoV0TLV.dummy)
|
||||
|
||||
override def fromTLV(tlv: ContractInfoV0TLV): ContractInfo = {
|
||||
ContractInfo(tlv.totalCollateral,
|
||||
ContractDescriptor.fromTLV(tlv.contractDescriptor),
|
||||
OracleInfo.fromTLV(tlv.oracleInfo))
|
||||
}
|
||||
|
||||
def apply(
|
||||
oracleInfo: OracleInfo,
|
||||
offerContractInfo: ContractInfo): OracleAndContractInfo = {
|
||||
OracleAndContractInfo(oracleInfo,
|
||||
offerContractInfo,
|
||||
offerContractInfo.max)
|
||||
enumDescriptor: EnumContractDescriptor,
|
||||
enumOracleInfo: EnumOracleInfo): ContractInfo = {
|
||||
ContractInfo(totalCollateral = enumDescriptor.values.maxBy(_.toLong),
|
||||
enumDescriptor,
|
||||
enumOracleInfo)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -486,7 +650,7 @@ object DLCMessage {
|
|||
/**
|
||||
* The initiating party starts the protocol by sending an offer message to the other party.
|
||||
*
|
||||
* @param oracleAndContractInfo The oracle public key and R point(s) to use to build the CETs as
|
||||
* @param contractInfo The oracle public key and R point(s) to use to build the CETs as
|
||||
* well as meta information to identify the oracle to be used in the contract,
|
||||
* and a map to be used to create CETs.
|
||||
* @param pubKeys The relevant public keys that the initiator will be using
|
||||
|
@ -497,7 +661,7 @@ object DLCMessage {
|
|||
* @param timeouts The set of timeouts for the CETs
|
||||
*/
|
||||
case class DLCOffer(
|
||||
oracleAndContractInfo: OracleAndContractInfo,
|
||||
contractInfo: ContractInfo,
|
||||
pubKeys: DLCPublicKeys,
|
||||
totalCollateral: Satoshis,
|
||||
fundingInputs: Vector[DLCFundingInput],
|
||||
|
@ -506,11 +670,10 @@ object DLCMessage {
|
|||
timeouts: DLCTimeouts)
|
||||
extends DLCSetupMessage {
|
||||
|
||||
val oracleInfo: OracleInfo = oracleAndContractInfo.oracleInfo
|
||||
val contractInfo: ContractInfo = oracleAndContractInfo.offerContractInfo
|
||||
val oracleInfo: OracleInfo = contractInfo.oracleInfo
|
||||
val contractDescriptor: ContractDescriptor = contractInfo.contractDescriptor
|
||||
|
||||
lazy val paramHash: Sha256DigestBE =
|
||||
calcParamHash(oracleInfo, contractInfo, timeouts)
|
||||
lazy val paramHash: Sha256DigestBE = calcParamHash(contractInfo, timeouts)
|
||||
|
||||
val tempContractId: Sha256Digest =
|
||||
CryptoUtil.sha256(toMessage.bytes)
|
||||
|
@ -523,7 +686,6 @@ object DLCMessage {
|
|||
contractFlags = 0x00,
|
||||
chainHash = chainHash,
|
||||
contractInfo.toTLV,
|
||||
oracleInfo.toTLV,
|
||||
fundingPubKey = pubKeys.fundingKey,
|
||||
payoutSPK = pubKeys.payoutAddress.scriptPubKey,
|
||||
totalCollateralSatoshis = totalCollateral,
|
||||
|
@ -546,10 +708,9 @@ object DLCMessage {
|
|||
val network = Networks.fromChainHash(offer.chainHash.flip)
|
||||
|
||||
val contractInfo = ContractInfo.fromTLV(offer.contractInfo)
|
||||
val oracleInfo = OracleInfo.fromTLV(offer.oracleInfo)
|
||||
|
||||
DLCOffer(
|
||||
oracleAndContractInfo = OracleAndContractInfo(oracleInfo, contractInfo),
|
||||
contractInfo = contractInfo,
|
||||
pubKeys = DLCPublicKeys(
|
||||
offer.fundingPubKey,
|
||||
BitcoinAddress.fromScriptPubKey(offer.payoutSPK, network)),
|
||||
|
@ -693,12 +854,7 @@ object DLCMessage {
|
|||
accept: DLCAcceptTLV,
|
||||
network: NetworkParameters,
|
||||
contractInfo: ContractInfo): DLCAccept = {
|
||||
contractInfo match {
|
||||
case info: SingleNonceContractInfo =>
|
||||
fromTLV(accept, network, info.keys)
|
||||
case multi: MultiNonceContractInfo =>
|
||||
fromTLV(accept, network, multi.allOutcomes)
|
||||
}
|
||||
fromTLV(accept, network, contractInfo.allOutcomes)
|
||||
}
|
||||
|
||||
def fromTLV(accept: DLCAcceptTLV, offer: DLCOffer): DLCAccept = {
|
||||
|
@ -764,18 +920,10 @@ object DLCMessage {
|
|||
}
|
||||
|
||||
def fromTLV(sign: DLCSignTLV, offer: DLCOffer): DLCSign = {
|
||||
offer.contractInfo match {
|
||||
case info: SingleNonceContractInfo =>
|
||||
fromTLV(sign,
|
||||
offer.pubKeys.fundingKey,
|
||||
info.keys,
|
||||
offer.fundingInputs.map(_.outPoint))
|
||||
case multi: MultiNonceContractInfo =>
|
||||
fromTLV(sign,
|
||||
offer.pubKeys.fundingKey,
|
||||
multi.allOutcomes,
|
||||
offer.fundingInputs.map(_.outPoint))
|
||||
}
|
||||
fromTLV(sign,
|
||||
offer.pubKeys.fundingKey,
|
||||
offer.contractInfo.allOutcomes,
|
||||
offer.fundingInputs.map(_.outPoint))
|
||||
}
|
||||
|
||||
def fromMessage(sign: LnMessage[DLCSignTLV], offer: DLCOffer): DLCSign = {
|
||||
|
|
|
@ -25,8 +25,8 @@ sealed trait DLCStatus {
|
|||
def isInitiator: Boolean
|
||||
def state: DLCState
|
||||
def tempContractId: Sha256Digest
|
||||
def oracleInfo: OracleInfo
|
||||
def contractInfo: ContractInfo
|
||||
def oracleInfo: OracleInfo = contractInfo.oracleInfo
|
||||
def timeouts: DLCTimeouts
|
||||
def feeRate: FeeUnit
|
||||
def totalCollateral: CurrencyUnit
|
||||
|
@ -59,7 +59,6 @@ object DLCStatus {
|
|||
paramHash: Sha256DigestBE,
|
||||
isInitiator: Boolean,
|
||||
tempContractId: Sha256Digest,
|
||||
oracleInfo: OracleInfo,
|
||||
contractInfo: ContractInfo,
|
||||
timeouts: DLCTimeouts,
|
||||
feeRate: FeeUnit,
|
||||
|
@ -74,7 +73,6 @@ object DLCStatus {
|
|||
isInitiator: Boolean,
|
||||
tempContractId: Sha256Digest,
|
||||
contractId: ByteVector,
|
||||
oracleInfo: OracleInfo,
|
||||
contractInfo: ContractInfo,
|
||||
timeouts: DLCTimeouts,
|
||||
feeRate: FeeUnit,
|
||||
|
@ -89,7 +87,6 @@ object DLCStatus {
|
|||
isInitiator: Boolean,
|
||||
tempContractId: Sha256Digest,
|
||||
contractId: ByteVector,
|
||||
oracleInfo: OracleInfo,
|
||||
contractInfo: ContractInfo,
|
||||
timeouts: DLCTimeouts,
|
||||
feeRate: FeeUnit,
|
||||
|
@ -104,7 +101,6 @@ object DLCStatus {
|
|||
isInitiator: Boolean,
|
||||
tempContractId: Sha256Digest,
|
||||
contractId: ByteVector,
|
||||
oracleInfo: OracleInfo,
|
||||
contractInfo: ContractInfo,
|
||||
timeouts: DLCTimeouts,
|
||||
feeRate: FeeUnit,
|
||||
|
@ -120,7 +116,6 @@ object DLCStatus {
|
|||
isInitiator: Boolean,
|
||||
tempContractId: Sha256Digest,
|
||||
contractId: ByteVector,
|
||||
oracleInfo: OracleInfo,
|
||||
contractInfo: ContractInfo,
|
||||
timeouts: DLCTimeouts,
|
||||
feeRate: FeeUnit,
|
||||
|
@ -136,7 +131,6 @@ object DLCStatus {
|
|||
isInitiator: Boolean,
|
||||
tempContractId: Sha256Digest,
|
||||
contractId: ByteVector,
|
||||
oracleInfo: OracleInfo,
|
||||
contractInfo: ContractInfo,
|
||||
timeouts: DLCTimeouts,
|
||||
feeRate: FeeUnit,
|
||||
|
@ -155,7 +149,6 @@ object DLCStatus {
|
|||
isInitiator: Boolean,
|
||||
tempContractId: Sha256Digest,
|
||||
contractId: ByteVector,
|
||||
oracleInfo: OracleInfo,
|
||||
contractInfo: ContractInfo,
|
||||
timeouts: DLCTimeouts,
|
||||
feeRate: FeeUnit,
|
||||
|
@ -175,7 +168,6 @@ object DLCStatus {
|
|||
isInitiator: Boolean,
|
||||
tempContractId: Sha256Digest,
|
||||
contractId: ByteVector,
|
||||
oracleInfo: OracleInfo,
|
||||
contractInfo: ContractInfo,
|
||||
timeouts: DLCTimeouts,
|
||||
feeRate: FeeUnit,
|
||||
|
@ -244,8 +236,9 @@ object DLCStatus {
|
|||
require(cetSigs.size == 2,
|
||||
s"There must be only 2 signatures, got ${cetSigs.size}")
|
||||
|
||||
val oraclePubKey = offer.oracleInfo.pubKey
|
||||
val rVals = offer.oracleInfo.nonces
|
||||
val oraclePubKey =
|
||||
offer.oracleInfo.asInstanceOf[SingleOracleInfo].publicKey // FIXME
|
||||
val rVals = offer.oracleInfo.asInstanceOf[SingleOracleInfo].nonces // FIXME
|
||||
|
||||
def aggregateR(numSigs: Int): SchnorrNonce = {
|
||||
rVals.take(numSigs).map(_.publicKey).reduce(_.add(_)).schnorrNonce
|
||||
|
@ -296,8 +289,8 @@ object DLCStatus {
|
|||
val outcomeValues = wCET.outputs.map(_.value).sorted
|
||||
val totalCollateral = offer.totalCollateral + accept.totalCollateral
|
||||
|
||||
val possibleMessages = offer.contractInfo match {
|
||||
case DLCMessage.SingleNonceContractInfo(outcomeValueMap) =>
|
||||
val possibleMessages = offer.contractInfo.contractDescriptor match {
|
||||
case DLCMessage.EnumContractDescriptor(outcomeValueMap) =>
|
||||
outcomeValueMap
|
||||
.filter {
|
||||
case (_, amt) =>
|
||||
|
@ -306,8 +299,8 @@ object DLCStatus {
|
|||
.sorted == outcomeValues
|
||||
}
|
||||
.map(_._1)
|
||||
case info: DLCMessage.MultiNonceContractInfo =>
|
||||
info.outcomeVec
|
||||
case _: DLCMessage.NumericContractDescriptor =>
|
||||
offer.contractInfo.outcomeVecOpt.get
|
||||
.filter {
|
||||
case (_, amt) =>
|
||||
val amts = Vector(amt, totalCollateral - amt)
|
||||
|
@ -350,7 +343,7 @@ object DLCStatus {
|
|||
val sigOpt = outcomeSigs.find {
|
||||
case (outcome, adaptorSig) =>
|
||||
val possibleOracleSig = sigFromMsgAndSigs(outcome, adaptorSig, cetSig)
|
||||
val sigPoint = offer.oracleAndContractInfo.sigPointForOutcome(outcome)
|
||||
val sigPoint = offer.contractInfo.sigPointForOutcome(outcome)
|
||||
possibleOracleSig.sig.getPublicKey == sigPoint
|
||||
}
|
||||
|
||||
|
|
|
@ -155,6 +155,8 @@ object TLV extends TLVParentFactory[TLV] {
|
|||
OracleEventV0TLV,
|
||||
RoundingIntervalsV0TLV,
|
||||
PayoutFunctionV0TLV,
|
||||
OracleParamsV0TLV,
|
||||
ContractInfoV0TLV,
|
||||
FundingInputV0TLV,
|
||||
CETSignaturesV0TLV,
|
||||
FundingSignaturesV0TLV,
|
||||
|
@ -162,7 +164,7 @@ object TLV extends TLVParentFactory[TLV] {
|
|||
DLCAcceptTLV,
|
||||
DLCSignTLV
|
||||
) ++ EventDescriptorTLV.allFactories ++
|
||||
ContractInfoTLV.allFactories ++
|
||||
ContractDescriptorTLV.allFactories ++
|
||||
OracleInfoTLV.allFactories ++
|
||||
OracleAnnouncementTLV.allFactories ++
|
||||
NegotiationFieldsTLV.allFactories
|
||||
|
@ -806,26 +808,58 @@ object OracleAnnouncementV0TLV extends TLVFactory[OracleAnnouncementV0TLV] {
|
|||
UInt32.zero,
|
||||
EnumEventDescriptorV0TLV.dummy,
|
||||
"dummy")
|
||||
val sig = priv.schnorrSign(CryptoUtil.sha256(event.bytes).bytes)
|
||||
val sig =
|
||||
priv.schnorrSign(CryptoUtil.sha256DLCAnnouncement(event.bytes).bytes)
|
||||
|
||||
OracleAnnouncementV0TLV(sig, priv.schnorrPublicKey, event)
|
||||
}
|
||||
|
||||
def dummyForEventsAndKeys(
|
||||
privKey: ECPrivateKey,
|
||||
nonce: SchnorrNonce,
|
||||
events: Vector[EnumOutcome]): OracleAnnouncementTLV = {
|
||||
val event = OracleEventV0TLV(
|
||||
Vector(nonce),
|
||||
UInt32.zero,
|
||||
EnumEventDescriptorV0TLV(events.map(outcome => outcome.outcome)),
|
||||
"dummy")
|
||||
val sig =
|
||||
privKey.schnorrSign(CryptoUtil.sha256DLCAnnouncement(event.bytes).bytes)
|
||||
|
||||
OracleAnnouncementV0TLV(sig, privKey.schnorrPublicKey, event)
|
||||
}
|
||||
|
||||
def dummyForKeys(
|
||||
privKey: ECPrivateKey,
|
||||
nonces: Vector[SchnorrNonce]): OracleAnnouncementTLV = {
|
||||
val eventDescriptor = DigitDecompositionEventDescriptorV0TLV(UInt16(2),
|
||||
isSigned =
|
||||
false,
|
||||
nonces.length,
|
||||
"dummy",
|
||||
Int32.zero)
|
||||
val event = OracleEventV0TLV(nonces, UInt32.zero, eventDescriptor, "dummy")
|
||||
val sig =
|
||||
privKey.schnorrSign(CryptoUtil.sha256DLCAnnouncement(event.bytes).bytes)
|
||||
|
||||
OracleAnnouncementV0TLV(sig, privKey.schnorrPublicKey, event)
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait ContractInfoTLV extends TLV
|
||||
sealed trait ContractDescriptorTLV extends TLV
|
||||
|
||||
object ContractInfoTLV extends TLVParentFactory[ContractInfoTLV] {
|
||||
object ContractDescriptorTLV extends TLVParentFactory[ContractDescriptorTLV] {
|
||||
|
||||
val allFactories: Vector[TLVFactory[ContractInfoTLV]] =
|
||||
Vector(ContractInfoV0TLV, ContractInfoV1TLV)
|
||||
val allFactories: Vector[TLVFactory[ContractDescriptorTLV]] =
|
||||
Vector(ContractDescriptorV0TLV, ContractDescriptorV1TLV)
|
||||
|
||||
override def typeName: String = "ContractInfoTLV"
|
||||
override def typeName: String = "ContractDescriptorTLV"
|
||||
}
|
||||
|
||||
/** @see https://github.com/discreetlogcontracts/dlcspecs/blob/master/Messaging.md#version-0-contract_info */
|
||||
case class ContractInfoV0TLV(outcomes: Vector[(String, Satoshis)])
|
||||
extends ContractInfoTLV {
|
||||
override val tpe: BigSizeUInt = ContractInfoV0TLV.tpe
|
||||
case class ContractDescriptorV0TLV(outcomes: Vector[(String, Satoshis)])
|
||||
extends ContractDescriptorTLV {
|
||||
override val tpe: BigSizeUInt = ContractDescriptorV0TLV.tpe
|
||||
|
||||
override val value: ByteVector = {
|
||||
bigSizePrefixedList[(String, Satoshis)](
|
||||
|
@ -838,10 +872,10 @@ case class ContractInfoV0TLV(outcomes: Vector[(String, Satoshis)])
|
|||
}
|
||||
}
|
||||
|
||||
object ContractInfoV0TLV extends TLVFactory[ContractInfoV0TLV] {
|
||||
object ContractDescriptorV0TLV extends TLVFactory[ContractDescriptorV0TLV] {
|
||||
override val tpe: BigSizeUInt = BigSizeUInt(42768)
|
||||
|
||||
override def fromTLVValue(value: ByteVector): ContractInfoV0TLV = {
|
||||
override def fromTLVValue(value: ByteVector): ContractDescriptorV0TLV = {
|
||||
val iter = ValueIterator(value)
|
||||
|
||||
val outcomes = iter.takeBigSizePrefixedList { () =>
|
||||
|
@ -851,7 +885,7 @@ object ContractInfoV0TLV extends TLVFactory[ContractInfoV0TLV] {
|
|||
outcome -> amt
|
||||
}
|
||||
|
||||
ContractInfoV0TLV(outcomes)
|
||||
ContractDescriptorV0TLV(outcomes)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -951,41 +985,31 @@ object PayoutFunctionV0TLV extends TLVFactory[PayoutFunctionV0TLV] {
|
|||
}
|
||||
}
|
||||
|
||||
case class ContractInfoV1TLV(
|
||||
base: Int,
|
||||
case class ContractDescriptorV1TLV(
|
||||
numDigits: Int,
|
||||
totalCollateral: Satoshis,
|
||||
payoutFunction: PayoutFunctionV0TLV,
|
||||
roundingIntervals: RoundingIntervalsV0TLV)
|
||||
extends ContractInfoTLV {
|
||||
override val tpe: BigSizeUInt = ContractInfoV1TLV.tpe
|
||||
extends ContractDescriptorTLV {
|
||||
override val tpe: BigSizeUInt = ContractDescriptorV1TLV.tpe
|
||||
|
||||
override val value: ByteVector = {
|
||||
BigSizeUInt(base).bytes ++
|
||||
UInt16(numDigits).bytes ++
|
||||
satBytes(totalCollateral) ++
|
||||
UInt16(numDigits).bytes ++
|
||||
payoutFunction.bytes ++
|
||||
roundingIntervals.bytes
|
||||
}
|
||||
}
|
||||
|
||||
object ContractInfoV1TLV extends TLVFactory[ContractInfoV1TLV] {
|
||||
object ContractDescriptorV1TLV extends TLVFactory[ContractDescriptorV1TLV] {
|
||||
override val tpe: BigSizeUInt = BigSizeUInt(42784)
|
||||
|
||||
override def fromTLVValue(value: ByteVector): ContractInfoV1TLV = {
|
||||
override def fromTLVValue(value: ByteVector): ContractDescriptorV1TLV = {
|
||||
val iter = ValueIterator(value)
|
||||
|
||||
val base = iter.takeBigSize()
|
||||
val numDigits = iter.takeU16()
|
||||
val totalCollateral = iter.takeSats()
|
||||
val payoutFunction = iter.take(PayoutFunctionV0TLV)
|
||||
val roundingIntervals = iter.take(RoundingIntervalsV0TLV)
|
||||
|
||||
ContractInfoV1TLV(base.toInt,
|
||||
numDigits.toInt,
|
||||
totalCollateral,
|
||||
payoutFunction,
|
||||
roundingIntervals)
|
||||
ContractDescriptorV1TLV(numDigits.toInt, payoutFunction, roundingIntervals)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -994,17 +1018,17 @@ sealed trait OracleInfoTLV extends TLV
|
|||
object OracleInfoTLV extends TLVParentFactory[OracleInfoTLV] {
|
||||
|
||||
override val allFactories: Vector[TLVFactory[OracleInfoTLV]] =
|
||||
Vector(OracleInfoV0TLV, OracleInfoV1TLV)
|
||||
Vector(OracleInfoV0TLV, OracleInfoV1TLV, OracleInfoV2TLV)
|
||||
|
||||
override def typeName: String = "OracleInfoTLV"
|
||||
}
|
||||
|
||||
case class OracleInfoV0TLV(pubKey: SchnorrPublicKey, rValue: SchnorrNonce)
|
||||
case class OracleInfoV0TLV(announcement: OracleAnnouncementTLV)
|
||||
extends OracleInfoTLV {
|
||||
override val tpe: BigSizeUInt = OracleInfoV0TLV.tpe
|
||||
|
||||
override val value: ByteVector = {
|
||||
pubKey.bytes ++ rValue.bytes
|
||||
announcement.bytes
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1014,21 +1038,20 @@ object OracleInfoV0TLV extends TLVFactory[OracleInfoV0TLV] {
|
|||
override def fromTLVValue(value: ByteVector): OracleInfoV0TLV = {
|
||||
val iter = ValueIterator(value)
|
||||
|
||||
val pubKey = iter.take(SchnorrPublicKey, 32)
|
||||
val rValue = iter.take(SchnorrNonce, 32)
|
||||
val announcement = iter.take(OracleAnnouncementTLV)
|
||||
|
||||
OracleInfoV0TLV(pubKey, rValue)
|
||||
OracleInfoV0TLV(announcement)
|
||||
}
|
||||
}
|
||||
|
||||
case class OracleInfoV1TLV(
|
||||
pubKey: SchnorrPublicKey,
|
||||
nonces: Vector[SchnorrNonce])
|
||||
extends OracleInfoTLV {
|
||||
sealed trait MultiOracleInfoTLV extends OracleInfoTLV
|
||||
|
||||
case class OracleInfoV1TLV(oracles: Vector[OracleAnnouncementTLV])
|
||||
extends MultiOracleInfoTLV {
|
||||
override val tpe: BigSizeUInt = OracleInfoV1TLV.tpe
|
||||
|
||||
override val value: ByteVector = {
|
||||
pubKey.bytes ++ u16PrefixedList(nonces)
|
||||
u16PrefixedList(oracles)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1038,10 +1061,100 @@ object OracleInfoV1TLV extends TLVFactory[OracleInfoV1TLV] {
|
|||
override def fromTLVValue(value: ByteVector): OracleInfoV1TLV = {
|
||||
val iter = ValueIterator(value)
|
||||
|
||||
val pubKey = iter.take(SchnorrPublicKey, 32)
|
||||
val nonces = iter.takeU16PrefixedList(() => iter.take(SchnorrNonce, 32))
|
||||
val oracles =
|
||||
iter.takeU16PrefixedList(() => iter.take(OracleAnnouncementTLV))
|
||||
|
||||
OracleInfoV1TLV(pubKey, nonces)
|
||||
OracleInfoV1TLV(oracles)
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait OracleParamsTLV extends TLV
|
||||
|
||||
case class OracleParamsV0TLV(
|
||||
maxErrorExp: Int,
|
||||
minFailExp: Int,
|
||||
maximizeCoverage: Boolean)
|
||||
extends OracleParamsTLV {
|
||||
override val tpe: BigSizeUInt = OracleParamsV0TLV.tpe
|
||||
|
||||
override val value: ByteVector = {
|
||||
UInt16(maxErrorExp).bytes ++
|
||||
UInt16(minFailExp).bytes ++
|
||||
boolBytes(maximizeCoverage)
|
||||
}
|
||||
}
|
||||
|
||||
object OracleParamsV0TLV extends TLVFactory[OracleParamsV0TLV] {
|
||||
override val tpe: BigSizeUInt = BigSizeUInt(55338)
|
||||
|
||||
override def fromTLVValue(value: ByteVector): OracleParamsV0TLV = {
|
||||
val iter = ValueIterator(value)
|
||||
|
||||
val maxErrorExp = iter.takeU16().toInt
|
||||
val minFailExp = iter.takeU16().toInt
|
||||
val maximizeCoverage = iter.takeBoolean()
|
||||
|
||||
OracleParamsV0TLV(maxErrorExp, minFailExp, maximizeCoverage)
|
||||
}
|
||||
}
|
||||
|
||||
case class OracleInfoV2TLV(
|
||||
oracles: Vector[OracleAnnouncementTLV],
|
||||
params: OracleParamsTLV)
|
||||
extends MultiOracleInfoTLV {
|
||||
override val tpe: BigSizeUInt = OracleInfoV2TLV.tpe
|
||||
|
||||
override val value: ByteVector = {
|
||||
u16PrefixedList(oracles) ++ params.bytes
|
||||
}
|
||||
}
|
||||
|
||||
object OracleInfoV2TLV extends TLVFactory[OracleInfoV2TLV] {
|
||||
override val tpe: BigSizeUInt = BigSizeUInt(55340)
|
||||
|
||||
override def fromTLVValue(value: ByteVector): OracleInfoV2TLV = {
|
||||
val iter = ValueIterator(value)
|
||||
|
||||
val oracles =
|
||||
iter.takeU16PrefixedList(() => iter.take(OracleAnnouncementTLV))
|
||||
val params = iter.take(OracleParamsV0TLV)
|
||||
|
||||
OracleInfoV2TLV(oracles, params)
|
||||
}
|
||||
}
|
||||
|
||||
case class ContractInfoV0TLV(
|
||||
totalCollateral: Satoshis,
|
||||
contractDescriptor: ContractDescriptorTLV,
|
||||
oracleInfo: OracleInfoTLV)
|
||||
extends TLV {
|
||||
override val tpe: BigSizeUInt = ContractInfoV0TLV.tpe
|
||||
|
||||
override val value: ByteVector = {
|
||||
satBytes(totalCollateral) ++
|
||||
contractDescriptor.bytes ++
|
||||
oracleInfo.bytes
|
||||
}
|
||||
}
|
||||
|
||||
object ContractInfoV0TLV extends TLVFactory[ContractInfoV0TLV] {
|
||||
override val tpe: BigSizeUInt = BigSizeUInt(55342)
|
||||
|
||||
val dummy: ContractInfoV0TLV = {
|
||||
ContractInfoV0TLV(
|
||||
Satoshis.zero,
|
||||
ContractDescriptorV0TLV(Vector("dummy" -> Satoshis(10000))),
|
||||
OracleInfoV0TLV(OracleAnnouncementV0TLV.dummy))
|
||||
}
|
||||
|
||||
override def fromTLVValue(value: ByteVector): ContractInfoV0TLV = {
|
||||
val iter = ValueIterator(value)
|
||||
|
||||
val totalCollateral = iter.takeSats()
|
||||
val contractDescriptor = iter.take(ContractDescriptorTLV)
|
||||
val oracleInfo = iter.take(OracleInfoTLV)
|
||||
|
||||
ContractInfoV0TLV(totalCollateral, contractDescriptor, oracleInfo)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1174,8 +1287,7 @@ object FundingSignaturesV0TLV extends TLVFactory[FundingSignaturesV0TLV] {
|
|||
case class DLCOfferTLV(
|
||||
contractFlags: Byte,
|
||||
chainHash: DoubleSha256Digest,
|
||||
contractInfo: ContractInfoTLV,
|
||||
oracleInfo: OracleInfoTLV,
|
||||
contractInfo: ContractInfoV0TLV,
|
||||
fundingPubKey: ECPublicKey,
|
||||
payoutSPK: ScriptPubKey,
|
||||
totalCollateralSatoshis: Satoshis,
|
||||
|
@ -1191,7 +1303,6 @@ case class DLCOfferTLV(
|
|||
ByteVector(contractFlags) ++
|
||||
chainHash.bytes ++
|
||||
contractInfo.bytes ++
|
||||
oracleInfo.bytes ++
|
||||
fundingPubKey.bytes ++
|
||||
TLV.encodeScript(payoutSPK) ++
|
||||
satBytes(totalCollateralSatoshis) ++
|
||||
|
@ -1211,8 +1322,7 @@ object DLCOfferTLV extends TLVFactory[DLCOfferTLV] {
|
|||
|
||||
val contractFlags = iter.take(1).head
|
||||
val chainHash = iter.take(DoubleSha256Digest, 32)
|
||||
val contractInfo = iter.take(ContractInfoTLV)
|
||||
val oracleInfo = iter.take(OracleInfoTLV)
|
||||
val contractInfo = iter.take(ContractInfoV0TLV)
|
||||
val fundingPubKey = iter.take(ECPublicKey, 33)
|
||||
val payoutSPK = iter.takeSPK()
|
||||
val totalCollateralSatoshis = iter.takeSats()
|
||||
|
@ -1227,7 +1337,6 @@ object DLCOfferTLV extends TLVFactory[DLCOfferTLV] {
|
|||
contractFlags,
|
||||
chainHash,
|
||||
contractInfo,
|
||||
oracleInfo,
|
||||
fundingPubKey,
|
||||
payoutSPK,
|
||||
totalCollateralSatoshis,
|
||||
|
|
|
@ -82,13 +82,13 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg {
|
|||
val result = dlcDbManagement.migrate()
|
||||
dlcAppConfig.driver match {
|
||||
case SQLite =>
|
||||
val expected = 2
|
||||
val expected = 1
|
||||
assert(result == expected)
|
||||
val flywayInfo = dlcAppConfig.info()
|
||||
assert(flywayInfo.applied().length == expected)
|
||||
assert(flywayInfo.pending().length == 0)
|
||||
case PostgreSQL =>
|
||||
val expected = 2
|
||||
val expected = 1
|
||||
assert(result == expected)
|
||||
val flywayInfo = dlcAppConfig.info()
|
||||
|
||||
|
|
|
@ -263,9 +263,9 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) {
|
|||
.base[ContractInfo, String](_.hex, ContractInfo.fromHex)
|
||||
}
|
||||
|
||||
implicit val contractInfoTLVMapper: BaseColumnType[ContractInfoTLV] = {
|
||||
implicit val contractInfoTLVMapper: BaseColumnType[ContractInfoV0TLV] = {
|
||||
MappedColumnType
|
||||
.base[ContractInfoTLV, String](_.hex, ContractInfoTLV.fromHex)
|
||||
.base[ContractInfoV0TLV, String](_.hex, ContractInfoV0TLV.fromHex)
|
||||
}
|
||||
|
||||
implicit val dlcOutcomeTypeMapper: BaseColumnType[DLCOutcomeType] = {
|
||||
|
|
|
@ -10,9 +10,13 @@ import org.bitcoins.core.currency.{
|
|||
import org.bitcoins.core.number.{UInt16, UInt32}
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
import org.bitcoins.core.protocol.BlockStamp.BlockHeight
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.SingleNonceOracleInfo
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.{
|
||||
ContractInfo,
|
||||
EnumSingleOracleInfo
|
||||
}
|
||||
import org.bitcoins.core.protocol.dlc._
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.tlv.EnumOutcome
|
||||
import org.bitcoins.core.protocol.transaction.{
|
||||
Transaction,
|
||||
TransactionConstants,
|
||||
|
@ -305,12 +309,19 @@ class DLCClientIntegrationTest extends BitcoindRpcTest {
|
|||
|
||||
val outcomeStrs = DLCTestUtil.genOutcomes(numOutcomes)
|
||||
|
||||
val (outcomes, otherOutcomes) =
|
||||
DLCTestUtil.genContractInfos(outcomeStrs, totalInput)
|
||||
val oracleInfo = EnumSingleOracleInfo.dummyForKeys(
|
||||
oraclePrivKey,
|
||||
preCommittedR,
|
||||
outcomeStrs.map(EnumOutcome.apply))
|
||||
|
||||
val (outcomesDesc, otherOutcomesDesc) =
|
||||
DLCTestUtil.genContractDescriptors(outcomeStrs, totalInput)
|
||||
|
||||
val outcomes = ContractInfo(outcomesDesc, oracleInfo)
|
||||
val otherOutcomes = ContractInfo(otherOutcomesDesc, oracleInfo)
|
||||
|
||||
val acceptDLC = TestDLCClient(
|
||||
outcomes = outcomes,
|
||||
oracleInfo = SingleNonceOracleInfo(oraclePubKey, preCommittedR),
|
||||
isInitiator = false,
|
||||
fundingPrivKey = localFundingPrivKey,
|
||||
payoutPrivKey = localPayoutPrivKey,
|
||||
|
@ -330,7 +341,6 @@ class DLCClientIntegrationTest extends BitcoindRpcTest {
|
|||
|
||||
val offerDLC = TestDLCClient(
|
||||
outcomes = otherOutcomes,
|
||||
oracleInfo = SingleNonceOracleInfo(oraclePubKey, preCommittedR),
|
||||
isInitiator = true,
|
||||
fundingPrivKey = remoteFundingPrivKey,
|
||||
payoutPrivKey = remotePayoutPrivKey,
|
||||
|
|
|
@ -3,14 +3,9 @@ package org.bitcoins.dlc
|
|||
import org.bitcoins.core.config.RegTest
|
||||
import org.bitcoins.core.currency.{CurrencyUnit, CurrencyUnits, Satoshis}
|
||||
import org.bitcoins.core.number.{UInt16, UInt32}
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.{
|
||||
DLCSign,
|
||||
MultiNonceContractInfo,
|
||||
MultiNonceOracleInfo,
|
||||
SingleNonceOracleInfo
|
||||
}
|
||||
import org.bitcoins.core.protocol.dlc._
|
||||
import org.bitcoins.core.protocol.BlockStamp.BlockTime
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage._
|
||||
import org.bitcoins.core.protocol.dlc._
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.tlv.{
|
||||
DLCOutcomeType,
|
||||
|
@ -29,6 +24,7 @@ import org.bitcoins.dlc.testgen.{DLCTestUtil, TestDLCClient}
|
|||
import org.bitcoins.dlc.verify.DLCSignatureVerifier
|
||||
import org.bitcoins.testkit.util.{BitcoinSAsyncTest, BytesUtil}
|
||||
import org.scalatest.Assertion
|
||||
import scodec.bits.BitVector
|
||||
|
||||
import scala.concurrent.{Future, Promise}
|
||||
|
||||
|
@ -202,30 +198,38 @@ class DLCClientTest extends BitcoinSAsyncTest {
|
|||
TestDLCClient,
|
||||
TestDLCClient,
|
||||
Vector[DLCOutcomeType]) = {
|
||||
val (outcomes, remoteOutcomes, strsOrDigits) = if (!isMultiNonce) {
|
||||
val outcomeStrs = DLCTestUtil.genOutcomes(numOutcomes)
|
||||
val outcomeStrs = DLCTestUtil.genOutcomes(numOutcomes)
|
||||
val oracleInfo = if (!isMultiNonce) {
|
||||
EnumSingleOracleInfo.dummyForKeys(oraclePrivKey,
|
||||
preCommittedR,
|
||||
outcomeStrs.map(EnumOutcome.apply))
|
||||
} else {
|
||||
NumericSingleOracleInfo.dummyForKeys(oraclePrivKey,
|
||||
preCommittedRs.take(numOutcomes))
|
||||
}
|
||||
|
||||
val (outcomes, remoteOutcomes, strsOrDigits) = if (!isMultiNonce) {
|
||||
|
||||
val (localDesc, remoteDesc) =
|
||||
DLCTestUtil.genContractDescriptors(outcomeStrs, totalInput)
|
||||
val local = ContractInfo(totalInput.satoshis, localDesc, oracleInfo)
|
||||
val remote = ContractInfo(totalInput.satoshis, remoteDesc, oracleInfo)
|
||||
|
||||
val (local, remote) =
|
||||
DLCTestUtil.genContractInfos(outcomeStrs, totalInput)
|
||||
(local, remote, outcomeStrs.map(EnumOutcome.apply))
|
||||
} else {
|
||||
val (local, remote) =
|
||||
val (localDesc, remoteDesc) =
|
||||
DLCTestUtil.genMultiDigitContractInfo(numOutcomes,
|
||||
totalInput,
|
||||
numRounds = 4)
|
||||
(local, remote, local.allOutcomes)
|
||||
}
|
||||
val local = ContractInfo(totalInput.satoshis, localDesc, oracleInfo)
|
||||
val remote = ContractInfo(totalInput.satoshis, remoteDesc, oracleInfo)
|
||||
|
||||
val oracleInfo = if (!isMultiNonce) {
|
||||
SingleNonceOracleInfo(oraclePubKey, preCommittedR)
|
||||
} else {
|
||||
MultiNonceOracleInfo(oraclePubKey, preCommittedRs.take(numOutcomes))
|
||||
(local, remote, local.allOutcomes)
|
||||
}
|
||||
|
||||
// Offer is local
|
||||
val dlcOffer: TestDLCClient = TestDLCClient(
|
||||
outcomes = outcomes,
|
||||
oracleInfo = oracleInfo,
|
||||
isInitiator = true,
|
||||
fundingPrivKey = offerFundingPrivKey,
|
||||
payoutPrivKey = offerPayoutPrivKey,
|
||||
|
@ -246,7 +250,6 @@ class DLCClientTest extends BitcoinSAsyncTest {
|
|||
// Accept is remote
|
||||
val dlcAccept: TestDLCClient = TestDLCClient(
|
||||
outcomes = remoteOutcomes,
|
||||
oracleInfo = oracleInfo,
|
||||
isInitiator = false,
|
||||
fundingPrivKey = acceptFundingPrivKey,
|
||||
payoutPrivKey = acceptPayoutPrivKey,
|
||||
|
@ -380,8 +383,8 @@ class DLCClientTest extends BitcoinSAsyncTest {
|
|||
}
|
||||
} else {
|
||||
val points =
|
||||
dlcOffer.dlcTxBuilder.oracleAndContractInfo.offerContractInfo
|
||||
.asInstanceOf[MultiNonceContractInfo]
|
||||
dlcOffer.dlcTxBuilder.contractInfo.contractDescriptor
|
||||
.asInstanceOf[NumericContractDescriptor]
|
||||
.outcomeValueFunc
|
||||
.points
|
||||
val left = points(1).outcome
|
||||
|
@ -391,7 +394,7 @@ class DLCClientTest extends BitcoinSAsyncTest {
|
|||
(2 * left + right) / 3 + (outcomeIndex % (right - left) / 3)
|
||||
|
||||
val fullDigits =
|
||||
NumberUtil.decompose(outcomeNum, base = 10, numOutcomes)
|
||||
NumberUtil.decompose(outcomeNum, base = 2, numOutcomes)
|
||||
|
||||
val digits =
|
||||
CETCalculator.searchForNumericOutcome(fullDigits, outcomes) match {
|
||||
|
@ -460,15 +463,16 @@ class DLCClientTest extends BitcoinSAsyncTest {
|
|||
}
|
||||
}
|
||||
|
||||
val numDigitsToTest: Vector[Int] = Vector(2, 3, 5)
|
||||
val numDigitsToTest: Vector[Int] = Vector(4, 5, 10)
|
||||
|
||||
def runMultiNonceTests(
|
||||
exec: (Long, Int, Boolean) => Future[Assertion]): Future[Assertion] = {
|
||||
runTestsForParam(numDigitsToTest) { numDigits =>
|
||||
val randDigits = (0 until numDigits).toVector.map { _ =>
|
||||
scala.util.Random.nextInt(10)
|
||||
scala.util.Random.nextInt(2)
|
||||
}
|
||||
val num = randDigits.mkString("").toLong
|
||||
val num =
|
||||
BitVector.fromValidBin(randDigits.mkString("")).toLong(signed = false)
|
||||
|
||||
exec(num, numDigits, true)
|
||||
}
|
||||
|
@ -486,21 +490,24 @@ class DLCClientTest extends BitcoinSAsyncTest {
|
|||
val numDigits = 8
|
||||
|
||||
val randDigits = (0 until numDigits).toVector.map { _ =>
|
||||
scala.util.Random.nextInt(10)
|
||||
scala.util.Random.nextInt(2)
|
||||
}
|
||||
val num = randDigits.mkString("").toLong
|
||||
val num =
|
||||
BitVector.fromValidBin(randDigits.mkString("")).toLong(signed = false)
|
||||
|
||||
executeForCase(num, numDigits, isMultiDigit = true)
|
||||
}
|
||||
|
||||
it should "be able to construct and verify with ScriptInterpreter every tx in a DLC for the refund case" in {
|
||||
val testFs = numEnumOutcomesToTest.map { numOutcomes =>
|
||||
executeRefundCase(numOutcomes, isMultiNonce = false).flatMap { _ =>
|
||||
executeRefundCase(numOutcomes, isMultiNonce = true)
|
||||
}
|
||||
val testF1 = numEnumOutcomesToTest.map { numOutcomes =>
|
||||
executeRefundCase(numOutcomes, isMultiNonce = false)
|
||||
}
|
||||
|
||||
Future.sequence(testFs).map(_ => succeed)
|
||||
val testF2 = numDigitsToTest.map { numDigits =>
|
||||
executeRefundCase(numDigits, isMultiNonce = true)
|
||||
}
|
||||
|
||||
Future.sequence(Vector(testF1, testF2).flatten).map(_ => succeed)
|
||||
}
|
||||
|
||||
it should "all work for a 100 outcome DLC" in {
|
||||
|
@ -695,12 +702,14 @@ class DLCClientTest extends BitcoinSAsyncTest {
|
|||
it should "be able to derive aggregate oracle signature from remote CET signatures" in {
|
||||
// Larger numbers of digits make tests take too long.
|
||||
// TODO: In the future when bases other than 10 can be used try more digits with base 2
|
||||
val numDigitsToTest = Vector(2, 3)
|
||||
val numDigitsToTest = Vector(5, 9)
|
||||
runTestsForParam(numDigitsToTest) { numDigits =>
|
||||
val max = (1L << numDigits) - 1
|
||||
val outcomesToTest = 0
|
||||
.until(9)
|
||||
.toVector
|
||||
.map(num => Vector(num) ++ Vector.fill(numDigits - 1)(0))
|
||||
.map(num => (max / num.toDouble).toLong)
|
||||
.map(num => NumberUtil.decompose(num, 2, numDigits))
|
||||
|
||||
setupDLC(numDigits, isMultiDigit = true).flatMap {
|
||||
case (acceptSetup, dlcAccept, offerSetup, dlcOffer, outcomes) =>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package org.bitcoins.dlc.wallet
|
||||
|
||||
import org.bitcoins.core.currency.Satoshis
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.{
|
||||
ContractInfo,
|
||||
MultiNonceContractInfo,
|
||||
SingleNonceContractInfo
|
||||
EnumContractDescriptor,
|
||||
NumericContractDescriptor
|
||||
}
|
||||
import org.bitcoins.core.protocol.dlc.DLCState
|
||||
import org.bitcoins.core.protocol.dlc.DLCStatus.{
|
||||
|
@ -11,7 +12,6 @@ import org.bitcoins.core.protocol.dlc.DLCStatus.{
|
|||
Refunded,
|
||||
RemoteClaimed
|
||||
}
|
||||
import org.bitcoins.core.currency.Satoshis
|
||||
import org.bitcoins.core.script.interpreter.ScriptInterpreter
|
||||
import org.bitcoins.crypto.{CryptoUtil, SchnorrDigitalSignature}
|
||||
import org.bitcoins.testkit.wallet.DLCWalletUtil._
|
||||
|
@ -30,15 +30,15 @@ class DLCExecutionTest extends BitcoinSDualWalletTest {
|
|||
def getSigs(contractInfo: ContractInfo): (
|
||||
SchnorrDigitalSignature,
|
||||
SchnorrDigitalSignature) = {
|
||||
val info: SingleNonceContractInfo = contractInfo match {
|
||||
case info: SingleNonceContractInfo => info
|
||||
case _: MultiNonceContractInfo =>
|
||||
val desc: EnumContractDescriptor = contractInfo.contractDescriptor match {
|
||||
case desc: EnumContractDescriptor => desc
|
||||
case _: NumericContractDescriptor =>
|
||||
throw new IllegalArgumentException("Unexpected Contract Info")
|
||||
}
|
||||
|
||||
// Get a hash that the initiator wins for
|
||||
val initiatorWinStr =
|
||||
info
|
||||
desc
|
||||
.maxBy(_._2.toLong)
|
||||
._1
|
||||
.outcome
|
||||
|
@ -50,7 +50,7 @@ class DLCExecutionTest extends BitcoinSDualWalletTest {
|
|||
|
||||
// Get a hash that the recipient wins for
|
||||
val recipientWinStr =
|
||||
info.find(_._2 == Satoshis.zero).get._1.outcome
|
||||
desc.find(_._2 == Satoshis.zero).get._1.outcome
|
||||
val recipientWinSig = DLCWalletUtil.oraclePrivKey
|
||||
.schnorrSignWithNonce(CryptoUtil
|
||||
.sha256DLCAttestation(recipientWinStr)
|
||||
|
|
|
@ -3,8 +3,8 @@ package org.bitcoins.dlc.wallet
|
|||
import org.bitcoins.core.currency.Satoshis
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.{
|
||||
ContractInfo,
|
||||
MultiNonceContractInfo,
|
||||
SingleNonceContractInfo
|
||||
EnumContractDescriptor,
|
||||
NumericContractDescriptor
|
||||
}
|
||||
import org.bitcoins.core.protocol.dlc.DLCState
|
||||
import org.bitcoins.core.protocol.dlc.DLCStatus.{Claimed, RemoteClaimed}
|
||||
|
@ -26,14 +26,14 @@ class DLCMultiNonceExecutionTest extends BitcoinSDualWalletTest {
|
|||
def getSigs(contractInfo: ContractInfo): (
|
||||
Vector[SchnorrDigitalSignature],
|
||||
Vector[SchnorrDigitalSignature]) = {
|
||||
val multiNonceContractInfo: MultiNonceContractInfo = contractInfo match {
|
||||
case info: MultiNonceContractInfo => info
|
||||
case _: SingleNonceContractInfo =>
|
||||
contractInfo.contractDescriptor match {
|
||||
case _: NumericContractDescriptor => ()
|
||||
case _: EnumContractDescriptor =>
|
||||
throw new IllegalArgumentException("Unexpected Contract Info")
|
||||
}
|
||||
|
||||
val initiatorWinVec =
|
||||
multiNonceContractInfo.outcomeVec
|
||||
contractInfo.outcomeVecOpt.get
|
||||
.maxBy(_._2.toLong)
|
||||
._1
|
||||
|
||||
|
@ -49,7 +49,7 @@ class DLCMultiNonceExecutionTest extends BitcoinSDualWalletTest {
|
|||
}
|
||||
|
||||
val recipientWinVec =
|
||||
multiNonceContractInfo.outcomeVec.find(_._2 == Satoshis.zero).get._1
|
||||
contractInfo.outcomeVecOpt.get.find(_._2 == Satoshis.zero).get._1
|
||||
|
||||
val kValues2 = DLCWalletUtil.kValues.take(recipientWinVec.size)
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.bitcoins.dlc.wallet
|
|||
import org.bitcoins.core.currency.Satoshis
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage._
|
||||
import org.bitcoins.core.protocol.dlc._
|
||||
import org.bitcoins.core.protocol.tlv._
|
||||
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
import org.bitcoins.crypto._
|
||||
import org.bitcoins.testkit.wallet.DLCWalletUtil._
|
||||
|
@ -29,7 +30,6 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
|||
|
||||
for {
|
||||
offer <- walletA.createDLCOffer(
|
||||
offerData.oracleInfo,
|
||||
offerData.contractInfo,
|
||||
offerData.totalCollateral,
|
||||
Some(offerData.feeRate),
|
||||
|
@ -130,7 +130,6 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
|||
|
||||
for {
|
||||
offer <- walletA.createDLCOffer(
|
||||
offerData.oracleInfo,
|
||||
offerData.contractInfo.toTLV,
|
||||
offerData.totalCollateral,
|
||||
Some(offerData.feeRate),
|
||||
|
@ -226,7 +225,6 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
|||
offerData: DLCOffer = DLCWalletUtil.sampleDLCOffer): Future[DLCAccept] = {
|
||||
for {
|
||||
offer <- walletA.createDLCOffer(
|
||||
offerData.oracleInfo,
|
||||
offerData.contractInfo,
|
||||
offerData.totalCollateral,
|
||||
Some(offerData.feeRate),
|
||||
|
@ -343,23 +341,17 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
|||
|
||||
val betSize = 10000
|
||||
|
||||
lazy val contractInfo: ContractInfo =
|
||||
SingleNonceContractInfo.fromStringVec(
|
||||
val contractDescriptor: EnumContractDescriptor =
|
||||
EnumContractDescriptor.fromStringVec(
|
||||
Vector(winStr -> Satoshis(betSize),
|
||||
loseStr -> Satoshis.zero,
|
||||
drawStr -> Satoshis(betSize / 2)))
|
||||
|
||||
val oraclePubKey = SchnorrPublicKey(
|
||||
"bd25c9f473eb5d37e5299b86f2d7b625d01ae0441da428cc65cf19e1c6021db6")
|
||||
val oracleNonce = SchnorrNonce(
|
||||
"d535016b6d837587ac6375d0044cb60292afb9ca6763483595eb2909c91063af")
|
||||
val attestation = FieldElement(
|
||||
"413c05252d4003cd20f0a0901da193d0c7b53b7c6c3e3426e6f106a0ef96e18f")
|
||||
|
||||
val oracleInfo = SingleNonceOracleInfo(oraclePubKey, oracleNonce)
|
||||
val oracleInfo = EnumSingleOracleInfo(OracleAnnouncementTLV(
|
||||
"fdd824b4caaec7479cc9d37003f5add6504d035054ffeac8637a990305a45cfecc1062044c3f68b45318f57e41c4544a4a950c0744e2a80854349a3426b00ad86da5090b9e942dc6df2ae87f007b45b0ccd63e6c354d92c4545fc099ea3e137e54492d1efdd822500001a6a09c7c83c50b34f9db560a2e14fef2eab5224c15b18c7114331756364bfce65ffe3800fdd8062400030c44656d6f637261745f77696e0e52657075626c6963616e5f77696e056f746865720161"))
|
||||
|
||||
val offerData = DLCOffer(
|
||||
OracleAndContractInfo(oracleInfo, contractInfo),
|
||||
ContractInfo(contractDescriptor, oracleInfo),
|
||||
dummyDLCKeys,
|
||||
Satoshis(5000),
|
||||
Vector(dummyFundingInputs.head),
|
||||
|
@ -368,15 +360,14 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
|||
dummyTimeouts
|
||||
)
|
||||
|
||||
val oracleSig = SchnorrDigitalSignature(oracleNonce, attestation)
|
||||
val oracleSig = SchnorrDigitalSignature(
|
||||
"a6a09c7c83c50b34f9db560a2e14fef2eab5224c15b18c7114331756364bfce6c59736cdcfe1e0a89064f846d5dbde0902f82688dde34dc1833965a60240f287")
|
||||
|
||||
val paramHash = DLCMessage.calcParamHash(offerData.oracleInfo,
|
||||
offerData.contractInfo,
|
||||
offerData.timeouts)
|
||||
val paramHash =
|
||||
DLCMessage.calcParamHash(offerData.contractInfo, offerData.timeouts)
|
||||
|
||||
for {
|
||||
offer <- walletA.createDLCOffer(
|
||||
offerData.oracleInfo,
|
||||
offerData.contractInfo,
|
||||
offerData.totalCollateral,
|
||||
Some(offerData.feeRate),
|
||||
|
|
|
@ -11,6 +11,7 @@ CREATE TABLE "wallet_dlcs"
|
|||
"funding_outpoint" TEXT,
|
||||
"funding_tx_id" TEXT,
|
||||
"closing_tx_id" TEXT,
|
||||
"outcome" TEXT,
|
||||
constraint "pk_dlc" primary key ("param_hash")
|
||||
);
|
||||
CREATE INDEX "wallet_dlcs_param_hash_index" on "wallet_dlcs" ("param_hash");
|
||||
|
@ -19,7 +20,6 @@ CREATE TABLE "wallet_dlc_offers"
|
|||
(
|
||||
"param_hash" VARCHAR(254) NOT NULL UNIQUE,
|
||||
"temp_contract_id" TEXT NOT NULL UNIQUE,
|
||||
"oracle_info_tlv" TEXT NOT NULL,
|
||||
"contract_info" TEXT NOT NULL,
|
||||
"contract_maturity" TEXT NOT NULL,
|
||||
"contract_timeout" TEXT NOT NULL,
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
ALTER TABLE "wallet_dlcs" ADD COLUMN "outcome" TEXT;
|
|
@ -10,7 +10,8 @@ CREATE TABLE "wallet_dlcs"
|
|||
"oracle_sigs" VARCHAR(254),
|
||||
"funding_outpoint" VARCHAR(254),
|
||||
"funding_tx_id" VARCHAR(254),
|
||||
"closing_tx_id" VARCHAR(254)
|
||||
"closing_tx_id" VARCHAR(254),
|
||||
"outcome" VARCHAR(254)
|
||||
);
|
||||
CREATE INDEX "wallet_dlcs_param_hash_index" on "wallet_dlcs" ("param_hash");
|
||||
|
||||
|
@ -18,7 +19,6 @@ CREATE TABLE "wallet_dlc_offers"
|
|||
(
|
||||
"param_hash" VARCHAR(254) NOT NULL UNIQUE,
|
||||
"temp_contract_id" VARCHAR(254) NOT NULL UNIQUE,
|
||||
"oracle_info_tlv" VARCHAR(254) NOT NULL,
|
||||
"contract_info" VARCHAR(254) NOT NULL,
|
||||
"contract_maturity" VARCHAR(254) NOT NULL,
|
||||
"contract_timeout" VARCHAR(254) NOT NULL,
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
ALTER TABLE "wallet_dlcs" ADD COLUMN "outcome" TEXT;
|
|
@ -396,7 +396,6 @@ abstract class DLCWallet extends Wallet with AnyDLCHDWalletApi {
|
|||
* This is the first step of the initiator
|
||||
*/
|
||||
override def createDLCOffer(
|
||||
oracleInfo: OracleInfo,
|
||||
contractInfo: ContractInfo,
|
||||
collateral: Satoshis,
|
||||
feeRateOpt: Option[FeeUnit],
|
||||
|
@ -407,7 +406,7 @@ abstract class DLCWallet extends Wallet with AnyDLCHDWalletApi {
|
|||
val timeouts =
|
||||
DLCTimeouts(BlockStamp(locktime.toInt), BlockStamp(refundLocktime.toInt))
|
||||
|
||||
val paramHash = DLCMessage.calcParamHash(oracleInfo, contractInfo, timeouts)
|
||||
val paramHash = DLCMessage.calcParamHash(contractInfo, timeouts)
|
||||
|
||||
logger.debug(
|
||||
s"Checking if DLC Offer has already been made (${paramHash.hex})")
|
||||
|
@ -433,7 +432,6 @@ abstract class DLCWallet extends Wallet with AnyDLCHDWalletApi {
|
|||
case None =>
|
||||
createNewDLCOffer(
|
||||
collateral = collateral,
|
||||
oracleInfo = oracleInfo,
|
||||
contractInfo = contractInfo,
|
||||
feeRate = satoshisPerVirtualByte,
|
||||
timeouts = timeouts
|
||||
|
@ -444,12 +442,11 @@ abstract class DLCWallet extends Wallet with AnyDLCHDWalletApi {
|
|||
|
||||
private def createNewDLCOffer(
|
||||
collateral: CurrencyUnit,
|
||||
oracleInfo: OracleInfo,
|
||||
contractInfo: ContractInfo,
|
||||
feeRate: SatoshisPerVirtualByte,
|
||||
timeouts: DLCTimeouts): Future[DLCOffer] = {
|
||||
logger.info("Creating DLC Offer")
|
||||
val paramHash = DLCMessage.calcParamHash(oracleInfo, contractInfo, timeouts)
|
||||
val paramHash = DLCMessage.calcParamHash(contractInfo, timeouts)
|
||||
|
||||
for {
|
||||
account <- getDefaultAccountForType(AddressType.SegWit)
|
||||
|
@ -476,7 +473,7 @@ abstract class DLCWallet extends Wallet with AnyDLCHDWalletApi {
|
|||
_ = logger.debug(
|
||||
s"DLC Offer data collected, creating database entry, ${paramHash.hex}")
|
||||
|
||||
offer = DLCOffer(OracleAndContractInfo(oracleInfo, contractInfo),
|
||||
offer = DLCOffer(contractInfo,
|
||||
dlcPubKeys,
|
||||
collateral.satoshis,
|
||||
utxos,
|
||||
|
@ -1451,7 +1448,6 @@ abstract class DLCWallet extends Wallet with AnyDLCHDWalletApi {
|
|||
paramHash,
|
||||
dlcDb.isInitiator,
|
||||
dlcDb.tempContractId,
|
||||
offerDb.oracleInfo,
|
||||
offerDb.contractInfo,
|
||||
offerDb.dlcTimeouts,
|
||||
offerDb.feeRate,
|
||||
|
@ -1464,7 +1460,6 @@ abstract class DLCWallet extends Wallet with AnyDLCHDWalletApi {
|
|||
dlcDb.isInitiator,
|
||||
dlcDb.tempContractId,
|
||||
dlcDb.contractIdOpt.get,
|
||||
offerDb.oracleInfo,
|
||||
offerDb.contractInfo,
|
||||
offerDb.dlcTimeouts,
|
||||
offerDb.feeRate,
|
||||
|
@ -1477,7 +1472,6 @@ abstract class DLCWallet extends Wallet with AnyDLCHDWalletApi {
|
|||
dlcDb.isInitiator,
|
||||
dlcDb.tempContractId,
|
||||
dlcDb.contractIdOpt.get,
|
||||
offerDb.oracleInfo,
|
||||
offerDb.contractInfo,
|
||||
offerDb.dlcTimeouts,
|
||||
offerDb.feeRate,
|
||||
|
@ -1490,7 +1484,6 @@ abstract class DLCWallet extends Wallet with AnyDLCHDWalletApi {
|
|||
dlcDb.isInitiator,
|
||||
dlcDb.tempContractId,
|
||||
dlcDb.contractIdOpt.get,
|
||||
offerDb.oracleInfo,
|
||||
offerDb.contractInfo,
|
||||
offerDb.dlcTimeouts,
|
||||
offerDb.feeRate,
|
||||
|
@ -1504,7 +1497,6 @@ abstract class DLCWallet extends Wallet with AnyDLCHDWalletApi {
|
|||
dlcDb.isInitiator,
|
||||
dlcDb.tempContractId,
|
||||
dlcDb.contractIdOpt.get,
|
||||
offerDb.oracleInfo,
|
||||
offerDb.contractInfo,
|
||||
offerDb.dlcTimeouts,
|
||||
offerDb.feeRate,
|
||||
|
@ -1518,7 +1510,6 @@ abstract class DLCWallet extends Wallet with AnyDLCHDWalletApi {
|
|||
dlcDb.isInitiator,
|
||||
dlcDb.tempContractId,
|
||||
dlcDb.contractIdOpt.get,
|
||||
offerDb.oracleInfo,
|
||||
offerDb.contractInfo,
|
||||
offerDb.dlcTimeouts,
|
||||
offerDb.feeRate,
|
||||
|
@ -1539,7 +1530,6 @@ abstract class DLCWallet extends Wallet with AnyDLCHDWalletApi {
|
|||
dlcDb.isInitiator,
|
||||
dlcDb.tempContractId,
|
||||
dlcDb.contractIdOpt.get,
|
||||
offerDb.oracleInfo,
|
||||
offerDb.contractInfo,
|
||||
offerDb.dlcTimeouts,
|
||||
offerDb.feeRate,
|
||||
|
@ -1556,7 +1546,6 @@ abstract class DLCWallet extends Wallet with AnyDLCHDWalletApi {
|
|||
dlcDb.isInitiator,
|
||||
dlcDb.tempContractId,
|
||||
dlcDb.contractIdOpt.get,
|
||||
offerDb.oracleInfo,
|
||||
offerDb.contractInfo,
|
||||
offerDb.dlcTimeouts,
|
||||
offerDb.feeRate,
|
||||
|
|
|
@ -17,23 +17,16 @@ import scala.concurrent.Future
|
|||
trait DLCWalletApi { self: WalletApi =>
|
||||
|
||||
def createDLCOffer(
|
||||
oracleInfo: OracleInfo,
|
||||
contractInfoTLV: ContractInfoTLV,
|
||||
contractInfoTLV: ContractInfoV0TLV,
|
||||
collateral: Satoshis,
|
||||
feeRateOpt: Option[FeeUnit],
|
||||
locktime: UInt32,
|
||||
refundLT: UInt32): Future[DLCOffer] = {
|
||||
val contractInfo = ContractInfo.fromTLV(contractInfoTLV)
|
||||
createDLCOffer(oracleInfo,
|
||||
contractInfo,
|
||||
collateral,
|
||||
feeRateOpt,
|
||||
locktime,
|
||||
refundLT)
|
||||
createDLCOffer(contractInfo, collateral, feeRateOpt, locktime, refundLT)
|
||||
}
|
||||
|
||||
def createDLCOffer(
|
||||
oracleInfo: OracleInfo,
|
||||
contractInfo: ContractInfo,
|
||||
collateral: Satoshis,
|
||||
feeRateOpt: Option[FeeUnit],
|
||||
|
@ -42,7 +35,6 @@ trait DLCWalletApi { self: WalletApi =>
|
|||
|
||||
def registerDLCOffer(dlcOffer: DLCOffer): Future[DLCOffer] = {
|
||||
createDLCOffer(
|
||||
dlcOffer.oracleInfo,
|
||||
dlcOffer.contractInfo,
|
||||
dlcOffer.totalCollateral,
|
||||
Some(dlcOffer.feeRate),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.bitcoins.dlc.wallet.models
|
||||
|
||||
import org.bitcoins.core.currency.CurrencyUnit
|
||||
import org.bitcoins.core.protocol.tlv.{ContractInfoTLV, OracleInfoTLV}
|
||||
import org.bitcoins.core.protocol.tlv.ContractInfoV0TLV
|
||||
import org.bitcoins.core.protocol.{BitcoinAddress, BlockTimeStamp}
|
||||
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
import org.bitcoins.crypto._
|
||||
|
@ -68,9 +68,7 @@ case class DLCOfferDAO()(implicit
|
|||
def tempContractId: Rep[Sha256Digest] =
|
||||
column("temp_contract_id", O.Unique)
|
||||
|
||||
def oracleInfoTLV: Rep[OracleInfoTLV] = column("oracle_info_tlv")
|
||||
|
||||
def contractInfoTLV: Rep[ContractInfoTLV] = column("contract_info")
|
||||
def contractInfoTLV: Rep[ContractInfoV0TLV] = column("contract_info")
|
||||
|
||||
def contractMaturity: Rep[BlockTimeStamp] = column("contract_maturity")
|
||||
|
||||
|
@ -89,7 +87,6 @@ case class DLCOfferDAO()(implicit
|
|||
def * : ProvenShape[DLCOfferDb] =
|
||||
(paramHash,
|
||||
tempContractId,
|
||||
oracleInfoTLV,
|
||||
contractInfoTLV,
|
||||
contractMaturity,
|
||||
contractTimeout,
|
||||
|
|
|
@ -7,7 +7,7 @@ import org.bitcoins.core.protocol.dlc.{
|
|||
DLCPublicKeys,
|
||||
DLCTimeouts
|
||||
}
|
||||
import org.bitcoins.core.protocol.tlv.{ContractInfoTLV, OracleInfoTLV}
|
||||
import org.bitcoins.core.protocol.tlv.ContractInfoV0TLV
|
||||
import org.bitcoins.core.protocol.{BitcoinAddress, BlockTimeStamp}
|
||||
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
import org.bitcoins.crypto._
|
||||
|
@ -15,8 +15,7 @@ import org.bitcoins.crypto._
|
|||
case class DLCOfferDb(
|
||||
paramHash: Sha256DigestBE,
|
||||
tempContractId: Sha256Digest,
|
||||
oracleInfoTLV: OracleInfoTLV,
|
||||
contractInfoTLV: ContractInfoTLV,
|
||||
contractInfoTLV: ContractInfoV0TLV,
|
||||
contractMaturity: BlockTimeStamp,
|
||||
contractTimeout: BlockTimeStamp,
|
||||
fundingKey: ECPublicKey,
|
||||
|
@ -25,10 +24,10 @@ case class DLCOfferDb(
|
|||
feeRate: SatoshisPerVirtualByte,
|
||||
changeAddress: BitcoinAddress) {
|
||||
|
||||
lazy val oracleInfo: OracleInfo = OracleInfo.fromTLV(oracleInfoTLV)
|
||||
|
||||
lazy val contractInfo: ContractInfo = ContractInfo.fromTLV(contractInfoTLV)
|
||||
|
||||
lazy val oracleInfo: OracleInfo = contractInfo.oracleInfo
|
||||
|
||||
lazy val dlcPubKeys: DLCPublicKeys = DLCPublicKeys(fundingKey, payoutAddress)
|
||||
|
||||
lazy val dlcTimeouts: DLCTimeouts =
|
||||
|
@ -37,7 +36,7 @@ case class DLCOfferDb(
|
|||
def toDLCOffer(fundingInputs: Vector[DLCFundingInput]): DLCOffer = {
|
||||
|
||||
DLCOffer(
|
||||
OracleAndContractInfo(oracleInfo, contractInfo),
|
||||
contractInfo,
|
||||
dlcPubKeys,
|
||||
totalCollateral.satoshis,
|
||||
fundingInputs,
|
||||
|
@ -54,7 +53,6 @@ object DLCOfferDbHelper {
|
|||
DLCOfferDb(
|
||||
offer.paramHash,
|
||||
offer.tempContractId,
|
||||
offer.oracleInfo.toTLV,
|
||||
offer.contractInfo.toTLV,
|
||||
offer.timeouts.contractMaturity,
|
||||
offer.timeouts.contractTimeout,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package org.bitcoins.dlc.builder
|
||||
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.OracleAndContractInfo
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.ContractInfo
|
||||
import org.bitcoins.core.protocol.dlc.DLCTimeouts
|
||||
import org.bitcoins.core.protocol.script.{
|
||||
EmptyScriptSignature,
|
||||
|
@ -25,7 +25,7 @@ import scala.concurrent.{ExecutionContext, Future}
|
|||
* Contract Execution Transactions (CETs)
|
||||
*/
|
||||
case class DLCCETBuilder(
|
||||
oracleAndContractInfo: OracleAndContractInfo,
|
||||
contractInfo: ContractInfo,
|
||||
offerFundingKey: ECPublicKey,
|
||||
offerFinalSPK: ScriptPubKey,
|
||||
acceptFundingKey: ECPublicKey,
|
||||
|
@ -53,7 +53,7 @@ case class DLCCETBuilder(
|
|||
ec: ExecutionContext): Future[WitnessTransaction] = {
|
||||
val builder = RawTxBuilder().setLockTime(timeouts.contractMaturity.toUInt32)
|
||||
|
||||
val (offerValue, acceptValue) = oracleAndContractInfo.getPayouts(msg)
|
||||
val (offerValue, acceptValue) = contractInfo.getPayouts(msg)
|
||||
|
||||
builder += TransactionOutput(offerValue, offerFinalSPK)
|
||||
builder += TransactionOutput(acceptValue, acceptFinalSPK)
|
||||
|
|
|
@ -53,12 +53,12 @@ case class DLCTxBuilder(offer: DLCOffer, accept: DLCAcceptWithoutSigs)(implicit
|
|||
// builder.offer.oracleAndContractInfo should not be used,
|
||||
// builder.oracleAndContractInfo should be used instead in case a party
|
||||
// is over-collateralized in which case payouts will be incorrect here.
|
||||
private val oracleAndContractInfoBeforeAccept: OracleAndContractInfo =
|
||||
offer.oracleAndContractInfo
|
||||
private val contractInfoBeforeAccept: ContractInfo =
|
||||
offer.contractInfo
|
||||
|
||||
val oracleAndContractInfo: OracleAndContractInfo =
|
||||
oracleAndContractInfoBeforeAccept.updateOnAccept(totalInput.satoshis,
|
||||
acceptNegotiationFields)
|
||||
val contractInfo: ContractInfo =
|
||||
contractInfoBeforeAccept.updateOnAccept(totalInput.satoshis,
|
||||
acceptNegotiationFields)
|
||||
|
||||
val offerTotalFunding: CurrencyUnit =
|
||||
offerFundingInputs.map(_.output.value).sum
|
||||
|
@ -74,7 +74,7 @@ case class DLCTxBuilder(offer: DLCOffer, accept: DLCAcceptWithoutSigs)(implicit
|
|||
"Offer change address must have same network as final address")
|
||||
require(acceptChangeAddress.networkParameters == network,
|
||||
"Accept change address must have same network as final address")
|
||||
require(totalInput >= oracleAndContractInfo.offerContractInfo.max,
|
||||
require(totalInput >= contractInfo.max,
|
||||
"Total collateral must add up to max winnings")
|
||||
require(
|
||||
offerTotalFunding >= offerTotalCollateral,
|
||||
|
@ -87,7 +87,7 @@ case class DLCTxBuilder(offer: DLCOffer, accept: DLCAcceptWithoutSigs)(implicit
|
|||
def getPayouts(oracleSigs: Vector[SchnorrDigitalSignature]): (
|
||||
CurrencyUnit,
|
||||
CurrencyUnit) = {
|
||||
oracleAndContractInfo.getPayouts(oracleSigs)
|
||||
contractInfo.getPayouts(oracleSigs)
|
||||
}
|
||||
|
||||
lazy val fundingTxBuilder: DLCFundingTxBuilder = {
|
||||
|
@ -124,7 +124,7 @@ case class DLCTxBuilder(offer: DLCOffer, accept: DLCAcceptWithoutSigs)(implicit
|
|||
OutputReference(fundingOutPoint, fundingTx.outputs.head)
|
||||
|
||||
DLCCETBuilder(
|
||||
oracleAndContractInfo = oracleAndContractInfo,
|
||||
contractInfo = contractInfo,
|
||||
offerFundingKey = offerFundingKey,
|
||||
offerFinalSPK = offerFinalAddress.scriptPubKey,
|
||||
acceptFundingKey = acceptFundingKey,
|
||||
|
|
|
@ -78,7 +78,7 @@ case class DLCExecutor(signer: DLCTxSigner)(implicit ec: ExecutionContext) {
|
|||
ExecutedDLCOutcome] = {
|
||||
val SetupDLC(fundingTx, cetInfos, _) = dlcSetup
|
||||
|
||||
val msgOpt = builder.oracleAndContractInfo.findOutcome(oracleSigs)
|
||||
val msgOpt = builder.contractInfo.findOutcome(oracleSigs)
|
||||
val (msg, remoteAdaptorSig) = msgOpt match {
|
||||
case Some(msg) =>
|
||||
val cetInfo = cetInfos(msg)
|
||||
|
|
|
@ -181,7 +181,7 @@ case class DLCTxSigner(
|
|||
|
||||
/** Signs remote's Contract Execution Transaction (CET) for a given outcome hash */
|
||||
def createRemoteCETSig(msg: DLCOutcomeType): Future[ECAdaptorSignature] = {
|
||||
val adaptorPoint = builder.oracleAndContractInfo.sigPointForOutcome(msg)
|
||||
val adaptorPoint = builder.contractInfo.sigPointForOutcome(msg)
|
||||
val hashType = HashType.sigHashAll
|
||||
for {
|
||||
fundingTx <- builder.buildFundingTx
|
||||
|
@ -281,7 +281,7 @@ case class DLCTxSigner(
|
|||
|
||||
/** Creates all of this party's CETSignatures */
|
||||
def createCETSigs(): Future[CETSignatures] = {
|
||||
val cetSigFs = builder.oracleAndContractInfo.allOutcomes.map { msg =>
|
||||
val cetSigFs = builder.contractInfo.allOutcomes.map { msg =>
|
||||
// Need to wrap in another future so they are all started at once
|
||||
// and do not block each other
|
||||
Future(createRemoteCETSig(msg).map(msg -> _)).flatten
|
||||
|
|
|
@ -149,19 +149,6 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] {
|
|||
|
||||
def apply(tlv: TLV): DLCParsingTestVector = {
|
||||
tlv match {
|
||||
case ContractInfoV0TLV(outcomes) =>
|
||||
val fields = Vector(
|
||||
"tpe" -> Element(ContractInfoV0TLV.tpe),
|
||||
"length" -> Element(tlv.length),
|
||||
"outcomes" -> MultiElement(outcomes.map {
|
||||
case (outcome, amt) =>
|
||||
NamedMultiElement("outcome" -> CryptoUtil
|
||||
.sha256DLCAttestation(outcome)
|
||||
.bytes,
|
||||
"localPayout" -> amt.toUInt64.bytes)
|
||||
})
|
||||
)
|
||||
DLCTLVTestVector(tlv, "contract_info_v0", fields)
|
||||
case PayoutFunctionV0TLV(points) =>
|
||||
val fields = Vector(
|
||||
"tpe" -> Element(PayoutFunctionV0TLV.tpe),
|
||||
|
@ -190,37 +177,71 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] {
|
|||
})
|
||||
)
|
||||
DLCTLVTestVector(tlv, "rounding_intervals_v0", fields)
|
||||
case ContractInfoV1TLV(base,
|
||||
numDigits,
|
||||
totalCollateral,
|
||||
payoutFunction,
|
||||
roundingIntervals) =>
|
||||
case ContractDescriptorV0TLV(outcomes) =>
|
||||
val fields = Vector(
|
||||
"tpe" -> Element(ContractInfoV1TLV.tpe),
|
||||
"tpe" -> Element(ContractDescriptorV0TLV.tpe),
|
||||
"length" -> Element(tlv.length),
|
||||
"outcomes" -> MultiElement(outcomes.map {
|
||||
case (outcome, amt) =>
|
||||
NamedMultiElement("outcome" -> CryptoUtil.sha256(outcome).bytes,
|
||||
"localPayout" -> amt.toUInt64.bytes)
|
||||
})
|
||||
)
|
||||
DLCTLVTestVector(tlv, "contract_descriptor_v0", fields)
|
||||
case ContractDescriptorV1TLV(numDigits,
|
||||
payoutFunction,
|
||||
roundingIntervals) =>
|
||||
val fields = Vector(
|
||||
"tpe" -> Element(ContractDescriptorV1TLV.tpe),
|
||||
"length" -> Element(tlv.length),
|
||||
"base" -> Element(BigSizeUInt(base)),
|
||||
"numDigits" -> Element(UInt16(numDigits)),
|
||||
"totalCollateral" -> Element(UInt64(totalCollateral.toLong)),
|
||||
"payoutFunction" -> Element(payoutFunction),
|
||||
"roundingIntervals" -> Element(roundingIntervals)
|
||||
)
|
||||
DLCTLVTestVector(tlv, "contract_info_v1", fields)
|
||||
case OracleInfoV0TLV(pubKey, rValue) =>
|
||||
DLCTLVTestVector(tlv, "contract_descriptor_v1", fields)
|
||||
case OracleInfoV0TLV(announcement) =>
|
||||
val fields = Vector(
|
||||
"tpe" -> Element(OracleInfoV0TLV.tpe),
|
||||
"length" -> Element(tlv.length),
|
||||
"pubKey" -> Element(pubKey),
|
||||
"rValue" -> Element(rValue)
|
||||
"announcement" -> Element(announcement)
|
||||
)
|
||||
DLCTLVTestVector(tlv, "oracle_info_v0", fields)
|
||||
case OracleInfoV1TLV(pubKey, nonces) =>
|
||||
case OracleParamsV0TLV(maxErrorExp, minFailExp, maximizeCoverage) =>
|
||||
val maximizeCoverageBytes = ByteVector(
|
||||
if (maximizeCoverage) TLV.TRUE_BYTE else TLV.FALSE_BYTE)
|
||||
|
||||
val fields = Vector(
|
||||
"tpe" -> Element(OracleParamsV0TLV.tpe),
|
||||
"length" -> Element(tlv.length),
|
||||
"maxErrorExp" -> Element(UInt16(maxErrorExp)),
|
||||
"minFailExp" -> Element(UInt16(minFailExp)),
|
||||
"maximizeCoverage" -> Element(maximizeCoverageBytes)
|
||||
)
|
||||
DLCTLVTestVector(tlv, "oracle_params_v0", fields)
|
||||
case OracleInfoV1TLV(announcements) =>
|
||||
val fields = Vector(
|
||||
"tpe" -> Element(OracleInfoV1TLV.tpe),
|
||||
"length" -> Element(tlv.length),
|
||||
"pubKey" -> Element(pubKey),
|
||||
"nonces" -> MultiElement(nonces.map(Element(_)))
|
||||
"announcements" -> MultiElement(announcements.map(Element(_)))
|
||||
)
|
||||
DLCTLVTestVector(tlv, "oracle_info_v1", fields)
|
||||
case OracleInfoV2TLV(oracles, params) =>
|
||||
val fields = Vector(
|
||||
"tpe" -> Element(OracleInfoV2TLV.tpe),
|
||||
"length" -> Element(tlv.length),
|
||||
"announcements" -> MultiElement(oracles.map(Element(_))),
|
||||
"params" -> Element(params)
|
||||
)
|
||||
DLCTLVTestVector(tlv, "oracle_info_v2", fields)
|
||||
case ContractInfoV0TLV(totalCollateral, contractDescriptor, oracleInfo) =>
|
||||
val fields = Vector(
|
||||
"tpe" -> Element(ContractInfoV0TLV.tpe),
|
||||
"length" -> Element(tlv.length),
|
||||
"totalCollateral" -> Element(totalCollateral.toUInt64),
|
||||
"contractDescriptor" -> Element(contractDescriptor),
|
||||
"oracleInfo" -> Element(oracleInfo)
|
||||
)
|
||||
DLCTLVTestVector(tlv, "contract_info_v0", fields)
|
||||
case FundingInputV0TLV(prevTx,
|
||||
prevTxVout,
|
||||
sequence,
|
||||
|
@ -272,7 +293,6 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] {
|
|||
case DLCOfferTLV(contractFlags,
|
||||
chainHash,
|
||||
contractInfo,
|
||||
oracleInfo,
|
||||
fundingPubKey,
|
||||
payoutSPK,
|
||||
totalCollateralSatoshis,
|
||||
|
@ -286,7 +306,6 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] {
|
|||
"contractFlags" -> Element(ByteVector(contractFlags)),
|
||||
"chainHash" -> Element(chainHash),
|
||||
"contractInfo" -> Element(contractInfo),
|
||||
"oracleInfo" -> Element(oracleInfo),
|
||||
"fundingPubKey" -> Element(fundingPubKey),
|
||||
"payoutSPKLen" -> Element(UInt16(payoutSPK.asmBytes.length)),
|
||||
"payoutSPK" -> Element(payoutSPK.asmBytes),
|
||||
|
|
|
@ -28,7 +28,7 @@ object DLCParsingTestVectorGen
|
|||
override def generateTestVectors(): Future[Vector[DLCParsingTestVector]] = {
|
||||
Future.successful(
|
||||
Vector(
|
||||
DLCTLVGen.contractInfoParsingTestVector(),
|
||||
DLCTLVGen.contractDescriptorParsingTestVector(),
|
||||
DLCTLVGen.oracleInfoParsingTestVector(),
|
||||
DLCTLVGen.fundingInputParsingTestVector(),
|
||||
DLCTLVGen.cetSigsParsingTestVector(),
|
||||
|
|
|
@ -24,42 +24,56 @@ object DLCTLVGen {
|
|||
CryptoUtil.sha256(bytes)
|
||||
}
|
||||
|
||||
def genContractInfo(
|
||||
def genContractDescriptor(
|
||||
outcomes: Vector[String] = DLCTestUtil.genOutcomes(3),
|
||||
totalInput: CurrencyUnit = defaultAmt * 2): SingleNonceContractInfo = {
|
||||
DLCTestUtil.genContractInfos(outcomes, totalInput)._1
|
||||
totalInput: CurrencyUnit = defaultAmt * 2): EnumContractDescriptor = {
|
||||
DLCTestUtil.genContractDescriptors(outcomes, totalInput)._1
|
||||
}
|
||||
|
||||
def contractInfoParsingTestVector(
|
||||
def contractDescriptorParsingTestVector(
|
||||
outcomes: Vector[String] = DLCTestUtil.genOutcomes(3),
|
||||
totalInput: CurrencyUnit = defaultAmt * 2): DLCParsingTestVector = {
|
||||
DLCParsingTestVector(genContractInfo(outcomes, totalInput).toTLV)
|
||||
DLCParsingTestVector(genContractDescriptor(outcomes, totalInput).toTLV)
|
||||
}
|
||||
|
||||
def genOracleInfo(
|
||||
oraclePubKey: SchnorrPublicKey =
|
||||
ECPublicKey.freshPublicKey.schnorrPublicKey,
|
||||
oracleRValue: SchnorrNonce =
|
||||
ECPublicKey.freshPublicKey.schnorrNonce): SingleNonceOracleInfo = {
|
||||
SingleNonceOracleInfo(oraclePubKey, oracleRValue)
|
||||
oraclePrivKey: ECPrivateKey = ECPrivateKey.freshPrivateKey,
|
||||
oracleRValue: SchnorrNonce = ECPublicKey.freshPublicKey.schnorrNonce,
|
||||
events: Vector[String] =
|
||||
Vector("dummy1", "dummy2")): EnumSingleOracleInfo = {
|
||||
EnumSingleOracleInfo(
|
||||
OracleAnnouncementV0TLV.dummyForEventsAndKeys(
|
||||
oraclePrivKey,
|
||||
oracleRValue,
|
||||
events.map(EnumOutcome.apply)))
|
||||
}
|
||||
|
||||
def genOracleAndContractInfo(
|
||||
oraclePubKey: SchnorrPublicKey =
|
||||
ECPublicKey.freshPublicKey.schnorrPublicKey,
|
||||
def genContractInfo(
|
||||
oraclePrivKey: ECPrivateKey = ECPrivateKey.freshPrivateKey,
|
||||
oracleRValue: SchnorrNonce = ECPublicKey.freshPublicKey.schnorrNonce,
|
||||
outcomes: Vector[String] = DLCTestUtil.genOutcomes(3),
|
||||
totalInput: CurrencyUnit = defaultAmt * 2): OracleAndContractInfo = {
|
||||
OracleAndContractInfo(genOracleInfo(oraclePubKey, oracleRValue),
|
||||
genContractInfo(outcomes, totalInput))
|
||||
totalInput: CurrencyUnit = defaultAmt * 2): ContractInfo = {
|
||||
ContractInfo(totalInput.satoshis,
|
||||
genContractDescriptor(outcomes, totalInput),
|
||||
genOracleInfo(oraclePrivKey, oracleRValue, outcomes))
|
||||
}
|
||||
|
||||
def contractInfoParsingTestVector(
|
||||
oraclePrivKey: ECPrivateKey = ECPrivateKey.freshPrivateKey,
|
||||
oracleRValue: SchnorrNonce = ECPublicKey.freshPublicKey.schnorrNonce,
|
||||
outcomes: Vector[String] = DLCTestUtil.genOutcomes(3),
|
||||
totalInput: CurrencyUnit = defaultAmt * 2): DLCParsingTestVector = {
|
||||
DLCParsingTestVector(
|
||||
genContractInfo(oraclePrivKey, oracleRValue, outcomes, totalInput).toTLV)
|
||||
}
|
||||
|
||||
def oracleInfoParsingTestVector(
|
||||
oraclePubKey: SchnorrPublicKey =
|
||||
ECPublicKey.freshPublicKey.schnorrPublicKey,
|
||||
oracleRValue: SchnorrNonce =
|
||||
ECPublicKey.freshPublicKey.schnorrNonce): DLCParsingTestVector = {
|
||||
DLCParsingTestVector(genOracleInfo(oraclePubKey, oracleRValue).toTLV)
|
||||
oraclePrivKey: ECPrivateKey = ECPrivateKey.freshPrivateKey,
|
||||
oracleRValue: SchnorrNonce = ECPublicKey.freshPublicKey.schnorrNonce,
|
||||
events: Vector[String] =
|
||||
Vector("dummy1", "dummy2")): DLCParsingTestVector = {
|
||||
DLCParsingTestVector(
|
||||
genOracleInfo(oraclePrivKey, oracleRValue, events).toTLV)
|
||||
}
|
||||
|
||||
def p2wpkh(
|
||||
|
@ -188,7 +202,7 @@ object DLCTLVGen {
|
|||
}
|
||||
|
||||
def dlcOffer(
|
||||
oracleAndContractInfo: OracleAndContractInfo = genOracleAndContractInfo(),
|
||||
contractInfo: ContractInfo = genContractInfo(),
|
||||
fundingPubKey: ECPublicKey = ECPublicKey.freshPublicKey,
|
||||
payoutAddress: BitcoinAddress = address(),
|
||||
totalCollateral: Satoshis = defaultAmt,
|
||||
|
@ -198,7 +212,7 @@ object DLCTLVGen {
|
|||
contractMaturityBound: BlockTimeStamp = BlockTimeStamp(100),
|
||||
contractTimeout: BlockTimeStamp = BlockTimeStamp(200)): DLCOffer = {
|
||||
DLCOffer(
|
||||
oracleAndContractInfo,
|
||||
contractInfo,
|
||||
DLCPublicKeys(fundingPubKey, payoutAddress),
|
||||
totalCollateral,
|
||||
fundingInputs,
|
||||
|
@ -209,7 +223,7 @@ object DLCTLVGen {
|
|||
}
|
||||
|
||||
def dlcOfferTLV(
|
||||
oracleAndContractInfo: OracleAndContractInfo = genOracleAndContractInfo(),
|
||||
contractInfo: ContractInfo = genContractInfo(),
|
||||
fundingPubKey: ECPublicKey = ECPublicKey.freshPublicKey,
|
||||
payoutAddress: BitcoinAddress = address(),
|
||||
totalCollateral: Satoshis = defaultAmt,
|
||||
|
@ -218,7 +232,7 @@ object DLCTLVGen {
|
|||
feeRate: SatoshisPerVirtualByte = SatoshisPerVirtualByte.one,
|
||||
contractMaturityBound: BlockTimeStamp = BlockTimeStamp(100),
|
||||
contractTimeout: BlockTimeStamp = BlockTimeStamp(200)): DLCOfferTLV = {
|
||||
dlcOffer(oracleAndContractInfo,
|
||||
dlcOffer(contractInfo,
|
||||
fundingPubKey,
|
||||
payoutAddress,
|
||||
totalCollateral,
|
||||
|
@ -230,7 +244,7 @@ object DLCTLVGen {
|
|||
}
|
||||
|
||||
def dlcOfferParsingTestVector(
|
||||
oracleAndContractInfo: OracleAndContractInfo = genOracleAndContractInfo(),
|
||||
contractInfo: ContractInfo = genContractInfo(),
|
||||
fundingPubKey: ECPublicKey = ECPublicKey.freshPublicKey,
|
||||
payoutAddress: BitcoinAddress = address(),
|
||||
totalCollateral: Satoshis = defaultAmt,
|
||||
|
@ -241,7 +255,7 @@ object DLCTLVGen {
|
|||
contractTimeout: BlockTimeStamp =
|
||||
BlockTimeStamp(200)): DLCParsingTestVector = {
|
||||
DLCParsingTestVector(
|
||||
dlcOfferTLV(oracleAndContractInfo,
|
||||
dlcOfferTLV(contractInfo,
|
||||
fundingPubKey,
|
||||
payoutAddress,
|
||||
totalCollateral,
|
||||
|
@ -315,7 +329,7 @@ object DLCTLVGen {
|
|||
offer.contractInfo.max - offer.totalCollateral + overCollateral
|
||||
|
||||
val cetSignatures =
|
||||
cetSigs(offer.oracleAndContractInfo.allOutcomes, fundingPubKey)
|
||||
cetSigs(offer.contractInfo.allOutcomes, fundingPubKey)
|
||||
|
||||
val tempContractId = offer.tempContractId
|
||||
|
||||
|
@ -371,7 +385,7 @@ object DLCTLVGen {
|
|||
offer: DLCOffer,
|
||||
contractId: ByteVector = hash().bytes): DLCSign = {
|
||||
val cetSignatures =
|
||||
cetSigs(offer.oracleAndContractInfo.allOutcomes, offer.pubKeys.fundingKey)
|
||||
cetSigs(offer.contractInfo.allOutcomes, offer.pubKeys.fundingKey)
|
||||
val fundingSignatures = fundingSigs(offer.fundingInputs.map(_.outPoint))
|
||||
DLCSign(cetSignatures, fundingSignatures, contractId)
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@ package org.bitcoins.dlc.testgen
|
|||
|
||||
import org.bitcoins.core.currency.{CurrencyUnit, Satoshis}
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.{
|
||||
MultiNonceContractInfo,
|
||||
SingleNonceContractInfo
|
||||
EnumContractDescriptor,
|
||||
NumericContractDescriptor
|
||||
}
|
||||
import org.bitcoins.core.protocol.dlc.{
|
||||
DLCPayoutCurve,
|
||||
|
@ -35,15 +35,17 @@ object DLCTestUtil {
|
|||
valsWithOrder.sortBy(_._2).map(_._1)
|
||||
}
|
||||
|
||||
def genContractInfos(outcomes: Vector[String], totalInput: CurrencyUnit): (
|
||||
SingleNonceContractInfo,
|
||||
SingleNonceContractInfo) = {
|
||||
def genContractDescriptors(
|
||||
outcomes: Vector[String],
|
||||
totalInput: CurrencyUnit): (
|
||||
EnumContractDescriptor,
|
||||
EnumContractDescriptor) = {
|
||||
val outcomeMap =
|
||||
outcomes
|
||||
.map(EnumOutcome.apply)
|
||||
.zip(DLCTestUtil.genValues(outcomes.length, totalInput))
|
||||
|
||||
val info = SingleNonceContractInfo(outcomeMap)
|
||||
val info = EnumContractDescriptor(outcomeMap)
|
||||
val remoteInfo = info.flip(totalInput.satoshis)
|
||||
|
||||
(info, remoteInfo)
|
||||
|
@ -60,8 +62,10 @@ object DLCTestUtil {
|
|||
numDigits: Int,
|
||||
totalCollateral: CurrencyUnit,
|
||||
roundingIntervals: RoundingIntervals = RoundingIntervals.noRounding,
|
||||
numRounds: Int = 0): (MultiNonceContractInfo, MultiNonceContractInfo) = {
|
||||
val overMaxValue = Math.pow(10, numDigits).toLong
|
||||
numRounds: Int = 0): (
|
||||
NumericContractDescriptor,
|
||||
NumericContractDescriptor) = {
|
||||
val overMaxValue = Math.pow(2, numDigits).toLong
|
||||
// Left collar goes from [0, botCollar]
|
||||
val botCollar = NumberUtil.randomLong(overMaxValue / 2)
|
||||
val halfWindow = scala.math.min(overMaxValue / 4, 2500)
|
||||
|
@ -92,11 +96,8 @@ object DLCTestUtil {
|
|||
}
|
||||
RoundingIntervals(intervalStarts)
|
||||
} else roundingIntervals
|
||||
val info = MultiNonceContractInfo(func,
|
||||
base = 10,
|
||||
numDigits,
|
||||
totalCollateral.satoshis,
|
||||
roundingIntervalsToUse)
|
||||
val info =
|
||||
NumericContractDescriptor(func, numDigits, roundingIntervalsToUse)
|
||||
val remoteInfo = info.flip(totalCollateral.satoshis)
|
||||
(info, remoteInfo)
|
||||
}
|
||||
|
|
|
@ -110,9 +110,9 @@ case class DLCPartyParams(
|
|||
|
||||
def toOffer(params: DLCParams): DLCOffer = {
|
||||
DLCOffer(
|
||||
OracleAndContractInfo(
|
||||
params.oracleInfo,
|
||||
SingleNonceContractInfo(params.contractInfo.map(_.toMapEntry))),
|
||||
ContractInfo(
|
||||
EnumContractDescriptor(params.contractInfo.map(_.toMapEntry)),
|
||||
params.oracleInfo),
|
||||
DLCPublicKeys(fundingPrivKey.publicKey, payoutAddress),
|
||||
collateral.satoshis,
|
||||
fundingInputs,
|
||||
|
@ -135,7 +135,7 @@ case class SerializedContractInfoEntry(
|
|||
|
||||
object SerializedContractInfoEntry {
|
||||
|
||||
def fromContractInfo(contractInfo: SingleNonceContractInfo): Vector[
|
||||
def fromContractDescriptor(contractInfo: EnumContractDescriptor): Vector[
|
||||
SerializedContractInfoEntry] = {
|
||||
contractInfo.map {
|
||||
case (EnumOutcome(str), amt) =>
|
||||
|
@ -147,7 +147,7 @@ object SerializedContractInfoEntry {
|
|||
}
|
||||
|
||||
case class DLCParams(
|
||||
oracleInfo: OracleInfo,
|
||||
oracleInfo: EnumSingleOracleInfo,
|
||||
contractInfo: Vector[SerializedContractInfoEntry],
|
||||
contractMaturityBound: BlockTimeStamp,
|
||||
contractTimeout: BlockTimeStamp,
|
||||
|
@ -226,18 +226,8 @@ object SuccessTestVector extends TestVectorParser[SuccessTestVector] {
|
|||
{ element => JsString(element.hex) }
|
||||
)
|
||||
|
||||
implicit val oracleInfoFormat: Format[OracleInfo] = Format[OracleInfo](
|
||||
{
|
||||
_.validate[Map[String, String]]
|
||||
.map(map =>
|
||||
SingleNonceOracleInfo(SchnorrPublicKey(map("publicKey")),
|
||||
SchnorrNonce(map("nonce"))))
|
||||
},
|
||||
{ info =>
|
||||
Json.toJson(
|
||||
Map("publicKey" -> info.pubKey.hex, "nonce" -> info.nonces.head.hex))
|
||||
}
|
||||
)
|
||||
implicit val oracleInfoFormat: Format[EnumSingleOracleInfo] = hexFormat(
|
||||
EnumSingleOracleInfo)
|
||||
|
||||
implicit val blockTimeStampFormat: Format[BlockTimeStamp] =
|
||||
Format[BlockTimeStamp](
|
||||
|
|
|
@ -4,11 +4,11 @@ import org.bitcoins.core.currency.{CurrencyUnit, Satoshis}
|
|||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.{
|
||||
DLCSign,
|
||||
SingleNonceContractInfo,
|
||||
SingleNonceOracleInfo
|
||||
EnumContractDescriptor,
|
||||
EnumSingleOracleInfo
|
||||
}
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.tlv.EnumOutcome
|
||||
import org.bitcoins.core.protocol.tlv.{EnumOutcome, OracleAnnouncementV0TLV}
|
||||
import org.bitcoins.core.protocol.transaction._
|
||||
import org.bitcoins.core.protocol.{BitcoinAddress, BlockTimeStamp}
|
||||
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
|
@ -22,16 +22,19 @@ object DLCTxGen {
|
|||
import DLCTLVGen._
|
||||
|
||||
def dlcParams(
|
||||
contractInfo: SingleNonceContractInfo = genContractInfo(),
|
||||
contractDescriptor: EnumContractDescriptor = genContractDescriptor(),
|
||||
contractMaturityBound: BlockTimeStamp = BlockTimeStamp(100),
|
||||
contractTimeout: BlockTimeStamp = BlockTimeStamp(200),
|
||||
feeRate: SatoshisPerVirtualByte =
|
||||
SatoshisPerVirtualByte(Satoshis(5))): DLCParams = {
|
||||
val privKey = ECPrivateKey.freshPrivateKey
|
||||
val kVal = ECPrivateKey.freshPrivateKey
|
||||
val oracleInfo =
|
||||
SingleNonceOracleInfo(privKey.schnorrPublicKey, kVal.schnorrNonce)
|
||||
val realOutcome = contractInfo.keys(contractInfo.size / 2)
|
||||
val oracleInfo = EnumSingleOracleInfo(
|
||||
OracleAnnouncementV0TLV
|
||||
.dummyForEventsAndKeys(privKey,
|
||||
kVal.schnorrNonce,
|
||||
contractDescriptor.keys))
|
||||
val realOutcome = contractDescriptor.keys(contractDescriptor.size / 2)
|
||||
val sig =
|
||||
privKey.schnorrSignWithNonce(CryptoUtil
|
||||
.sha256DLCAttestation(realOutcome.outcome)
|
||||
|
@ -39,7 +42,7 @@ object DLCTxGen {
|
|||
kVal)
|
||||
DLCParams(
|
||||
oracleInfo,
|
||||
SerializedContractInfoEntry.fromContractInfo(contractInfo),
|
||||
SerializedContractInfoEntry.fromContractDescriptor(contractDescriptor),
|
||||
contractMaturityBound,
|
||||
contractTimeout,
|
||||
feeRate,
|
||||
|
@ -141,10 +144,10 @@ object DLCTxGen {
|
|||
acceptInputs: Vector[FundingInputTx],
|
||||
numOutcomes: Int = 3): ValidTestInputs = {
|
||||
val outcomes = DLCTestUtil.genOutcomes(numOutcomes)
|
||||
val contractInfo = genContractInfo(outcomes)
|
||||
val contractDescriptor = genContractDescriptor(outcomes)
|
||||
|
||||
validTestInputs(
|
||||
params = dlcParams(contractInfo = contractInfo),
|
||||
params = dlcParams(contractDescriptor = contractDescriptor),
|
||||
offerParams = dlcPartyParams(fundingInputTxs = offerInputs),
|
||||
acceptParams = dlcPartyParams(fundingInputTxs = acceptInputs)
|
||||
)
|
||||
|
@ -205,9 +208,10 @@ object DLCTxGen {
|
|||
def randomTxTestVector(numOutcomes: Int)(implicit
|
||||
ec: ExecutionContext): Future[DLCTxTestVector] = {
|
||||
val outcomes = DLCTestUtil.genOutcomes(numOutcomes)
|
||||
val contractInfo = genContractInfo(outcomes)
|
||||
val contractDescriptor = genContractDescriptor(outcomes)
|
||||
|
||||
dlcTxTestVector(validTestInputs(dlcParams(contractInfo = contractInfo)))
|
||||
dlcTxTestVector(
|
||||
validTestInputs(dlcParams(contractDescriptor = contractDescriptor)))
|
||||
}
|
||||
|
||||
def successTestVector(inputs: ValidTestInputs = validTestInputs())(implicit
|
||||
|
@ -272,8 +276,9 @@ object DLCTxGen {
|
|||
def randomSuccessTestVector(numOutcomes: Int)(implicit
|
||||
ec: ExecutionContext): Future[SuccessTestVector] = {
|
||||
val outcomes = DLCTestUtil.genOutcomes(numOutcomes)
|
||||
val contractInfo = genContractInfo(outcomes)
|
||||
val contractDescriptor = genContractDescriptor(outcomes)
|
||||
|
||||
successTestVector(validTestInputs(dlcParams(contractInfo = contractInfo)))
|
||||
successTestVector(
|
||||
validTestInputs(dlcParams(contractDescriptor = contractDescriptor)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,9 @@ package org.bitcoins.dlc.testgen
|
|||
|
||||
import org.bitcoins.core.config.{BitcoinNetwork, RegTest}
|
||||
import org.bitcoins.core.currency.CurrencyUnit
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.{
|
||||
ContractInfo,
|
||||
DLCAccept,
|
||||
OracleInfo
|
||||
}
|
||||
import org.bitcoins.core.protocol.dlc._
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.{ContractInfo, DLCAccept}
|
||||
import org.bitcoins.core.protocol.dlc._
|
||||
import org.bitcoins.core.protocol.script.ScriptPubKey
|
||||
import org.bitcoins.core.protocol.tlv.DLCOutcomeType
|
||||
import org.bitcoins.core.protocol.transaction.Transaction
|
||||
|
@ -58,7 +54,7 @@ case class TestDLCClient(
|
|||
|
||||
private val dlcExecutor = DLCExecutor(dlcTxSigner)
|
||||
|
||||
val messages: Vector[DLCOutcomeType] = offer.oracleAndContractInfo.allOutcomes
|
||||
val messages: Vector[DLCOutcomeType] = offer.contractInfo.allOutcomes
|
||||
|
||||
val timeouts: DLCTimeouts = offer.timeouts
|
||||
|
||||
|
@ -127,7 +123,6 @@ object TestDLCClient {
|
|||
|
||||
def apply(
|
||||
outcomes: ContractInfo,
|
||||
oracleInfo: OracleInfo,
|
||||
isInitiator: Boolean,
|
||||
fundingPrivKey: ECPrivateKey,
|
||||
payoutPrivKey: ECPrivateKey,
|
||||
|
@ -147,8 +142,10 @@ object TestDLCClient {
|
|||
network
|
||||
)
|
||||
|
||||
val remoteOutcomes: ContractInfo =
|
||||
outcomes.flip((input + remoteInput).satoshis)
|
||||
val remoteOutcomes: ContractInfo = {
|
||||
outcomes.copy(contractDescriptor =
|
||||
outcomes.contractDescriptor.flip((input + remoteInput).satoshis))
|
||||
}
|
||||
|
||||
val changeAddress = BitcoinAddress.fromScriptPubKey(changeSPK, network)
|
||||
val remoteChangeAddress =
|
||||
|
@ -185,8 +182,7 @@ object TestDLCClient {
|
|||
}
|
||||
|
||||
val offer = DLCMessage.DLCOffer(
|
||||
oracleAndContractInfo =
|
||||
DLCMessage.OracleAndContractInfo(oracleInfo, offerOutcomes),
|
||||
contractInfo = offerOutcomes,
|
||||
pubKeys = offerPubKeys,
|
||||
totalCollateral = offerInput.satoshis,
|
||||
fundingInputs = offerFundingInputs,
|
||||
|
|
|
@ -1,37 +1,36 @@
|
|||
[ {
|
||||
"tpeName" : "contract_info_v0",
|
||||
"input" : "fda710550313383739383330313036323334303937393934330000000000000000133536333934333434353837303033323734353000000000074a9371132d373938323838383237313838393935333530000000000bebc200",
|
||||
"tpeName" : "contract_descriptor_v0",
|
||||
"input" : "fda71057031337343730333734383832303531313332393232000000000bebc200142d33363133323438373939393532393639383735000000000aeeb364142d343236333233333538353533323934303835370000000000000000",
|
||||
"fields" : {
|
||||
"tpe" : "fda710",
|
||||
"length" : "55",
|
||||
"length" : "57",
|
||||
"outcomes" : [ {
|
||||
"outcome" : "f8c323888565496f382949ff2d19303bb1e555f41faaccb31fd4592d1026a0bb",
|
||||
"localPayout" : "0000000000000000"
|
||||
}, {
|
||||
"outcome" : "a368cb1585fec2782673feb9043fdaebd5428783a102cfde3a3886e86659172e",
|
||||
"localPayout" : "00000000074a9371"
|
||||
}, {
|
||||
"outcome" : "680d392bea45c4bed262f3b180aa325da3a7b3d65de2f334c3c778761685cadc",
|
||||
"outcome" : "18aadcad027d04c91806b55b6d533af4427f2196197463f9a71ca728219993b4",
|
||||
"localPayout" : "000000000bebc200"
|
||||
}, {
|
||||
"outcome" : "241b50567287d20db68a351b6f06f4feda0d731d9744e2cea42076ca14a7f8fe",
|
||||
"localPayout" : "000000000aeeb364"
|
||||
}, {
|
||||
"outcome" : "8fef4af31be25553203dafd671068dce1f8da1411c53a868a084941036c9c858",
|
||||
"localPayout" : "0000000000000000"
|
||||
} ]
|
||||
}
|
||||
}, {
|
||||
"tpeName" : "oracle_info_v0",
|
||||
"input" : "fda7124081643fa4a105ee583e26f77db925c81e89781f3e71cf28e3b517a5e984a093d6218f01ddec118e1e2a5ee1a0ac8d8618f59eaaed3e83d33ae3ea07752c76af7c",
|
||||
"input" : "fda712a8fdd824a4fab22628f6e2602e1671c286a2f63a9246794008627a1749639217f4214cb4a9494c93d1a852221080f44f697adb4355df59eb339f6ba0f9b01ba661a8b108d4da078bbb1d34e7729e38e2ae34236e776da121af442626fa31e31ae55a279a0bfdd8224000013cfba011378411b20a5ab773cb95daab93e9bcd1e4cce44986a7dda84e01841b00000000fdd8061000020664756d6d79310664756d6d79320564756d6d79",
|
||||
"fields" : {
|
||||
"tpe" : "fda712",
|
||||
"length" : "40",
|
||||
"pubKey" : "81643fa4a105ee583e26f77db925c81e89781f3e71cf28e3b517a5e984a093d6",
|
||||
"rValue" : "218f01ddec118e1e2a5ee1a0ac8d8618f59eaaed3e83d33ae3ea07752c76af7c"
|
||||
"length" : "a8",
|
||||
"announcement" : "fdd824a4fab22628f6e2602e1671c286a2f63a9246794008627a1749639217f4214cb4a9494c93d1a852221080f44f697adb4355df59eb339f6ba0f9b01ba661a8b108d4da078bbb1d34e7729e38e2ae34236e776da121af442626fa31e31ae55a279a0bfdd8224000013cfba011378411b20a5ab773cb95daab93e9bcd1e4cce44986a7dda84e01841b00000000fdd8061000020664756d6d79310664756d6d79320564756d6d79"
|
||||
}
|
||||
}, {
|
||||
"tpeName" : "funding_input_v0",
|
||||
"input" : "fda71437002902000000000100c2eb0b00000000160014053d0b5c0436a6d1718648f13b85dd86fde7d0d40000000000000000ffffffff006b0000",
|
||||
"input" : "fda71437002902000000000100c2eb0b00000000160014e70dcc9ffa7ff84c889c9e79b218708bae3bc9580000000000000000ffffffff006b0000",
|
||||
"fields" : {
|
||||
"tpe" : "fda714",
|
||||
"length" : "37",
|
||||
"prevTxLen" : "0029",
|
||||
"prevTx" : "02000000000100c2eb0b00000000160014053d0b5c0436a6d1718648f13b85dd86fde7d0d400000000",
|
||||
"prevTx" : "02000000000100c2eb0b00000000160014e70dcc9ffa7ff84c889c9e79b218708bae3bc95800000000",
|
||||
"prevTxVout" : "00000000",
|
||||
"sequence" : "ffffffff",
|
||||
"maxWitnessLen" : "006b",
|
||||
|
@ -40,24 +39,24 @@
|
|||
}
|
||||
}, {
|
||||
"tpeName" : "cet_adaptor_signatures_v0",
|
||||
"input" : "fda716fd01e703018c8ec8726fe693d4b6b6bffcca429101448a80096eafc35d7298ea42770a19aa16a8ef931403b93432d660033d9d00ceb5ca9c8d3d66c68e2d6f75b67e8e239c0059184e0b0bcff0568fe91e651e35353cad516c714016e29a2c1a4f4ddb7529b4142330861ef4fe794171617fbe3c386d26cf87fc616d9672fd627e035994ff6c5b190906464fd120ef63b9ec7a37082a1ad7593ec2eebd8621f10d1bc15c5b59005df60b967ec3b8201bec3c5754dbccc8ceb3031aac9a2fd341cbb72ab435227dc6e84d6d6638f4598edcf8dd99dd97154949309b236dd7bd570280434b9415aa01e145a633cc81286f8f1500025727152999586a26878d75e6b66a170a4ace3e86ac9bc5e6ee89dab9aef774561163258e9f058c7097d55b8a9b2506ecf1a8d1d611e7463500b98eb154dd37d54ffac093a947599483e6578db931b5b43c2de6e201dd29f198b2e154f9853987e9d31d48a272aa5afd9d774b02b55b27ce53d4136f2caed5168e29bab159809784c512c5066995d0ba511bbdc2c1ca8ed434f5be2d01c6e96bd0064385420b2db773738846811b29d0ba8dcb10bd73754e9ab2692ac853b313e0ee62b748082dabe8210956ed91efbd1d12c96ff8e33fc04b4e9108843bf6ed202ea81b556a310b45974d120cb502ebae132ffa3dc7e206cb1ff34205",
|
||||
"input" : "fda716fd01e703005030c6b47800881605e2664820fe34507b5c27de3f21055494dadc6fc16ad26ef4009d6214467cd9bc75461b5bc401fb4f88f3ef6999788bb7c15abd2a6e6d0e00a8df0ec2fd10fa25fd1b3c783744526d9159563ac8050046c871e0517974c234d8b3804d87f952363d23a38d037a2350eeb854bca721ffeced60bd2f4d3c322a28e679a28c0e25c98d52ab0dedbbc103639edf32f922c9d60bb0a399a10fec2a00c1c9af6bac6f2e25ee91d918f82215a64452233362732d4b003204d3d4656f1b480d3274963308e7fe9b6d7bce87ceb92f1270bf954242d4a7b44c218093a741018d917c2e18d30840f8c0892192174459819699924c2f67b169b8a7ff44221760e0e69a6f3ee9bf531869fdec716b2863d48325d4aa41302eaed3b86b261d9380d77ae7cc5e1a9950b0b962d0f218802221b087f90e584a4d9b384fafa7a016c50025b86e63b3bf4edfba24bfdc019832ea1be085700aa8358ff5b5e510414915f5a204ad05b8866c9d83ba396b91c8ff5461c80c6f091d576afdbe98971d885ca700437301b19548a3ed227301acb3a8ec791c2ff52035007077caa3ca9d012860d5329024c06aa12b1154be4298a659a294a45b257f0d3c282d9d7adbe0db7972cd5e141e5bdb3b6db5460b583cbc38a805a63cb1352b489000d2ec4cc43dc40e77",
|
||||
"fields" : {
|
||||
"tpe" : "fda716",
|
||||
"length" : "fd01e7",
|
||||
"sigs" : [ {
|
||||
"encryptedSig" : "018c8ec8726fe693d4b6b6bffcca429101448a80096eafc35d7298ea42770a19aa16a8ef931403b93432d660033d9d00ceb5ca9c8d3d66c68e2d6f75b67e8e239c",
|
||||
"dleqProof" : "0059184e0b0bcff0568fe91e651e35353cad516c714016e29a2c1a4f4ddb7529b4142330861ef4fe794171617fbe3c386d26cf87fc616d9672fd627e035994ff6c5b190906464fd120ef63b9ec7a37082a1ad7593ec2eebd8621f10d1bc15c5b59"
|
||||
"encryptedSig" : "005030c6b47800881605e2664820fe34507b5c27de3f21055494dadc6fc16ad26ef4009d6214467cd9bc75461b5bc401fb4f88f3ef6999788bb7c15abd2a6e6d0e",
|
||||
"dleqProof" : "00a8df0ec2fd10fa25fd1b3c783744526d9159563ac8050046c871e0517974c234d8b3804d87f952363d23a38d037a2350eeb854bca721ffeced60bd2f4d3c322a28e679a28c0e25c98d52ab0dedbbc103639edf32f922c9d60bb0a399a10fec2a"
|
||||
}, {
|
||||
"encryptedSig" : "005df60b967ec3b8201bec3c5754dbccc8ceb3031aac9a2fd341cbb72ab435227dc6e84d6d6638f4598edcf8dd99dd97154949309b236dd7bd570280434b9415aa",
|
||||
"dleqProof" : "01e145a633cc81286f8f1500025727152999586a26878d75e6b66a170a4ace3e86ac9bc5e6ee89dab9aef774561163258e9f058c7097d55b8a9b2506ecf1a8d1d611e7463500b98eb154dd37d54ffac093a947599483e6578db931b5b43c2de6e2"
|
||||
"encryptedSig" : "00c1c9af6bac6f2e25ee91d918f82215a64452233362732d4b003204d3d4656f1b480d3274963308e7fe9b6d7bce87ceb92f1270bf954242d4a7b44c218093a741",
|
||||
"dleqProof" : "018d917c2e18d30840f8c0892192174459819699924c2f67b169b8a7ff44221760e0e69a6f3ee9bf531869fdec716b2863d48325d4aa41302eaed3b86b261d9380d77ae7cc5e1a9950b0b962d0f218802221b087f90e584a4d9b384fafa7a016c5"
|
||||
}, {
|
||||
"encryptedSig" : "01dd29f198b2e154f9853987e9d31d48a272aa5afd9d774b02b55b27ce53d4136f2caed5168e29bab159809784c512c5066995d0ba511bbdc2c1ca8ed434f5be2d",
|
||||
"dleqProof" : "01c6e96bd0064385420b2db773738846811b29d0ba8dcb10bd73754e9ab2692ac853b313e0ee62b748082dabe8210956ed91efbd1d12c96ff8e33fc04b4e9108843bf6ed202ea81b556a310b45974d120cb502ebae132ffa3dc7e206cb1ff34205"
|
||||
"encryptedSig" : "0025b86e63b3bf4edfba24bfdc019832ea1be085700aa8358ff5b5e510414915f5a204ad05b8866c9d83ba396b91c8ff5461c80c6f091d576afdbe98971d885ca7",
|
||||
"dleqProof" : "00437301b19548a3ed227301acb3a8ec791c2ff52035007077caa3ca9d012860d5329024c06aa12b1154be4298a659a294a45b257f0d3c282d9d7adbe0db7972cd5e141e5bdb3b6db5460b583cbc38a805a63cb1352b489000d2ec4cc43dc40e77"
|
||||
} ]
|
||||
}
|
||||
}, {
|
||||
"tpeName" : "funding_signatures_v0",
|
||||
"input" : "fda71871000100020048304502210090276d8795ed508925d627e231a9652f9b6eac74bebc84c280eb10456e16acde02206f37585646dc65454f33e1dc7cf08fa7557e40d2318314c93579992e081f1923010021021db97135d3ab89e799b2b8efec086038041f439034fc3f0443ae986fe02bd552",
|
||||
"input" : "fda718710001000200483045022100b16f3aad7591ab2d22e33c84c9a385546776810cf9134f4b38ef714635cb312a02202e3c1a7b983501de70f4316ebce9e484ce87f4bdf067eba50597503b3e219ca601002102b8c26d692ae3f6f3dcb78c5bb660b90bdc90e7cdaafeec94f63de0fa08ab403e",
|
||||
"fields" : {
|
||||
"tpe" : "fda718",
|
||||
"length" : "71",
|
||||
|
@ -66,60 +65,59 @@
|
|||
"stackLen" : "0002",
|
||||
"stack" : [ {
|
||||
"stackElementLen" : "0048",
|
||||
"stackElement" : "304502210090276d8795ed508925d627e231a9652f9b6eac74bebc84c280eb10456e16acde02206f37585646dc65454f33e1dc7cf08fa7557e40d2318314c93579992e081f192301"
|
||||
"stackElement" : "3045022100b16f3aad7591ab2d22e33c84c9a385546776810cf9134f4b38ef714635cb312a02202e3c1a7b983501de70f4316ebce9e484ce87f4bdf067eba50597503b3e219ca601"
|
||||
}, {
|
||||
"stackElementLen" : "0021",
|
||||
"stackElement" : "021db97135d3ab89e799b2b8efec086038041f439034fc3f0443ae986fe02bd552"
|
||||
"stackElement" : "02b8c26d692ae3f6f3dcb78c5bb660b90bdc90e7cdaafeec94f63de0fa08ab403e"
|
||||
} ]
|
||||
} ]
|
||||
}
|
||||
}, {
|
||||
"tpeName" : "offer_dlc_v0",
|
||||
"input" : "a71a0006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910ffda7105703133736363931393336343532323830393236343900000000097a46cd142d34343932383232333839373539363634313830000000000bebc200142d343930313436363239333731383033323434310000000000000000fda71240f17f614d83f0a12f70c99aac831a33d1374c3cd1d435f346215dcb3924cd3c754b75d5510c30f713c39fa1b42198f8de22042aa38f84aff186f5fe83abc98299030407874e02b13492a679915f678d61a063f5dee609135e8489caf0aa85ab54ef00160014af7efec124314243c07b2aff5feb98762e408e0c0000000005f5e1000001fda71437002902000000000100c2eb0b00000000160014fe759e578312948a553a8a5dbe5bb588f1c4f1890000000000000000ffffffff006b00000016001494eb035c0ef04a32edee53d9810a9e663f8642b5000000000000000100000064000000c8",
|
||||
"input" : "a71a0006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910ffdd82efd0139000000000bebc200fda71054031331313735353432353737323939343932373434000000000592ab711331393738383935313131323435383436303133000000000000000012353538303833303332333138373338333634000000000bebc200fda712d5fdd824d1c16171569e48d1dcaa9144ee9021558a979792eb5670a581b362d788ff5bed31a97328c9bc55d2eac086f271d194ba106f0bbc8061cc340971be61a7fdb35737015f4361a2eadd269728a4e107aa3b0de033951f849cde3cc0e0536c7bdedcf4fdd8226d00014c8d56e0967ad13461bab6ade6980179e7acde2c8deb1d35cb9fd523980434eb00000000fdd8063d000313313137353534323537373239393439323734341331393738383935313131323435383436303133123535383038333033323331383733383336340564756d6d790327efea09ff4dfb13230e887cbab8821d5cc249c7ff28668c6633ff9f4b4c08e3001600142bbdec425007dc360523b0294d2c64d2213af4980000000005f5e1000001fda71437002902000000000100c2eb0b00000000160014369d63a82ed846f4d47ad55045e594ab95539d600000000000000000ffffffff006b000000160014afa16f949f3055f38bd3a73312bed00b61558884000000000000000100000064000000c8",
|
||||
"fields" : {
|
||||
"tpe" : "a71a",
|
||||
"contractFlags" : "00",
|
||||
"chainHash" : "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f",
|
||||
"contractInfo" : "fda7105703133736363931393336343532323830393236343900000000097a46cd142d34343932383232333839373539363634313830000000000bebc200142d343930313436363239333731383033323434310000000000000000",
|
||||
"oracleInfo" : "fda71240f17f614d83f0a12f70c99aac831a33d1374c3cd1d435f346215dcb3924cd3c754b75d5510c30f713c39fa1b42198f8de22042aa38f84aff186f5fe83abc98299",
|
||||
"fundingPubKey" : "030407874e02b13492a679915f678d61a063f5dee609135e8489caf0aa85ab54ef",
|
||||
"contractInfo" : "fdd82efd0139000000000bebc200fda71054031331313735353432353737323939343932373434000000000592ab711331393738383935313131323435383436303133000000000000000012353538303833303332333138373338333634000000000bebc200fda712d5fdd824d1c16171569e48d1dcaa9144ee9021558a979792eb5670a581b362d788ff5bed31a97328c9bc55d2eac086f271d194ba106f0bbc8061cc340971be61a7fdb35737015f4361a2eadd269728a4e107aa3b0de033951f849cde3cc0e0536c7bdedcf4fdd8226d00014c8d56e0967ad13461bab6ade6980179e7acde2c8deb1d35cb9fd523980434eb00000000fdd8063d000313313137353534323537373239393439323734341331393738383935313131323435383436303133123535383038333033323331383733383336340564756d6d79",
|
||||
"fundingPubKey" : "0327efea09ff4dfb13230e887cbab8821d5cc249c7ff28668c6633ff9f4b4c08e3",
|
||||
"payoutSPKLen" : "0016",
|
||||
"payoutSPK" : "0014af7efec124314243c07b2aff5feb98762e408e0c",
|
||||
"payoutSPK" : "00142bbdec425007dc360523b0294d2c64d2213af498",
|
||||
"totalCollateralSatoshis" : "0000000005f5e100",
|
||||
"fundingInputsLen" : "0001",
|
||||
"fundingInputs" : [ "fda71437002902000000000100c2eb0b00000000160014fe759e578312948a553a8a5dbe5bb588f1c4f1890000000000000000ffffffff006b0000" ],
|
||||
"fundingInputs" : [ "fda71437002902000000000100c2eb0b00000000160014369d63a82ed846f4d47ad55045e594ab95539d600000000000000000ffffffff006b0000" ],
|
||||
"changeSPKLen" : "0016",
|
||||
"changeSPK" : "001494eb035c0ef04a32edee53d9810a9e663f8642b5",
|
||||
"changeSPK" : "0014afa16f949f3055f38bd3a73312bed00b61558884",
|
||||
"feeRate" : "0000000000000001",
|
||||
"contractMaturityBound" : "00000064",
|
||||
"contractTimeout" : "000000c8"
|
||||
}
|
||||
}, {
|
||||
"tpeName" : "accept_dlc_v0",
|
||||
"input" : "a71c9d322b27cfbbb5c1387acd985b554953eafbce8db21d0cf244750b9306ef561d0000000005f5e10002a997405cbaa2c40ae72e51e834074d29f3c825921543f59f8d7152ac5640f41000160014dba4cf029c1dd41a0905a039c7559c8a07712fee0001fda71437002902000000000100c2eb0b00000000160014c97292d1dfb59da5ae6a9da2c0102d07e53bba080000000000000000ffffffff006b000000160014c50e3cb3a242d25050ab04128acd2d8ee3e2eecffda716fd01e703018b97dd8ca3771815391051c0fd9ece7b3cba3b2e88896a5aaf2e8f61c3dc959ac3f5e712d15939a090ba9a1f626894863ef34162c392c6db53d3d5de76ff7907012544a0d021ec9b47ee3fabe5d3107ecfbe7d2b7959aabf5c7cd26526b5b0ac576993cd15bb21ab6786b18bcfa5206a97871f9d051e5e949f18b3fe489db1327b52acf8f1f1bc3c001a6c096e5cf8d1cca2eda845f56a16be241d03bb72fb81290131f2ef57d89dea2eda03d08b402c66c79333caa6a3139c16ac1a771ddc56ae7ff75f34eaa04d1fc8661466589cb87d22633b22db1431052d7f28679a2d9c6d8d01128ce8235b9045a8a70e5987228a18e722847d8d85756a49ad574812b84d35c6766845a99166da49d3e31275bc8bb5a5f6315710269ca4670fad828bdf01c5a1e9328f29381138a1fac1a5189b1d0c9ad24c200b8d87e8a0409eaa8c9ab7981d00251f9ec2d54f67edbf6cced161827da759425cc3e256eca68c7070b80484a23cbecbdf0c0053cc24d070739cc25b4987759e69d6f66be179eed83bd5a052649400fcbff364d8de8fe6d7ac3a672f2824542a8f0386f1e94a4f7f5f050c5bc7021dcada2ae29a175903a51457bec01bc33d6489df4fb7e2f4dd620de945cc00dab84d6ba82e0af199ae93aba23382dc2772bf0d8e8be3516ac7045a57ec5ce009cb071c251c7275706eca59f1a03e0094a120b0bbdc377b5464d049d63fc468aa7b4c5a372dd656334293abd0424b48acd8569dabd4fc3bc563dc90c27ca8700c07fdd82600",
|
||||
"input" : "a71c960fb5f7960382ac7e76f3e24eb6b00059b1e68632a946843c22e1f65fdf216a0000000005f5e100026d8bec9093f96ccc42de166cb9a6c576c95fc24ee16b10e87c3baaa4e49684d90016001436054fa379f7564b5e458371db643666365c8fb30001fda71437002902000000000100c2eb0b000000001600149ea3bf2d6eb9c2ffa35e36f41e117403ed7fafe90000000000000000ffffffff006b000000160014074c82dbe058212905bacc61814456b7415012edfda716fd01e703016292f1b5c67b675aea69c95ec81e8462ab5bb9b7a01f810f6d1a7d1d886893b3605fe7fcb75a14b1b1de917917d37e9efac6437d7a080da53fb6dbbcfbfbe7a801efbecb2bce89556e1fb4d31622628830e02a6d04c487f67aca20e9f60fb127f985293541cd14e2bf04e4777d50953531e169dd37c65eb3cc17d6b5e4dbe58487f9fae1f68f603fe014a699a346b14a63048c26c9b31236d83a7e369a2b29a29200e52fe05d832bcce4538d9c27f3537a0f2086b265b6498f30cf667f77ff2fa87606574bc9a915ef57f7546ebb6852a490ad0547bdc52b19791d2d0f0cc0acabab01f32459001a28850fa8ee4278111deb0494a8175f02e31a1c18b39bd82ec64026a6f341bcd5ba169d67b855030e36bdc65feecc0397a07d3bc514da69811ec5485f5553aebda782bc5ac9b47e8e11d701a38ef2c2b7d8af3906dd8dfc759754ce006f769592c744141a5ddface6e98f756a9df1bb75ad41508ea013bdfee133b396d85be51f870bf2e0ae836bfa984109dab96cc6f4ab2a7f118bc6b0b25a4c70d401c768c1d677c6ff0b7ea69fdf29aff1000794227db368dff16e838d1f44c4afe9e952ee63d603f7b14de13c1d73b363cc2b1740d0b688e73d8e71cddf40f8e7e912df413903779c4e5d6644c504c8609baec8fdcb90d6d341cf316748f5d7945f7c8ad6de287b62a1ed1d74ed9116a5158abc7f97376d201caa88e0f9daad68fcda4c271cc003512e768f403a57e5242bd1f6aa1750d7f3597598094a43b1c7bbfdd82600",
|
||||
"fields" : {
|
||||
"tpe" : "a71c",
|
||||
"tempContractId" : "9d322b27cfbbb5c1387acd985b554953eafbce8db21d0cf244750b9306ef561d",
|
||||
"tempContractId" : "960fb5f7960382ac7e76f3e24eb6b00059b1e68632a946843c22e1f65fdf216a",
|
||||
"totalCollateralSatoshis" : "0000000005f5e100",
|
||||
"fundingPubKey" : "02a997405cbaa2c40ae72e51e834074d29f3c825921543f59f8d7152ac5640f410",
|
||||
"fundingPubKey" : "026d8bec9093f96ccc42de166cb9a6c576c95fc24ee16b10e87c3baaa4e49684d9",
|
||||
"payoutSPKLen" : "0016",
|
||||
"payoutSPK" : "0014dba4cf029c1dd41a0905a039c7559c8a07712fee",
|
||||
"payoutSPK" : "001436054fa379f7564b5e458371db643666365c8fb3",
|
||||
"fundingInputsLen" : "0001",
|
||||
"fundingInputs" : [ "fda71437002902000000000100c2eb0b00000000160014c97292d1dfb59da5ae6a9da2c0102d07e53bba080000000000000000ffffffff006b0000" ],
|
||||
"fundingInputs" : [ "fda71437002902000000000100c2eb0b000000001600149ea3bf2d6eb9c2ffa35e36f41e117403ed7fafe90000000000000000ffffffff006b0000" ],
|
||||
"changeSPKLen" : "0016",
|
||||
"changeSPK" : "0014c50e3cb3a242d25050ab04128acd2d8ee3e2eecf",
|
||||
"cetSignatures" : "fda716fd01e703018b97dd8ca3771815391051c0fd9ece7b3cba3b2e88896a5aaf2e8f61c3dc959ac3f5e712d15939a090ba9a1f626894863ef34162c392c6db53d3d5de76ff7907012544a0d021ec9b47ee3fabe5d3107ecfbe7d2b7959aabf5c7cd26526b5b0ac576993cd15bb21ab6786b18bcfa5206a97871f9d051e5e949f18b3fe489db1327b52acf8f1f1bc3c001a6c096e5cf8d1cca2eda845f56a16be241d03bb72fb81290131f2ef57d89dea2eda03d08b402c66c79333caa6a3139c16ac1a771ddc56ae7ff75f34eaa04d1fc8661466589cb87d22633b22db1431052d7f28679a2d9c6d8d01128ce8235b9045a8a70e5987228a18e722847d8d85756a49ad574812b84d35c6766845a99166da49d3e31275bc8bb5a5f6315710269ca4670fad828bdf01c5a1e9328f29381138a1fac1a5189b1d0c9ad24c200b8d87e8a0409eaa8c9ab7981d00251f9ec2d54f67edbf6cced161827da759425cc3e256eca68c7070b80484a23cbecbdf0c0053cc24d070739cc25b4987759e69d6f66be179eed83bd5a052649400fcbff364d8de8fe6d7ac3a672f2824542a8f0386f1e94a4f7f5f050c5bc7021dcada2ae29a175903a51457bec01bc33d6489df4fb7e2f4dd620de945cc00dab84d6ba82e0af199ae93aba23382dc2772bf0d8e8be3516ac7045a57ec5ce009cb",
|
||||
"refundSignature" : "071c251c7275706eca59f1a03e0094a120b0bbdc377b5464d049d63fc468aa7b4c5a372dd656334293abd0424b48acd8569dabd4fc3bc563dc90c27ca8700c07",
|
||||
"changeSPK" : "0014074c82dbe058212905bacc61814456b7415012ed",
|
||||
"cetSignatures" : "fda716fd01e703016292f1b5c67b675aea69c95ec81e8462ab5bb9b7a01f810f6d1a7d1d886893b3605fe7fcb75a14b1b1de917917d37e9efac6437d7a080da53fb6dbbcfbfbe7a801efbecb2bce89556e1fb4d31622628830e02a6d04c487f67aca20e9f60fb127f985293541cd14e2bf04e4777d50953531e169dd37c65eb3cc17d6b5e4dbe58487f9fae1f68f603fe014a699a346b14a63048c26c9b31236d83a7e369a2b29a29200e52fe05d832bcce4538d9c27f3537a0f2086b265b6498f30cf667f77ff2fa87606574bc9a915ef57f7546ebb6852a490ad0547bdc52b19791d2d0f0cc0acabab01f32459001a28850fa8ee4278111deb0494a8175f02e31a1c18b39bd82ec64026a6f341bcd5ba169d67b855030e36bdc65feecc0397a07d3bc514da69811ec5485f5553aebda782bc5ac9b47e8e11d701a38ef2c2b7d8af3906dd8dfc759754ce006f769592c744141a5ddface6e98f756a9df1bb75ad41508ea013bdfee133b396d85be51f870bf2e0ae836bfa984109dab96cc6f4ab2a7f118bc6b0b25a4c70d401c768c1d677c6ff0b7ea69fdf29aff1000794227db368dff16e838d1f44c4afe9e952ee63d603f7b14de13c1d73b363cc2b1740d0b688e73d8e71cddf40f8e7e912df413903779c4e5d6644c504c8609baec8fdcb90d6d341cf316748f5d7945f",
|
||||
"refundSignature" : "7c8ad6de287b62a1ed1d74ed9116a5158abc7f97376d201caa88e0f9daad68fcda4c271cc003512e768f403a57e5242bd1f6aa1750d7f3597598094a43b1c7bb",
|
||||
"negotiationFields" : "fdd82600"
|
||||
}
|
||||
}, {
|
||||
"tpeName" : "sign_dlc_v0",
|
||||
"input" : "a71e59e67278aa6bd346ecb2147d6f3763c75047ada2088a3a0ca766effc149fcff4fda716fd01e70301f08da14891887cc00cf865b96d085db2e874dd5a5693b4eecf8029c7ef69781535d77210b2e4e22f0ea1dc1a61cfc883e8cc4f885e8b65e9f8f127957cca240f013feffdc413863e5c0dbcf59216d444fdc473a78ad0eda3625a66be484d2184d5939e8f7ee812acb9ef9e205e147a3e3d839380ed97609b7033b81b99416f748043f0426510c6c090b1b5d07216c719bc41f2d78855507358c45497e3c8d6d6b60190edadc2b7d7c96d7c7777cf3cf622e156d5203604f2c8e506d46dd5e50639f7bd0dc4c7a87d66442d1ad394ee1db6b82078b79b3fc1fa2f379763be45363aec01d2ad2e223aaf85978ab5880593e0c1e5405185b51656ac3fbf3a8cd1c7b2ae8d9e9aa04d1b05e473ba49dc5be919cfae63e96b843969612d4e9298aad57df99c5650930df7869a260884d33ea280a432f47d1ce976a3a8c1f6c5f6223a40c95601f06172c4977a2040c9c043b6757dfc143d8b1c94414db14cbe6d0112a15af8641b26c55e031d86fd1ccadef6c87bb8c1366ef7fac66931aecc086a6fce227eeb00741b84a32f49aacaf1600015aae3ae879439d71d81c69e19956d48b4794334a38534dd702a49edbc1113466e48b3c46d487bc035c1097376dbb05ea09889b2f77604605934bb6c776b2b719311bc6a8c06f6180002fbcf2d814f24e9f95963bdf4fa3e6b711593a9f56b9897a41c6d5debb9a00075e9d06c0b17116b69844ba129b861daf7919e86e366bdee5632164293a7a19131c6f1fe10fe6eedc7dcb36ffda718710001000200483045022100a5ff7bf98bd38d7b60e92c9a65083c3dbc102a7dd6c7cf3b090c2ab541fe3b2b02207f1f954d9c2336444171ab9508fa32e4608bf9a246452e53f6d793bca4d34dd6010021028a43479523323c8449fcb574b975af240a3a8d419b8c8246d729d4205c11d473",
|
||||
"input" : "a71ec1c79e1e9e2fa2840b2514902ea244f39eb3001a4037a52ea43c797d4f841269fda716fd01e70300c706fe7ed70197a77397fb7ce8445fcf1d0b239b4ab41ebdad4f76e0a671d7830470f4fef96d0838e8f3cec33176a6a427d777b57d256f8545b570cd702972910192f8ad4eb341ac2867d203360516028b967b46ef0e5d1603b59a7d8ebc81d655dd11673febcf098006eba74b3604d0a1da818208ea2833079505a3dee7392255f0682e5b357a7382aae6e5bdcc728b94c9d0a52fb6f49ac5cbe32804fcfb71b10125e92381be588737f6ac5c28325c843c6551995880f830d926abd35ee3f8ed9fdfc47a5fd277d0df2a1f1d0bafba8efad7b127e2a232a4846ed90810c81e65750039dba803adb78100f20ca12b09b68a92b996b07a5ee47806379cedfa217848644f48d96ed6443ea7143adf1ce19a4386d0841b5071e31f5d3e4c479eab6a856b426c80d091da3de3959b29e4c2e3ae47ddba2758c2ca1c6a064dfee4671ba5010098f2595778a1596054ffcafb599f8f4a65c4215de757548c142d50b12eb67d4c1407690b808e33eba95fe818223886fd8e9ce4c758b4662636af663e0055376300a915ee71914ee8ae2c18d55b397649c0057a01f0a85c6ecf1b0eb26f7485f21b24c89013e1cb15a4bf40256e52a66751f33de46032db0801975933be2977a1e37d5d5f2d43f48481cc68783dbfeb21a35c62c1ca2eb6ee2ccfc12b74e9fd7a08fbf56fbb4bbcb01d1be3169dfda6f465020ee89c1e368d4a91e36d0d4cc44e6123db348c223988dfe147d611ae9351d6e78cfb902e3d01beed0c909e52a3aae9fda71870000100020047304402203812d7d194d44ec68f244cc3fd68507c563ec8c729fdfa3f4a79395b98abe84f0220704ab3f3ffd9c50c2488e59f90a90465fccc2d924d67a1e98a133676bf52f37201002102dde41aa1f21671a2e28ad92155d2d66e0b5428de15d18db4cbcf216bf00de919",
|
||||
"fields" : {
|
||||
"tpe" : "a71e",
|
||||
"contractId" : "59e67278aa6bd346ecb2147d6f3763c75047ada2088a3a0ca766effc149fcff4",
|
||||
"cetSignatures" : "fda716fd01e70301f08da14891887cc00cf865b96d085db2e874dd5a5693b4eecf8029c7ef69781535d77210b2e4e22f0ea1dc1a61cfc883e8cc4f885e8b65e9f8f127957cca240f013feffdc413863e5c0dbcf59216d444fdc473a78ad0eda3625a66be484d2184d5939e8f7ee812acb9ef9e205e147a3e3d839380ed97609b7033b81b99416f748043f0426510c6c090b1b5d07216c719bc41f2d78855507358c45497e3c8d6d6b60190edadc2b7d7c96d7c7777cf3cf622e156d5203604f2c8e506d46dd5e50639f7bd0dc4c7a87d66442d1ad394ee1db6b82078b79b3fc1fa2f379763be45363aec01d2ad2e223aaf85978ab5880593e0c1e5405185b51656ac3fbf3a8cd1c7b2ae8d9e9aa04d1b05e473ba49dc5be919cfae63e96b843969612d4e9298aad57df99c5650930df7869a260884d33ea280a432f47d1ce976a3a8c1f6c5f6223a40c95601f06172c4977a2040c9c043b6757dfc143d8b1c94414db14cbe6d0112a15af8641b26c55e031d86fd1ccadef6c87bb8c1366ef7fac66931aecc086a6fce227eeb00741b84a32f49aacaf1600015aae3ae879439d71d81c69e19956d48b4794334a38534dd702a49edbc1113466e48b3c46d487bc035c1097376dbb05ea09889b2f77604605934bb6c776b2b719311bc6a8c06f6180002fbcf2d814f24e9f95963bd",
|
||||
"refundSignature" : "f4fa3e6b711593a9f56b9897a41c6d5debb9a00075e9d06c0b17116b69844ba129b861daf7919e86e366bdee5632164293a7a19131c6f1fe10fe6eedc7dcb36f",
|
||||
"fundingSignatures" : "fda718710001000200483045022100a5ff7bf98bd38d7b60e92c9a65083c3dbc102a7dd6c7cf3b090c2ab541fe3b2b02207f1f954d9c2336444171ab9508fa32e4608bf9a246452e53f6d793bca4d34dd6010021028a43479523323c8449fcb574b975af240a3a8d419b8c8246d729d4205c11d473"
|
||||
"contractId" : "c1c79e1e9e2fa2840b2514902ea244f39eb3001a4037a52ea43c797d4f841269",
|
||||
"cetSignatures" : "fda716fd01e70300c706fe7ed70197a77397fb7ce8445fcf1d0b239b4ab41ebdad4f76e0a671d7830470f4fef96d0838e8f3cec33176a6a427d777b57d256f8545b570cd702972910192f8ad4eb341ac2867d203360516028b967b46ef0e5d1603b59a7d8ebc81d655dd11673febcf098006eba74b3604d0a1da818208ea2833079505a3dee7392255f0682e5b357a7382aae6e5bdcc728b94c9d0a52fb6f49ac5cbe32804fcfb71b10125e92381be588737f6ac5c28325c843c6551995880f830d926abd35ee3f8ed9fdfc47a5fd277d0df2a1f1d0bafba8efad7b127e2a232a4846ed90810c81e65750039dba803adb78100f20ca12b09b68a92b996b07a5ee47806379cedfa217848644f48d96ed6443ea7143adf1ce19a4386d0841b5071e31f5d3e4c479eab6a856b426c80d091da3de3959b29e4c2e3ae47ddba2758c2ca1c6a064dfee4671ba5010098f2595778a1596054ffcafb599f8f4a65c4215de757548c142d50b12eb67d4c1407690b808e33eba95fe818223886fd8e9ce4c758b4662636af663e0055376300a915ee71914ee8ae2c18d55b397649c0057a01f0a85c6ecf1b0eb26f7485f21b24c89013e1cb15a4bf40256e52a66751f33de46032db0801975933be2977a1e37d5d5f2d43f48481cc68783dbfeb21a35c62c1ca2eb6ee2ccfc12b74e9fd7a08",
|
||||
"refundSignature" : "fbf56fbb4bbcb01d1be3169dfda6f465020ee89c1e368d4a91e36d0d4cc44e6123db348c223988dfe147d611ae9351d6e78cfb902e3d01beed0c909e52a3aae9",
|
||||
"fundingSignatures" : "fda71870000100020047304402203812d7d194d44ec68f244cc3fd68507c563ec8c729fdfa3f4a79395b98abe84f0220704ab3f3ffd9c50c2488e59f90a90465fccc2d924d67a1e98a133676bf52f37201002102dde41aa1f21671a2e28ad92155d2d66e0b5428de15d18db4cbcf216bf00de919"
|
||||
}
|
||||
} ]
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
@ -73,7 +73,7 @@ case class DLCSignatureVerifier(builder: DLCTxBuilder, isInitiator: Boolean)
|
|||
builder.offerFundingKey
|
||||
}
|
||||
|
||||
val adaptorPoint = builder.oracleAndContractInfo.sigPointForOutcome(outcome)
|
||||
val adaptorPoint = builder.contractInfo.sigPointForOutcome(outcome)
|
||||
|
||||
val cet = Await.result(builder.buildCET(outcome), 5.seconds)
|
||||
|
||||
|
@ -93,7 +93,7 @@ case class DLCSignatureVerifier(builder: DLCTxBuilder, isInitiator: Boolean)
|
|||
def verifyCETSigs(sigs: Vector[(DLCOutcomeType, ECAdaptorSignature)])(implicit
|
||||
ec: ExecutionContext): Future[Boolean] = {
|
||||
val correctNumberOfSigs =
|
||||
sigs.size >= builder.oracleAndContractInfo.allOutcomes.length
|
||||
sigs.size >= builder.contractInfo.allOutcomes.length
|
||||
|
||||
def runVerify(
|
||||
outcomeSigs: Vector[(DLCOutcomeType, ECAdaptorSignature)]): Future[
|
||||
|
|
|
@ -115,7 +115,8 @@ trait TLVGen {
|
|||
} yield OracleAnnouncementV0TLV(sig, pubkey, eventTLV)
|
||||
}
|
||||
|
||||
def contractInfoV0TLV: Gen[ContractInfoV0TLV] = {
|
||||
def contractDescriptorV0TLVWithTotalCollateral: Gen[
|
||||
(ContractDescriptorV0TLV, Satoshis)] = {
|
||||
for {
|
||||
numOutcomes <- Gen.choose(2, 10)
|
||||
outcomes <- Gen.listOfN(numOutcomes, StringGenerators.genString)
|
||||
|
@ -123,18 +124,39 @@ trait TLVGen {
|
|||
Gen
|
||||
.choose(numOutcomes + 1, Long.MaxValue / 10000L)
|
||||
.map(Satoshis.apply)
|
||||
(contractInfo, _) =
|
||||
DLCTestUtil.genContractInfos(outcomes.toVector, totalInput)
|
||||
(contractDescriptor, _) =
|
||||
DLCTestUtil.genContractDescriptors(outcomes.toVector, totalInput)
|
||||
} yield {
|
||||
contractInfo.toTLV
|
||||
(contractDescriptor.toTLV, totalInput)
|
||||
}
|
||||
}
|
||||
|
||||
def contractDescriptorV0TLV: Gen[ContractDescriptorV0TLV] = {
|
||||
contractDescriptorV0TLVWithTotalCollateral.map(_._1)
|
||||
}
|
||||
|
||||
def oracleInfoV0TLV: Gen[OracleInfoV0TLV] = {
|
||||
for {
|
||||
pubKey <- CryptoGenerators.schnorrPublicKey
|
||||
privKey <- CryptoGenerators.privateKey
|
||||
rValue <- CryptoGenerators.schnorrNonce
|
||||
} yield OracleInfoV0TLV(pubKey, rValue)
|
||||
outcomes <- Gen.listOf(StringGenerators.genUTF8String)
|
||||
} yield {
|
||||
OracleInfoV0TLV(
|
||||
OracleAnnouncementV0TLV.dummyForEventsAndKeys(
|
||||
privKey,
|
||||
rValue,
|
||||
outcomes.toVector.map(EnumOutcome.apply)))
|
||||
}
|
||||
}
|
||||
|
||||
def contractInfoV0TLV: Gen[ContractInfoV0TLV] = {
|
||||
for {
|
||||
(descriptor, totalCollateral) <-
|
||||
contractDescriptorV0TLVWithTotalCollateral
|
||||
oracleInfo <- oracleInfoV0TLV
|
||||
} yield {
|
||||
ContractInfoV0TLV(totalCollateral, descriptor, oracleInfo)
|
||||
}
|
||||
}
|
||||
|
||||
def oracleInfoV0TLVWithKeys: Gen[
|
||||
|
@ -142,8 +164,13 @@ trait TLVGen {
|
|||
for {
|
||||
privKey <- CryptoGenerators.privateKey
|
||||
kValue <- CryptoGenerators.privateKey
|
||||
outcomes <- Gen.listOf(StringGenerators.genUTF8String)
|
||||
} yield {
|
||||
(OracleInfoV0TLV(privKey.schnorrPublicKey, kValue.schnorrNonce),
|
||||
(OracleInfoV0TLV(
|
||||
OracleAnnouncementV0TLV.dummyForEventsAndKeys(
|
||||
privKey,
|
||||
kValue.schnorrNonce,
|
||||
outcomes.toVector.map(EnumOutcome.apply))),
|
||||
privKey,
|
||||
kValue)
|
||||
}
|
||||
|
@ -235,7 +262,6 @@ trait TLVGen {
|
|||
chainHash <- Gen.oneOf(
|
||||
Networks.knownNetworks.map(_.chainParams.genesisBlock.blockHeader.hash))
|
||||
contractInfo <- contractInfoV0TLV
|
||||
oracleInfo <- oracleInfoV0TLV
|
||||
fundingPubKey <- CryptoGenerators.publicKey
|
||||
payoutAddress <- AddressGenerator.bitcoinAddress
|
||||
totalCollateralSatoshis <- CurrencyUnitGenerator.positiveRealistic
|
||||
|
@ -256,7 +282,6 @@ trait TLVGen {
|
|||
0.toByte,
|
||||
chainHash,
|
||||
contractInfo,
|
||||
oracleInfo,
|
||||
fundingPubKey,
|
||||
payoutAddress.scriptPubKey,
|
||||
totalCollateralSatoshis,
|
||||
|
@ -275,7 +300,10 @@ trait TLVGen {
|
|||
offer <- dlcOfferTLV
|
||||
(oracleInfo, oraclePrivKey, oracleRValue) <- oracleInfoV0TLVWithKeys
|
||||
} yield {
|
||||
(offer.copy(oracleInfo = oracleInfo), oraclePrivKey, oracleRValue)
|
||||
(offer.copy(contractInfo =
|
||||
offer.contractInfo.copy(oracleInfo = oracleInfo)),
|
||||
oraclePrivKey,
|
||||
oracleRValue)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.bitcoins.testkit.wallet
|
||||
|
||||
import org.bitcoins.core.currency.Satoshis
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.OracleAndContractInfo
|
||||
import org.bitcoins.core.protocol.dlc.DLCMessage.ContractInfo
|
||||
import org.bitcoins.db.AppConfig
|
||||
import org.bitcoins.dlc.testgen.DLCTestUtil
|
||||
import org.bitcoins.dlc.wallet.DLCAppConfig
|
||||
|
@ -80,21 +80,22 @@ trait BitcoinSDualWalletTest extends BitcoinSWalletTest {
|
|||
getBIP39PasswordOpt(),
|
||||
Some(segwitWalletConf))(config2, system)
|
||||
|
||||
oracleAndContractInfo =
|
||||
contractInfo =
|
||||
if (multiNonce) {
|
||||
DLCWalletUtil.multiNonceOracleAndContractInfo
|
||||
DLCWalletUtil.multiNonceContractInfo
|
||||
} else {
|
||||
val numOutcomes = 8
|
||||
val outcomes = DLCTestUtil.genOutcomes(numOutcomes)
|
||||
val (contractInfo, _) =
|
||||
DLCTestUtil.genContractInfos(outcomes, Satoshis(10000))
|
||||
val (contractDescriptor, _) =
|
||||
DLCTestUtil.genContractDescriptors(outcomes, Satoshis(10000))
|
||||
|
||||
OracleAndContractInfo(DLCWalletUtil.sampleOracleInfo,
|
||||
contractInfo)
|
||||
ContractInfo(Satoshis(10000),
|
||||
contractDescriptor,
|
||||
DLCWalletUtil.sampleOracleInfo)
|
||||
}
|
||||
|
||||
(dlcWalletA, dlcWalletB) <-
|
||||
DLCWalletUtil.initDLC(walletA, walletB, oracleAndContractInfo)
|
||||
DLCWalletUtil.initDLC(walletA, walletB, contractInfo)
|
||||
} yield (dlcWalletA, dlcWalletB),
|
||||
destroy = { dlcWallets: (InitializedDLCWallet, InitializedDLCWallet) =>
|
||||
for {
|
||||
|
|
|
@ -8,7 +8,11 @@ import org.bitcoins.core.policy.Policy
|
|||
import org.bitcoins.core.protocol.dlc.DLCMessage._
|
||||
import org.bitcoins.core.protocol.dlc._
|
||||
import org.bitcoins.core.protocol.script.{P2WPKHWitnessSPKV0, P2WPKHWitnessV0}
|
||||
import org.bitcoins.core.protocol.tlv.{DLCOutcomeType, EnumOutcome}
|
||||
import org.bitcoins.core.protocol.tlv.{
|
||||
DLCOutcomeType,
|
||||
EnumOutcome,
|
||||
OracleAnnouncementV0TLV
|
||||
}
|
||||
import org.bitcoins.core.protocol.transaction._
|
||||
import org.bitcoins.core.protocol.{BitcoinAddress, BlockTimeStamp}
|
||||
import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature
|
||||
|
@ -44,15 +48,20 @@ object DLCWalletUtil {
|
|||
lazy val loseHash: Sha256Digest =
|
||||
CryptoUtil.sha256DLCAttestation(loseStr)
|
||||
|
||||
val sampleOutcomes: Vector[(EnumOutcome, Satoshis)] = Vector(
|
||||
EnumOutcome(winStr) -> Satoshis(10000),
|
||||
EnumOutcome(loseStr) -> Satoshis.zero)
|
||||
|
||||
lazy val sampleContractDescriptor: ContractDescriptor =
|
||||
EnumContractDescriptor(sampleOutcomes)
|
||||
|
||||
lazy val sampleOracleInfo: OracleInfo =
|
||||
SingleNonceOracleInfo(oraclePrivKey.schnorrPublicKey, rValue)
|
||||
EnumSingleOracleInfo.dummyForKeys(oraclePrivKey,
|
||||
rValue,
|
||||
sampleOutcomes.map(_._1))
|
||||
|
||||
lazy val sampleContractInfo: ContractInfo =
|
||||
SingleNonceContractInfo.fromStringVec(
|
||||
Vector(winStr -> Satoshis(10000), loseStr -> Satoshis.zero))
|
||||
|
||||
lazy val sampleOracleAndContractInfo: OracleAndContractInfo =
|
||||
OracleAndContractInfo(sampleOracleInfo, sampleContractInfo)
|
||||
ContractInfo(Satoshis(10000), sampleContractDescriptor, sampleOracleInfo)
|
||||
|
||||
lazy val sampleOracleWinSig: SchnorrDigitalSignature =
|
||||
oraclePrivKey.schnorrSignWithNonce(winHash.bytes, kValue)
|
||||
|
@ -62,15 +71,18 @@ object DLCWalletUtil {
|
|||
|
||||
val numDigits: Int = 6
|
||||
|
||||
lazy val multiNonceContractInfo: MultiNonceContractInfo =
|
||||
lazy val multiNonceContractDescriptor: NumericContractDescriptor =
|
||||
DLCTestUtil.genMultiDigitContractInfo(numDigits, Satoshis(10000))._1
|
||||
|
||||
lazy val multiNonceOracleInfo: MultiNonceOracleInfo =
|
||||
MultiNonceOracleInfo(oraclePrivKey.schnorrPublicKey,
|
||||
rValues.take(numDigits))
|
||||
lazy val multiNonceOracleInfo: NumericSingleOracleInfo =
|
||||
NumericSingleOracleInfo(
|
||||
OracleAnnouncementV0TLV.dummyForKeys(oraclePrivKey,
|
||||
rValues.take(numDigits)))
|
||||
|
||||
lazy val multiNonceOracleAndContractInfo: OracleAndContractInfo =
|
||||
OracleAndContractInfo(multiNonceOracleInfo, multiNonceContractInfo)
|
||||
lazy val multiNonceContractInfo: ContractInfo =
|
||||
ContractInfo(Satoshis(10000),
|
||||
multiNonceContractDescriptor,
|
||||
multiNonceOracleInfo)
|
||||
|
||||
lazy val dummyContractMaturity: BlockTimeStamp = BlockTimeStamp(1666335)
|
||||
lazy val dummyContractTimeout: BlockTimeStamp = BlockTimeStamp(1666337)
|
||||
|
@ -115,7 +127,7 @@ object DLCWalletUtil {
|
|||
)
|
||||
|
||||
lazy val sampleDLCOffer: DLCOffer = DLCOffer(
|
||||
sampleOracleAndContractInfo,
|
||||
sampleContractInfo,
|
||||
dummyDLCKeys,
|
||||
Satoshis(5000),
|
||||
Vector(dummyFundingInputs.head),
|
||||
|
@ -125,12 +137,10 @@ object DLCWalletUtil {
|
|||
)
|
||||
|
||||
lazy val sampleMultiNonceDLCOffer: DLCOffer =
|
||||
sampleDLCOffer.copy(oracleAndContractInfo = multiNonceOracleAndContractInfo)
|
||||
sampleDLCOffer.copy(contractInfo = multiNonceContractInfo)
|
||||
|
||||
lazy val sampleDLCParamHash: Sha256DigestBE =
|
||||
DLCMessage.calcParamHash(sampleOracleInfo,
|
||||
sampleContractInfo,
|
||||
dummyTimeouts)
|
||||
DLCMessage.calcParamHash(sampleContractInfo, dummyTimeouts)
|
||||
|
||||
lazy val dummyOutcomeSigs: Vector[(DLCOutcomeType, ECAdaptorSignature)] =
|
||||
Vector(EnumOutcome(winStr) -> ECAdaptorSignature.dummy,
|
||||
|
@ -174,16 +184,14 @@ object DLCWalletUtil {
|
|||
def initDLC(
|
||||
fundedWalletA: FundedDLCWallet,
|
||||
fundedWalletB: FundedDLCWallet,
|
||||
oracleAndContractInfo: OracleAndContractInfo)(implicit
|
||||
ec: ExecutionContext): Future[
|
||||
contractInfo: ContractInfo)(implicit ec: ExecutionContext): Future[
|
||||
(InitializedDLCWallet, InitializedDLCWallet)] = {
|
||||
val walletA = fundedWalletA.wallet
|
||||
val walletB = fundedWalletB.wallet
|
||||
|
||||
for {
|
||||
offer <- walletA.createDLCOffer(
|
||||
oracleInfo = oracleAndContractInfo.oracleInfo,
|
||||
contractInfo = oracleAndContractInfo.offerContractInfo,
|
||||
contractInfo = contractInfo,
|
||||
collateral = Satoshis(5000),
|
||||
feeRateOpt = None,
|
||||
locktime = dummyTimeouts.contractMaturity.toUInt32,
|
||||
|
|
Loading…
Add table
Reference in a new issue