Esempio n. 1
0
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
}
Esempio n. 2
0
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
}