Skip to content

Commit c5d47a5

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 a86d067 commit c5d47a5

File tree

4 files changed

+67
-21
lines changed

4 files changed

+67
-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: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,60 @@ 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 != nullptr && 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 != nullptr && 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+
sigdata.signatures.emplace(keyid, SigPair(pubkey, sig_out));
77+
return true;
78+
}
79+
return false;
80+
}
81+
3682
/**
3783
* Sign scriptPubKey using signature made with creator.
3884
* Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
3985
* unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
4086
* Returns false if scriptPubKey could not be completely satisfied.
4187
*/
4288
static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey,
43-
std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion)
89+
std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion, SignatureData& sigdata)
4490
{
4591
CScript scriptRet;
4692
uint160 h160;
@@ -59,20 +105,20 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
59105
case TX_WITNESS_UNKNOWN:
60106
return false;
61107
case TX_PUBKEY:
62-
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;
63109
ret.push_back(std::move(sig));
64110
return true;
65111
case TX_PUBKEYHASH: {
66112
keyID = CKeyID(uint160(vSolutions[0]));
67-
if (!creator.CreateSig(provider, sig, keyID, scriptPubKey, sigversion)) return false;
113+
if (!CreateSig(creator, sigdata, provider, sig, keyID, scriptPubKey, sigversion)) return false;
68114
ret.push_back(std::move(sig));
69115
CPubKey pubkey;
70-
provider.GetPubKey(keyID, pubkey);
116+
GetPubKey(&provider, &sigdata, keyID, pubkey);
71117
ret.push_back(ToByteVector(pubkey));
72118
return true;
73119
}
74120
case TX_SCRIPTHASH:
75-
if (provider.GetCScript(uint160(vSolutions[0]), scriptRet)) {
121+
if (GetCScript(&provider, &sigdata, uint160(vSolutions[0]), scriptRet)) {
76122
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
77123
return true;
78124
}
@@ -83,7 +129,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
83129
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
84130
for (size_t i = 1; i < vSolutions.size() - 1; ++i) {
85131
CPubKey pubkey = CPubKey(vSolutions[i]);
86-
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)) {
87133
ret.push_back(std::move(sig));
88134
}
89135
}
@@ -99,7 +145,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
99145

100146
case TX_WITNESS_V0_SCRIPTHASH:
101147
CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin());
102-
if (provider.GetCScript(h160, scriptRet)) {
148+
if (GetCScript(&provider, &sigdata, h160, scriptRet)) {
103149
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
104150
return true;
105151
}
@@ -131,7 +177,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
131177

132178
std::vector<valtype> result;
133179
txnouttype whichType;
134-
bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE);
180+
bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE, sigdata);
135181
bool P2SH = false;
136182
CScript subscript;
137183
sigdata.scriptWitness.stack.clear();
@@ -142,7 +188,8 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
142188
// the final scriptSig is the signatures from that
143189
// and then the serialized subscript:
144190
subscript = CScript(result[0].begin(), result[0].end());
145-
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;
146193
P2SH = true;
147194
}
148195

@@ -151,15 +198,16 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
151198
CScript witnessscript;
152199
witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG;
153200
txnouttype subType;
154-
solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0);
201+
solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata);
155202
sigdata.scriptWitness.stack = result;
156203
result.clear();
157204
}
158205
else if (solved && whichType == TX_WITNESS_V0_SCRIPTHASH)
159206
{
160207
CScript witnessscript(result[0].begin(), result[0].end());
208+
sigdata.witness_script = witnessscript;
161209
txnouttype subType;
162-
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;
163211
result.push_back(std::vector<unsigned char>(witnessscript.begin(), witnessscript.end()));
164212
sigdata.scriptWitness.stack = result;
165213
result.clear();
@@ -491,6 +539,7 @@ class DummySignatureCreator final : public BaseSignatureCreator {
491539
}
492540

493541
const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator();
542+
const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider();
494543

495544
bool IsSolvable(const SigningProvider& provider, const CScript& script)
496545
{

src/script/sign.h

Lines changed: 5 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:

0 commit comments

Comments
 (0)