diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 2f5745c..e74ab7d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -34,22 +34,20 @@ jobs: with: platforms: arm64 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: "3.10" - name: Build wheels - uses: PyO3/maturin-action@v1.44.0 + uses: PyO3/maturin-action@v1.49.4 with: target: ${{ matrix.platform.target }} - args: --release --out dist --interpreter python3.9 python3.10 python3.11 python3.12 python3.13 + args: --release --out dist --interpreter python3.9 python3.10 python3.11 python3.12 python3.13 python3.14 sccache: 'true' manylinux: auto before-script-linux: | # run this installation and add CFLAGS only for aarch64 if [ "${{ matrix.platform.target }}" = "aarch64" ]; then - apt-get update - apt-get install -y pkg-config libssl-dev export CFLAGS="-D__ARM_ARCH=8" fi @@ -70,16 +68,16 @@ jobs: target: x86 steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: "3.10" architecture: ${{ matrix.platform.target }} - name: Build wheels - uses: PyO3/maturin-action@v1.44.0 + uses: PyO3/maturin-action@v1.49.4 with: target: ${{ matrix.platform.target }} - args: --release --out dist --interpreter python3.9 python3.10 python3.11 python3.12 python3.13 + args: --release --out dist --interpreter python3.9 python3.10 python3.11 python3.12 python3.13 python3.14 sccache: 'true' - name: Upload wheels @@ -99,15 +97,15 @@ jobs: target: aarch64 steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: "3.10" - name: Build wheels - uses: PyO3/maturin-action@v1 + uses: PyO3/maturin-action@v1.49.4 with: target: ${{ matrix.platform.target }} - args: --release --out dist --interpreter python3.9 python3.10 python3.11 python3.12 python3.13 + args: --release --out dist --interpreter python3.9 python3.10 python3.11 python3.12 python3.13 python3.14 sccache: 'true' - name: Upload wheels @@ -121,7 +119,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Build sdist - uses: PyO3/maturin-action@v1.44.0 + uses: PyO3/maturin-action@v1.49.4 with: command: sdist args: --out dist @@ -154,7 +152,7 @@ jobs: subject-path: 'wheels-*/*' - name: Publish to PyPI - uses: PyO3/maturin-action@v1 + uses: PyO3/maturin-action@v1.49.4 with: command: upload args: --non-interactive --skip-existing wheels-*/* diff --git a/.gitignore b/.gitignore index 54825f8..99f5798 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ target *.egg-info __pycache__ # IDE -.vscode \ No newline at end of file +.vscode diff --git a/Cargo.lock b/Cargo.lock index 88fb112..102d7c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,10 +20,36 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "base58" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bt_decode" version = "0.7.0" dependencies = [ + "base58", + "blake2", "custom_derive", "frame-metadata 16.0.0", "log", @@ -31,8 +57,6 @@ dependencies = [ "pyo3", "pyo3-log", "pythonize", - "scale-bits 0.4.0", - "scale-decode", "scale-info", "scale-value", "serde_json", @@ -44,12 +68,32 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +[[package]] +name = "cc" +version = "1.2.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" +dependencies = [ + "find-msvc-tools", + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "custom_derive" version = "0.2.0" @@ -70,6 +114,17 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "either" version = "1.13.0" @@ -82,6 +137,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + [[package]] name = "frame-metadata" version = "15.1.0" @@ -105,6 +166,16 @@ dependencies = [ "serde", ] +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -179,9 +250,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "parity-scale-codec" @@ -233,11 +304,10 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.23.3" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e484fd2c8b4cb67ab05a318f1fd6fa8f199fcc30819f08f07d200809dba26c15" +checksum = "7ba0117f4212101ee6544044dae45abe1083d30ce7b29c4b5cbdfa2354e07383" dependencies = [ - "cfg-if", "indoc", "libc", "memoffset", @@ -251,19 +321,19 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.23.3" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0e0469a84f208e20044b98965e1561028180219e35352a2afaf2b942beff3b" +checksum = "4fc6ddaf24947d12a9aa31ac65431fb1b851b8f4365426e182901eabfb87df5f" dependencies = [ - "once_cell", + "python3-dll-a", "target-lexicon", ] [[package]] name = "pyo3-ffi" -version = "0.23.3" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1547a7f9966f6f1a0f0227564a9945fe36b90da5a93b3933fc3dc03fae372d" +checksum = "025474d3928738efb38ac36d4744a74a400c901c7596199e20e45d98eb194105" dependencies = [ "libc", "pyo3-build-config", @@ -271,9 +341,9 @@ dependencies = [ [[package]] name = "pyo3-log" -version = "0.12.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be5bb22b77965a7b5394e9aae9897a0607b51df5167561ffc3b02643b4200bc7" +checksum = "d359e20231345f21a3b5b6aea7e73f4dc97e1712ef3bfe2d88997ac6a308d784" dependencies = [ "arc-swap", "log", @@ -282,9 +352,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.23.3" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb6da8ec6fa5cedd1626c886fc8749bdcbb09424a86461eb8cdf096b7c33257" +checksum = "2e64eb489f22fe1c95911b77c44cc41e7c19f3082fc81cce90f657cdc42ffded" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -294,9 +364,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.23.3" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38a385202ff5a92791168b1136afae5059d3ac118457bb7bc304c197c2d33e7d" +checksum = "100246c0ecf400b475341b8455a9213344569af29a3c841d29270e53102e0fcf" dependencies = [ "heck", "proc-macro2", @@ -305,11 +375,20 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "python3-dll-a" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d381ef313ae70b4da5f95f8a4de773c6aa5cd28f73adec4b4a31df70b66780d8" +dependencies = [ + "cc", +] + [[package]] name = "pythonize" -version = "0.23.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91a6ee7a084f913f98d70cdc3ebec07e852b735ae3059a1500db2661265da9ff" +checksum = "11e06e4cff9be2bbf2bddf28a486ae619172ea57e79787f856572878c62dcfe2" dependencies = [ "pyo3", "serde", @@ -330,15 +409,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "scale-bits" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "036575c29af9b6e4866ffb7fa055dbf623fe7a9cc159b33786de6013a6969d89" -dependencies = [ - "parity-scale-codec", -] - [[package]] name = "scale-bits" version = "0.6.0" @@ -359,7 +429,7 @@ checksum = "e98f3262c250d90e700bb802eb704e1f841e03331c2eb815e46516c4edbf5b27" dependencies = [ "derive_more", "parity-scale-codec", - "scale-bits 0.6.0", + "scale-bits", "scale-type-resolver", "smallvec", ] @@ -372,7 +442,7 @@ checksum = "4ba0b9c48dc0eb20c60b083c29447c0c4617cb7c4a4c9fef72aa5c5bc539e15e" dependencies = [ "derive_more", "parity-scale-codec", - "scale-bits 0.6.0", + "scale-bits", "scale-type-resolver", "smallvec", ] @@ -422,7 +492,7 @@ dependencies = [ "either", "frame-metadata 15.1.0", "parity-scale-codec", - "scale-bits 0.6.0", + "scale-bits", "scale-decode", "scale-encode", "scale-info", @@ -461,12 +531,24 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "1.0.109" @@ -491,9 +573,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.16" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" [[package]] name = "toml_datetime" @@ -512,6 +594,12 @@ dependencies = [ "winnow", ] +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -524,6 +612,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "winnow" version = "0.5.40" diff --git a/Cargo.toml b/Cargo.toml index 5a53533..83b7ed0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,23 +13,31 @@ name = "bt_decode" crate-type = ["cdylib"] [dependencies.pyo3] -version = "0.23.3" -features = ["extension-module"] +version = "0.26.0" +features = ["extension-module", "generate-import-lib"] [dependencies.custom_derive] path = "libs/custom-derive" [dependencies] -frame-metadata = { version = "16.0.0", features = [ "current", "decode", "serde_full" ], default-features = false } -scale-decode = { version = "0.13.0", default-features = false } +frame-metadata = { version = "16.0.0", features = [ + "current", + "decode", + "serde_full", +], default-features = false } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.11.2", features = [ "serde" ], default-features = false } -serde_json = { version = "1.0.127", features = [ "alloc" ], default-features = false } -scale-bits = { version = "0.4.0", default-features = false } +scale-info = { version = "2.11.2", features = [ + "serde", +], default-features = false } +serde_json = { version = "1.0.127", features = [ + "alloc", +], default-features = false } scale-value = { version = "0.16.2", default-features = false } -pythonize = "0.23.0" +pythonize = "0.26.0" log = { version = "0.4.25", default-features = false } -pyo3-log = { version = "0.12.1", default-features = false } +pyo3-log = { version = "0.13.1", default-features = false } +blake2 = "0.10" +base58 = "0.2" diff --git a/pyproject.toml b/pyproject.toml index cd4ed08..a3904a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ readme = "README.md" license = {file = "LICENSE"} keywords = ["substrate", "scale", "codec", "bittensor"] -dependencies = ["toml==0.10.0"] +dependencies = ["toml>=0.10.0"] requires-python = ">= 3.9" authors = [ diff --git a/src/lib.rs b/src/lib.rs index 1529f0d..7e72492 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,21 +2,27 @@ use codec::{Decode, Encode}; use custom_derive::pydecode; use frame_metadata::{RuntimeMetadata, RuntimeMetadataPrefixed}; use log; +use std::ffi::CString; use pyo3::prelude::*; +use pyo3::types::PyAny; // Implements ToPyObject for Compact where T is an unsigned integer. macro_rules! impl_UnsignedCompactIntoPy { - ( $($type:ty),* $(,)? ) => { + ($($type:ty),+) => { $( - impl IntoPy for Compact<$type> { - fn into_py(self, py: Python<'_>) -> PyObject { - let value: $type = self.0.into(); - - value.into_py(py) + impl<'py> IntoPyObject<'py> for Compact<$type> { + type Target = PyAny; + type Output = Bound<'py, Self::Target>; + type Error = PyErr; + + fn into_pyobject(self, py: Python<'py>) -> Result { + // Compact wraps codec::Compact in .0, extract inner value + let inner_value: $type = self.0.0; + Ok(inner_value.into_pyobject(py)?.into_any()) } } - )* + )+ }; } @@ -375,48 +381,54 @@ mod bt_decode { } } - fn composite_to_py_object(py: Python, value: Composite) -> PyResult> { + fn composite_to_py_object<'py>( + py: Python<'py>, + value: Composite, + ) -> PyResult> { match value { Composite::Named(inner_) => { - let dict = PyDict::new_bound(py); + let dict = PyDict::new(py); for (key, val) in inner_.iter() { let val_py = value_to_pyobject(py, val.clone())?; dict.set_item(key, val_py)?; } - Ok(dict.to_object(py)) + Ok(dict.into_pyobject(py)?.into_any()) } Composite::Unnamed(inner_) => { - let tuple = PyTuple::new_bound( + let tuple = PyTuple::new( py, inner_ .iter() .map(|val| value_to_pyobject(py, val.clone())) - .collect::>>>()?, + .collect::>>>()?, ); - Ok(tuple.to_object(py)) + Ok(tuple.unwrap().into_any()) } } } - fn value_to_pyobject(py: Python, value: Value) -> PyResult> { + fn value_to_pyobject<'py>(py: Python<'py>, value: Value) -> PyResult> { match value.value { ValueDef::::Primitive(inner) => { let value = match inner { - Primitive::U128(value) => value.to_object(py), - Primitive::U256(value) => value.to_object(py), - Primitive::I128(value) => value.to_object(py), - Primitive::I256(value) => value.to_object(py), - Primitive::Bool(value) => value.to_object(py), - Primitive::Char(value) => value.to_object(py), - Primitive::String(value) => value.to_object(py), + Primitive::U128(value) => value.into_pyobject(py)?.into_any(), + Primitive::U256(value) => value.into_pyobject(py)?.into_any(), + Primitive::I128(value) => value.into_pyobject(py)?.into_any(), + Primitive::I256(value) => value.into_pyobject(py)?.into_any(), + Primitive::Bool(value) => { + let bound = value.into_pyobject(py)?; + Bound::clone(&bound).into_any() + } + Primitive::Char(value) => value.into_pyobject(py)?.into_any(), + Primitive::String(value) => value.into_pyobject(py)?.into_any(), }; Ok(value) } ValueDef::::BitSequence(inner) => { - let value = inner.to_vec().to_object(py); + let value = inner.to_vec().into_pyobject(py)?.into_any(); Ok(value) } @@ -428,19 +440,16 @@ mod bt_decode { ValueDef::::Variant(inner) => { if inner.name == "None" || inner.name == "Some" { match inner.name.as_str() { - "None" => Ok(py.None()), + "None" => Ok(py.None().into_bound(py)), "Some" => { let some = composite_to_py_object(py, inner.values.clone())?; if inner.values.len() == 1 { let tuple = some - .downcast_bound::(py) + .downcast::() .expect("Failed to downcast back to a tuple"); - Ok(tuple - .get_item(0) - .expect("Failed to get item from tuple") - .to_object(py)) + Ok(tuple.get_item(0).expect("Failed to get item from tuple")) } else { - Ok(some.to_object(py)) + Ok(some.into_pyobject(py)?.into_any()) } } _ => Err(PyErr::new::(format!( @@ -449,28 +458,25 @@ mod bt_decode { ))), } } else { - let value = PyDict::new_bound(py); + let value = PyDict::new(py); value.set_item( inner.name.clone(), composite_to_py_object(py, inner.values)?, )?; - Ok(value.to_object(py)) + Ok(value.into_pyobject(py)?.into_any()) } } } } fn py_isinstance(py: Python, value: &Py, type_name: &str) -> PyResult { - let locals = PyDict::new_bound(py); + let locals = PyDict::new(py); locals.set_item("value", value)?; - py.run_bound( - &format!("ret = isinstance(value, {})", type_name), - None, - Some(&locals), - ) - .map_err(|e| { + let code = CString::new(format!("ret = isinstance(value, {})", type_name)) + .expect("CString conversion failed"); + py.run(&code, None, Some(&locals)).map_err(|e| { PyErr::new::(format!( "Error checking isinstance of: {}: {:?}", type_name, e @@ -483,11 +489,10 @@ mod bt_decode { } fn py_is_positive(py: Python, value: &Py) -> PyResult { - let locals = PyDict::new_bound(py); + let locals = PyDict::new(py); locals.set_item("value", value)?; - py.run_bound("ret = value >= 0", None, Some(&locals)) - .unwrap(); + py.run(c"ret = value >= 0", None, Some(&locals))?; let ret = locals.get_item("ret").unwrap().unwrap(); let result = ret.extract::()?; @@ -495,11 +500,10 @@ mod bt_decode { } fn py_has_dict_method(py: Python, value: &Py) -> PyResult { - let locals = PyDict::new_bound(py); + let locals = PyDict::new(py); locals.set_item("value", value)?; - py.run_bound("ret = hasattr(value, \'__dict__\')", None, Some(&locals)) - .unwrap(); + py.run(c"ret = hasattr(value, '__dict__')", None, Some(&locals))?; let ret = locals.get_item("ret").unwrap().unwrap(); let result = ret.extract::()?; @@ -1063,7 +1067,7 @@ mod bt_decode { )) })?; - value_to_pyobject(py, decoded) + value_to_pyobject(py, decoded).map(|value| value.unbind()) } #[pyfunction(name = "decode_list")] @@ -1099,7 +1103,7 @@ mod bt_decode { )) })?; - decoded_list.push(value_to_pyobject(py, decoded)?); + decoded_list.push(value_to_pyobject(py, decoded).map(|value| value.unbind())?); } Ok(decoded_list)