From e87a5bc8474dc1168ab6759b8799e2db68a6d1ba Mon Sep 17 00:00:00 2001 From: smartgoo Date: Sun, 13 Oct 2024 11:20:03 -0400 Subject: [PATCH 1/7] Python ScriptBuilder --- Cargo.lock | 3 + crypto/txscript/Cargo.toml | 3 + crypto/txscript/src/error.rs | 9 ++ crypto/txscript/src/lib.rs | 4 +- crypto/txscript/src/python/builder.rs | 188 ++++++++++++++++++++++++++ crypto/txscript/src/python/mod.rs | 9 ++ crypto/txscript/src/script_builder.rs | 2 +- crypto/txscript/src/wasm/mod.rs | 2 + crypto/txscript/src/wasm/opcodes.rs | 13 ++ python/Cargo.toml | 2 + python/examples/script_builder.py | 23 ++++ python/src/lib.rs | 3 + 12 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 crypto/txscript/src/python/builder.rs create mode 100644 crypto/txscript/src/python/mod.rs create mode 100644 python/examples/script_builder.py diff --git a/Cargo.lock b/Cargo.lock index 63dc2b3b3..cfd6ce103 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3303,6 +3303,7 @@ dependencies = [ "borsh", "cfg-if 1.0.0", "criterion", + "faster-hex", "hex", "hexplay", "indexmap 2.4.0", @@ -3315,6 +3316,7 @@ dependencies = [ "kaspa-wasm-core", "log", "parking_lot", + "pyo3", "rand 0.8.5", "secp256k1", "serde", @@ -5005,6 +5007,7 @@ dependencies = [ "kaspa-consensus-client", "kaspa-consensus-core", "kaspa-hashes", + "kaspa-txscript", "kaspa-wallet-core", "kaspa-wallet-keys", "kaspa-wrpc-python", diff --git a/crypto/txscript/Cargo.toml b/crypto/txscript/Cargo.toml index e2f492ad3..9ab09f9db 100644 --- a/crypto/txscript/Cargo.toml +++ b/crypto/txscript/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true repository.workspace = true [features] +py-sdk = ["pyo3"] wasm32-core = [] wasm32-sdk = [] @@ -17,6 +18,7 @@ wasm32-sdk = [] blake2b_simd.workspace = true borsh.workspace = true cfg-if.workspace = true +faster-hex.workspace = true hexplay.workspace = true indexmap.workspace = true itertools.workspace = true @@ -28,6 +30,7 @@ kaspa-utils.workspace = true kaspa-wasm-core.workspace = true log.workspace = true parking_lot.workspace = true +pyo3 = { workspace = true, optional = true } rand.workspace = true secp256k1.workspace = true serde_json.workspace = true diff --git a/crypto/txscript/src/error.rs b/crypto/txscript/src/error.rs index 7d45fb05e..bc9732001 100644 --- a/crypto/txscript/src/error.rs +++ b/crypto/txscript/src/error.rs @@ -1,4 +1,6 @@ use crate::script_builder; +#[cfg(feature = "py-sdk")] +use pyo3::{exceptions::PyException, prelude::PyErr}; use thiserror::Error; use wasm_bindgen::{JsError, JsValue}; use workflow_wasm::jserror::JsErrorData; @@ -87,3 +89,10 @@ impl From for Error { Self::SerdeWasmBindgen(JsValue::from(err).into()) } } + +#[cfg(feature = "py-sdk")] +impl From for PyErr { + fn from(value: Error) -> Self { + PyException::new_err(value.to_string()) + } +} diff --git a/crypto/txscript/src/lib.rs b/crypto/txscript/src/lib.rs index b145fb90e..50f19bc84 100644 --- a/crypto/txscript/src/lib.rs +++ b/crypto/txscript/src/lib.rs @@ -5,11 +5,13 @@ pub mod caches; mod data_stack; pub mod error; pub mod opcodes; +#[cfg(feature = "py-sdk")] +pub mod python; pub mod result; pub mod script_builder; pub mod script_class; pub mod standard; -#[cfg(feature = "wasm32-sdk")] +#[cfg(any(feature = "wasm32-sdk", feature = "py-sdk"))] pub mod wasm; use crate::caches::Cache; diff --git a/crypto/txscript/src/python/builder.rs b/crypto/txscript/src/python/builder.rs new file mode 100644 index 000000000..a7b75ad08 --- /dev/null +++ b/crypto/txscript/src/python/builder.rs @@ -0,0 +1,188 @@ +use crate::result::Result; +use crate::wasm::opcodes::Opcodes; +use crate::{script_builder as native, standard}; +use faster_hex::hex_decode; +use kaspa_consensus_core::tx::ScriptPublicKey; +use kaspa_utils::hex::ToHex; +use pyo3::prelude::*; +// use std::cell::{Ref, RefCell, RefMut}; +use std::sync::{Arc, Mutex, MutexGuard}; + +#[derive(Clone)] +#[pyclass] +pub struct ScriptBuilder { + script_builder: Arc>, +} + +impl ScriptBuilder { + #[inline] + pub fn inner(&self) -> MutexGuard { + self.script_builder.lock().unwrap() + } +} + +impl Default for ScriptBuilder { + fn default() -> Self { + Self { script_builder: Arc::new(Mutex::new(native::ScriptBuilder::new())) } + } +} + +#[pymethods] +impl ScriptBuilder { + #[new] + pub fn new() -> Self { + Self::default() + } + + #[staticmethod] + pub fn from_script(script: Bound) -> PyResult { + let builder = ScriptBuilder::default(); + let script = PyBinary::try_from(script)?; + builder.inner().extend(&script.data); + + Ok(builder) + } + + pub fn add_op(&self, op: Bound) -> PyResult { + let op = extract_ops(op)?; + let mut inner = self.inner(); + inner.add_op(op[0]).map_err(|err| pyo3::exceptions::PyException::new_err(format!("{}", err)))?; + + Ok(self.clone()) + } + + pub fn add_ops(&self, opcodes: Bound) -> PyResult { + let ops = extract_ops(opcodes)?; + self.inner().add_ops(&ops.as_slice()).map_err(|err| pyo3::exceptions::PyException::new_err(format!("{}", err)))?; + + Ok(self.clone()) + } + + pub fn add_data(&self, data: Bound) -> PyResult { + let data = PyBinary::try_from(data)?; + + let mut inner = self.inner(); + inner.add_data(&data.data).map_err(|err| pyo3::exceptions::PyException::new_err(format!("{}", err)))?; + + Ok(self.clone()) + } + + pub fn add_i64(&self, value: i64) -> PyResult { + let mut inner = self.inner(); + inner.add_i64(value).map_err(|err| pyo3::exceptions::PyException::new_err(format!("{}", err)))?; + + Ok(self.clone()) + } + + pub fn add_lock_time(&self, lock_time: u64) -> PyResult { + let mut inner = self.inner(); + inner.add_lock_time(lock_time).map_err(|err| pyo3::exceptions::PyException::new_err(format!("{}", err)))?; + + Ok(self.clone()) + } + + pub fn add_sequence(&self, sequence: u64) -> PyResult { + let mut inner = self.inner(); + inner.add_sequence(sequence).map_err(|err| pyo3::exceptions::PyException::new_err(format!("{}", err)))?; + + Ok(self.clone()) + } + + #[staticmethod] + pub fn canonical_data_size(data: String) -> PyResult { + let data = data.as_bytes(); + let size = native::ScriptBuilder::canonical_data_size(&data) as u32; + + Ok(size) + } + + pub fn to_string(&self) -> String { + let inner = self.inner(); + + inner.script().to_vec().iter().map(|b| format!("{:02x}", b)).collect() + } + + pub fn drain(&self) -> String { + let mut inner = self.inner(); + + String::from_utf8(inner.drain()).unwrap() + } + + #[pyo3(name = "create_pay_to_script_hash_script")] + pub fn pay_to_script_hash_script(&self) -> ScriptPublicKey { + let inner = self.inner(); + let script = inner.script(); + + standard::pay_to_script_hash_script(script) + } + + #[pyo3(name = "encode_pay_to_script_hash_signature_script")] + pub fn pay_to_script_hash_signature_script(&self, signature: String) -> Result { + let inner = self.inner(); + let script = inner.script(); + let signature = signature.as_bytes(); + let generated_script = standard::pay_to_script_hash_signature_script(script.into(), signature.to_vec())?; + + Ok(generated_script.to_hex().into()) + } + + // pub fn hex_view(&self, args: Option) -> Result { + // let inner = self.inner(); + // let script = inner.script(); + + // let config = args.map(HexViewConfig::try_from).transpose()?.unwrap_or_default(); + // Ok(config.build(script).to_string()) + // } +} + +fn extract_ops(input: Bound) -> PyResult> { + if let Ok(opcode) = extract_op(&input) { + // Single u8 or Opcodes variant + Ok(vec![opcode]) + } else if let Ok(list) = input.downcast::() { + // List of u8 or Opcodes variants + list.iter().map(|item| extract_op(&item)).collect::>>() + } else { + Err(pyo3::exceptions::PyTypeError::new_err("Expected an Opcodes enum or an integer.")) + } +} + +fn extract_op(item: &Bound) -> PyResult { + if let Ok(op) = item.extract::() { + Ok(op) + } else if let Ok(op) = item.extract::() { + Ok(op.value()) + } else { + Err(pyo3::exceptions::PyTypeError::new_err("Expected Opcodes variant or u8")) + } +} + +struct PyBinary { + pub data: Vec, +} + +impl TryFrom> for PyBinary { + type Error = PyErr; + fn try_from(value: Bound) -> Result { + if let Ok(str) = value.extract::() { + // Python `str` type of valid hex + let mut data = vec![0u8; str.len() / 2]; + match hex_decode(str.as_bytes(), &mut data) { + Ok(()) => Ok(PyBinary { data }), // Hex string + Err(_) => Err(pyo3::exceptions::PyValueError::new_err("Invalid hex string")), + } + } else if let Ok(py_bytes) = value.downcast::() { + // Python `bytes` type + Ok(PyBinary { data: py_bytes.as_bytes().to_vec() }) + } else if let Ok(op_list) = value.downcast::() { + // Python `[int]` (list of bytes) + let data = op_list.iter().map(|item| item.extract::().unwrap()).collect(); + Ok(PyBinary { data }) + } else if let Ok(op) = value.extract::() { + // Single byte + Ok(PyBinary { data: vec![op] }) + } else { + Err(pyo3::exceptions::PyTypeError::new_err("Expected `str` (of valid hex), `bytes`, `int` (u8), or `[int]` (u8)")) + } + } +} diff --git a/crypto/txscript/src/python/mod.rs b/crypto/txscript/src/python/mod.rs new file mode 100644 index 000000000..480725c72 --- /dev/null +++ b/crypto/txscript/src/python/mod.rs @@ -0,0 +1,9 @@ +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(feature = "py-sdk")] { + pub mod builder; + + pub use self::builder::*; + } +} diff --git a/crypto/txscript/src/script_builder.rs b/crypto/txscript/src/script_builder.rs index 731c47680..01f532e03 100644 --- a/crypto/txscript/src/script_builder.rs +++ b/crypto/txscript/src/script_builder.rs @@ -70,7 +70,7 @@ impl ScriptBuilder { &self.script } - #[cfg(any(test, target_arch = "wasm32"))] + #[cfg(any(test, target_arch = "wasm32", feature = "py-sdk"))] pub fn extend(&mut self, data: &[u8]) { self.script.extend(data); } diff --git a/crypto/txscript/src/wasm/mod.rs b/crypto/txscript/src/wasm/mod.rs index e88e580c7..0d293916f 100644 --- a/crypto/txscript/src/wasm/mod.rs +++ b/crypto/txscript/src/wasm/mod.rs @@ -11,5 +11,7 @@ cfg_if! { pub use self::opcodes::*; pub use self::builder::*; + } else if #[cfg(feature = "py-sdk")] { + pub mod opcodes; } } diff --git a/crypto/txscript/src/wasm/opcodes.rs b/crypto/txscript/src/wasm/opcodes.rs index 40492cc83..31b5be95c 100644 --- a/crypto/txscript/src/wasm/opcodes.rs +++ b/crypto/txscript/src/wasm/opcodes.rs @@ -1,8 +1,12 @@ +#[cfg(feature = "py-sdk")] +use pyo3::prelude::*; pub use wasm_bindgen::prelude::*; /// Kaspa Transaction Script Opcodes /// @see {@link ScriptBuilder} /// @category Consensus +#[derive(Clone)] +#[cfg_attr(feature = "py-sdk", pyclass)] #[wasm_bindgen] pub enum Opcodes { OpFalse = 0x00, @@ -294,3 +298,12 @@ pub enum Opcodes { OpPubKey = 0xfe, OpInvalidOpCode = 0xff, } + +#[cfg(feature = "py-sdk")] +#[pymethods] +impl Opcodes { + #[getter] + pub fn value(&self) -> u8 { + self.clone() as u8 + } +} diff --git a/python/Cargo.toml b/python/Cargo.toml index f5cf3e1a7..d09111ec8 100644 --- a/python/Cargo.toml +++ b/python/Cargo.toml @@ -17,6 +17,7 @@ kaspa-bip32.workspace = true kaspa-consensus-core.workspace = true kaspa-consensus-client.workspace = true kaspa-hashes.workspace = true +kaspa-txscript.workspace = true kaspa-wallet-core.workspace = true kaspa-wallet-keys.workspace = true kaspa-wrpc-python.workspace = true @@ -28,6 +29,7 @@ py-sdk = [ "pyo3/extension-module", "kaspa-addresses/py-sdk", "kaspa-consensus-client/py-sdk", + "kaspa-txscript/py-sdk", "kaspa-wallet-keys/py-sdk", "kaspa-wallet-core/py-sdk", "kaspa-wrpc-python/py-sdk", diff --git a/python/examples/script_builder.py b/python/examples/script_builder.py new file mode 100644 index 000000000..93c8fb2c7 --- /dev/null +++ b/python/examples/script_builder.py @@ -0,0 +1,23 @@ +import json + +from kaspa import Opcodes, ScriptBuilder, PrivateKey + + +if __name__ == "__main__": + private_key = PrivateKey("389840d7696e89c38856a066175e8e92697f0cf182b854c883237a50acaf1f69") + keypair = private_key.to_keypair() + + data = {"p": "krc-20", "op": "mint", "tick": "TNACHO"} + + script = ScriptBuilder() + script.add_data(keypair.public_key) + script.add_op(Opcodes.OpCheckSig) + script.add_op(Opcodes.OpFalse) + script.add_op(Opcodes.OpIf) + script.add_data(b"kasplex") + script.add_i64(0) + script.add_data(json.dumps(data, separators=(',', ':')).encode('utf-8')) + script.add_op(Opcodes.OpEndIf) + + print(script.to_string()) + p2sh_address = script.create_pay_to_script_hash_script() diff --git a/python/src/lib.rs b/python/src/lib.rs index 663c7a8b9..499ed11f7 100644 --- a/python/src/lib.rs +++ b/python/src/lib.rs @@ -21,6 +21,9 @@ cfg_if::cfg_if! { m.add_class::()?; m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; m.add_function(wrap_pyfunction!(kaspa_wallet_core::python::tx::utils::create_transaction_py, m)?)?; m.add_function(wrap_pyfunction!(kaspa_wallet_core::python::signer::py_sign_transaction, m)?)?; From e231b23fa5b3e357198230c854ad30b869482dc5 Mon Sep 17 00:00:00 2001 From: smartgoo Date: Sun, 13 Oct 2024 13:30:48 -0400 Subject: [PATCH 2/7] address_from_script_public_key py util fn --- consensus/client/src/utils.rs | 10 ++++++++++ python/src/lib.rs | 1 + 2 files changed, 11 insertions(+) diff --git a/consensus/client/src/utils.rs b/consensus/client/src/utils.rs index 4f543d45b..119ab5692 100644 --- a/consensus/client/src/utils.rs +++ b/consensus/client/src/utils.rs @@ -53,6 +53,16 @@ pub fn address_from_script_public_key(script_public_key: &ScriptPublicKeyT, netw } } +#[cfg(feature = "py-sdk")] +#[pyfunction] +#[pyo3(name = "address_from_script_public_key")] +pub fn address_from_script_public_key_py(script_public_key: &ScriptPublicKey, network: &str) -> PyResult
{ + match standard::extract_script_pub_key_address(script_public_key, network.try_into()?) { + Ok(address) => Ok(address), + Err(err) => Err(pyo3::exceptions::PyException::new_err(format!("{}", err))) + } +} + /// Returns true if the script passed is a pay-to-pubkey. /// @param script - The script ({@link HexString} or Uint8Array). /// @category Wallet SDK diff --git a/python/src/lib.rs b/python/src/lib.rs index 499ed11f7..5f40d4512 100644 --- a/python/src/lib.rs +++ b/python/src/lib.rs @@ -15,6 +15,7 @@ cfg_if::cfg_if! { m.add_class::()?; m.add_class::()?; m.add_class::()?; + m.add_function(wrap_pyfunction!(kaspa_consensus_client::address_from_script_public_key_py, m)?)?; m.add_class::()?; From ea011e6195288c109816acd4b149c2b1edded51c Mon Sep 17 00:00:00 2001 From: smartgoo Date: Sun, 13 Oct 2024 13:33:01 -0400 Subject: [PATCH 3/7] remove unused --- crypto/txscript/src/python/builder.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crypto/txscript/src/python/builder.rs b/crypto/txscript/src/python/builder.rs index a7b75ad08..09cc68fee 100644 --- a/crypto/txscript/src/python/builder.rs +++ b/crypto/txscript/src/python/builder.rs @@ -5,7 +5,6 @@ use faster_hex::hex_decode; use kaspa_consensus_core::tx::ScriptPublicKey; use kaspa_utils::hex::ToHex; use pyo3::prelude::*; -// use std::cell::{Ref, RefCell, RefMut}; use std::sync::{Arc, Mutex, MutexGuard}; #[derive(Clone)] From a4b2e89241e76202799c014712ff6c3344cc1ef5 Mon Sep 17 00:00:00 2001 From: smartgoo Date: Sun, 13 Oct 2024 13:43:35 -0400 Subject: [PATCH 4/7] tx examples --- python/examples/script_builder.py | 23 -------- python/examples/transactions/krc20_deploy.py | 53 +++++++++++++++++++ .../{ => transactions}/transaction_simple.py | 0 3 files changed, 53 insertions(+), 23 deletions(-) delete mode 100644 python/examples/script_builder.py create mode 100644 python/examples/transactions/krc20_deploy.py rename python/examples/{ => transactions}/transaction_simple.py (100%) diff --git a/python/examples/script_builder.py b/python/examples/script_builder.py deleted file mode 100644 index 93c8fb2c7..000000000 --- a/python/examples/script_builder.py +++ /dev/null @@ -1,23 +0,0 @@ -import json - -from kaspa import Opcodes, ScriptBuilder, PrivateKey - - -if __name__ == "__main__": - private_key = PrivateKey("389840d7696e89c38856a066175e8e92697f0cf182b854c883237a50acaf1f69") - keypair = private_key.to_keypair() - - data = {"p": "krc-20", "op": "mint", "tick": "TNACHO"} - - script = ScriptBuilder() - script.add_data(keypair.public_key) - script.add_op(Opcodes.OpCheckSig) - script.add_op(Opcodes.OpFalse) - script.add_op(Opcodes.OpIf) - script.add_data(b"kasplex") - script.add_i64(0) - script.add_data(json.dumps(data, separators=(',', ':')).encode('utf-8')) - script.add_op(Opcodes.OpEndIf) - - print(script.to_string()) - p2sh_address = script.create_pay_to_script_hash_script() diff --git a/python/examples/transactions/krc20_deploy.py b/python/examples/transactions/krc20_deploy.py new file mode 100644 index 000000000..6eeb1fd81 --- /dev/null +++ b/python/examples/transactions/krc20_deploy.py @@ -0,0 +1,53 @@ +import asyncio +import json + +from kaspa import ( + Opcodes, + PrivateKey, + Resolver, + RpcClient, + ScriptBuilder, + address_from_script_public_key, + create_transaction, + sign_transaction +) + +async def main(): + private_key = PrivateKey("389840d7696e89c38856a066175e8e92697f0cf182b854c883237a50acaf1f69") + keypair = private_key.to_keypair() + address = keypair.to_address("kaspatest") + + ###################### + # Commit tx + + data = { + "p": "krc-20", + "op": "deploy", + "tick": "PYSDK", + "max": "112121115100107", + "lim":" 1000", + } + + script = ScriptBuilder() + script.add_data(keypair.public_key) + script.add_op(Opcodes.OpCheckSig) + script.add_op(Opcodes.OpFalse) + script.add_op(Opcodes.OpIf) + script.add_data(b"kasplex") + script.add_i64(0) + script.add_data(json.dumps(data, separators=(',', ':')).encode('utf-8')) + script.add_op(Opcodes.OpEndIf) + + print(script.to_string()) + + p2sh_address = address_from_script_public_key(script.create_pay_to_script_hash_script(), "kaspatest") + print(p2sh_address.to_string()) + + # TODO tx submission + + ###################### + # Reveal tx + # TODO + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/python/examples/transaction_simple.py b/python/examples/transactions/transaction_simple.py similarity index 100% rename from python/examples/transaction_simple.py rename to python/examples/transactions/transaction_simple.py From f377ee53f1f8f4e0af4a4af81f57ed60254ce8c5 Mon Sep 17 00:00:00 2001 From: smartgoo Date: Sun, 13 Oct 2024 14:19:46 -0400 Subject: [PATCH 5/7] .pyi file --- crypto/txscript/src/python/builder.rs | 9 ++--- python/kaspa.pyi | 56 ++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/crypto/txscript/src/python/builder.rs b/crypto/txscript/src/python/builder.rs index 09cc68fee..2a04f3ecd 100644 --- a/crypto/txscript/src/python/builder.rs +++ b/crypto/txscript/src/python/builder.rs @@ -88,9 +88,9 @@ impl ScriptBuilder { } #[staticmethod] - pub fn canonical_data_size(data: String) -> PyResult { - let data = data.as_bytes(); - let size = native::ScriptBuilder::canonical_data_size(&data) as u32; + pub fn canonical_data_size(data: Bound) -> PyResult { + let data = PyBinary::try_from(data)?; + let size = native::ScriptBuilder::canonical_data_size(&data.data.as_slice()) as u32; Ok(size) } @@ -177,9 +177,6 @@ impl TryFrom> for PyBinary { // Python `[int]` (list of bytes) let data = op_list.iter().map(|item| item.extract::().unwrap()).collect(); Ok(PyBinary { data }) - } else if let Ok(op) = value.extract::() { - // Single byte - Ok(PyBinary { data: vec![op] }) } else { Err(pyo3::exceptions::PyTypeError::new_err("Expected `str` (of valid hex), `bytes`, `int` (u8), or `[int]` (u8)")) } diff --git a/python/kaspa.pyi b/python/kaspa.pyi index 6dbe1760c..38a0d767f 100644 --- a/python/kaspa.pyi +++ b/python/kaspa.pyi @@ -1,5 +1,5 @@ from enum import Enum -from typing import Any, Callable, Optional +from typing import Any, Callable, Optional, Union class Address: @@ -205,6 +205,16 @@ class UtxoEntryReference: def script_public_key(self) -> ScriptPublicKey: ... +def address_from_script_public_key(script_public_key: ScriptPublicKey, network: str) -> Address: ... + + +class Hash: + + def __init__(self, hex_str: str) -> None: ... + + def to_string(self) -> str: ... + + class Language(Enum): English: 1 @@ -234,6 +244,45 @@ class Mnemonic: def to_seed(self, password: Optional[str]) -> str: ... +class ScriptBuilder: + + def __init__(self) -> None: ... + + @staticmethod + def from_script(script: Union[str, bytes, list[int]]) -> ScriptBuilder: ... + + def add_op(self, op: Union[Opcode, int]) -> ScriptBuilder: ... + + def add_ops(self, opcodes: Union[list[Opcode], list[int]]) -> ScriptBuilder: ... + + def add_data(self, data: Union[str, bytes, list[int]]) -> ScriptBuilder: ... + + def add_i64(self, value: int) -> ScriptBuilder: ... + + def add_lock_time(self, lock_time: int) -> ScriptBuilder: ... + + def add_sequence(self, sequence: int) -> ScriptBuilder: ... + + @staticmethod + def canonical_data_size(data: Union[str, bytes, list[int]]) -> int: ... + + def to_string(self) -> str: ... + + def drain(self) -> str: ... + + def create_pay_to_script_hash_script(self) -> ScriptPublicKey: ... + + def encode_pay_to_script_hash_signature_script(self) -> str: ... + + +class Opcodes(Enum): ... + # TODO + + +class PaymentOutput: + + def __init__(self, address: Address, amount: int) -> None: ... + def create_transaction( utxo_entry_source: list[dict], @@ -246,11 +295,6 @@ def create_transaction( def sign_transaction(tx: Transaction, signer: list[PrivateKey], verify_sig: bool) -> Transaction: ... -class PaymentOutput: - - def __init__(self, address: Address, amount: int) -> None: ... - - class DerivationPath: def __init__(self, path: str) -> None: ... From 35c4a1f8be983aa8da8bc223aae8ea3d7d9f504e Mon Sep 17 00:00:00 2001 From: smartgoo Date: Sun, 13 Oct 2024 14:30:36 -0400 Subject: [PATCH 6/7] script builder comment --- crypto/txscript/src/python/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/txscript/src/python/builder.rs b/crypto/txscript/src/python/builder.rs index 2a04f3ecd..399a1cc47 100644 --- a/crypto/txscript/src/python/builder.rs +++ b/crypto/txscript/src/python/builder.rs @@ -164,7 +164,7 @@ impl TryFrom> for PyBinary { type Error = PyErr; fn try_from(value: Bound) -> Result { if let Ok(str) = value.extract::() { - // Python `str` type of valid hex + // Python `str` (of valid hex) let mut data = vec![0u8; str.len() / 2]; match hex_decode(str.as_bytes(), &mut data) { Ok(()) => Ok(PyBinary { data }), // Hex string From 76a4f2133494992f6594dd44d01097085c277919 Mon Sep 17 00:00:00 2001 From: smartgoo Date: Sun, 13 Oct 2024 14:34:14 -0400 Subject: [PATCH 7/7] lint --- consensus/client/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensus/client/src/utils.rs b/consensus/client/src/utils.rs index 119ab5692..c3bd0b3da 100644 --- a/consensus/client/src/utils.rs +++ b/consensus/client/src/utils.rs @@ -59,7 +59,7 @@ pub fn address_from_script_public_key(script_public_key: &ScriptPublicKeyT, netw pub fn address_from_script_public_key_py(script_public_key: &ScriptPublicKey, network: &str) -> PyResult
{ match standard::extract_script_pub_key_address(script_public_key, network.try_into()?) { Ok(address) => Ok(address), - Err(err) => Err(pyo3::exceptions::PyException::new_err(format!("{}", err))) + Err(err) => Err(pyo3::exceptions::PyException::new_err(format!("{}", err))), } }