mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-19 14:53:43 +01:00
Merge #21640: [0.21] Introduce DeferredSignatureChecker and have SignatureExtractorClass subclass it
f79189ca54Test that signrawtx works when a signed CSV and CLTV inputs are present (Andrew Chow)7de019bc61Introduce DeferringSignatureChecker and inherit with SignatureExtractor (Andrew Chow) Pull request description: Backport of #21166 ACKs for top commit: MarcoFalke: checked this is a clean cherry-pick did not review ACKf79189ca54🐖 instagibbs: ACKf79189ca54Tree-SHA512: 51e945c9b353713423d3886c557066c66a6517d2300523832e5a5471ab91a8943385096d9bf5b46910477cb4c47470431690cf3da09b9f6956fe030f13ddff51
This commit is contained in:
@@ -272,6 +272,34 @@ public:
|
||||
using TransactionSignatureChecker = GenericTransactionSignatureChecker<CTransaction>;
|
||||
using MutableTransactionSignatureChecker = GenericTransactionSignatureChecker<CMutableTransaction>;
|
||||
|
||||
class DeferringSignatureChecker : public BaseSignatureChecker
|
||||
{
|
||||
protected:
|
||||
BaseSignatureChecker& m_checker;
|
||||
|
||||
public:
|
||||
DeferringSignatureChecker(BaseSignatureChecker& checker) : m_checker(checker) {}
|
||||
|
||||
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
|
||||
{
|
||||
return m_checker.CheckECDSASignature(scriptSig, vchPubKey, scriptCode, sigversion);
|
||||
}
|
||||
|
||||
bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override
|
||||
{
|
||||
return m_checker.CheckSchnorrSignature(sig, pubkey, sigversion, execdata, serror);
|
||||
}
|
||||
|
||||
bool CheckLockTime(const CScriptNum& nLockTime) const override
|
||||
{
|
||||
return m_checker.CheckLockTime(nLockTime);
|
||||
}
|
||||
bool CheckSequence(const CScriptNum& nSequence) const override
|
||||
{
|
||||
return m_checker.CheckSequence(nSequence);
|
||||
}
|
||||
};
|
||||
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* error = nullptr);
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
|
||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr);
|
||||
|
||||
@@ -253,17 +253,17 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
|
||||
}
|
||||
|
||||
namespace {
|
||||
class SignatureExtractorChecker final : public BaseSignatureChecker
|
||||
class SignatureExtractorChecker final : public DeferringSignatureChecker
|
||||
{
|
||||
private:
|
||||
SignatureData& sigdata;
|
||||
BaseSignatureChecker& checker;
|
||||
|
||||
public:
|
||||
SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : sigdata(sigdata), checker(checker) {}
|
||||
SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : DeferringSignatureChecker(checker), sigdata(sigdata) {}
|
||||
|
||||
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
|
||||
{
|
||||
if (checker.CheckECDSASignature(scriptSig, vchPubKey, scriptCode, sigversion)) {
|
||||
if (m_checker.CheckECDSASignature(scriptSig, vchPubKey, scriptCode, sigversion)) {
|
||||
CPubKey pubkey(vchPubKey);
|
||||
sigdata.signatures.emplace(pubkey.GetID(), SigPair(pubkey, scriptSig));
|
||||
return true;
|
||||
|
||||
@@ -4,16 +4,17 @@
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test transaction signing using the signrawtransaction* RPCs."""
|
||||
|
||||
from test_framework.address import check_script, script_to_p2sh
|
||||
from test_framework.address import check_script, script_to_p2sh, script_to_p2wsh
|
||||
from test_framework.key import ECKey
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import assert_equal, assert_raises_rpc_error, find_vout_for_address, hex_str_to_bytes
|
||||
from test_framework.messages import sha256
|
||||
from test_framework.script import CScript, OP_0, OP_CHECKSIG
|
||||
from test_framework.messages import sha256, CTransaction, CTxInWitness
|
||||
from test_framework.script import CScript, OP_0, OP_CHECKSIG, OP_CHECKSEQUENCEVERIFY, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_TRUE
|
||||
from test_framework.script_util import key_to_p2pkh_script, script_to_p2sh_p2wsh_script, script_to_p2wsh_script
|
||||
from test_framework.wallet_util import bytes_to_wif
|
||||
|
||||
from decimal import Decimal
|
||||
from decimal import Decimal, getcontext
|
||||
from io import BytesIO
|
||||
|
||||
class SignRawTransactionsTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
@@ -238,6 +239,78 @@ class SignRawTransactionsTest(BitcoinTestFramework):
|
||||
txn = self.nodes[0].signrawtransactionwithwallet(hex_str, prev_txs)
|
||||
assert txn["complete"]
|
||||
|
||||
def test_signing_with_csv(self):
|
||||
self.log.info("Test signing a transaction containing a fully signed CSV input")
|
||||
self.nodes[0].walletpassphrase("password", 9999)
|
||||
getcontext().prec = 8
|
||||
|
||||
# Make sure CSV is active
|
||||
self.nodes[0].generate(500)
|
||||
|
||||
# Create a P2WSH script with CSV
|
||||
script = CScript([1, OP_CHECKSEQUENCEVERIFY, OP_DROP])
|
||||
address = script_to_p2wsh(script)
|
||||
|
||||
# Fund that address and make the spend
|
||||
txid = self.nodes[0].sendtoaddress(address, 1)
|
||||
vout = find_vout_for_address(self.nodes[0], txid, address)
|
||||
self.nodes[0].generate(1)
|
||||
utxo = self.nodes[0].listunspent()[0]
|
||||
amt = Decimal(1) + utxo["amount"] - Decimal(0.00001)
|
||||
tx = self.nodes[0].createrawtransaction(
|
||||
[{"txid": txid, "vout": vout, "sequence": 1},{"txid": utxo["txid"], "vout": utxo["vout"]}],
|
||||
[{self.nodes[0].getnewaddress(): amt}],
|
||||
self.nodes[0].getblockcount()
|
||||
)
|
||||
|
||||
# Set the witness script
|
||||
ctx = CTransaction()
|
||||
ctx.deserialize(BytesIO(hex_str_to_bytes(tx)))
|
||||
ctx.wit.vtxinwit.append(CTxInWitness())
|
||||
ctx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), script]
|
||||
tx = ctx.serialize_with_witness().hex()
|
||||
|
||||
# Sign and send the transaction
|
||||
signed = self.nodes[0].signrawtransactionwithwallet(tx)
|
||||
assert_equal(signed["complete"], True)
|
||||
self.nodes[0].sendrawtransaction(signed["hex"])
|
||||
|
||||
def test_signing_with_cltv(self):
|
||||
self.log.info("Test signing a transaction containing a fully signed CLTV input")
|
||||
self.nodes[0].walletpassphrase("password", 9999)
|
||||
getcontext().prec = 8
|
||||
|
||||
# Make sure CSV is active
|
||||
self.nodes[0].generate(1500)
|
||||
|
||||
# Create a P2WSH script with CLTV
|
||||
script = CScript([1000, OP_CHECKLOCKTIMEVERIFY, OP_DROP])
|
||||
address = script_to_p2wsh(script)
|
||||
|
||||
# Fund that address and make the spend
|
||||
txid = self.nodes[0].sendtoaddress(address, 1)
|
||||
vout = find_vout_for_address(self.nodes[0], txid, address)
|
||||
self.nodes[0].generate(1)
|
||||
utxo = self.nodes[0].listunspent()[0]
|
||||
amt = Decimal(1) + utxo["amount"] - Decimal(0.00001)
|
||||
tx = self.nodes[0].createrawtransaction(
|
||||
[{"txid": txid, "vout": vout},{"txid": utxo["txid"], "vout": utxo["vout"]}],
|
||||
[{self.nodes[0].getnewaddress(): amt}],
|
||||
self.nodes[0].getblockcount()
|
||||
)
|
||||
|
||||
# Set the witness script
|
||||
ctx = CTransaction()
|
||||
ctx.deserialize(BytesIO(hex_str_to_bytes(tx)))
|
||||
ctx.wit.vtxinwit.append(CTxInWitness())
|
||||
ctx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), script]
|
||||
tx = ctx.serialize_with_witness().hex()
|
||||
|
||||
# Sign and send the transaction
|
||||
signed = self.nodes[0].signrawtransactionwithwallet(tx)
|
||||
assert_equal(signed["complete"], True)
|
||||
self.nodes[0].sendrawtransaction(signed["hex"])
|
||||
|
||||
def run_test(self):
|
||||
self.successful_signing_test()
|
||||
self.script_verification_error_test()
|
||||
@@ -245,6 +318,8 @@ class SignRawTransactionsTest(BitcoinTestFramework):
|
||||
self.OP_1NEGATE_test()
|
||||
self.test_with_lock_outputs()
|
||||
self.test_fully_signed_tx()
|
||||
self.test_signing_with_csv()
|
||||
self.test_signing_with_cltv()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user