Skip to content

Commit

Permalink
dcr: stdscript migration
Browse files Browse the repository at this point in the history
This migrates to the new txscript/v4/stdscript package with the newly tagged
txscript v4.0.0 module.

This also updates to tagged versions of the following dcrd modules:

- chaincfg/v3 v3.1.0
- edwards/v2 v2.0.2
- secp256k1/v4 v4.0.1
- dcrutil/v4 v4.0.0
- wire v1.5.0
- gcs/v3.0.0
- hdkeychain/v3.0.1

The new stdscript package lends itself to quite a bit of simplification and removal
of duplicate code, which as it turns out was a bit more fragile than necessary
w.r.t. script versions, new stake opcodes, etc.
  • Loading branch information
chappjc committed Dec 17, 2021
1 parent 10bb7a3 commit 920b35a
Show file tree
Hide file tree
Showing 10 changed files with 313 additions and 545 deletions.
48 changes: 27 additions & 21 deletions client/asset/dcr/dcr.go
Expand Up @@ -37,6 +37,7 @@ import (
"github.com/decred/dcrd/txscript/v4"
"github.com/decred/dcrd/txscript/v4/sign"
"github.com/decred/dcrd/txscript/v4/stdaddr"
"github.com/decred/dcrd/txscript/v4/stdscript"
"github.com/decred/dcrd/wire"
)

Expand Down Expand Up @@ -937,7 +938,7 @@ func (dcr *ExchangeWallet) tryFund(utxos []*compositeUTXO, enough func(sum uint6

okUTXOs := make([]*compositeUTXO, 0, len(utxos)) // over-allocate
for _, cu := range utxos {
if cu.confs >= minconf {
if cu.confs >= minconf && cu.rpc.Spendable {
okUTXOs = append(okUTXOs, cu)
}
}
Expand Down Expand Up @@ -1521,19 +1522,13 @@ func (dcr *ExchangeWallet) AuditContract(coinID, contract, txData dex.Bytes, reb
// Validate contract output.
// Script must be P2SH, with 1 address and 1 required signature.
contractTxOut := contractTx.TxOut[vout]
scriptClass, addrs, sigsReq, err := txscript.ExtractPkScriptAddrs(contractTxOut.Version, contractTxOut.PkScript, dcr.chainParams, false)
if err != nil {
return nil, fmt.Errorf("error extracting script addresses from '%x': %w", contractTxOut.PkScript, err)
}
if scriptClass != txscript.ScriptHashTy {
scriptClass, addrs := stdscript.ExtractAddrs(contractTxOut.Version, contractTxOut.PkScript, dcr.chainParams)
if scriptClass != stdscript.STScriptHash {
return nil, fmt.Errorf("unexpected script class %d", scriptClass)
}
if len(addrs) != 1 {
return nil, fmt.Errorf("unexpected number of addresses for P2SH script: %d", len(addrs))
}
if sigsReq != 1 {
return nil, fmt.Errorf("unexpected number of signatures for P2SH script: %d", sigsReq)
}
// Compare the contract hash to the P2SH address.
contractHash := dcrutil.Hash160(contract)
addr := addrs[0]
Expand Down Expand Up @@ -1780,8 +1775,9 @@ func (dcr *ExchangeWallet) queueFindRedemptionRequest(ctx context.Context, contr
if int(vout) > len(msgTx.TxOut)-1 {
return nil, nil, fmt.Errorf("vout index %d out of range for transaction %s", vout, txHash)
}
contractP2shScript := msgTx.TxOut[vout].PkScript
if !dexdcr.IsScriptHashScript(contractP2shScript) {
contractScript := msgTx.TxOut[vout].PkScript
contractScriptVer := msgTx.TxOut[vout].Version
if !stdscript.IsScriptHashScript(contractScriptVer, contractScript) {
return nil, nil, fmt.Errorf("coin %s not a valid contract", contractOutpoint.String())
}
var contractBlock *block
Expand All @@ -1801,8 +1797,8 @@ func (dcr *ExchangeWallet) queueFindRedemptionRequest(ctx context.Context, contr
resultChan := make(chan *findRedemptionResult, 1)
dcr.findRedemptionQueue[contractOutpoint] = &findRedemptionReq{
ctx: ctx,
contractP2SHScript: contractP2shScript,
contractOutputScriptVer: msgTx.TxOut[vout].Version,
contractP2SHScript: contractScript,
contractOutputScriptVer: contractScriptVer,
resultChan: resultChan,
}
return resultChan, contractBlock, nil
Expand Down Expand Up @@ -2010,7 +2006,8 @@ func (dcr *ExchangeWallet) findRedemptionsInTx(scanPoint string, tx *chainjson.T
}
found++

redeemTxHash, secret, err := extractSecret(i, dexdcr.ExtractScriptHash(req.contractP2SHScript), req.contractOutputScriptVer)
scriptHash := dexdcr.ExtractScriptHash(req.contractOutputScriptVer, req.contractP2SHScript)
redeemTxHash, secret, err := extractSecret(i, scriptHash, req.contractOutputScriptVer)
if err != nil {
dcr.log.Errorf("Error parsing contract secret for %s from tx input %s:%d in %s: %v",
contractOutpoint.String(), tx.Txid, i, scanPoint, err)
Expand Down Expand Up @@ -2383,14 +2380,17 @@ type compositeUTXO struct {
// The returned list is sorted by ascending value.
func (dcr *ExchangeWallet) parseUTXOs(unspents []walletjson.ListUnspentResult) ([]*compositeUTXO, error) {
utxos := make([]*compositeUTXO, 0, len(unspents))
for _, txout := range unspents {
scriptPK, err := hex.DecodeString(txout.ScriptPubKey)
for _, utxo := range unspents {
if !utxo.Spendable {
continue
}
scriptPK, err := hex.DecodeString(utxo.ScriptPubKey)
if err != nil {
return nil, fmt.Errorf("error decoding pubkey script for %s, script = %s: %w", txout.TxID, txout.ScriptPubKey, err)
return nil, fmt.Errorf("error decoding pubkey script for %s, script = %s: %w", utxo.TxID, utxo.ScriptPubKey, err)
}
redeemScript, err := hex.DecodeString(txout.RedeemScript)
redeemScript, err := hex.DecodeString(utxo.RedeemScript)
if err != nil {
return nil, fmt.Errorf("error decoding redeem script for %s, script = %s: %w", txout.TxID, txout.RedeemScript, err)
return nil, fmt.Errorf("error decoding redeem script for %s, script = %s: %w", utxo.TxID, utxo.RedeemScript, err)
}

// NOTE: listunspent does not indicate script version, so for the
Expand All @@ -2402,10 +2402,16 @@ func (dcr *ExchangeWallet) parseUTXOs(unspents []walletjson.ListUnspentResult) (
}
return nil, fmt.Errorf("error reading asset info: %w", err)
}
if nfo.ScriptType == dexdcr.ScriptUnsupported || nfo.NonStandardScript {
// InputInfo sets NonStandardScript for P2SH with non-standard
// redeem scripts. Don't return these since they cannot fund
// arbitrary txns.
continue
}
utxos = append(utxos, &compositeUTXO{
rpc: txout,
rpc: utxo,
input: nfo,
confs: txout.Confirmations,
confs: utxo.Confirmations,
})
}
// Sort in ascending order by amount (smallest first).
Expand Down
14 changes: 10 additions & 4 deletions client/asset/dcr/dcr_test.go
Expand Up @@ -721,6 +721,7 @@ func TestAvailableFund(t *testing.T) {
Amount: float64(atomAmt) / 1e8,
Confirmations: confs,
ScriptPubKey: hex.EncodeToString(tP2PKHScript),
Spendable: true,
}
if lock {
node.lluCoins = append(node.lluCoins, utxo)
Expand Down Expand Up @@ -1045,10 +1046,11 @@ func TestFundingCoins(t *testing.T) {
vout := uint32(123)
coinID := toCoinID(tTxHash, vout)
p2pkhUnspent := walletjson.ListUnspentResult{
TxID: tTxID,
Vout: vout,
Address: tPKHAddr.String(),
Account: wallet.acct,
TxID: tTxID,
Vout: vout,
Address: tPKHAddr.String(),
Account: wallet.acct,
Spendable: true,
}

node.unspent = []walletjson.ListUnspentResult{p2pkhUnspent}
Expand Down Expand Up @@ -1174,6 +1176,7 @@ func TestFundEdges(t *testing.T) {
Amount: float64(swapVal+fees-1) / 1e8, // one atom less than needed
Confirmations: 5,
ScriptPubKey: hex.EncodeToString(tP2PKHScript),
Spendable: true,
}

node.unspent = []walletjson.ListUnspentResult{p2pkhUnspent}
Expand Down Expand Up @@ -2043,6 +2046,7 @@ func testSender(t *testing.T, senderType tSenderType) {
Amount: float64(unspentVal) / 1e8,
Confirmations: 5,
ScriptPubKey: hex.EncodeToString(tP2PKHScript),
Spendable: true,
}}
//node.unspent = append(node.unspent, node.unspent[0])

Expand Down Expand Up @@ -2099,6 +2103,7 @@ func Test_sendMinusFees(t *testing.T) {
Amount: float64(unspentVal) / 1e8,
Confirmations: 5,
ScriptPubKey: hex.EncodeToString(tP2PKHScript),
Spendable: true,
}}

addr, err := stdaddr.DecodeAddress(address, tChainParams)
Expand Down Expand Up @@ -2427,6 +2432,7 @@ func TestPreSwap(t *testing.T) {
Amount: float64(swapVal+fees-1) / 1e8, // one atom less than needed
Confirmations: 5,
ScriptPubKey: hex.EncodeToString(tP2PKHScript),
Spendable: true,
}

node.unspent = []walletjson.ListUnspentResult{p2pkhUnspent}
Expand Down

0 comments on commit 920b35a

Please sign in to comment.