Skip to content

Add support for 128-bit integers.#63

Merged
twittner merged 4 commits into
twittner:developfrom
sdbondi:feat/u128
Jul 22, 2026
Merged

Add support for 128-bit integers.#63
twittner merged 4 commits into
twittner:developfrom
sdbondi:feat/u128

Conversation

@sdbondi

@sdbondi sdbondi commented May 19, 2026

Copy link
Copy Markdown
Contributor

Adds u128 and i128 encoding and decoding, including Encode, Decode, CborLen, NonZeroU128, and NonZeroI128 impls. Values within the CBOR integer range are encoded as native unsigned/signed ints; values outside are encoded as positive or negative bignums (tags 2 and 3) per RFC 8949 §3.4.3.

sdbondi added 2 commits May 19, 2026 11:13
Adds `u128` and `i128` encoding and decoding, including `Encode`,
`Decode`, `CborLen`, `NonZeroU128`, and `NonZeroI128` impls. Values
within the CBOR integer range are encoded as native unsigned/signed
ints; values outside are encoded as positive or negative bignums
(tags 2 and 3) per RFC 8949 §3.4.3.

Signed-off-by: Stan Bondi <sdbondi@users.noreply.github.com>
Wires `Serializer::serialize_u128`/`serialize_i128` and the matching
`Deserializer::deserialize_u128`/`deserialize_i128` through to the new
`Encoder`/`Decoder` methods. Extends `deserialize_any` to recognise the
positive (tag 2) and negative (tag 3) bignum encodings and route them
to `visit_u128`/`visit_i128`; CBOR integers wider than `i64` (`Type::Int`)
are likewise routed to `visit_i128`.

Note that serde's `Content` buffer used by untagged enums only stores
values up to 64 bits, so bignum dispatch through `deserialize_any` is
only observable to visitors that implement `visit_u128`/`visit_i128`
themselves.

Signed-off-by: Stan Bondi <sdbondi@users.noreply.github.com>
sdbondi added a commit to sdbondi/tari-ootle that referenced this pull request May 19, 2026
…nicbor-serde

minicbor-serde 0.6.2 doesn't implement serialize_u128/serialize_i128 (upstream
PR twittner/minicbor#63 is in flight), which left
foreign types like tari_sidechain::ShardGroupAccumulatedData::total_exhaust_burn
unencodable through serde_bridge. Vendor a fork into tari_bor::serde_codec that
adds:

  - serialize_u128 / serialize_i128 via RFC 8949 §3.4.3 bignum tags (2 / 3) +
    bstr of positive-magnitude bytes with leading zeros stripped, plus matching
    decoder paths that also accept the plain integer encoding for values that
    fit in u64.
  - deserialize_seq fallback that surfaces a CBOR byte string as a Vec<u8>-shaped
    sequence (single-byte SeqAccess), so foreign types using
    `#[serde(with = "hex_or_bytes")]` like tari_sidechain::SidechainBlockHeader
    round-trip via Vec<u8> / Cow<'_, [u8]> without re-implementing their serde
    impls.
  - collect_indef_bytes helper that pre-sizes the destination buffer for
    indefinite-length CBOR byte strings.

All 58 consensus_tests now run (they were previously hanging in a
"u128 is not supported" loop on the foreign sidechain proof).

Companion changes:

  - tari_bor::adapters::u128_codec: a dedicated tag-2 positive-bignum adapter
    for direct u128 fields we control. consensus_types::ShardGroupAccumulatedData
    switched off serde_bridge to use it.
  - tari_bor::cbor! macro: $v:expr arms now route through a new helper that
    calls tari_bor::to_value, so any Encode<()> type drops in directly without
    callers having to wrap it. Primitive behaviour preserved via encode/decode
    round-trip identity.
  - engine/benches/common/mod.rs: bench component body uses the positional
    [FAUCET_VAULT_ID] shape matching the template struct's minicbor array
    encoding (not the old string-keyed map).
  - Two clippy fixes in tari_bor / engine_types (drop &Box<[T]> in the
    boxed_slice adapter and 14 redundant .map_err(BorError::from) calls in
    indexed_value where Value::decoded() already returns BorError).

Workspace cleanup:

  - All direct minicbor-serde callers — state_store_rocksdb::SerdeBridgeCodec,
    p2p::conversions::rpc, ootle_serde tests, applications/tari_indexer
    storage_sqlite serialization, ootle_address tests — routed through
    tari_bor::serde_codec.
  - minicbor-serde dropped from workspace dependencies.

Version bumps (workspace + 16 self-versioned crates):

  - workspace.package.version 0.30.12 → 0.31.0
  - tari_bor 0.13 → 0.14, ootle_byte_type 0.7 → 0.8, ootle_serde 0.2 → 0.3,
    ootle-network 0.1 → 0.2, tari_ootle_address 0.5 → 0.6, tari_template_abi
    0.16 → 0.17, tari_template_macros 0.19 → 0.20, tari_template_lib 0.26 →
    0.27, tari_template_lib_types 0.26 → 0.27, tari_ootle_template_build 0.6 →
    0.7, tari_ootle_template_metadata 0.6 → 0.7, tari_template_builtin 0.30 →
    0.31, ootle-rs 0.6 → 0.7, tari_ootle_wallet_sdk_services 0.1 → 0.2,
    tari_indexer_client 0.30 → 0.31, tari_ootle_walletd_client 0.30 → 0.31.
    Matching workspace dependency version constraints updated.
sdbondi added a commit to sdbondi/tari-ootle that referenced this pull request May 19, 2026
…nicbor-serde

minicbor-serde 0.6.2 doesn't implement serialize_u128/serialize_i128 (upstream
PR twittner/minicbor#63 is in flight), which left
foreign types like tari_sidechain::ShardGroupAccumulatedData::total_exhaust_burn
unencodable through serde_bridge. Vendor a fork into tari_bor::serde_codec that
adds:

  - serialize_u128 / serialize_i128 via RFC 8949 §3.4.3 bignum tags (2 / 3) +
    bstr of positive-magnitude bytes with leading zeros stripped, plus matching
    decoder paths that also accept the plain integer encoding for values that
    fit in u64.
  - deserialize_seq fallback that surfaces a CBOR byte string as a Vec<u8>-shaped
    sequence (single-byte SeqAccess), so foreign types using
    `#[serde(with = "hex_or_bytes")]` like tari_sidechain::SidechainBlockHeader
    round-trip via Vec<u8> / Cow<'_, [u8]> without re-implementing their serde
    impls.
  - collect_indef_bytes helper that pre-sizes the destination buffer for
    indefinite-length CBOR byte strings.

All 58 consensus_tests now run (they were previously hanging in a
"u128 is not supported" loop on the foreign sidechain proof).

Companion changes:

  - tari_bor::adapters::u128_codec: a dedicated tag-2 positive-bignum adapter
    for direct u128 fields we control. consensus_types::ShardGroupAccumulatedData
    switched off serde_bridge to use it.
  - tari_bor::cbor! macro: $v:expr arms now route through a new helper that
    calls tari_bor::to_value, so any Encode<()> type drops in directly without
    callers having to wrap it. Primitive behaviour preserved via encode/decode
    round-trip identity.
  - engine/benches/common/mod.rs: bench component body uses the positional
    [FAUCET_VAULT_ID] shape matching the template struct's minicbor array
    encoding (not the old string-keyed map).
  - Two clippy fixes in tari_bor / engine_types (drop &Box<[T]> in the
    boxed_slice adapter and 14 redundant .map_err(BorError::from) calls in
    indexed_value where Value::decoded() already returns BorError).

Workspace cleanup:

  - All direct minicbor-serde callers — state_store_rocksdb::SerdeBridgeCodec,
    p2p::conversions::rpc, ootle_serde tests, applications/tari_indexer
    storage_sqlite serialization, ootle_address tests — routed through
    tari_bor::serde_codec.
  - minicbor-serde dropped from workspace dependencies.

Version bumps (workspace + 16 self-versioned crates):

  - workspace.package.version 0.30.12 → 0.31.0
  - tari_bor 0.13 → 0.14, ootle_byte_type 0.7 → 0.8, ootle_serde 0.2 → 0.3,
    ootle-network 0.1 → 0.2, tari_ootle_address 0.5 → 0.6, tari_template_abi
    0.16 → 0.17, tari_template_macros 0.19 → 0.20, tari_template_lib 0.26 →
    0.27, tari_template_lib_types 0.26 → 0.27, tari_ootle_template_build 0.6 →
    0.7, tari_ootle_template_metadata 0.6 → 0.7, tari_template_builtin 0.30 →
    0.31, ootle-rs 0.6 → 0.7, tari_ootle_wallet_sdk_services 0.1 → 0.2,
    tari_indexer_client 0.30 → 0.31, tari_ootle_walletd_client 0.30 → 0.31.
    Matching workspace dependency version constraints updated.
sdbondi added a commit to sdbondi/tari-ootle that referenced this pull request May 19, 2026
…nicbor-serde

minicbor-serde 0.6.2 doesn't implement serialize_u128/serialize_i128 (upstream
PR twittner/minicbor#63 is in flight), which left
foreign types like tari_sidechain::ShardGroupAccumulatedData::total_exhaust_burn
unencodable through serde_bridge. Vendor a fork into tari_bor::serde_codec that
adds:

  - serialize_u128 / serialize_i128 via RFC 8949 §3.4.3 bignum tags (2 / 3) +
    bstr of positive-magnitude bytes with leading zeros stripped, plus matching
    decoder paths that also accept the plain integer encoding for values that
    fit in u64.
  - deserialize_seq fallback that surfaces a CBOR byte string as a Vec<u8>-shaped
    sequence (single-byte SeqAccess), so foreign types using
    `#[serde(with = "hex_or_bytes")]` like tari_sidechain::SidechainBlockHeader
    round-trip via Vec<u8> / Cow<'_, [u8]> without re-implementing their serde
    impls.
  - collect_indef_bytes helper that pre-sizes the destination buffer for
    indefinite-length CBOR byte strings.

All 58 consensus_tests now run (they were previously hanging in a
"u128 is not supported" loop on the foreign sidechain proof).

Companion changes:

  - tari_bor::adapters::u128_codec: a dedicated tag-2 positive-bignum adapter
    for direct u128 fields we control. consensus_types::ShardGroupAccumulatedData
    switched off serde_bridge to use it.
  - tari_bor::cbor! macro: $v:expr arms now route through a new helper that
    calls tari_bor::to_value, so any Encode<()> type drops in directly without
    callers having to wrap it. Primitive behaviour preserved via encode/decode
    round-trip identity.
  - engine/benches/common/mod.rs: bench component body uses the positional
    [FAUCET_VAULT_ID] shape matching the template struct's minicbor array
    encoding (not the old string-keyed map).
  - Two clippy fixes in tari_bor / engine_types (drop &Box<[T]> in the
    boxed_slice adapter and 14 redundant .map_err(BorError::from) calls in
    indexed_value where Value::decoded() already returns BorError).

Workspace cleanup:

  - All direct minicbor-serde callers — state_store_rocksdb::SerdeBridgeCodec,
    p2p::conversions::rpc, ootle_serde tests, applications/tari_indexer
    storage_sqlite serialization, ootle_address tests — routed through
    tari_bor::serde_codec.
  - minicbor-serde dropped from workspace dependencies.

Version bumps (workspace + 16 self-versioned crates):

  - workspace.package.version 0.30.12 → 0.31.0
  - tari_bor 0.13 → 0.14, ootle_byte_type 0.7 → 0.8, ootle_serde 0.2 → 0.3,
    ootle-network 0.1 → 0.2, tari_ootle_address 0.5 → 0.6, tari_template_abi
    0.16 → 0.17, tari_template_macros 0.19 → 0.20, tari_template_lib 0.26 →
    0.27, tari_template_lib_types 0.26 → 0.27, tari_ootle_template_build 0.6 →
    0.7, tari_ootle_template_metadata 0.6 → 0.7, tari_template_builtin 0.30 →
    0.31, ootle-rs 0.6 → 0.7, tari_ootle_wallet_sdk_services 0.1 → 0.2,
    tari_indexer_client 0.30 → 0.31, tari_ootle_walletd_client 0.30 → 0.31.
    Matching workspace dependency version constraints updated.
Comment thread minicbor-serde/src/de.rs Outdated
Comment thread minicbor/src/decode/decoder.rs Outdated
Comment thread minicbor/src/decode/decoder.rs Outdated
Comment thread minicbor/src/decode/decoder.rs Outdated
Comment thread minicbor/src/encode/encoder.rs Outdated
Comment thread minicbor/src/encode/encoder.rs Outdated
Comment thread minicbor/src/encode/encoder.rs Outdated
sdbondi and others added 2 commits July 21, 2026 12:21
Refer to `IanaTag::PosBignum`/`IanaTag::NegBignum` instead of matching
raw tag numbers in `Decoder::u128`, `Decoder::i128` and the serde
`Deserializer`. Comparing a `Tag` against an `IanaTag` requires new
`PartialEq` impls, which are added in both directions.

Compute the number of leading zero bytes in `Encoder::u128`/`i128` via
`leading_zeros() / 8`, matching the existing `CborLen` impls, and let
the non-negative branch of `Encoder::i128` delegate to `Encoder::u128`
rather than duplicating the bignum encoding.

Handle the empty byte string explicitly in `decode_bignum_u128`.

Also drop an inaccurate remark about overflow: `-1 - x` does not
overflow for any negative `x: i128`, so that is not the reason to
prefer `!x`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Bondi <sdbondi@users.noreply.github.com>
* develop:
  Import `wrap_in_crate_alias`.
  Update CHANGELOG and increment versions.
  Style
  Use IP and socket address types from `core`.
  Add `#[cbor(crate = "...")]` to override the minicbor crate path
  Update CHANGELOG and increment version.
  Minor changes.
  Add buffer getters on io Readers and Writers
  add interop unit tests for tags
  ser: add support to serialize tag wrappers
  de: add support to deserialize into tag wrappers
  introduce tag module
@sdbondi

sdbondi commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review and suggestions - applied them :)

@twittner
twittner merged commit 58ea027 into twittner:develop Jul 22, 2026
2 checks passed
@twittner

Copy link
Copy Markdown
Owner

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants