Metadata-Version: 2.4
Name: cyscale
Version: 0.1.6
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 :: 2 - Pre-Alpha
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
Requires-Dist: more-itertools
Requires-Dist: base58>=2.0.1
Requires-Dist: requests>=2.24.0
Provides-Extra: test
Requires-Dist: coverage; extra == "test"
Requires-Dist: pytest; extra == "test"
Provides-Extra: cython
Requires-Dist: Cython>=3.0; extra == "cython"
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.).

A drop-in replacement for [py-scale-codec](https://github.com/polkascan/py-scale-codec) — same `scalecodec` module name, same public API, 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.16 |    2.60×   |
| u16 decode                                   |      2.99 |      1.25 |    2.40×   |
| u32 decode                                   |      3.11 |      1.26 |    2.47×   |
| u64 decode                                   |      3.09 |      1.22 |    2.53×   |
| u128 decode                                  |      2.91 |      1.22 |    2.39×   |
| Compact<u32> decode                          |      9.59 |      4.38 |    2.19×   |
| bool decode                                  |      2.93 |      1.18 |    2.48×   |
| H256 decode                                  |      2.93 |      1.21 |    2.41×   |
| AccountId decode (SS58 format 42)            |     11.45 |      6.11 |    1.87×   |
| Str decode                                   |     12.89 |      5.82 |    2.22×   |
| (u32, u64, bool) decode                      |     21.96 |      5.59 |    3.93×   |
| u32 encode                                   |      2.34 |      1.10 |    2.13×   |
| u64 encode                                   |      2.33 |      1.20 |    1.93×   |
| Compact<u32> encode                          |      8.85 |      4.42 |    2.00×   |
| H256 encode                                  |      2.47 |      1.01 |    2.44×   |
### Large payloads

| Benchmark                                       | py (µs)    | cy (µs)    | speedup |
|-------------------------------------------------|-----------:|-----------:|--------:|
| Vec<u32> decode (64 elements)                |    224.20 |     98.13 |    2.28×   |
| Vec<u32> decode (1,024 elements)             |   3217.32 |   1423.46 |    2.26×   |
| Vec<u32> decode (16,384 elements)            |  50396.95 |  22435.45 |    2.25×   |
| Bytes decode (1 KB)                          |     14.67 |      6.87 |    2.14×   |
| Bytes decode (64 KB)                         |     64.15 |     45.05 |    1.42×   |
| Bytes decode (512 KB)                        |    379.99 |    300.14 |    1.27×   |
| Vec<EventRecord> decode (5 events, V10)      |    301.10 |    135.32 |    2.23×   |
| MetadataVersioned decode (V10, 85 KB)        |  64958.83 |  29839.68 |    2.18×   |
| MetadataVersioned decode (V13, 219 KB)       | 143029.99 |  65651.69 |    2.18×   |
| MetadataVersioned decode (V14, 300 KB)       | 390902.34 | 183644.98 |    2.13×   |
| Bittensor metadata + portable registry (254 KB) | 443089.47 | 212345.78 |    2.09×   |

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 |     42.07 |    2.77×   |
| batch_decode AccountId ×100     |   1159.47 |    415.44 |    2.79×   |
| batch_decode AccountId ×1,000   |  11530.59 |   4112.27 |    2.80×   |
| Mixed (AccountId/u32/u128) ×100 |    599.73 |    147.75 |    4.06×   |

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).
