@@ -193,21 +193,27 @@ specification for the semantics of OP_CHECKTEMPLATEVERIFY.
193
193
Where
194
194
195
195
bool CheckDefaultCheckTemplateVerifyHash(const std::vector<unsigned char>& hash) {
196
+ // note: for anti-DoS, a real implementation *must* cache parts of this computation
197
+ // to avoid quadratic hashing DoS all variable length computations must be precomputed
198
+ // including hashes of the scriptsigs, sequences, and outputs. See the section
199
+ // "Denial of Service and Validation Costs" below.
196
200
return GetDefaultCheckTemplateVerifyHash(current_tx, current_input_index) == uint256(hash);
197
201
}
198
202
199
203
The hash is computed as follows:
200
-
204
+ // not DoS safe, for reference/testing!
201
205
uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& tx, uint32_t input_index) {
202
206
return GetDefaultCheckTemplateVerifyHash(tx, GetOutputsSHA256(tx), GetSequenceSHA256(tx), input_index);
203
207
}
208
+ // not DoS safe for reference/testing!
204
209
uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
205
210
const uint32_t input_index) {
206
211
bool skip_scriptSigs = std::find_if(tx.vin.begin(), tx.vin.end(),
207
212
[](const CTxIn& c) { return c.scriptSig != CScript(); }) == tx.vin.end();
208
213
return skip_scriptSigs ? GetDefaultCheckTemplateVerifyHashEmptyScript(tx, outputs_hash, sequences_hash, input_index) :
209
214
GetDefaultCheckTemplateVerifyHashWithScript(tx, outputs_hash, sequences_hash, GetScriptSigsSHA256(tx), input_index);
210
215
}
216
+ // DoS safe, fixed length hash!
211
217
uint256 GetDefaultCheckTemplateVerifyHashWithScript(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
212
218
const uint256& scriptSig_hash, const uint32_t input_index) {
213
219
auto h = CHashWriter(SER_GETHASH, 0)
@@ -221,6 +227,7 @@ The hash is computed as follows:
221
227
<< input_index;
222
228
return h.GetSHA256();
223
229
}
230
+ // DoS safe, fixed length hash!
224
231
uint256 GetDefaultCheckTemplateVerifyHashEmptyScript(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
225
232
const uint32_t input_index) {
226
233
auto h = CHashWriter(SER_GETHASH, 0)
@@ -512,6 +519,38 @@ unintentional introduction of the 'half spend' problem.
512
519
513
520
Templates, as restricted as they are, bear some risks.
514
521
522
+ ====Denial of Service and Validation Costs ====
523
+
524
+ CTV is designed to be able to be validated very cheaply without introducing DoS, either by checking a
525
+ precomputed hash or computing a hash of fixed length arguments (some of which may be cached from more
526
+ expensive computations).
527
+
528
+ In particular, CTV requires that clients cache the computation of a hash over all the scriptSigs, sequences,
529
+ and outputs. Before CTV, the hash of the scriptSigs was not required. CTV also requires that the presence of
530
+ any non-empty scriptSig be hashed, but this can be handled as a part of the scriptSigs hash.
531
+
532
+ As such, evaluating a CTV hash during consensus is always O(1) computation when the caches are available.
533
+ These caches usually must be available due to similar issues in CHECKSIG behavior. Computing the caches
534
+ is O(T) (the size of the transaction).
535
+
536
+ An example of a script that could experience an DoS issue without caching is:
537
+
538
+ ```
539
+ <H> CTV CTV CTV... CTV
540
+ ```
541
+
542
+ Such a script would cause the intepreter to compute hashes (supposing N CTV's) over O(N*T) data.
543
+ If the scriptSigs non-nullity is not cached, then the O(T) transaction could be scanned over O(N)
544
+ times as well (although cheaper than hashing, still a DoS). As such, CTV caches hashes and computations
545
+ over all variable length fields in a transaction.
546
+
547
+ For CTV, the Denial-of-Service exposure and validation costs are relatively clear. Implementors must be careful
548
+ to correctly code CTV to make use of existing caches and cache the (new for CTV) computations over scriptSigs.
549
+ Other more flexible covenant proposals may have a more difficult time solving DoS issues as more complex computations may
550
+ be less cacheable and expose issues around quadratic hashing, it is a tradeoff CTV makes in favor of cheap and secure
551
+ validation at the expense of flexibility. For example, if CTV allowed the hashing only select outputs by a bitmask,
552
+ caching of all combinations of outputs would not be possible and would cause a quadratic hashing DoS vulnerability.
553
+
515
554
====Permanently Unspendable Outputs ====
516
555
517
556
The preimage argument passed to CHECKTEMPLATEVERIFY may be unknown or otherwise unsatisfiable.
@@ -603,6 +642,7 @@ Given the simplicity of this approach to implement and analyze, and the benefits
603
642
applications, CHECKTEMPLATEVERIFY's template based approach is proposed in lieu of more complete
604
643
covenants system.
605
644
645
+
606
646
====Future Upgrades ====
607
647
608
648
This section describes updates to OP_CHECKTEMPLATEVERIFY that are possible in
0 commit comments