// 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.ScriptVerifyDERSignatures | 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 }
// validateHandler consumes items to validate from the internal validate channel // and returns the result of the validation on the internal result channel. It // must be run as a goroutine. func (v *txValidator) validateHandler() { out: for { select { case txVI := <-v.validateChan: // Ensure the referenced input transaction is available. txIn := txVI.txIn originTxHash := &txIn.PreviousOutPoint.Hash originTx, exists := v.txStore[*originTxHash] if !exists || originTx.Err != nil || originTx.Tx == nil { str := fmt.Sprintf("unable to find input "+ "transaction %v referenced from "+ "transaction %v", originTxHash, txVI.tx.Sha()) err := ruleError(ErrMissingTx, str) v.sendResult(err) break out } originMsgTx := originTx.Tx.MsgTx() // Ensure the output index in the referenced transaction // is available. originTxIndex := txIn.PreviousOutPoint.Index if originTxIndex >= uint32(len(originMsgTx.TxOut)) { str := fmt.Sprintf("out of bounds "+ "input index %d in transaction %v "+ "referenced from transaction %v", originTxIndex, originTxHash, txVI.tx.Sha()) err := ruleError(ErrBadTxInput, str) v.sendResult(err) break out } // Create a new script engine for the script pair. sigScript := txIn.SignatureScript pkScript := originMsgTx.TxOut[originTxIndex].PkScript engine, err := txscript.NewScript(sigScript, pkScript, txVI.txInIndex, txVI.tx.MsgTx(), v.flags) if err != nil { str := fmt.Sprintf("failed to parse input "+ "%s:%d which references output %s:%d - "+ "%v (input script bytes %x, prev output "+ "script bytes %x)", txVI.tx.Sha(), txVI.txInIndex, originTxHash, originTxIndex, err, sigScript, pkScript) err := ruleError(ErrScriptMalformed, str) v.sendResult(err) break out } // Execute the script pair. if err := engine.Execute(); err != nil { str := fmt.Sprintf("failed to validate input "+ "%s:%d which references output %s:%d - "+ "%v (input script bytes %x, prev output "+ "script bytes %x)", txVI.tx.Sha(), txVI.txInIndex, originTxHash, originTxIndex, err, sigScript, pkScript) err := ruleError(ErrScriptValidation, str) v.sendResult(err) break out } // Validation succeeded. v.sendResult(nil) case <-v.quitChan: break out } } }