diff --git a/.github/workflows/code_checks.yml b/.github/workflows/code_checks.yml index e16703d..3a57ac2 100644 --- a/.github/workflows/code_checks.yml +++ b/.github/workflows/code_checks.yml @@ -36,7 +36,7 @@ jobs: - name: Install Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \ - --default-toolchain $(python ./build-tools/cargo-info-extractor/extract.py --rust-version) + --default-toolchain $(python ./build-tools/cargo-info-extractor/extract.py --rust-version-for-checks) - name: Install Clippy run: rustup component add clippy @@ -63,7 +63,7 @@ jobs: - name: Install Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \ - --default-toolchain $(python ./build-tools/cargo-info-extractor/extract.py --rust-version) + --default-toolchain $(python ./build-tools/cargo-info-extractor/extract.py --rust-version-for-checks) - name: Install Clippy run: rustup component add clippy @@ -99,7 +99,7 @@ jobs: shell: bash run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \ - --default-toolchain $(python ./build-tools/cargo-info-extractor/extract.py --rust-version) + --default-toolchain $(python ./build-tools/cargo-info-extractor/extract.py --rust-version-for-checks) - name: Install Clippy run: rustup component add clippy diff --git a/Cargo.lock b/Cargo.lock index be10bba..7a6dde3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -129,8 +129,7 @@ dependencies = [ [[package]] name = "parity-scale-codec" version = "3.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" +source = "git+https://github.com/paritytech/parity-scale-codec.git?rev=5021525697edc0661591ebc71392c48d950a10b0#5021525697edc0661591ebc71392c48d950a10b0" dependencies = [ "arrayvec", "byte-slice-cast", @@ -143,8 +142,7 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" version = "3.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" +source = "git+https://github.com/paritytech/parity-scale-codec.git?rev=5021525697edc0661591ebc71392c48d950a10b0#5021525697edc0661591ebc71392c48d950a10b0" dependencies = [ "proc-macro-crate", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 05e3da5..6b0302b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,13 +6,29 @@ repository = "https://github.com/mintlayer/mintlayer-core-primitives" readme = "README.md" license = "MIT" version = "1.0.0" -edition = "2024" -rust-version = "1.88" +edition = "2021" +# Note: the maximum Rust version we can use here is limited by the Rust toolchains available +# in the Nix packages and Docker images used by the Trezor firmware and Ledger app repositories. +# There is also another Rust version hard-coded in `build-tools/cargo-info-extractor/extract.py` - +# `RUST_VERSION_FOR_CHECKS`; it's used to run `do_checks.sh` and it may be higher than this one. +rust-version = "1.85" [dependencies] -derive_more = { version = "2.0", default-features = false, features = ["debug"] } +derive_more = { version = "2.0", default-features = false, features = [ + "debug", +] } fixed-hash = { version = "0.8", default-features = false } -parity-scale-codec = { version = "3.7", default-features = false, features = ["derive"] } + +# Use the specific commit "5021525697edc0661591ebc71392c48d950a10b0", +# which includes a fix for NanoX devices that do not support certain +# atomic operations. +# +# Fix reference: https://github.com/paritytech/parity-scale-codec/pull/751 +# This fix should be included in releases after version 3.7.5. +parity-scale-codec = { git = "https://github.com/paritytech/parity-scale-codec.git", rev = "5021525697edc0661591ebc71392c48d950a10b0", default-features = false, features = [ + "derive", +] } + strum = { version = "0.27", default-features = false, features = ["derive"] } [dev-dependencies] diff --git a/build-tools/cargo-info-extractor/extract.py b/build-tools/cargo-info-extractor/extract.py index fd631a2..6638c36 100755 --- a/build-tools/cargo-info-extractor/extract.py +++ b/build-tools/cargo-info-extractor/extract.py @@ -12,8 +12,14 @@ ROOT_DIR = pathlib.Path(__file__).resolve().parent.parent.parent ROOT_CARGO_TOML = ROOT_DIR.joinpath("Cargo.toml") +# Note: running `do_checks.sh` may need a Rust version that is higher than the one we can use +# for compilation. In particular, at the time of writing this, installing the latest cargo-deny +# requires Rust 1.88. +# TODO: put it elsewhere? +RUST_VERSION_FOR_CHECKS = "1.88.0" -def get_rust_version(cargo_toml_root): + +def get_rust_version_from_cargo_toml(cargo_toml_root): version = cargo_toml_root["package"]["rust-version"] if len(version.split('.')) == 2: @@ -23,17 +29,31 @@ def get_rust_version(cargo_toml_root): def main(): - parser = argparse.ArgumentParser() + parser = argparse.ArgumentParser( + # Use a bigger max_help_position, so that each parameter's help fits into one line. + formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=30) + ) mutex_group = parser.add_mutually_exclusive_group(required=True) - mutex_group.add_argument('--rust-version', action='store_true', help='extract Rust version') + mutex_group.add_argument( + '--rust-version', + action='store_true', + help='extract Rust version from Cargo.toml; this is the version that should be used for compilation' + ) + mutex_group.add_argument( + '--rust-version-for-checks', + action='store_true', + help='return the Rust version needed to run do_checks.sh' + ) args = parser.parse_args() with open(ROOT_CARGO_TOML, "rb") as file: cargo_toml_root = tomllib.load(file) if args.rust_version: - result = get_rust_version(cargo_toml_root) + result = get_rust_version_from_cargo_toml(cargo_toml_root) print(result) + elif args.rust_version_for_checks: + print(RUST_VERSION_FOR_CHECKS) if __name__ == "__main__": diff --git a/src/coin_type.rs b/src/coin_type.rs new file mode 100644 index 0000000..8faf15e --- /dev/null +++ b/src/coin_type.rs @@ -0,0 +1,125 @@ +// Copyright (c) 2024-2025 RBB S.r.l +// opensource@mintlayer.org +// SPDX-License-Identifier: MIT +// Licensed under the MIT License; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/mintlayer/mintlayer-core-primitives/blob/master/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::Destination; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum CoinType { + Mainnet, + Testnet, + Regtest, + Signet, +} + +impl CoinType { + pub const fn coin_ticker(&self) -> &'static str { + match self { + Self::Mainnet => "ML", + Self::Testnet => "TML", + Self::Regtest => "RML", + Self::Signet => "SML", + } + } + + pub const fn bip44_coin_type(&self) -> u32 { + let hardened_bit = 1 << 31; + match self { + Self::Mainnet => 19788 + hardened_bit, + Self::Testnet | Self::Regtest | Self::Signet => 1 + hardened_bit, + } + } + + pub const fn coin_decimals(&self) -> u8 { + 11 + } + + pub const fn address_prefix(&self, destination: &Destination) -> &'static str { + match self { + Self::Mainnet => match destination { + Destination::AnyoneCanSpend => "mxanyonecanspend", + Destination::PublicKeyHash(_) => "mtc", + Destination::PublicKey(_) => "mptc", + Destination::ScriptHash(_) => "mstc", + Destination::ClassicMultisig(_) => "mmtc", + }, + Self::Testnet => match destination { + Destination::AnyoneCanSpend => "txanyonecanspend", + Destination::PublicKeyHash(_) => "tmt", + Destination::PublicKey(_) => "tpmt", + Destination::ScriptHash(_) => "tstc", + Destination::ClassicMultisig(_) => "tmtc", + }, + Self::Regtest => match destination { + Destination::AnyoneCanSpend => "rxanyonecanspend", + Destination::PublicKeyHash(_) => "rmt", + Destination::PublicKey(_) => "rpmt", + Destination::ScriptHash(_) => "rstc", + Destination::ClassicMultisig(_) => "rmtc", + }, + Self::Signet => match destination { + Destination::AnyoneCanSpend => "sxanyonecanspend", + Destination::PublicKeyHash(_) => "smt", + Destination::PublicKey(_) => "spmt", + Destination::ScriptHash(_) => "sstc", + Destination::ClassicMultisig(_) => "smtc", + }, + } + } + + pub const fn pool_id_address_prefix(&self) -> &'static str { + match self { + Self::Mainnet => "mpool", + Self::Testnet => "tpool", + Self::Regtest => "rpool", + Self::Signet => "spool", + } + } + + pub const fn delegation_id_address_prefix(&self) -> &'static str { + match self { + Self::Mainnet => "mdelg", + Self::Testnet => "tdelg", + Self::Regtest => "rdelg", + Self::Signet => "sdelg", + } + } + + pub const fn token_id_address_prefix(&self) -> &'static str { + match self { + Self::Mainnet => "mmltk", + Self::Testnet => "tmltk", + Self::Regtest => "rmltk", + Self::Signet => "smltk", + } + } + + pub const fn order_id_address_prefix(&self) -> &'static str { + match self { + Self::Mainnet => "mordr", + Self::Testnet => "tordr", + Self::Regtest => "rordr", + Self::Signet => "sordr", + } + } + + pub const fn vrf_public_key_address_prefix(&self) -> &'static str { + match self { + Self::Mainnet => "mvrfpk", + Self::Testnet => "tvrfpk", + Self::Regtest => "rvrfpk", + Self::Signet => "svrfpk", + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 04318df..dbb0078 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ #![no_std] mod accounts; +mod coin_type; mod crypto; mod destination; mod id; @@ -30,6 +31,7 @@ mod utxo_outpoint; mod tests; pub use accounts::*; +pub use coin_type::*; pub use crypto::*; pub use destination::*; pub use id::*; diff --git a/src/misc.rs b/src/misc.rs index 4cacc6d..cb7fc63 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use parity_scale_codec::{Decode, Encode}; +use parity_scale_codec::{Decode, DecodeAll, Encode}; use crate::TokenId; @@ -32,6 +32,8 @@ pub struct Amount { } impl Amount { + pub const ZERO: Self = Self::from_atoms(0); + pub const fn from_atoms(v: AmountUIntType) -> Self { Amount { atoms: v } } @@ -89,3 +91,22 @@ pub type SecondsCountUIntType = u64; #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Encode, Decode)] pub struct SecondsCount(#[codec(compact)] pub SecondsCountUIntType); + +pub fn encode(t: &T) -> PscVec { + t.encode() +} + +pub fn encode_to(t: &T, buf: &mut PscVec) { + t.encode_to(buf) +} + +pub fn decode_all(mut bytes: &[u8]) -> Result { + T::decode_all(&mut bytes) +} + +pub fn encode_as_compact(num: T) -> PscVec +where + for<'a> parity_scale_codec::CompactRef<'a, T>: Encode + From<&'a T>, +{ + parity_scale_codec::Compact::::encode(&num.into()) +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 8fed9d5..8f99fc0 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -25,14 +25,14 @@ use parity_scale_codec::Encode; use strum::IntoEnumIterator as _; use crate::tests::utils::{ + SCALE_CODEC_COMPACT_ENC_10_BYTE_VAL_START, SCALE_CODEC_COMPACT_ENC_11_BYTE_VAL_START, + SCALE_CODEC_COMPACT_ENC_12_BYTE_VAL_START, SCALE_CODEC_COMPACT_ENC_13_BYTE_VAL_START, + SCALE_CODEC_COMPACT_ENC_14_BYTE_VAL_START, SCALE_CODEC_COMPACT_ENC_15_BYTE_VAL_START, + SCALE_CODEC_COMPACT_ENC_16_BYTE_VAL_START, SCALE_CODEC_COMPACT_ENC_17_BYTE_VAL_START, SCALE_CODEC_COMPACT_ENC_2_BYTE_VAL_START, SCALE_CODEC_COMPACT_ENC_4_BYTE_VAL_START, SCALE_CODEC_COMPACT_ENC_5_BYTE_VAL_START, SCALE_CODEC_COMPACT_ENC_6_BYTE_VAL_START, SCALE_CODEC_COMPACT_ENC_7_BYTE_VAL_START, SCALE_CODEC_COMPACT_ENC_8_BYTE_VAL_START, - SCALE_CODEC_COMPACT_ENC_9_BYTE_VAL_START, SCALE_CODEC_COMPACT_ENC_10_BYTE_VAL_START, - SCALE_CODEC_COMPACT_ENC_11_BYTE_VAL_START, SCALE_CODEC_COMPACT_ENC_12_BYTE_VAL_START, - SCALE_CODEC_COMPACT_ENC_13_BYTE_VAL_START, SCALE_CODEC_COMPACT_ENC_14_BYTE_VAL_START, - SCALE_CODEC_COMPACT_ENC_15_BYTE_VAL_START, SCALE_CODEC_COMPACT_ENC_16_BYTE_VAL_START, - SCALE_CODEC_COMPACT_ENC_17_BYTE_VAL_START, + SCALE_CODEC_COMPACT_ENC_9_BYTE_VAL_START, }; use super::*;