Metadata-Version: 2.4
Name: cyscale
Version: 0.4.0
Summary: Cython SCALE Codec Library
Author-email: BD Himes <b@latent.to>
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/thewhaleking/cy-scale-codec
Project-URL: Bug Reports, https://github.com/thewhaleking/cy-scale-codec/issues
Project-URL: Source, https://github.com/thewhaleking/cy-scale-codec
Keywords: scale,codec,polkascan,polkadot,substrate,blockchain,kusama,cython,bittensor
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Cython
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Provides-Extra: test
Requires-Dist: coverage; extra == "test"
Requires-Dist: pytest; extra == "test"
Requires-Dist: base58>=2.0.1; extra == "test"
Provides-Extra: cython
Requires-Dist: Cython>=3.0; extra == "cython"
Provides-Extra: requests
Requires-Dist: requests>=2.24.0; extra == "requests"
Dynamic: license-file

# cyscale

[![Build Status](https://img.shields.io/github/actions/workflow/status/thewhaleking/cyscale/unittests.yml?branch=master)](https://github.com/thewhaleking/cyscale/actions/workflows/unittests.yml?query=workflow%3A%22Run+unit+tests%22)
[![Latest Version](https://img.shields.io/pypi/v/cyscale.svg)](https://pypi.org/project/cyscale/)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/cyscale.svg)](https://pypi.org/project/cyscale/)
[![License](https://img.shields.io/pypi/l/cyscale.svg)](https://github.com/thewhaleking/cy-scale-codec/blob/master/LICENSE)

Cython-accelerated [SCALE codec](https://docs.substrate.io/reference/scale-codec/) library for Substrate-based blockchains (Polkadot, Kusama, Bittensor, etc.), with no external runtime dependencies.

A drop-in replacement for [py-scale-codec](https://github.com/polkascan/py-scale-codec): same `scalecodec` module name and public API, but compiled with Cython for improved throughput.

## Installation

```bash
pip install cyscale
```

## Performance

Benchmarked on Apple M-series (Python 3.13) against py-scale-codec 1.2.12.
All timings are µs per call; speedup = py ÷ cy.

### Primitives and small types

| Benchmark                                    |  py (µs) |  cy (µs) | speedup |
|----------------------------------------------|---------:|---------:|--------:|
| u8 decode                                    |     3.01 |     1.69 |   1.78× |
| u16 decode                                   |     2.99 |     1.80 |   1.66× |
| u32 decode                                   |     3.11 |     1.83 |   1.70× |
| u64 decode                                   |     3.09 |     1.79 |   1.73× |
| u128 decode                                  |     2.91 |     1.84 |   1.58× |
| Compact<u32> decode                          |     9.59 |     6.90 |   1.39× |
| bool decode                                  |     2.93 |     1.61 |   1.82× |
| H256 decode                                  |     2.93 |     1.66 |   1.76× |
| AccountId decode (SS58 format 42)            |    11.45 |     4.31 |   2.66× |
| Str decode                                   |    12.89 |     8.58 |   1.50× |
| (u32, u64, bool) decode                      |    21.96 |     8.36 |   2.63× |
| u32 encode                                   |     2.34 |     1.50 |   1.57× |
| u64 encode                                   |     2.33 |     1.55 |   1.50× |
| Compact<u32> encode                          |     8.85 |     6.36 |   1.39× |
| H256 encode                                  |     2.47 |     1.42 |   1.74× |
### Large payloads

| Benchmark                                       |   py (µs) |   cy (µs) |   speedup |
|-------------------------------------------------|----------:|----------:|----------:|
| Vec<u32> decode (64 elements)                   |    224.20 |     20.88 |    10.74× |
| Vec<u32> decode (1,024 elements)                |   3217.32 |    147.21 |    21.85× |
| Vec<u32> decode (16,384 elements)               |  50396.95 |   2150.86 |    23.43× |
| Bytes decode (1 KB)                             |     14.67 |      9.99 |     1.47× |
| Bytes decode (64 KB)                            |     64.15 |     63.30 |     1.01× |
| Bytes decode (512 KB)                           |    379.99 |    429.74 |     0.88× |
| Vec<EventRecord> decode (5 events, V10)         |    301.10 |    131.81 |     2.28× |
| MetadataVersioned decode (V10, 85 KB)           |  64958.83 |  35936.30 |     1.81× |
| MetadataVersioned decode (V13, 219 KB)          | 143029.99 |  81044.60 |     1.76× |
| MetadataVersioned decode (V14, 300 KB)          | 390902.34 | 185823.12 |     2.10× |
| Bittensor metadata + portable registry (254 KB) | 443089.47 | 211343.83 |     2.10× |

Primitives and small types see **~2.0–2.6× speedup**. Large metadata decoding
sees **~2.1–2.3× speedup** — the gain compounds across thousands of recursive
decode calls. Raw bulk byte operations (`Bytes`/`Vec<u8>`) above ~64 KB are
dominated by `memcpy` and see a reduced **~1.3–1.4× speedup**.

`AccountId` with SS58 encoding shows a **1.87× speedup** — the SS58 encoding
itself (`ss58_encode`) is pure Python and limits gains in that path.

### batch_decode (cyscale-only API)

`batch_decode(type_strings, bytes_list)` amortises Python dispatch overhead
across a list of decodes. The baseline below is a py-scale-codec decode loop,
which is the equivalent operation without this API.
Note: `bt_decode` is excluded from this comparison because it does not perform
SS58 encoding — including it without that post-processing step would be unfair.

| Benchmark                        | py loop (µs) | cy batch (µs) |   speedup |
|----------------------------------|-------------:|--------------:|----------:|
| batch_decode AccountId ×10       |       116.66 |         19.36 |     6.03× |
| batch_decode AccountId ×100      |      1159.47 |        190.19 |     6.10× |
| batch_decode AccountId ×1,000    |     11530.59 |       1888.99 |     6.10× |
| Mixed (AccountId/u32/u128) ×100  |       599.73 |         71.42 |     8.40× |

To reproduce, run:

```bash
# save a py-scale-codec baseline
python benchmarks/bench.py --save-baseline benchmarks/baseline_py.json

# compare against cy-scale-codec
PYTHONPATH=. python benchmarks/bench.py --compare benchmarks/baseline_py.json
```

## Examples of different types

| Type | Description | Example SCALE decoding value | SCALE encoded value |
|------|-------------|------------------------------|---------------------|
| `bool` | Boolean values are encoded using the least significant bit of a single byte. | `True` | `0x01` |
| `u16` | Basic integers are encoded using a fixed-width little-endian (LE) format. | `42` | `0x2a00` |
| `Compact` | A "compact" or general integer encoding is sufficient for encoding large integers (up to 2\*\*536) and is more efficient at encoding most values than the fixed-width version. | `1` | `0x04` |
| `Vec` | A collection of same-typed values is encoded, prefixed with a compact encoding of the number of items, followed by each item's encoding concatenated in turn. | `[4, 8, 15, 16, 23, 42]` | `0x18040008000f00100017002a00` |
| `str`, `Bytes` | Strings are Vectors of bytes (`Vec<u8>`) containing a valid UTF8 sequence. | `"Test"` | `0x1054657374` |
| `AccountId` | An [SS58 formatted](https://docs.substrate.io/reference/address-formats/) representation of an account. | `"5GDyPHLVHcQYPTWfygtPYeogQjyZy7J9fsi4brPhgEFq4pcv"` | `0xb80269ec...` |
| `Enum` | A fixed number of variants, each mutually exclusive. Encoded as the first byte identifying the index of the variant. | `{'Int': 8}` | `0x002a` |
| `Struct` | For structures, values are named but that is irrelevant for the encoding (only order matters). | `{"votes": [...], "id": 4}` | `0x04b80269...` |

## License

Apache 2.0 — see [LICENSE](LICENSE) and [NOTICE](NOTICE).
