github.com/btcsuite/btcd@v0.24.0/txscript/example_test.go (about)

     1  // Copyright (c) 2014-2016 The btcsuite developers
     2  // Copyright (c) 2015-2019 The Decred developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package txscript_test
     7  
     8  import (
     9  	"encoding/hex"
    10  	"fmt"
    11  
    12  	"github.com/btcsuite/btcd/btcec/v2"
    13  	"github.com/btcsuite/btcd/btcutil"
    14  	"github.com/btcsuite/btcd/chaincfg"
    15  	"github.com/btcsuite/btcd/chaincfg/chainhash"
    16  	"github.com/btcsuite/btcd/txscript"
    17  	"github.com/btcsuite/btcd/wire"
    18  )
    19  
    20  // This example demonstrates creating a script which pays to a bitcoin address.
    21  // It also prints the created script hex and uses the DisasmString function to
    22  // display the disassembled script.
    23  func ExamplePayToAddrScript() {
    24  	// Parse the address to send the coins to into a btcutil.Address
    25  	// which is useful to ensure the accuracy of the address and determine
    26  	// the address type.  It is also required for the upcoming call to
    27  	// PayToAddrScript.
    28  	addressStr := "12gpXQVcCL2qhTNQgyLVdCFG2Qs2px98nV"
    29  	address, err := btcutil.DecodeAddress(addressStr, &chaincfg.MainNetParams)
    30  	if err != nil {
    31  		fmt.Println(err)
    32  		return
    33  	}
    34  
    35  	// Create a public key script that pays to the address.
    36  	script, err := txscript.PayToAddrScript(address)
    37  	if err != nil {
    38  		fmt.Println(err)
    39  		return
    40  	}
    41  	fmt.Printf("Script Hex: %x\n", script)
    42  
    43  	disasm, err := txscript.DisasmString(script)
    44  	if err != nil {
    45  		fmt.Println(err)
    46  		return
    47  	}
    48  	fmt.Println("Script Disassembly:", disasm)
    49  
    50  	// Output:
    51  	// Script Hex: 76a914128004ff2fcaf13b2b91eb654b1dc2b674f7ec6188ac
    52  	// Script Disassembly: OP_DUP OP_HASH160 128004ff2fcaf13b2b91eb654b1dc2b674f7ec61 OP_EQUALVERIFY OP_CHECKSIG
    53  }
    54  
    55  // This example demonstrates extracting information from a standard public key
    56  // script.
    57  func ExampleExtractPkScriptAddrs() {
    58  	// Start with a standard pay-to-pubkey-hash script.
    59  	scriptHex := "76a914128004ff2fcaf13b2b91eb654b1dc2b674f7ec6188ac"
    60  	script, err := hex.DecodeString(scriptHex)
    61  	if err != nil {
    62  		fmt.Println(err)
    63  		return
    64  	}
    65  
    66  	// Extract and print details from the script.
    67  	scriptClass, addresses, reqSigs, err := txscript.ExtractPkScriptAddrs(
    68  		script, &chaincfg.MainNetParams)
    69  	if err != nil {
    70  		fmt.Println(err)
    71  		return
    72  	}
    73  	fmt.Println("Script Class:", scriptClass)
    74  	fmt.Println("Addresses:", addresses)
    75  	fmt.Println("Required Signatures:", reqSigs)
    76  
    77  	// Output:
    78  	// Script Class: pubkeyhash
    79  	// Addresses: [12gpXQVcCL2qhTNQgyLVdCFG2Qs2px98nV]
    80  	// Required Signatures: 1
    81  }
    82  
    83  // This example demonstrates manually creating and signing a redeem transaction.
    84  func ExampleSignTxOutput() {
    85  	// Ordinarily the private key would come from whatever storage mechanism
    86  	// is being used, but for this example just hard code it.
    87  	privKeyBytes, err := hex.DecodeString("22a47fa09a223f2aa079edf85a7c2" +
    88  		"d4f8720ee63e502ee2869afab7de234b80c")
    89  	if err != nil {
    90  		fmt.Println(err)
    91  		return
    92  	}
    93  	privKey, pubKey := btcec.PrivKeyFromBytes(privKeyBytes)
    94  	pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed())
    95  	addr, err := btcutil.NewAddressPubKeyHash(pubKeyHash,
    96  		&chaincfg.MainNetParams)
    97  	if err != nil {
    98  		fmt.Println(err)
    99  		return
   100  	}
   101  
   102  	// For this example, create a fake transaction that represents what
   103  	// would ordinarily be the real transaction that is being spent.  It
   104  	// contains a single output that pays to address in the amount of 1 BTC.
   105  	originTx := wire.NewMsgTx(wire.TxVersion)
   106  	prevOut := wire.NewOutPoint(&chainhash.Hash{}, ^uint32(0))
   107  	txIn := wire.NewTxIn(prevOut, []byte{txscript.OP_0, txscript.OP_0}, nil)
   108  	originTx.AddTxIn(txIn)
   109  	pkScript, err := txscript.PayToAddrScript(addr)
   110  	if err != nil {
   111  		fmt.Println(err)
   112  		return
   113  	}
   114  	txOut := wire.NewTxOut(100000000, pkScript)
   115  	originTx.AddTxOut(txOut)
   116  	originTxHash := originTx.TxHash()
   117  
   118  	// Create the transaction to redeem the fake transaction.
   119  	redeemTx := wire.NewMsgTx(wire.TxVersion)
   120  
   121  	// Add the input(s) the redeeming transaction will spend.  There is no
   122  	// signature script at this point since it hasn't been created or signed
   123  	// yet, hence nil is provided for it.
   124  	prevOut = wire.NewOutPoint(&originTxHash, 0)
   125  	txIn = wire.NewTxIn(prevOut, nil, nil)
   126  	redeemTx.AddTxIn(txIn)
   127  
   128  	// Ordinarily this would contain that actual destination of the funds,
   129  	// but for this example don't bother.
   130  	txOut = wire.NewTxOut(0, nil)
   131  	redeemTx.AddTxOut(txOut)
   132  
   133  	// Sign the redeeming transaction.
   134  	lookupKey := func(a btcutil.Address) (*btcec.PrivateKey, bool, error) {
   135  		// Ordinarily this function would involve looking up the private
   136  		// key for the provided address, but since the only thing being
   137  		// signed in this example uses the address associated with the
   138  		// private key from above, simply return it with the compressed
   139  		// flag set since the address is using the associated compressed
   140  		// public key.
   141  		//
   142  		// NOTE: If you want to prove the code is actually signing the
   143  		// transaction properly, uncomment the following line which
   144  		// intentionally returns an invalid key to sign with, which in
   145  		// turn will result in a failure during the script execution
   146  		// when verifying the signature.
   147  		//
   148  		// privKey.D.SetInt64(12345)
   149  		//
   150  		return privKey, true, nil
   151  	}
   152  	// Notice that the script database parameter is nil here since it isn't
   153  	// used.  It must be specified when pay-to-script-hash transactions are
   154  	// being signed.
   155  	sigScript, err := txscript.SignTxOutput(&chaincfg.MainNetParams,
   156  		redeemTx, 0, originTx.TxOut[0].PkScript, txscript.SigHashAll,
   157  		txscript.KeyClosure(lookupKey), nil, nil)
   158  	if err != nil {
   159  		fmt.Println(err)
   160  		return
   161  	}
   162  	redeemTx.TxIn[0].SignatureScript = sigScript
   163  
   164  	// Prove that the transaction has been validly signed by executing the
   165  	// script pair.
   166  	flags := txscript.ScriptBip16 | txscript.ScriptVerifyDERSignatures |
   167  		txscript.ScriptStrictMultiSig |
   168  		txscript.ScriptDiscourageUpgradableNops
   169  	vm, err := txscript.NewEngine(originTx.TxOut[0].PkScript, redeemTx, 0,
   170  		flags, nil, nil, -1, nil)
   171  	if err != nil {
   172  		fmt.Println(err)
   173  		return
   174  	}
   175  	if err := vm.Execute(); err != nil {
   176  		fmt.Println(err)
   177  		return
   178  	}
   179  	fmt.Println("Transaction successfully signed")
   180  
   181  	// Output:
   182  	// Transaction successfully signed
   183  }
   184  
   185  // This example demonstrates creating a script tokenizer instance and using it
   186  // to count the number of opcodes a script contains.
   187  func ExampleScriptTokenizer() {
   188  	// Create a script to use in the example.  Ordinarily this would come from
   189  	// some other source.
   190  	hash160 := btcutil.Hash160([]byte("example"))
   191  	script, err := txscript.NewScriptBuilder().AddOp(txscript.OP_DUP).
   192  		AddOp(txscript.OP_HASH160).AddData(hash160).
   193  		AddOp(txscript.OP_EQUALVERIFY).AddOp(txscript.OP_CHECKSIG).Script()
   194  	if err != nil {
   195  		fmt.Printf("failed to build script: %v\n", err)
   196  		return
   197  	}
   198  
   199  	// Create a tokenizer to iterate the script and count the number of opcodes.
   200  	const scriptVersion = 0
   201  	var numOpcodes int
   202  	tokenizer := txscript.MakeScriptTokenizer(scriptVersion, script)
   203  	for tokenizer.Next() {
   204  		numOpcodes++
   205  	}
   206  	if tokenizer.Err() != nil {
   207  		fmt.Printf("script failed to parse: %v\n", err)
   208  	} else {
   209  		fmt.Printf("script contains %d opcode(s)\n", numOpcodes)
   210  	}
   211  
   212  	// Output:
   213  	// script contains 5 opcode(s)
   214  }