func VerifyTxScript(sigScr []byte, pkScr []byte, i int, tx *btc.Tx, ver_flags uint32) bool { if DBG_SCR { fmt.Println("VerifyTxScript", tx.Hash.String(), i+1, "/", len(tx.TxIn)) fmt.Println("sigScript:", hex.EncodeToString(sigScr[:])) fmt.Println("_pkScript:", hex.EncodeToString(pkScr)) fmt.Printf("flagz:%x\n", ver_flags) } var st, stP2SH scrStack if !evalScript(sigScr, &st, tx, i, ver_flags) { if DBG_ERR { if tx != nil { fmt.Println("VerifyTxScript", tx.Hash.String(), i+1, "/", len(tx.TxIn)) } fmt.Println("sigScript failed :", hex.EncodeToString(sigScr[:])) fmt.Println("pkScript:", hex.EncodeToString(pkScr[:])) } return false } if DBG_SCR { fmt.Println("\nsigScr verified OK") //st.print() fmt.Println() } // copy the stack content to stP2SH if st.size() > 0 { idx := -st.size() for i := 0; i < st.size(); i++ { x := st.top(idx) stP2SH.push(x) idx++ } } if !evalScript(pkScr, &st, tx, i, ver_flags) { if DBG_SCR { fmt.Println("* pkScript failed :", hex.EncodeToString(pkScr[:])) fmt.Println("* VerifyTxScript", tx.Hash.String(), i+1, "/", len(tx.TxIn)) fmt.Println("* sigScript:", hex.EncodeToString(sigScr[:])) } return false } if st.size() == 0 { if DBG_SCR { fmt.Println("* stack empty after executing scripts:", hex.EncodeToString(pkScr[:])) } return false } if !st.popBool() { if DBG_SCR { fmt.Println("* FALSE on stack after executing scripts:", hex.EncodeToString(pkScr[:])) } return false } // Additional validation for spend-to-script-hash transactions: if (ver_flags&VER_P2SH) != 0 && btc.IsPayToScript(pkScr) { if DBG_SCR { fmt.Println() fmt.Println() fmt.Println(" ******************* Looks like P2SH script ********************* ") stP2SH.print() } if DBG_SCR { fmt.Println("sigScr len", len(sigScr), hex.EncodeToString(sigScr)) } if !IsPushOnly(sigScr) { if DBG_ERR { fmt.Println("P2SH is not push only") } return false } pubKey2 := stP2SH.pop() if DBG_SCR { fmt.Println("pubKey2:", hex.EncodeToString(pubKey2)) } if !evalScript(pubKey2, &stP2SH, tx, i, ver_flags) { if DBG_ERR { fmt.Println("P2SH extra verification failed") } return false } if stP2SH.size() == 0 { if DBG_SCR { fmt.Println("* P2SH stack empty after executing script:", hex.EncodeToString(pubKey2)) } return false } if !stP2SH.popBool() { if DBG_SCR { fmt.Println("* FALSE on stack after executing P2SH script:", hex.EncodeToString(pubKey2)) } return false } } return true }
func VerifyTxScript(pkScr []byte, amount uint64, i int, tx *btc.Tx, ver_flags uint32) (result bool) { if VerifyConsensus != nil { defer func() { // We call CompareToConsensus inside another function to wait for final "result" VerifyConsensus(pkScr, amount, i, tx, ver_flags, result) }() } sigScr := tx.TxIn[i].ScriptSig if (ver_flags&VER_SIGPUSHONLY) != 0 && !btc.IsPushOnly(sigScr) { if DBG_ERR { fmt.Println("Not push only") } return false } if DBG_SCR { fmt.Println("VerifyTxScript", tx.Hash.String(), i+1, "/", len(tx.TxIn)) fmt.Println("sigScript:", hex.EncodeToString(sigScr[:])) fmt.Println("_pkScript:", hex.EncodeToString(pkScr)) fmt.Printf("flagz:%x\n", ver_flags) } var stack, stackCopy scrStack if !evalScript(sigScr, amount, &stack, tx, i, ver_flags, SIGVERSION_BASE) { if DBG_ERR { if tx != nil { fmt.Println("VerifyTxScript", tx.Hash.String(), i+1, "/", len(tx.TxIn)) } fmt.Println("sigScript failed :", hex.EncodeToString(sigScr[:])) fmt.Println("pkScript:", hex.EncodeToString(pkScr[:])) } return } if DBG_SCR { fmt.Println("\nsigScr verified OK") //stack.print() fmt.Println() } if (ver_flags&VER_P2SH) != 0 && stack.size() > 0 { // copy the stack content to stackCopy stackCopy.copy_from(&stack) } if !evalScript(pkScr, amount, &stack, tx, i, ver_flags, SIGVERSION_BASE) { if DBG_SCR { fmt.Println("* pkScript failed :", hex.EncodeToString(pkScr[:])) fmt.Println("* VerifyTxScript", tx.Hash.String(), i+1, "/", len(tx.TxIn)) fmt.Println("* sigScript:", hex.EncodeToString(sigScr[:])) } return } if stack.size() == 0 { if DBG_SCR { fmt.Println("* stack empty after executing scripts:", hex.EncodeToString(pkScr[:])) } return } if !stack.topBool(-1) { if DBG_SCR { fmt.Println("* FALSE on stack after executing scripts:", hex.EncodeToString(pkScr[:])) } return } // Bare witness programs var witnessversion int var witnessprogram []byte var hadWitness bool var witness witness_ctx if (ver_flags & VER_WITNESS) != 0 { if tx.SegWit != nil { for _, wd := range tx.SegWit[i] { witness.stack.push(wd) } } witnessversion, witnessprogram = btc.IsWitnessProgram(pkScr) if DBG_SCR { fmt.Println("------------witnessversion:", witnessversion, " witnessprogram:", hex.EncodeToString(witnessprogram)) } if witnessprogram != nil { hadWitness = true if len(sigScr) != 0 { if DBG_ERR { fmt.Println("SCRIPT_ERR_WITNESS_MALLEATED") } return } if !VerifyWitnessProgram(&witness, amount, tx, i, witnessversion, witnessprogram, ver_flags) { if DBG_ERR { fmt.Println("VerifyWitnessProgram failed A") } return false } // Bypass the cleanstack check at the end. The actual stack is obviously not clean // for witness programs. stack.resize(1) } else { if DBG_SCR { fmt.Println("No witness program") } } } else { if DBG_SCR { fmt.Println("Witness flag off") } } // Additional validation for spend-to-script-hash transactions: if (ver_flags&VER_P2SH) != 0 && btc.IsPayToScript(pkScr) { if DBG_SCR { fmt.Println() fmt.Println() fmt.Println(" ******************* Looks like P2SH script ********************* ") stack.print() } if DBG_SCR { fmt.Println("sigScr len", len(sigScr), hex.EncodeToString(sigScr)) } if !btc.IsPushOnly(sigScr) { if DBG_ERR { fmt.Println("P2SH is not push only") } return } // Restore stack. stack = stackCopy pubKey2 := stack.pop() if DBG_SCR { fmt.Println("pubKey2:", hex.EncodeToString(pubKey2)) } if !evalScript(pubKey2, amount, &stack, tx, i, ver_flags, SIGVERSION_BASE) { if DBG_ERR { fmt.Println("P2SH extra verification failed") } return } if stack.size() == 0 { if DBG_SCR { fmt.Println("* P2SH stack empty after executing script:", hex.EncodeToString(pubKey2)) } return } if !stack.topBool(-1) { if DBG_SCR { fmt.Println("* FALSE on stack after executing P2SH script:", hex.EncodeToString(pubKey2)) } return } if (ver_flags & VER_WITNESS) != 0 { witnessversion, witnessprogram = btc.IsWitnessProgram(pubKey2) if DBG_SCR { fmt.Println("============witnessversion:", witnessversion, " witnessprogram:", hex.EncodeToString(witnessprogram)) } if witnessprogram != nil { hadWitness = true bt := new(bytes.Buffer) btc.WritePutLen(bt, uint32(len(pubKey2))) bt.Write(pubKey2) if !bytes.Equal(sigScr, bt.Bytes()) { if DBG_ERR { fmt.Println(hex.EncodeToString(sigScr)) fmt.Println(hex.EncodeToString(bt.Bytes())) fmt.Println("SCRIPT_ERR_WITNESS_MALLEATED_P2SH") } return } if !VerifyWitnessProgram(&witness, amount, tx, i, witnessversion, witnessprogram, ver_flags) { if DBG_ERR { fmt.Println("VerifyWitnessProgram failed B") } return false } // Bypass the cleanstack check at the end. The actual stack is obviously not clean // for witness programs. stack.resize(1) } } } if (ver_flags & VER_CLEANSTACK) != 0 { if (ver_flags & VER_P2SH) == 0 { panic("VER_CLEANSTACK without VER_P2SH") } if DBG_SCR { fmt.Println("stack size", stack.size()) } if stack.size() != 1 { if DBG_ERR { fmt.Println("Stack not clean") } return } } if (ver_flags & VER_WITNESS) != 0 { // We can't check for correct unexpected witness data if P2SH was off, so require // that WITNESS implies P2SH. Otherwise, going from WITNESS->P2SH+WITNESS would be // possible, which is not a softfork. if (ver_flags & VER_P2SH) == 0 { panic("VER_WITNESS must be used with P2SH") } if !hadWitness && !witness.IsNull() { if DBG_ERR { fmt.Println("SCRIPT_ERR_WITNESS_UNEXPECTED", len(tx.SegWit)) } return } } result = true return true }