github.com/lbryio/lbcd@v0.22.119/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/lbryio/lbcd/btcec" 13 "github.com/lbryio/lbcd/chaincfg" 14 "github.com/lbryio/lbcd/chaincfg/chainhash" 15 "github.com/lbryio/lbcd/txscript" 16 "github.com/lbryio/lbcd/wire" 17 btcutil "github.com/lbryio/lbcutil" 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 := "bHW58d37s1hBjj3wPBkn5zpCX3F8ZW3uWf" 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: 76a914345991dbf57bfb014b87006acdfafbfc5fe8292f88ac 52 // Script Disassembly: OP_DUP OP_HASH160 345991dbf57bfb014b87006acdfafbfc5fe8292f 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: [bER6Ddq6YfRKDJDmmdeaqrP8XHmDJcYSJQ] 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(btcec.S256(), 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) 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 }