feat(sighash): implement sighash bitmask [part 1/7]#911
feat(sighash): implement sighash bitmask [part 1/7]#911
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #911 +/- ##
==========================================
- Coverage 84.26% 84.12% -0.15%
==========================================
Files 320 321 +1
Lines 24455 24601 +146
Branches 3744 3773 +29
==========================================
+ Hits 20608 20696 +88
- Misses 3113 3168 +55
- Partials 734 737 +3 ☔ View full report in Codecov by Sentry. |
9ebcf3e to
9042fd7
Compare
5df23a6 to
9f778fd
Compare
| outputs=bytes_to_int(outputs) | ||
| ) | ||
| except Exception as e: | ||
| raise CustomSighashModelInvalid('Could not construct sighash bitmask.') from e |
There was a problem hiding this comment.
How can we differentiate a code bug from a bad input? I feel that we should capture only the exceptions raised by the bytes_to_int() and let all others blow up.
There was a problem hiding this comment.
Changed in b611297 to catch only pydantic.ValidationError. The bytes_to_int() function does not raise any exceptions explicitly, so the only expected exception to be raised here is the model validation from pydantic.
However, I believe this is a shortcoming caused by the try-except model itself. There's no way to formally differentiate between exceptions caused by bugs or bad inputs, because there's no formally typed list of expected exceptions. In my opinion we should improve this by using result monads throughout the code.
hathor/transaction/scripts/opcode.py
Outdated
| max_inputs=bytes_to_int(max_inputs), | ||
| max_outputs=bytes_to_int(max_outputs) | ||
| ) | ||
| except Exception as e: |
b611297 to
783f397
Compare
783f397 to
ebebb1f
Compare
|
| Branch | feat/sighash/bitmask |
| Testbed | ubuntu-22.04 |
Click to view all benchmark results
| Benchmark | Latency | Benchmark Result minutes (m) (Result Δ%) | Lower Boundary minutes (m) (Limit %) | Upper Boundary minutes (m) (Limit %) |
|---|---|---|---|---|
| sync-v2 (up to 20000 blocks) | 📈 view plot 🚷 view threshold | 1.50 m(-7.99%)Baseline: 1.63 m | 1.47 m (97.82%) | 1.79 m (83.65%) |
ebebb1f to
3c1f9a7
Compare
3c1f9a7 to
a457f0a
Compare
|
|
||
|
|
||
| def script_eval(tx: Transaction, txin: TxInput, spent_tx: BaseTransaction) -> None: | ||
| def script_eval(tx: Transaction, spent_tx: BaseTransaction, *, input_index: int) -> 'ScriptContext': |
There was a problem hiding this comment.
As you're already changing the method signature, you can put it all as kwargs only, right? The docstring is also outdated with the new signature.
| self.verify_script(tx=tx, input_tx=input_tx, spent_tx=spent_tx) | ||
| script_context = self.verify_script(tx=tx, spent_tx=spent_tx, input_index=input_index) | ||
| selected_outputs = script_context.get_selected_outputs() | ||
| all_selected_outputs = all_selected_outputs.union(selected_outputs) |
There was a problem hiding this comment.
You can use all_selected_outputs.update(selected_outputs) to prevent creating a new set.
2f8579f to
6bbc55a
Compare
6bbc55a to
922055e
Compare
eb416fa to
21d7909
Compare
Depends on #851
Motivation
Implement the new SIGHASH structure. This PR implements everything necessary for creating P2PKH inputs/outputs using
OP_SIGHASH_BITMASK. That is, creating atomic swap txs is already fully functional, but gated to prevent a fork (this will later be toggled by Feature Activation).Adding support for
OP_SIGHASH_RANGEand MultiSig is straightforward and will be done in separate PRs. Tests for new functionality will also be implemented in a separate PR.Acceptance Criteria
SighashAll,SighashBitmask,SighashRange, andSighashLimit.evaluate_final_context()and changeexecute_eval()to call it.execute_eval()andscript_eval()to return the selected outputs from the context.op_sighash_bitmask()andop_max_inputs_outputs().op_checksig()to use theScriptContextfor signature verification.is_opcode_valid()and use it to gate new opcodes inexecute_op_code().P2PKH.create_input_data()to supportSighashBitmaskandSighashLimit.ScriptContextwith methods for interacting with sighash.Transaction.get_custom_sighash_data()and changeget_sighash_all()to unify implementations.TransactionVerifier.verify_inputs()to check for unsigned outputs.