diff --git a/blockchain/chain_test.go b/blockchain/chain_test.go index 61bd361dd5..124fafe5f8 100644 --- a/blockchain/chain_test.go +++ b/blockchain/chain_test.go @@ -1,5 +1,5 @@ // Copyright (c) 2013-2016 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -21,6 +21,7 @@ import ( "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/chaincfg/v3" "github.com/decred/dcrd/dcrutil/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -125,7 +126,7 @@ func TestBlockchainFunctions(t *testing.T) { "want %v, got %v", expectedVal, val) } - a, _ := dcrutil.DecodeAddress("SsbKpMkPnadDcZFFZqRPY8nvdFagrktKuzB", params) + a, _ := stdaddr.DecodeAddress("SsbKpMkPnadDcZFFZqRPY8nvdFagrktKuzB", params) hs, err := chain.TicketsWithAddress(a, noTreasury) if err != nil { t.Errorf("Failed to do TicketsWithAddress: %v", err) diff --git a/blockchain/chaingen/generator.go b/blockchain/chaingen/generator.go index f37076492d..02c40df53c 100644 --- a/blockchain/chaingen/generator.go +++ b/blockchain/chaingen/generator.go @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Decred developers +// Copyright (c) 2016-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -19,6 +19,7 @@ import ( "github.com/decred/dcrd/chaincfg/v3" "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -158,15 +159,16 @@ func (t stakeTicketSorter) Less(i, j int) bool { // available spendable outputs and generic payment scripts used throughout the // tests. type Generator struct { - params *chaincfg.Params - tip *wire.MsgBlock - tipName string - blocks map[chainhash.Hash]*wire.MsgBlock - blockHeights map[chainhash.Hash]uint32 - blocksByName map[string]*wire.MsgBlock - blockNames map[chainhash.Hash]string - p2shOpTrueAddr dcrutil.Address - p2shOpTrueScript []byte + params *chaincfg.Params + tip *wire.MsgBlock + tipName string + blocks map[chainhash.Hash]*wire.MsgBlock + blockHeights map[chainhash.Hash]uint32 + blocksByName map[string]*wire.MsgBlock + blockNames map[chainhash.Hash]string + p2shOpTrueAddr stdaddr.StakeAddress + p2shOpTrueScriptVer uint16 + p2shOpTrueScript []byte // Used for tracking spendable coinbase outputs. spendableOuts [][]SpendableOut @@ -188,31 +190,29 @@ func MakeGenerator(params *chaincfg.Params) (Generator, error) { // Generate a generic pay-to-script-hash script that is a simple // OP_TRUE. This allows the tests to avoid needing to generate and // track actual public keys and signatures. - p2shOpTrueAddr, err := dcrutil.NewAddressScriptHash(opTrueScript, params) - if err != nil { - return Generator{}, err - } - p2shOpTrueScript, err := txscript.PayToAddrScript(p2shOpTrueAddr) + p2shOpTrueAddr, err := stdaddr.NewAddressScriptHashV0(opTrueScript, params) if err != nil { return Generator{}, err } + p2shOpTrueScriptVer, p2shOpTrueScript := p2shOpTrueAddr.PaymentScript() genesis := params.GenesisBlock genesisHash := genesis.BlockHash() return Generator{ - params: params, - tip: genesis, - tipName: "genesis", - blocks: map[chainhash.Hash]*wire.MsgBlock{genesisHash: genesis}, - blockHeights: map[chainhash.Hash]uint32{genesisHash: 0}, - blocksByName: map[string]*wire.MsgBlock{"genesis": genesis}, - blockNames: map[chainhash.Hash]string{genesisHash: "genesis"}, - p2shOpTrueAddr: p2shOpTrueAddr, - p2shOpTrueScript: p2shOpTrueScript, - originalParents: make(map[chainhash.Hash]chainhash.Hash), - wonTickets: make(map[chainhash.Hash][]*stakeTicket), - revokedTickets: make(map[chainhash.Hash][]*stakeTicket), - missedVotes: make(map[chainhash.Hash]*stakeTicket), + params: params, + tip: genesis, + tipName: "genesis", + blocks: map[chainhash.Hash]*wire.MsgBlock{genesisHash: genesis}, + blockHeights: map[chainhash.Hash]uint32{genesisHash: 0}, + blocksByName: map[string]*wire.MsgBlock{"genesis": genesis}, + blockNames: map[chainhash.Hash]string{genesisHash: "genesis"}, + p2shOpTrueAddr: p2shOpTrueAddr, + p2shOpTrueScriptVer: p2shOpTrueScriptVer, + p2shOpTrueScript: p2shOpTrueScript, + originalParents: make(map[chainhash.Hash]chainhash.Hash), + wonTickets: make(map[chainhash.Hash][]*stakeTicket), + revokedTickets: make(map[chainhash.Hash][]*stakeTicket), + missedVotes: make(map[chainhash.Hash]*stakeTicket), }, nil } @@ -233,7 +233,7 @@ func (g *Generator) TipName() string { // P2shOpTrueAddr returns the generator p2sh script that is composed with // a single OP_TRUE. -func (g *Generator) P2shOpTrueAddr() dcrutil.Address { +func (g *Generator) P2shOpTrueAddr() stdaddr.StakeAddress { return g.p2shOpTrueAddr } @@ -395,6 +395,15 @@ func standardCoinbaseOpReturnScript(blockHeight uint32) []byte { return opReturnScript(data) } +// newTxOut returns a new transaction output with the given parameters. +func newTxOut(amount int64, pkScriptVer uint16, pkScript []byte) *wire.TxOut { + return &wire.TxOut{ + Value: amount, + Version: pkScriptVer, + PkScript: pkScript, + } +} + // addCoinbaseTxOutputs adds the following outputs to the provided transaction // which is assumed to be a coinbase transaction: // - First output pays the development subsidy portion to the dev org @@ -423,7 +432,8 @@ func (g *Generator) addCoinbaseTxOutputs(tx *wire.MsgTx, blockHeight uint32, dev if i == numPoWOutputs-1 { amount = powSubsidy - amount*(numPoWOutputs-1) } - tx.AddTxOut(wire.NewTxOut(int64(amount), g.p2shOpTrueScript)) + tx.AddTxOut(newTxOut(int64(amount), g.p2shOpTrueScriptVer, + g.p2shOpTrueScript)) } } @@ -458,41 +468,6 @@ func (g *Generator) CreateCoinbaseTx(blockHeight uint32, numVotes uint16) *wire. return tx } -// PurchaseCommitmentScript returns a standard provably-pruneable OP_RETURN -// commitment script suitable for use in a ticket purchase tx (sstx) using the -// provided target address, amount, and fee limits. -func PurchaseCommitmentScript(addr dcrutil.Address, amount, voteFeeLimit, revocationFeeLimit dcrutil.Amount) []byte { - // The limits are defined in terms of the closest base 2 exponent and - // a bit that must be set to specify the limit is to be applied. The - // vote fee exponent is in the bottom 8 bits, while the revocation fee - // exponent is in the upper 8 bits. - limits := uint16(0) - if voteFeeLimit != 0 { - exp := uint16(math.Ceil(math.Log2(float64(voteFeeLimit)))) - limits |= (exp | 0x40) - } - if revocationFeeLimit != 0 { - exp := uint16(math.Ceil(math.Log2(float64(revocationFeeLimit)))) - limits |= ((exp | 0x40) << 8) - } - - // The data consists of the 20-byte raw script address for the given - // address, 8 bytes for the amount to commit to (with the upper bit flag - // set to indicate a pay-to-script-hash address), and 2 bytes for the - // fee limits. - var data [30]byte - copy(data[:], addr.ScriptAddress()) - binary.LittleEndian.PutUint64(data[20:], uint64(amount)) - data[27] |= 1 << 7 - binary.LittleEndian.PutUint16(data[28:], limits) - script, err := txscript.NewScriptBuilder().AddOp(txscript.OP_RETURN). - AddData(data[:]).Script() - if err != nil { - panic(err) - } - return script -} - // CreateTicketPurchaseTx creates a new transaction that spends the provided // output to purchase a stake submission ticket (sstx) at the given ticket // price. Both the ticket and the change will go to a p2sh script that is @@ -505,21 +480,15 @@ func PurchaseCommitmentScript(addr dcrutil.Address, amount, voteFeeLimit, revoca func (g *Generator) CreateTicketPurchaseTx(spend *SpendableOut, ticketPrice, fee dcrutil.Amount) *wire.MsgTx { // The first output is the voting rights address. This impl uses the // standard pay-to-script-hash to an OP_TRUE. - pkScript, err := txscript.PayToSStx(g.p2shOpTrueAddr) - if err != nil { - panic(err) - } + voteScriptVer, voteScript := g.p2shOpTrueAddr.VotingRightsScript() // Generate the commitment script. - commitScript := PurchaseCommitmentScript(g.p2shOpTrueAddr, - ticketPrice+fee, 0, ticketPrice) + commitScriptVer, commitScript := g.p2shOpTrueAddr.RewardCommitmentScript( + int64(ticketPrice+fee), 0, int64(ticketPrice)) // Calculate change and generate script to deliver it. change := spend.amount - ticketPrice - fee - changeScript, err := txscript.PayToSStxChange(g.p2shOpTrueAddr) - if err != nil { - panic(err) - } + changeScriptVer, changeScript := g.p2shOpTrueAddr.StakeChangeScript() // Generate and return the transaction spending from the provided // spendable output with the previously described outputs. @@ -532,37 +501,32 @@ func (g *Generator) CreateTicketPurchaseTx(spend *SpendableOut, ticketPrice, fee BlockIndex: spend.blockIndex, SignatureScript: opTrueRedeemScript, }) - tx.AddTxOut(wire.NewTxOut(int64(ticketPrice), pkScript)) - tx.AddTxOut(wire.NewTxOut(0, commitScript)) - tx.AddTxOut(wire.NewTxOut(int64(change), changeScript)) + tx.AddTxOut(newTxOut(int64(ticketPrice), voteScriptVer, voteScript)) + tx.AddTxOut(newTxOut(0, commitScriptVer, commitScript)) + tx.AddTxOut(newTxOut(int64(change), changeScriptVer, changeScript)) return tx } -// CreateTreasuryTAdd creates a new transaction that spends the provided output -// to the treasury. If the amount minus fee is zero the returned transaction -// does not have a change output. +// CreateTreasuryTAddChange creates a new transaction that spends the provided +// output to the treasury. If the amount minus fee is zero the returned +// transaction does not have a change output. // // The transaction consists of the following outputs: // - First output is an OP_TADD // - Second output is optional and when used it is an OP_SSTXCHANGE paying to // the provided changeAddr func (g *Generator) CreateTreasuryTAddChange(spend *SpendableOut, - amount, fee dcrutil.Amount, changeAddr dcrutil.Address) *wire.MsgTx { + amount, fee dcrutil.Amount, changeAddr stdaddr.StakeAddress) *wire.MsgTx { // Calculate change and generate script to deliver it. - var ( - changeScript []byte - err error - ) + var changeScriptVer uint16 + var changeScript []byte change := spend.amount - amount - fee if change < 0 { panic(fmt.Sprintf("negative change %v", change)) } if change > 0 { - changeScript, err = txscript.PayToSStxChange(changeAddr) - if err != nil { - panic(err) - } + changeScriptVer, changeScript = changeAddr.StakeChangeScript() } // Generate and return the transaction spending from the provided @@ -576,10 +540,9 @@ func (g *Generator) CreateTreasuryTAddChange(spend *SpendableOut, BlockIndex: spend.blockIndex, SignatureScript: opTrueRedeemScript, }) - tx.AddTxOut(wire.NewTxOut(int64(amount), - []byte{txscript.OP_TADD})) + tx.AddTxOut(wire.NewTxOut(int64(amount), []byte{txscript.OP_TADD})) if len(changeScript) > 0 { - tx.AddTxOut(wire.NewTxOut(int64(change), changeScript)) + tx.AddTxOut(newTxOut(int64(change), changeScriptVer, changeScript)) } return tx } @@ -593,7 +556,7 @@ func (g *Generator) CreateTreasuryTAdd(spend *SpendableOut, amount, fee dcrutil. // AddressAmountTuple wraps address+amount in a tuple for easy parameter // passing. type AddressAmountTuple struct { - Address dcrutil.Address + Address stdaddr.Address Amount dcrutil.Amount } @@ -624,13 +587,7 @@ func (g *Generator) CreateTreasuryTSpend(privKey []byte, payouts []AddressAmount if err != nil { panic(err) } - builder := txscript.NewScriptBuilder() - builder.AddOp(txscript.OP_RETURN) - builder.AddData(payload[:]) - opretScript, err := builder.Script() - if err != nil { - panic(err) - } + opretScript := opReturnScript(payload[:]) msgTx := wire.NewMsgTx() msgTx.Version = wire.TxVersionTreasury msgTx.Expiry = expiry @@ -638,18 +595,15 @@ func (g *Generator) CreateTreasuryTSpend(privKey []byte, payouts []AddressAmount // OP_TGEN for _, v := range payouts { - addr := g.p2shOpTrueAddr + addr := g.p2shOpTrueAddr.(stdaddr.Address) if v.Address != nil { addr = v.Address } - script, err := txscript.PayToAddrScript(addr) - if err != nil { - panic(err) - } + scriptVer, script := addr.PaymentScript() tgenScript := make([]byte, len(script)+1) tgenScript[0] = txscript.OP_TGEN copy(tgenScript[1:], script) - msgTx.AddTxOut(wire.NewTxOut(int64(v.Amount), tgenScript)) + msgTx.AddTxOut(newTxOut(int64(v.Amount), scriptVer, tgenScript)) } // Treasury spend transactions have no inputs since the funds are @@ -799,10 +753,7 @@ func (g *Generator) CreateVoteTx(voteBlock *wire.MsgBlock, ticketTx *wire.MsgTx, // The third and subsequent outputs pay the original commitment amounts // along with the appropriate portion of the vote subsidy. This impl // uses the standard pay-to-script-hash to an OP_TRUE. - stakeGenScript, err := txscript.PayToSSGen(g.p2shOpTrueAddr) - if err != nil { - panic(err) - } + genScriptVer, genScript := g.p2shOpTrueAddr.PayVoteCommitmentScript() // Generate and return the transaction with the proof-of-stake subsidy // coinbase and spending from the provided ticket along with the @@ -829,7 +780,7 @@ func (g *Generator) CreateVoteTx(voteBlock *wire.MsgBlock, ticketTx *wire.MsgTx, }) tx.AddTxOut(wire.NewTxOut(0, blockScript)) tx.AddTxOut(wire.NewTxOut(0, voteScript)) - tx.AddTxOut(wire.NewTxOut(int64(voteSubsidy+ticketPrice), stakeGenScript)) + tx.AddTxOut(newTxOut(int64(voteSubsidy+ticketPrice), genScriptVer, genScript)) return tx } @@ -851,10 +802,7 @@ func (g *Generator) createVoteTxFromTicket(voteBlock *wire.MsgBlock, ticket *sta func (g *Generator) CreateRevocationTx(ticketTx *wire.MsgTx, ticketBlockHeight, ticketBlockIndex uint32) *wire.MsgTx { // The outputs pay the original commitment amounts. This impl uses the // standard pay-to-script-hash to an OP_TRUE. - revokeScript, err := txscript.PayToSSRtx(g.p2shOpTrueAddr) - if err != nil { - panic(err) - } + revokeScrVer, revokeScript := g.p2shOpTrueAddr.PayRevokeCommitmentScript() // Generate and return the transaction spending from the provided ticket // along with the previously described outputs. @@ -870,7 +818,7 @@ func (g *Generator) CreateRevocationTx(ticketTx *wire.MsgTx, ticketBlockHeight, BlockIndex: ticketBlockIndex, SignatureScript: opTrueRedeemScript, }) - tx.AddTxOut(wire.NewTxOut(ticketPrice, revokeScript)) + tx.AddTxOut(newTxOut(ticketPrice, revokeScrVer, revokeScript)) return tx } @@ -1773,8 +1721,7 @@ func (g *Generator) CreateSpendTx(spend *SpendableOut, fee dcrutil.Amount) *wire BlockIndex: spend.blockIndex, SignatureScript: opTrueRedeemScript, }) - spendTx.AddTxOut(wire.NewTxOut(int64(spend.amount-fee), - g.p2shOpTrueScript)) + spendTx.AddTxOut(wire.NewTxOut(int64(spend.amount-fee), g.p2shOpTrueScript)) spendTx.AddTxOut(wire.NewTxOut(0, UniqueOpReturnScript())) return spendTx } diff --git a/blockchain/fullblocktests/generate.go b/blockchain/fullblocktests/generate.go index 3e6a01fe73..64ea868c2e 100644 --- a/blockchain/fullblocktests/generate.go +++ b/blockchain/fullblocktests/generate.go @@ -1,5 +1,5 @@ // Copyright (c) 2016 The btcsuite developers -// Copyright (c) 2016-2020 The Decred developers +// Copyright (c) 2016-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -20,6 +20,7 @@ import ( "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -41,11 +42,6 @@ const ( // whether or not to approve the previous block. voteBitNo = 0x0000 voteBitYes = 0x0001 - - // noTreasury signifies the treasury agenda should be treated as though - // it is inactive. It is used to increase the readability of the - // tests. - noTreasury = false ) var ( @@ -158,7 +154,7 @@ func (b RejectedNonCanonicalBlock) FullBlockTestInstance() {} // payToScriptHashScript returns a standard pay-to-script-hash for the provided // redeem script. func payToScriptHashScript(redeemScript []byte) []byte { - redeemScriptHash := dcrutil.Hash160(redeemScript) + redeemScriptHash := stdaddr.Hash160(redeemScript) script, err := txscript.NewScriptBuilder(). AddOp(txscript.OP_HASH160).AddData(redeemScriptHash). AddOp(txscript.OP_EQUAL).Script() @@ -825,21 +821,15 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) { g.SetTip("bf6") g.NextBlock("bbadtaxscript", outs[4], ticketOuts[4], func(b *wire.MsgBlock) { - taxOutput := b.Transactions[0].TxOut[0] - _, addrs, _, _ := txscript.ExtractPkScriptAddrs( - g.Params().OrganizationPkScriptVersion, - taxOutput.PkScript, g.Params(), noTreasury) - p2shTaxAddr := addrs[0].(*dcrutil.AddressScriptHash) - p2pkhTaxAddr, err := dcrutil.NewAddressPubKeyHash( - p2shTaxAddr.Hash160()[:], g.Params(), - dcrec.STEcdsaSecp256k1) - if err != nil { - panic(err) - } - p2pkhScript, err := txscript.PayToAddrScript(p2pkhTaxAddr) + h160 := g.Params().OrganizationPkScript[2:22] + p2pkhTaxAddr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + h160, g.Params()) if err != nil { panic(err) } + p2pkhScriptVer, p2pkhScript := p2pkhTaxAddr.PaymentScript() + taxOutput := b.Transactions[0].TxOut[0] + taxOutput.Version = p2pkhScriptVer taxOutput.PkScript = p2pkhScript }) rejected(blockchain.ErrNoTax) @@ -1280,12 +1270,12 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) { // \-> bv15(9) g.SetTip("bsl5") g.NextBlock("bv15", outs[9], ticketOuts[9], func(b *wire.MsgBlock) { - ticketFee := dcrutil.Amount(2) - ticketPrice := dcrutil.Amount(g.CalcNextReqStakeDifficulty(g.Tip())) + ticketFee := int64(2) + ticketPrice := g.CalcNextReqStakeDifficulty(g.Tip()) ticketPrice-- - b.STransactions[5].TxOut[1].PkScript = - chaingen.PurchaseCommitmentScript(g.P2shOpTrueAddr(), - ticketPrice+ticketFee, 0, ticketPrice) + commitTxOut := b.STransactions[5].TxOut[1] + commitTxOut.Version, commitTxOut.PkScript = g.P2shOpTrueAddr(). + RewardCommitmentScript(ticketPrice+ticketFee, 0, ticketPrice) }) rejected(blockchain.ErrTicketCommitment) diff --git a/blockchain/go.mod b/blockchain/go.mod index fe0aca00e7..070d57e580 100644 --- a/blockchain/go.mod +++ b/blockchain/go.mod @@ -13,7 +13,7 @@ require ( github.com/decred/dcrd/dcrutil/v4 v4.0.0-20210129181600-6ae0142d3b28 github.com/decred/dcrd/gcs/v3 v3.0.0-20210129195202-a4265d63b619 github.com/decred/dcrd/lru v1.1.0 - github.com/decred/dcrd/txscript/v4 v4.0.0-20210129190127-4ebd135a82f1 + github.com/decred/dcrd/txscript/v4 v4.0.0-20210330065944-a2366e6e0b3b github.com/decred/dcrd/wire v1.4.0 github.com/decred/slog v1.1.0 ) diff --git a/blockchain/indexers/addrindex.go b/blockchain/indexers/addrindex.go index bf84ea23d1..2495101695 100644 --- a/blockchain/indexers/addrindex.go +++ b/blockchain/indexers/addrindex.go @@ -1,5 +1,5 @@ // Copyright (c) 2016 The btcsuite developers -// Copyright (c) 2016-2020 The Decred developers +// Copyright (c) 2016-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -15,9 +15,9 @@ import ( "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/chaincfg/v3" "github.com/decred/dcrd/database/v2" - "github.com/decred/dcrd/dcrec" "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -533,49 +533,35 @@ func dbRemoveAddrIndexEntries(bucket internalBucket, addrKey [addrKeySize]byte, // addrToKey converts known address types to an addrindex key. An error is // returned for unsupported types. -func addrToKey(addr dcrutil.Address) ([addrKeySize]byte, error) { - switch addr := addr.(type) { - case *dcrutil.AddressPubKeyHash: - switch addr.DSA() { - case dcrec.STEcdsaSecp256k1: - var result [addrKeySize]byte - result[0] = addrKeyTypePubKeyHash - copy(result[1:], addr.Hash160()[:]) - return result, nil - case dcrec.STEd25519: - var result [addrKeySize]byte - result[0] = addrKeyTypePubKeyHashEdwards - copy(result[1:], addr.Hash160()[:]) - return result, nil - case dcrec.STSchnorrSecp256k1: - var result [addrKeySize]byte - result[0] = addrKeyTypePubKeyHashSchnorr - copy(result[1:], addr.Hash160()[:]) - return result, nil - } +func addrToKey(addr stdaddr.Address) ([addrKeySize]byte, error) { + // Convert public key addresses to public key hash variants. + if addrPKH, ok := addr.(stdaddr.AddressPubKeyHasher); ok { + addr = addrPKH.AddressPubKeyHash() + } - case *dcrutil.AddressScriptHash: + switch addr := addr.(type) { + case *stdaddr.AddressPubKeyHashEcdsaSecp256k1V0: var result [addrKeySize]byte - result[0] = addrKeyTypeScriptHash + result[0] = addrKeyTypePubKeyHash copy(result[1:], addr.Hash160()[:]) return result, nil - case *dcrutil.AddressSecpPubKey: + case *stdaddr.AddressPubKeyHashEd25519V0: var result [addrKeySize]byte - result[0] = addrKeyTypePubKeyHash - copy(result[1:], addr.AddressPubKeyHash().Hash160()[:]) + result[0] = addrKeyTypePubKeyHashEdwards + copy(result[1:], addr.Hash160()[:]) return result, nil - case *dcrutil.AddressEdwardsPubKey: + case *stdaddr.AddressPubKeyHashSchnorrSecp256k1V0: var result [addrKeySize]byte - result[0] = addrKeyTypePubKeyHashEdwards - copy(result[1:], addr.AddressPubKeyHash().Hash160()[:]) + result[0] = addrKeyTypePubKeyHashSchnorr + copy(result[1:], addr.Hash160()[:]) return result, nil - case *dcrutil.AddressSecSchnorrPubKey: + case *stdaddr.AddressScriptHashV0: var result [addrKeySize]byte - result[0] = addrKeyTypePubKeyHashSchnorr - copy(result[1:], addr.AddressPubKeyHash().Hash160()[:]) + result[0] = addrKeyTypeScriptHash + copy(result[1:], addr.Hash160()[:]) return result, nil } @@ -897,7 +883,7 @@ func (idx *AddrIndex) DisconnectBlock(dbTx database.Tx, block, parent *dcrutil.B // that involve a given address. // // This function is safe for concurrent access. -func (idx *AddrIndex) EntriesForAddress(dbTx database.Tx, addr dcrutil.Address, numToSkip, numRequested uint32, reverse bool) ([]TxIndexEntry, uint32, error) { +func (idx *AddrIndex) EntriesForAddress(dbTx database.Tx, addr stdaddr.Address, numToSkip, numRequested uint32, reverse bool) ([]TxIndexEntry, uint32, error) { addrKey, err := addrToKey(addr) if err != nil { return nil, 0, err @@ -933,8 +919,8 @@ func (idx *AddrIndex) indexUnconfirmedAddresses(scriptVersion uint16, pkScript [ // The error is ignored here since the only reason it can fail is if the // script fails to parse and it was already validated before being // admitted to the mempool. - class, addresses, _, _ := txscript.ExtractPkScriptAddrs(scriptVersion, - pkScript, idx.chainParams, isTreasuryEnabled) + class, addrs, _, _ := txscript.ExtractPkScriptAddrs(scriptVersion, pkScript, + idx.chainParams, isTreasuryEnabled) if isSStx && class == txscript.NullDataTy { addr, err := stake.AddrFromSStxPkScrCommitment(pkScript, idx.chainParams) @@ -943,10 +929,10 @@ func (idx *AddrIndex) indexUnconfirmedAddresses(scriptVersion uint16, pkScript [ return } - addresses = append(addresses, addr) + addrs = append(addrs, addr) } - for _, addr := range addresses { + for _, addr := range addrs { // Ignore unsupported address types. addrKey, err := addrToKey(addr) if err != nil { @@ -1042,7 +1028,7 @@ func (idx *AddrIndex) RemoveUnconfirmedTx(hash *chainhash.Hash) { // Unsupported address types are ignored and will result in no results. // // This function is safe for concurrent access. -func (idx *AddrIndex) UnconfirmedTxnsForAddress(addr dcrutil.Address) []*dcrutil.Tx { +func (idx *AddrIndex) UnconfirmedTxnsForAddress(addr stdaddr.Address) []*dcrutil.Tx { // Ignore unsupported address types. addrKey, err := addrToKey(addr) if err != nil { diff --git a/blockchain/indexers/existsaddrindex.go b/blockchain/indexers/existsaddrindex.go index f421901165..ed2f982e13 100644 --- a/blockchain/indexers/existsaddrindex.go +++ b/blockchain/indexers/existsaddrindex.go @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Decred developers +// Copyright (c) 2016-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -13,6 +13,7 @@ import ( "github.com/decred/dcrd/database/v2" "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -144,7 +145,7 @@ func (idx *ExistsAddrIndex) existsAddress(bucket internalBucket, k [addrKeySize] // ExistsAddress is the concurrency safe, exported function that returns // whether or not an address has been seen before. -func (idx *ExistsAddrIndex) ExistsAddress(addr dcrutil.Address) (bool, error) { +func (idx *ExistsAddrIndex) ExistsAddress(addr stdaddr.Address) (bool, error) { k, err := addrToKey(addr) if err != nil { return false, err @@ -174,7 +175,7 @@ func (idx *ExistsAddrIndex) ExistsAddress(addr dcrutil.Address) (bool, error) { // ExistsAddresses is the concurrency safe, exported function that returns // whether or not each address in a slice of addresses has been seen before. -func (idx *ExistsAddrIndex) ExistsAddresses(addrs []dcrutil.Address) ([]bool, error) { +func (idx *ExistsAddrIndex) ExistsAddresses(addrs []stdaddr.Address) ([]bool, error) { exists := make([]bool, len(addrs)) addrKeys := make([][addrKeySize]byte, len(addrs)) for i := range addrKeys { @@ -244,8 +245,7 @@ func (idx *ExistsAddrIndex) ConnectBlock(dbTx database.Tx, block, parent *dcruti rs := txscript.MultisigRedeemScriptFromScriptSig( txIn.SignatureScript) class, addrs, _, err := txscript.ExtractPkScriptAddrs( - scriptVersion, rs, idx.chainParams, - isTreasuryEnabled) + scriptVersion, rs, idx.chainParams, isTreasuryEnabled) if err != nil { // Non-standard outputs are skipped. continue @@ -267,9 +267,8 @@ func (idx *ExistsAddrIndex) ConnectBlock(dbTx database.Tx, block, parent *dcruti } for _, txOut := range tx.MsgTx().TxOut { - class, addrs, _, err := txscript.ExtractPkScriptAddrs( - txOut.Version, txOut.PkScript, idx.chainParams, - isTreasuryEnabled) + class, addrs, _, err := txscript.ExtractPkScriptAddrs(txOut.Version, + txOut.PkScript, idx.chainParams, isTreasuryEnabled) if err != nil { // Non-standard outputs are skipped. continue @@ -364,9 +363,8 @@ func (idx *ExistsAddrIndex) addUnconfirmedTx(tx *wire.MsgTx, isTreasuryEnabled b const scriptVersion = 0 rs := txscript.MultisigRedeemScriptFromScriptSig( txIn.SignatureScript) - class, addrs, _, err := txscript.ExtractPkScriptAddrs( - scriptVersion, rs, idx.chainParams, - isTreasuryEnabled) + class, addrs, _, err := txscript.ExtractPkScriptAddrs(scriptVersion, + rs, idx.chainParams, isTreasuryEnabled) if err != nil { // Non-standard outputs are skipped. continue diff --git a/blockchain/stake/go.mod b/blockchain/stake/go.mod index ce2053a2e7..31cf94e64f 100644 --- a/blockchain/stake/go.mod +++ b/blockchain/stake/go.mod @@ -6,10 +6,9 @@ require ( github.com/decred/dcrd/chaincfg/chainhash v1.0.2 github.com/decred/dcrd/chaincfg/v3 v3.0.0 github.com/decred/dcrd/database/v2 v2.0.3-0.20210129190127-4ebd135a82f1 - github.com/decred/dcrd/dcrec v1.0.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210127014238-b33b46cf1a24 github.com/decred/dcrd/dcrutil/v4 v4.0.0-20210129181600-6ae0142d3b28 - github.com/decred/dcrd/txscript/v4 v4.0.0-20210129190127-4ebd135a82f1 + github.com/decred/dcrd/txscript/v4 v4.0.0-20210330065944-a2366e6e0b3b github.com/decred/dcrd/wire v1.4.0 github.com/decred/slog v1.1.0 ) diff --git a/blockchain/stake/scripttype_test.go b/blockchain/stake/scripttype_test.go index 773d7be1b3..4c96f53222 100644 --- a/blockchain/stake/scripttype_test.go +++ b/blockchain/stake/scripttype_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Decred developers +// Copyright (c) 2020-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -7,12 +7,12 @@ package stake import ( "testing" - "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" ) var ( - hash160 = dcrutil.Hash160([]byte("test")) + hash160 = stdaddr.Hash160([]byte("test")) ) func TestIsRevocationScript(t *testing.T) { diff --git a/blockchain/stake/staketx.go b/blockchain/stake/staketx.go index 1184bb19c0..4b0510ac85 100644 --- a/blockchain/stake/staketx.go +++ b/blockchain/stake/staketx.go @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. // @@ -15,9 +15,9 @@ import ( "math/big" "github.com/decred/dcrd/chaincfg/chainhash" - "github.com/decred/dcrd/dcrec" "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -395,7 +395,7 @@ func TxSStxStakeOutputInfo(tx *wire.MsgTx) ([]bool, [][]byte, []int64, []int64, // AddrFromSStxPkScrCommitment extracts a P2SH or P2PKH address from a ticket // commitment pkScript. -func AddrFromSStxPkScrCommitment(pkScript []byte, params dcrutil.AddressParams) (dcrutil.Address, error) { +func AddrFromSStxPkScrCommitment(pkScript []byte, params stdaddr.AddressParams) (stdaddr.Address, error) { if len(pkScript) < SStxPKHMinOutSize { str := "short read of sstx commit pkscript" return nil, stakeRuleError(ErrSStxBadCommitAmount, str) @@ -417,10 +417,9 @@ func AddrFromSStxPkScrCommitment(pkScript []byte, params dcrutil.AddressParams) // Return the correct address type. if isP2SH { - return dcrutil.NewAddressScriptHashFromHash(hashBytes, params) + return stdaddr.NewAddressScriptHashV0FromHash(hashBytes, params) } - return dcrutil.NewAddressPubKeyHash(hashBytes, params, - dcrec.STEcdsaSecp256k1) + return stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(hashBytes, params) } // AmountFromSStxPkScrCommitment extracts a commitment amount from a diff --git a/blockchain/stake/staketx_test.go b/blockchain/stake/staketx_test.go index 24eca653fc..c82d85c085 100644 --- a/blockchain/stake/staketx_test.go +++ b/blockchain/stake/staketx_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -14,6 +14,7 @@ import ( "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -1260,7 +1261,7 @@ func TestGetStakeRewards(t *testing.T) { } func TestIsNullDataScript(t *testing.T) { - var hash160 = dcrutil.Hash160([]byte("test")) + var hash160 = stdaddr.Hash160([]byte("test")) var overMaxDataCarrierSize = make([]byte, txscript.MaxDataCarrierSize+1) var underMaxDataCarrierSize = make([]byte, txscript.MaxDataCarrierSize/2) rand.Read(overMaxDataCarrierSize) diff --git a/blockchain/stake/treasury_test.go b/blockchain/stake/treasury_test.go index c5324d9178..e8ef3c474d 100644 --- a/blockchain/stake/treasury_test.go +++ b/blockchain/stake/treasury_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Decred developers +// Copyright (c) 2020-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -14,10 +14,10 @@ import ( "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/chaincfg/v3" - "github.com/decred/dcrd/dcrec" "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -162,6 +162,15 @@ var ( // panic("x") //} +// newTxOut returns a new transaction output with the given parameters. +func newTxOut(amount int64, pkScriptVer uint16, pkScript []byte) *wire.TxOut { + return &wire.TxOut{ + Value: amount, + Version: pkScriptVer, + PkScript: pkScript, + } +} + // TestTreasuryIsFunctions goes through all valid treasury opcode combinations. func TestTreasuryIsFunctions(t *testing.T) { tests := []struct { @@ -264,17 +273,15 @@ func TestTreasuryIsFunctions(t *testing.T) { msgTx.Version = wire.TxVersionTreasury msgTx.AddTxOut(wire.NewTxOut(0, script)) - p2shOpTrueAddr, err := dcrutil.NewAddressScriptHash([]byte{txscript.OP_TRUE}, + opTrueScript := []byte{txscript.OP_TRUE} + p2shOpTrueAddr, err := stdaddr.NewAddressScriptHashV0(opTrueScript, chaincfg.MainNetParams()) if err != nil { panic(err) } - changeScript, err := txscript.PayToSStxChange(p2shOpTrueAddr) - if err != nil { - panic(err) - } - msgTx.AddTxOut(wire.NewTxOut(1, changeScript)) - msgTx.AddTxIn(&wire.TxIn{}) // On input required + changeScriptVer, changeScript := p2shOpTrueAddr.StakeChangeScript() + msgTx.AddTxOut(newTxOut(1, changeScriptVer, changeScript)) + msgTx.AddTxIn(&wire.TxIn{}) // One input required return msgTx }, is: IsTAdd, @@ -392,19 +399,14 @@ func TestTreasuryIsFunctions(t *testing.T) { msgTx.AddTxOut(wire.NewTxOut(0, opretScript)) // OP_TGEN - p2shOpTrueAddr, err := dcrutil.NewAddressScriptHash([]byte{txscript.OP_TRUE}, + opTrueScript := []byte{txscript.OP_TRUE} + p2shOpTrueAddr, err := stdaddr.NewAddressScriptHashV0(opTrueScript, chaincfg.MainNetParams()) if err != nil { panic(err) } - p2shOpTrueScript, err := txscript.PayToAddrScript(p2shOpTrueAddr) - if err != nil { - panic(err) - } - script := make([]byte, len(p2shOpTrueScript)+1) - script[0] = txscript.OP_TGEN - copy(script[1:], p2shOpTrueScript) - msgTx.AddTxOut(wire.NewTxOut(0, script)) + genScriptVer, genScript := p2shOpTrueAddr.PayFromTreasuryScript() + msgTx.AddTxOut(newTxOut(0, genScriptVer, genScript)) // tspend builder = txscript.NewScriptBuilder() @@ -456,19 +458,16 @@ func TestTreasuryIsFunctions(t *testing.T) { // OP_TGEN privKey := secp256k1.NewPrivateKey(new(secp256k1.ModNScalar).SetInt(1)) pubKey := privKey.PubKey().SerializeCompressed() - p2pkhAddr, err := dcrutil.NewAddressSecpPubKey(pubKey, + p2pkAddr, err := stdaddr.NewAddressPubKeyEcdsaSecp256k1V0Raw(pubKey, chaincfg.MainNetParams()) if err != nil { panic(err) } - p2pkhOpTrueScript, err := txscript.PayToAddrScript(p2pkhAddr) - if err != nil { - panic(err) - } - script := make([]byte, len(p2pkhOpTrueScript)+1) + p2pkScriptVer, p2pkScript := p2pkAddr.PaymentScript() + script := make([]byte, len(p2pkScript)+1) script[0] = txscript.OP_TGEN - copy(script[1:], p2pkhOpTrueScript) - msgTx.AddTxOut(wire.NewTxOut(0, script)) + copy(script[1:], p2pkScript) + msgTx.AddTxOut(newTxOut(0, p2pkScriptVer, script)) // tspend builder = txscript.NewScriptBuilder() @@ -520,21 +519,14 @@ func TestTreasuryIsFunctions(t *testing.T) { // OP_TGEN privKey := secp256k1.NewPrivateKey(new(secp256k1.ModNScalar).SetInt(1)) pubKey := privKey.PubKey() - pkHash := dcrutil.Hash160(pubKey.SerializeCompressed()) - p2pkhAddr, err := dcrutil.NewAddressPubKeyHash(pkHash, - chaincfg.MainNetParams(), dcrec.STEcdsaSecp256k1) - + pkHash := stdaddr.Hash160(pubKey.SerializeCompressed()) + p2pkhAddr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + pkHash, chaincfg.MainNetParams()) if err != nil { panic(err) } - p2shOpTrueScript, err := txscript.PayToAddrScript(p2pkhAddr) - if err != nil { - panic(err) - } - script := make([]byte, len(p2shOpTrueScript)+1) - script[0] = txscript.OP_TGEN - copy(script[1:], p2shOpTrueScript) - msgTx.AddTxOut(wire.NewTxOut(0, script)) + genScriptVer, genScript := p2pkhAddr.PayFromTreasuryScript() + msgTx.AddTxOut(newTxOut(0, genScriptVer, genScript)) // tspend builder = txscript.NewScriptBuilder() diff --git a/blockchain/stakeext.go b/blockchain/stakeext.go index 19b7166a86..8c6948a554 100644 --- a/blockchain/stakeext.go +++ b/blockchain/stakeext.go @@ -10,6 +10,7 @@ import ( "github.com/decred/dcrd/database/v2" "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -101,13 +102,14 @@ func (b *BlockChain) MissedTickets() ([]chainhash.Hash, error) { // corresponding to the given address. // // This function is safe for concurrent access. -func (b *BlockChain) TicketsWithAddress(address dcrutil.Address, isTreasuryEnabled bool) ([]chainhash.Hash, error) { +func (b *BlockChain) TicketsWithAddress(address stdaddr.Address, isTreasuryEnabled bool) ([]chainhash.Hash, error) { b.chainLock.RLock() sn := b.bestChain.Tip().stakeNode b.chainLock.RUnlock() tickets := sn.LiveTickets() + encodedAddr := address.Address() var ticketsWithAddr []chainhash.Hash err := b.db.View(func(dbTx database.Tx) error { for _, hash := range tickets { @@ -122,7 +124,7 @@ func (b *BlockChain) TicketsWithAddress(address dcrutil.Address, isTreasuryEnabl if err != nil { return err } - if addrs[0].Address() == address.Address() { + if addrs[0].Address() == encodedAddr { ticketsWithAddr = append(ticketsWithAddr, hash) } } diff --git a/blockchain/treasury_test.go b/blockchain/treasury_test.go index e7d825af2a..46b0305a87 100644 --- a/blockchain/treasury_test.go +++ b/blockchain/treasury_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Decred developers +// Copyright (c) 2020-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -27,6 +27,7 @@ import ( "github.com/decred/dcrd/gcs/v3/blockcf2" "github.com/decred/dcrd/lru" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -1873,14 +1874,14 @@ func TestSpendableTreasuryTxs(t *testing.T) { // mining these txs. spendPrivKey := secp256k1.NewPrivateKey(new(secp256k1.ModNScalar).SetInt(1)) pubKey := spendPrivKey.PubKey().SerializeCompressed() - pubKeyHash := dcrutil.Hash160(pubKey) - spendP2pkhAddr, err := dcrutil.NewAddressPubKeyHash(pubKeyHash, params, - dcrec.STEcdsaSecp256k1) + pubKeyHash := stdaddr.Hash160(pubKey) + spendP2pkhAddr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + pubKeyHash, params) if err != nil { t.Fatal(err) } spendP2shScript := []byte{txscript.OP_NOP, txscript.OP_TRUE} - spendP2shAddr, err := dcrutil.NewAddressScriptHash(spendP2shScript, + spendP2shAddr, err := stdaddr.NewAddressScriptHashV0(spendP2shScript, params) if err != nil { t.Fatal(err) @@ -1888,14 +1889,14 @@ func TestSpendableTreasuryTxs(t *testing.T) { addPrivKey := secp256k1.NewPrivateKey(new(secp256k1.ModNScalar).SetInt(2)) pubKey = addPrivKey.PubKey().SerializeCompressed() - pubKeyHash = dcrutil.Hash160(pubKey) - addP2pkhAddr, err := dcrutil.NewAddressPubKeyHash(pubKeyHash, params, - dcrec.STEcdsaSecp256k1) + pubKeyHash = stdaddr.Hash160(pubKey) + addP2pkhAddr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + pubKeyHash, params) if err != nil { t.Fatal(err) } addP2shScript := []byte{txscript.OP_NOP, txscript.OP_NOP, txscript.OP_TRUE} - addP2shAddr, err := dcrutil.NewAddressScriptHash(addP2shScript, params) + addP2shAddr, err := stdaddr.NewAddressScriptHashV0(addP2shScript, params) if err != nil { t.Fatal(err) } @@ -3357,15 +3358,23 @@ func TestTreasuryBalance(t *testing.T) { } } +// newTxOut returns a new transaction output with the given parameters. +func newTxOut(amount int64, pkScriptVer uint16, pkScript []byte) *wire.TxOut { + return &wire.TxOut{ + Value: amount, + Version: pkScriptVer, + PkScript: pkScript, + } +} + func createTAdd(spend chaingen.SpendableOut, changeDivisor dcrutil.Amount, params *chaincfg.Params) func(b *wire.MsgBlock) { - p2shOpTrueAddr, err := dcrutil.NewAddressScriptHash([]byte{txscript.OP_TRUE}, - params) + redeemScript := []byte{txscript.OP_TRUE} + p2shOpTrueAddr, err := stdaddr.NewAddressScriptHashV0(redeemScript, params) if err != nil { panic(err) } return func(b *wire.MsgBlock) { - // Add TADD amount := spend.Amount() tx := wire.NewMsgTx() tx.AddTxIn(&wire.TxIn{ @@ -3374,25 +3383,20 @@ func createTAdd(spend chaingen.SpendableOut, changeDivisor dcrutil.Amount, param ValueIn: int64(amount), BlockHeight: spend.BlockHeight(), BlockIndex: spend.BlockIndex(), - SignatureScript: []byte{txscript.OP_DATA_1, - txscript.OP_TRUE}, + SignatureScript: []byte{txscript.OP_DATA_1, txscript.OP_TRUE}, }) // Add negative change. + trsyAddScript := []byte{txscript.OP_TADD} if changeDivisor != 0 { - changeScript, err := txscript.PayToSStxChange(p2shOpTrueAddr) - if err != nil { - panic(err) - } + changeScriptVer, changeScript := p2shOpTrueAddr.StakeChangeScript() change := spend.Amount() / changeDivisor amount := spend.Amount() - change - tx.AddTxOut(wire.NewTxOut(int64(amount), - []byte{txscript.OP_TADD})) - tx.AddTxOut(wire.NewTxOut(int64(change), changeScript)) + tx.AddTxOut(wire.NewTxOut(int64(amount), trsyAddScript)) + tx.AddTxOut(newTxOut(int64(change), changeScriptVer, changeScript)) } else { - tx.AddTxOut(wire.NewTxOut(int64(amount), - []byte{txscript.OP_TADD})) + tx.AddTxOut(wire.NewTxOut(int64(amount), trsyAddScript)) } tx.Version = wire.TxVersionTreasury b.AddSTransaction(tx) diff --git a/config.go b/config.go index 477684c326..056cfffd71 100644 --- a/config.go +++ b/config.go @@ -31,6 +31,7 @@ import ( "github.com/decred/dcrd/internal/version" "github.com/decred/dcrd/rpc/jsonrpc/types/v3" "github.com/decred/dcrd/sampleconfig" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/go-socks/socks" "github.com/decred/slog" flags "github.com/jessevdk/go-flags" @@ -232,7 +233,7 @@ type config struct { lookup func(string) ([]net.IP, error) oniondial func(context.Context, string, string) (net.Conn, error) dial func(context.Context, string, string) (net.Conn, error) - miningAddrs []dcrutil.Address + miningAddrs []stdaddr.Address minRelayTxFee dcrutil.Amount whitelists []*net.IPNet ipv4NetInfo types.NetworksResult @@ -1084,9 +1085,9 @@ func loadConfig(appName string) (*config, []string, error) { } // Check mining addresses are valid and saved parsed versions. - cfg.miningAddrs = make([]dcrutil.Address, 0, len(cfg.MiningAddrs)) + cfg.miningAddrs = make([]stdaddr.Address, 0, len(cfg.MiningAddrs)) for _, strAddr := range cfg.MiningAddrs { - addr, err := dcrutil.DecodeAddress(strAddr, cfg.params.Params) + addr, err := stdaddr.DecodeAddress(strAddr, cfg.params.Params) if err != nil { str := "%s: mining address '%s' failed to decode: %w" err := fmt.Errorf(str, funcName, strAddr, err) diff --git a/gcs/go.mod b/gcs/go.mod index 2265c486c9..653d40c990 100644 --- a/gcs/go.mod +++ b/gcs/go.mod @@ -7,7 +7,7 @@ require ( github.com/decred/dcrd/blockchain/stake/v4 v4.0.0-20210129192908-660d0518b4cf github.com/decred/dcrd/chaincfg/chainhash v1.0.2 github.com/decred/dcrd/crypto/blake256 v1.0.0 - github.com/decred/dcrd/txscript/v4 v4.0.0-20210129190127-4ebd135a82f1 + github.com/decred/dcrd/txscript/v4 v4.0.0-20210330065944-a2366e6e0b3b github.com/decred/dcrd/wire v1.4.0 ) diff --git a/go.mod b/go.mod index ebd8699b64..6c8e1ce363 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/decred/dcrd/peer/v3 v3.0.0 github.com/decred/dcrd/rpc/jsonrpc/types/v3 v3.0.0-20210129200153-14fd1a785bf2 github.com/decred/dcrd/rpcclient/v7 v7.0.0-20210129214723-fc227a05904d - github.com/decred/dcrd/txscript/v4 v4.0.0-20210129190127-4ebd135a82f1 + github.com/decred/dcrd/txscript/v4 v4.0.0-20210330065944-a2366e6e0b3b github.com/decred/dcrd/wire v1.4.0 github.com/decred/go-socks v1.1.0 github.com/decred/slog v1.2.0 diff --git a/hdkeychain/example_test.go b/hdkeychain/example_test.go index f7d543fab6..bd407d02b9 100644 --- a/hdkeychain/example_test.go +++ b/hdkeychain/example_test.go @@ -1,5 +1,5 @@ // Copyright (c) 2014 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -9,9 +9,8 @@ import ( "fmt" "github.com/decred/dcrd/chaincfg/v3" - "github.com/decred/dcrd/dcrec" - "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/hdkeychain/v3" + "github.com/decred/dcrd/txscript/v4/stdaddr" ) // This example demonstrates how to generate a cryptographically random seed @@ -127,9 +126,8 @@ func Example_defaultWalletLayout() { // pubKeyHashAddr is a convenience function to convert an extended // pubkey to a standard pay-to-pubkey-hash address. pubKeyHashAddr := func(extKey *hdkeychain.ExtendedKey) (string, error) { - pkHash := dcrutil.Hash160(extKey.SerializedPubKey()) - addr, err := dcrutil.NewAddressPubKeyHash(pkHash, net, - dcrec.STEcdsaSecp256k1) + pkHash := stdaddr.Hash160(extKey.SerializedPubKey()) + addr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(pkHash, net) if err != nil { fmt.Println(err) return "", err diff --git a/hdkeychain/go.mod b/hdkeychain/go.mod index 7e88bf3316..741771f161 100644 --- a/hdkeychain/go.mod +++ b/hdkeychain/go.mod @@ -7,12 +7,11 @@ require ( github.com/decred/dcrd/chaincfg/v3 v3.0.0 github.com/decred/dcrd/crypto/blake256 v1.0.0 github.com/decred/dcrd/crypto/ripemd160 v1.0.1 - github.com/decred/dcrd/dcrec v1.0.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210127014238-b33b46cf1a24 - github.com/decred/dcrd/dcrutil/v4 v4.0.0-20210129181600-6ae0142d3b28 + github.com/decred/dcrd/txscript/v4 v4.0.0-20210330065944-a2366e6e0b3b ) replace ( github.com/decred/dcrd/dcrec/secp256k1/v4 => ../dcrec/secp256k1 - github.com/decred/dcrd/dcrutil/v4 => ../dcrutil + github.com/decred/dcrd/txscript/v4 => ../txscript ) diff --git a/hdkeychain/go.sum b/hdkeychain/go.sum index f8fd4e9bce..fb2083ca73 100644 --- a/hdkeychain/go.sum +++ b/hdkeychain/go.sum @@ -2,6 +2,7 @@ github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7I github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dchest/siphash v1.2.2/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4= github.com/decred/base58 v1.0.3 h1:KGZuh8d1WEMIrK0leQRM47W85KqCAdl2N+uagbctdDI= github.com/decred/base58 v1.0.3/go.mod h1:pXP9cXCfM2sFLb2viz2FNIdeMWmZDBKG3ZBYbiSM78E= github.com/decred/dcrd/chaincfg/chainhash v1.0.2 h1:rt5Vlq/jM3ZawwiacWjPa+smINyLRN07EO0cNBV6DGU= @@ -16,5 +17,7 @@ github.com/decred/dcrd/dcrec v1.0.0 h1:W+z6Es+Rai3MXYVoPAxYr5U1DGis0Co33scJ6uH2J github.com/decred/dcrd/dcrec v1.0.0/go.mod h1:HIaqbEJQ+PDzQcORxnqen5/V1FR3B4VpIfmePklt8Q8= github.com/decred/dcrd/dcrec/edwards/v2 v2.0.1 h1:V6eqU1crZzuoFT4KG2LhaU5xDSdkHuvLQsj25wd7Wb4= github.com/decred/dcrd/dcrec/edwards/v2 v2.0.1/go.mod h1:d0H8xGMWbiIQP7gN3v2rByWUcuZPm9YsgmnfoxgbINc= +github.com/decred/dcrd/dcrutil/v4 v4.0.0-20210129181600-6ae0142d3b28/go.mod h1:xe59jKcMx5G/dbRmsZ8+FzY+WQDE/7YBP3k3uzJTtmI= github.com/decred/dcrd/wire v1.4.0 h1:KmSo6eTQIvhXS0fLBQ/l7hG7QLcSJQKSwSyzSqJYDk0= github.com/decred/dcrd/wire v1.4.0/go.mod h1:WxC/0K+cCAnBh+SKsRjIX9YPgvrjhmE+6pZlel1G7Ro= +github.com/decred/slog v1.1.0/go.mod h1:kVXlGnt6DHy2fV5OjSeuvCJ0OmlmTF6LFpEPMu/fOY0= diff --git a/internal/mempool/mempool_test.go b/internal/mempool/mempool_test.go index 7ffcac9bbc..9d254e6bec 100644 --- a/internal/mempool/mempool_test.go +++ b/internal/mempool/mempool_test.go @@ -19,7 +19,6 @@ import ( "github.com/decred/dcrd/blockchain/stake/v4" "github.com/decred/dcrd/blockchain/standalone/v2" "github.com/decred/dcrd/blockchain/v4" - "github.com/decred/dcrd/blockchain/v4/chaingen" "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/chaincfg/v3" "github.com/decred/dcrd/dcrec" @@ -27,6 +26,7 @@ import ( "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/internal/mining" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -341,9 +341,13 @@ type poolHarness struct { // // payAddr is the p2sh address for the signing key and is used for the // payment address throughout the tests. + // + // payScriptVer and payScript are the script version and script to pay the + // aforementioned payAddr. signKey []byte sigType dcrec.SignatureType - payAddr dcrutil.Address + payAddr stdaddr.StakeAddress + payScriptVer uint16 payScript []byte chainParams *chaincfg.Params treasuryActive bool @@ -355,13 +359,13 @@ type poolHarness struct { // GetScript is the pool harness' implementation of the ScriptDB interface. // It returns the pool harness' payment redeem script for any address // passed in. -func (p *poolHarness) GetScript(addr dcrutil.Address) ([]byte, error) { +func (p *poolHarness) GetScript(addr stdaddr.Address) ([]byte, error) { return p.payScript, nil } // GetKey is the pool harness' implementation of the KeyDB interface. // It returns the pool harness' signature key for any address passed in. -func (p *poolHarness) GetKey(addr dcrutil.Address) ([]byte, dcrec.SignatureType, bool, error) { +func (p *poolHarness) GetKey(addr stdaddr.Address) ([]byte, dcrec.SignatureType, bool, error) { return p.signKey, p.sigType, true, nil } @@ -527,22 +531,15 @@ func (p *poolHarness) CreateTx(out spendableOutput) (*dcrutil.Tx, error) { // CreateTicketPurchase creates a ticket purchase spending the first output of // the provided transaction. func (p *poolHarness) CreateTicketPurchase(sourceTx *dcrutil.Tx, cost int64) (*dcrutil.Tx, error) { - ticketFee := dcrutil.Amount(singleInputTicketSize) - ticketPrice := dcrutil.Amount(cost) + ticketFee := singleInputTicketSize + ticketPrice := cost - // Generate the p2sh, commitment and change scripts of the ticket. - pkScript, err := txscript.PayToSStx(p.payAddr) - if err != nil { - return nil, err - } - commitScript := chaingen.PurchaseCommitmentScript(p.payAddr, + // Generate the voting rights, commitment, and change scripts of the ticket. + voteScriptVer, voteScript := p.payAddr.VotingRightsScript() + commitScriptVer, commitScript := p.payAddr.RewardCommitmentScript( ticketPrice+ticketFee, 0, ticketPrice) - change := dcrutil.Amount(sourceTx.MsgTx().TxOut[0].Value) - - ticketPrice - ticketFee - changeScript, err := txscript.PayToSStxChange(p.payAddr) - if err != nil { - return nil, err - } + change := sourceTx.MsgTx().TxOut[0].Value - ticketPrice - ticketFee + changeScriptVer, changeScript := p.payAddr.StakeChangeScript() // Generate the ticket purchase. tx := wire.NewMsgTx() @@ -557,9 +554,9 @@ func (p *poolHarness) CreateTicketPurchase(sourceTx *dcrutil.Tx, cost int64) (*d BlockHeight: uint32(p.chain.BestHeight()), }) - tx.AddTxOut(wire.NewTxOut(int64(ticketPrice), pkScript)) - tx.AddTxOut(wire.NewTxOut(0, commitScript)) - tx.AddTxOut(wire.NewTxOut(int64(change), changeScript)) + tx.AddTxOut(newTxOut(ticketPrice, voteScriptVer, voteScript)) + tx.AddTxOut(newTxOut(0, commitScriptVer, commitScript)) + tx.AddTxOut(newTxOut(change, changeScriptVer, changeScript)) // Sign the ticket purchase. sigScript, err := txscript.SignatureScript(tx, 0, @@ -582,6 +579,15 @@ func newVoteScript(voteBits stake.VoteBits) ([]byte, error) { return txscript.GenerateProvablyPruneableOut(b) } +// newTxOut returns a new transaction output with the given parameters. +func newTxOut(amount int64, pkScriptVer uint16, pkScript []byte) *wire.TxOut { + return &wire.TxOut{ + Value: amount, + Version: pkScriptVer, + PkScript: pkScript, + } +} + // CreateVote creates a vote transaction using the provided ticket. The vote // will vote on the current best block hash and height associated with the // harness. @@ -627,15 +633,18 @@ func (p *poolHarness) CreateVote(ticket *dcrutil.Tx, mungers ...func(*wire.MsgTx } vote.AddTxOut(wire.NewTxOut(0, voteScript)) - // Create P2SH scripts for the ticket outputs. - for i, hash160 := range ticketHash160s { - scriptFn := txscript.PayToSSGenPKHDirect + // Create payment scripts for the ticket commitments. + params := p.chainParams + for i, h160 := range ticketHash160s { + var addr stdaddr.StakeAddress if ticketPayKinds[i] { // P2SH - scriptFn = txscript.PayToSSGenSHDirect + addr, _ = stdaddr.NewAddressScriptHashV0FromHash(h160, params) + } else { + addr, _ = stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(h160, params) } - // Error is checking for a nil hash160, just ignore it. - script, _ := scriptFn(hash160) - vote.AddTxOut(wire.NewTxOut(voteRewardValues[i], script)) + + scriptVer, script := addr.PayVoteCommitmentScript() + vote.AddTxOut(newTxOut(voteRewardValues[i], scriptVer, script)) } // Perform any transaction munging just before signing. @@ -679,13 +688,16 @@ func (p *poolHarness) CreateRevocation(ticket *dcrutil.Tx) (*dcrutil.Tx, error) // All remaining outputs pay to the output destinations and amounts tagged // by the ticket purchase. - for i, hash160 := range ticketHash160s { - scriptFn := txscript.PayToSSRtxPKHDirect + params := p.chainParams + for i, h160 := range ticketHash160s { + var addr stdaddr.StakeAddress if ticketPayKinds[i] { // P2SH - scriptFn = txscript.PayToSSRtxSHDirect + addr, _ = stdaddr.NewAddressScriptHashV0FromHash(h160, params) + } else { + addr, _ = stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(h160, params) } - // Error is checking for a nil hash160, just ignore it. - script, _ := scriptFn(hash160) + + _, script := addr.PayRevokeCommitmentScript() revocation.AddTxOut(wire.NewTxOut(revocationValues[i], script)) } @@ -739,16 +751,13 @@ func newPoolHarness(chainParams *chaincfg.Params) (*poolHarness, []spendableOutp // Generate associated pay-to-script-hash address and resulting payment // script. pubKeyBytes := signPub.SerializeCompressed() - payPubKeyAddr, err := dcrutil.NewAddressSecpPubKey(pubKeyBytes, + h160 := stdaddr.Hash160(pubKeyBytes) + payAddr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(h160, chainParams) if err != nil { return nil, nil, err } - payAddr := payPubKeyAddr.AddressPubKeyHash() - pkScript, err := txscript.PayToAddrScript(payAddr) - if err != nil { - return nil, nil, err - } + payScriptVer, payScript := payAddr.PaymentScript() // Create a new fake chain and harness bound to it. subsidyCache := standalone.NewSubsidyCache(chainParams) @@ -761,13 +770,13 @@ func newPoolHarness(chainParams *chaincfg.Params) (*poolHarness, []spendableOutp } var harness *poolHarness harness = &poolHarness{ - signKey: keyBytes, - sigType: dcrec.STEcdsaSecp256k1, - payAddr: payAddr, - payScript: pkScript, - chainParams: chainParams, - - chain: chain, + signKey: keyBytes, + sigType: dcrec.STEcdsaSecp256k1, + payAddr: payAddr, + payScriptVer: payScriptVer, + payScript: payScript, + chainParams: chainParams, + chain: chain, txPool: New(&Config{ Policy: Policy{ EnableAncestorTracking: true, @@ -2541,23 +2550,18 @@ func TestHandlesTSpends(t *testing.T) { // createTAdd creates a treasury add transaction spending from the given // harness output and sending back any outstanding change to the given address. func createTAdd(t *testing.T, spend *spendableOutput, payScript, signKey []byte, - amount, fee dcrutil.Amount, changeAddr dcrutil.Address) *wire.MsgTx { + amount, fee dcrutil.Amount, changeAddr stdaddr.StakeAddress) *wire.MsgTx { t.Helper() // Calculate change and generate script to deliver it. - var ( - changeScript []byte - err error - ) + var changeScriptVer uint16 + var changeScript []byte change := spend.amount - amount - fee if change < 0 { t.Fatalf("negative change %v", change) } if change > 0 { - changeScript, err = txscript.PayToSStxChange(changeAddr) - if err != nil { - t.Fatalf("unable to generate Pay2SStxChange: %v", err) - } + changeScriptVer, changeScript = changeAddr.StakeChangeScript() } // Generate and return the transaction spending from the provided @@ -2569,12 +2573,12 @@ func createTAdd(t *testing.T, spend *spendableOutput, payScript, signKey []byte, Sequence: wire.MaxTxInSequenceNum, ValueIn: int64(spend.amount), }) - tx.AddTxOut(wire.NewTxOut(int64(amount), - []byte{txscript.OP_TADD})) + tx.AddTxOut(wire.NewTxOut(int64(amount), []byte{txscript.OP_TADD})) if len(changeScript) > 0 { - tx.AddTxOut(wire.NewTxOut(int64(change), changeScript)) + tx.AddTxOut(newTxOut(int64(change), changeScriptVer, changeScript)) } + var err error tx.TxIn[0].SignatureScript, err = txscript.SignatureScript(tx, 0, payScript, txscript.SigHashAll, signKey, dcrec.STEcdsaSecp256k1, true) @@ -2603,14 +2607,14 @@ func TestHandlesTAdds(t *testing.T) { // Addresses to use in the following TAdds. addPrivKey := secp256k1.NewPrivateKey(new(secp256k1.ModNScalar).SetInt(2)) pubKey := addPrivKey.PubKey().SerializeCompressed() - pubKeyHash := dcrutil.Hash160(pubKey) - addP2pkhAddr, err := dcrutil.NewAddressPubKeyHash(pubKeyHash, net, - dcrec.STEcdsaSecp256k1) + pubKeyHash := stdaddr.Hash160(pubKey) + addP2pkhAddr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(pubKeyHash, + net) if err != nil { t.Fatal(err) } addP2shScript := []byte{txscript.OP_NOP, txscript.OP_NOP, txscript.OP_TRUE} - addP2shAddr, err := dcrutil.NewAddressScriptHash(addP2shScript, net) + addP2shAddr, err := stdaddr.NewAddressScriptHashV0(addP2shScript, net) if err != nil { t.Fatal(err) } @@ -2618,7 +2622,7 @@ func TestHandlesTAdds(t *testing.T) { // Helper to create tadds for this test without having to keep passing // repeated parameters. createTAdd := func(spend *spendableOutput, amount, fee dcrutil.Amount, - changeAddr dcrutil.Address) *dcrutil.Tx { + changeAddr stdaddr.StakeAddress) *dcrutil.Tx { t.Helper() return dcrutil.NewTx(createTAdd(t, spend, harness.payScript, harness.signKey, amount, fee, changeAddr)) diff --git a/internal/mempool/policy_test.go b/internal/mempool/policy_test.go index cf5285bddd..25393355f1 100644 --- a/internal/mempool/policy_test.go +++ b/internal/mempool/policy_test.go @@ -1,5 +1,5 @@ // Copyright (c) 2013-2016 The btcsuite developers -// Copyright (c) 2016-2020 The Decred developers +// Copyright (c) 2016-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -14,10 +14,10 @@ import ( "github.com/decred/dcrd/blockchain/stake/v4" "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/chaincfg/v3" - "github.com/decred/dcrd/dcrec" "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -326,18 +326,15 @@ func TestCheckTransactionStandard(t *testing.T) { SignatureScript: dummySigScript, } addrHash := [20]byte{0x01} - addr, err := dcrutil.NewAddressPubKeyHash(addrHash[:], - chaincfg.RegNetParams(), dcrec.STEcdsaSecp256k1) + addr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(addrHash[:], + chaincfg.RegNetParams()) if err != nil { t.Fatalf("NewAddressPubKeyHash: unexpected error: %v", err) } - dummyPkScript, err := txscript.PayToAddrScript(addr) - if err != nil { - t.Fatalf("PayToAddrScript: unexpected error: %v", err) - } + dummyPkScriptVer, dummyPkScript := addr.PaymentScript() dummyTxOut := wire.TxOut{ Value: 100000000, // 1 BTC - Version: 0, + Version: dummyPkScriptVer, PkScript: dummyPkScript, } diff --git a/internal/mining/bgblktmplgenerator.go b/internal/mining/bgblktmplgenerator.go index 3b2c239a91..d978f9c40c 100644 --- a/internal/mining/bgblktmplgenerator.go +++ b/internal/mining/bgblktmplgenerator.go @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Decred developers +// Copyright (c) 2019-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -17,6 +17,7 @@ import ( "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/lru" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -323,7 +324,7 @@ type BgBlkTmplConfig struct { // MiningAddrs specifies the addresses to choose from when paying mining // rewards in generated templates. - MiningAddrs []dcrutil.Address + MiningAddrs []stdaddr.Address // AllowUnsyncedMining indicates block templates should be created even when // the chain is not fully synced. diff --git a/internal/mining/mining.go b/internal/mining/mining.go index 3b403f370e..d7b26f3889 100644 --- a/internal/mining/mining.go +++ b/internal/mining/mining.go @@ -1,5 +1,5 @@ // Copyright (c) 2014-2016 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -21,6 +21,7 @@ import ( "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/gcs/v3/blockcf2" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -502,7 +503,7 @@ func calcBlockCommitmentRootV1(block *wire.MsgBlock, prevScripts blockcf2.PrevSc // // See the comment for NewBlockTemplate for more information about why the nil // address handling is useful. -func createCoinbaseTx(subsidyCache *standalone.SubsidyCache, coinbaseScript []byte, opReturnPkScript []byte, nextBlockHeight int64, addr dcrutil.Address, voters uint16, params *chaincfg.Params, isTreasuryEnabled bool) (*dcrutil.Tx, error) { +func createCoinbaseTx(subsidyCache *standalone.SubsidyCache, coinbaseScript []byte, opReturnPkScript []byte, nextBlockHeight int64, addr stdaddr.Address, voters uint16, params *chaincfg.Params, isTreasuryEnabled bool) (*dcrutil.Tx, error) { // Coinbase transactions have no inputs, so previous outpoint is zero hash // and max index. coinbaseInput := &wire.TxIn{ @@ -532,18 +533,6 @@ func createCoinbaseTx(subsidyCache *standalone.SubsidyCache, coinbaseScript []by return dcrutil.NewTx(tx), nil } - // Create the script to pay to the provided payment address if one was - // specified. Otherwise create a script that allows the coinbase to be - // redeemable by anyone. - workSubsidyScript := opTrueScript - if addr != nil { - var err error - workSubsidyScript, err = txscript.PayToAddrScript(addr) - if err != nil { - return nil, err - } - } - // Prior to the decentralized treasury agenda, the transaction version must // be 1 and there is an additional output that either pays to organization // associated with the treasury or a provably pruneable zero-value output @@ -578,6 +567,15 @@ func createCoinbaseTx(subsidyCache *standalone.SubsidyCache, coinbaseScript []by txVersion = wire.TxVersionTreasury } + // Create the script to pay to the provided payment address if one was + // specified. Otherwise create a script that allows the coinbase to be + // redeemable by anyone. + workSubsidyScriptVer := uint16(0) + workSubsidyScript := opTrueScript + if addr != nil { + workSubsidyScriptVer, workSubsidyScript = addr.PaymentScript() + } + // Create a coinbase with expected inputs and outputs. // // Inputs: @@ -602,6 +600,7 @@ func createCoinbaseTx(subsidyCache *standalone.SubsidyCache, coinbaseScript []by }) tx.AddTxOut(&wire.TxOut{ Value: workSubsidy, + Version: workSubsidyScriptVer, PkScript: workSubsidyScript, }) return dcrutil.NewTx(tx), nil @@ -765,7 +764,7 @@ func (g *BlkTmplGenerator) maybeInsertStakeTx(stx *dcrutil.Tx, treeValid bool, i // work off of is present, it will return a copy of that template to pass to the // miner. // Safe for concurrent access. -func (g *BlkTmplGenerator) handleTooFewVoters(nextHeight int64, miningAddress dcrutil.Address, isTreasuryEnabled bool) (*BlockTemplate, error) { +func (g *BlkTmplGenerator) handleTooFewVoters(nextHeight int64, miningAddress stdaddr.Address, isTreasuryEnabled bool) (*BlockTemplate, error) { stakeValidationHeight := g.cfg.ChainParams.StakeValidationHeight // Handle not enough voters being present if we're set to mine aggressively @@ -1010,7 +1009,7 @@ func calcFeePerKb(txDesc *TxDesc, ancestorStats *TxAncestorStats) float64 { // // This function returns nil, nil if there are not enough voters on any of // the current top blocks to create a new block template. -func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress dcrutil.Address) (*BlockTemplate, error) { +func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress stdaddr.Address) (*BlockTemplate, error) { // All transaction scripts are verified using the more strict standard // flags. scriptFlags, err := g.cfg.Policy.StandardVerifyFlags() diff --git a/internal/mining/mining_harness_test.go b/internal/mining/mining_harness_test.go index c92697cad8..9167bc4635 100644 --- a/internal/mining/mining_harness_test.go +++ b/internal/mining/mining_harness_test.go @@ -14,13 +14,13 @@ import ( "github.com/decred/dcrd/blockchain/stake/v4" "github.com/decred/dcrd/blockchain/standalone/v2" "github.com/decred/dcrd/blockchain/v4" - "github.com/decred/dcrd/blockchain/v4/chaingen" "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/chaincfg/v3" "github.com/decred/dcrd/dcrec" "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -918,10 +918,14 @@ type miningHarness struct { // // payAddr is the p2sh address for the signing key and is used for the // payment address throughout the tests. - signKey []byte - sigType dcrec.SignatureType - payAddr dcrutil.Address - payScript []byte + // + // payScriptVer and payScript are the script version and script to pay the + // aforementioned payAddr. + signKey []byte + sigType dcrec.SignatureType + payAddr stdaddr.StakeAddress + payScriptVer uint16 + payScript []byte generator *BlkTmplGenerator } @@ -929,13 +933,13 @@ type miningHarness struct { // GetScript is the mining harness' implementation of the ScriptDB interface. // It returns the mining harness' payment redeem script for any address passed // in. -func (m *miningHarness) GetScript(addr dcrutil.Address) ([]byte, error) { +func (m *miningHarness) GetScript(addr stdaddr.Address) ([]byte, error) { return m.payScript, nil } // GetKey is the mining harness' implementation of the KeyDB interface. It // returns the mining harness' signature key for any address passed in. -func (m *miningHarness) GetKey(addr dcrutil.Address) ([]byte, dcrec.SignatureType, bool, error) { +func (m *miningHarness) GetKey(addr stdaddr.Address) ([]byte, dcrec.SignatureType, bool, error) { return m.signKey, m.sigType, true, nil } @@ -971,10 +975,7 @@ func (m *miningHarness) CreateCoinbaseTx(blockHeight int64, numOutputs uint32) ( if i == numOutputs-1 { amount = amountPerOutput + remainder } - tx.AddTxOut(&wire.TxOut{ - PkScript: m.payScript, - Value: amount, - }) + tx.AddTxOut(newTxOut(amount, m.payScriptVer, m.payScript)) } return dcrutil.NewTx(tx), nil @@ -998,10 +999,8 @@ func (m *miningHarness) CreateTxChain(firstOutput spendableOutput, numTxns uint3 Sequence: wire.MaxTxInSequenceNum, ValueIn: int64(spendableAmount), }) - tx.AddTxOut(&wire.TxOut{ - PkScript: m.payScript, - Value: int64(spendableAmount), - }) + tx.AddTxOut(newTxOut(int64(spendableAmount), m.payScriptVer, + m.payScript)) // Sign the new transaction. sigScript, err := txscript.SignatureScript(tx, 0, @@ -1067,10 +1066,7 @@ func (m *miningHarness) CreateSignedTx(inputs []spendableOutput, numOutputs uint if i == numOutputs-1 { amount += remainder } - tx.AddTxOut(&wire.TxOut{ - PkScript: m.payScript, - Value: amount, - }) + tx.AddTxOut(newTxOut(amount, m.payScriptVer, m.payScript)) } // Perform any transaction munging just before signing. @@ -1092,25 +1088,27 @@ func (m *miningHarness) CreateSignedTx(inputs []spendableOutput, numOutputs uint return dcrutil.NewTx(tx), nil } +// newTxOut returns a new transaction output with the given parameters. +func newTxOut(amount int64, pkScriptVer uint16, pkScript []byte) *wire.TxOut { + return &wire.TxOut{ + Value: amount, + Version: pkScriptVer, + PkScript: pkScript, + } +} + // CreateTicketPurchase creates a ticket purchase spending the first output of // the provided transaction. func (m *miningHarness) CreateTicketPurchase(sourceTx *dcrutil.Tx, cost int64) (*dcrutil.Tx, error) { - ticketFee := dcrutil.Amount(singleInputTicketSize) - ticketPrice := dcrutil.Amount(cost) + ticketFee := singleInputTicketSize + ticketPrice := cost - // Generate the p2sh, commitment and change scripts of the ticket. - pkScript, err := txscript.PayToSStx(m.payAddr) - if err != nil { - return nil, err - } - commitScript := chaingen.PurchaseCommitmentScript(m.payAddr, + // Generate the voting rights, commitment, and change scripts of the ticket. + voteScriptVer, voteScript := m.payAddr.VotingRightsScript() + commitScriptVer, commitScript := m.payAddr.RewardCommitmentScript( ticketPrice+ticketFee, 0, ticketPrice) - change := dcrutil.Amount(sourceTx.MsgTx().TxOut[0].Value) - - ticketPrice - ticketFee - changeScript, err := txscript.PayToSStxChange(m.payAddr) - if err != nil { - return nil, err - } + change := sourceTx.MsgTx().TxOut[0].Value - ticketPrice - ticketFee + changeScriptVer, changeScript := m.payAddr.StakeChangeScript() // Generate the ticket purchase. tx := wire.NewMsgTx() @@ -1125,9 +1123,9 @@ func (m *miningHarness) CreateTicketPurchase(sourceTx *dcrutil.Tx, cost int64) ( BlockHeight: uint32(m.generator.cfg.BestSnapshot().Height), }) - tx.AddTxOut(wire.NewTxOut(int64(ticketPrice), pkScript)) - tx.AddTxOut(wire.NewTxOut(0, commitScript)) - tx.AddTxOut(wire.NewTxOut(int64(change), changeScript)) + tx.AddTxOut(newTxOut(ticketPrice, voteScriptVer, voteScript)) + tx.AddTxOut(newTxOut(0, commitScriptVer, commitScript)) + tx.AddTxOut(newTxOut(change, changeScriptVer, changeScript)) // Sign the ticket purchase. sigScript, err := txscript.SignatureScript(tx, 0, @@ -1195,14 +1193,17 @@ func (m *miningHarness) CreateVote(ticket *dcrutil.Tx, mungers ...func(*wire.Msg } vote.AddTxOut(wire.NewTxOut(0, voteScript)) - // Create P2SH scripts for the ticket outputs. - for i, hash160 := range ticketHash160s { - scriptFn := txscript.PayToSSGenPKHDirect + // Create payment scripts for the ticket commitments. + params := m.chainParams + for i, h160 := range ticketHash160s { + var addr stdaddr.StakeAddress if ticketPayKinds[i] { // P2SH - scriptFn = txscript.PayToSSGenSHDirect + addr, _ = stdaddr.NewAddressScriptHashV0FromHash(h160, params) + } else { + addr, _ = stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(h160, params) } - // Error is checking for a nil hash160, just ignore it. - script, _ := scriptFn(hash160) + + _, script := addr.PayVoteCommitmentScript() vote.AddTxOut(wire.NewTxOut(voteRewardValues[i], script)) } @@ -1214,14 +1215,14 @@ func (m *miningHarness) CreateVote(ticket *dcrutil.Tx, mungers ...func(*wire.Msg // Sign the input. inputToSign := 1 redeemTicketScript := ticket.MsgTx().TxOut[0].PkScript - signedScript, err := txscript.SignTxOutput(m.chainParams, vote, - inputToSign, redeemTicketScript, txscript.SigHashAll, m, m, + signedScript, err := txscript.SignTxOutput(params, vote, inputToSign, + redeemTicketScript, txscript.SigHashAll, m, m, vote.TxIn[inputToSign].SignatureScript, m.chain.isTreasuryAgendaActive) if err != nil { return nil, err } - vote.TxIn[0].SignatureScript = m.chainParams.StakeBaseSigScript + vote.TxIn[0].SignatureScript = params.StakeBaseSigScript vote.TxIn[1].SignatureScript = signedScript return dcrutil.NewTx(vote), nil @@ -1272,15 +1273,13 @@ func newMiningHarness(chainParams *chaincfg.Params) (*miningHarness, []spendable // Generate associated pay-to-script-hash address and resulting payment // script. pubKeyBytes := signPub.SerializeCompressed() - payPubKeyAddr, err := dcrutil.NewAddressSecpPubKey(pubKeyBytes, chainParams) - if err != nil { - return nil, nil, err - } - payAddr := payPubKeyAddr.AddressPubKeyHash() - pkScript, err := txscript.PayToAddrScript(payAddr) + h160 := stdaddr.Hash160(pubKeyBytes) + payAddr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(h160, + chainParams) if err != nil { return nil, nil, err } + payScriptVer, payScript := payAddr.PaymentScript() // Create a SigCache instance. sigCache, err := txscript.NewSigCache(1000) @@ -1367,7 +1366,8 @@ func newMiningHarness(chainParams *chaincfg.Params) (*miningHarness, []spendable signKey: keyBytes, sigType: dcrec.STEcdsaSecp256k1, payAddr: payAddr, - payScript: pkScript, + payScriptVer: payScriptVer, + payScript: payScript, generator: NewBlkTmplGenerator(&Config{ Policy: policy, TxSource: txSource, diff --git a/internal/mining/mining_test.go b/internal/mining/mining_test.go index 741e6e0802..4b04e67a94 100644 --- a/internal/mining/mining_test.go +++ b/internal/mining/mining_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Decred developers +// Copyright (c) 2020-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -13,6 +13,7 @@ import ( "github.com/decred/dcrd/chaincfg/v3" "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -28,7 +29,7 @@ func TestNewBlockTemplateBasicErrorScenarios(t *testing.T) { } // Create a test address for use in template generation. - address, err := dcrutil.DecodeAddress("Dsi8CRt85xYyempXs7ZPL1rBxvDdAGZmgsg", + address, err := stdaddr.DecodeAddress("Dsi8CRt85xYyempXs7ZPL1rBxvDdAGZmgsg", harness.chainParams) if err != nil { t.Fatalf("error decoding address: %v", err) @@ -70,7 +71,7 @@ func TestNewBlockTemplate(t *testing.T) { } // Create a test address for use in template generation. - address, err := dcrutil.DecodeAddress("Dsi8CRt85xYyempXs7ZPL1rBxvDdAGZmgsg", + address, err := stdaddr.DecodeAddress("Dsi8CRt85xYyempXs7ZPL1rBxvDdAGZmgsg", harness.chainParams) if err != nil { t.Fatalf("error decoding address: %v", err) diff --git a/internal/rpcserver/interface.go b/internal/rpcserver/interface.go index 5b8cc0800d..e0c4b250d4 100644 --- a/internal/rpcserver/interface.go +++ b/internal/rpcserver/interface.go @@ -22,6 +22,7 @@ import ( "github.com/decred/dcrd/internal/mining" "github.com/decred/dcrd/peer/v3" "github.com/decred/dcrd/rpc/jsonrpc/types/v3" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -372,7 +373,7 @@ type Chain interface { // TicketsWithAddress returns a slice of ticket hashes that are currently // live corresponding to the given address. - TicketsWithAddress(address dcrutil.Address, isTreasuryEnabled bool) ([]chainhash.Hash, error) + TicketsWithAddress(address stdaddr.Address, isTreasuryEnabled bool) ([]chainhash.Hash, error) // TipGeneration returns the entire generation of blocks stemming from the // parent of the current tip. @@ -552,11 +553,11 @@ type FiltererV2 interface { // ExistsAddresser before calling methods associated with it. type ExistsAddresser interface { // ExistsAddress returns whether or not an address has been seen before. - ExistsAddress(addr dcrutil.Address) (bool, error) + ExistsAddress(addr stdaddr.Address) (bool, error) // ExistsAddresses returns whether or not each address in a slice of // addresses has been seen before. - ExistsAddresses(addrs []dcrutil.Address) ([]bool, error) + ExistsAddresses(addrs []stdaddr.Address) ([]bool, error) } // TxMempooler represents a source of mempool transaction data for the RPC @@ -607,13 +608,13 @@ type AddrIndexer interface { // NOTE: These results only include transactions confirmed in blocks. See the // UnconfirmedTxnsForAddress method for obtaining unconfirmed transactions // that involve a given address. - EntriesForAddress(dbTx database.Tx, addr dcrutil.Address, numToSkip, + EntriesForAddress(dbTx database.Tx, addr stdaddr.Address, numToSkip, numRequested uint32, reverse bool) ([]indexers.TxIndexEntry, uint32, error) // UnconfirmedTxnsForAddress returns all transactions currently in the // unconfirmed (memory-only) address index that involve the passed address. // Unsupported address types are ignored and will result in no results. - UnconfirmedTxnsForAddress(addr dcrutil.Address) []*dcrutil.Tx + UnconfirmedTxnsForAddress(addr stdaddr.Address) []*dcrutil.Tx } // TxIndexer provides an interface for retrieving details for a given diff --git a/internal/rpcserver/rpcserver.go b/internal/rpcserver/rpcserver.go index 8843b38ab7..75d005ab70 100644 --- a/internal/rpcserver/rpcserver.go +++ b/internal/rpcserver/rpcserver.go @@ -50,6 +50,7 @@ import ( "github.com/decred/dcrd/internal/version" "github.com/decred/dcrd/rpc/jsonrpc/types/v3" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" "github.com/jrick/bitset" ) @@ -634,6 +635,15 @@ func (s *Server) messageToHex(msg wire.Message) (string, error) { return hex.EncodeToString(buf.Bytes()), nil } +// newTxOut returns a new transaction output with the given parameters. +func newTxOut(amount int64, pkScriptVer uint16, pkScript []byte) *wire.TxOut { + return &wire.TxOut{ + Value: amount, + Version: pkScriptVer, + PkScript: pkScript, + } +} + // handleCreateRawTransaction handles createrawtransaction commands. func handleCreateRawTransaction(_ context.Context, s *Server, cmd interface{}) (interface{}, error) { c := cmd.(*types.CreateRawTransactionCmd) @@ -699,28 +709,19 @@ func handleCreateRawTransaction(_ context.Context, s *Server, cmd interface{}) ( // Decode the provided address. This also ensures the network encoded // with the address matches the network the server is currently on. - addr, err := dcrutil.DecodeAddress(encodedAddr, s.cfg.ChainParams) + addr, err := stdaddr.DecodeAddress(encodedAddr, s.cfg.ChainParams) if err != nil { return nil, rpcAddressKeyError("Could not decode address: %v", err) } // Ensure the address is one of the supported types. - switch addr.(type) { - case *dcrutil.AddressPubKeyHash: - case *dcrutil.AddressScriptHash: - default: + if _, ok := addr.(stdaddr.StakeAddress); !ok { return nil, rpcAddressKeyError("Invalid type: %T", addr) } // Create a new script which pays to the provided address. - pkScript, err := txscript.PayToAddrScript(addr) - if err != nil { - return nil, rpcInternalError(err.Error(), - "Pay to address script") - } - - txOut := wire.NewTxOut(int64(atoms), pkScript) - mtx.AddTxOut(txOut) + pkScriptVer, pkScript := addr.PaymentScript() + mtx.AddTxOut(newTxOut(int64(atoms), pkScriptVer, pkScript)) } // Set the Locktime, if given. @@ -793,30 +794,20 @@ func handleCreateRawSStx(_ context.Context, s *Server, cmd interface{}) (interfa // Decode the provided address. This also ensures the network encoded // with the address matches the network the server is currently on. - addr, err := dcrutil.DecodeAddress(encodedAddr, s.cfg.ChainParams) + addr, err := stdaddr.DecodeAddress(encodedAddr, s.cfg.ChainParams) if err != nil { return nil, rpcAddressKeyError("Could not decode address: %v", err) } // Ensure the address is one of the supported types. - switch addr.(type) { - case *dcrutil.AddressPubKeyHash: - case *dcrutil.AddressScriptHash: - default: - return nil, rpcAddressKeyError("Invalid address type: "+ - "%T", addr) + stakeAddr, ok := addr.(stdaddr.StakeAddress) + if !ok { + return nil, rpcAddressKeyError("Invalid address type: %T", addr) } - // Create a new script which pays to the provided address with an - // SStx tagged output. - pkScript, err := txscript.PayToSStx(addr) - if err != nil { - return nil, rpcInternalError(err.Error(), - "Could not create TX script") - } - - txOut := wire.NewTxOut(amount, pkScript) - mtx.AddTxOut(txOut) + // Create the necessary voting rights script. + pkScriptVer, pkScript := stakeAddr.VotingRightsScript() + mtx.AddTxOut(newTxOut(amount, pkScriptVer, pkScript)) amtTicket += amount } @@ -854,32 +845,25 @@ func handleCreateRawSStx(_ context.Context, s *Server, cmd interface{}) (interfa // Append future commitment output. This also ensures the network // encoded with the address matches the network the server is currently // on. - addr, err := dcrutil.DecodeAddress(cout.Addr, s.cfg.ChainParams) + addr, err := stdaddr.DecodeAddress(cout.Addr, s.cfg.ChainParams) if err != nil { return nil, rpcAddressKeyError("Could not decode address: %v", err) } // Ensure the address is one of the supported types. - switch addr.(type) { - case *dcrutil.AddressPubKeyHash: - break - case *dcrutil.AddressScriptHash: - break - default: + stakeAddr, ok := addr.(stdaddr.StakeAddress) + if !ok { return nil, rpcAddressKeyError("Invalid type: %T", addr) } - // Create an OP_RETURN push containing the pubkeyhash to send - // rewards to. TODO Replace 0x0000 fee limits with an argument - // passed to the RPC call. - pkScript, err := txscript.GenerateSStxAddrPush(addr, - dcrutil.Amount(amountsCommitted[i]), 0x0000) - if err != nil { - return nil, rpcInternalError(err.Error(), - "Could not create SStx script") - } - txout := wire.NewTxOut(int64(0), pkScript) - mtx.AddTxOut(txout) + // Create the reward commitment script. + // + // TODO: Allow fee limits to be specified with an argument. + const voteFeeLimit = 0 + const revokeFeeLimit = 0 + cmtScriptVer, cmtScript := stakeAddr.RewardCommitmentScript( + amountsCommitted[i], voteFeeLimit, revokeFeeLimit) + mtx.AddTxOut(newTxOut(0, cmtScriptVer, cmtScript)) // 2. Append change output. @@ -891,34 +875,21 @@ func handleCreateRawSStx(_ context.Context, s *Server, cmd interface{}) (interfa // Decode the provided address. This also ensures the network encoded // with the address matches the network the server is currently on. - addr, err = dcrutil.DecodeAddress(cout.ChangeAddr, s.cfg.ChainParams) + addr, err = stdaddr.DecodeAddress(cout.ChangeAddr, s.cfg.ChainParams) if err != nil { return nil, rpcAddressKeyError("Wrong network: %v", addr) } - // Ensure the address is one of the supported types and that - // the network encoded with the address matches the network the - // server is currently on. - switch addr.(type) { - case *dcrutil.AddressPubKeyHash: - break - case *dcrutil.AddressScriptHash: - break - default: + // Ensure the address is one of the supported types. + stakeAddr, ok = addr.(stdaddr.StakeAddress) + if !ok { return nil, rpcAddressKeyError("Invalid type: %T", addr) } - // Create a new script which pays to the provided address with - // an SStx change tagged output. - pkScript, err = txscript.PayToSStxChange(addr) - if err != nil { - return nil, rpcInternalError(err.Error(), - "Could not create SStx change script") - } - - txOut := wire.NewTxOut(cout.ChangeAmt, pkScript) - mtx.AddTxOut(txOut) + // Create a new script which pays change to the provided address. + changeScriptVer, changeScript := stakeAddr.StakeChangeScript() + mtx.AddTxOut(newTxOut(cout.ChangeAmt, changeScriptVer, changeScript)) } // Make sure we generated a valid SStx. @@ -1028,17 +999,21 @@ func handleCreateRawSSRtx(_ context.Context, s *Server, cmd interface{}) (interf var ssrtxOutScript []byte switch ssrtxPayTypes[i] { case false: // P2PKH - ssrtxOutScript, err = txscript.PayToSSRtxPKHDirect(ssrtxPkh) + addr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(ssrtxPkh, + s.cfg.ChainParams) if err != nil { return nil, rpcInvalidError("Could not "+ "generate P2PKH script: %v", err) } + _, ssrtxOutScript = addr.PayRevokeCommitmentScript() case true: // P2SH - ssrtxOutScript, err = txscript.PayToSSRtxSHDirect(ssrtxPkh) + addr, err := stdaddr.NewAddressScriptHashV0FromHash(ssrtxPkh, + s.cfg.ChainParams) if err != nil { return nil, rpcInvalidError("Could not "+ "generate P2SH script: %v", err) } + _, ssrtxOutScript = addr.PayRevokeCommitmentScript() } // Add the txout to our SSGen tx. @@ -1179,7 +1154,7 @@ func createVoutList(mtx *wire.MsgTx, chainParams *chaincfg.Params, filterAddrMap // the case of stake submission transactions, the odd outputs // contain a commitment address, so detect that case // accordingly. - var addrs []dcrutil.Address + var addrs []stdaddr.Address var scriptClass string var reqSigs int var commitAmt *dcrutil.Amount @@ -1192,7 +1167,7 @@ func createVoutList(mtx *wire.MsgTx, chainParams *chaincfg.Params, filterAddrMap "commitment addr output for tx hash "+ "%v, output idx %v", mtx.TxHash(), i) } else { - addrs = []dcrutil.Address{addr} + addrs = []stdaddr.Address{addr} } amt, err := stake.AmountFromSStxPkScrCommitment(v.PkScript) if err != nil { @@ -1207,9 +1182,8 @@ func createVoutList(mtx *wire.MsgTx, chainParams *chaincfg.Params, filterAddrMap // couldn't parse and there is no additional information // about it anyways. var sc txscript.ScriptClass - sc, addrs, reqSigs, _ = txscript.ExtractPkScriptAddrs( - v.Version, v.PkScript, chainParams, - isTreasuryEnabled) + sc, addrs, reqSigs, _ = txscript.ExtractPkScriptAddrs(v.Version, + v.PkScript, chainParams, isTreasuryEnabled) scriptClass = sc.String() } @@ -1372,11 +1346,15 @@ func handleDecodeScript(_ context.Context, s *Server, cmd interface{}) (interfac scriptVersion, script, s.cfg.ChainParams, isTreasuryEnabled) addresses := make([]string, len(addrs)) for i, addr := range addrs { + if pkHasher, ok := addr.(stdaddr.AddressPubKeyHasher); ok { + addr = pkHasher.AddressPubKeyHash() + } addresses[i] = addr.Address() } // Convert the script itself to a pay-to-script-hash address. - p2sh, err := dcrutil.NewAddressScriptHash(script, s.cfg.ChainParams) + p2sh, err := stdaddr.NewAddressScriptHash(scriptVersion, script, + s.cfg.ChainParams) if err != nil { return nil, rpcInternalError(err.Error(), "Failed to convert script to pay-to-script-hash") @@ -1511,7 +1489,7 @@ func handleExistsAddress(_ context.Context, s *Server, cmd interface{}) (interfa // Decode the provided address. This also ensures the network encoded with // the address matches the network the server is currently on. - addr, err := dcrutil.DecodeAddress(c.Address, s.cfg.ChainParams) + addr, err := stdaddr.DecodeAddress(c.Address, s.cfg.ChainParams) if err != nil { return nil, rpcAddressKeyError("Could not decode address: %v", err) @@ -1536,11 +1514,11 @@ func handleExistsAddresses(_ context.Context, s *Server, cmd interface{}) (inter } c := cmd.(*types.ExistsAddressesCmd) - addresses := make([]dcrutil.Address, len(c.Addresses)) + addresses := make([]stdaddr.Address, len(c.Addresses)) for i := range c.Addresses { // Decode the provided address. This also ensures the network encoded // with the address matches the network the server is currently on. - addr, err := dcrutil.DecodeAddress(c.Addresses[i], s.cfg.ChainParams) + addr, err := stdaddr.DecodeAddress(c.Addresses[i], s.cfg.ChainParams) if err != nil { return nil, rpcAddressKeyError("Could not decode address: %v", err) } @@ -4306,7 +4284,7 @@ func createVinListPrevOut(s *Server, mtx *wire.MsgTx, // fetchMempoolTxnsForAddress queries the address index for all unconfirmed // transactions that involve the provided address. The results will be limited // by the number to skip and the number requested. -func fetchMempoolTxnsForAddress(s *Server, addr dcrutil.Address, numToSkip, numRequested uint32) ([]*dcrutil.Tx, uint32) { +func fetchMempoolTxnsForAddress(s *Server, addr stdaddr.Address, numToSkip, numRequested uint32) ([]*dcrutil.Tx, uint32) { // There are no entries to return when there are less available than // the number being skipped. mpTxns := s.cfg.AddrIndexer.UnconfirmedTxnsForAddress(addr) @@ -4351,7 +4329,7 @@ func handleSearchRawTransactions(_ context.Context, s *Server, cmd interface{}) // Attempt to decode the supplied address. This also ensures the network // encoded with the address matches the network the server is currently on. - addr, err := dcrutil.DecodeAddress(c.Address, s.cfg.ChainParams) + addr, err := stdaddr.DecodeAddress(c.Address, s.cfg.ChainParams) if err != nil { return nil, rpcAddressKeyError("Could not decode address: %v", err) @@ -5075,7 +5053,7 @@ func handleTicketsForAddress(_ context.Context, s *Server, cmd interface{}) (int // Decode the provided address. This also ensures the network encoded // with the address matches the network the server is currently on. - addr, err := dcrutil.DecodeAddress(c.Address, s.cfg.ChainParams) + addr, err := stdaddr.DecodeAddress(c.Address, s.cfg.ChainParams) if err != nil { return nil, rpcInvalidError("Invalid address: %v", err) } @@ -5253,7 +5231,7 @@ func handleTxFeeInfo(_ context.Context, s *Server, cmd interface{}) (interface{} func handleValidateAddress(_ context.Context, s *Server, cmd interface{}) (interface{}, error) { c := cmd.(*types.ValidateAddressCmd) result := types.ValidateAddressChainResult{} - addr, err := dcrutil.DecodeAddress(c.Address, s.cfg.ChainParams) + addr, err := stdaddr.DecodeAddress(c.Address, s.cfg.ChainParams) if err != nil { // Return the default value (false) for IsValid. return result, nil @@ -5320,14 +5298,15 @@ func handleVerifyMessage(_ context.Context, s *Server, cmd interface{}) (interfa // Decode the provided address. This also ensures the network encoded with // the address matches the network the server is currently on. - addr, err := dcrutil.DecodeAddress(c.Address, s.cfg.ChainParams) + params := s.cfg.ChainParams + addr, err := stdaddr.DecodeAddress(c.Address, params) if err != nil { return nil, rpcAddressKeyError("Could not decode address: %v", err) } - // Only P2PKH addresses are valid for signing. - if _, ok := addr.(*dcrutil.AddressPubKeyHash); !ok { + // Only version 0 P2PKH addresses are valid for signing. + if _, ok := addr.(*stdaddr.AddressPubKeyHashEcdsaSecp256k1V0); !ok { return nil, &dcrjson.RPCError{ Code: dcrjson.ErrRPCType, Message: "Address is not a pay-to-pubkey-hash address", @@ -5349,27 +5328,22 @@ func handleVerifyMessage(_ context.Context, s *Server, cmd interface{}) (interfa wire.WriteVarString(&buf, 0, "Decred Signed Message:\n") wire.WriteVarString(&buf, 0, c.Message) expectedMessageHash := chainhash.HashB(buf.Bytes()) - pk, wasCompressed, err := ecdsa.RecoverCompact(sig, - expectedMessageHash) + pk, wasCompressed, err := ecdsa.RecoverCompact(sig, expectedMessageHash) if err != nil { - // Mirror Bitcoin Core behavior, which treats error in - // RecoverCompact as invalid signature. + // Treat errors in RecoverCompact as an invalid signature. return false, nil } // Reconstruct the pubkey hash. - dcrPK := pk - var serializedPK []byte + var pkHash []byte if wasCompressed { - serializedPK = dcrPK.SerializeCompressed() + pkHash = stdaddr.Hash160(pk.SerializeCompressed()) } else { - serializedPK = dcrPK.SerializeUncompressed() + pkHash = stdaddr.Hash160(pk.SerializeUncompressed()) } - address, err := dcrutil.NewAddressSecpPubKey(serializedPK, - s.cfg.ChainParams) + address, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(pkHash, params) if err != nil { - // Again mirror Bitcoin Core behavior, which treats error in - // public key reconstruction as invalid signature. + // Treat error in reconstruction as an invalid signature. return false, nil } @@ -6219,7 +6193,7 @@ type Config struct { TestNet bool // MiningAddrs is a list of payment addresses to use for the generated blocks. - MiningAddrs []dcrutil.Address + MiningAddrs []stdaddr.Address // AllowUnsyncedMining indicates whether block templates should be created even // when the chain is not fully synced. diff --git a/internal/rpcserver/rpcserverhandlers_test.go b/internal/rpcserver/rpcserverhandlers_test.go index ec92c9e77a..8e58b7b7b1 100644 --- a/internal/rpcserver/rpcserverhandlers_test.go +++ b/internal/rpcserver/rpcserverhandlers_test.go @@ -44,6 +44,7 @@ import ( "github.com/decred/dcrd/peer/v3" "github.com/decred/dcrd/rpc/jsonrpc/types/v3" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -392,7 +393,7 @@ func (c *testRPCChain) TicketPoolValue() (dcrutil.Amount, error) { // TicketsWithAddress returns a mocked slice of ticket hashes that are currently // live corresponding to the given address. -func (c *testRPCChain) TicketsWithAddress(address dcrutil.Address, isTreasuryEnabled bool) ([]chainhash.Hash, error) { +func (c *testRPCChain) TicketsWithAddress(address stdaddr.Address, isTreasuryEnabled bool) ([]chainhash.Hash, error) { return c.ticketsWithAddress, c.ticketsWithAddressErr } @@ -547,13 +548,13 @@ type testExistsAddresser struct { // ExistsAddress returns a mocked bool representing whether or not an address // has been seen before. -func (e *testExistsAddresser) ExistsAddress(addr dcrutil.Address) (bool, error) { +func (e *testExistsAddresser) ExistsAddress(addr stdaddr.Address) (bool, error) { return e.existsAddress, e.existsAddressErr } // ExistsAddresses returns a mocked bool slice representing whether or not each // address in a slice of addresses has been seen before. -func (e *testExistsAddresser) ExistsAddresses(addrs []dcrutil.Address) ([]bool, error) { +func (e *testExistsAddresser) ExistsAddresses(addrs []stdaddr.Address) ([]bool, error) { return e.existsAddresses, e.existsAddressesErr } @@ -569,14 +570,14 @@ type testAddrIndexer struct { // EntriesForAddress returns a mocked slice of indexers.TxIndexEntry that // involve the given address. func (a *testAddrIndexer) EntriesForAddress(dbTx database.Tx, - addr dcrutil.Address, numToSkip, numRequested uint32, reverse bool) ( + addr stdaddr.Address, numToSkip, numRequested uint32, reverse bool) ( []indexers.TxIndexEntry, uint32, error) { return a.entriesForAddress, a.entriesForAddressSkipped, a.entriesForAddressErr } // UnconfirmedTxnsForAddress returns a mocked slice of transactions that are // currently in the unconfirmed (memory-only) address index. -func (a *testAddrIndexer) UnconfirmedTxnsForAddress(addr dcrutil.Address) []*dcrutil.Tx { +func (a *testAddrIndexer) UnconfirmedTxnsForAddress(addr stdaddr.Address) []*dcrutil.Tx { return a.unconfirmedTxnsForAddress } @@ -940,7 +941,7 @@ func (f *testFiltererV2) FilterByBlockHash(hash *chainhash.Hash) (*gcs.FilterV2, // testMiningState provides a mock mining state. type testMiningState struct { allowUnsyncedMining bool - miningAddrs []dcrutil.Address + miningAddrs []stdaddr.Address workState *workState } @@ -1317,7 +1318,7 @@ type rpcTest struct { mockLogManager *testLogManager mockFiltererV2 *testFiltererV2 mockTxMempooler *testTxMempooler - mockMiningAddrs []dcrutil.Address + mockMiningAddrs []stdaddr.Address mockHelpCacher *testHelpCacher result interface{} wantErr bool @@ -1968,7 +1969,7 @@ func TestHandleCreateRawSStx(t *testing.T) { COuts: defaultCmdCOuts, }, wantErr: true, - errCode: dcrjson.ErrRPCInternal.Code, + errCode: dcrjson.ErrRPCInvalidAddressOrKey, }, { name: "handleCreateRawSStx: change amount greater than input amount", handler: handleCreateRawSStx, @@ -2028,7 +2029,7 @@ func TestHandleCreateRawSStx(t *testing.T) { }}, }, wantErr: true, - errCode: dcrjson.ErrRPCInternal.Code, + errCode: dcrjson.ErrRPCInvalidAddressOrKey, }, { name: "handleCreateRawSStx: invalid change amount > dcrutil.MaxAmount", handler: handleCreateRawSStx, @@ -2108,7 +2109,7 @@ func TestHandleCreateRawSStx(t *testing.T) { }}, }, wantErr: true, - errCode: dcrjson.ErrRPCInternal.Code, + errCode: dcrjson.ErrRPCInvalidAddressOrKey, }}) } @@ -3312,11 +3313,11 @@ func TestHandleGenerate(t *testing.T) { hashStrTwo := "00000000000000001a1ec2becd0dd90bfbd0c65f42fdaf608dd9ceac2a3aee1d" generatedBlocks := []*chainhash.Hash{mustParseHash(hashStrOne), mustParseHash(hashStrTwo)} res := []string{hashStrOne, hashStrTwo} - miningAddr, err := dcrutil.DecodeAddress("DcurAwesomeAddressmqDctW5wJCW1Cn2MF", defaultChainParams) + miningAddr, err := stdaddr.DecodeAddress("DcurAwesomeAddressmqDctW5wJCW1Cn2MF", defaultChainParams) if err != nil { t.Fatalf("[DecodeAddress] unexpected error: %v", err) } - miningAddrs := []dcrutil.Address{miningAddr} + miningAddrs := []stdaddr.Address{miningAddr} chainParams := cloneParams(defaultChainParams) chainParams.GenerateSupported = true cpu := defaultMockCPUMiner() @@ -5994,14 +5995,14 @@ func TestHandleGetWork(t *testing.T) { buf.Write(submissionB[240:]) invalidPOWSub := buf.String() - miningaddr, err := dcrutil.DecodeAddress("DsRM6qwzT3r85evKvDBJBviTgYcaLKL4ipD", defaultChainParams) + miningaddr, err := stdaddr.DecodeAddress("DsRM6qwzT3r85evKvDBJBviTgYcaLKL4ipD", defaultChainParams) if err != nil { t.Fatalf("[DecodeAddress] unexpected error: %v", err) } mine := func() *testMiningState { ms := defaultMockMiningState() - ms.miningAddrs = []dcrutil.Address{miningaddr} + ms.miningAddrs = []stdaddr.Address{miningaddr} return ms } @@ -6127,7 +6128,7 @@ func TestHandleGetWork(t *testing.T) { }, mockMiningState: func() *testMiningState { ms := defaultMockMiningState() - ms.miningAddrs = []dcrutil.Address{miningaddr} + ms.miningAddrs = []stdaddr.Address{miningaddr} ms.workState = newWorkState() return ms }(), @@ -6209,7 +6210,7 @@ func TestHandleSetGenerate(t *testing.T) { procLimit := 2 zeroProcLimit := 0 - miningaddr, err := dcrutil.DecodeAddress("DsRM6qwzT3r85evKvDBJBviTgYcaLKL4ipD", defaultChainParams) + miningaddr, err := stdaddr.DecodeAddress("DsRM6qwzT3r85evKvDBJBviTgYcaLKL4ipD", defaultChainParams) if err != nil { t.Fatalf("[DecodeAddress] unexpected error: %v", err) } @@ -6232,7 +6233,7 @@ func TestHandleSetGenerate(t *testing.T) { }, mockMiningState: func() *testMiningState { ms := defaultMockMiningState() - ms.miningAddrs = []dcrutil.Address{miningaddr} + ms.miningAddrs = []stdaddr.Address{miningaddr} return ms }(), }, { diff --git a/internal/rpcserver/rpcwebsocket.go b/internal/rpcserver/rpcwebsocket.go index 5c70c3c6fe..4bce4fdf09 100644 --- a/internal/rpcserver/rpcwebsocket.go +++ b/internal/rpcserver/rpcwebsocket.go @@ -1,5 +1,5 @@ // Copyright (c) 2013-2016 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -33,6 +33,7 @@ import ( "github.com/decred/dcrd/internal/mining" "github.com/decred/dcrd/rpc/jsonrpc/types/v3" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -302,7 +303,7 @@ type wsClientFilter struct { mu sync.Mutex // Parameter for address decoding. - params dcrutil.AddressParams + params stdaddr.AddressParams // Implemented fast paths for address lookup. pubKeyHashes map[[ripemd160.Size]byte]struct{} @@ -318,7 +319,7 @@ type wsClientFilter struct { unspent map[wire.OutPoint]struct{} } -func makeWSClientFilter(addresses []string, unspentOutPoints []*wire.OutPoint, params dcrutil.AddressParams) *wsClientFilter { +func makeWSClientFilter(addresses []string, unspentOutPoints []*wire.OutPoint, params stdaddr.AddressParams) *wsClientFilter { filter := &wsClientFilter{ params: params, pubKeyHashes: map[[ripemd160.Size]byte]struct{}{}, @@ -338,16 +339,16 @@ func makeWSClientFilter(addresses []string, unspentOutPoints []*wire.OutPoint, p return filter } -func (f *wsClientFilter) addAddress(a dcrutil.Address) { +func (f *wsClientFilter) addAddress(a stdaddr.Address) { switch a := a.(type) { - case *dcrutil.AddressPubKeyHash: + case *stdaddr.AddressPubKeyHashEcdsaSecp256k1V0: f.pubKeyHashes[*a.Hash160()] = struct{}{} return - case *dcrutil.AddressScriptHash: + case *stdaddr.AddressScriptHashV0: f.scriptHashes[*a.Hash160()] = struct{}{} return - case *dcrutil.AddressSecpPubKey: - serializedPubKey := a.ScriptAddress() + case *stdaddr.AddressPubKeyEcdsaSecp256k1V0: + serializedPubKey := a.SerializedPubKey() switch len(serializedPubKey) { case 33: // compressed var compressedPubKey [33]byte @@ -361,33 +362,34 @@ func (f *wsClientFilter) addAddress(a dcrutil.Address) { } func (f *wsClientFilter) addAddressStr(s string) { - a, err := dcrutil.DecodeAddress(s, f.params) - // If address can't be decoded, no point in saving it since it should also - // impossible to create the address from an inspected transaction output - // script. + a, err := stdaddr.DecodeAddress(s, f.params) if err != nil { + // There is no point in saving the address if it can't be decoded since + // it should also be impossible to create the address from an inspected + // transaction output script. return } f.addAddress(a) } -func (f *wsClientFilter) existsAddress(a dcrutil.Address) bool { +func (f *wsClientFilter) existsAddress(a stdaddr.Address) bool { switch a := a.(type) { - case *dcrutil.AddressPubKeyHash: + case *stdaddr.AddressPubKeyHashEcdsaSecp256k1V0: _, ok := f.pubKeyHashes[*a.Hash160()] return ok - case *dcrutil.AddressScriptHash: + case *stdaddr.AddressScriptHashV0: _, ok := f.scriptHashes[*a.Hash160()] return ok - case *dcrutil.AddressSecpPubKey: - serializedPubKey := a.ScriptAddress() + case *stdaddr.AddressPubKeyEcdsaSecp256k1V0: + serializedPubKey := a.SerializedPubKey() switch len(serializedPubKey) { case 33: // compressed var compressedPubKey [33]byte copy(compressedPubKey[:], serializedPubKey) _, ok := f.compressedPubKeys[compressedPubKey] if !ok { - _, ok = f.pubKeyHashes[*a.AddressPubKeyHash().Hash160()] + h160 := a.AddressPubKeyHash().(stdaddr.Hash160er).Hash160() + _, ok = f.pubKeyHashes[*h160] } return ok } @@ -659,10 +661,13 @@ func (m *wsNotificationManager) subscribedClients(tx *dcrutil.Tx, clients map[ch subscribed := make(map[chan struct{}]struct{}) // Reusable backing array for a slice of a single address. - var scratchAddress [1]dcrutil.Address + var scratchAddress [1]stdaddr.Address const isTreasuryEnabled = true // No need to look it up here. + // Local for convenience. + params := m.server.cfg.ChainParams + msgTx := tx.MsgTx() var isTicket bool // lazily set for q, c := range clients { @@ -683,8 +688,7 @@ func (m *wsNotificationManager) subscribedClients(tx *dcrutil.Tx, clients map[ch for i, output := range msgTx.TxOut { watchOutput := true sc, addrs, _, err := txscript.ExtractPkScriptAddrs(output.Version, - output.PkScript, m.server.cfg.ChainParams, - isTreasuryEnabled) + output.PkScript, params, isTreasuryEnabled) if err != nil { // Clients are not able to subscribe to // nonstandard or non-address outputs. @@ -699,7 +703,7 @@ func (m *wsNotificationManager) subscribedClients(tx *dcrutil.Tx, clients map[ch // These outputs cannot be spent and do not need to // be watched. addr, err := stake.AddrFromSStxPkScrCommitment( - output.PkScript, m.server.cfg.ChainParams) + output.PkScript, params) if err != nil { log.Errorf("Failed to read commitment from "+ "previously-validated ticket: %v", err) @@ -1193,8 +1197,7 @@ func (m *wsNotificationManager) notifyRelevantTxAccepted(tx *dcrutil.Tx, for i, output := range msgTx.TxOut { _, addrs, _, err := txscript.ExtractPkScriptAddrs(output.Version, - output.PkScript, m.server.cfg.ChainParams, - isTreasuryEnabled) + output.PkScript, m.server.cfg.ChainParams, isTreasuryEnabled) if err != nil { continue } @@ -2314,9 +2317,8 @@ func rescanBlock(filter *wsClientFilter, block *dcrutil.Block, params *chaincfg. LoopOutputs: for i, output := range tx.TxOut { - _, addrs, _, err := txscript.ExtractPkScriptAddrs( - output.Version, output.PkScript, params, - isTreasuryEnabled) + _, addrs, _, err := txscript.ExtractPkScriptAddrs(output.Version, + output.PkScript, params, isTreasuryEnabled) if err != nil { continue } diff --git a/internal/rpcserver/treasury_test.go b/internal/rpcserver/treasury_test.go index 3486cb0807..95ea68b6d1 100644 --- a/internal/rpcserver/treasury_test.go +++ b/internal/rpcserver/treasury_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Decred developers +// Copyright (c) 2020-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -24,6 +24,7 @@ import ( "github.com/decred/dcrd/rpcclient/v7" "github.com/decred/dcrd/rpctest" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -39,7 +40,7 @@ func timeoutCtx(t testing.TB, timeout time.Duration) context.Context { } type tspendPayout struct { - address dcrutil.Address + address stdaddr.Address amount dcrutil.Amount } @@ -72,14 +73,9 @@ func createTSpend(privKey []byte, payouts []tspendPayout, fee dcrutil.Amount, ex // OP_TGEN for _, v := range payouts { - script, err := txscript.PayToAddrScript(v.address) - if err != nil { - panic(err) - } - tgenScript := make([]byte, len(script)+1) - tgenScript[0] = txscript.OP_TGEN - copy(tgenScript[1:], script) - msgTx.AddTxOut(wire.NewTxOut(int64(v.amount), tgenScript)) + addr := v.address.(stdaddr.StakeAddress) + genScriptVer, genScript := addr.PayFromTreasuryScript() + msgTx.AddTxOut(newTxOut(int64(v.amount), genScriptVer, genScript)) } // Treasury spend transactions have no inputs since the funds are @@ -107,7 +103,7 @@ func createTSpend(privKey []byte, payouts []tspendPayout, fee dcrutil.Amount, ex func createTAdd(t testing.TB, privKey []byte, prevOut *wire.OutPoint, pkScript []byte, amountIn, amountOut, fee dcrutil.Amount, - changeAddr dcrutil.Address) *wire.MsgTx { + changeAddr stdaddr.StakeAddress) *wire.MsgTx { tx := wire.NewMsgTx() tx.AddTxIn(&wire.TxIn{ @@ -116,14 +112,11 @@ func createTAdd(t testing.TB, privKey []byte, prevOut *wire.OutPoint, pkScript [ ValueIn: int64(amountIn), }) - changeScript, err := txscript.PayToSStxChange(changeAddr) - if err != nil { - t.Fatal(err) - } + changeScriptVer, changeScript := changeAddr.StakeChangeScript() changeAmount := amountIn - amountOut - fee tx.AddTxOut(wire.NewTxOut(int64(amountOut), []byte{txscript.OP_TADD})) if changeAmount > 0 { - tx.AddTxOut(wire.NewTxOut(int64(changeAmount), changeScript)) + tx.AddTxOut(newTxOut(int64(changeAmount), changeScriptVer, changeScript)) } tx.Version = wire.TxVersionTreasury @@ -270,21 +263,18 @@ func TestTreasury(t *testing.T) { // Create a privkey and p2pkh addr we control for use in the tests. privKey := secp256k1.NewPrivateKey(new(secp256k1.ModNScalar).SetInt(1)) pubKey := privKey.PubKey().SerializeCompressed() - pubKeyHash := dcrutil.Hash160(pubKey) - p2pkhAddr, err := dcrutil.NewAddressPubKeyHash(pubKeyHash, net, - dcrec.STEcdsaSecp256k1) - if err != nil { - t.Fatal(err) - } - p2pkhScript, err := txscript.PayToAddrScript(p2pkhAddr) + pubKeyHash := stdaddr.Hash160(pubKey) + p2pkhAddr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(pubKeyHash, + net) if err != nil { t.Fatal(err) } + p2pkhScriptVer, p2pkhScript := p2pkhAddr.PaymentScript() // Generate a p2sh script and addr we control for use in the tests. - p2shScript := []byte{txscript.OP_TRUE} + redeemScript := []byte{txscript.OP_TRUE} p2shSigScript := []byte{txscript.OP_DATA_1, txscript.OP_TRUE} - p2shAddr, err := dcrutil.NewAddressScriptHash(p2shScript, net) + p2shAddr, err := stdaddr.NewAddressScriptHashV0(redeemScript, net) if err != nil { t.Fatal(err) } @@ -294,7 +284,7 @@ func TestTreasury(t *testing.T) { taddInAmt := dcrutil.Amount(1e8) // 1 DCR taddPrevOuts := make([]*wire.OutPoint, nbTAddPrevOuts) for i := 0; i < nbTAddPrevOuts; i++ { - txOut := &wire.TxOut{PkScript: p2pkhScript, Value: int64(taddInAmt)} + txOut := newTxOut(int64(taddInAmt), p2pkhScriptVer, p2pkhScript) txHash, err := hn.SendOutputs([]*wire.TxOut{txOut}, defaultFeeRate) if err != nil { t.Fatal(err) diff --git a/rpcclient/chain.go b/rpcclient/chain.go index 21817075ee..382106fb94 100644 --- a/rpcclient/chain.go +++ b/rpcclient/chain.go @@ -1,5 +1,5 @@ // Copyright (c) 2014-2016 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -17,6 +17,7 @@ import ( "github.com/decred/dcrd/gcs/v3" "github.com/decred/dcrd/gcs/v3/blockcf2" chainjson "github.com/decred/dcrd/rpc/jsonrpc/types/v3" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -628,14 +629,14 @@ func (r *FutureValidateAddressResult) Receive() (*chainjson.ValidateAddressChain // the returned instance. // // See ValidateAddress for the blocking version and more details. -func (c *Client) ValidateAddressAsync(ctx context.Context, address dcrutil.Address) *FutureValidateAddressResult { +func (c *Client) ValidateAddressAsync(ctx context.Context, address stdaddr.Address) *FutureValidateAddressResult { addr := address.Address() cmd := chainjson.NewValidateAddressCmd(addr) return (*FutureValidateAddressResult)(c.sendCmd(ctx, cmd)) } // ValidateAddress returns information about the given Decred address. -func (c *Client) ValidateAddress(ctx context.Context, address dcrutil.Address) (*chainjson.ValidateAddressChainResult, error) { +func (c *Client) ValidateAddress(ctx context.Context, address stdaddr.Address) (*chainjson.ValidateAddressChainResult, error) { return c.ValidateAddressAsync(ctx, address).Receive() } @@ -666,7 +667,7 @@ func (r *FutureVerifyMessageResult) Receive() (bool, error) { // returned instance. // // See VerifyMessage for the blocking version and more details. -func (c *Client) VerifyMessageAsync(ctx context.Context, address dcrutil.Address, signature, message string) *FutureVerifyMessageResult { +func (c *Client) VerifyMessageAsync(ctx context.Context, address stdaddr.Address, signature, message string) *FutureVerifyMessageResult { addr := address.Address() cmd := chainjson.NewVerifyMessageCmd(addr, signature, message) return (*FutureVerifyMessageResult)(c.sendCmd(ctx, cmd)) @@ -676,7 +677,7 @@ func (c *Client) VerifyMessageAsync(ctx context.Context, address dcrutil.Address // // NOTE: This function requires to the wallet to be unlocked. See the // WalletPassphrase function for more details. -func (c *Client) VerifyMessage(ctx context.Context, address dcrutil.Address, signature, message string) (bool, error) { +func (c *Client) VerifyMessage(ctx context.Context, address stdaddr.Address, signature, message string) (bool, error) { return c.VerifyMessageAsync(ctx, address, signature, message).Receive() } diff --git a/rpcclient/extensions.go b/rpcclient/extensions.go index efbfc5e684..b9442c1851 100644 --- a/rpcclient/extensions.go +++ b/rpcclient/extensions.go @@ -1,5 +1,5 @@ // Copyright (c) 2014-2015 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -12,6 +12,7 @@ import ( "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/dcrutil/v4" chainjson "github.com/decred/dcrd/rpc/jsonrpc/types/v3" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -134,7 +135,7 @@ func (r *FutureExistsAddressResult) Receive() (bool, error) { // ExistsAddressAsync returns an instance of a type that can be used to get the // result of the RPC at some future time by invoking the Receive function on the // returned instance. -func (c *Client) ExistsAddressAsync(ctx context.Context, address dcrutil.Address) *FutureExistsAddressResult { +func (c *Client) ExistsAddressAsync(ctx context.Context, address stdaddr.Address) *FutureExistsAddressResult { cmd := chainjson.NewExistsAddressCmd(address.Address()) return (*FutureExistsAddressResult)(c.sendCmd(ctx, cmd)) } @@ -143,7 +144,7 @@ func (c *Client) ExistsAddressAsync(ctx context.Context, address dcrutil.Address // used on the main chain or in mempool. // // NOTE: This is a dcrd extension. -func (c *Client) ExistsAddress(ctx context.Context, address dcrutil.Address) (bool, error) { +func (c *Client) ExistsAddress(ctx context.Context, address stdaddr.Address) (bool, error) { return c.ExistsAddressAsync(ctx, address).Receive() } @@ -172,7 +173,7 @@ func (r *FutureExistsAddressesResult) Receive() (string, error) { // ExistsAddressesAsync returns an instance of a type that can be used to get the // result of the RPC at some future time by invoking the Receive function on the // returned instance. -func (c *Client) ExistsAddressesAsync(ctx context.Context, addresses []dcrutil.Address) *FutureExistsAddressesResult { +func (c *Client) ExistsAddressesAsync(ctx context.Context, addresses []stdaddr.Address) *FutureExistsAddressesResult { addrsStr := make([]string, len(addresses)) for i := range addresses { addrsStr[i] = addresses[i].Address() @@ -186,7 +187,7 @@ func (c *Client) ExistsAddressesAsync(ctx context.Context, addresses []dcrutil.A // in the blockchain or memory pool. // // NOTE: This is a dcrd extension. -func (c *Client) ExistsAddresses(ctx context.Context, addresses []dcrutil.Address) (string, error) { +func (c *Client) ExistsAddresses(ctx context.Context, addresses []stdaddr.Address) (string, error) { return c.ExistsAddressesAsync(ctx, addresses).Receive() } diff --git a/rpcclient/go.mod b/rpcclient/go.mod index 9a42156673..72863a512b 100644 --- a/rpcclient/go.mod +++ b/rpcclient/go.mod @@ -8,6 +8,7 @@ require ( github.com/decred/dcrd/dcrutil/v4 v4.0.0-20210129181600-6ae0142d3b28 github.com/decred/dcrd/gcs/v3 v3.0.0-20210129195202-a4265d63b619 github.com/decred/dcrd/rpc/jsonrpc/types/v3 v3.0.0-20210129200153-14fd1a785bf2 + github.com/decred/dcrd/txscript/v4 v4.0.0-20210330065944-a2366e6e0b3b github.com/decred/dcrd/wire v1.4.0 github.com/decred/go-socks v1.1.0 github.com/decred/slog v1.1.0 diff --git a/rpcclient/notify.go b/rpcclient/notify.go index 974b35815b..77ed0e048c 100644 --- a/rpcclient/notify.go +++ b/rpcclient/notify.go @@ -1,5 +1,5 @@ // Copyright (c) 2014-2016 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -16,6 +16,7 @@ import ( "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/dcrutil/v4" chainjson "github.com/decred/dcrd/rpc/jsonrpc/types/v3" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -1139,7 +1140,7 @@ func (r *FutureLoadTxFilterResult) Receive() error { // See LoadTxFilter for the blocking version and more details. // // NOTE: This is a dcrd extension and requires a websocket connection. -func (c *Client) LoadTxFilterAsync(ctx context.Context, reload bool, addresses []dcrutil.Address, +func (c *Client) LoadTxFilterAsync(ctx context.Context, reload bool, addresses []stdaddr.Address, outPoints []wire.OutPoint) *FutureLoadTxFilterResult { addrStrs := make([]string, len(addresses)) @@ -1164,6 +1165,6 @@ func (c *Client) LoadTxFilterAsync(ctx context.Context, reload bool, addresses [ // during mempool acceptance, block acceptance, and for all rescanned blocks. // // NOTE: This is a dcrd extension and requires a websocket connection. -func (c *Client) LoadTxFilter(ctx context.Context, reload bool, addresses []dcrutil.Address, outPoints []wire.OutPoint) error { +func (c *Client) LoadTxFilter(ctx context.Context, reload bool, addresses []stdaddr.Address, outPoints []wire.OutPoint) error { return c.LoadTxFilterAsync(ctx, reload, addresses, outPoints).Receive() } diff --git a/rpcclient/rawtransactions.go b/rpcclient/rawtransactions.go index 57fc6210b8..4bd759c37c 100644 --- a/rpcclient/rawtransactions.go +++ b/rpcclient/rawtransactions.go @@ -1,5 +1,5 @@ // Copyright (c) 2014-2016 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -15,6 +15,7 @@ import ( "github.com/decred/dcrd/dcrjson/v3" "github.com/decred/dcrd/dcrutil/v4" chainjson "github.com/decred/dcrd/rpc/jsonrpc/types/v3" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -199,11 +200,11 @@ func (r *FutureCreateRawTransactionResult) Receive() (*wire.MsgTx, error) { // // See CreateRawTransaction for the blocking version and more details. func (c *Client) CreateRawTransactionAsync(ctx context.Context, inputs []chainjson.TransactionInput, - amounts map[dcrutil.Address]dcrutil.Amount, lockTime *int64, expiry *int64) *FutureCreateRawTransactionResult { + amounts map[stdaddr.Address]dcrutil.Amount, lockTime *int64, expiry *int64) *FutureCreateRawTransactionResult { convertedAmts := make(map[string]float64, len(amounts)) for addr, amount := range amounts { - convertedAmts[addr.String()] = amount.ToCoin() + convertedAmts[addr.Address()] = amount.ToCoin() } cmd := chainjson.NewCreateRawTransactionCmd(inputs, convertedAmts, lockTime, expiry) return (*FutureCreateRawTransactionResult)(c.sendCmd(ctx, cmd)) @@ -212,7 +213,7 @@ func (c *Client) CreateRawTransactionAsync(ctx context.Context, inputs []chainjs // CreateRawTransaction returns a new transaction spending the provided inputs // and sending to the provided addresses. func (c *Client) CreateRawTransaction(ctx context.Context, inputs []chainjson.TransactionInput, - amounts map[dcrutil.Address]dcrutil.Amount, lockTime *int64, expiry *int64) (*wire.MsgTx, error) { + amounts map[stdaddr.Address]dcrutil.Amount, lockTime *int64, expiry *int64) (*wire.MsgTx, error) { return c.CreateRawTransactionAsync(ctx, inputs, amounts, lockTime, expiry).Receive() } @@ -255,9 +256,9 @@ func (r *FutureCreateRawSStxResult) Receive() (*wire.MsgTx, error) { // a commitment address and amount, and a change address and amount. Same // name as the JSON lib, but different internal structures. type SStxCommitOut struct { - Addr dcrutil.Address + Addr stdaddr.Address CommitAmt dcrutil.Amount - ChangeAddr dcrutil.Address + ChangeAddr stdaddr.Address ChangeAmt dcrutil.Amount } @@ -267,18 +268,18 @@ type SStxCommitOut struct { // // See CreateRawSStx for the blocking version and more details. func (c *Client) CreateRawSStxAsync(ctx context.Context, inputs []chainjson.SStxInput, - amount map[dcrutil.Address]dcrutil.Amount, + amount map[stdaddr.Address]dcrutil.Amount, couts []SStxCommitOut) *FutureCreateRawSStxResult { convertedAmt := make(map[string]int64, len(amount)) for addr, amt := range amount { - convertedAmt[addr.String()] = int64(amt) + convertedAmt[addr.Address()] = int64(amt) } convertedCouts := make([]chainjson.SStxCommitOut, len(couts)) for i, cout := range couts { - convertedCouts[i].Addr = cout.Addr.String() + convertedCouts[i].Addr = cout.Addr.Address() convertedCouts[i].CommitAmt = int64(cout.CommitAmt) - convertedCouts[i].ChangeAddr = cout.ChangeAddr.String() + convertedCouts[i].ChangeAddr = cout.ChangeAddr.Address() convertedCouts[i].ChangeAmt = int64(cout.ChangeAmt) } @@ -289,7 +290,7 @@ func (c *Client) CreateRawSStxAsync(ctx context.Context, inputs []chainjson.SStx // CreateRawSStx returns a new transaction spending the provided inputs // and sending to the provided addresses. func (c *Client) CreateRawSStx(ctx context.Context, inputs []chainjson.SStxInput, - amount map[dcrutil.Address]dcrutil.Amount, + amount map[stdaddr.Address]dcrutil.Amount, couts []SStxCommitOut) (*wire.MsgTx, error) { return c.CreateRawSStxAsync(ctx, inputs, amount, couts).Receive() @@ -440,7 +441,7 @@ func (r *FutureSearchRawTransactionsResult) Receive() ([]*wire.MsgTx, error) { // // See SearchRawTransactions for the blocking version and more details. func (c *Client) SearchRawTransactionsAsync(ctx context.Context, - address dcrutil.Address, skip, count int, reverse bool, + address stdaddr.Address, skip, count int, reverse bool, filterAddrs []string) *FutureSearchRawTransactionsResult { addr := address.Address() @@ -459,7 +460,7 @@ func (c *Client) SearchRawTransactionsAsync(ctx context.Context, // See SearchRawTransactionsVerbose to retrieve a list of data structures with // information about the transactions instead of the transactions themselves. func (c *Client) SearchRawTransactions(ctx context.Context, - address dcrutil.Address, skip, count int, + address stdaddr.Address, skip, count int, reverse bool, filterAddrs []string) ([]*wire.MsgTx, error) { return c.SearchRawTransactionsAsync(ctx, address, skip, count, reverse, @@ -495,7 +496,7 @@ func (r *FutureSearchRawTransactionsVerboseResult) Receive() ([]*chainjson.Searc // // See SearchRawTransactionsVerbose for the blocking version and more details. func (c *Client) SearchRawTransactionsVerboseAsync(ctx context.Context, - address dcrutil.Address, skip, count int, includePrevOut bool, reverse bool, + address stdaddr.Address, skip, count int, includePrevOut bool, reverse bool, filterAddrs *[]string) *FutureSearchRawTransactionsVerboseResult { addr := address.Address() @@ -517,7 +518,7 @@ func (c *Client) SearchRawTransactionsVerboseAsync(ctx context.Context, // // See SearchRawTransactions to retrieve a list of raw transactions instead. func (c *Client) SearchRawTransactionsVerbose(ctx context.Context, - address dcrutil.Address, skip, count int, includePrevOut, reverse bool, + address stdaddr.Address, skip, count int, includePrevOut, reverse bool, filterAddrs []string) ([]*chainjson.SearchRawTransactionsResult, error) { return c.SearchRawTransactionsVerboseAsync(ctx, address, skip, count, diff --git a/rpctest/memwallet.go b/rpctest/memwallet.go index e31d59272e..594ead3418 100644 --- a/rpctest/memwallet.go +++ b/rpctest/memwallet.go @@ -1,5 +1,5 @@ // Copyright (c) 2016-2017 The btcsuite developers -// Copyright (c) 2017-2020 The Decred developers +// Copyright (c) 2017-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -22,6 +22,7 @@ import ( "github.com/decred/dcrd/hdkeychain/v3" "github.com/decred/dcrd/rpcclient/v7" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -82,7 +83,7 @@ type undoEntry struct { // hierarchy which promotes reproducibility between harness test runs. type memWallet struct { coinbaseKey *secp256k1.PrivateKey - coinbaseAddr dcrutil.Address + coinbaseAddr stdaddr.Address // hdRoot is the root master private key for the wallet. hdRoot *hdkeychain.ExtendedKey @@ -96,7 +97,7 @@ type memWallet struct { // addrs tracks all addresses belonging to the wallet. The addresses // are indexed by their keypath from the hdRoot. - addrs map[uint32]dcrutil.Address + addrs map[uint32]stdaddr.Address // utxos is the set of utxos spendable by the wallet. utxos map[wire.OutPoint]*utxo @@ -152,7 +153,7 @@ func newMemWallet(t *testing.T, net *chaincfg.Params, harnessID uint32) (*memWal // Track the coinbase generation address to ensure we properly track // newly generated coins we can spend. - addrs := make(map[uint32]dcrutil.Address) + addrs := make(map[uint32]stdaddr.Address) addrs[0] = coinbaseAddr return &memWallet{ @@ -280,8 +281,8 @@ func (m *memWallet) evalOutputs(outputs []*wire.TxOut, txHash *chainhash.Hash, i // Scan all the addresses we currently control to see if the // output is paying to us. for keyIndex, addr := range m.addrs { - pkHash := addr.ScriptAddress() - if !bytes.Contains(pkScript, pkHash) { + pkHash := addr.(stdaddr.Hash160er).Hash160() + if !bytes.Contains(pkScript, pkHash[:]) { continue } @@ -355,7 +356,7 @@ func (m *memWallet) UnwindBlock(header []byte) { // newAddress returns a new address from the wallet's hd key chain. It also // loads the address into the RPC client's transaction filter to ensure any // transactions that involve it are delivered via the notifications. -func (m *memWallet) newAddress() (dcrutil.Address, error) { +func (m *memWallet) newAddress() (stdaddr.Address, error) { tracef(m.t, "memwallet.newAddress") defer tracef(m.t, "memwallet.newAddress exit") @@ -376,7 +377,7 @@ func (m *memWallet) newAddress() (dcrutil.Address, error) { } err = m.rpc.LoadTxFilter(context.Background(), false, - []dcrutil.Address{addr}, nil) + []stdaddr.Address{addr}, nil) if err != nil { return nil, err } @@ -391,7 +392,7 @@ func (m *memWallet) newAddress() (dcrutil.Address, error) { // NewAddress returns a fresh address spendable by the wallet. // // This function is safe for concurrent access. -func (m *memWallet) NewAddress() (dcrutil.Address, error) { +func (m *memWallet) NewAddress() (stdaddr.Address, error) { m.Lock() defer m.Unlock() @@ -451,12 +452,10 @@ func (m *memWallet) fundTx(tx *wire.MsgTx, amt dcrutil.Amount, feeRate dcrutil.A if err != nil { return err } - pkScript, err := txscript.PayToAddrScript(addr) - if err != nil { - return err - } + pkScriptVer, pkScript := addr.PaymentScript() changeOutput := &wire.TxOut{ Value: int64(changeVal), + Version: pkScriptVer, PkScript: pkScript, } tx.AddTxOut(changeOutput) @@ -598,10 +597,11 @@ func (m *memWallet) ConfirmedBalance() dcrutil.Amount { } // keyToAddr maps the passed private to corresponding p2pkh address. -func keyToAddr(serializedPrivKey []byte, net *chaincfg.Params) (dcrutil.Address, error) { +func keyToAddr(serializedPrivKey []byte, net *chaincfg.Params) (stdaddr.Address, error) { key := secp256k1.PrivKeyFromBytes(serializedPrivKey) serializedKey := key.PubKey().SerializeCompressed() - pubKeyAddr, err := dcrutil.NewAddressSecpPubKey(serializedKey, net) + pubKeyAddr, err := stdaddr.NewAddressPubKeyEcdsaSecp256k1V0Raw( + serializedKey, net) if err != nil { return nil, err } diff --git a/rpctest/rpc_harness.go b/rpctest/rpc_harness.go index 4e356db7fb..51017e5a2a 100644 --- a/rpctest/rpc_harness.go +++ b/rpctest/rpc_harness.go @@ -1,5 +1,5 @@ // Copyright (c) 2016 The btcsuite developers -// Copyright (c) 2017-2020 The Decred developers +// Copyright (c) 2017-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -21,6 +21,7 @@ import ( "github.com/decred/dcrd/chaincfg/v3" "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/rpcclient/v7" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -259,7 +260,7 @@ func (h *Harness) SetUp(createTestChain bool, numMatureOutputs uint32) error { // Filter transactions that pay to the coinbase associated with the // wallet. - filterAddrs := []dcrutil.Address{h.wallet.coinbaseAddr} + filterAddrs := []stdaddr.Address{h.wallet.coinbaseAddr} if err := h.Node.LoadTxFilter(ctx, true, filterAddrs, nil); err != nil { return err } @@ -367,7 +368,7 @@ func (h *Harness) connectRPCClient() error { // wallet. // // This function is safe for concurrent access. -func (h *Harness) NewAddress() (dcrutil.Address, error) { +func (h *Harness) NewAddress() (stdaddr.Address, error) { return h.wallet.NewAddress() } diff --git a/rpctest/rpc_harness_test.go b/rpctest/rpc_harness_test.go index 0a9236367e..6b64267284 100644 --- a/rpctest/rpc_harness_test.go +++ b/rpctest/rpc_harness_test.go @@ -1,5 +1,5 @@ // Copyright (c) 2016 The btcsuite developers -// Copyright (c) 2017-2020 The Decred developers +// Copyright (c) 2017-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -10,6 +10,7 @@ package rpctest import ( "context" + "fmt" "os" "testing" "time" @@ -18,7 +19,6 @@ import ( "github.com/decred/dcrd/chaincfg/v3" "github.com/decred/dcrd/dcrutil/v4" dcrdtypes "github.com/decred/dcrd/rpc/jsonrpc/types/v3" - "github.com/decred/dcrd/txscript/v4" "github.com/decred/dcrd/wire" ) @@ -39,11 +39,8 @@ func testSendOutputs(ctx context.Context, r *Harness, t *testing.T) { // Next, send amt to this address, spending from one of our // mature coinbase outputs. - addrScript, err := txscript.PayToAddrScript(addr) - if err != nil { - t.Fatalf("unable to generate pkscript to addr: %v", err) - } - output := wire.NewTxOut(int64(amt), addrScript) + addrScriptVer, addrScript := addr.PaymentScript() + output := newTxOut(int64(amt), addrScriptVer, addrScript) txid, err := r.SendOutputs([]*wire.TxOut{output}, 10) if err != nil { t.Fatalf("coinbase spend failed: %v", err) @@ -393,11 +390,11 @@ func testJoinMempools(ctx context.Context, r *Harness, t *testing.T) { if err != nil { t.Fatalf("unable to get new address: %v", err) } - addrScript, err := txscript.PayToAddrScript(addr) + addrScriptVer, addrScript := addr.PaymentScript() if err != nil { t.Fatalf("unable to generate pkscript to addr: %v", err) } - output := wire.NewTxOut(5e8, addrScript) + output := newTxOut(5e8, addrScriptVer, addrScript) testTx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) if err != nil { t.Fatalf("coinbase spend failed: %v", err) @@ -408,39 +405,49 @@ func testJoinMempools(ctx context.Context, r *Harness, t *testing.T) { // Wait until the transaction shows up to ensure the two mempools are // not the same. - harnessSynced := make(chan struct{}) + harnessSynced := make(chan error) go func() { for { poolHashes, err := r.Node.GetRawMempool(ctx, dcrdtypes.GRMAll) if err != nil { - t.Fatalf("failed to retrieve harness mempool: %v", err) + err = fmt.Errorf("failed to retrieve harness mempool: %w", err) + harnessSynced <- err + return } if len(poolHashes) > 0 { break } time.Sleep(time.Millisecond * 100) } - harnessSynced <- struct{}{} + harnessSynced <- nil }() select { - case <-harnessSynced: + case err := <-harnessSynced: + if err != nil { + t.Fatal(err) + } case <-time.After(time.Minute): - t.Fatalf("harness node never received transaction") + t.Fatal("harness node never received transaction") } // This select case should fall through to the default as the goroutine // should be blocked on the JoinNodes call. - poolsSynced := make(chan struct{}) + poolsSynced := make(chan error) go func() { if err := JoinNodes(nodeSlice, Mempools); err != nil { - t.Fatalf("unable to join node on mempools: %v", err) + err = fmt.Errorf("unable to join node on mempools: %w", err) + poolsSynced <- err + return } - poolsSynced <- struct{}{} + poolsSynced <- nil }() select { - case <-poolsSynced: - t.Fatalf("mempools detected as synced yet harness has a new tx") + case err := <-poolsSynced: + if err != nil { + t.Fatal(err) + } + t.Fatal("mempools detected as synced yet harness has a new tx") default: } @@ -464,10 +471,12 @@ func testJoinMempools(ctx context.Context, r *Harness, t *testing.T) { // channel. The send should immediately succeed. In order to avoid the // test hanging indefinitely, a 1 minute timeout is in place. select { - case <-poolsSynced: - // fall through + case err := <-poolsSynced: + if err != nil { + t.Fatal(err) + } case <-time.After(time.Minute): - t.Fatalf("mempools never detected as synced") + t.Fatal("mempools never detected as synced") } } @@ -487,18 +496,22 @@ func testJoinBlocks(_ context.Context, r *Harness, t *testing.T) { defer harness.TearDown() nodeSlice := []*Harness{r, harness} - blocksSynced := make(chan struct{}) + blocksSynced := make(chan error) go func() { if err := JoinNodes(nodeSlice, Blocks); err != nil { - t.Fatalf("unable to join node on blocks: %v", err) + blocksSynced <- fmt.Errorf("unable to join node on blocks: %w", err) + return } - blocksSynced <- struct{}{} + blocksSynced <- nil }() // This select case should fall through to the default as the goroutine // should be blocked on the JoinNodes calls. select { - case <-blocksSynced: + case err := <-blocksSynced: + if err != nil { + t.Fatal(err) + } t.Fatalf("blocks detected as synced yet local harness is behind") default: } @@ -514,7 +527,10 @@ func testJoinBlocks(_ context.Context, r *Harness, t *testing.T) { // channel. The send should immediately succeed. In order to avoid the // test hanging indefinitely, a 1 minute timeout is in place. select { - case <-blocksSynced: + case err := <-blocksSynced: + if err != nil { + t.Fatal(err) + } case <-time.After(time.Minute): t.Fatalf("blocks never detected as synced") } @@ -576,12 +592,9 @@ func testMemWalletLockedOutputs(_ context.Context, r *Harness, t *testing.T) { if err != nil { t.Fatalf("unable to generate new address: %v", err) } - pkScript, err := txscript.PayToAddrScript(addr) - if err != nil { - t.Fatalf("unable to create script: %v", err) - } + pkScriptVer, pkScript := addr.PaymentScript() outputAmt := dcrutil.Amount(50 * dcrutil.AtomsPerCoin) - output := wire.NewTxOut(int64(outputAmt), pkScript) + output := newTxOut(int64(outputAmt), pkScriptVer, pkScript) tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) if err != nil { t.Fatalf("unable to create transaction: %v", err) @@ -647,7 +660,7 @@ func TestHarness(t *testing.T) { // Current tip should be at a height of numMatureOutputs plus the // required number of blocks for coinbase maturity plus an additional // block for the premine block. - ctx := context.TODO() + ctx := context.Background() nodeInfo, err := mainHarness.Node.GetInfo(ctx) if err != nil { t.Fatalf("unable to execute getinfo on node: %v", err) diff --git a/rpctest/votingwallet.go b/rpctest/votingwallet.go index 6fb0c3bdcc..46d997f608 100644 --- a/rpctest/votingwallet.go +++ b/rpctest/votingwallet.go @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Decred developers +// Copyright (c) 2019-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -21,6 +21,7 @@ import ( dcrdtypes "github.com/decred/dcrd/rpc/jsonrpc/types/v3" "github.com/decred/dcrd/rpcclient/v7" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -92,18 +93,23 @@ type utxoInfo struct { type VotingWallet struct { hn *Harness privateKey []byte - address dcrutil.Address + address stdaddr.Address c *rpcclient.Client blockConnectedNtfnChan chan blockConnectedNtfn winningTicketsNtfnChan chan winningTicketsNtfn quitChan chan struct{} + p2sstxVer uint16 p2sstx []byte - commitmentScript []byte + commitScriptVer uint16 + commitScript []byte p2pkh []byte + p2pkhVer uint16 + voteScriptVer uint16 voteScript []byte - voteReturnScript []byte + voteRetScriptVer uint16 + voteRetScript []byte errorReporter func(error) @@ -136,42 +142,29 @@ type VotingWallet struct { // of the harness working after it has passed SVH (Stake Validation Height) by // continuously buying tickets and voting on them. func NewVotingWallet(ctx context.Context, hn *Harness) (*VotingWallet, error) { - privKey := secp256k1.PrivKeyFromBytes(hardcodedPrivateKey) serPub := privKey.PubKey().SerializeCompressed() - hashPub := dcrutil.Hash160(serPub) - addr, err := dcrutil.NewAddressPubKeyHash(hashPub, hn.ActiveNet, - dcrec.STEcdsaSecp256k1) + h160 := stdaddr.Hash160(serPub) + addr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(h160, hn.ActiveNet) if err != nil { return nil, fmt.Errorf("unable to generate address for pubkey: %v", err) } - p2sstx, err := txscript.PayToSStx(addr) - if err != nil { - return nil, fmt.Errorf("unable to prepare p2sstx script: %v", err) - } - - p2pkh, err := txscript.PayToAddrScript(addr) - if err != nil { - return nil, fmt.Errorf("unable to prepare p2pkh script: %v", err) - } + p2sstxVer, p2sstx := addr.VotingRightsScript() + p2pkhVer, p2pkh := addr.PaymentScript() - commitAmount := dcrutil.Amount(hn.ActiveNet.MinimumStakeDiff * commitAmountMultiplier) - limit := uint16(0x0058) - commitmentScript, err := txscript.GenerateSStxAddrPush(addr, commitAmount, limit) - if err != nil { - return nil, fmt.Errorf("unable to prepare commitment script: %v", err) - } + commitAmount := hn.ActiveNet.MinimumStakeDiff * commitAmountMultiplier + const voteFeeLimit = 0 + const revokeFeeLimit = 16777216 + commitScriptVer, commitScript := addr.RewardCommitmentScript(commitAmount, + voteFeeLimit, revokeFeeLimit) + voteScriptVer := uint16(0) voteScript, err := txscript.GenerateSSGenVotes(0x0001) if err != nil { return nil, fmt.Errorf("unable to prepare vote script: %v", err) } - - voteReturnScript, err := txscript.PayToSSGen(addr) - if err != nil { - return nil, fmt.Errorf("unable to generate vote return script: %v", err) - } + voteReturnScriptVer, voteReturnScript := addr.PayVoteCommitmentScript() // Hints for the initial sizing of the tickets and maturing votes maps. // Given we have a deterministic purchase process, this should allow us to @@ -187,11 +180,16 @@ func NewVotingWallet(ctx context.Context, hn *Harness) (*VotingWallet, error) { hn: hn, privateKey: hardcodedPrivateKey, address: addr, + p2sstxVer: p2sstxVer, p2sstx: p2sstx, + p2pkhVer: p2pkhVer, p2pkh: p2pkh, - commitmentScript: commitmentScript, + commitScriptVer: commitScriptVer, + commitScript: commitScript, + voteScriptVer: voteScriptVer, voteScript: voteScript, - voteReturnScript: voteReturnScript, + voteRetScriptVer: voteReturnScriptVer, + voteRetScript: voteReturnScript, subsidyCache: standalone.NewSubsidyCache(hn.ActiveNet), limitNbVotes: int(hn.ActiveNet.TicketsPerBlock), tickets: make(map[chainhash.Hash]ticketInfo, hintTicketsCap), @@ -399,6 +397,15 @@ func (w *VotingWallet) onBlockConnected(blockHeader []byte, transactions [][]byt } } +// newTxOut returns a new transaction output with the given parameters. +func newTxOut(amount int64, pkScriptVer uint16, pkScript []byte) *wire.TxOut { + return &wire.TxOut{ + Value: amount, + Version: pkScriptVer, + PkScript: pkScript, + } +} + func (w *VotingWallet) handleBlockConnectedNtfn(ntfn *blockConnectedNtfn) { var header wire.BlockHeader err := header.FromBytes(ntfn.blockHeader) @@ -440,13 +447,13 @@ func (w *VotingWallet) handleBlockConnectedNtfn(ntfn *blockConnectedNtfn) { t := &tickets[i] t.Version = wire.TxVersion t.AddTxIn(wire.NewTxIn(&utxos[i].outpoint, wire.NullValueIn, nil)) - t.AddTxOut(wire.NewTxOut(ticketPrice, w.p2sstx)) - t.AddTxOut(wire.NewTxOut(0, w.commitmentScript)) + t.AddTxOut(newTxOut(ticketPrice, w.p2sstxVer, w.p2sstx)) + t.AddTxOut(newTxOut(0, w.commitScriptVer, w.commitScript)) t.AddTxOut(wire.NewTxOut(changeAmount, nullPay2SSTXChange)) prevScript := w.p2pkh if utxos[i].outpoint.Tree == wire.TxTreeStake { - prevScript = w.voteReturnScript + prevScript = w.voteRetScript } sig, err := txscript.SignatureScript(t, 0, prevScript, txscript.SigHashAll, @@ -494,7 +501,6 @@ func (w *VotingWallet) onWinningTickets(blockHash *chainhash.Hash, blockHeight i } func (w *VotingWallet) handleWinningTicketsNtfn(ntfn *winningTicketsNtfn) { - blockRefScript, err := txscript.GenerateSSGenBlockRef(*ntfn.blockHash, uint32(ntfn.blockHeight)) if err != nil { @@ -502,8 +508,6 @@ func (w *VotingWallet) handleWinningTicketsNtfn(ntfn *winningTicketsNtfn) { return } - voteScript := w.voteScript - voteReturnScript := w.voteReturnScript stakebaseValue := w.subsidyCache.CalcStakeVoteSubsidy(ntfn.blockHeight) // Create the votes. nbVotes is the number of tickets from the wallet that @@ -521,7 +525,7 @@ func (w *VotingWallet) handleWinningTicketsNtfn(ntfn *winningTicketsNtfn) { continue } - voteReturnValue := ticket.ticketPrice + stakebaseValue + voteRetValue := ticket.ticketPrice + stakebaseValue // Create a corresponding vote transaction. vote := &votes[nbVotes] @@ -535,8 +539,8 @@ func (w *VotingWallet) handleWinningTicketsNtfn(ntfn *winningTicketsNtfn) { wire.NullValueIn, nil, )) vote.AddTxOut(wire.NewTxOut(0, blockRefScript)) - vote.AddTxOut(wire.NewTxOut(0, voteScript)) - vote.AddTxOut(wire.NewTxOut(voteReturnValue, voteReturnScript)) + vote.AddTxOut(newTxOut(0, w.voteScriptVer, w.voteScript)) + vote.AddTxOut(newTxOut(voteRetValue, w.voteRetScriptVer, w.voteRetScript)) // If there are tspends to vote for, create an additional // output. diff --git a/txscript/error.go b/txscript/error.go index 4c75ceb299..7076af78ab 100644 --- a/txscript/error.go +++ b/txscript/error.go @@ -27,10 +27,6 @@ const ( // index that is greater than or equal to the number of outputs. ErrInvalidSigHashSingleIndex = ErrorKind("ErrInvalidSigHashSingleIndex") - // ErrUnsupportedAddress is returned when a concrete type that - // implements a dcrutil.Address is not a supported type. - ErrUnsupportedAddress = ErrorKind("ErrUnsupportedAddress") - // ErrNotMultisigScript is returned from CalcMultiSigStats when the // provided script is not a multisig script. ErrNotMultisigScript = ErrorKind("ErrNotMultisigScript") diff --git a/txscript/error_test.go b/txscript/error_test.go index eeb901ebed..9a22a404f0 100644 --- a/txscript/error_test.go +++ b/txscript/error_test.go @@ -19,7 +19,6 @@ func TestErrorKindStringer(t *testing.T) { }{ {ErrInvalidIndex, "ErrInvalidIndex"}, {ErrInvalidSigHashSingleIndex, "ErrInvalidSigHashSingleIndex"}, - {ErrUnsupportedAddress, "ErrUnsupportedAddress"}, {ErrTooManyRequiredSigs, "ErrTooManyRequiredSigs"}, {ErrTooMuchNullData, "ErrTooMuchNullData"}, {ErrUnsupportedScriptVersion, "ErrUnsupportedScriptVersion"}, diff --git a/txscript/example_test.go b/txscript/example_test.go index 9c863ee3b7..204d375ce9 100644 --- a/txscript/example_test.go +++ b/txscript/example_test.go @@ -1,5 +1,5 @@ // Copyright (c) 2014-2016 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -13,8 +13,8 @@ import ( "github.com/decred/dcrd/chaincfg/v3" "github.com/decred/dcrd/dcrec" "github.com/decred/dcrd/dcrec/secp256k1/v4" - "github.com/decred/dcrd/dcrutil/v4" "github.com/decred/dcrd/txscript/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -25,42 +25,6 @@ const ( noTreasury = false ) -// This example demonstrates creating a script which pays to a Decred address. -// It also prints the created script hex and uses the DisasmString function to -// display the disassembled script. -func ExamplePayToAddrScript() { - // Parse the address to send the coins to into a dcrutil.Address - // which is useful to ensure the accuracy of the address and determine - // the address type. It is also required for the upcoming call to - // PayToAddrScript. - mainNetParams := chaincfg.MainNetParams() - addressStr := "DsSej1qR3Fyc8kV176DCh9n9cY9nqf9Quxk" - address, err := dcrutil.DecodeAddress(addressStr, mainNetParams) - if err != nil { - fmt.Println(err) - return - } - - // Create a public key script that pays to the address. - script, err := txscript.PayToAddrScript(address) - if err != nil { - fmt.Println(err) - return - } - fmt.Printf("Script Hex: %x\n", script) - - disasm, err := txscript.DisasmString(script) - if err != nil { - fmt.Println(err) - return - } - fmt.Println("Script Disassembly:", disasm) - - // Output: - // Script Hex: 76a914128004ff2fcaf13b2b91eb654b1dc2b674f7ec6188ac - // Script Disassembly: OP_DUP OP_HASH160 128004ff2fcaf13b2b91eb654b1dc2b674f7ec61 OP_EQUALVERIFY OP_CHECKSIG -} - // This example demonstrates extracting information from a standard public key // script. func ExampleExtractPkScriptAddrs() { @@ -102,11 +66,10 @@ func ExampleSignTxOutput() { return } pubKey := secp256k1.PrivKeyFromBytes(privKeyBytes).PubKey() - pubKeyHash := dcrutil.Hash160(pubKey.SerializeCompressed()) + pubKeyHash := stdaddr.Hash160(pubKey.SerializeCompressed()) mainNetParams := chaincfg.MainNetParams() - sigType := dcrec.STEcdsaSecp256k1 - addr, err := dcrutil.NewAddressPubKeyHash(pubKeyHash, mainNetParams, - sigType) + addr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(pubKeyHash, + mainNetParams) if err != nil { fmt.Println(err) return @@ -119,12 +82,9 @@ func ExampleSignTxOutput() { prevOut := wire.NewOutPoint(&chainhash.Hash{}, ^uint32(0), wire.TxTreeRegular) txIn := wire.NewTxIn(prevOut, 100000000, []byte{txscript.OP_0, txscript.OP_0}) originTx.AddTxIn(txIn) - pkScript, err := txscript.PayToAddrScript(addr) - if err != nil { - fmt.Println(err) - return - } + pkScriptVer, pkScript := addr.PaymentScript() txOut := wire.NewTxOut(100000000, pkScript) + txOut.Version = pkScriptVer originTx.AddTxOut(txOut) originTxHash := originTx.TxHash() @@ -144,7 +104,8 @@ func ExampleSignTxOutput() { redeemTx.AddTxOut(txOut) // Sign the redeeming transaction. - lookupKey := func(a dcrutil.Address) ([]byte, dcrec.SignatureType, bool, error) { + sigType := dcrec.STEcdsaSecp256k1 + lookupKey := func(a stdaddr.Address) ([]byte, dcrec.SignatureType, bool, error) { // Ordinarily this function would involve looking up the private // key for the provided address, but since the only thing being // signed in this example uses the address associated with the @@ -199,7 +160,7 @@ func ExampleSignTxOutput() { func ExampleScriptTokenizer() { // Create a script to use in the example. Ordinarily this would come from // some other source. - hash160 := dcrutil.Hash160([]byte("example")) + hash160 := stdaddr.Hash160([]byte("example")) script, err := txscript.NewScriptBuilder().AddOp(txscript.OP_DUP). AddOp(txscript.OP_HASH160).AddData(hash160). AddOp(txscript.OP_EQUALVERIFY).AddOp(txscript.OP_CHECKSIG).Script() diff --git a/txscript/sign.go b/txscript/sign.go index 1576760f4f..40ab4e49b1 100644 --- a/txscript/sign.go +++ b/txscript/sign.go @@ -1,5 +1,5 @@ // Copyright (c) 2013-2015 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -14,7 +14,7 @@ import ( "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" "github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr" - "github.com/decred/dcrd/dcrutil/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -118,7 +118,7 @@ func p2pkSignatureScript(tx *wire.MsgTx, idx int, subScript []byte, // arguably legal to not be able to sign any of the outputs, no error is // returned. func signMultiSig(tx *wire.MsgTx, idx int, subScript []byte, hashType SigHashType, - addresses []dcrutil.Address, nRequired int, kdb KeyDB) ([]byte, bool) { + addresses []stdaddr.Address, nRequired int, kdb KeyDB) ([]byte, bool) { // No need to add dummy in Decred. builder := NewScriptBuilder() @@ -149,8 +149,8 @@ func signMultiSig(tx *wire.MsgTx, idx int, subScript []byte, hashType SigHashTyp // sign. It handles the signing of stake outputs. func handleStakeOutSign(tx *wire.MsgTx, idx int, subScript []byte, hashType SigHashType, kdb KeyDB, sdb ScriptDB, - addresses []dcrutil.Address, class ScriptClass, subClass ScriptClass, - nrequired int) ([]byte, ScriptClass, []dcrutil.Address, int, error) { + addresses []stdaddr.Address, class ScriptClass, subClass ScriptClass, + nrequired int) ([]byte, ScriptClass, []stdaddr.Address, int, error) { // look up key for address switch subClass { @@ -182,7 +182,7 @@ func handleStakeOutSign(tx *wire.MsgTx, idx int, subScript []byte, // its input index, a database of keys, a database of scripts, and information // about the type of signature and returns a signature, script class, the // addresses involved, and the number of signatures required. -func sign(chainParams dcrutil.AddressParams, tx *wire.MsgTx, idx int, subScript []byte, hashType SigHashType, kdb KeyDB, sdb ScriptDB, isTreasuryEnabled bool) ([]byte, ScriptClass, []dcrutil.Address, int, error) { +func sign(chainParams stdaddr.AddressParams, tx *wire.MsgTx, idx int, subScript []byte, hashType SigHashType, kdb KeyDB, sdb ScriptDB, isTreasuryEnabled bool) ([]byte, ScriptClass, []stdaddr.Address, int, error) { const scriptVersion = 0 class, addresses, nrequired, err := ExtractPkScriptAddrs(scriptVersion, @@ -319,7 +319,7 @@ func sign(chainParams dcrutil.AddressParams, tx *wire.MsgTx, idx int, subScript // NOTE: This function is only valid for version 0 scripts. Since the function // does not accept a script version, the results are undefined for other script // versions. -func mergeMultiSig(tx *wire.MsgTx, idx int, addresses []dcrutil.Address, +func mergeMultiSig(tx *wire.MsgTx, idx int, addresses []stdaddr.Address, nRequired int, pkScript, sigScript, prevScript []byte) []byte { // Nothing to merge if either the new or previous signature scripts are @@ -393,9 +393,11 @@ sigLoop: // All multisig addresses should be pubkey addresses // it is an error to call this internal function with // bad input. - pkaddr := addr.(*dcrutil.AddressSecpPubKey) - - pubKey := pkaddr.PubKey() + pkAddr := addr.(stdaddr.SerializedPubKeyer) + pubKey, err := secp256k1.ParsePubKey(pkAddr.SerializedPubKey()) + if err != nil { + continue + } // If it matches we put it in the map. We only // can take one signature per public key so if we @@ -444,7 +446,7 @@ sigLoop: // NOTE: This function is only valid for version 0 scripts. Since the function // does not accept a script version, the results are undefined for other script // versions. -func mergeScripts(chainParams dcrutil.AddressParams, tx *wire.MsgTx, idx int, pkScript []byte, class ScriptClass, addresses []dcrutil.Address, nRequired int, sigScript, prevScript []byte, isTreasuryEnabled bool) []byte { +func mergeScripts(chainParams stdaddr.AddressParams, tx *wire.MsgTx, idx int, pkScript []byte, class ScriptClass, addresses []stdaddr.Address, nRequired int, sigScript, prevScript []byte, isTreasuryEnabled bool) []byte { // TODO(oga) the scripthash and multisig paths here are overly // inefficient in that they will recompute already known data. @@ -511,28 +513,28 @@ func mergeScripts(chainParams dcrutil.AddressParams, tx *wire.MsgTx, idx int, pk // KeyDB is an interface type provided to SignTxOutput, it encapsulates // any user state required to get the private keys for an address. type KeyDB interface { - GetKey(dcrutil.Address) ([]byte, dcrec.SignatureType, bool, error) + GetKey(stdaddr.Address) ([]byte, dcrec.SignatureType, bool, error) } // KeyClosure implements KeyDB with a closure. -type KeyClosure func(dcrutil.Address) ([]byte, dcrec.SignatureType, bool, error) +type KeyClosure func(stdaddr.Address) ([]byte, dcrec.SignatureType, bool, error) // GetKey implements KeyDB by returning the result of calling the closure. -func (kc KeyClosure) GetKey(address dcrutil.Address) ([]byte, dcrec.SignatureType, bool, error) { +func (kc KeyClosure) GetKey(address stdaddr.Address) ([]byte, dcrec.SignatureType, bool, error) { return kc(address) } // ScriptDB is an interface type provided to SignTxOutput, it encapsulates any // user state required to get the scripts for a pay-to-script-hash address. type ScriptDB interface { - GetScript(dcrutil.Address) ([]byte, error) + GetScript(stdaddr.Address) ([]byte, error) } // ScriptClosure implements ScriptDB with a closure. -type ScriptClosure func(dcrutil.Address) ([]byte, error) +type ScriptClosure func(stdaddr.Address) ([]byte, error) // GetScript implements ScriptDB by returning the result of calling the closure. -func (sc ScriptClosure) GetScript(address dcrutil.Address) ([]byte, error) { +func (sc ScriptClosure) GetScript(address stdaddr.Address) ([]byte, error) { return sc(address) } @@ -547,7 +549,7 @@ func (sc ScriptClosure) GetScript(address dcrutil.Address) ([]byte, error) { // NOTE: This function is only valid for version 0 scripts. Since the function // does not accept a script version, the results are undefined for other script // versions. -func SignTxOutput(chainParams dcrutil.AddressParams, tx *wire.MsgTx, idx int, pkScript []byte, hashType SigHashType, kdb KeyDB, sdb ScriptDB, previousScript []byte, isTreasuryEnabled bool) ([]byte, error) { +func SignTxOutput(chainParams stdaddr.AddressParams, tx *wire.MsgTx, idx int, pkScript []byte, hashType SigHashType, kdb KeyDB, sdb ScriptDB, previousScript []byte, isTreasuryEnabled bool) ([]byte, error) { sigScript, class, addresses, nrequired, err := sign(chainParams, tx, idx, pkScript, hashType, kdb, sdb, isTreasuryEnabled) diff --git a/txscript/sign_test.go b/txscript/sign_test.go index d733c06b26..bff58a09c3 100644 --- a/txscript/sign_test.go +++ b/txscript/sign_test.go @@ -1,5 +1,5 @@ // Copyright (c) 2013-2016 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -17,7 +17,7 @@ import ( "github.com/decred/dcrd/dcrec" "github.com/decred/dcrd/dcrec/edwards/v2" "github.com/decred/dcrd/dcrec/secp256k1/v4" - "github.com/decred/dcrd/dcrutil/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) @@ -47,12 +47,12 @@ type addressToKey struct { func mkGetKey(keys map[string]addressToKey) KeyDB { if keys == nil { - return KeyClosure(func(addr dcrutil.Address) ([]byte, + return KeyClosure(func(addr stdaddr.Address) ([]byte, dcrec.SignatureType, bool, error) { return nil, 0, false, errors.New("nope 1") }) } - return KeyClosure(func(addr dcrutil.Address) ([]byte, + return KeyClosure(func(addr stdaddr.Address) ([]byte, dcrec.SignatureType, bool, error) { a2k, ok := keys[addr.Address()] if !ok { @@ -64,14 +64,14 @@ func mkGetKey(keys map[string]addressToKey) KeyDB { func mkGetKeyPub(keys map[string]addressToKey) KeyDB { if keys == nil { - return KeyClosure(func(addr dcrutil.Address) ([]byte, + return KeyClosure(func(addr stdaddr.Address) ([]byte, dcrec.SignatureType, bool, error) { return nil, 0, false, errors.New("nope 1") }) } - return KeyClosure(func(addr dcrutil.Address) ([]byte, + return KeyClosure(func(addr stdaddr.Address) ([]byte, dcrec.SignatureType, bool, error) { - a2k, ok := keys[addr.String()] + a2k, ok := keys[addr.Address()] if !ok { return nil, 0, false, errors.New("nope 2") } @@ -81,12 +81,12 @@ func mkGetKeyPub(keys map[string]addressToKey) KeyDB { func mkGetScript(scripts map[string][]byte) ScriptDB { if scripts == nil { - return ScriptClosure(func(addr dcrutil.Address) ( + return ScriptClosure(func(addr stdaddr.Address) ( []byte, error) { return nil, errors.New("nope 3") }) } - return ScriptClosure(func(addr dcrutil.Address) ([]byte, + return ScriptClosure(func(addr stdaddr.Address) ([]byte, error) { script, ok := scripts[addr.Address()] if !ok { @@ -227,40 +227,42 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte + var keyDB []byte + msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeUncompressed() + pkBytes := privKey.PubKey().SerializeUncompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + h160, testingParams) + case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeUncompressed() + pkBytes := pk.SerializeUncompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEd25519V0(h160, + testingParams) + case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() + pkBytes := privKey.PubKey().SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashSchnorrSecp256k1V0( + h160, testingParams) } - - msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - - address, err := dcrutil.NewAddressPubKeyHash( - dcrutil.Hash160(pkBytes), testingParams, - suite) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } - pkScript, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } + _, pkScript := address.PaymentScript() // Without treasury agenda. if err := signAndCheck(msg, tx, i, pkScript, hashType, @@ -303,39 +305,42 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte + var keyDB []byte + msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeUncompressed() + pkBytes := privKey.PubKey().SerializeUncompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + h160, testingParams) + case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeUncompressed() + pkBytes := pk.SerializeUncompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEd25519V0(h160, + testingParams) + case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() + pkBytes := privKey.PubKey().SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashSchnorrSecp256k1V0( + h160, testingParams) } - - msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - - address, err := dcrutil.NewAddressPubKeyHash( - dcrutil.Hash160(pkBytes), testingParams, - suite) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } - pkScript, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } + _, pkScript := address.PaymentScript() // Without treasury agenda. sigScript, err := SignTxOutput( @@ -408,39 +413,42 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte + var keyDB []byte + msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() + pkBytes := privKey.PubKey().SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + h160, testingParams) + case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeCompressed() + pkBytes := pk.SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEd25519V0(h160, + testingParams) + case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() + pkBytes := privKey.PubKey().SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashSchnorrSecp256k1V0( + h160, testingParams) } - - msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - - address, err := dcrutil.NewAddressPubKeyHash( - dcrutil.Hash160(pkBytes), testingParams, - suite) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } - pkScript, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } + _, pkScript := address.PaymentScript() // Without treasury agenda. if err := signAndCheck(msg, tx, i, pkScript, hashType, @@ -483,39 +491,42 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte + var keyDB []byte + msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() + pkBytes := privKey.PubKey().SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + h160, testingParams) + case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeCompressed() + pkBytes := pk.SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEd25519V0(h160, + testingParams) + case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() + pkBytes := privKey.PubKey().SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashSchnorrSecp256k1V0( + h160, testingParams) } - - msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - - address, err := dcrutil.NewAddressPubKeyHash( - dcrutil.Hash160(pkBytes), testingParams, - suite) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } - pkScript, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } + _, pkScript := address.PaymentScript() // Without treasury agenda. sigScript, err := SignTxOutput(testingParams, @@ -597,23 +608,16 @@ func TestSignTxOutput(t *testing.T) { keyDB := privKey.Serialize() pkBytes := privKey.PubKey().SerializeCompressed() - suite := dcrec.STEcdsaSecp256k1 - address, err := dcrutil.NewAddressPubKeyHash( - dcrutil.Hash160(pkBytes), testingParams, - suite) + address, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + stdaddr.Hash160(pkBytes), testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - break + t.Errorf("failed to make address for %s: %v", msg, err) } - pkScript, err := PayToSStx(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } + _, pkScript := address.VotingRightsScript() // Without treasury agenda. + suite := dcrec.STEcdsaSecp256k1 if err := signAndCheck(msg, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.Address(): {keyDB, suite, true}, @@ -662,23 +666,17 @@ func TestSignTxOutput(t *testing.T) { keyDB := privKey.Serialize() pkBytes := privKey.PubKey().SerializeCompressed() - suite := dcrec.STEcdsaSecp256k1 - address, err := dcrutil.NewAddressPubKeyHash( - dcrutil.Hash160(pkBytes), testingParams, - suite) + address, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + stdaddr.Hash160(pkBytes), testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } - pkScript, err := PayToSStxChange(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } + _, pkScript := address.StakeChangeScript() // Without treasury agenda. + suite := dcrec.STEcdsaSecp256k1 if err := signAndCheck(msg, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.Address(): {keyDB, suite, true}, @@ -727,23 +725,17 @@ func TestSignTxOutput(t *testing.T) { keyDB := privKey.Serialize() pkBytes := privKey.PubKey().SerializeCompressed() - suite := dcrec.STEcdsaSecp256k1 - address, err := dcrutil.NewAddressPubKeyHash( - dcrutil.Hash160(pkBytes), testingParams, - suite) + address, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + stdaddr.Hash160(pkBytes), testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } - pkScript, err := PayToSSGen(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } + _, pkScript := address.PayVoteCommitmentScript() // Without treasury agenda. + suite := dcrec.STEcdsaSecp256k1 if err := signAndCheck(msg, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.Address(): {keyDB, suite, true}, @@ -792,23 +784,18 @@ func TestSignTxOutput(t *testing.T) { keyDB := privKey.Serialize() pkBytes := privKey.PubKey().SerializeCompressed() - suite := dcrec.STEcdsaSecp256k1 - address, err := dcrutil.NewAddressPubKeyHash( - dcrutil.Hash160(pkBytes), testingParams, - suite) + address, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + stdaddr.Hash160(pkBytes), testingParams) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) break } - pkScript, err := PayToSSRtx(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } + _, pkScript := address.PayRevokeCommitmentScript() // Without treasury agenda. + suite := dcrec.STEcdsaSecp256k1 if err := signAndCheck(msg, tx, i, pkScript, hashType, mkGetKey(map[string]addressToKey{ address.Address(): {keyDB, suite, true}, @@ -846,68 +833,58 @@ func TestSignTxOutput(t *testing.T) { // Pay to PubKey (uncompressed) for _, hashType := range hashTypes { - for _, suite := range signatureSuites { - for i := range tx.TxIn { - msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) - privKey, err := secp256k1.GeneratePrivateKey() - if err != nil { - t.Errorf("failed to generate key: %v", err) - break - } - keyDB := privKey.Serialize() - pk := privKey.PubKey() - suite := dcrec.STEcdsaSecp256k1 - // For address generation, consensus rules require using - // a compressed public key. Look up ExtractPkScriptAddrs - // for more details - address, err := dcrutil.NewAddressSecpPubKeyCompressed(pk, - testingParams) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - break - } + privKey, err := secp256k1.GeneratePrivateKey() + if err != nil { + t.Errorf("failed to generate key: %v", err) + break + } + keyDB := privKey.Serialize() + pk := privKey.PubKey() + address, err := stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pk, + testingParams) + if err != nil { + t.Errorf("failed to make address for %s: %v", msg, err) + break + } - pkScript, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } + _, pkScript := address.PaymentScript() - // Without treasury agenda. - if err := signAndCheck(msg, tx, i, pkScript, hashType, - mkGetKey(map[string]addressToKey{ - address.Address(): {keyDB, suite, false}, - }), mkGetScript(nil), noTreasury); err != nil { - t.Error(err) - break - } + // Without treasury agenda. + suite := dcrec.STEcdsaSecp256k1 + if err := signAndCheck(msg, tx, i, pkScript, hashType, + mkGetKey(map[string]addressToKey{ + address.Address(): {keyDB, suite, false}, + }), mkGetScript(nil), noTreasury); err != nil { + t.Error(err) + break + } - if err := signBadAndCheck(msg, tx, i, pkScript, hashType, - mkGetKey(map[string]addressToKey{ - address.Address(): {keyDB, dcrec.STEcdsaSecp256k1, false}, - }), mkGetScript(nil), noTreasury); err == nil { - t.Errorf("corrupted signature validated: %s", msg) - break - } + if err := signBadAndCheck(msg, tx, i, pkScript, hashType, + mkGetKey(map[string]addressToKey{ + address.Address(): {keyDB, dcrec.STEcdsaSecp256k1, false}, + }), mkGetScript(nil), noTreasury); err == nil { + t.Errorf("corrupted signature validated: %s", msg) + break + } - // With treasury agenda. - if err := signAndCheck(msg, tx, i, pkScript, hashType, - mkGetKey(map[string]addressToKey{ - address.Address(): {keyDB, suite, false}, - }), mkGetScript(nil), withTreasury); err != nil { - t.Error(err) - break - } + // With treasury agenda. + if err := signAndCheck(msg, tx, i, pkScript, hashType, + mkGetKey(map[string]addressToKey{ + address.Address(): {keyDB, suite, false}, + }), mkGetScript(nil), withTreasury); err != nil { + t.Error(err) + break + } - if err := signBadAndCheck(msg, tx, i, pkScript, hashType, - mkGetKey(map[string]addressToKey{ - address.Address(): {keyDB, dcrec.STEcdsaSecp256k1, false}, - }), mkGetScript(nil), withTreasury); err == nil { - t.Errorf("corrupted signature validated: %s", msg) - break - } + if err := signBadAndCheck(msg, tx, i, pkScript, hashType, + mkGetKey(map[string]addressToKey{ + address.Address(): {keyDB, dcrec.STEcdsaSecp256k1, false}, + }), mkGetScript(nil), withTreasury); err == nil { + t.Errorf("corrupted signature validated: %s", msg) + break } } } @@ -916,61 +893,50 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte - var address dcrutil.Address - var err error + var keyDB []byte msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() pk := privKey.PubKey() - // For address generation, consensus rules require using - // a compressed public key. Look up ExtractPkScriptAddrs - // for more details - address, err = dcrutil.NewAddressSecpPubKeyCompressed(pk, + address, err = stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pk, testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) } case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeUncompressed() - address, err = dcrutil.NewAddressEdwardsPubKey(pkBytes, + pkBytes := pk.SerializeUncompressed() + address, err = stdaddr.NewAddressPubKeyEd25519V0Raw(pkBytes, testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) } case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() - address, err = dcrutil.NewAddressSecSchnorrPubKey(pkBytes, + pk := privKey.PubKey() + address, err = stdaddr.NewAddressPubKeySchnorrSecp256k1V0(pk, testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) } } - pkScript, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } + _, pkScript := address.PaymentScript() // Without treasury agenda. sigScript, err := SignTxOutput(testingParams, tx, i, pkScript, hashType, mkGetKeyPub(map[string]addressToKey{ - address.String(): {keyDB, suite, false}, + address.Address(): {keyDB, suite, false}, }), mkGetScript(nil), nil, noTreasury) if err != nil { t.Errorf("failed to sign output %s: %v", msg, @@ -982,7 +948,7 @@ func TestSignTxOutput(t *testing.T) { sigScript, err = SignTxOutput(testingParams, tx, i, pkScript, hashType, mkGetKeyPub(map[string]addressToKey{ - address.String(): {keyDB, suite, false}, + address.Address(): {keyDB, suite, false}, }), mkGetScript(nil), sigScript, noTreasury) if err != nil { t.Errorf("failed to sign output %s a "+ @@ -999,7 +965,7 @@ func TestSignTxOutput(t *testing.T) { sigScript, err = SignTxOutput(testingParams, tx, i, pkScript, hashType, mkGetKeyPub(map[string]addressToKey{ - address.String(): {keyDB, suite, false}, + address.Address(): {keyDB, suite, false}, }), mkGetScript(nil), nil, withTreasury) if err != nil { t.Errorf("failed to sign output %s: %v", msg, @@ -1011,7 +977,7 @@ func TestSignTxOutput(t *testing.T) { sigScript, err = SignTxOutput(testingParams, tx, i, pkScript, hashType, mkGetKeyPub(map[string]addressToKey{ - address.String(): {keyDB, suite, false}, + address.Address(): {keyDB, suite, false}, }), mkGetScript(nil), sigScript, withTreasury) if err != nil { t.Errorf("failed to sign output %s a "+ @@ -1031,60 +997,49 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte - var address dcrutil.Address - var err error + var keyDB []byte msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() pk := privKey.PubKey() - // For address generation, consensus rules require using - // a compressed public key. Look up ExtractPkScriptAddrs - // for more details - address, err = dcrutil.NewAddressSecpPubKeyCompressed(pk, + address, err = stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pk, testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) } case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeCompressed() - address, err = dcrutil.NewAddressEdwardsPubKey(pkBytes, + pkBytes := pk.SerializeCompressed() + address, err = stdaddr.NewAddressPubKeyEd25519V0Raw(pkBytes, testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) } case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() - address, err = dcrutil.NewAddressSecSchnorrPubKey(pkBytes, + pk := privKey.PubKey() + address, err = stdaddr.NewAddressPubKeySchnorrSecp256k1V0(pk, testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) } } - pkScript, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } + _, pkScript := address.PaymentScript() // Without treasury agenda. if err := signAndCheck(msg, tx, i, pkScript, hashType, mkGetKeyPub(map[string]addressToKey{ - address.String(): {keyDB, suite, true}, + address.Address(): {keyDB, suite, true}, }), mkGetScript(nil), noTreasury); err != nil { t.Error(err) break @@ -1092,7 +1047,7 @@ func TestSignTxOutput(t *testing.T) { if err := signBadAndCheck(msg, tx, i, pkScript, hashType, mkGetKeyPub(map[string]addressToKey{ - address.String(): {keyDB, suite, true}, + address.Address(): {keyDB, suite, true}, }), mkGetScript(nil), noTreasury); err == nil { t.Errorf("corrupted signature validated: %s", msg) break @@ -1101,7 +1056,7 @@ func TestSignTxOutput(t *testing.T) { // With treasury agenda. if err := signAndCheck(msg, tx, i, pkScript, hashType, mkGetKeyPub(map[string]addressToKey{ - address.String(): {keyDB, suite, true}, + address.Address(): {keyDB, suite, true}, }), mkGetScript(nil), withTreasury); err != nil { t.Error(err) break @@ -1109,7 +1064,7 @@ func TestSignTxOutput(t *testing.T) { if err := signBadAndCheck(msg, tx, i, pkScript, hashType, mkGetKeyPub(map[string]addressToKey{ - address.String(): {keyDB, suite, true}, + address.Address(): {keyDB, suite, true}, }), mkGetScript(nil), withTreasury); err == nil { t.Errorf("corrupted signature validated: %s", msg) break @@ -1122,52 +1077,44 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte - var address dcrutil.Address - var err error + var keyDB []byte msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() pk := privKey.PubKey() - address, err = dcrutil.NewAddressSecpPubKeyCompressed(pk, + address, err = stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pk, testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) } case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeCompressed() - address, err = dcrutil.NewAddressEdwardsPubKey(pkBytes, + pkBytes := pk.SerializeCompressed() + address, err = stdaddr.NewAddressPubKeyEd25519V0Raw(pkBytes, testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) } case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() - address, err = dcrutil.NewAddressSecSchnorrPubKey(pkBytes, + pk := privKey.PubKey() + address, err = stdaddr.NewAddressPubKeySchnorrSecp256k1V0(pk, testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) } } - pkScript, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } + _, pkScript := address.PaymentScript() // Without treasury agenda. sigScript, err := SignTxOutput(testingParams, @@ -1241,55 +1188,51 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte + var keyDB []byte + msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeUncompressed() + pkBytes := privKey.PubKey().SerializeUncompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + h160, testingParams) + case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeUncompressed() + pkBytes := pk.SerializeUncompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEd25519V0(h160, + testingParams) + case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() + pkBytes := privKey.PubKey().SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashSchnorrSecp256k1V0( + h160, testingParams) } - - msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - - address, err := dcrutil.NewAddressPubKeyHash( - dcrutil.Hash160(pkBytes), testingParams, suite) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } - pkScript, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - break - } + _, pkScript := address.PaymentScript() - scriptAddr, err := dcrutil.NewAddressScriptHash( - pkScript, testingParams) + scriptAddr, err := stdaddr.NewAddressScriptHashV0(pkScript, + testingParams) if err != nil { - t.Errorf("failed to make p2sh addr for %s: %v", - msg, err) + t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } - scriptPkScript, err := PayToAddrScript( - scriptAddr) - if err != nil { - t.Errorf("failed to make script pkscript for "+ - "%s: %v", msg, err) - break - } + _, scriptPkScript := scriptAddr.PaymentScript() // Without treasury agenda. if err := signAndCheck(msg, tx, i, scriptPkScript, @@ -1338,55 +1281,51 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte + var keyDB []byte + msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeUncompressed() + pkBytes := privKey.PubKey().SerializeUncompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + h160, testingParams) + case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeUncompressed() + pkBytes := pk.SerializeUncompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEd25519V0(h160, + testingParams) + case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() + pkBytes := privKey.PubKey().SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashSchnorrSecp256k1V0( + h160, testingParams) } - - msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - - address, err := dcrutil.NewAddressPubKeyHash( - dcrutil.Hash160(pkBytes), testingParams, suite) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } - pkScript, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - break - } + _, pkScript := address.PaymentScript() - scriptAddr, err := dcrutil.NewAddressScriptHash( - pkScript, testingParams) + scriptAddr, err := stdaddr.NewAddressScriptHashV0(pkScript, + testingParams) if err != nil { - t.Errorf("failed to make p2sh addr for %s: %v", - msg, err) + t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } - scriptPkScript, err := PayToAddrScript( - scriptAddr) - if err != nil { - t.Errorf("failed to make script pkscript for "+ - "%s: %v", msg, err) - break - } + _, scriptPkScript := scriptAddr.PaymentScript() // Without treasury agenda. _, err = SignTxOutput(testingParams, tx, i, @@ -1465,54 +1404,51 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte + var keyDB []byte + msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() + pkBytes := privKey.PubKey().SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + h160, testingParams) + case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeCompressed() + pkBytes := pk.SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEd25519V0(h160, + testingParams) + case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() + pkBytes := privKey.PubKey().SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashSchnorrSecp256k1V0( + h160, testingParams) } - - msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - - address, err := dcrutil.NewAddressPubKeyHash( - dcrutil.Hash160(pkBytes), testingParams, suite) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } - pkScript, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } + _, pkScript := address.PaymentScript() - scriptAddr, err := dcrutil.NewAddressScriptHash( - pkScript, testingParams) + scriptAddr, err := stdaddr.NewAddressScriptHashV0(pkScript, + testingParams) if err != nil { - t.Errorf("failed to make p2sh addr for %s: %v", - msg, err) + t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } - scriptPkScript, err := PayToAddrScript( - scriptAddr) - if err != nil { - t.Errorf("failed to make script pkscript for "+ - "%s: %v", msg, err) - break - } + _, scriptPkScript := scriptAddr.PaymentScript() // Without treasury agenda. if err := signAndCheck(msg, tx, i, scriptPkScript, @@ -1561,54 +1497,51 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte + var keyDB []byte + msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() + pkBytes := privKey.PubKey().SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + h160, testingParams) + case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeCompressed() + pkBytes := pk.SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashEd25519V0(h160, + testingParams) + case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() + pkBytes := privKey.PubKey().SerializeCompressed() + h160 := stdaddr.Hash160(pkBytes) + address, err = stdaddr.NewAddressPubKeyHashSchnorrSecp256k1V0( + h160, testingParams) } - - msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - - address, err := dcrutil.NewAddressPubKeyHash( - dcrutil.Hash160(pkBytes), testingParams, suite) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } - pkScript, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } + _, pkScript := address.PaymentScript() - scriptAddr, err := dcrutil.NewAddressScriptHash( - pkScript, testingParams) + scriptAddr, err := stdaddr.NewAddressScriptHashV0(pkScript, + testingParams) if err != nil { - t.Errorf("failed to make p2sh addr for %s: %v", - msg, err) + t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } - scriptPkScript, err := PayToAddrScript( - scriptAddr) - if err != nil { - t.Errorf("failed to make script pkscript for "+ - "%s: %v", msg, err) - break - } + _, scriptPkScript := scriptAddr.PaymentScript() // Without treasury agenda. _, err = SignTxOutput(testingParams, @@ -1689,70 +1622,48 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte - var address dcrutil.Address - var err error + var keyDB []byte msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() pk := privKey.PubKey() - // For address generation, consensus rules require using - // a compressed public key. Look up ExtractPkScriptAddrs - // for more details - address, err = dcrutil.NewAddressSecpPubKeyCompressed(pk, + address, err = stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pk, testingParams) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - } case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeUncompressed() - address, err = dcrutil.NewAddressEdwardsPubKey(pkBytes, + pkBytes := pk.SerializeUncompressed() + address, err = stdaddr.NewAddressPubKeyEd25519V0Raw(pkBytes, testingParams) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - } case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() - address, err = dcrutil.NewAddressSecSchnorrPubKey(pkBytes, + pk := privKey.PubKey() + address, err = stdaddr.NewAddressPubKeySchnorrSecp256k1V0(pk, testingParams) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - } } - - pkScript, err := PayToAddrScript(address) if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) + break } - scriptAddr, err := dcrutil.NewAddressScriptHash( - pkScript, testingParams) - if err != nil { - t.Errorf("failed to make p2sh addr for %s: %v", - msg, err) - } + _, pkScript := address.PaymentScript() - scriptPkScript, err := PayToAddrScript( - scriptAddr) + scriptAddr, err := stdaddr.NewAddressScriptHashV0(pkScript, + testingParams) if err != nil { - t.Errorf("failed to make script pkscript for "+ - "%s: %v", msg, err) + t.Errorf("failed to make p2sh addr for %s: %v", msg, err) } + _, scriptPkScript := scriptAddr.PaymentScript() + // Without treasury agenda. if err := signAndCheck(msg, tx, i, scriptPkScript, hashType, @@ -1798,70 +1709,48 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte - var address dcrutil.Address - var err error + var keyDB []byte msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() pk := privKey.PubKey() - // For address generation, consensus rules require using - // a compressed public key. Look up ExtractPkScriptAddrs - // for more details - address, err = dcrutil.NewAddressSecpPubKeyCompressed(pk, + address, err = stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pk, testingParams) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - } case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeUncompressed() - address, err = dcrutil.NewAddressEdwardsPubKey(pkBytes, + pkBytes := pk.SerializeUncompressed() + address, err = stdaddr.NewAddressPubKeyEd25519V0Raw(pkBytes, testingParams) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - } case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() - address, err = dcrutil.NewAddressSecSchnorrPubKey(pkBytes, + pk := privKey.PubKey() + address, err = stdaddr.NewAddressPubKeySchnorrSecp256k1V0(pk, testingParams) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - } } - - pkScript, err := PayToAddrScript(address) if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) + break } - scriptAddr, err := dcrutil.NewAddressScriptHash( - pkScript, testingParams) - if err != nil { - t.Errorf("failed to make p2sh addr for %s: %v", - msg, err) - } + _, pkScript := address.PaymentScript() - scriptPkScript, err := PayToAddrScript( - scriptAddr) + scriptAddr, err := stdaddr.NewAddressScriptHashV0(pkScript, + testingParams) if err != nil { - t.Errorf("failed to make script pkscript for "+ - "%s: %v", msg, err) + t.Errorf("failed to make p2sh addr for %s: %v", msg, err) } + _, scriptPkScript := scriptAddr.PaymentScript() + // Without treasury agenda. _, err = SignTxOutput(testingParams, tx, i, scriptPkScript, hashType, @@ -1941,69 +1830,49 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte - var address dcrutil.Address - var err error + var keyDB []byte msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() pk := privKey.PubKey() - address, err = dcrutil.NewAddressSecpPubKeyCompressed(pk, + address, err = stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pk, testingParams) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - } case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeCompressed() - address, err = dcrutil.NewAddressEdwardsPubKey(pkBytes, + pkBytes := pk.SerializeCompressed() + address, err = stdaddr.NewAddressPubKeyEd25519V0Raw(pkBytes, testingParams) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - } case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() - address, err = dcrutil.NewAddressSecSchnorrPubKey(pkBytes, + pk := privKey.PubKey() + address, err = stdaddr.NewAddressPubKeySchnorrSecp256k1V0(pk, testingParams) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - } - } - - pkScript, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) } - - scriptAddr, err := dcrutil.NewAddressScriptHash( - pkScript, testingParams) if err != nil { - t.Errorf("failed to make p2sh addr for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } - scriptPkScript, err := PayToAddrScript( - scriptAddr) + _, pkScript := address.PaymentScript() + + scriptAddr, err := stdaddr.NewAddressScriptHashV0(pkScript, + testingParams) if err != nil { - t.Errorf("failed to make script pkscript for "+ - "%s: %v", msg, err) + t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } + _, scriptPkScript := scriptAddr.PaymentScript() + // Without treasury agenda. if err := signAndCheck(msg, tx, i, scriptPkScript, hashType, @@ -2051,69 +1920,49 @@ func TestSignTxOutput(t *testing.T) { for _, hashType := range hashTypes { for _, suite := range signatureSuites { for i := range tx.TxIn { - var keyDB, pkBytes []byte - var address dcrutil.Address - var err error + var keyDB []byte msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite) - + var address stdaddr.Address + var err error switch suite { case dcrec.STEcdsaSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() pk := privKey.PubKey() - address, err = dcrutil.NewAddressSecpPubKeyCompressed(pk, + address, err = stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pk, testingParams) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - } case dcrec.STEd25519: keyDB, _, _, _ = edwards.GenerateKey(rand.Reader) _, pk := edwards.PrivKeyFromBytes(keyDB) - pkBytes = pk.SerializeCompressed() - address, err = dcrutil.NewAddressEdwardsPubKey(pkBytes, + pkBytes := pk.SerializeCompressed() + address, err = stdaddr.NewAddressPubKeyEd25519V0Raw(pkBytes, testingParams) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - } case dcrec.STSchnorrSecp256k1: privKey, _ := secp256k1.GeneratePrivateKey() keyDB = privKey.Serialize() - pkBytes = privKey.PubKey().SerializeCompressed() - address, err = dcrutil.NewAddressSecSchnorrPubKey(pkBytes, + pk := privKey.PubKey() + address, err = stdaddr.NewAddressPubKeySchnorrSecp256k1V0(pk, testingParams) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - } } - - pkScript, err := PayToAddrScript(address) if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) - } - - scriptAddr, err := dcrutil.NewAddressScriptHash( - pkScript, testingParams) - if err != nil { - t.Errorf("failed to make p2sh addr for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } - scriptPkScript, err := PayToAddrScript( - scriptAddr) + _, pkScript := address.PaymentScript() + + scriptAddr, err := stdaddr.NewAddressScriptHashV0(pkScript, + testingParams) if err != nil { - t.Errorf("failed to make script pkscript for "+ - "%s: %v", msg, err) + t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } + _, scriptPkScript := scriptAddr.PaymentScript() + // Without treasury agenda. _, err = SignTxOutput(testingParams, tx, i, scriptPkScript, hashType, @@ -2201,13 +2050,11 @@ func TestSignTxOutput(t *testing.T) { } keyDB1 := privKey1.Serialize() pk1 := privKey1.PubKey() - suite1 := dcrec.STEcdsaSecp256k1 - address1, err := dcrutil.NewAddressSecpPubKeyCompressed(pk1, + address1, err := stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pk1, testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } @@ -2218,39 +2065,32 @@ func TestSignTxOutput(t *testing.T) { } keyDB2 := privKey2.Serialize() pk2 := privKey2.PubKey() - suite2 := dcrec.STEcdsaSecp256k1 - address2, err := dcrutil.NewAddressSecpPubKeyCompressed(pk2, + address2, err := stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pk2, testingParams) if err != nil { - t.Errorf("failed to make address 2 for %s: %v", - msg, err) + t.Errorf("failed to make address 2 for %s: %v", msg, err) break } pkScript, err := MultiSigScript(2, pk1.SerializeCompressed(), pk2.SerializeCompressed()) if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) + t.Errorf("failed to make pkscript for %s: %v", msg, err) } - scriptAddr, err := dcrutil.NewAddressScriptHash( - pkScript, testingParams) + scriptAddr, err := stdaddr.NewAddressScriptHashV0(pkScript, + testingParams) if err != nil { - t.Errorf("failed to make p2sh addr for %s: %v", - msg, err) + t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } - scriptPkScript, err := PayToAddrScript(scriptAddr) - if err != nil { - t.Errorf("failed to make script pkscript for "+ - "%s: %v", msg, err) - break - } + _, scriptPkScript := scriptAddr.PaymentScript() // Without treasury agenda. + suite1 := dcrec.STEcdsaSecp256k1 + suite2 := dcrec.STEcdsaSecp256k1 if err := signAndCheck(msg, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ @@ -2308,13 +2148,11 @@ func TestSignTxOutput(t *testing.T) { } keyDB1 := privKey1.Serialize() pk1 := privKey1.PubKey() - suite1 := dcrec.STEcdsaSecp256k1 - address1, err := dcrutil.NewAddressSecpPubKeyCompressed(pk1, + address1, err := stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pk1, testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } @@ -2325,13 +2163,11 @@ func TestSignTxOutput(t *testing.T) { } keyDB2 := privKey2.Serialize() pk2 := privKey2.PubKey() - suite2 := dcrec.STEcdsaSecp256k1 - address2, err := dcrutil.NewAddressSecpPubKeyCompressed(pk2, + address2, err := stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pk2, testingParams) if err != nil { - t.Errorf("failed to make address 2 for %s: %v", - msg, err) + t.Errorf("failed to make address 2 for %s: %v", msg, err) break } @@ -2342,22 +2178,18 @@ func TestSignTxOutput(t *testing.T) { "for %s: %v", msg, err) } - scriptAddr, err := dcrutil.NewAddressScriptHash( - pkScript, testingParams) + scriptAddr, err := stdaddr.NewAddressScriptHashV0(pkScript, + testingParams) if err != nil { - t.Errorf("failed to make p2sh addr for %s: %v", - msg, err) + t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } - scriptPkScript, err := PayToAddrScript(scriptAddr) - if err != nil { - t.Errorf("failed to make script pkscript for "+ - "%s: %v", msg, err) - break - } + _, scriptPkScript := scriptAddr.PaymentScript() // Without treasury agenda. + suite1 := dcrec.STEcdsaSecp256k1 + suite2 := dcrec.STEcdsaSecp256k1 sigScript, err := SignTxOutput(testingParams, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ @@ -2456,13 +2288,11 @@ func TestSignTxOutput(t *testing.T) { } keyDB1 := privKey1.Serialize() pk1 := privKey1.PubKey() - suite1 := dcrec.STEcdsaSecp256k1 - address1, err := dcrutil.NewAddressSecpPubKeyCompressed(pk1, + address1, err := stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pk1, testingParams) if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) + t.Errorf("failed to make address for %s: %v", msg, err) break } @@ -2473,38 +2303,35 @@ func TestSignTxOutput(t *testing.T) { } keyDB2 := privKey2.Serialize() pk2 := privKey2.PubKey() - suite2 := dcrec.STEcdsaSecp256k1 - address2, err := dcrutil.NewAddressSecpPubKeyCompressed(pk2, + address2, err := stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pk2, testingParams) if err != nil { - t.Errorf("failed to make address 2 for %s: %v", - msg, err) + t.Errorf("failed to make address 2 for %s: %v", msg, err) break } pkScript, err := MultiSigScript(2, pk1.SerializeCompressed(), pk2.SerializeCompressed()) if err != nil { - t.Errorf("failed to make pkscript "+ - "for %s: %v", msg, err) + t.Errorf("failed to make pkscript for %s: %v", msg, err) } - scriptAddr, err := dcrutil.NewAddressScriptHash( - pkScript, testingParams) + scriptAddr, err := stdaddr.NewAddressScriptHashV0(pkScript, + testingParams) if err != nil { - t.Errorf("failed to make p2sh addr for %s: %v", - msg, err) + t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } - scriptPkScript, err := PayToAddrScript(scriptAddr) + _, scriptPkScript := scriptAddr.PaymentScript() if err != nil { - t.Errorf("failed to make script pkscript for "+ - "%s: %v", msg, err) + t.Errorf("failed to make script pkscript for %s: %v", msg, err) break } // Without treasury agenda. + suite1 := dcrec.STEcdsaSecp256k1 + suite2 := dcrec.STEcdsaSecp256k1 sigScript, err := SignTxOutput(testingParams, tx, i, scriptPkScript, hashType, mkGetKey(map[string]addressToKey{ @@ -2622,14 +2449,14 @@ var ( 0xac, 0x70, 0x7f, 0x3d, 0xa4, 0x39, 0x5e, 0xcb, 0x3b, 0xb0, 0xd6, 0x0e, 0x06, 0x92} thisPubKey = secp256k1.PrivKeyFromBytes(privKeyD).PubKey() - thisAddressUnc, _ = dcrutil.NewAddressPubKeyHash( - dcrutil.Hash160(thisPubKey.SerializeUncompressed()), - testingParams, dcrec.STEcdsaSecp256k1) - uncompressedPkScript, _ = PayToAddrScript(thisAddressUnc) - thisAddressCom, _ = dcrutil.NewAddressPubKeyHash( - dcrutil.Hash160(thisPubKey.SerializeCompressed()), - testingParams, dcrec.STEcdsaSecp256k1) - compressedPkScript, _ = PayToAddrScript(thisAddressCom) + thisAddressUnc, _ = stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + stdaddr.Hash160(thisPubKey.SerializeUncompressed()), + testingParams) + _, uncompressedPkScript = thisAddressUnc.PaymentScript() + thisAddressCom, _ = stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0( + stdaddr.Hash160(thisPubKey.SerializeCompressed()), + testingParams) + _, compressedPkScript = thisAddressCom.PaymentScript() shortPkScript = []byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5, 0xeb, 0xa4, 0x02, 0xcb, 0x68, 0xe0, 0x69, 0x56, 0xbf, 0x32, 0x53, 0x90, 0x0e, 0x0a, 0x88, 0xac} diff --git a/txscript/standard.go b/txscript/standard.go index 4b15e1f87c..098e123121 100644 --- a/txscript/standard.go +++ b/txscript/standard.go @@ -1,5 +1,5 @@ // Copyright (c) 2013-2017 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -12,18 +12,13 @@ import ( "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/dcrec" "github.com/decred/dcrd/dcrec/secp256k1/v4" - "github.com/decred/dcrd/dcrutil/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" ) const ( // MaxDataCarrierSize is the maximum number of bytes allowed in pushed // data to be considered a nulldata transaction. MaxDataCarrierSize = 256 - - // nilAddrErrStr is the common error string to use for attempts to - // generate payment scripts to nil addresses embedded within a - // dcrutil.Address interface. - nilAddrErrStr = "unable to generate payment script for nil address" ) // ScriptClass is an enumeration for the list of standard types of script. @@ -743,327 +738,6 @@ func MultisigRedeemScriptFromScriptSig(script []byte) []byte { return finalOpcodeData(scriptVersion, script) } -// payToPubKeyHashScript creates a new script to pay a transaction -// output to a 20-byte pubkey hash. It is expected that the input is a valid -// hash. -func payToPubKeyHashScript(pubKeyHash []byte) ([]byte, error) { - return NewScriptBuilder().AddOp(OP_DUP).AddOp(OP_HASH160). - AddData(pubKeyHash).AddOp(OP_EQUALVERIFY).AddOp(OP_CHECKSIG). - Script() -} - -// payToPubKeyHashEdwardsScript creates a new script to pay a transaction -// output to a 20-byte pubkey hash of an Edwards public key. It is expected -// that the input is a valid hash. -func payToPubKeyHashEdwardsScript(pubKeyHash []byte) ([]byte, error) { - edwardsData := []byte{byte(dcrec.STEd25519)} - return NewScriptBuilder().AddOp(OP_DUP).AddOp(OP_HASH160). - AddData(pubKeyHash).AddOp(OP_EQUALVERIFY).AddData(edwardsData). - AddOp(OP_CHECKSIGALT).Script() -} - -// payToPubKeyHashSchnorrScript creates a new script to pay a transaction -// output to a 20-byte pubkey hash of a secp256k1 public key, but expecting -// a schnorr signature instead of a classic secp256k1 signature. It is -// expected that the input is a valid hash. -func payToPubKeyHashSchnorrScript(pubKeyHash []byte) ([]byte, error) { - schnorrData := []byte{byte(dcrec.STSchnorrSecp256k1)} - return NewScriptBuilder().AddOp(OP_DUP).AddOp(OP_HASH160). - AddData(pubKeyHash).AddOp(OP_EQUALVERIFY).AddData(schnorrData). - AddOp(OP_CHECKSIGALT).Script() -} - -// payToScriptHashScript creates a new script to pay a transaction output to a -// script hash. It is expected that the input is a valid hash. -func payToScriptHashScript(scriptHash []byte) ([]byte, error) { - return NewScriptBuilder().AddOp(OP_HASH160).AddData(scriptHash). - AddOp(OP_EQUAL).Script() -} - -// PayToScriptHashScript is the exported version of payToScriptHashScript. -func PayToScriptHashScript(scriptHash []byte) ([]byte, error) { - return payToScriptHashScript(scriptHash) -} - -// payToPubkeyScript creates a new script to pay a transaction output to a -// public key. It is expected that the input is a valid pubkey. -func payToPubKeyScript(serializedPubKey []byte) ([]byte, error) { - return NewScriptBuilder().AddData(serializedPubKey). - AddOp(OP_CHECKSIG).Script() -} - -// payToEdwardsPubKeyScript creates a new script to pay a transaction output -// to an Ed25519 public key. It is expected that the input is a valid pubkey. -func payToEdwardsPubKeyScript(serializedPubKey []byte) ([]byte, error) { - edwardsData := []byte{byte(dcrec.STEd25519)} - return NewScriptBuilder().AddData(serializedPubKey).AddData(edwardsData). - AddOp(OP_CHECKSIGALT).Script() -} - -// payToSchnorrPubKeyScript creates a new script to pay a transaction output -// to a secp256k1 public key, but to be signed by Schnorr type signature. It -// is expected that the input is a valid pubkey. -func payToSchnorrPubKeyScript(serializedPubKey []byte) ([]byte, error) { - schnorrData := []byte{byte(dcrec.STSchnorrSecp256k1)} - return NewScriptBuilder().AddData(serializedPubKey).AddData(schnorrData). - AddOp(OP_CHECKSIGALT).Script() -} - -// PayToSStx creates a new script to pay a transaction output to a script hash or -// public key hash, but tags the output with OP_SSTX. For use in constructing -// valid SStxs. -func PayToSStx(addr dcrutil.Address) ([]byte, error) { - // Only pay to pubkey hash and pay to script hash are - // supported. - scriptType := PubKeyHashTy - switch addr := addr.(type) { - case *dcrutil.AddressPubKeyHash: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - if addr.DSA() != dcrec.STEcdsaSecp256k1 { - str := "unable to generate payment script for " + - "unsupported digital signature algorithm" - return nil, scriptError(ErrUnsupportedAddress, str) - } - - case *dcrutil.AddressScriptHash: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - scriptType = ScriptHashTy - - default: - str := fmt.Sprintf("unable to generate payment script for "+ - "unsupported address type %T", addr) - return nil, scriptError(ErrUnsupportedAddress, str) - } - - hash := addr.ScriptAddress() - - if scriptType == PubKeyHashTy { - return NewScriptBuilder().AddOp(OP_SSTX).AddOp(OP_DUP). - AddOp(OP_HASH160).AddData(hash).AddOp(OP_EQUALVERIFY). - AddOp(OP_CHECKSIG).Script() - } - return NewScriptBuilder().AddOp(OP_SSTX).AddOp(OP_HASH160). - AddData(hash).AddOp(OP_EQUAL).Script() -} - -// PayToSStxChange creates a new script to pay a transaction output to a -// public key hash, but tags the output with OP_SSTXCHANGE. For use in constructing -// valid SStxs. -func PayToSStxChange(addr dcrutil.Address) ([]byte, error) { - // Only pay to pubkey hash and pay to script hash are - // supported. - scriptType := PubKeyHashTy - switch addr := addr.(type) { - case *dcrutil.AddressPubKeyHash: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - if addr.DSA() != dcrec.STEcdsaSecp256k1 { - str := "unable to generate payment script for " + - "unsupported digital signature algorithm" - return nil, scriptError(ErrUnsupportedAddress, str) - } - - case *dcrutil.AddressScriptHash: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - scriptType = ScriptHashTy - - default: - str := fmt.Sprintf("unable to generate payment script for "+ - "unsupported address type %T", addr) - return nil, scriptError(ErrUnsupportedAddress, str) - } - - hash := addr.ScriptAddress() - - if scriptType == PubKeyHashTy { - return NewScriptBuilder().AddOp(OP_SSTXCHANGE).AddOp(OP_DUP). - AddOp(OP_HASH160).AddData(hash).AddOp(OP_EQUALVERIFY). - AddOp(OP_CHECKSIG).Script() - } - return NewScriptBuilder().AddOp(OP_SSTXCHANGE).AddOp(OP_HASH160). - AddData(hash).AddOp(OP_EQUAL).Script() -} - -// PayToSSGen creates a new script to pay a transaction output to a public key -// hash or script hash, but tags the output with OP_SSGEN. For use in constructing -// valid SSGen txs. -func PayToSSGen(addr dcrutil.Address) ([]byte, error) { - // Only pay to pubkey hash and pay to script hash are - // supported. - scriptType := PubKeyHashTy - switch addr := addr.(type) { - case *dcrutil.AddressPubKeyHash: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - if addr.DSA() != dcrec.STEcdsaSecp256k1 { - str := "unable to generate payment script for " + - "unsupported digital signature algorithm" - return nil, scriptError(ErrUnsupportedAddress, str) - } - - case *dcrutil.AddressScriptHash: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - scriptType = ScriptHashTy - - default: - str := fmt.Sprintf("unable to generate payment script for "+ - "unsupported address type %T", addr) - return nil, scriptError(ErrUnsupportedAddress, str) - } - - hash := addr.ScriptAddress() - - if scriptType == PubKeyHashTy { - return NewScriptBuilder().AddOp(OP_SSGEN).AddOp(OP_DUP). - AddOp(OP_HASH160).AddData(hash).AddOp(OP_EQUALVERIFY). - AddOp(OP_CHECKSIG).Script() - } - return NewScriptBuilder().AddOp(OP_SSGEN).AddOp(OP_HASH160). - AddData(hash).AddOp(OP_EQUAL).Script() -} - -// PayToSSGenPKHDirect creates a new script to pay a transaction output to a -// public key hash, but tags the output with OP_SSGEN. For use in constructing -// valid SSGen txs. Unlike PayToSSGen, this function directly uses the HASH160 -// pubkeyhash (instead of an address). -func PayToSSGenPKHDirect(pkh []byte) ([]byte, error) { - return NewScriptBuilder().AddOp(OP_SSGEN).AddOp(OP_DUP). - AddOp(OP_HASH160).AddData(pkh).AddOp(OP_EQUALVERIFY). - AddOp(OP_CHECKSIG).Script() -} - -// PayToSSGenSHDirect creates a new script to pay a transaction output to a -// script hash, but tags the output with OP_SSGEN. For use in constructing -// valid SSGen txs. Unlike PayToSSGen, this function directly uses the HASH160 -// script hash (instead of an address). -func PayToSSGenSHDirect(sh []byte) ([]byte, error) { - return NewScriptBuilder().AddOp(OP_SSGEN).AddOp(OP_HASH160). - AddData(sh).AddOp(OP_EQUAL).Script() -} - -// PayToSSRtx creates a new script to pay a transaction output to a -// public key hash, but tags the output with OP_SSRTX. For use in constructing -// valid SSRtx. -func PayToSSRtx(addr dcrutil.Address) ([]byte, error) { - // Only pay to pubkey hash and pay to script hash are - // supported. - scriptType := PubKeyHashTy - switch addr := addr.(type) { - case *dcrutil.AddressPubKeyHash: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - if addr.DSA() != dcrec.STEcdsaSecp256k1 { - str := "unable to generate payment script for " + - "unsupported digital signature algorithm" - return nil, scriptError(ErrUnsupportedAddress, str) - } - - case *dcrutil.AddressScriptHash: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - scriptType = ScriptHashTy - - default: - str := fmt.Sprintf("unable to generate payment script for "+ - "unsupported address type %T", addr) - return nil, scriptError(ErrUnsupportedAddress, str) - } - - hash := addr.ScriptAddress() - - if scriptType == PubKeyHashTy { - return NewScriptBuilder().AddOp(OP_SSRTX).AddOp(OP_DUP). - AddOp(OP_HASH160).AddData(hash).AddOp(OP_EQUALVERIFY). - AddOp(OP_CHECKSIG).Script() - } - return NewScriptBuilder().AddOp(OP_SSRTX).AddOp(OP_HASH160). - AddData(hash).AddOp(OP_EQUAL).Script() -} - -// PayToSSRtxPKHDirect creates a new script to pay a transaction output to a -// public key hash, but tags the output with OP_SSRTX. For use in constructing -// valid SSRtx. Unlike PayToSSRtx, this function directly uses the HASH160 -// pubkeyhash (instead of an address). -func PayToSSRtxPKHDirect(pkh []byte) ([]byte, error) { - return NewScriptBuilder().AddOp(OP_SSRTX).AddOp(OP_DUP). - AddOp(OP_HASH160).AddData(pkh).AddOp(OP_EQUALVERIFY). - AddOp(OP_CHECKSIG).Script() -} - -// PayToSSRtxSHDirect creates a new script to pay a transaction output to a -// script hash, but tags the output with OP_SSRTX. For use in constructing -// valid SSRtx. Unlike PayToSSRtx, this function directly uses the HASH160 -// script hash (instead of an address). -func PayToSSRtxSHDirect(sh []byte) ([]byte, error) { - return NewScriptBuilder().AddOp(OP_SSRTX).AddOp(OP_HASH160). - AddData(sh).AddOp(OP_EQUAL).Script() -} - -// GenerateSStxAddrPush generates an OP_RETURN push for SSGen payment addresses in -// an SStx. -func GenerateSStxAddrPush(addr dcrutil.Address, amount dcrutil.Amount, limits uint16) ([]byte, error) { - // Only pay to pubkey hash and pay to script hash are - // supported. - scriptType := PubKeyHashTy - switch addr := addr.(type) { - case *dcrutil.AddressPubKeyHash: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - if addr.DSA() != dcrec.STEcdsaSecp256k1 { - str := "unable to generate payment script for " + - "unsupported digital signature algorithm" - return nil, scriptError(ErrUnsupportedAddress, str) - } - - case *dcrutil.AddressScriptHash: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - scriptType = ScriptHashTy - - default: - str := fmt.Sprintf("unable to generate payment script for "+ - "unsupported address type %T", addr) - return nil, scriptError(ErrUnsupportedAddress, str) - } - - // Concatenate the prefix, pubkeyhash, and amount. - adBytes := make([]byte, 20+8+2) - copy(adBytes[0:20], addr.ScriptAddress()) - binary.LittleEndian.PutUint64(adBytes[20:28], uint64(amount)) - binary.LittleEndian.PutUint16(adBytes[28:30], limits) - - // Set the bit flag indicating pay to script hash. - if scriptType == ScriptHashTy { - adBytes[27] |= 1 << 7 - } - - return NewScriptBuilder().AddOp(OP_RETURN).AddData(adBytes).Script() -} - // GenerateSSGenBlockRef generates an OP_RETURN push for the block header hash and // height which the block votes on. func GenerateSSGenBlockRef(blockHash chainhash.Hash, height uint32) ([]byte, error) { @@ -1097,58 +771,6 @@ func GenerateProvablyPruneableOut(data []byte) ([]byte, error) { return NewScriptBuilder().AddOp(OP_RETURN).AddData(data).Script() } -// PayToAddrScript creates a new script to pay a transaction output to a the -// specified address. -func PayToAddrScript(addr dcrutil.Address) ([]byte, error) { - switch addr := addr.(type) { - case *dcrutil.AddressPubKeyHash: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - switch addr.DSA() { - case dcrec.STEcdsaSecp256k1: - return payToPubKeyHashScript(addr.ScriptAddress()) - case dcrec.STEd25519: - return payToPubKeyHashEdwardsScript(addr.ScriptAddress()) - case dcrec.STSchnorrSecp256k1: - return payToPubKeyHashSchnorrScript(addr.ScriptAddress()) - } - - case *dcrutil.AddressScriptHash: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - return payToScriptHashScript(addr.ScriptAddress()) - - case *dcrutil.AddressSecpPubKey: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - return payToPubKeyScript(addr.ScriptAddress()) - - case *dcrutil.AddressEdwardsPubKey: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - return payToEdwardsPubKeyScript(addr.ScriptAddress()) - - case *dcrutil.AddressSecSchnorrPubKey: - if addr == nil { - return nil, scriptError(ErrUnsupportedAddress, - nilAddrErrStr) - } - return payToSchnorrPubKeyScript(addr.ScriptAddress()) - } - - str := fmt.Sprintf("unable to generate payment script for unsupported "+ - "address type %T", addr) - return nil, scriptError(ErrUnsupportedAddress, str) -} - // MultiSigScript returns a valid script for a multisignature redemption where // the specified threshold number of the keys in the given public keys are // required to have signed the transaction for success. @@ -1209,11 +831,10 @@ func PushedData(script []byte) ([][]byte, error) { // pubKeyHashToAddrs is a convenience function to attempt to convert the // passed hash to a pay-to-pubkey-hash address housed within an address // slice. It is used to consolidate common code. -func pubKeyHashToAddrs(hash []byte, params dcrutil.AddressParams) []dcrutil.Address { +func pubKeyHashToAddrs(hash []byte, params stdaddr.AddressParams) []stdaddr.Address { // Skip the pubkey hash if it's invalid for some reason. - var addrs []dcrutil.Address - addr, err := dcrutil.NewAddressPubKeyHash(hash, params, - dcrec.STEcdsaSecp256k1) + var addrs []stdaddr.Address + addr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(hash, params) if err == nil { addrs = append(addrs, addr) } @@ -1223,10 +844,10 @@ func pubKeyHashToAddrs(hash []byte, params dcrutil.AddressParams) []dcrutil.Addr // scriptHashToAddrs is a convenience function to attempt to convert the passed // hash to a pay-to-script-hash address housed within an address slice. It is // used to consolidate common code. -func scriptHashToAddrs(hash []byte, params dcrutil.AddressParams) []dcrutil.Address { +func scriptHashToAddrs(hash []byte, params stdaddr.AddressParams) []stdaddr.Address { // Skip the hash if it's invalid for some reason. - var addrs []dcrutil.Address - addr, err := dcrutil.NewAddressScriptHashFromHash(hash, params) + var addrs []stdaddr.Address + addr, err := stdaddr.NewAddressScriptHashV0FromHash(hash, params) if err == nil { addrs = append(addrs, addr) } @@ -1241,7 +862,7 @@ func scriptHashToAddrs(hash []byte, params dcrutil.AddressParams) []dcrutil.Addr // NOTE: This function only attempts to identify version 0 scripts. The return // value will indicate a nonstandard script type for other script versions along // with an invalid script version error. -func ExtractPkScriptAddrs(version uint16, pkScript []byte, chainParams dcrutil.AddressParams, isTreasuryEnabled bool) (ScriptClass, []dcrutil.Address, int, error) { +func ExtractPkScriptAddrs(version uint16, pkScript []byte, chainParams stdaddr.AddressParams, isTreasuryEnabled bool) (ScriptClass, []stdaddr.Address, int, error) { if version != 0 { return NonStandardTy, nil, 0, fmt.Errorf("invalid script version") } @@ -1258,20 +879,32 @@ func ExtractPkScriptAddrs(version uint16, pkScript []byte, chainParams dcrutil.A // Check for pay-to-alt-pubkey-hash script. if data, sigType := extractPubKeyHashAltDetails(pkScript); data != nil { - var addrs []dcrutil.Address - addr, err := dcrutil.NewAddressPubKeyHash(data, chainParams, sigType) - if err == nil { - addrs = append(addrs, addr) + var addrs []stdaddr.Address + switch sigType { + case dcrec.STEd25519: + addr, err := stdaddr.NewAddressPubKeyHashEd25519(version, data, + chainParams) + if err == nil { + addrs = append(addrs, addr) + } + + case dcrec.STSchnorrSecp256k1: + addr, err := stdaddr.NewAddressPubKeyHashSchnorrSecp256k1(version, + data, chainParams) + if err == nil { + addrs = append(addrs, addr) + } } return PubkeyHashAltTy, addrs, 1, nil } // Check for pay-to-pubkey script. if data := extractPubKey(pkScript); data != nil { - var addrs []dcrutil.Address + var addrs []stdaddr.Address pk, err := secp256k1.ParsePubKey(data) if err == nil { - addr, err := dcrutil.NewAddressSecpPubKeyCompressed(pk, chainParams) + addr, err := stdaddr.NewAddressPubKeyEcdsaSecp256k1(version, pk, + chainParams) if err == nil { addrs = append(addrs, addr) } @@ -1281,16 +914,18 @@ func ExtractPkScriptAddrs(version uint16, pkScript []byte, chainParams dcrutil.A // Check for pay-to-alt-pubkey script. if pk, sigType := extractPubKeyAltDetails(pkScript); pk != nil { - var addrs []dcrutil.Address + var addrs []stdaddr.Address switch sigType { case dcrec.STEd25519: - addr, err := dcrutil.NewAddressEdwardsPubKey(pk, chainParams) + addr, err := stdaddr.NewAddressPubKeyEd25519Raw(version, pk, + chainParams) if err == nil { addrs = append(addrs, addr) } case dcrec.STSchnorrSecp256k1: - addr, err := dcrutil.NewAddressSecSchnorrPubKey(pk, chainParams) + addr, err := stdaddr.NewAddressPubKeySchnorrSecp256k1Raw(version, + pk, chainParams) if err == nil { addrs = append(addrs, addr) } @@ -1303,12 +938,12 @@ func ExtractPkScriptAddrs(version uint16, pkScript []byte, chainParams dcrutil.A details := extractMultisigScriptDetails(version, pkScript, true) if details.valid { // Convert the public keys while skipping any that are invalid. - addrs := make([]dcrutil.Address, 0, details.numPubKeys) + addrs := make([]stdaddr.Address, 0, details.numPubKeys) for i := 0; i < details.numPubKeys; i++ { pubkey, err := secp256k1.ParsePubKey(details.pubKeys[i]) if err == nil { - addr, err := dcrutil.NewAddressSecpPubKeyCompressed(pubkey, - chainParams) + addr, err := stdaddr.NewAddressPubKeyEcdsaSecp256k1(version, + pubkey, chainParams) if err == nil { addrs = append(addrs, addr) } diff --git a/txscript/standard_test.go b/txscript/standard_test.go index 6a801a67fc..f7cf5a4e10 100644 --- a/txscript/standard_test.go +++ b/txscript/standard_test.go @@ -1,5 +1,5 @@ // Copyright (c) 2013-2017 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -14,9 +14,8 @@ import ( "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/chaincfg/v3" - "github.com/decred/dcrd/dcrec" "github.com/decred/dcrd/dcrec/secp256k1/v4" - "github.com/decred/dcrd/dcrutil/v4" + "github.com/decred/dcrd/txscript/v4/stdaddr" ) // mainNetParams is an instance of the main network parameters and is shared @@ -37,16 +36,16 @@ func mustParseShortForm(script string) []byte { return s } -// newAddressPubKey returns a new dcrutil.AddressPubKey from the provided -// serialized public key. It panics if an error occurs. This is only used in -// the tests as a helper since the only way it can fail is if there is an error -// in the test source code. -func newAddressPubKey(serializedPubKey []byte) dcrutil.Address { +// newAddressPubKey returns a new pubkey address from the provided serialized +// public key. It panics if an error occurs. This is only used in the tests as +// a helper since the only way it can fail is if there is an error in the test +// source code. +func newAddressPubKey(serializedPubKey []byte) stdaddr.Address { pubkey, err := secp256k1.ParsePubKey(serializedPubKey) if err != nil { panic("invalid public key in test source") } - addr, err := dcrutil.NewAddressSecpPubKeyCompressed(pubkey, mainNetParams) + addr, err := stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(pubkey, mainNetParams) if err != nil { panic("invalid public key in test source") } @@ -54,13 +53,12 @@ func newAddressPubKey(serializedPubKey []byte) dcrutil.Address { return addr } -// newAddressPubKeyHash returns a new dcrutil.AddressPubKeyHash from the -// provided hash. It panics if an error occurs. This is only used in the tests -// as a helper since the only way it can fail is if there is an error in the -// test source code. -func newAddressPubKeyHash(pkHash []byte) dcrutil.Address { - addr, err := dcrutil.NewAddressPubKeyHash(pkHash, mainNetParams, - dcrec.STEcdsaSecp256k1) +// newAddressPubKeyHash returns a new pubkey hash from the provided hash. It +// panics if an error occurs. This is only used in the tests as a helper since +// the only way it can fail is if there is an error in the test source code. +func newAddressPubKeyHash(pkHash []byte) stdaddr.Address { + addr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(pkHash, + mainNetParams) if err != nil { panic("invalid public key hash in test source") } @@ -68,12 +66,13 @@ func newAddressPubKeyHash(pkHash []byte) dcrutil.Address { return addr } -// newAddressScriptHash returns a new dcrutil.AddressScriptHash from the -// provided hash. It panics if an error occurs. This is only used in the tests -// as a helper since the only way it can fail is if there is an error in the -// test source code. -func newAddressScriptHash(scriptHash []byte) dcrutil.Address { - addr, err := dcrutil.NewAddressScriptHashFromHash(scriptHash, mainNetParams) +// newAddressScriptHash returns a new script hash address from the provided +// hash. It panics if an error occurs. This is only used in the tests as a +// helper since the only way it can fail is if there is an error in the test +// source code. +func newAddressScriptHash(scriptHash []byte) stdaddr.Address { + addr, err := stdaddr.NewAddressScriptHashV0FromHash(scriptHash, + mainNetParams) if err != nil { panic("invalid script hash in test source") } @@ -90,7 +89,7 @@ func TestExtractPkScriptAddrs(t *testing.T) { tests := []struct { name string script []byte - addrs []dcrutil.Address + addrs []stdaddr.Address reqSigs int class ScriptClass noparse bool @@ -99,7 +98,7 @@ func TestExtractPkScriptAddrs(t *testing.T) { name: "standard p2pk with compressed pubkey (0x02)", script: hexToBytes("2102192d74d0cb94344c9569c2e779015" + "73d8d7903c3ebec3a957724895dca52c6b4ac"), - addrs: []dcrutil.Address{ + addrs: []stdaddr.Address{ newAddressPubKey(hexToBytes("02192d74d0cb9434" + "4c9569c2e77901573d8d7903c3ebec3a9577" + "24895dca52c6b4")), @@ -113,7 +112,7 @@ func TestExtractPkScriptAddrs(t *testing.T) { "c1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddf" + "b84ccf9744464f82e160bfa9b8b64f9d4c03f999b864" + "3f656b412a3ac"), - addrs: []dcrutil.Address{ + addrs: []stdaddr.Address{ newAddressPubKey(hexToBytes("0411db93e1dcdb8a" + "016b49840f8c53bc1eb68a382e97b1482eca" + "d7b148a6909a5cb2e0eaddfb84ccf9744464" + @@ -127,7 +126,7 @@ func TestExtractPkScriptAddrs(t *testing.T) { name: "standard p2pk with compressed pubkey (0x03)", script: hexToBytes("2103b0bd634234abbb1ba1e986e884185" + "c61cf43e001f9137f23c2c409273eb16e65ac"), - addrs: []dcrutil.Address{ + addrs: []stdaddr.Address{ newAddressPubKey(hexToBytes("03b0bd634234abbb" + "1ba1e986e884185c61cf43e001f9137f23c2" + "c409273eb16e65")), @@ -141,7 +140,7 @@ func TestExtractPkScriptAddrs(t *testing.T) { "c61cf43e001f9137f23c2c409273eb16e6537a576782" + "eba668a7ef8bd3b3cfb1edb7117ab65129b8a2e681f3" + "c1e0908ef7bac"), - addrs: []dcrutil.Address{ + addrs: []stdaddr.Address{ newAddressPubKey(hexToBytes("04b0bd634234abbb" + "1ba1e986e884185c61cf43e001f9137f23c2" + "c409273eb16e6537a576782eba668a7ef8bd" + @@ -155,7 +154,7 @@ func TestExtractPkScriptAddrs(t *testing.T) { name: "standard p2pkh", script: hexToBytes("76a914ad06dd6ddee55cbca9a9e3713bd" + "7587509a3056488ac"), - addrs: []dcrutil.Address{ + addrs: []stdaddr.Address{ newAddressPubKeyHash(hexToBytes("ad06dd6ddee5" + "5cbca9a9e3713bd7587509a30564")), }, @@ -166,7 +165,7 @@ func TestExtractPkScriptAddrs(t *testing.T) { name: "standard p2sh", script: hexToBytes("a91463bcc565f9e68ee0189dd5cc67f1b" + "0e5f02f45cb87"), - addrs: []dcrutil.Address{ + addrs: []stdaddr.Address{ newAddressScriptHash(hexToBytes("63bcc565f9e6" + "8ee0189dd5cc67f1b0e5f02f45cb")), }, @@ -183,7 +182,7 @@ func TestExtractPkScriptAddrs(t *testing.T) { "1354d80e550078cb532a34bfa2fcfdeb7d76519aecc6" + "2770f5b0e4ef8551946d8a540911abe3e7854a26f39f" + "58b25c15342af52ae"), - addrs: []dcrutil.Address{ + addrs: []stdaddr.Address{ newAddressPubKey(hexToBytes("04cc71eb30d653c0" + "c3163990c47b976f3fb3f37cccdcbedb169a" + "1dfef58bbfbfaff7d8a473e7e2e6d317b87b" + @@ -211,7 +210,7 @@ func TestExtractPkScriptAddrs(t *testing.T) { "2bbf781c5410d3f22a7a3a56ffefb2238af8627363bd" + "f2ed97c1f89784a1aecdb43384f11d2acc64443c7fc2" + "99cef0400421a53ae"), - addrs: []dcrutil.Address{ + addrs: []stdaddr.Address{ newAddressPubKey(hexToBytes("04cb9c3c222c5f7a" + "7d3b9bd152f363a0b6d54c9eb312c4d4f9af" + "1e8551b6c421a6a4ab0e29105f24de20ff46" + @@ -288,7 +287,7 @@ func TestExtractPkScriptAddrs(t *testing.T) { "16e20626520666f756e6420696e207472616e7361637" + "4696f6e2036633533636439383731313965663739376" + "435616463636453ae"), - addrs: []dcrutil.Address{}, + addrs: []stdaddr.Address{}, reqSigs: 1, class: MultiSigTy, }, @@ -305,7 +304,7 @@ func TestExtractPkScriptAddrs(t *testing.T) { "13963663463303363363039633539336333653931666" + "56465373032392102323364643432643235363339643" + "338613663663530616234636434340a00000053ae"), - addrs: []dcrutil.Address{}, + addrs: []stdaddr.Address{}, reqSigs: 1, class: MultiSigTy, }, @@ -391,146 +390,6 @@ func TestExtractPkScriptAddrs(t *testing.T) { } } -// bogusAddress implements the dcrutil.Address interface so the tests can ensure -// unsupported address types are handled properly. -type bogusAddress struct{} - -// Address simply returns an empty string. It exists to satisfy the -// dcrutil.Address interface. -func (b *bogusAddress) Address() string { - return "" -} - -// ScriptAddress simply returns an empty byte slice. It exists to satisfy the -// dcrutil.Address interface. -func (b *bogusAddress) ScriptAddress() []byte { - return nil -} - -// Hash160 simply returns an empty byte slice. It exists to satisfy the -// dcrutil.Address interface. -func (b *bogusAddress) Hash160() *[20]byte { - return nil -} - -// String simply returns an empty string. It exists to satisfy the -// dcrutil.Address interface. -func (b *bogusAddress) String() string { - return "" -} - -// TestPayToAddrScript ensures the PayToAddrScript function generates the -// correct scripts for the various types of addresses. -func TestPayToAddrScript(t *testing.T) { - t.Parallel() - - // 1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX - p2pkhMain, err := dcrutil.NewAddressPubKeyHash(hexToBytes("e34cce70c86"+ - "373273efcc54ce7d2a491bb4a0e84"), mainNetParams, dcrec.STEcdsaSecp256k1) - if err != nil { - t.Fatalf("Unable to create public key hash address: %v", err) - } - - // Taken from transaction: - // b0539a45de13b3e0403909b8bd1a555b8cbe45fd4e3f3fda76f3a5f52835c29d - p2shMain, _ := dcrutil.NewAddressScriptHashFromHash(hexToBytes("e8c30"+ - "0c87986efa84c37c0519929019ef86eb5b4"), mainNetParams) - if err != nil { - t.Fatalf("Unable to create script hash address: %v", err) - } - - // mainnet p2pk 13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg - p2pkCompressedMain, err := dcrutil.NewAddressSecpPubKey(hexToBytes("02192d7"+ - "4d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"), - mainNetParams) - if err != nil { - t.Fatalf("Unable to create pubkey address (compressed): %v", - err) - } - p2pkCompressed2Main, err := dcrutil.NewAddressSecpPubKey(hexToBytes("03b0b"+ - "d634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65"), - mainNetParams) - if err != nil { - t.Fatalf("Unable to create pubkey address (compressed 2): %v", - err) - } - - p2pkUncompressedMain := newAddressPubKey(hexToBytes("0411db" + - "93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2" + - "e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3")) - - tests := []struct { - in dcrutil.Address - expected string - err error - }{ - // pay-to-pubkey-hash address on mainnet 0 - { - p2pkhMain, - "DUP HASH160 DATA_20 0xe34cce70c86373273efcc54ce7d2a4" + - "91bb4a0e8488 CHECKSIG", - nil, - }, - // pay-to-script-hash address on mainnet 1 - { - p2shMain, - "HASH160 DATA_20 0xe8c300c87986efa84c37c0519929019ef8" + - "6eb5b4 EQUAL", - nil, - }, - // pay-to-pubkey address on mainnet. compressed key. 2 - { - p2pkCompressedMain, - "DATA_33 0x02192d74d0cb94344c9569c2e77901573d8d7903c3" + - "ebec3a957724895dca52c6b4 CHECKSIG", - nil, - }, - // pay-to-pubkey address on mainnet. compressed key (other way). 3 - { - p2pkCompressed2Main, - "DATA_33 0x03b0bd634234abbb1ba1e986e884185c61cf43e001" + - "f9137f23c2c409273eb16e65 CHECKSIG", - nil, - }, - // pay-to-pubkey address on mainnet. for Decred this would - // be uncompressed, but standard for Decred is 33 byte - // compressed public keys. - { - p2pkUncompressedMain, - "DATA_33 0x0311db93e1dcdb8a016b49840f8c53bc1eb68a382e97b" + - "1482ecad7b148a6909a5cac", - nil, - }, - - // Supported address types with nil pointers. - {(*dcrutil.AddressPubKeyHash)(nil), "", ErrUnsupportedAddress}, - {(*dcrutil.AddressScriptHash)(nil), "", ErrUnsupportedAddress}, - {(*dcrutil.AddressSecpPubKey)(nil), "", ErrUnsupportedAddress}, - {(*dcrutil.AddressEdwardsPubKey)(nil), "", ErrUnsupportedAddress}, - {(*dcrutil.AddressSecSchnorrPubKey)(nil), "", ErrUnsupportedAddress}, - - // Unsupported address type. - {&bogusAddress{}, "", ErrUnsupportedAddress}, - } - - t.Logf("Running %d tests", len(tests)) - for i, test := range tests { - pkScript, err := PayToAddrScript(test.in) - if !errors.Is(err, test.err) { - t.Errorf("PayToAddrScript #%d unexpected error - got %v, want %v", - i, err, test.err) - continue - } - - expected := mustParseShortForm(test.expected) - if !bytes.Equal(pkScript, expected) { - t.Errorf("PayToAddrScript #%d got: %x\nwant: %x", - i, pkScript, expected) - continue - } - } -} - // TestMultiSigScript ensures the MultiSigScript function returns the expected // scripts and errors. func TestMultiSigScript(t *testing.T) { @@ -1055,51 +914,6 @@ func TestGenerateProvablyPruneableOut(t *testing.T) { } } -// TestGenerateSStxAddrPush ensures an expected OP_RETURN push is generated. -func TestGenerateSStxAddrPush(t *testing.T) { - testNetParams := chaincfg.TestNet3Params() - var tests = []struct { - addrStr string - net dcrutil.AddressParams - amount dcrutil.Amount - limits uint16 - expected []byte - }{ - { - "Dcur2mcGjmENx4DhNqDctW5wJCVyT3Qeqkx", - mainNetParams, - 1000, - 10, - hexToBytes("6a1ef5916158e3e2c4551c1796708db8367207ed1" + - "3bbe8030000000000800a00"), - }, - { - "TscB7V5RuR1oXpA364DFEsNDuAs8Rk6BHJE", - testNetParams, - 543543, - 256, - hexToBytes("6a1e7a5c4cca76f2e0b36db4763daacbd6cbb6ee6" + - "e7b374b0800000000000001"), - }, - } - for _, test := range tests { - addr, err := dcrutil.DecodeAddress(test.addrStr, test.net) - if err != nil { - t.Errorf("DecodeAddress failed: %v", err) - continue - } - s, err := GenerateSStxAddrPush(addr, test.amount, test.limits) - if err != nil { - t.Errorf("GenerateSStxAddrPush failed: %v", err) - continue - } - if !bytes.Equal(s, test.expected) { - t.Errorf("GenerateSStxAddrPush: unexpected script:\n "+ - "got %x\nwant %x", s, test.expected) - } - } -} - // TestGenerateSSGenBlockRef ensures an expected OP_RETURN push is generated. func TestGenerateSSGenBlockRef(t *testing.T) { var tests = []struct {