Skip to content

Commit 4e0725e

Browse files
committed
merge bitcoin#21166: Introduce DeferredSignatureChecker and have SignatureExtractorClass subclass it
1 parent f883122 commit 4e0725e

File tree

3 files changed

+96
-8
lines changed

3 files changed

+96
-8
lines changed

src/script/interpreter.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,28 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker
189189
using TransactionSignatureChecker = GenericTransactionSignatureChecker<CTransaction>;
190190
using MutableTransactionSignatureChecker = GenericTransactionSignatureChecker<CMutableTransaction>;
191191

192+
class DeferringSignatureChecker : public BaseSignatureChecker
193+
{
194+
protected:
195+
BaseSignatureChecker& m_checker;
196+
197+
public:
198+
DeferringSignatureChecker(BaseSignatureChecker& checker) : m_checker(checker) {}
199+
200+
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
201+
{
202+
return m_checker.CheckSig(scriptSig, vchPubKey, scriptCode, sigversion);
203+
}
204+
bool CheckLockTime(const CScriptNum& nLockTime) const override
205+
{
206+
return m_checker.CheckLockTime(nLockTime);
207+
}
208+
bool CheckSequence(const CScriptNum& nSequence) const override
209+
{
210+
return m_checker.CheckSequence(nSequence);
211+
}
212+
};
213+
192214
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
193215
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = nullptr);
194216

src/script/sign.cpp

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

220220
namespace {
221-
class SignatureExtractorChecker final : public BaseSignatureChecker
221+
class SignatureExtractorChecker final : public DeferringSignatureChecker
222222
{
223223
private:
224224
SignatureData& sigdata;
225-
BaseSignatureChecker& checker;
226225

227226
public:
228-
SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : sigdata(sigdata), checker(checker) {}
227+
SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : DeferringSignatureChecker(checker), sigdata(sigdata) {}
228+
229229
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
230230
{
231-
if (checker.CheckSig(scriptSig, vchPubKey, scriptCode, sigversion)) {
231+
if (m_checker.CheckSig(scriptSig, vchPubKey, scriptCode, sigversion)) {
232232
CPubKey pubkey(vchPubKey);
233233
sigdata.signatures.emplace(pubkey.GetID(), SigPair(pubkey, scriptSig));
234234
return true;

test/functional/rpc_signrawtransaction.py

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
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 script_to_p2sh
78
from test_framework.test_framework import BitcoinTestFramework
8-
from test_framework.util import (
9-
assert_equal,
10-
assert_raises_rpc_error,
11-
)
9+
from test_framework.util import assert_equal, assert_raises_rpc_error, find_vout_for_address
10+
from test_framework.script import CScript, OP_CHECKSEQUENCEVERIFY, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_TRUE
1211

12+
from decimal import Decimal, getcontext
1313

1414
class SignRawTransactionsTest(BitcoinTestFramework):
1515
def set_test_params(self):
@@ -153,12 +153,78 @@ def OP_1NEGATE_test(self):
153153
txn = self.nodes[0].signrawtransactionwithwallet(hex_str, prev_txs)
154154
assert txn["complete"]
155155

156+
def test_signing_with_csv(self):
157+
self.log.info("Test signing a transaction containing a fully signed CSV input")
158+
self.nodes[0].walletpassphrase("password", 9999)
159+
getcontext().prec = 8
160+
161+
# Make sure CSV is active
162+
self.generate(self.nodes[0], 500)
163+
164+
# Create a P2SH script with CSV
165+
script = CScript([1, OP_CHECKSEQUENCEVERIFY, OP_DROP, OP_TRUE])
166+
address = script_to_p2sh(script)
167+
168+
# Fund that address and make the spend
169+
txid = self.nodes[0].sendtoaddress(address, 1)
170+
vout = find_vout_for_address(self.nodes[0], txid, address)
171+
self.generate(self.nodes[0], 1)
172+
utxo = self.nodes[0].listunspent()[0]
173+
amt = Decimal(1) + utxo["amount"] - Decimal(0.00001)
174+
tx = self.nodes[0].createrawtransaction(
175+
[{"txid": txid, "vout": vout, "sequence": 1},{"txid": utxo["txid"], "vout": utxo["vout"]}],
176+
[{self.nodes[0].getnewaddress(): amt}],
177+
self.nodes[0].getblockcount()
178+
)
179+
180+
# Sign and send the transaction
181+
self.nodes[0].importaddress(script.hex(), p2sh=True)
182+
signed = self.nodes[0].signrawtransactionwithwallet(tx)
183+
assert_equal(signed["complete"], True)
184+
self.nodes[0].sendrawtransaction(signed["hex"])
185+
186+
def test_signing_with_cltv(self):
187+
self.log.info("Test signing a transaction containing a fully signed CLTV input")
188+
self.nodes[0].walletpassphrase("password", 9999)
189+
getcontext().prec = 8
190+
191+
# Make sure CSV is active
192+
self.generate(self.nodes[0], 1500)
193+
194+
# Create a P2SH script with CLTV
195+
script = CScript([1000, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_TRUE])
196+
address = script_to_p2sh(script)
197+
198+
# Fund that address and make the spend
199+
txid = self.nodes[0].sendtoaddress(address, 1)
200+
vout = find_vout_for_address(self.nodes[0], txid, address)
201+
self.generate(self.nodes[0], 1)
202+
utxo = self.nodes[0].listunspent()[0]
203+
amt = Decimal(1) + utxo["amount"] - Decimal(0.00001)
204+
tx = self.nodes[0].createrawtransaction(
205+
[{"txid": txid, "vout": vout},{"txid": utxo["txid"], "vout": utxo["vout"]}],
206+
[{self.nodes[0].getnewaddress(): amt}],
207+
self.nodes[0].getblockcount()
208+
)
209+
210+
# Sign and send the transaction
211+
self.nodes[0].importaddress(script.hex(), p2sh=True)
212+
signed = self.nodes[0].signrawtransactionwithwallet(tx)
213+
assert_equal(signed["complete"], True)
214+
self.nodes[0].sendrawtransaction(signed["hex"])
215+
156216
def run_test(self):
157217
self.successful_signing_test()
158218
self.script_verification_error_test()
159219
self.OP_1NEGATE_test()
160220
self.test_with_lock_outputs()
161221
self.test_fully_signed_tx()
222+
# Descriptor wallets enforce stricter separation between wallets with and without private
223+
# key while these tests require spending P2SH and non-P2SH inputs, which cannot reside in
224+
# the same wallet, skip.
225+
if not self.options.descriptors:
226+
self.test_signing_with_csv()
227+
self.test_signing_with_cltv()
162228

163229

164230
if __name__ == '__main__':

0 commit comments

Comments
 (0)