Outstanding DLC branch diff (#2432)

This commit is contained in:
Nadav Kohen 2020-12-23 18:13:57 -06:00 committed by GitHub
parent c33f88eb05
commit 528b4e01ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 131 additions and 8 deletions

View file

@ -1,7 +1,8 @@
package org.bitcoins.gui
import org.bitcoins.cli.Config
import org.bitcoins.core.config.BitcoinNetwork
import org.bitcoins.core.config._
import org.bitcoins.crypto.DoubleSha256DigestBE
import org.bitcoins.gui.settings.Themes
import scalafx.beans.property.{DoubleProperty, StringProperty}
@ -34,4 +35,24 @@ object GlobalData {
case Some(rpcPort) =>
Config(debug = debug, rpcPort = rpcPort)
}
lazy val broadcastUrl: String = GlobalData.network match {
case MainNet =>
"https://blockstream.info/api/tx"
case TestNet3 =>
"https://blockstream.info/testnet/api/tx"
case net @ (RegTest | SigNet) => s"Broadcast from your own node on $net"
}
/** Builds a url for the blockstream explorer to view the tx */
def buildTxUrl(txid: DoubleSha256DigestBE): String = {
network match {
case MainNet =>
s"https://blockstream.info/tx/${txid.hex}"
case TestNet3 =>
s"https://blockstream.info/testnet/tx/${txid.hex}"
case net @ (RegTest | SigNet) =>
s"View transaction on your own node on $net"
}
}
}

View file

@ -8,6 +8,7 @@ import org.bitcoins.core.config.MainNet
import org.bitcoins.core.number.{Int32, UInt16, UInt32}
import org.bitcoins.core.protocol.dlc.DLCStatus
import org.bitcoins.core.protocol.tlv._
import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.crypto.{CryptoUtil, ECPrivateKey, Sha256DigestBE}
import org.bitcoins.gui.dlc.dialog._
import org.bitcoins.gui.{GlobalData, TaskRunner}
@ -17,11 +18,32 @@ import scalafx.scene.control.TextArea
import scalafx.stage.Window
import upickle.default._
import scala.util.{Failure, Success}
import scala.util.{Failure, Success, Try}
class DLCPaneModel(resultArea: TextArea, oracleInfoArea: TextArea) {
var taskRunner: TaskRunner = _
lazy val txPrintFunc: String => String = str => {
// See if it was an error or not
Try(Transaction.fromHex(str)) match {
case Failure(_) =>
// if it was print the error
str
case Success(tx) =>
s"""|TxId: ${tx.txIdBE.hex}
|
|url: ${GlobalData.buildTxUrl(tx.txIdBE)}
|
|If the tx doesn't show up after a few minutes at this url you may need to manually
|broadcast the tx with the full hex below
|
|Link to broadcast: ${GlobalData.broadcastUrl}
|
|Transaction: ${tx.hex}
""".stripMargin
}
}
// Sadly, it is a Java "pattern" to pass null into
// constructors to signal that you want some default
val parentWindow: ObjectProperty[Window] =
@ -62,7 +84,8 @@ class DLCPaneModel(resultArea: TextArea, oracleInfoArea: TextArea) {
def printDLCDialogResult[T <: CliCommand](
caption: String,
dialog: DLCDialog[T]): Unit = {
dialog: DLCDialog[T],
postProcessStr: String => String = str => str): Unit = {
val result = dialog.showAndWait(parentWindow.value)
result match {
@ -71,7 +94,8 @@ class DLCPaneModel(resultArea: TextArea, oracleInfoArea: TextArea) {
caption = caption,
op = {
ConsoleCli.exec(command, GlobalData.consoleCliConfig) match {
case Success(commandReturn) => resultArea.text = commandReturn
case Success(commandReturn) =>
resultArea.text = postProcessStr(commandReturn)
case Failure(err) =>
err.printStackTrace()
resultArea.text = s"Error executing command:\n${err.getMessage}"
@ -220,15 +244,17 @@ class DLCPaneModel(resultArea: TextArea, oracleInfoArea: TextArea) {
}
def onGetFunding(): Unit = {
printDLCDialogResult("GetDLCFundingTx", new GetFundingDLCDialog)
printDLCDialogResult("GetDLCFundingTx",
new GetFundingDLCDialog,
txPrintFunc)
}
def onExecute(): Unit = {
printDLCDialogResult("ExecuteDLC", new ExecuteDLCDialog)
printDLCDialogResult("ExecuteDLC", new ExecuteDLCDialog, txPrintFunc)
}
def onRefund(): Unit = {
printDLCDialogResult("ExecuteDLCRefund", new RefundDLCDialog)
printDLCDialogResult("ExecuteDLCRefund", new RefundDLCDialog, txPrintFunc)
}
def viewDLC(status: DLCStatus): Unit = {

View file

@ -673,7 +673,7 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord])
tx.outputs(txIn.previousOutput.vout.toInt)
} else {
throw new UnsupportedOperationException(
"Not enough information in the InputPSBTMap to get a valid InputInfo")
s"Not enough information in the InputPSBTMap to get a valid InputInfo: $elements")
}
val redeemScriptOpt = finalizedScriptSigOpt match {

View file

@ -0,0 +1,71 @@
package org.bitcoins.testkit.util
import org.bitcoins.core.protocol.dlc.{CETSignatures, FundingSignatures}
import org.bitcoins.core.protocol.script.{
EmptyScriptPubKey,
P2WPKHWitnessV0,
P2WSHWitnessV0,
ScriptWitnessV0
}
import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature
import org.bitcoins.crypto.{ECAdaptorSignature, ECDigitalSignature}
import scodec.bits.ByteVector
object BytesUtil {
def flipAtIndex(bytes: ByteVector, byteIndex: Int): ByteVector = {
val (front, backWithToFlip) = bytes.splitAt(byteIndex)
val (toFlip, back) = backWithToFlip.splitAt(1)
front ++ toFlip.xor(ByteVector.fromByte(1)) ++ back
}
def flipBit(signature: ECDigitalSignature): ECDigitalSignature = {
ECDigitalSignature(flipAtIndex(signature.bytes, 60))
}
def flipBit(partialSignature: PartialSignature): PartialSignature = {
partialSignature.copy(signature = flipBit(partialSignature.signature))
}
def flipBit(adaptorSignature: ECAdaptorSignature): ECAdaptorSignature = {
ECAdaptorSignature(flipAtIndex(adaptorSignature.bytes, 40))
}
def flipBit(witness: ScriptWitnessV0): ScriptWitnessV0 = {
witness match {
case p2wpkh: P2WPKHWitnessV0 =>
P2WPKHWitnessV0(p2wpkh.pubKey, flipBit(p2wpkh.signature))
case p2wsh: P2WSHWitnessV0 =>
val sigOpt = p2wsh.stack.zipWithIndex.find {
case (bytes, _) =>
bytes.length >= 67 && bytes.length <= 73
}
sigOpt match {
case Some((sig, index)) =>
P2WSHWitnessV0(
EmptyScriptPubKey,
p2wsh.stack.updated(index,
flipBit(ECDigitalSignature(sig)).bytes))
case None =>
P2WSHWitnessV0(
EmptyScriptPubKey,
p2wsh.stack.updated(0, flipAtIndex(p2wsh.stack.head, 0)))
}
}
}
def flipBit(fundingSigs: FundingSignatures): FundingSignatures = {
val (firstOutPoint, witness) = fundingSigs.head
val badWitness = flipBit(witness)
FundingSignatures(fundingSigs.tail.toVector.+:(firstOutPoint -> badWitness))
}
def flipBit(cetSigs: CETSignatures): CETSignatures = {
val badOutcomeSigs = cetSigs.outcomeSigs.map {
case (outcome, sig) => outcome -> flipBit(sig)
}
val badRefundSig = flipBit(cetSigs.refundSig)
CETSignatures(badOutcomeSigs, badRefundSig)
}
}

View file

@ -83,6 +83,11 @@ trait TxDAO[DbEntryType <: TxDB]
def findByTxId(txId: DoubleSha256Digest): Future[Option[DbEntryType]] =
findByTxId(txId.flip)
def findByTxIdBEs(
txIdBEs: Vector[DoubleSha256DigestBE]): Future[Vector[DbEntryType]] = {
database.run(findByPrimaryKeys(txIdBEs).result).map(_.toVector)
}
}
case class TransactionDAO()(implicit