5
5
#include " bloom.h"
6
6
7
7
#include " primitives/transaction.h"
8
+ #include " evo/specialtx.h"
9
+ #include " evo/providertx.h"
10
+ #include " evo/cbtx.h"
11
+ #include " llmq/quorums_commitment.h"
8
12
#include " hash.h"
9
13
#include " script/script.h"
10
14
#include " script/standard.h"
@@ -113,6 +117,12 @@ bool CBloomFilter::contains(const uint256& hash) const
113
117
return contains (data);
114
118
}
115
119
120
+ bool CBloomFilter::contains (const uint160& hash) const
121
+ {
122
+ std::vector<unsigned char > data (hash.begin (), hash.end ());
123
+ return contains (data);
124
+ }
125
+
116
126
void CBloomFilter::clear ()
117
127
{
118
128
vData.assign (vData.size (),0 );
@@ -131,6 +141,96 @@ bool CBloomFilter::IsWithinSizeConstraints() const
131
141
return vData.size () <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
132
142
}
133
143
144
+ // Match if the filter contains any arbitrary script data element in script
145
+ bool CBloomFilter::CheckScript (const CScript &script) const
146
+ {
147
+ CScript::const_iterator pc = script.begin ();
148
+ std::vector<unsigned char > data;
149
+ while (pc < script.end ()) {
150
+ opcodetype opcode;
151
+ if (!script.GetOp (pc, opcode, data))
152
+ break ;
153
+ if (data.size () != 0 && contains (data))
154
+ return true ;
155
+ }
156
+ return false ;
157
+ }
158
+
159
+ // If the transaction is a special transaction that has a registration
160
+ // transaction hash, test the registration transaction hash.
161
+ // If the transaction is a special transaction with any public keys or any
162
+ // public key hashes test them.
163
+ // If the transaction is a special transaction with payout addresses test
164
+ // the hash160 of those addresses.
165
+ // Filter is updated only if it has BLOOM_UPDATE_ALL flag to be able to have
166
+ // simple SPV wallets that doesn't work with DIP2 transactions (multicoin
167
+ // wallets, etc.)
168
+ bool CBloomFilter::CheckSpecialTransactionMatchesAndUpdate (const CTransaction &tx)
169
+ {
170
+ if (tx.nVersion != 3 || tx.nType == TRANSACTION_NORMAL) {
171
+ return false ; // it is not a special transaction
172
+ }
173
+ switch (tx.nType ) {
174
+ case (TRANSACTION_PROVIDER_REGISTER): {
175
+ CProRegTx proTx;
176
+ if (GetTxPayload (tx, proTx)) {
177
+ if (contains (proTx.collateralOutpoint ) ||
178
+ contains (proTx.keyIDOwner ) ||
179
+ contains (proTx.keyIDVoting ) ||
180
+ CheckScript (proTx.scriptPayout )) {
181
+ if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
182
+ insert (tx.GetHash ());
183
+ return true ;
184
+ }
185
+ }
186
+ return false ;
187
+ }
188
+ case (TRANSACTION_PROVIDER_UPDATE_SERVICE): {
189
+ CProUpServTx proTx;
190
+ if (GetTxPayload (tx, proTx)) {
191
+ if (contains (proTx.proTxHash )) {
192
+ return true ;
193
+ }
194
+ if (CheckScript (proTx.scriptOperatorPayout )) {
195
+ if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
196
+ insert (proTx.proTxHash );
197
+ return true ;
198
+ }
199
+ }
200
+ return false ;
201
+ }
202
+ case (TRANSACTION_PROVIDER_UPDATE_REGISTRAR): {
203
+ CProUpRegTx proTx;
204
+ if (GetTxPayload (tx, proTx)) {
205
+ if (contains (proTx.proTxHash ))
206
+ return true ;
207
+ if (contains (proTx.keyIDVoting ) ||
208
+ CheckScript (proTx.scriptPayout )) {
209
+ if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
210
+ insert (proTx.proTxHash );
211
+ return true ;
212
+ }
213
+ }
214
+ return false ;
215
+ }
216
+ case (TRANSACTION_PROVIDER_UPDATE_REVOKE): {
217
+ CProUpRevTx proTx;
218
+ if (GetTxPayload (tx, proTx)) {
219
+ if (contains (proTx.proTxHash ))
220
+ return true ;
221
+ }
222
+ return false ;
223
+ }
224
+ case (TRANSACTION_COINBASE):
225
+ case (TRANSACTION_QUORUM_COMMITMENT):
226
+ // No aditional checks for this transaction types
227
+ return false ;
228
+ }
229
+
230
+ LogPrintf (" Unknown special transaction type in Bloom filter check." );
231
+ return false ;
232
+ }
233
+
134
234
bool CBloomFilter::IsRelevantAndUpdate (const CTransaction& tx)
135
235
{
136
236
bool fFound = false ;
@@ -144,34 +244,27 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
144
244
if (contains (hash))
145
245
fFound = true ;
146
246
247
+ // Check additional matches for special transactions
248
+ fFound = fFound || CheckSpecialTransactionMatchesAndUpdate (tx);
249
+
147
250
for (unsigned int i = 0 ; i < tx.vout .size (); i++)
148
251
{
149
252
const CTxOut& txout = tx.vout [i];
150
253
// Match if the filter contains any arbitrary script data element in any scriptPubKey in tx
151
254
// If this matches, also add the specific output that was matched.
152
255
// This means clients don't have to update the filter themselves when a new relevant tx
153
256
// is discovered in order to find spending transactions, which avoids round-tripping and race conditions.
154
- CScript::const_iterator pc = txout.scriptPubKey .begin ();
155
- std::vector<unsigned char > data;
156
- while (pc < txout.scriptPubKey .end ())
157
- {
158
- opcodetype opcode;
159
- if (!txout.scriptPubKey .GetOp (pc, opcode, data))
160
- break ;
161
- if (data.size () != 0 && contains (data))
257
+ if (CheckScript (txout.scriptPubKey )) {
258
+ fFound = true ;
259
+ if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
260
+ insert (COutPoint (hash, i));
261
+ else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
162
262
{
163
- fFound = true ;
164
- if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
263
+ txnouttype type;
264
+ std::vector<std::vector<unsigned char > > vSolutions;
265
+ if (Solver (txout.scriptPubKey , type, vSolutions) &&
266
+ (type == TX_PUBKEY || type == TX_MULTISIG))
165
267
insert (COutPoint (hash, i));
166
- else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
167
- {
168
- txnouttype type;
169
- std::vector<std::vector<unsigned char > > vSolutions;
170
- if (Solver (txout.scriptPubKey , type, vSolutions) &&
171
- (type == TX_PUBKEY || type == TX_MULTISIG))
172
- insert (COutPoint (hash, i));
173
- }
174
- break ;
175
268
}
176
269
}
177
270
}
@@ -186,16 +279,8 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
186
279
return true ;
187
280
188
281
// Match if the filter contains any arbitrary script data element in any scriptSig in tx
189
- CScript::const_iterator pc = txin.scriptSig .begin ();
190
- std::vector<unsigned char > data;
191
- while (pc < txin.scriptSig .end ())
192
- {
193
- opcodetype opcode;
194
- if (!txin.scriptSig .GetOp (pc, opcode, data))
195
- break ;
196
- if (data.size () != 0 && contains (data))
197
- return true ;
198
- }
282
+ if (CheckScript (txin.scriptSig ))
283
+ return true ;
199
284
}
200
285
201
286
return false ;
0 commit comments