Skip to content

Commit 245a5cd

Browse files
committed
Merge #21166: Introduce DeferredSignatureChecker and have SignatureExtractorClass subclass it
a97a929 Test that signrawtx works when a signed CSV and CLTV inputs are present (Andrew Chow) 6965456 Introduce DeferringSignatureChecker and inherit with SignatureExtractor (Andrew Chow) Pull request description: Previously SignatureExtractorChecker took a MutableTransactionSignatureChecker and passed through function calls to that. However not all functions were implemented so not everything passed through as it should have. To solve this, SignatureExctractorChecker now implements all of those functions via a new class - DeferredSignatureChecker. DeferredSignatureChecker is introduced to allow for future signature checkers which use another SignatureChecker but need to be able to do somethings outside of just the signature checking. Fixes #21151 ACKs for top commit: sipa: utACK a97a929 meshcollider: Code review ACK a97a929 instagibbs: utACK a97a929 Tree-SHA512: bca784c75c2fc3fcb74e81f4e3ff516699e8debaa2db81e12843abdfe9cf265dac11db8619751cb9b3e9bbe779805d029fabe5f3cbca5e86bfd72de3664b0b94
2 parents 9be7fe4 + a97a929 commit 245a5cd

File tree

3 files changed

+111
-8
lines changed

3 files changed

+111
-8
lines changed

src/script/interpreter.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,34 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker
272272
using TransactionSignatureChecker = GenericTransactionSignatureChecker<CTransaction>;
273273
using MutableTransactionSignatureChecker = GenericTransactionSignatureChecker<CMutableTransaction>;
274274

275+
class DeferringSignatureChecker : public BaseSignatureChecker
276+
{
277+
protected:
278+
BaseSignatureChecker& m_checker;
279+
280+
public:
281+
DeferringSignatureChecker(BaseSignatureChecker& checker) : m_checker(checker) {}
282+
283+
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
284+
{
285+
return m_checker.CheckECDSASignature(scriptSig, vchPubKey, scriptCode, sigversion);
286+
}
287+
288+
bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override
289+
{
290+
return m_checker.CheckSchnorrSignature(sig, pubkey, sigversion, execdata, serror);
291+
}
292+
293+
bool CheckLockTime(const CScriptNum& nLockTime) const override
294+
{
295+
return m_checker.CheckLockTime(nLockTime);
296+
}
297+
bool CheckSequence(const CScriptNum& nSequence) const override
298+
{
299+
return m_checker.CheckSequence(nSequence);
300+
}
301+
};
302+
275303
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);
276304
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
277305
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr);

src/script/sign.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,17 +250,17 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
250250
}
251251

252252
namespace {
253-
class SignatureExtractorChecker final : public BaseSignatureChecker
253+
class SignatureExtractorChecker final : public DeferringSignatureChecker
254254
{
255255
private:
256256
SignatureData& sigdata;
257-
BaseSignatureChecker& checker;
258257

259258
public:
260-
SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : sigdata(sigdata), checker(checker) {}
259+
SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : DeferringSignatureChecker(checker), sigdata(sigdata) {}
260+
261261
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
262262
{
263-
if (checker.CheckECDSASignature(scriptSig, vchPubKey, scriptCode, sigversion)) {
263+
if (m_checker.CheckECDSASignature(scriptSig, vchPubKey, scriptCode, sigversion)) {
264264
CPubKey pubkey(vchPubKey);
265265
sigdata.signatures.emplace(pubkey.GetID(), SigPair(pubkey, scriptSig));
266266
return true;

test/functional/rpc_signrawtransaction.py

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test transaction signing using the signrawtransaction* RPCs."""
66

7-
from test_framework.address import check_script, script_to_p2sh
7+
from test_framework.address import check_script, script_to_p2sh, script_to_p2wsh
88
from test_framework.key import ECKey
99
from test_framework.test_framework import BitcoinTestFramework
1010
from test_framework.util import assert_equal, assert_raises_rpc_error, find_vout_for_address, hex_str_to_bytes
11-
from test_framework.messages import sha256
12-
from test_framework.script import CScript, OP_0, OP_CHECKSIG
11+
from test_framework.messages import sha256, CTransaction, CTxInWitness
12+
from test_framework.script import CScript, OP_0, OP_CHECKSIG, OP_CHECKSEQUENCEVERIFY, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_TRUE
1313
from test_framework.script_util import key_to_p2pkh_script, script_to_p2sh_p2wsh_script, script_to_p2wsh_script
1414
from test_framework.wallet_util import bytes_to_wif
1515

16-
from decimal import Decimal
16+
from decimal import Decimal, getcontext
17+
from io import BytesIO
1718

1819
class SignRawTransactionsTest(BitcoinTestFramework):
1920
def set_test_params(self):
@@ -238,13 +239,87 @@ def OP_1NEGATE_test(self):
238239
txn = self.nodes[0].signrawtransactionwithwallet(hex_str, prev_txs)
239240
assert txn["complete"]
240241

242+
def test_signing_with_csv(self):
243+
self.log.info("Test signing a transaction containing a fully signed CSV input")
244+
self.nodes[0].walletpassphrase("password", 9999)
245+
getcontext().prec = 8
246+
247+
# Make sure CSV is active
248+
self.nodes[0].generate(500)
249+
250+
# Create a P2WSH script with CSV
251+
script = CScript([1, OP_CHECKSEQUENCEVERIFY, OP_DROP])
252+
address = script_to_p2wsh(script)
253+
254+
# Fund that address and make the spend
255+
txid = self.nodes[0].sendtoaddress(address, 1)
256+
vout = find_vout_for_address(self.nodes[0], txid, address)
257+
self.nodes[0].generate(1)
258+
utxo = self.nodes[0].listunspent()[0]
259+
amt = Decimal(1) + utxo["amount"] - Decimal(0.00001)
260+
tx = self.nodes[0].createrawtransaction(
261+
[{"txid": txid, "vout": vout, "sequence": 1},{"txid": utxo["txid"], "vout": utxo["vout"]}],
262+
[{self.nodes[0].getnewaddress(): amt}],
263+
self.nodes[0].getblockcount()
264+
)
265+
266+
# Set the witness script
267+
ctx = CTransaction()
268+
ctx.deserialize(BytesIO(hex_str_to_bytes(tx)))
269+
ctx.wit.vtxinwit.append(CTxInWitness())
270+
ctx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), script]
271+
tx = ctx.serialize_with_witness().hex()
272+
273+
# Sign and send the transaction
274+
signed = self.nodes[0].signrawtransactionwithwallet(tx)
275+
assert_equal(signed["complete"], True)
276+
self.nodes[0].sendrawtransaction(signed["hex"])
277+
278+
def test_signing_with_cltv(self):
279+
self.log.info("Test signing a transaction containing a fully signed CLTV input")
280+
self.nodes[0].walletpassphrase("password", 9999)
281+
getcontext().prec = 8
282+
283+
# Make sure CSV is active
284+
self.nodes[0].generate(1500)
285+
286+
# Create a P2WSH script with CLTV
287+
script = CScript([1000, OP_CHECKLOCKTIMEVERIFY, OP_DROP])
288+
address = script_to_p2wsh(script)
289+
290+
# Fund that address and make the spend
291+
txid = self.nodes[0].sendtoaddress(address, 1)
292+
vout = find_vout_for_address(self.nodes[0], txid, address)
293+
self.nodes[0].generate(1)
294+
utxo = self.nodes[0].listunspent()[0]
295+
amt = Decimal(1) + utxo["amount"] - Decimal(0.00001)
296+
tx = self.nodes[0].createrawtransaction(
297+
[{"txid": txid, "vout": vout},{"txid": utxo["txid"], "vout": utxo["vout"]}],
298+
[{self.nodes[0].getnewaddress(): amt}],
299+
self.nodes[0].getblockcount()
300+
)
301+
302+
# Set the witness script
303+
ctx = CTransaction()
304+
ctx.deserialize(BytesIO(hex_str_to_bytes(tx)))
305+
ctx.wit.vtxinwit.append(CTxInWitness())
306+
ctx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), script]
307+
tx = ctx.serialize_with_witness().hex()
308+
309+
# Sign and send the transaction
310+
signed = self.nodes[0].signrawtransactionwithwallet(tx)
311+
assert_equal(signed["complete"], True)
312+
self.nodes[0].sendrawtransaction(signed["hex"])
313+
241314
def run_test(self):
242315
self.successful_signing_test()
243316
self.script_verification_error_test()
244317
self.witness_script_test()
245318
self.OP_1NEGATE_test()
246319
self.test_with_lock_outputs()
247320
self.test_fully_signed_tx()
321+
self.test_signing_with_csv()
322+
self.test_signing_with_cltv()
248323

249324

250325
if __name__ == '__main__':

0 commit comments

Comments
 (0)