-
Notifications
You must be signed in to change notification settings - Fork 260
feat(txscript): introduce human readable viewer #743
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
bcc1905
e701e0d
1a4b312
e712392
04d7320
2a89f08
75a5c91
fa1603b
4a0a6c2
1cb3b95
e23d8ac
d0c715e
b330081
5996247
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| target | ||
| web-root | ||
| **/.idea/ | ||
| **/.zed/ | ||
| /rust-toolchain | ||
| /.vscode/ | ||
| **/db-* | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| use kaspa_consensus_core::{hashing::sighash::SigHashReusedValuesSync, tx::ValidatedTransaction}; | ||
| use kaspa_txscript::{script_builder::ScriptBuilder, viewer::ScriptViewerOptions}; | ||
|
|
||
| fn main() { | ||
| let script_vec = hex::decode("4130ef124590e4e6627078a658e2eb0b89fe4733f40d8cbfe0d077ae16bb90afb0a5f10e5693352e4b9d19d77a98fe75e395ce60988a0750ab8603a252c9c7290401412294d292317d03d1a5f49a8204c35486da84bbbea604209637e2bbfb5bbfabb36bcb37fc90aeb9836ed950a42b87382880fbd926b362cdbca16e9db9891918850141c2d76d4c64c9b8a8a64fa34a69f7cea953c4f0e564463226d931481ee1fbccafd7c20500a699fc8a10d01d03219d25944081750cdbba89e6a5a64b3224f58a5a014c875320b0a2f302b97271d6d1f20f2168e8b86b037d42a52aaf7ca959bea8a8bbf859a220e040996f44024491881ad4d2f59d4397a5a1f2e169c55624cb9509693fbb7a14204e518f0ecb51eef7db45042e441bb4d99f2c68277359bea369fcb7c80bee5b0120924013135715c9a8076141a33d6528a13fa2e816d3f006897b6d6c8b1da90fd754ae").unwrap(); | ||
|
|
||
| // build the script from hex | ||
| let mut s = ScriptBuilder::new(); | ||
| s.script_mut().extend_from_slice(&script_vec); | ||
|
|
||
| // print the hexadecimal form | ||
| println!("{}", s.hex_view(0, 30)); | ||
|
|
||
| // print the human readable form | ||
| println!( | ||
| "{}", | ||
| s.string_view::<ValidatedTransaction, SigHashReusedValuesSync>(ScriptViewerOptions { contains_redeem_script: false }) | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| use crate::opcodes::to_small_int; | ||
| use kaspa_consensus_core::{hashing::sighash::SigHashReusedValues, tx::VerifiableTransaction}; | ||
| use kaspa_txscript_errors::TxScriptError; | ||
|
|
||
| use crate::opcodes::OpCodeImplementation; | ||
|
|
||
| #[derive(Debug)] | ||
| pub struct MultiSigSchnorrScriptParameters { | ||
| pub required_signatures_count: u8, | ||
| pub signers_count: u8, | ||
| pub signers_pubkey: Vec<secp256k1::XOnlyPublicKey>, | ||
| } | ||
|
|
||
| /// Extract parameters from a standard multisig script (schnorr): | ||
| /// OP_m <pubkey1> ... <pubkeyn> OP_n OP_CHECKMULTISIG | ||
| pub fn get_schnorr_multisig_params<T: VerifiableTransaction, Reused: SigHashReusedValues>( | ||
| opcodes: &[Box<dyn OpCodeImplementation<T, Reused>>], | ||
| checkmultisig_index: usize, | ||
| ) -> Result<MultiSigSchnorrScriptParameters, TxScriptError> { | ||
| let op_n = opcodes | ||
| .get(checkmultisig_index.checked_sub(1).ok_or_else(|| TxScriptError::InvalidState("index out of bounds".into()))?) | ||
| .ok_or_else(|| TxScriptError::InvalidState("index out of bounds".into()))?; | ||
|
|
||
| let n = to_small_int(op_n); | ||
| if n == 0 { | ||
| return Err(TxScriptError::InvalidPubKeyCount("n must be >= 1".into())); | ||
| } | ||
| let n_usize = n as usize; | ||
|
|
||
| let pubkeys_end = checkmultisig_index.checked_sub(1).ok_or_else(|| TxScriptError::InvalidState("index out of bounds".into()))?; | ||
| let pubkeys_start = pubkeys_end.checked_sub(n_usize).ok_or_else(|| TxScriptError::InvalidState("index out of bounds".into()))?; | ||
|
|
||
| let pubkeys_ops = | ||
| opcodes.get(pubkeys_start..pubkeys_end).ok_or_else(|| TxScriptError::InvalidState("index out of bounds".into()))?; | ||
|
|
||
| let mut pubkeys = Vec::with_capacity(n_usize); | ||
| for op in pubkeys_ops { | ||
| if !op.is_push_opcode() { | ||
| return Err(TxScriptError::InvalidOpcode("expected push opcode for pubkey".into())); | ||
| } | ||
| let data = op.get_data(); | ||
|
|
||
| match data.len() { | ||
| 32 => { | ||
| let pk = secp256k1::XOnlyPublicKey::from_slice(data).map_err(|_| TxScriptError::PubKeyFormat)?; | ||
| pubkeys.push(pk); | ||
| } | ||
| _ => return Err(TxScriptError::PubKeyFormat), | ||
| } | ||
| } | ||
|
|
||
| let op_m = opcodes | ||
| .get(pubkeys_start.checked_sub(1).ok_or_else(|| TxScriptError::InvalidState("index out of bounds".into()))?) | ||
| .ok_or_else(|| TxScriptError::InvalidState("index out of bounds".into()))?; | ||
|
|
||
| let m = to_small_int(op_m); | ||
|
|
||
| if m > n { | ||
| return Err(TxScriptError::InvalidSignatureCount("m must be <= n".into())); | ||
| } | ||
|
|
||
| Ok(MultiSigSchnorrScriptParameters { required_signatures_count: m, signers_count: n, signers_pubkey: pubkeys }) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,7 +62,7 @@ macro_rules! opcode_init { | |
| } | ||
|
|
||
| macro_rules! opcode_impl { | ||
| ($name: ident, $num: literal, $length: tt, $code: expr, $self:ident, $vm:ident ) => { | ||
| ($name: ident, $str_rep: literal, $num: literal, $length: tt, $code: expr, $self:ident, $vm:ident ) => { | ||
| type $name = OpCode<$num>; | ||
|
|
||
| impl OpcodeSerialization for $name { | ||
|
|
@@ -83,11 +83,17 @@ macro_rules! opcode_impl { | |
| } | ||
|
|
||
| impl<T: VerifiableTransaction, Reused: SigHashReusedValues> OpCodeImplementation<T, Reused> for $name {} | ||
|
|
||
| impl std::fmt::Display for $name { | ||
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
| write!(f, $str_rep) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| macro_rules! opcode_list { | ||
| ( $( opcode $(|$alias:ident|)? $name:ident<$num:literal, $length:tt>($self:ident, $vm:ident) $code: expr ) *) => { | ||
| ( $( opcode $(|$alias:ident|)? $name:ident<$str_rep:literal, $num:literal, $length:tt>($self:ident, $vm:ident) $code: expr ) *) => { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think $name:ident can be used instead on str_rep directly and it will be consistent with enum
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, let's try this 👍
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not familiar with macros, but compiler complains on introduced
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. name:ident already there. You can reuse it
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No |
||
| pub mod codes { | ||
| $( | ||
| #[allow(non_upper_case_globals)] | ||
|
|
@@ -103,7 +109,7 @@ macro_rules! opcode_list { | |
| } | ||
|
|
||
| $( | ||
| opcode_impl!($name, $num, $length, $code, $self, $vm); | ||
| opcode_impl!($name, $str_rep, $num, $length, $code, $self, $vm); | ||
|
|
||
| $( | ||
| #[allow(dead_code)] | ||
|
|
||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use faster hex. i think we should use the library everywhere instead of mixing them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in review: replace hex with faster hex for fresh code