decred.org/dcrdex@v1.0.3/dex/networks/btc/script.go (about) 1 // This code is available on the terms of the project LICENSE.md file, 2 // also available online at https://blueoakcouncil.org/license/1.0.0. 3 4 package btc 5 6 import ( 7 "bytes" 8 "crypto/sha256" 9 "encoding/binary" 10 "encoding/hex" 11 "errors" 12 "fmt" 13 14 "decred.org/dcrdex/dex" 15 "decred.org/dcrdex/server/account" 16 "github.com/btcsuite/btcd/btcutil" 17 "github.com/btcsuite/btcd/chaincfg" 18 "github.com/btcsuite/btcd/txscript" 19 "github.com/btcsuite/btcd/wire" 20 dcrtxscript "github.com/decred/dcrd/txscript/v4" 21 ) 22 23 const ( 24 // MaxCLTVScriptNum is the largest usable value for a CLTV lockTime. This 25 // will actually be stored in a 5-byte ScriptNum since they have a sign bit, 26 // however, it is not 2^39-1 since the spending transaction's nLocktime is 27 // an unsigned 32-bit integer and it must be at least the CLTV value. This 28 // establishes a maximum lock time of February 7, 2106. Any later requires 29 // using a block height instead of a unix epoch time stamp. 30 MaxCLTVScriptNum = 1<<32 - 1 // 0xffff_ffff a.k.a. 2^32-1 31 32 // SecretHashSize is the byte-length of the hash of the secret key used in an 33 // atomic swap. 34 SecretHashSize = 32 35 36 // SecretKeySize is the byte-length of the secret key used in an atomic swap. 37 SecretKeySize = 32 38 39 // ContractHashSize is the size of the script-hash for an atomic swap 40 // contract. 41 ContractHashSize = 20 42 43 // PubKeyLength is the length of a serialized compressed public key. 44 PubKeyLength = 33 45 46 // 4 bytes version + 4 bytes locktime + 2 bytes of varints for the number of 47 // transaction inputs and outputs 48 MinimumBlockOverHead = 10 49 50 // SwapContractSize is the worst case scenario size for a swap contract, 51 // which is the pk-script of the non-change output of an initialization 52 // transaction as used in execution of an atomic swap. 53 // See ExtractSwapDetails for a breakdown of the bytes. 54 SwapContractSize = 97 55 56 // DERSigLength is the maximum length of a DER encoded signature with a 57 // sighash type byte. 58 DERSigLength = 73 59 60 // RedeemSwapSigScriptSize is the worst case (largest) serialize size 61 // of a transaction signature script that redeems atomic swap output contract. 62 // It is calculated as: 63 // 64 // - OP_DATA_73 65 // - 72 bytes DER signature + 1 byte sighash 66 // - OP_DATA_33 67 // - 33 bytes serialized compressed pubkey 68 // - OP_DATA_32 69 // - 32 bytes secret key 70 // - OP_1 71 // - varint 97 72 // - 97 bytes redeem script 73 RedeemSwapSigScriptSize = 1 + DERSigLength + 1 + 33 + 1 + 32 + 1 + 2 + 97 74 75 // RefundSigScriptSize is the worst case (largest) serialize size 76 // of a transaction input script that refunds a compressed P2PKH output. 77 // It is calculated as: 78 // 79 // - OP_DATA_73 80 // - 72 bytes DER signature + 1 byte sighash 81 // - OP_DATA_33 82 // - 33 bytes serialized compressed pubkey 83 // - OP_0 84 // - varint 97 => OP_PUSHDATA1(0x4c) + 0x61 85 // - 97 bytes contract 86 RefundSigScriptSize = 1 + DERSigLength + 1 + 33 + 1 + 2 + 97 87 88 // Overhead for a wire.TxIn. See wire.TxIn.SerializeSize. 89 // hash 32 bytes + index 4 bytes + sequence 4 bytes. 90 TxInOverhead = 32 + 4 + 4 // 40 91 92 // TxOutOverhead is the overhead associated with a transaction output. 93 // 8 bytes value + at least 1 byte varint script size 94 TxOutOverhead = 8 + 1 95 96 RedeemP2PKSigScriptSize = 1 + DERSigLength 97 98 // RedeemP2PKHSigScriptSize is the worst case (largest) serialize size 99 // of a transaction input script that redeems a compressed P2PKH output. 100 // It is calculated as: 101 // 102 // - OP_DATA_73 103 // - 72 bytes DER signature + 1 byte sighash 104 // - OP_DATA_33 105 // - 33 bytes serialized compressed pubkey 106 RedeemP2PKHSigScriptSize = 1 + DERSigLength + 1 + 33 // 108 107 108 // RedeemP2SHSigScriptSize does not include the redeem script. 109 //RedeemP2SHSigScriptSize = 1 + DERSigLength + 1 + 1 + 33 + 1 // + redeem script! 110 111 // P2PKHPkScriptSize is the size of a transaction output script that 112 // pays to a compressed pubkey hash. It is calculated as: 113 // 114 // - OP_DUP 115 // - OP_HASH160 116 // - OP_DATA_20 117 // - 20 bytes pubkey hash 118 // - OP_EQUALVERIFY 119 // - OP_CHECKSIG 120 P2PKHPkScriptSize = 1 + 1 + 1 + 20 + 1 + 1 // 25 121 122 // P2PKHOutputSize is the size of the serialized P2PKH output. 123 P2PKHOutputSize = TxOutOverhead + P2PKHPkScriptSize // 9 + 25 = 34 124 125 // P2SHPkScriptSize is the size of a transaction output script that 126 // pays to a redeem script. It is calculated as: 127 // 128 // - OP_HASH160 129 // - OP_DATA_20 130 // - 20 bytes redeem script hash 131 // - OP_EQUAL 132 P2SHPkScriptSize = 1 + 1 + 20 + 1 133 134 // P2SHOutputSize is the size of the serialized P2SH output. 135 P2SHOutputSize = TxOutOverhead + P2SHPkScriptSize // 9 + 23 = 32 136 137 // P2WSHPkScriptSize is the size of a segwit transaction output script that 138 // pays to a redeem script. It is calculated as: 139 // 140 // - OP_0 141 // - OP_DATA_32 142 // - 32 bytes redeem script hash 143 P2WSHPkScriptSize = 1 + 1 + 32 144 145 // P2WSHOutputSize is the size of the serialized P2WSH output. 146 P2WSHOutputSize = TxOutOverhead + P2WSHPkScriptSize // 9 + 34 = 43 147 148 // RedeemP2PKHInputSize is the worst case (largest) serialize size of a 149 // transaction input redeeming a compressed P2PKH output. It is 150 // calculated as: 151 // 152 // - 32 bytes previous tx 153 // - 4 bytes output index 154 // - 4 bytes sequence 155 // - 1 byte compact int encoding value 108 156 // - 108 bytes signature script 157 RedeemP2PKHInputSize = TxInOverhead + 1 + RedeemP2PKHSigScriptSize // 40 + 1 + 108 = 149 158 159 // RedeemP2WPKHInputSize is the worst case size of a transaction 160 // input redeeming a P2WPKH output. This does not account for witness data, 161 // which is considered at a lower weight for fee calculations. It is 162 // calculated as 163 // 164 // - 32 bytes previous tx 165 // - 4 bytes output index 166 // - 4 bytes sequence 167 // - 1 byte encoding empty redeem script 168 // - 0 bytes signature script 169 RedeemP2WPKHInputSize = TxInOverhead + 1 170 171 // RedeemP2WPKHInputWitnessWeight is the worst case weight of 172 // a witness for spending P2WPKH and nested P2WPKH outputs. It 173 // is calculated as: 174 // 175 // - 1 wu compact int encoding value 2 (number of items) 176 // - 1 wu compact int encoding value 73 177 // - 72 wu DER signature + 1 wu sighash 178 // - 1 wu compact int encoding value 33 179 // - 33 wu serialized compressed pubkey 180 // NOTE: witness data is not script. 181 RedeemP2WPKHInputWitnessWeight = 1 + 1 + DERSigLength + 1 + 33 // 109 182 183 // RedeemP2WPKHInputTotalSize is the worst case size of a transaction 184 // input redeeming a P2WPKH output and the corresponding witness data. 185 // It is calculated as: 186 // 187 // 41 vbytes base tx input 188 // 109wu witness = 28 vbytes 189 // total = 69 vbytes 190 RedeemP2WPKHInputTotalSize = RedeemP2WPKHInputSize + 191 (RedeemP2WPKHInputWitnessWeight+(witnessWeight-1))/witnessWeight 192 193 // SigwitMarkerAndFlagWeight is the 2 bytes of overhead witness data 194 // added to every segwit transaction. 195 SegwitMarkerAndFlagWeight = 2 196 197 // RedeemP2WSHInputWitnessWeight depends on the number of redeem script and 198 // number of signatures. 199 // version + signatures + length of redeem script + redeem script 200 // RedeemP2WSHInputWitnessWeight = 1 + N*DERSigLength + 1 + (redeem script bytes) 201 202 // P2WPKHPkScriptSize is the size of a transaction output script that 203 // pays to a witness pubkey hash. It is calculated as: 204 // 205 // - OP_0 206 // - OP_DATA_20 207 // - 20 bytes pubkey hash 208 P2WPKHPkScriptSize = 1 + 1 + 20 209 210 // P2WPKHOutputSize is the serialize size of a transaction output with a 211 // P2WPKH output script. It is calculated as: 212 // 213 // - 8 bytes output value 214 // - 1 byte compact int encoding value 22 215 // - 22 bytes P2PKH output script 216 P2WPKHOutputSize = TxOutOverhead + P2WPKHPkScriptSize // 31 217 218 // MinimumTxOverhead is the size of an empty transaction. 219 // 4 bytes version + 4 bytes locktime + 2 bytes of varints for the number of 220 // transaction inputs and outputs 221 MinimumTxOverhead = 4 + 4 + 1 + 1 // 10 222 223 // InitTxSizeBase is the size of a standard serialized atomic swap 224 // initialization transaction with one change output and no inputs. This is 225 // MsgTx overhead + 1 P2PKH change output + 1 P2SH contract output. However, 226 // the change output might be P2WPKH, in which case it would be smaller. 227 InitTxSizeBase = MinimumTxOverhead + P2PKHOutputSize + P2SHOutputSize // 10 + 34 + 32 = 76 228 // leaner with P2WPKH+P2SH outputs: 10 + 31 + 32 = 73 229 230 // InitTxSize is InitTxBaseSize + 1 P2PKH input 231 InitTxSize = InitTxSizeBase + RedeemP2PKHInputSize // 76 + 149 = 225 232 // Varies greatly with some other input types, e.g nested witness (p2sh with 233 // p2wpkh redeem script): 23 byte scriptSig + 108 byte (75 vbyte) witness = ~50 234 235 // InitTxSizeBaseSegwit is the size of a standard serialized atomic swap 236 // initialization transaction with one change output and no inputs. The 237 // change output is assumed to be segwit. 10 + 31 + 43 = 84 238 InitTxSizeBaseSegwit = MinimumTxOverhead + P2WPKHOutputSize + P2WSHOutputSize 239 240 // InitTxSizeSegwit is InitTxSizeSegwit + 1 P2WPKH input. 241 // 84 vbytes base tx 242 // 41 vbytes base tx input 243 // 109wu witness + 2wu segwit marker and flag = 28 vbytes 244 // total = 153 vbytes 245 InitTxSizeSegwit = InitTxSizeBaseSegwit + RedeemP2WPKHInputSize + 246 (SegwitMarkerAndFlagWeight+RedeemP2WPKHInputWitnessWeight+(witnessWeight-1))/witnessWeight 247 248 witnessWeight = 4 // github.com/btcsuite/btcd/blockchain.WitnessScaleFactor 249 250 // BondScriptSize is the maximum size of a DEX time-locked fidelity bond 251 // output script to which a bond P2SH pays: 252 // OP_DATA_4/5 (4/5 bytes lockTime) OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 OP_DATA_20 (20-byte pubkey hash160) OP_EQUALVERIFY OP_CHECKSIG 253 BondScriptSize = 1 + 5 + 1 + 1 + 1 + 1 + 1 + 20 + 1 + 1 // 33 254 255 // RedeemBondSigScriptSize is the worst case size of a fidelity bond 256 // signature script that spends a bond output. It includes a signature, a 257 // compressed pubkey, and the bond script. Each of said data pushes use an 258 // OP_DATA_ code. 259 RedeemBondSigScriptSize = 1 + DERSigLength + 1 + 33 + 1 + BondScriptSize // 142 260 261 // BondPushDataSize is the size of the nulldata in a bond commitment output: 262 // OP_RETURN <pushData: ver[2] | account_id[32] | lockTime[4] | pkh[20]> 263 BondPushDataSize = 2 + account.HashSize + 4 + 20 264 ) 265 266 // redeemP2SHTxSize calculates the size of the redeeming transaction for a 267 // P2SH transaction with the given sigScipt (or witness data) size. 268 func redeemP2SHTxSize(segwit bool, redeemSigScriptSize uint64) uint64 { 269 if segwit { 270 witnessVBytes := (redeemSigScriptSize + 2 + 3) / 4 271 return MinimumTxOverhead + TxInOverhead + witnessVBytes + P2WPKHOutputSize 272 } 273 inputSize := TxInOverhead + redeemSigScriptSize 274 return MinimumTxOverhead + inputSize + P2PKHOutputSize 275 } 276 277 // RedeemSwapTxSize returns the size of a swap refund tx. 278 func RedeemSwapTxSize(segwit bool) uint64 { 279 return redeemP2SHTxSize(segwit, RedeemSwapSigScriptSize) 280 } 281 282 // RefundBondTxSize returns the size of a bond refund tx. 283 func RefundBondTxSize(segwit bool) uint64 { 284 return redeemP2SHTxSize(segwit, RedeemBondSigScriptSize) 285 } 286 287 // minHTLCValue calculates the minimum value for the output of a chained 288 // P2SH -> P2WPKH transaction pair where the spending tx size is known. 289 func minHTLCValue(maxFeeRate, redeemTxSize uint64, segwit bool) uint64 { 290 // Reversing IsDustVal. 291 // totalSize adds some buffer for the spending transaction. 292 var outputSize uint64 = P2PKHOutputSize // larger of p2sh output and p2pkh output. 293 if segwit { 294 outputSize = P2WSHOutputSize // larger of p2wsh output and p2wpkh output 295 } 296 totalSize := outputSize + 41 297 if segwit { 298 totalSize += (107 / witnessWeight) // + 26 299 } else { 300 totalSize += 107 301 } 302 minInitTxValue := maxFeeRate * totalSize * 3 303 304 // The minInitTxValue would get the pssh tx accepted, but when we go to 305 // redemption, we need that output to pass too, so we need to add the fees 306 // for the redemption tx itself. 307 redeemFees := redeemTxSize * maxFeeRate 308 309 return minInitTxValue + redeemFees 310 } 311 312 // MinBondSize is the minimum bond size that avoids dust for a given max network 313 // fee rate. 314 func MinBondSize(maxFeeRate uint64, segwit bool) uint64 { 315 refundTxSize := RefundBondTxSize(segwit) 316 return minHTLCValue(maxFeeRate, refundTxSize, segwit) 317 } 318 319 // MinLotSize is the minimum lot size that avoids dust for a given max network 320 // fee rate. 321 func MinLotSize(maxFeeRate uint64, segwit bool) uint64 { 322 redeemSize := RedeemSwapTxSize(segwit) 323 return minHTLCValue(maxFeeRate, redeemSize, segwit) 324 } 325 326 // BTCScriptType holds details about a pubkey script and possibly it's redeem 327 // script. 328 type BTCScriptType uint8 329 330 const ( 331 ScriptP2PKH = 1 << iota 332 ScriptP2PK 333 ScriptP2SH 334 ScriptTypeSegwit 335 ScriptMultiSig 336 ScriptUnsupported 337 ) 338 339 // IsP2SH will return boolean true if the script is a P2SH script. 340 func (s BTCScriptType) IsP2SH() bool { 341 return s&ScriptP2SH != 0 && s&ScriptTypeSegwit == 0 342 } 343 344 // IsP2WSH will return boolean true if the script is a P2WSH script. 345 func (s BTCScriptType) IsP2WSH() bool { 346 return s&ScriptP2SH != 0 && s&ScriptTypeSegwit != 0 347 } 348 349 // IsP2PKH will return boolean true if the script is a P2PKH script. 350 func (s BTCScriptType) IsP2PKH() bool { 351 return s&ScriptP2PKH != 0 && s&ScriptTypeSegwit == 0 352 } 353 354 // IsP2PK will return boolean true if the script is a P2PK script. 355 func (s BTCScriptType) IsP2PK() bool { 356 return s&ScriptP2PK != 0 && s&ScriptTypeSegwit == 0 357 } 358 359 // IsP2WPKH will return boolean true if the script is a P2WPKH script. 360 func (s BTCScriptType) IsP2WPKH() bool { 361 return s&ScriptP2PKH != 0 && s&ScriptTypeSegwit != 0 362 } 363 364 // IsSegwit will return boolean true if the script is a P2WPKH or P2WSH script. 365 func (s BTCScriptType) IsSegwit() bool { 366 return s&ScriptTypeSegwit != 0 367 } 368 369 // IsMultiSig is whether the pkscript references a multi-sig redeem script. 370 // Since the DEX will know the redeem script, we can say whether it's multi-sig. 371 func (s BTCScriptType) IsMultiSig() bool { 372 return s&ScriptMultiSig != 0 373 } 374 375 // ParseScriptType creates a BTCScriptType bitmap for the script type. A script 376 // type will be some combination of pay-to-pubkey-hash, pay-to-script-hash, 377 // and stake. If a script type is P2SH, it may or may not be mutli-sig. 378 func ParseScriptType(pkScript, redeemScript []byte) BTCScriptType { 379 var scriptType BTCScriptType 380 class := txscript.GetScriptClass(pkScript) 381 382 switch class { 383 case txscript.PubKeyTy: 384 scriptType |= ScriptP2PK 385 case txscript.PubKeyHashTy: 386 scriptType |= ScriptP2PKH 387 case txscript.WitnessV0PubKeyHashTy: 388 scriptType |= ScriptP2PKH | ScriptTypeSegwit 389 case txscript.ScriptHashTy: 390 scriptType |= ScriptP2SH 391 case txscript.WitnessV0ScriptHashTy: 392 scriptType |= ScriptP2SH | ScriptTypeSegwit 393 default: 394 return ScriptUnsupported 395 } 396 if scriptType.IsP2SH() || scriptType.IsP2WSH() { 397 scriptClass := txscript.GetScriptClass(redeemScript) 398 if scriptClass == txscript.MultiSigTy { 399 scriptType |= ScriptMultiSig 400 } 401 if scriptClass == txscript.ScriptHashTy || scriptClass == txscript.WitnessV0ScriptHashTy { 402 // nested p2sh-pswsh, p2sh-p2sh, etc are not supported. 403 return ScriptUnsupported 404 } 405 } 406 return scriptType 407 } 408 409 // MakeContract creates a segwit atomic swap contract. The secretHash MUST 410 // be computed from a secret of length SecretKeySize bytes or the resulting 411 // contract will be invalid. 412 func MakeContract(rAddr, sAddr btcutil.Address, secretHash []byte, lockTime int64, segwit bool, chainParams *chaincfg.Params) ([]byte, error) { 413 if segwit { 414 _, ok := rAddr.(*btcutil.AddressWitnessPubKeyHash) 415 if !ok { 416 return nil, fmt.Errorf("recipient address %s is not a witness-pubkey-hash address", rAddr.String()) 417 } 418 _, ok = sAddr.(*btcutil.AddressWitnessPubKeyHash) 419 if !ok { 420 return nil, fmt.Errorf("sender address %s is not a witness-pubkey-hash address", sAddr.String()) 421 } 422 } else { 423 _, ok := rAddr.(*btcutil.AddressPubKeyHash) 424 if !ok { 425 return nil, fmt.Errorf("recipient address %s is not a pubkey-hash address", rAddr.String()) 426 } 427 _, ok = sAddr.(*btcutil.AddressPubKeyHash) 428 if !ok { 429 return nil, fmt.Errorf("sender address %s is not a witness-pubkey-hash address", sAddr.String()) 430 } 431 } 432 if len(secretHash) != SecretHashSize { 433 return nil, fmt.Errorf("secret hash of length %d not supported", len(secretHash)) 434 } 435 436 return txscript.NewScriptBuilder(). 437 AddOps([]byte{ 438 txscript.OP_IF, 439 txscript.OP_SIZE, 440 }).AddInt64(SecretKeySize). 441 AddOps([]byte{ 442 txscript.OP_EQUALVERIFY, 443 txscript.OP_SHA256, 444 }).AddData(secretHash). 445 AddOps([]byte{ 446 txscript.OP_EQUALVERIFY, 447 txscript.OP_DUP, 448 txscript.OP_HASH160, 449 }).AddData(rAddr.ScriptAddress()). 450 AddOp(txscript.OP_ELSE). 451 AddInt64(lockTime).AddOps([]byte{ 452 txscript.OP_CHECKLOCKTIMEVERIFY, 453 txscript.OP_DROP, 454 txscript.OP_DUP, 455 txscript.OP_HASH160, 456 }).AddData(sAddr.ScriptAddress()). 457 AddOps([]byte{ 458 txscript.OP_ENDIF, 459 txscript.OP_EQUALVERIFY, 460 txscript.OP_CHECKSIG, 461 }).Script() 462 } 463 464 // IsDust returns whether or not the passed transaction output amount is 465 // considered dust or not based on the passed minimum transaction relay fee. 466 // Dust is defined in terms of the minimum transaction relay fee. 467 // Based on btcd/policy isDust. See btcd/policy for further documentation. 468 func IsDust(txOut *wire.TxOut, minRelayTxFee uint64) bool { 469 if txscript.IsUnspendable(txOut.PkScript) { 470 return true 471 } 472 return IsDustVal(uint64(txOut.SerializeSize()), uint64(txOut.Value), minRelayTxFee, txscript.IsWitnessProgram(txOut.PkScript)) 473 } 474 475 // IsDustVal is like IsDust but only takes the txSize, amount and if segwit. 476 func IsDustVal(txOutSize, value, minRelayTxFee uint64, segwit bool) bool { 477 totalSize := txOutSize + 41 478 if segwit { 479 // This function is taken from btcd, but noting here that we are not 480 // rounding up and probably should be. 481 totalSize += (107 / witnessWeight) // + 26 482 } else { 483 totalSize += 107 484 } 485 return int64(value)/(3*int64(totalSize)) < int64(minRelayTxFee) 486 } 487 488 // ExtractScriptData extracts script type, addresses, and required signature 489 // count from a pkScript. Non-standard scripts are not necessarily an error; 490 // non-nil errors are only returned if the script cannot be parsed. See also 491 // InputInfo for additional signature script size data 492 func ExtractScriptData(script []byte, chainParams *chaincfg.Params) (BTCScriptType, []string, int, error) { 493 class, addrs, numRequired, err := txscript.ExtractPkScriptAddrs(script, chainParams) 494 if err != nil { 495 return ScriptUnsupported, nil, 0, err 496 } 497 if class == txscript.NonStandardTy { 498 return ScriptUnsupported, nil, 0, nil 499 } 500 501 // Could switch on class from ExtractPkScriptAddrs, but use ParseScriptType 502 // for internal consistency. 503 scriptType := ParseScriptType(script, nil) 504 505 addresses := make([]string, len(addrs)) 506 for i, addr := range addrs { 507 addresses[i] = addr.String() 508 } 509 510 return scriptType, addresses, numRequired, nil 511 } 512 513 // BtcScriptAddrs is information about the pubkeys or pubkey hashes present in 514 // a scriptPubKey (and the redeem script, for p2sh). This information can be 515 // used to estimate the spend script size, e.g. pubkeys in a redeem script don't 516 // require pubkeys in the witness/scriptSig, but pubkey hashes do. 517 type BtcScriptAddrs struct { 518 PubKeys []btcutil.Address 519 NumPK int 520 PkHashes []btcutil.Address 521 NumPKH int 522 NRequired int // num sigs needed 523 } 524 525 // ExtractScriptAddrs extracts the addresses from the pubkey script, or the 526 // redeem script if the pubkey script is P2SH. The returned bool indicates if 527 // the script is non-standard. 528 func ExtractScriptAddrs(script []byte, chainParams *chaincfg.Params) (*BtcScriptAddrs, bool, error) { 529 pubkeys := make([]btcutil.Address, 0) 530 pkHashes := make([]btcutil.Address, 0) 531 // For P2SH and non-P2SH multi-sig, pull the addresses from the pubkey script. 532 class, addrs, numRequired, err := txscript.ExtractPkScriptAddrs(script, chainParams) 533 nonStandard := class == txscript.NonStandardTy 534 if err != nil { // txscript.ExtractPkScriptAddrs always returns a nil error now, so this should not happen 535 return nil, nonStandard, fmt.Errorf("ExtractScriptAddrs: %w", err) 536 } 537 if nonStandard { 538 return &BtcScriptAddrs{}, nonStandard, nil 539 } 540 for _, addr := range addrs { 541 // If the address is an unhashed public key, is won't need a pubkey as part 542 // of its sigScript, so count them separately. 543 _, isPubkey := addr.(*btcutil.AddressPubKey) 544 if isPubkey { 545 pubkeys = append(pubkeys, addr) 546 } else { 547 pkHashes = append(pkHashes, addr) 548 } 549 } 550 return &BtcScriptAddrs{ 551 PubKeys: pubkeys, 552 NumPK: len(pubkeys), 553 PkHashes: pkHashes, 554 NumPKH: len(pkHashes), 555 NRequired: numRequired, 556 }, false, nil 557 } 558 559 // ExtractSwapDetails extacts the sender and receiver addresses from a swap 560 // contract. If the provided script is not a swap contract, an error will be 561 // returned. 562 func ExtractSwapDetails(pkScript []byte, segwit bool, chainParams *chaincfg.Params) ( 563 sender, receiver btcutil.Address, lockTime uint64, secretHash []byte, err error) { 564 // A swap redemption sigScript is <pubkey> <secret> and satisfies the 565 // following swap contract. 566 // 567 // OP_IF 568 // OP_SIZE OP_DATA_1 secretSize OP_EQUALVERIFY OP_SHA256 OP_DATA_32 secretHash OP_EQUALVERIFY OP_DUP OP_HASH160 OP_DATA20 pkHashReceiver 569 // 1 + 1 + 1 + 1 + 1 + 1 + 32 + 1 + 1 + 1 + 1 + 20 570 // OP_ELSE 571 // OP_DATA4 lockTime OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 OP_DATA_20 pkHashSender 572 // 1 + 4 + 1 + 1 + 1 + 1 + 1 + 20 573 // OP_ENDIF 574 // OP_EQUALVERIFY 575 // OP_CHECKSIG 576 // 577 // 5 bytes if-else-endif-equalverify-checksig 578 // 1 + 1 + 1 + 1 + 1 + 1 + 32 + 1 + 1 + 1 + 1 + 20 = 62 bytes for redeem block 579 // 1 + 4 + 1 + 1 + 1 + 1 + 1 + 20 = 30 bytes for refund block 580 // 5 + 62 + 30 = 97 bytes 581 // 582 // Note that this allows for a secret size of up to 75 bytes, but the secret 583 // must be 32 bytes to be considered valid. 584 if len(pkScript) != SwapContractSize { 585 err = fmt.Errorf("incorrect swap contract length. expected %d, got %d", 586 SwapContractSize, len(pkScript)) 587 return 588 } 589 590 if pkScript[0] == txscript.OP_IF && 591 pkScript[1] == txscript.OP_SIZE && 592 pkScript[2] == txscript.OP_DATA_1 && 593 // secretSize (1 bytes) 594 pkScript[4] == txscript.OP_EQUALVERIFY && 595 pkScript[5] == txscript.OP_SHA256 && 596 pkScript[6] == txscript.OP_DATA_32 && 597 // secretHash (32 bytes) 598 pkScript[39] == txscript.OP_EQUALVERIFY && 599 pkScript[40] == txscript.OP_DUP && 600 pkScript[41] == txscript.OP_HASH160 && 601 pkScript[42] == txscript.OP_DATA_20 && 602 // receiver's pkh (20 bytes) 603 pkScript[63] == txscript.OP_ELSE && 604 pkScript[64] == txscript.OP_DATA_4 && 605 // lockTime (4 bytes) 606 pkScript[69] == txscript.OP_CHECKLOCKTIMEVERIFY && 607 pkScript[70] == txscript.OP_DROP && 608 pkScript[71] == txscript.OP_DUP && 609 pkScript[72] == txscript.OP_HASH160 && 610 pkScript[73] == txscript.OP_DATA_20 && 611 // sender's pkh (20 bytes) 612 pkScript[94] == txscript.OP_ENDIF && 613 pkScript[95] == txscript.OP_EQUALVERIFY && 614 pkScript[96] == txscript.OP_CHECKSIG { 615 616 if ssz := pkScript[3]; ssz != SecretKeySize { 617 return nil, nil, 0, nil, fmt.Errorf("invalid secret size %d", ssz) 618 } 619 620 if segwit { 621 receiver, err = btcutil.NewAddressWitnessPubKeyHash(pkScript[43:63], chainParams) 622 if err != nil { 623 return nil, nil, 0, nil, fmt.Errorf("error decoding address from recipient's pubkey hash") 624 } 625 626 sender, err = btcutil.NewAddressWitnessPubKeyHash(pkScript[74:94], chainParams) 627 if err != nil { 628 return nil, nil, 0, nil, fmt.Errorf("error decoding address from sender's pubkey hash") 629 } 630 } else { 631 receiver, err = btcutil.NewAddressPubKeyHash(pkScript[43:63], chainParams) 632 if err != nil { 633 return nil, nil, 0, nil, fmt.Errorf("error decoding address from recipient's pubkey hash") 634 } 635 636 sender, err = btcutil.NewAddressPubKeyHash(pkScript[74:94], chainParams) 637 if err != nil { 638 return nil, nil, 0, nil, fmt.Errorf("error decoding address from sender's pubkey hash") 639 } 640 } 641 642 lockTime = uint64(binary.LittleEndian.Uint32(pkScript[65:69])) 643 secretHash = pkScript[7:39] 644 645 return 646 } 647 648 err = fmt.Errorf("invalid swap contract") 649 return 650 } 651 652 // RedeemP2SHContract returns the signature script to redeem a contract output 653 // using the redeemer's signature and the initiator's secret. This function 654 // assumes P2SH and appends the contract as the final data push. 655 func RedeemP2SHContract(contract, sig, pubkey, secret []byte) ([]byte, error) { 656 return txscript.NewScriptBuilder(). 657 AddData(sig). 658 AddData(pubkey). 659 AddData(secret). 660 AddInt64(1). 661 AddData(contract). 662 Script() 663 } 664 665 // RedeemP2WSHContract returns the witness script to redeem a contract output 666 // using the redeemer's signature and the initiator's secret. This function 667 // assumes P2WSH and appends the contract as the final data push. 668 func RedeemP2WSHContract(contract, sig, pubkey, secret []byte) [][]byte { 669 return [][]byte{ 670 sig, 671 pubkey, 672 secret, 673 {0x01}, 674 contract, 675 } 676 } 677 678 // RefundP2SHContract returns the signature script to refund a contract output 679 // using the contract author's signature after the locktime has been reached. 680 // This function assumes P2SH and appends the contract as the final data push. 681 func RefundP2SHContract(contract, sig, pubkey []byte) ([]byte, error) { 682 return txscript.NewScriptBuilder(). 683 AddData(sig). 684 AddData(pubkey). 685 AddInt64(0). 686 AddData(contract). 687 Script() 688 } 689 690 // OP_RETURN <pushData: ver[2] | account_id[32] | lockTime[4] | pkh[20]> 691 func extractBondCommitDataV0(pushData []byte) (acct account.AccountID, lockTime uint32, pubkeyHash [20]byte, err error) { 692 if len(pushData) < 2 { 693 err = errors.New("invalid data") 694 return 695 } 696 ver := binary.BigEndian.Uint16(pushData) 697 if ver != 0 { 698 err = fmt.Errorf("unexpected bond commitment version %d, expected 0", ver) 699 return 700 } 701 702 if len(pushData) != BondPushDataSize { 703 err = fmt.Errorf("invalid bond commitment output script length: %d", len(pushData)) 704 return 705 } 706 707 pushData = pushData[2:] // pop off ver 708 709 copy(acct[:], pushData) 710 pushData = pushData[account.HashSize:] 711 712 lockTime = binary.BigEndian.Uint32(pushData) 713 pushData = pushData[4:] 714 715 copy(pubkeyHash[:], pushData) 716 717 return 718 } 719 720 // ExtractBondCommitDataV0 parses a v0 bond commitment output script. This is 721 // the OP_RETURN output, not the P2SH bond output. Use ExtractBondDetailsV0 to 722 // parse the P2SH bond output's redeem script. 723 // 724 // If the decoded commitment data indicates a version other than 0, an error is 725 // returned. 726 func ExtractBondCommitDataV0(scriptVer uint16, pkScript []byte) (acct account.AccountID, lockTime uint32, pubkeyHash [20]byte, err error) { 727 tokenizer := txscript.MakeScriptTokenizer(scriptVer, pkScript) 728 if !tokenizer.Next() { 729 err = tokenizer.Err() 730 return 731 } 732 733 if tokenizer.Opcode() != txscript.OP_RETURN { 734 err = errors.New("not a null data output") 735 return 736 } 737 738 if !tokenizer.Next() { 739 err = tokenizer.Err() 740 return 741 } 742 743 pushData := tokenizer.Data() 744 acct, lockTime, pubkeyHash, err = extractBondCommitDataV0(pushData) 745 if err != nil { 746 return 747 } 748 749 if !tokenizer.Done() { 750 err = errors.New("script has extra opcodes") 751 return 752 } 753 754 return 755 } 756 757 // MakeBondScript constructs a versioned bond output script for the provided 758 // lock time and pubkey hash. Only version 0 is supported at present. The lock 759 // time must be less than 2^32-1 so that it uses at most 5 bytes. The lockTime 760 // is also required to use at least 4 bytes (time stamp, not block time). 761 func MakeBondScript(ver uint16, lockTime uint32, pubkeyHash []byte) ([]byte, error) { 762 if ver != 0 { 763 return nil, errors.New("only version 0 bonds supported") 764 } 765 if lockTime >= MaxCLTVScriptNum { // == should be OK, but let's not 766 return nil, errors.New("invalid lock time") 767 } 768 lockTimeInt64 := int64(lockTime) 769 if len(pubkeyHash) != 20 { 770 return nil, errors.New("invalid pubkey hash") 771 } 772 return txscript.NewScriptBuilder(). 773 AddInt64(lockTimeInt64). 774 AddOp(txscript.OP_CHECKLOCKTIMEVERIFY). 775 AddOp(txscript.OP_DROP). 776 AddOp(txscript.OP_DUP). 777 AddOp(txscript.OP_HASH160). 778 AddData(pubkeyHash). 779 AddOp(txscript.OP_EQUALVERIFY). 780 AddOp(txscript.OP_CHECKSIG). 781 Script() 782 } 783 784 // RefundBondScript builds the signature script to refund a time-locked fidelity 785 // bond in a P2SH output paying to the provided P2PKH bondScript. 786 func RefundBondScript(bondScript, sig, pubkey []byte) ([]byte, error) { 787 return txscript.NewScriptBuilder(). 788 AddData(sig). 789 AddData(pubkey). 790 AddData(bondScript). 791 Script() 792 } 793 794 // RefundBondScript builds the signature script to refund a time-locked fidelity 795 // bond in a P2WSH output paying to the provided P2PKH bondScript. 796 func RefundBondScriptSegwit(bondScript, sig, pubkey []byte) [][]byte { 797 return [][]byte{ 798 sig, 799 pubkey, 800 bondScript, 801 } 802 } 803 804 // ExtractBondDetailsV0 validates the provided bond redeem script, extracting 805 // the lock time and pubkey. The V0 format of the script must be as follows: 806 // 807 // <lockTime> OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 <pubkeyhash[20]> OP_EQUALVERIFY OP_CHECKSIG 808 // 809 // The script version refers to the pkScript version, not bond version, which 810 // pertains to DEX's version of the bond script. 811 func ExtractBondDetailsV0(scriptVersion uint16, bondScript []byte) (lockTime uint32, pkh []byte, err error) { 812 type templateMatch struct { 813 expectInt bool 814 maxIntBytes int 815 opcode byte 816 extractedInt int64 817 extractedData []byte 818 } 819 var template = [...]templateMatch{ 820 {expectInt: true, maxIntBytes: 5}, // extractedInt 821 {opcode: txscript.OP_CHECKLOCKTIMEVERIFY}, 822 {opcode: txscript.OP_DROP}, 823 {opcode: txscript.OP_DUP}, 824 {opcode: txscript.OP_HASH160}, 825 {opcode: txscript.OP_DATA_20}, // extractedData 826 {opcode: txscript.OP_EQUALVERIFY}, 827 {opcode: txscript.OP_CHECKSIG}, 828 } 829 830 var templateOffset int 831 tokenizer := txscript.MakeScriptTokenizer(scriptVersion, bondScript) 832 for tokenizer.Next() { 833 if templateOffset >= len(template) { 834 return 0, nil, errors.New("too many script elements") 835 } 836 837 op, data := tokenizer.Opcode(), tokenizer.Data() 838 tplEntry := &template[templateOffset] 839 if tplEntry.expectInt { 840 switch { 841 case data != nil: 842 val, err := dcrtxscript.MakeScriptNum(data, tplEntry.maxIntBytes) 843 if err != nil { 844 return 0, nil, err 845 } 846 tplEntry.extractedInt = int64(val) 847 case dcrtxscript.IsSmallInt(op): // not expected for our lockTimes, but it is an integer 848 tplEntry.extractedInt = int64(dcrtxscript.AsSmallInt(op)) 849 default: 850 return 0, nil, errors.New("expected integer") 851 } 852 } else { 853 if op != tplEntry.opcode { 854 return 0, nil, fmt.Errorf("expected opcode %v, got %v", tplEntry.opcode, op) 855 } 856 857 tplEntry.extractedData = data 858 } 859 860 templateOffset++ 861 } 862 if err := tokenizer.Err(); err != nil { 863 return 0, nil, err 864 } 865 if !tokenizer.Done() || templateOffset != len(template) { 866 return 0, nil, errors.New("incorrect script length") 867 } 868 869 // The script matches in structure. Now validate the two pushes. 870 871 lockTime64 := template[0].extractedInt 872 if lockTime64 <= 0 { // || lockTime64 > MaxCLTVScriptNum { 873 return 0, nil, fmt.Errorf("invalid locktime %d", lockTime64) 874 } 875 lockTime = uint32(lockTime64) 876 877 const pubkeyHashLen = 20 878 bondPubKeyHash := template[5].extractedData 879 if len(bondPubKeyHash) != pubkeyHashLen { 880 err = errors.New("missing or invalid pubkeyhash data") 881 return 882 } 883 pkh = make([]byte, pubkeyHashLen) 884 copy(pkh, bondPubKeyHash) 885 886 return 887 } 888 889 // MsgTxVBytes returns the transaction's virtual size, which accounts for the 890 // segwit input weighting. 891 func MsgTxVBytes(msgTx *wire.MsgTx) uint64 { 892 baseSize := msgTx.SerializeSizeStripped() 893 totalSize := msgTx.SerializeSize() 894 txWeight := baseSize*(witnessWeight-1) + totalSize 895 // vbytes is ceil(tx_weight/4) 896 return uint64(txWeight+(witnessWeight-1)) / witnessWeight // +3 before / 4 to round up 897 // NOTE: This is the same as doing the following: 898 // tx := btcutil.NewTx(msgTx) 899 // return uint64(blockchain.GetTransactionWeight(tx)+(blockchain.WitnessScaleFactor-1)) / 900 // blockchain.WitnessScaleFactor // mempool.GetTxVirtualSize(tx) 901 } 902 903 // RefundP2WSHContract returns the witness to refund a contract output 904 // using the contract author's signature after the locktime has been reached. 905 // This function assumes P2WSH and appends the contract as the final data push. 906 func RefundP2WSHContract(contract, sig, pubkey []byte) [][]byte { 907 return [][]byte{ 908 sig, 909 pubkey, 910 {}, 911 contract, 912 } 913 } 914 915 // SpendInfo is information about an input and it's previous outpoint. 916 type SpendInfo struct { 917 SigScriptSize uint32 918 WitnessSize uint32 919 ScriptAddrs *BtcScriptAddrs 920 ScriptType BTCScriptType 921 NonStandardScript bool 922 } 923 924 // VBytes is the virtual bytes of the spending transaction input. Miners use 925 // weight/4 = vbytes to calculate contribution to block size limit and therefore 926 // transaction fees. 927 func (nfo *SpendInfo) VBytes() uint32 { 928 return TxInOverhead + uint32(wire.VarIntSerializeSize(uint64(nfo.SigScriptSize))) + 929 nfo.SigScriptSize + (nfo.WitnessSize+(witnessWeight-1))/witnessWeight // Add 3 before dividing witness weight to force rounding up. 930 } 931 932 // InputInfo is some basic information about the input required to spend an 933 // output. The pubkey script of the output is provided. If the pubkey script 934 // parses as P2SH or P2WSH, the redeem script must be provided. 935 func InputInfo(pkScript, redeemScript []byte, chainParams *chaincfg.Params) (*SpendInfo, error) { 936 // Get information about the signatures and pubkeys needed to spend the utxo. 937 scriptType := ParseScriptType(pkScript, redeemScript) 938 if scriptType == ScriptUnsupported { 939 return nil, dex.UnsupportedScriptError 940 } 941 evalScript := pkScript 942 if scriptType.IsP2SH() || scriptType.IsP2WSH() { 943 if len(redeemScript) == 0 { 944 return nil, fmt.Errorf("no redeem script provided for p2sh or p2wsh address") 945 } 946 evalScript = redeemScript 947 } 948 scriptAddrs, nonStandard, err := ExtractScriptAddrs(evalScript, chainParams) 949 if err != nil { 950 return nil, fmt.Errorf("error parsing script addresses: %w", err) 951 } 952 if nonStandard { 953 return &SpendInfo{ 954 // SigScriptSize and WitnessSize cannot be determined, leave zero. 955 ScriptAddrs: scriptAddrs, 956 ScriptType: scriptType, 957 NonStandardScript: true, 958 }, nil 959 } 960 961 // Start with standard P2PKH. 962 var sigScriptSize, witnessWeight int 963 switch { 964 case scriptType.IsP2PK(): 965 sigScriptSize = RedeemP2PKSigScriptSize 966 witnessWeight = 0 967 case scriptType.IsP2PKH(): 968 sigScriptSize = RedeemP2PKHSigScriptSize 969 witnessWeight = 0 970 case scriptType.IsP2WPKH(): 971 sigScriptSize = 0 972 witnessWeight = RedeemP2WPKHInputWitnessWeight 973 case scriptType.IsP2SH(): 974 // If it's a P2SH, the size must be calculated based on other factors. 975 976 // If the redeem script is P2SM, there is a leading OP_0 in Bitcoin. 977 if scriptType.IsMultiSig() { 978 sigScriptSize++ 979 } 980 981 // The signatures. 982 sigScriptSize += (DERSigLength + 1) * scriptAddrs.NRequired // 73 max for sig, 1 for push code 983 984 // If there are pubkey-hash addresses, they'll need pubkeys. 985 if scriptAddrs.NumPKH > 0 { 986 sigScriptSize += scriptAddrs.NRequired * (PubKeyLength + 1) 987 } 988 989 // Then add the script_length(1) + len(script). 990 sigScriptSize += len(redeemScript) + 1 991 case scriptType.IsP2WSH(): 992 witnessWeight = (DERSigLength + 1) * scriptAddrs.NRequired 993 if scriptAddrs.NumPKH > 0 { 994 witnessWeight += scriptAddrs.NRequired * (PubKeyLength + 1) 995 } 996 witnessWeight += len(redeemScript) + 1 997 default: 998 return nil, fmt.Errorf("error calculating size. unknown script type %d?", scriptType) 999 } 1000 return &SpendInfo{ 1001 SigScriptSize: uint32(sigScriptSize), 1002 WitnessSize: uint32(witnessWeight), 1003 ScriptAddrs: scriptAddrs, 1004 ScriptType: scriptType, 1005 }, nil 1006 } 1007 1008 // FindKeyPush attempts to extract the secret key from the signature script. The 1009 // contract must be provided for the search algorithm to verify the correct data 1010 // push. Only contracts of length SwapContractSize that can be validated by 1011 // ExtractSwapDetails are recognized. 1012 func FindKeyPush(witness [][]byte, sigScript, contractHash []byte, segwit bool, chainParams *chaincfg.Params) ([]byte, error) { 1013 var redeemScript, secret []byte 1014 var hasher func([]byte) []byte 1015 if segwit { 1016 if len(witness) != 5 { 1017 return nil, fmt.Errorf("witness should contain 5 data pushes. Found %d", len(witness)) 1018 } 1019 secret, redeemScript = witness[2], witness[4] 1020 hasher = func(b []byte) []byte { 1021 h := sha256.Sum256(b) 1022 return h[:] 1023 } 1024 } else { 1025 pushes, err := txscript.PushedData(sigScript) 1026 if err != nil { 1027 return nil, fmt.Errorf("sigScript PushedData(%x): %w", sigScript, err) 1028 } 1029 if len(pushes) != 4 { 1030 return nil, fmt.Errorf("sigScript should contain 4 data pushes. Found %d", len(pushes)) 1031 } 1032 secret, redeemScript = pushes[2], pushes[3] 1033 hasher = btcutil.Hash160 1034 } 1035 return findKeyPush(redeemScript, secret, contractHash, chainParams, hasher) 1036 } 1037 1038 func findKeyPush(redeemScript, secret, contractHash []byte, chainParams *chaincfg.Params, hasher func([]byte) []byte) ([]byte, error) { 1039 // Doesn't matter what we pass for the bool segwit argument, since we're not 1040 // using the addresses, and the contract's 20-byte pubkey hashes are 1041 // compatible with both address types. 1042 _, _, _, keyHash, err := ExtractSwapDetails(redeemScript, true, chainParams) 1043 if err != nil { 1044 return nil, fmt.Errorf("error extracting atomic swap details: %w", err) 1045 } 1046 if !bytes.Equal(hasher(redeemScript), contractHash) { 1047 return nil, fmt.Errorf("redeemScript is not correct for provided contract hash") 1048 } 1049 h := sha256.Sum256(secret) 1050 if !bytes.Equal(h[:], keyHash) { 1051 return nil, fmt.Errorf("incorrect secret") 1052 } 1053 return secret, nil 1054 } 1055 1056 // ExtractPubKeyHash extracts the pubkey hash from the passed script if it is a 1057 // standard pay-to-pubkey-hash script. It will return nil otherwise. 1058 func ExtractPubKeyHash(script []byte) []byte { 1059 // A pay-to-pubkey-hash script is of the form: 1060 // OP_DUP OP_HASH160 <20-byte hash> OP_EQUALVERIFY OP_CHECKSIG 1061 if len(script) == 25 && 1062 script[0] == txscript.OP_DUP && 1063 script[1] == txscript.OP_HASH160 && 1064 script[2] == txscript.OP_DATA_20 && 1065 script[23] == txscript.OP_EQUALVERIFY && 1066 script[24] == txscript.OP_CHECKSIG { 1067 1068 return script[3:23] 1069 } 1070 1071 return nil 1072 } 1073 1074 // ExtractContractHash extracts the contract P2SH or P2WSH address from a 1075 // pkScript. A non-nil error is returned if the hexadecimal encoding of the 1076 // pkScript is invalid, or if the pkScript is not a P2SH or P2WSH script. 1077 func ExtractContractHash(scriptHex string) ([]byte, error) { 1078 pkScript, err := hex.DecodeString(scriptHex) 1079 if err != nil { 1080 return nil, fmt.Errorf("error decoding scriptPubKey '%s': %w", 1081 scriptHex, err) 1082 } 1083 scriptHash := ExtractScriptHash(pkScript) 1084 if scriptHash == nil { 1085 return nil, fmt.Errorf("error extracting script hash") 1086 } 1087 return scriptHash, nil 1088 } 1089 1090 // ExtractScriptHash attempts to extract the redeem script hash from a pkScript. 1091 // If it is not a P2SH or P2WSH pkScript, a nil slice is returned. 1092 func ExtractScriptHash(script []byte) []byte { 1093 // A pay-to-script-hash pkScript is of the form: 1094 // OP_HASH160 <20-byte scripthash> OP_EQUAL 1095 if len(script) == 23 && 1096 script[0] == txscript.OP_HASH160 && 1097 script[1] == txscript.OP_DATA_20 && 1098 script[22] == txscript.OP_EQUAL { 1099 1100 return script[2:22] 1101 } 1102 // A pay-to-witness-script-hash pkScript is of the form: 1103 // OP_0 <32-byte scripthash> 1104 if len(script) == 34 && 1105 script[0] == txscript.OP_0 && 1106 script[1] == txscript.OP_DATA_32 { 1107 return script[2:34] 1108 } 1109 return nil 1110 }