Skip to content

Commit ed94c8b

Browse files
committed
Replace CombineSignatures with ProduceSignature
Instead of using CombineSignatures to create the final scriptSig or scriptWitness of an input, use ProduceSignature itself. To allow for ProduceSignature to place signatures, pubkeys, and scripts that it does not know about, we pass down the SignatureData to SignStep which pulls out the information that it needs from the SignatureData.
1 parent 0422beb commit ed94c8b

File tree

4 files changed

+85
-21
lines changed

4 files changed

+85
-21
lines changed

src/bitcoin-tx.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -650,8 +650,6 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
650650
if (!fHashSingle || (i < mergedTx.vout.size()))
651651
ProduceSignature(keystore, MutableTransactionSignatureCreator(&mergedTx, i, amount, nHashType), prevPubKey, sigdata);
652652

653-
// ... and merge in other signatures:
654-
sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i, coin.out));
655653
UpdateInput(txin, sigdata);
656654
}
657655

src/rpc/rawtransaction.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -736,17 +736,15 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
736736
if (coin.IsSpent()) {
737737
throw JSONRPCError(RPC_VERIFY_ERROR, "Input not found or already spent");
738738
}
739-
const CScript& prevPubKey = coin.out.scriptPubKey;
740-
const CAmount& amount = coin.out.nValue;
741-
742739
SignatureData sigdata;
743740

744741
// ... and merge in other signatures:
745742
for (const CMutableTransaction& txv : txVariants) {
746743
if (txv.vin.size() > i) {
747-
sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i, coin.out));
744+
sigdata.MergeSignatureData(DataFromTransaction(txv, i, coin.out));
748745
}
749746
}
747+
ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(&mergedTx, i, coin.out.nValue, 1), coin.out.scriptPubKey, sigdata);
750748

751749
UpdateInput(txin, sigdata);
752750
}
@@ -880,7 +878,6 @@ UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival
880878
if (!fHashSingle || (i < mtx.vout.size())) {
881879
ProduceSignature(*keystore, MutableTransactionSignatureCreator(&mtx, i, amount, nHashType), prevPubKey, sigdata);
882880
}
883-
sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(mtx, i, coin.out));
884881

885882
UpdateInput(txin, sigdata);
886883

src/script/sign.cpp

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,61 @@ bool MutableTransactionSignatureCreator::CreateSig(const SigningProvider& provid
3333
return true;
3434
}
3535

36+
static bool GetCScript(const SigningProvider& provider, const SignatureData& sigdata, const CScriptID& scriptid, CScript& script)
37+
{
38+
if (provider.GetCScript(scriptid, script)) {
39+
return true;
40+
}
41+
// Look for scripts in SignatureData
42+
if (CScriptID(sigdata.redeem_script) == scriptid) {
43+
script = sigdata.redeem_script;
44+
return true;
45+
} else if (CScriptID(sigdata.witness_script) == scriptid) {
46+
script = sigdata.witness_script;
47+
return true;
48+
}
49+
return false;
50+
}
51+
52+
static bool GetPubKey(const SigningProvider& provider, const SignatureData& sigdata, const CKeyID& address, CPubKey& pubkey)
53+
{
54+
if (provider.GetPubKey(address, pubkey)) {
55+
return true;
56+
}
57+
// Look for pubkey in all partial sigs
58+
const auto it = sigdata.signatures.find(address);
59+
if (it != sigdata.signatures.end()) {
60+
pubkey = it->second.first;
61+
return true;
62+
}
63+
return false;
64+
}
65+
66+
static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector<unsigned char>& sig_out, const CKeyID& keyid, const CScript& scriptcode, SigVersion sigversion)
67+
{
68+
const auto it = sigdata.signatures.find(keyid);
69+
if (it != sigdata.signatures.end()) {
70+
sig_out = it->second.second;
71+
return true;
72+
}
73+
if (creator.CreateSig(provider, sig_out, keyid, scriptcode, sigversion)) {
74+
CPubKey pubkey;
75+
GetPubKey(provider, sigdata, keyid, pubkey);
76+
auto i = sigdata.signatures.emplace(keyid, SigPair(pubkey, sig_out));
77+
assert(i.second);
78+
return true;
79+
}
80+
return false;
81+
}
82+
3683
/**
3784
* Sign scriptPubKey using signature made with creator.
3885
* Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
3986
* unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
4087
* Returns false if scriptPubKey could not be completely satisfied.
4188
*/
4289
static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey,
43-
std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion)
90+
std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion, SignatureData& sigdata)
4491
{
4592
CScript scriptRet;
4693
uint160 h160;
@@ -58,20 +105,20 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
58105
case TX_WITNESS_UNKNOWN:
59106
return false;
60107
case TX_PUBKEY:
61-
if (!creator.CreateSig(provider, sig, CPubKey(vSolutions[0]).GetID(), scriptPubKey, sigversion)) return false;
108+
if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]).GetID(), scriptPubKey, sigversion)) return false;
62109
ret.push_back(std::move(sig));
63110
return true;
64111
case TX_PUBKEYHASH: {
65112
CKeyID keyID = CKeyID(uint160(vSolutions[0]));
66-
if (!creator.CreateSig(provider, sig, keyID, scriptPubKey, sigversion)) return false;
113+
if (!CreateSig(creator, sigdata, provider, sig, keyID, scriptPubKey, sigversion)) return false;
67114
ret.push_back(std::move(sig));
68115
CPubKey pubkey;
69-
provider.GetPubKey(keyID, pubkey);
116+
GetPubKey(provider, sigdata, keyID, pubkey);
70117
ret.push_back(ToByteVector(pubkey));
71118
return true;
72119
}
73120
case TX_SCRIPTHASH:
74-
if (provider.GetCScript(uint160(vSolutions[0]), scriptRet)) {
121+
if (GetCScript(provider, sigdata, uint160(vSolutions[0]), scriptRet)) {
75122
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
76123
return true;
77124
}
@@ -82,7 +129,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
82129
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
83130
for (size_t i = 1; i < vSolutions.size() - 1; ++i) {
84131
CPubKey pubkey = CPubKey(vSolutions[i]);
85-
if (ret.size() < required + 1 && creator.CreateSig(provider, sig, pubkey.GetID(), scriptPubKey, sigversion)) {
132+
if (ret.size() < required + 1 && CreateSig(creator, sigdata, provider, sig, pubkey.GetID(), scriptPubKey, sigversion)) {
86133
ret.push_back(std::move(sig));
87134
}
88135
}
@@ -98,7 +145,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
98145

99146
case TX_WITNESS_V0_SCRIPTHASH:
100147
CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin());
101-
if (provider.GetCScript(h160, scriptRet)) {
148+
if (GetCScript(provider, sigdata, h160, scriptRet)) {
102149
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
103150
return true;
104151
}
@@ -130,7 +177,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
130177

131178
std::vector<valtype> result;
132179
txnouttype whichType;
133-
bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE);
180+
bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE, sigdata);
134181
bool P2SH = false;
135182
CScript subscript;
136183
sigdata.scriptWitness.stack.clear();
@@ -141,7 +188,8 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
141188
// the final scriptSig is the signatures from that
142189
// and then the serialized subscript:
143190
subscript = CScript(result[0].begin(), result[0].end());
144-
solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE) && whichType != TX_SCRIPTHASH;
191+
sigdata.redeem_script = subscript;
192+
solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE, sigdata) && whichType != TX_SCRIPTHASH;
145193
P2SH = true;
146194
}
147195

@@ -150,15 +198,16 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
150198
CScript witnessscript;
151199
witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG;
152200
txnouttype subType;
153-
solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0);
201+
solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata);
154202
sigdata.scriptWitness.stack = result;
155203
result.clear();
156204
}
157205
else if (solved && whichType == TX_WITNESS_V0_SCRIPTHASH)
158206
{
159207
CScript witnessscript(result[0].begin(), result[0].end());
208+
sigdata.witness_script = witnessscript;
160209
txnouttype subType;
161-
solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH;
210+
solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH;
162211
result.push_back(std::vector<unsigned char>(witnessscript.begin(), witnessscript.end()));
163212
sigdata.scriptWitness.stack = result;
164213
result.clear();
@@ -290,6 +339,22 @@ void UpdateInput(CTxIn& input, const SignatureData& data)
290339
input.scriptWitness = data.scriptWitness;
291340
}
292341

342+
void SignatureData::MergeSignatureData(SignatureData sigdata)
343+
{
344+
if (complete) return;
345+
if (sigdata.complete) {
346+
*this = std::move(sigdata);
347+
return;
348+
}
349+
if (redeem_script.empty() && !sigdata.redeem_script.empty()) {
350+
redeem_script = sigdata.redeem_script;
351+
}
352+
if (witness_script.empty() && !sigdata.witness_script.empty()) {
353+
witness_script = sigdata.witness_script;
354+
}
355+
signatures.insert(std::make_move_iterator(sigdata.signatures.begin()), std::make_move_iterator(sigdata.signatures.end()));
356+
}
357+
293358
bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType)
294359
{
295360
assert(nIn < txTo.vin.size());
@@ -485,6 +550,7 @@ class DummySignatureCreator final : public BaseSignatureCreator {
485550
}
486551

487552
const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator();
553+
const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider();
488554

489555
bool IsSolvable(const SigningProvider& provider, const CScript& script)
490556
{

src/script/sign.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ class SigningProvider
2121
{
2222
public:
2323
virtual ~SigningProvider() {}
24-
virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const =0;
25-
virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const =0;
26-
virtual bool GetKey(const CKeyID &address, CKey& key) const =0;
24+
virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; }
25+
virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; }
26+
virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; }
2727
};
2828

29+
extern const SigningProvider& DUMMY_SIGNING_PROVIDER;
30+
2931
/** Interface for signature creators. */
3032
class BaseSignatureCreator {
3133
public:
@@ -68,6 +70,7 @@ struct SignatureData {
6870

6971
SignatureData() {}
7072
explicit SignatureData(const CScript& script) : scriptSig(script) {}
73+
void MergeSignatureData(SignatureData sigdata);
7174
};
7275

7376
/** Produce a script signature using a generic signature creator. */

0 commit comments

Comments
 (0)