@@ -35,22 +35,54 @@ const char* GetTxnOutputType(txnouttype t)
35
35
return nullptr ;
36
36
}
37
37
38
- bool Solver (const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector< unsigned char > >& vSolutionsRet )
38
+ static bool MatchPayToPubkey (const CScript& script, valtype& pubkey )
39
39
{
40
- // Templates
41
- static std::multimap<txnouttype, CScript> mTemplates ;
42
- if (mTemplates .empty ())
43
- {
44
- // Standard tx, sender provides pubkey, receiver adds signature
45
- mTemplates .insert (std::make_pair (TX_PUBKEY, CScript () << OP_PUBKEY << OP_CHECKSIG));
40
+ if (script.size () == CPubKey::PUBLIC_KEY_SIZE + 2 && script[0 ] == CPubKey::PUBLIC_KEY_SIZE && script.back () == OP_CHECKSIG) {
41
+ pubkey = valtype (script.begin () + 1 , script.begin () + CPubKey::PUBLIC_KEY_SIZE + 1 );
42
+ return CPubKey::ValidSize (pubkey);
43
+ }
44
+ if (script.size () == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 2 && script[0 ] == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE && script.back () == OP_CHECKSIG) {
45
+ pubkey = valtype (script.begin () + 1 , script.begin () + CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1 );
46
+ return CPubKey::ValidSize (pubkey);
47
+ }
48
+ return false ;
49
+ }
46
50
47
- // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
48
- mTemplates .insert (std::make_pair (TX_PUBKEYHASH, CScript () << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
51
+ static bool MatchPayToPubkeyHash (const CScript& script, valtype& pubkeyhash)
52
+ {
53
+ if (script.size () == 25 && script[0 ] == OP_DUP && script[1 ] == OP_HASH160 && script[2 ] == 20 && script[23 ] == OP_EQUALVERIFY && script[24 ] == OP_CHECKSIG) {
54
+ pubkeyhash = valtype (script.begin () + 3 , script.begin () + 23 );
55
+ return true ;
56
+ }
57
+ return false ;
58
+ }
59
+
60
+ /* * Test for "small positive integer" script opcodes - OP_1 through OP_16. */
61
+ static constexpr bool IsSmallInteger (opcodetype opcode)
62
+ {
63
+ return opcode >= OP_1 && opcode <= OP_16;
64
+ }
49
65
50
- // Sender provides N pubkeys, receivers provides M signatures
51
- mTemplates .insert (std::make_pair (TX_MULTISIG, CScript () << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
66
+ static bool MatchMultisig (const CScript& script, unsigned int & required, std::vector<valtype>& pubkeys)
67
+ {
68
+ opcodetype opcode;
69
+ valtype data;
70
+ CScript::const_iterator it = script.begin ();
71
+ if (script.size () < 1 || script.back () != OP_CHECKMULTISIG) return false ;
72
+
73
+ if (!script.GetOp (it, opcode, data) || !IsSmallInteger (opcode)) return false ;
74
+ required = CScript::DecodeOP_N (opcode);
75
+ while (script.GetOp (it, opcode, data) && CPubKey::ValidSize (data)) {
76
+ pubkeys.emplace_back (std::move (data));
52
77
}
78
+ if (!IsSmallInteger (opcode)) return false ;
79
+ unsigned int keys = CScript::DecodeOP_N (opcode);
80
+ if (pubkeys.size () != keys || keys < required) return false ;
81
+ return (it + 1 == script.end ());
82
+ }
53
83
84
+ bool Solver (const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char > >& vSolutionsRet)
85
+ {
54
86
vSolutionsRet.clear ();
55
87
56
88
// Shortcut for pay-to-script-hash, which are more constrained than the other types:
@@ -95,84 +127,27 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
95
127
return true ;
96
128
}
97
129
98
- // Scan templates
99
- const CScript& script1 = scriptPubKey;
100
- for ( const std::pair<txnouttype, CScript>& tplate : mTemplates )
101
- {
102
- const CScript& script2 = tplate. second ;
103
- vSolutionsRet. clear ();
130
+ std::vector< unsigned char > data;
131
+ if ( MatchPayToPubkey (scriptPubKey, data)) {
132
+ typeRet = TX_PUBKEY;
133
+ vSolutionsRet. push_back ( std::move (data));
134
+ return true ;
135
+ }
104
136
105
- opcodetype opcode1, opcode2;
106
- std::vector<unsigned char > vch1, vch2;
137
+ if (MatchPayToPubkeyHash (scriptPubKey, data)) {
138
+ typeRet = TX_PUBKEYHASH;
139
+ vSolutionsRet.push_back (std::move (data));
140
+ return true ;
141
+ }
107
142
108
- // Compare
109
- CScript::const_iterator pc1 = script1.begin ();
110
- CScript::const_iterator pc2 = script2.begin ();
111
- while (true )
112
- {
113
- if (pc1 == script1.end () && pc2 == script2.end ())
114
- {
115
- // Found a match
116
- typeRet = tplate.first ;
117
- if (typeRet == TX_MULTISIG)
118
- {
119
- // Additional checks for TX_MULTISIG:
120
- unsigned char m = vSolutionsRet.front ()[0 ];
121
- unsigned char n = vSolutionsRet.back ()[0 ];
122
- if (m < 1 || n < 1 || m > n || vSolutionsRet.size ()-2 != n)
123
- return false ;
124
- }
125
- return true ;
126
- }
127
- if (!script1.GetOp (pc1, opcode1, vch1))
128
- break ;
129
- if (!script2.GetOp (pc2, opcode2, vch2))
130
- break ;
131
-
132
- // Template matching opcodes:
133
- if (opcode2 == OP_PUBKEYS)
134
- {
135
- while (CPubKey::ValidSize (vch1))
136
- {
137
- vSolutionsRet.push_back (vch1);
138
- if (!script1.GetOp (pc1, opcode1, vch1))
139
- break ;
140
- }
141
- if (!script2.GetOp (pc2, opcode2, vch2))
142
- break ;
143
- // Normal situation is to fall through
144
- // to other if/else statements
145
- }
146
-
147
- if (opcode2 == OP_PUBKEY)
148
- {
149
- if (!CPubKey::ValidSize (vch1))
150
- break ;
151
- vSolutionsRet.push_back (vch1);
152
- }
153
- else if (opcode2 == OP_PUBKEYHASH)
154
- {
155
- if (vch1.size () != sizeof (uint160))
156
- break ;
157
- vSolutionsRet.push_back (vch1);
158
- }
159
- else if (opcode2 == OP_SMALLINTEGER)
160
- { // Single-byte small integer pushed onto vSolutions
161
- if (opcode1 == OP_0 ||
162
- (opcode1 >= OP_1 && opcode1 <= OP_16))
163
- {
164
- char n = (char )CScript::DecodeOP_N (opcode1);
165
- vSolutionsRet.push_back (valtype (1 , n));
166
- }
167
- else
168
- break ;
169
- }
170
- else if (opcode1 != opcode2 || vch1 != vch2)
171
- {
172
- // Others must match exactly
173
- break ;
174
- }
175
- }
143
+ unsigned int required;
144
+ std::vector<std::vector<unsigned char >> keys;
145
+ if (MatchMultisig (scriptPubKey, required, keys)) {
146
+ typeRet = TX_MULTISIG;
147
+ vSolutionsRet.push_back ({static_cast <unsigned char >(required)}); // safe as required is in range 1..16
148
+ vSolutionsRet.insert (vSolutionsRet.end (), keys.begin (), keys.end ());
149
+ vSolutionsRet.push_back ({static_cast <unsigned char >(keys.size ())}); // safe as size is in range 1..16
150
+ return true ;
176
151
}
177
152
178
153
vSolutionsRet.clear ();
0 commit comments