Add signature ordering to ClaimedDLCStatus.oracleSigs (#4804)

* Add signature ordering to ClaimedDLCStatus.oracleSigs

* fix bug
This commit is contained in:
Chris Stewart 2022-09-27 09:43:37 -05:00 committed by GitHub
parent 9c506b639f
commit 8d91abd678
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 13 deletions

View file

@ -11,6 +11,7 @@ import org.bitcoins.core.protocol.dlc.models.{
PayoutAddress
}
import org.bitcoins.core.util.TimeUtil
import org.bitcoins.core.util.sorted.OrderedSchnorrSignatures
import org.bitcoins.crypto.Sha256Digest
import org.bitcoins.testkitcore.gen.{CryptoGenerators, NumberGenerator, TLVGen}
import org.bitcoins.testkitcore.util.BitcoinSJvmTest
@ -247,7 +248,7 @@ class DLCStatusTest extends BitcoinSJvmTest {
offer.collateral,
fundingTxId,
closingTxId,
sigs.toVector,
OrderedSchnorrSignatures.fromUnsorted(sigs.toVector),
outcome,
myPayout = myPayout,
counterPartyPayout = theirPayout,

View file

@ -36,6 +36,7 @@ import org.bitcoins.core.psbt.PSBT
import org.bitcoins.core.serializers.PicklerKeys
import org.bitcoins.core.util.{NetworkUtil, TimeUtil}
import org.bitcoins.core.util.TimeUtil._
import org.bitcoins.core.util.sorted.OrderedSchnorrSignatures
import org.bitcoins.core.wallet.fee.{FeeUnit, SatoshisPerVirtualByte}
import org.bitcoins.core.wallet.utxo.{AddressLabelTag, TxoState}
import org.bitcoins.crypto._
@ -1190,10 +1191,12 @@ object Picklers {
lazy val contractId = ByteVector.fromValidHex(obj("contractId").str)
lazy val fundingTxId = DoubleSha256DigestBE(obj("fundingTxId").str)
lazy val closingTxId = DoubleSha256DigestBE(obj("closingTxId").str)
lazy val oracleSigs =
obj("oracleSigs").arr
lazy val oracleSigs = {
val unsorted = obj("oracleSigs").arr
.map(value => SchnorrDigitalSignature(value.str))
.toVector
OrderedSchnorrSignatures.fromUnsorted(unsorted)
}
val payoutAddressJs = obj("payoutAddress")
lazy val payoutAddress: Option[PayoutAddress] = payoutAddressJs match {

View file

@ -11,6 +11,7 @@ import org.bitcoins.core.protocol.dlc.models.DLCMessage.{
}
import org.bitcoins.core.protocol.tlv.OracleAnnouncementTLV
import org.bitcoins.core.protocol.transaction.WitnessTransaction
import org.bitcoins.core.util.sorted.OrderedSchnorrSignatures
import org.bitcoins.core.wallet.fee.FeeUnit
import org.bitcoins.crypto._
import scodec.bits.ByteVector
@ -78,7 +79,7 @@ sealed trait ClosedDLCStatus extends SignedDLCStatus {
sealed trait ClaimedDLCStatus extends ClosedDLCStatus {
def oracleOutcome: OracleOutcome
def oracleSigs: Vector[SchnorrDigitalSignature]
def oracleSigs: OrderedSchnorrSignatures
}
object DLCStatus {
@ -222,7 +223,7 @@ object DLCStatus {
localCollateral: CurrencyUnit,
fundingTxId: DoubleSha256DigestBE,
closingTxId: DoubleSha256DigestBE,
oracleSigs: Vector[SchnorrDigitalSignature],
oracleSigs: OrderedSchnorrSignatures,
oracleOutcome: OracleOutcome,
myPayout: CurrencyUnit,
counterPartyPayout: CurrencyUnit,
@ -253,7 +254,9 @@ object DLCStatus {
peer: Option[String])
extends ClaimedDLCStatus {
override val state: DLCState.RemoteClaimed.type = DLCState.RemoteClaimed
override val oracleSigs: Vector[SchnorrDigitalSignature] = Vector(oracleSig)
override val oracleSigs: OrderedSchnorrSignatures =
OrderedSchnorrSignatures(oracleSig)
}
case class Refunded(
@ -306,7 +309,7 @@ object DLCStatus {
}
def getOracleSignatures(
status: DLCStatus): Option[Vector[SchnorrDigitalSignature]] = {
status: DLCStatus): Option[OrderedSchnorrSignatures] = {
status match {
case claimed: ClaimedDLCStatus =>
Some(claimed.oracleSigs)

View file

@ -11,9 +11,10 @@ abstract class SortedVec[T, B >: T](
override val wrapped: Vector[T],
ord: Ordering[B])
extends SeqWrapper[T] {
require(
wrapped.init.zip(wrapped.tail).forall { case (x, y) => ord.lteq(x, y) },
s"Vector must be sorted. $wrapped")
require(wrapped.isEmpty || wrapped.init.zip(wrapped.tail).forall {
case (x, y) => ord.lteq(x, y)
},
s"Vector must be sorted. $wrapped")
}
object SortedVec {

View file

@ -16,6 +16,7 @@ import org.bitcoins.core.protocol.dlc.models.{
import org.bitcoins.core.protocol.tlv._
import org.bitcoins.core.script.interpreter.ScriptInterpreter
import org.bitcoins.core.script.util.PreviousOutputMap
import org.bitcoins.core.util.sorted.OrderedSchnorrSignatures
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
import org.bitcoins.testkit.wallet.DLCWalletUtil._
import org.bitcoins.testkit.wallet.{BitcoinSDualWalletTest, DLCWalletUtil}
@ -437,6 +438,43 @@ class DLCExecutionTest extends BitcoinSDualWalletTest {
} yield succeed
}
it must "throw an exception for a enum contract when do not have all the oracle signatures/outcomes" in {
wallets =>
val walletA = wallets._1.wallet
val resultF = for {
contractId <- getContractId(walletA)
status <- getDLCStatus(walletA)
(goodAttestment, _) = {
status.contractInfo match {
case single: SingleContractInfo =>
DLCWalletUtil.getSigs(single)
case disjoint: DisjointUnionContractInfo =>
sys.error(
s"Cannot retrieve sigs for disjoint union contract, got=$disjoint")
}
}
//purposefully drop these
//we cannot drop just a sig, or just an outcome because
//of invariants in OracleAttestmentV0TLV
badSigs = goodAttestment.sigs.dropRight(1)
badOutcomes = goodAttestment.outcomes.dropRight(1)
badAttestment = OracleAttestmentV0TLV(
eventId = goodAttestment.eventId,
publicKey = goodAttestment.publicKey,
sigs = OrderedSchnorrSignatures.fromUnsorted(badSigs.toVector),
outcomes = badOutcomes)
func = (wallet: DLCWallet) =>
wallet.executeDLC(contractId, badAttestment).map(_.get)
result <- dlcExecutionTest(wallets = wallets,
asInitiator = true,
func = func,
expectedOutputs = 1)
} yield assert(result)
recoverToSucceededIf[IllegalArgumentException](resultF)
}
it must "throw an exception when you try to execute a DLC in the SIGNED state" in {
wallets =>
val walletA = wallets._1.wallet

View file

@ -7,7 +7,7 @@ import org.bitcoins.core.protocol.dlc.models.DLCStatus._
import org.bitcoins.core.protocol.dlc.models._
import org.bitcoins.core.protocol.tlv._
import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.crypto.SchnorrDigitalSignature
import org.bitcoins.core.util.sorted.OrderedSchnorrSignatures
import org.bitcoins.dlc.wallet.accounting.{AccountingUtil, DLCAccountingDbs}
import org.bitcoins.dlc.wallet.models._
@ -317,7 +317,7 @@ object DLCStatusBuilder {
announcementsWithId: Vector[(OracleAnnouncementV0TLV, Long)],
nonceDbs: Vector[OracleNonceDb]): (
OracleOutcome,
Vector[SchnorrDigitalSignature]) = {
OrderedSchnorrSignatures) = {
val noncesByAnnouncement: Map[Long, Vector[OracleNonceDb]] =
nonceDbs.sortBy(_.index).groupBy(_.announcementId)
val oracleOutcome = {
@ -357,6 +357,7 @@ object DLCStatusBuilder {
}
val sigs = nonceDbs.flatMap(_.signatureOpt)
(oracleOutcome, sigs)
val ordered = OrderedSchnorrSignatures.fromUnsorted(sigs)
(oracleOutcome, ordered)
}
}