aboutsummaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
Diffstat (limited to 'src/script')
-rw-r--r--src/script/bitcoinconsensus.cpp2
-rw-r--r--src/script/interpreter.cpp23
-rw-r--r--src/script/interpreter.h14
-rw-r--r--src/script/sigcache.h2
-rw-r--r--src/script/sign.cpp9
5 files changed, 40 insertions, 10 deletions
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index 76609f01a7..a9aa6a0060 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -92,7 +92,7 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP
set_error(err, bitcoinconsensus_ERR_OK);
PrecomputedTransactionData txdata(tx);
- return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].scriptWitness, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata), nullptr);
+ return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].scriptWitness, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata, MissingDataBehavior::FAIL), nullptr);
} catch (const std::exception&) {
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
}
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 20a4ce48b0..abc0625bb1 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1488,8 +1488,20 @@ static const CHashWriter HASHER_TAPLEAF = TaggedHash("TapLeaf");
static const CHashWriter HASHER_TAPBRANCH = TaggedHash("TapBranch");
static const CHashWriter HASHER_TAPTWEAK = TaggedHash("TapTweak");
+static bool HandleMissingData(MissingDataBehavior mdb)
+{
+ switch (mdb) {
+ case MissingDataBehavior::ASSERT_FAIL:
+ assert(!"Missing data");
+ break;
+ case MissingDataBehavior::FAIL:
+ return false;
+ }
+ assert(!"Unknown MissingDataBehavior value");
+}
+
template<typename T>
-bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache)
+bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache, MissingDataBehavior mdb)
{
uint8_t ext_flag, key_version;
switch (sigversion) {
@@ -1509,7 +1521,9 @@ bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata
assert(false);
}
assert(in_pos < tx_to.vin.size());
- assert(cache.m_bip341_taproot_ready && cache.m_spent_outputs_ready);
+ if (!(cache.m_bip341_taproot_ready && cache.m_spent_outputs_ready)) {
+ return HandleMissingData(mdb);
+ }
CHashWriter ss = HASHER_TAPSIGHASH;
@@ -1667,6 +1681,9 @@ bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vecto
int nHashType = vchSig.back();
vchSig.pop_back();
+ // Witness sighashes need the amount.
+ if (sigversion == SigVersion::WITNESS_V0 && amount < 0) return HandleMissingData(m_mdb);
+
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata);
if (!VerifyECDSASignature(vchSig, pubkey, sighash))
@@ -1696,7 +1713,7 @@ bool GenericTransactionSignatureChecker<T>::CheckSchnorrSignature(Span<const uns
}
uint256 sighash;
assert(this->txdata);
- if (!SignatureHashSchnorr(sighash, execdata, *txTo, nIn, hashtype, sigversion, *this->txdata)) {
+ if (!SignatureHashSchnorr(sighash, execdata, *txTo, nIn, hashtype, sigversion, *this->txdata, m_mdb)) {
return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_HASHTYPE);
}
if (!VerifySchnorrSignature(sig, pubkey, sighash)) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG);
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index effbc055d4..c76b3acb22 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -247,11 +247,21 @@ public:
virtual ~BaseSignatureChecker() {}
};
+/** Enum to specify what *TransactionSignatureChecker's behavior should be
+ * when dealing with missing transaction data.
+ */
+enum class MissingDataBehavior
+{
+ ASSERT_FAIL, //!< Abort execution through assertion failure (for consensus code)
+ FAIL, //!< Just act as if the signature was invalid
+};
+
template <class T>
class GenericTransactionSignatureChecker : public BaseSignatureChecker
{
private:
const T* txTo;
+ const MissingDataBehavior m_mdb;
unsigned int nIn;
const CAmount amount;
const PrecomputedTransactionData* txdata;
@@ -261,8 +271,8 @@ protected:
virtual bool VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const;
public:
- GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
- GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
+ GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, MissingDataBehavior mdb) : txTo(txToIn), m_mdb(mdb), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
+ GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn, MissingDataBehavior mdb) : txTo(txToIn), m_mdb(mdb), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override;
bool CheckLockTime(const CScriptNum& nLockTime) const override;
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index bf0ba38c2d..7b6b91c963 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -27,7 +27,7 @@ private:
bool store;
public:
- CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amountIn, txdataIn), store(storeIn) {}
+ CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amountIn, txdataIn, MissingDataBehavior::ASSERT_FAIL), store(storeIn) {}
bool VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const override;
bool VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const override;
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 3c8f6d22ea..4d9026427e 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -14,7 +14,7 @@
typedef std::vector<unsigned char> valtype;
-MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
+MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn, MissingDataBehavior::FAIL) {}
bool MutableTransactionSignatureCreator::CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const
{
@@ -26,6 +26,9 @@ bool MutableTransactionSignatureCreator::CreateSig(const SigningProvider& provid
if (sigversion == SigVersion::WITNESS_V0 && !key.IsCompressed())
return false;
+ // Signing for witness scripts needs the amount.
+ if (sigversion == SigVersion::WITNESS_V0 && amount < 0) return false;
+
uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);
if (!key.Sign(hash, vchSig))
return false;
@@ -292,7 +295,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
Stacks stack(data);
// Get signatures
- MutableTransactionSignatureChecker tx_checker(&tx, nIn, txout.nValue);
+ MutableTransactionSignatureChecker tx_checker(&tx, nIn, txout.nValue, MissingDataBehavior::FAIL);
SignatureExtractorChecker extractor_checker(data, tx_checker);
if (VerifyScript(data.scriptSig, txout.scriptPubKey, &data.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, extractor_checker)) {
data.complete = true;
@@ -499,7 +502,7 @@ bool SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore,
}
ScriptError serror = SCRIPT_ERR_OK;
- if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
+ if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount, MissingDataBehavior::FAIL), &serror)) {
if (serror == SCRIPT_ERR_INVALID_STACK_OPERATION) {
// Unable to sign input and verification failed (possible attempt to partially sign).
input_errors[i] = "Unable to sign input, invalid stack size (possibly missing key)";