Skip to content

Commit

Permalink
Python Cleanup (kaspanet#125)
Browse files Browse the repository at this point in the history
* PaymentDestination::Change in Generator

* py-note cleanup

* comment clean up

* example cleanup

* cleanup

* lint
  • Loading branch information
smartgoo authored Nov 17, 2024
1 parent 6e2c380 commit 990472d
Show file tree
Hide file tree
Showing 19 changed files with 135 additions and 119 deletions.
7 changes: 0 additions & 7 deletions consensus/client/src/utxo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,6 @@ impl UtxoEntryReference {
#[cfg(feature = "py-sdk")]
#[pymethods]
impl UtxoEntryReference {
// PY-TODO
// fn py_to_string

#[getter]
#[pyo3(name = "entry")]
pub fn entry_py(&self) -> UtxoEntry {
Expand Down Expand Up @@ -426,10 +423,6 @@ impl UtxoEntries {
#[cfg(feature = "py-sdk")]
#[pymethods]
impl UtxoEntries {
// PY-TODO
// #[new]
// pub fn py_ctor()

#[getter]
#[pyo3(name = "items")]
pub fn get_items_as_py_list(&self) -> Vec<UtxoEntryReference> {
Expand Down
2 changes: 0 additions & 2 deletions crypto/addresses/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,6 @@ impl Address {
}
}

// PY-NOTE: WASM specific fn implementations
#[wasm_bindgen]
impl Address {
#[wasm_bindgen(constructor)]
Expand Down Expand Up @@ -271,7 +270,6 @@ impl Address {
}
}

// PY-NOTE: Python specific fn implementations
#[cfg(feature = "py-sdk")]
#[pymethods]
impl Address {
Expand Down
4 changes: 1 addition & 3 deletions crypto/txscript/src/bindings/python/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,9 @@ impl ScriptBuilder {

Ok(generated_script.to_hex().into())
}

// pub fn hex_view()
}

// PY-TODO change to PyOpcode struct and handle similar to PyBinary
// PY-TODO change to PyOpcode struct and handle similar to PyBinary?
fn extract_ops(input: &Bound<PyAny>) -> PyResult<Vec<u8>> {
if let Ok(opcode) = extract_op(&input) {
// Single u8 or Opcodes variant
Expand Down
15 changes: 15 additions & 0 deletions python/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
ISC License

Copyright (c) 2022-2024 Kaspa developers

Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
57 changes: 37 additions & 20 deletions python/README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
# Python bindings for Rusty Kaspa
Rusty-Kaspa/Rust bindings for Python, using [PyO3](https://pyo3.rs/v0.20.0/) and [Maturin](https://www.maturin.rs). The result is a Python package that exposes rusty-kaspa/rust source for use in Python programs.

# Building from Source
1. Ensure Python 3.9 or higher (`python --version`) is installed.
2. Clone Python SDK source: `git clone -b python https://github.com/aspectron/rusty-kaspa.git`
3. `cd rusty-kaspa`
4. `cd python` (Python SDK crate)
5. Create Python virtual environment with `python -m venv env` or your preferred env tool.
6. Activate Python virtual environment:
- Unix-like systems: `source env/bin/activate`
- Windows: `env/scripts/activate.bat`
5. Install Maturin build tool: `pip install maturin`
6. Build Python package with Maturin:
- Build & install in current active virtual env: `maturin develop --release --features py-sdk`
- Build source and built (wheel) distributions: `maturin build --release --strip --sdist --features py-sdk`. The resulting wheel (.whl file) location will be printed `Built wheel for CPython 3.x to <filepath>`. The `.whl` file can be copied to another location or machine and installed there with `pip install <.whl filepath>`

# Usage from Python
# Kaspa Python SDK
Rusty-Kaspa Python SDK exposes select Rusty-Kaspa source for use in Python applications, allowing Python developers to interact with the Kaspa BlockDAG.

This package is built from Rusty-Kaspa's Rust source code using [PyO3](https://pyo3.rs/v0.20.0/) and [Maturin](https://www.maturin.rs) to build bindings for Python.

> [!IMPORTANT]
> Kaspa Python SDK is currently in Beta (maybe even Alpha in some regards) status. Please use accordingly.
## Features
A goal of this package is to mirror Kaspa's WASM SDK as closely as possible. From both a feature coverage and usage perspective.

The following main feature categories are currently exposed for use from Python:
- wRPC Client
- Transaction generation
- Key management

This package does not yet fully mirror WASM SDK, gaps mostly exist around wallet functionality. Future work will bring this as close as possible. The ability to read Rusty-Kaspa's RocksDB database from Python is in progress.

## Installing from Source
This package can currently be installed from source.

### Instructions
1. To build the Python SDK from source, you need to have the Rust environment installed. To do that, follow instructions in the [Installation section of Rusty Kaspa README](https://github.com/kaspanet/rusty-kaspa?tab=readme-ov-file#installation).
2. `cd rusty-kaspa/python` to enter Python SDK crate
3. Run `./build-release` script to build source and built (wheel) dists.
4. The resulting wheel (`.whl`) file location will be printed: `Built wheel for CPython 3.x to <filepath>`. The `.whl` file can be copied to another location or machine and installed there with `pip install <.whl filepath>`

### `maturin develop` vs. `maturin build`
For full details, please see `build-release` script, `build-dev` script, and [Maturin](https://www.maturin.rs) documentation.

Build & install in current active virtual env: `maturin develop --release --features py-sdk`

Build source and built (wheel) distributions: `maturin build --release --strip --sdist --features py-sdk`.

## Usage from Python

The Python SDK module name is `kaspa`. The following example shows how to connect an RPC client to Kaspa's PNN (Public Node Network).

Expand All @@ -34,7 +51,7 @@ if __name__ == "__main__":

More detailed examples can be found in `./examples`.

# Project Layout
## SDK Project Layout
The Python package `kaspa` is built from the `kaspa-python` crate, which is located at `./python`.

As such, the `kaspa` function in `./python/src/lib.rs` is a good starting point. This function uses PyO3 to add functionality to the package.
As such, the Rust `kaspa` function in `./python/src/lib.rs` is a good starting point. This function uses PyO3 to add functionality to the package.
20 changes: 13 additions & 7 deletions python/build-dev
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
#!/bin/bash

set -e

VENV_DIR="env"

if [ ! -d "$VENV_DIR" ]; then
echo "Creating virtual environment in $VENV_DIR..."
echo "Creating virtual environment in '$VENV_DIR'"
python3 -m venv $VENV_DIR
else
echo "Virtual environment already exists, using '$VENV_DIR'"
fi

echo "Activating virtual environment..."
echo "Activating virtual environment '$VENV_DIR'"
source $VENV_DIR/bin/activate

if ! command -v maturin &> /dev/null; then
echo "Maturin not found, installing..."
echo "Maturin not found in '$VENV_DIR', installing Maturin"
pip install maturin
else
echo "Maturin is already installed."
echo "Maturin is already installed in '$VENV_DIR'"
maturin --version
fi

echo "Running 'maturin develop --features py-sdk'..."
maturin develop --release --features py-sdk
BUILD_CMD="maturin develop --target-dir ./target --features py-sdk"
echo "Building with command '$BUILD_CMD'"
$BUILD_CMD

echo "Script execution completed."
echo "Build complete."
29 changes: 29 additions & 0 deletions python/build-release
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash

set -e

VENV_DIR="env"

if [ ! -d "$VENV_DIR" ]; then
echo "Creating virtual environment in '$VENV_DIR'"
python3 -m venv $VENV_DIR
else
echo "Virtual environment already exists, using '$VENV_DIR'"
fi

echo "Activating virtual environment '$VENV_DIR'"
source $VENV_DIR/bin/activate

if ! command -v maturin &> /dev/null; then
echo "Maturin not found in '$VENV_DIR', installing Maturin"
pip install maturin
else
echo "Maturin is already installed in '$VENV_DIR'"
maturin --version
fi

BUILD_CMD="maturin build --release --strip --sdist --target-dir target --out target/wheels --features py-sdk"
echo "Building with command '$BUILD_CMD'"
$BUILD_CMD

echo "Build complete."
2 changes: 1 addition & 1 deletion python/examples/transactions/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ async def main():

entries = await client.get_utxos_by_addresses({"addresses": [source_address]})
entries = entries["entries"]

entries = sorted(entries, key=lambda x: x['utxoEntry']['amount'], reverse=True)
total = sum(item['utxoEntry']['amount'] for item in entries)

Expand Down
18 changes: 9 additions & 9 deletions python/examples/transactions/krc20_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ async def main():
'lim': '1000',
}

script = ScriptBuilder()
script.add_data(public_key.to_x_only_public_key().to_string())
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)
script = ScriptBuilder()\
.add_data(public_key.to_x_only_public_key().to_string())\
.add_op(Opcodes.OpCheckSig)\
.add_op(Opcodes.OpFalse)\
.add_op(Opcodes.OpIf)\
.add_data(b'kasplex')\
.add_i64(0)\
.add_data(json.dumps(data, separators=(',', ':')).encode('utf-8'))\
.add_op(Opcodes.OpEndIf)
print(f'Script: {script.to_string()}')

p2sh_address = address_from_script_public_key(script.create_pay_to_script_hash_script(), 'testnet')
Expand Down
30 changes: 0 additions & 30 deletions python/kaspa.toml

This file was deleted.

12 changes: 10 additions & 2 deletions python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,27 @@ build-backend = "maturin"

[project]
name = "kaspa"
version = "0.0.1"
version = "0.1.0"
description = "Kaspa Python SDK"
requires-python = ">=3.8"
readme = "README.md"
license = "ISC"
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python",
"Programming Language :: Rust",
]
dependencies = []

[project.urls]
"Source" = "https://github.com/kaspanet/rusty-kaspa/tree/master/python"

[package.metadata.maturin]
name = "kaspa"
description = "Kaspa Python SDK"

[tool.maturin]
name = "kaspa"
features = ["pyo3/extension-module"]
bindings = "pyo3"
features = ["pyo3/extension-module"]
strip = true
2 changes: 0 additions & 2 deletions rpc/core/src/bindings/python/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,6 @@ try_from_args! ( dict : SubmitTransactionRequest, {
verbose_data: None,
};

// PY-TODO transaction.into()
Ok(SubmitTransactionRequest { transaction: rpc_transaction, allow_orphan })
});

Expand All @@ -254,7 +253,6 @@ try_from_args! ( dict : SubmitTransactionReplacementRequest, {
.ok_or_else(|| PyException::new_err("Key `transactions` not present"))?
.extract()?;

// PY-TODO transaction.into()
Ok(SubmitTransactionReplacementRequest { transaction: transaction.into() })
});

Expand Down
16 changes: 5 additions & 11 deletions rpc/wrpc/bindings/python/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,6 @@ impl RpcClient {
timeout_duration: Option<u64>,
retry_interval: Option<u64>,
) -> PyResult<Py<PyAny>> {
// TODO expose args to Python similar to WASM wRPC Client IConnectOptions?

let block_async_connect = block_async_connect.unwrap_or(true);
let strategy = match strategy {
Some(strategy) => ConnectStrategy::from_str(&strategy).map_err(|err| PyException::new_err(format!("{}", err)))?,
Expand Down Expand Up @@ -335,7 +333,9 @@ impl RpcClient {
Ok(())
}

// fn clear_event_listener() PY-TODO
// fn clear_event_listener PY-TODO
// fn default_port PY-TODO
// fn parse_url PY-TODO

fn remove_all_event_listeners(&self) -> PyResult<()> {
*self.inner.callbacks.lock().unwrap() = Default::default();
Expand Down Expand Up @@ -480,12 +480,6 @@ impl RpcClient {
}
}

#[pymethods]
impl RpcClient {
// PY-TODO default_port
// PY-TODO parse_url
}

#[pymethods]
impl RpcClient {
fn subscribe_utxos_changed(&self, py: Python, addresses: Vec<Address>) -> PyResult<Py<PyAny>> {
Expand Down Expand Up @@ -538,8 +532,8 @@ impl RpcClient {
}

build_wrpc_python_subscriptions!([
// UtxosChanged - added above due to parameter `addresses: Vec<Address>``
// VirtualChainChanged - added above due to paramter `include_accepted_transaction_ids: bool`
// UtxosChanged - defined above due to parameter `addresses: Vec<Address>``
// VirtualChainChanged - defined above due to paramter `include_accepted_transaction_ids: bool`
BlockAdded,
FinalityConflict,
FinalityConflictResolved,
Expand Down
Loading

0 comments on commit 990472d

Please sign in to comment.