// Copyright (c) 2014-2016 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package txscript_test import ( "encoding/hex" "fmt" "github.com/daglabs/btcd/btcec" "github.com/daglabs/btcd/dagconfig" "github.com/daglabs/btcd/txscript" "github.com/daglabs/btcd/util" "github.com/daglabs/btcd/util/daghash" "github.com/daglabs/btcd/wire" ) // This example demonstrates creating a script which pays to a bitcoin 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 util.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. addressStr := "dagcoin:qqfgqp8l9l90zwetj84k2jcac2m8falvvy9uastr55" address, err := util.DecodeAddress(addressStr, util.Bech32PrefixDAGCoin) 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() { // Start with a standard pay-to-pubkey-hash script. scriptHex := "76a914128004ff2fcaf13b2b91eb654b1dc2b674f7ec6188ac" script, err := hex.DecodeString(scriptHex) if err != nil { fmt.Println(err) return } // Extract and print details from the script. scriptClass, addresses, reqSigs, err := txscript.ExtractPkScriptAddrs( script, &dagconfig.MainNetParams) if err != nil { fmt.Println(err) return } fmt.Println("Script Class:", scriptClass) fmt.Println("Addresses:", addresses) fmt.Println("Required Signatures:", reqSigs) // Output: // Script Class: pubkeyhash // Addresses: [dagcoin:qqfgqp8l9l90zwetj84k2jcac2m8falvvy9uastr55] // 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 := util.Hash160(pubKey.SerializeCompressed()) addr, err := util.NewAddressPubKeyHash(pubKeyHash, util.Bech32PrefixDAGCoin) 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. prevOut := wire.NewOutpoint(&daghash.TxID{}, ^uint32(0)) txIn := wire.NewTxIn(prevOut, []byte{txscript.Op0, txscript.Op0}) pkScript, err := txscript.PayToAddrScript(addr) if err != nil { fmt.Println(err) return } txOut := wire.NewTxOut(100000000, pkScript) originTx := wire.NewNativeMsgTx(wire.TxVersion, []*wire.TxIn{txIn}, []*wire.TxOut{txOut}) // Create the transaction to redeem the fake transaction. // 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(originTx.TxID(), 0) txIn = wire.NewTxIn(prevOut, nil) // Ordinarily this would contain that actual destination of the funds, // but for this example don't bother. txOut = wire.NewTxOut(0, nil) redeemTx := wire.NewNativeMsgTx(wire.TxVersion, []*wire.TxIn{txIn}, []*wire.TxOut{txOut}) // Sign the redeeming transaction. lookupKey := func(a util.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(&dagconfig.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.ScriptDiscourageUpgradableNops vm, err := txscript.NewEngine(originTx.TxOut[0].PkScript, redeemTx, 0, flags, nil) if err != nil { fmt.Println(err) return } if err := vm.Execute(); err != nil { fmt.Println(err) return } fmt.Println("Transaction successfully signed") // Output: // Transaction successfully signed }