txscript: Add example for manully signing a txout.
This commit adds a new example to the txscript package that demonstrates creating a new transaction which redeems funds and signing the referenced transaction output the SignTxOutput function.
This commit is contained in:
parent
73d4a68a00
commit
f82f7b6663
2 changed files with 113 additions and 0 deletions
|
@ -49,6 +49,10 @@ $ go get github.com/btcsuite/btcd/txscript
|
|||
(http://godoc.org/github.com/btcsuite/btcd/txscript#example-ExtractPkScriptAddrs)
|
||||
Demonstrates extracting information from a standard public key script.
|
||||
|
||||
* [Manually Signing a Transaction Output]
|
||||
(http://godoc.org/github.com/btcsuite/btcd/txscript#example-SignTxOutput)
|
||||
Demonstrates manually creating and signing a redeem transaction.
|
||||
|
||||
## GPG Verification Key
|
||||
|
||||
All official release tags are signed by Conformal so users can ensure the code
|
||||
|
|
|
@ -8,8 +8,10 @@ import (
|
|||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
)
|
||||
|
||||
|
@ -75,3 +77,110 @@ func ExampleExtractPkScriptAddrs() {
|
|||
// Addresses: [12gpXQVcCL2qhTNQgyLVdCFG2Qs2px98nV]
|
||||
// Required Signatures: 1
|
||||
}
|
||||
|
||||
// This example demonstrates manually creating and signing a redeem transaction.
|
||||
func ExampleSignTxOutput() {
|
||||
// Ordinarily the private key would come from whatever storage mechanism
|
||||
// is being used, but for this example just hard code it.
|
||||
privKeyBytes, err := hex.DecodeString("22a47fa09a223f2aa079edf85a7c2" +
|
||||
"d4f8720ee63e502ee2869afab7de234b80c")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes)
|
||||
pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed())
|
||||
addr, err := btcutil.NewAddressPubKeyHash(pubKeyHash,
|
||||
&chaincfg.MainNetParams)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// For this example, create a fake transaction that represents what
|
||||
// would ordinarily be the real transaction that is being spent. It
|
||||
// contains a single output that pays to address in the amount of 1 BTC.
|
||||
originTx := wire.NewMsgTx()
|
||||
prevOut := wire.NewOutPoint(&wire.ShaHash{}, ^uint32(0))
|
||||
txIn := wire.NewTxIn(prevOut, []byte{txscript.OP_0, txscript.OP_0})
|
||||
originTx.AddTxIn(txIn)
|
||||
pkScript, err := txscript.PayToAddrScript(addr)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
txOut := wire.NewTxOut(100000000, pkScript)
|
||||
originTx.AddTxOut(txOut)
|
||||
|
||||
originTxHash, err := originTx.TxSha()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Create the transaction to redeem the fake transaction.
|
||||
redeemTx := wire.NewMsgTx()
|
||||
|
||||
// Add the input(s) the redeeming transaction will spend. There is no
|
||||
// signature script at this point since it hasn't been created or signed
|
||||
// yet, hence nil is provided for it.
|
||||
prevOut = wire.NewOutPoint(&originTxHash, 0)
|
||||
txIn = wire.NewTxIn(prevOut, nil)
|
||||
redeemTx.AddTxIn(txIn)
|
||||
|
||||
// Ordinarily this would contain that actual destination of the funds,
|
||||
// but for this example don't bother.
|
||||
txOut = wire.NewTxOut(0, nil)
|
||||
redeemTx.AddTxOut(txOut)
|
||||
|
||||
// Sign the redeeming transaction.
|
||||
lookupKey := func(a btcutil.Address) (*btcec.PrivateKey, 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
|
||||
// private key from above, simply return it with the compressed
|
||||
// flag set since the address is using the associated compressed
|
||||
// public key.
|
||||
//
|
||||
// NOTE: If you want to prove the code is actually signing the
|
||||
// transaction properly, uncomment the following line which
|
||||
// intentionally returns an invalid key to sign with, which in
|
||||
// turn will result in a failure during the script execution
|
||||
// when verifying the signature.
|
||||
//
|
||||
// privKey.D.SetInt64(12345)
|
||||
//
|
||||
return privKey, true, nil
|
||||
}
|
||||
// Notice that the script database parameter is nil here since it isn't
|
||||
// used. It must be specified when pay-to-script-hash transactions are
|
||||
// being signed.
|
||||
sigScript, err := txscript.SignTxOutput(&chaincfg.MainNetParams,
|
||||
redeemTx, 0, originTx.TxOut[0].PkScript, txscript.SigHashAll,
|
||||
txscript.KeyClosure(lookupKey), nil, nil)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
redeemTx.TxIn[0].SignatureScript = sigScript
|
||||
|
||||
// Prove that the transaction has been validly signed by executing the
|
||||
// script pair.
|
||||
flags := txscript.ScriptBip16 | txscript.ScriptCanonicalSignatures |
|
||||
txscript.ScriptStrictMultiSig |
|
||||
txscript.ScriptDiscourageUpgradableNops
|
||||
s, err := txscript.NewScript(redeemTx.TxIn[0].SignatureScript,
|
||||
originTx.TxOut[0].PkScript, 0, redeemTx, flags)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
if err := s.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println("Transaction successfully signed")
|
||||
|
||||
// Output:
|
||||
// Transaction successfully signed
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue