@@ -161,124 +161,88 @@ forming a "Payment Pool".
161
161
162
162
==Detailed Specification ==
163
163
164
- The below code is the main logic for verifying CHECKTEMPLATEVERIFY, and is the canonical
165
- specification for the semantics of OP_CHECKTEMPLATEVERIFY.
166
-
167
- case OP_CHECKTEMPLATEVERIFY:
168
- {
169
- // if flags not enabled; treat as a NOP4
170
- if (!(flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH)) {
171
- if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
172
- return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
173
- break;
174
- }
175
-
176
- if (stack.size() < 1)
177
- return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
178
-
179
- // If the argument was not 32 bytes, treat as OP_NOP4:
180
- switch (stack.back().size()) {
181
- case 32:
182
- if (!checker.CheckDefaultCheckTemplateVerifyHash(stack.back())) {
183
- return set_error(serror, SCRIPT_ERR_TEMPLATE_MISMATCH);
184
- }
185
- break;
186
- default:
187
- // future upgrade can add semantics for this opcode with different length args
188
- // so discourage use when applicable
189
- if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
190
- return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
191
- }
192
- }
193
- }
194
- break;
195
-
196
- Where
197
-
198
- bool CheckDefaultCheckTemplateVerifyHash(const std::vector<unsigned char>& hash) {
199
- // note: for anti-DoS, a real implementation *must* cache parts of this computation
200
- // to avoid quadratic hashing DoS all variable length computations must be precomputed
201
- // including hashes of the scriptsigs, sequences, and outputs. See the section
202
- // "Denial of Service and Validation Costs" below.
203
- return GetDefaultCheckTemplateVerifyHash(current_tx, current_input_index) == uint256(hash);
204
- }
205
-
206
- The hash is computed as follows, where the outputs_hash and sequences_hash are computed as defined in BIP-341.
207
-
208
- /** Compute the (single) SHA256 of the concatenation of all scriptSigs in a tx. */
209
- template <class T>
210
- uint256 GetScriptSigsSHA256(const T& txTo)
211
- {
212
- CHashWriter ss(SER_GETHASH, 0);
213
- for (const auto& in : txTo.vin) {
214
- ss << in.scriptSig;
215
- }
216
- return ss.GetSHA256();
217
- }
218
- // not DoS safe, for reference/testing!
219
- uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& tx, uint32_t input_index) {
220
- return GetDefaultCheckTemplateVerifyHash(tx, GetOutputsSHA256(tx), GetSequenceSHA256(tx), input_index);
221
- }
222
- // not DoS safe for reference/testing!
223
- uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
224
- const uint32_t input_index) {
225
- bool skip_scriptSigs = std::find_if(tx.vin.begin(), tx.vin.end(),
226
- [](const CTxIn& c) { return c.scriptSig != CScript(); }) == tx.vin.end();
227
- return skip_scriptSigs ? GetDefaultCheckTemplateVerifyHashEmptyScript(tx, outputs_hash, sequences_hash, input_index) :
228
- GetDefaultCheckTemplateVerifyHashWithScript(tx, outputs_hash, sequences_hash, GetScriptSigsSHA256(tx), input_index);
229
- }
230
- // DoS safe, fixed length hash!
231
- uint256 GetDefaultCheckTemplateVerifyHashWithScript(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
232
- const uint256& scriptSig_hash, const uint32_t input_index) {
233
- auto h = CHashWriter(SER_GETHASH, 0)
234
- << tx.nVersion
235
- << tx.nLockTime
236
- << scriptSig_hash
237
- << uint32_t(tx.vin.size())
238
- << sequences_hash
239
- << uint32_t(tx.vout.size())
240
- << outputs_hash
241
- << input_index;
242
- return h.GetSHA256();
243
- }
244
- // DoS safe, fixed length hash!
245
- uint256 GetDefaultCheckTemplateVerifyHashEmptyScript(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
246
- const uint32_t input_index) {
247
- auto h = CHashWriter(SER_GETHASH, 0)
248
- << tx.nVersion
249
- << tx.nLockTime
250
- << uint32_t(tx.vin.size())
251
- << sequences_hash
252
- << uint32_t(tx.vout.size())
253
- << outputs_hash
254
- << input_index;
255
- return h.GetSHA256();
256
- }
257
-
258
- In python, this can be written as (but note this implementation is DoS-able).
259
-
260
- def get_default_check_template_hash(self, nIn):
164
+ The below code is the main logic for verifying CHECKTEMPLATEVERIFY, described
165
+ in pythonic pseduocode. The canonical specification for the semantics of
166
+ OP_CHECKTEMPLATEVERIFY as implemented in C++ in the context of Bitcoin Core can
167
+ be seen in the reference implementation.
168
+
169
+ The execution of the opcode is as follows:
170
+ def execute_bip_119(self):
171
+ # Before soft-fork activation / failed activation
172
+ if not self.flags.script_verify_default_check_template_verify_hash:
173
+ # Potentially set for node-local policy to discourage premature use
174
+ if self.flags.script_verify_discourage_upgradable_nops:
175
+ return self.errors_with(errors.script_err_discourage_upgradable_nops)
176
+ return self.return_as_nop()
177
+ # CTV always requires at least one stack argument
178
+ if len(self.stack) < 1:
179
+ return self.errors_with(errors.script_err_invalid_stack_operation)
180
+ # CTV only verifies the hash against a 32 byte argument
181
+ if len(self.stack[-1]) == 32:
182
+ # Ensure the precomputed data required for anti-DoS is available,
183
+ # or cache it on first use
184
+ if self.context.precomputed_ctv_data == None:
185
+ self.context.precomputed_ctv_data = self.context.tx.get_default_check_template_precomputed_data()
186
+ if stack[-1] != self.context.tx.get_default_check_template_hash(self.context.nIn, self.context.precomputed_ctv_data)
187
+ return self.errors_with(errors.script_err_template_mismatch)
188
+ return self.return_as_nop()
189
+ # future upgrade can add semantics for this opcode with different length args
190
+ # so discourage use when applicable
191
+ if self.flags.script_verify_discourage_upgradable_nops:
192
+ return self.errors_with(errors.script_err_discourage_upgradable_nops)
193
+ else:
194
+ return self.return_as_nop()
195
+
196
+ The computation of this hash can be implemented as specified below (where self
197
+ is the transaction type). Care must be taken that in any validation context,
198
+ the precomputed data must be initialized to prevent Denial-of-Service attacks.
199
+ Any implementation *must* cache these parts of the hash computation to avoid
200
+ quadratic hashing DoS. All variable length computations must be precomputed
201
+ including hashes of the scriptsigs, sequences, and outputs. See the section
202
+ "Denial of Service and Validation Costs" below. This is not a performance
203
+ optimization.
204
+
205
+ def get_default_check_template_precomputed_data(self):
206
+ result = {}
207
+ # If there are no scriptSigs we do not need to precompute a hash
208
+ if any(inp.scriptSig for inp in self.vin):
209
+ result["scriptSigs"] = sha256(b"".join(ser_string(inp.scriptSig) for inp in self.vin))
210
+ # The same value is also pre-computed for and defined in BIP-341 and can be shared
211
+ result["sequences"] = sha256(b"".join(struct.pack("<I", inp.nSequence) for inp in self.vin))
212
+ # The same value is also pre-computed for and defined in BIP-341 and can be shared
213
+ result["outputs"] = sha256(b"".join(out.serialize() for out in self.vout))
214
+ return result
215
+
216
+ # parameter precomputed must be passed in for DoS resistance
217
+ def get_default_check_template_hash(self, nIn, precomputed = None):
218
+ if precomputed == None:
219
+ precomputed = self.get_default_check_template_precomputed_data()
261
220
r = b""
221
+ # pack as 4 byte signed integer
262
222
r += struct.pack("<i", self.nVersion)
223
+ # pack as 4 byte unsigned integer
263
224
r += struct.pack("<I", self.nLockTime)
264
- if any(inp.scriptSig for inp in self.vin):
265
- r += sha256(b"".join(ser_string(inp.scriptSig) for inp in self.vin))
225
+ # we do not include the hash in the case where there is no
226
+ # scriptSigs
227
+ if "scriptSigs" in precomputed:
228
+ r += precomputed["scriptSigs"]
229
+ # pack as 4 byte unsigned integer
266
230
r += struct.pack("<I", len(self.vin))
267
- r += sha256(b"".join(struct.pack("<I", inp.nSequence) for inp in self.vin))
231
+ r += precomputed["sequences"]
232
+ # pack as 4 byte unsigned integer
268
233
r += struct.pack("<I", len(self.vout))
269
- r += sha256(b"".join(out.serialize() for out in self.vout))
234
+ r += precomputed["outputs"]
235
+ # pack as 4 byte unsigned integer
270
236
r += struct.pack("<I", nIn)
271
237
return sha256(r)
272
238
239
+
273
240
A PayToBareDefaultCheckTemplateVerifyHash output matches the following template:
274
241
275
- bool CScript::IsPayToBareDefaultCheckTemplateVerifyHash() const
276
- {
277
- // Extra-fast test for pay-to-basic-standard-template CScripts:
278
- return (this->size() == 34 &&
279
- (*this)[0] == 0x20 &&
280
- (*this)[33] == OP_CHECKTEMPLATEVERIFY);
281
- }
242
+ # Extra-fast test for pay-to-basic-standard-template CScripts:
243
+ def is_pay_to_bare_default_check_template_verify_hash(self):
244
+ return len(self) == 34 and self[0] == 0x20 and self[-1 ] == OP_CHECKTEMPLATEVERIFY
245
+
282
246
283
247
==Deployment ==
284
248
@@ -567,9 +531,7 @@ is O(T) (the size of the transaction).
567
531
568
532
An example of a script that could experience an DoS issue without caching is:
569
533
570
- ```
571
- <H> CTV CTV CTV... CTV
572
- ```
534
+ <H> CTV CTV CTV... CTV
573
535
574
536
Such a script would cause the intepreter to compute hashes (supposing N CTV's) over O(N*T) data.
575
537
If the scriptSigs non-nullity is not cached, then the O(T) transaction could be scanned over O(N)
0 commit comments