Skip to content
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
92cc3a8
fix(platform)!: adopt GroveDB dev and untrusted bincode decoding
QuantumExplorer Sep 8, 2026
e218331
build(platform): use rust-dashcore bincode fork directly
QuantumExplorer Sep 8, 2026
b49c33a
build(platform): use published bincode 2.1.0
QuantumExplorer Sep 8, 2026
e8f16ad
fix(platform-wallet-ffi): keep the payload decode tests after the FFI…
QuantumExplorer Sep 8, 2026
d87ce89
build(docker): build rocksdb 11.8.1 for the prebuilt static library
QuantumExplorer Sep 8, 2026
712b04f
build(platform): pin grovedb and rust-dashcore to their merged revisions
QuantumExplorer Sep 8, 2026
77a73fe
refactor(platform): import DecodeUntrusted instead of path-qualifying…
QuantumExplorer Sep 8, 2026
462faae
fix(dpp): keep tagged serialized structures byte-identical while addi…
QuantumExplorer Sep 8, 2026
5dd5d62
fix(drive): verify a page's cursor document in the page's walk direction
QuantumExplorer Sep 8, 2026
005f8e7
Merge branch 'v4.2-dev' into codex/grovedb-untrusted-bincode
QuantumExplorer Sep 8, 2026
3e0cd83
style(drive-abci): format the keep-history delete replay test
QuantumExplorer Sep 8, 2026
b606daa
test(drive-abci): verify contestant vote proofs with the requested or…
QuantumExplorer Sep 8, 2026
fa9ed7c
ci: ignore derive lists in the immutable structure check
QuantumExplorer Sep 8, 2026
f09aeb1
refactor(dpp): derive DecodeUntrusted on tagged structures
QuantumExplorer Sep 8, 2026
bdd3492
Merge branch 'build/grovedb-6-0-0-bincode-2-1-0' into codex/grovedb-u…
QuantumExplorer Sep 8, 2026
0cd0e03
test(platform-wallet-storage): observe allocations while rejecting tr…
QuantumExplorer Sep 9, 2026
f0c41bc
Merge branch 'build/grovedb-6-0-0-bincode-2-1-0' into codex/grovedb-u…
QuantumExplorer Sep 9, 2026
7452882
Merge branch 'build/grovedb-6-0-0-bincode-2-1-0' into codex/grovedb-u…
QuantumExplorer Sep 11, 2026
af0a8b8
Merge branch 'build/grovedb-6-0-0-bincode-2-1-0' into codex/grovedb-u…
QuantumExplorer Sep 11, 2026
178a71a
Merge branch 'build/grovedb-6-0-0-bincode-2-1-0' into codex/grovedb-u…
QuantumExplorer Sep 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
28 changes: 24 additions & 4 deletions .github/workflows/tests-rs-workspace.yml
Original file line number Diff line number Diff line change
Expand Up @@ -265,15 +265,35 @@ jobs:
'
}

# A derive list is not part of a structure's wire layout: adding or
# reordering a derive cannot change how the existing fields or
# variants serialize, while the fields, the variants and the
# attributes that do shape the encoding (serde, repr,
# platform_serialize) are still compared verbatim. Drop
# `#[derive(...)]` attributes, single- or multi-line, before diffing.
strip_derives() {
awk '
skipping {
if (index($0, ")]")) { skipping=0 }
next
}
/^[[:space:]]*#\[derive\(/ {
if (!index($0, ")]")) { skipping=1 }
next
}
{ print }
'
}

for file in $CHANGED_RS; do
if [ ! -f "$file" ]; then continue; fi
BASE_CONTENT=$(git show "$BASE_PARENT":"$file" 2>/dev/null || true)
if [ -z "$BASE_CONTENT" ]; then continue; fi

BASE_APPEND=$(echo "$BASE_CONTENT" | extract_tagged_block "@append_only")
PR_APPEND=$(extract_tagged_block "@append_only" < "$file")
BASE_IMMUTABLE=$(echo "$BASE_CONTENT" | extract_tagged_block "@immutable")
PR_IMMUTABLE=$(extract_tagged_block "@immutable" < "$file")
BASE_APPEND=$(echo "$BASE_CONTENT" | extract_tagged_block "@append_only" | strip_derives)
PR_APPEND=$(extract_tagged_block "@append_only" < "$file" | strip_derives)
BASE_IMMUTABLE=$(echo "$BASE_CONTENT" | extract_tagged_block "@immutable" | strip_derives)
PR_IMMUTABLE=$(extract_tagged_block "@immutable" < "$file" | strip_derives)

if [ -n "$BASE_APPEND" ]; then
# Check for deletions, ignoring comment-only lines and the tag itself
Expand Down
4 changes: 2 additions & 2 deletions packages/rs-dpp/src/address_funds/fee_strategy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ pub mod deduct_fee_from_inputs_and_outputs;

pub use deduct_fee_from_inputs_and_outputs::FeeDeductionResult;

use bincode::{Decode, Encode};
use bincode::{Decode, DecodeUntrusted, Encode};
#[cfg(feature = "serde-conversion")]
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, Hash, DecodeUntrusted)]
pub enum AddressFundsFeeStrategyStep {
/// Deduct fee from a specific input address by index.
/// The input must have remaining balance after its contribution to outputs.
Expand Down
9 changes: 5 additions & 4 deletions packages/rs-dpp/src/address_funds/platform_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::address_funds::AddressWitnessVerificationOperations;
use crate::prelude::AddressNonce;
use crate::ProtocolError;
use bech32::{Bech32m, Hrp};
use bincode::{Decode, Encode};
use bincode::{Decode, DecodeUntrusted, Encode};
use dashcore::address::Payload;
use dashcore::blockdata::script::ScriptBuf;
use dashcore::hashes::{sha256d, Hash};
Expand Down Expand Up @@ -34,6 +34,7 @@ pub const ADDRESS_HASH_SIZE: usize = 20;
Decode,
PlatformSerialize,
PlatformDeserialize,
DecodeUntrusted,
)]
#[platform_serialize(unversioned)]
pub enum PlatformAddress {
Expand Down Expand Up @@ -428,9 +429,9 @@ impl PlatformAddress {
/// Uses bincode deserialization which expects: 0x00 for P2pkh, 0x01 for P2sh.
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ProtocolError> {
let (address, _): (Self, usize) =
bincode::decode_from_slice(bytes, bincode::config::standard()).map_err(|e| {
ProtocolError::DecodingError(format!("cannot decode PlatformAddress: {}", e))
})?;
bincode::decode_from_slice_untrusted(bytes, bincode::config::standard()).map_err(
|e| ProtocolError::DecodingError(format!("cannot decode PlatformAddress: {}", e)),
)?;
Ok(address)
}

Expand Down
66 changes: 38 additions & 28 deletions packages/rs-dpp/src/address_funds/witness.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#[cfg(feature = "json-conversion")]
use crate::serialization::json_safe_fields;
use bincode::de::{BorrowDecoder, Decoder};
use bincode::de::BorrowDecoder;
use bincode::enc::Encoder;
use bincode::error::{DecodeError, EncodeError};
use bincode::{Decode, Encode};
use bincode::Encode;
use platform_value::BinaryData;
#[cfg(feature = "serde-conversion")]
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -77,36 +77,46 @@ impl Encode for AddressWitness {
}
}

impl<C> Decode<C> for AddressWitness {
fn decode<D: Decoder<Context = C>>(decoder: &mut D) -> Result<Self, DecodeError> {
let discriminant = u8::decode(decoder)?;
match discriminant {
0 => {
let signature = BinaryData::decode(decoder)?;
Ok(AddressWitness::P2pkh { signature })
}
1 => {
let signatures = Vec::<BinaryData>::decode(decoder)?;
if signatures.len() > MAX_P2SH_SIGNATURES {
return Err(DecodeError::OtherString(format!(
"P2SH signatures count {} exceeds maximum {}",
signatures.len(),
MAX_P2SH_SIGNATURES,
)));
// Share the wire schema and domain checks across both decoding APIs.
macro_rules! impl_address_witness_decode {
($decode:ident, $decoder:ident, $method:ident, $untrusted:expr) => {
impl<C> bincode::$decode<C> for AddressWitness {
fn $method<D: bincode::de::$decoder<Context = C>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let discriminant = u8::$method(decoder)?;
match discriminant {
0 => {
let signature = BinaryData::$method(decoder)?;
Ok(AddressWitness::P2pkh { signature })
}
1 => {
let signatures = Vec::<BinaryData>::$method(decoder)?;
if signatures.len() > MAX_P2SH_SIGNATURES {
return Err(DecodeError::OtherString(format!(
"P2SH signatures count {} exceeds maximum {}",
signatures.len(),
MAX_P2SH_SIGNATURES,
)));
}
let redeem_script = BinaryData::$method(decoder)?;
Ok(AddressWitness::P2sh {
signatures,
redeem_script,
})
}
_ => Err(DecodeError::OtherString(format!(
"Invalid AddressWitness discriminant: {}",
discriminant
))),
}
let redeem_script = BinaryData::decode(decoder)?;
Ok(AddressWitness::P2sh {
signatures,
redeem_script,
})
}
_ => Err(DecodeError::OtherString(format!(
"Invalid AddressWitness discriminant: {}",
discriminant
))),
}
}
};
}
impl_address_witness_decode!(Decode, Decoder, decode, false);
impl_address_witness_decode!(DecodeUntrusted, UntrustedDecoder, decode_untrusted, true);
bincode::impl_borrow_decode_untrusted!(AddressWitness);

impl<'de, C> bincode::BorrowDecode<'de, C> for AddressWitness {
fn borrow_decode<D: BorrowDecoder<'de, Context = C>>(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::asset_lock::reduced_asset_lock_value::v0::AssetLockValueV0;
use crate::fee::Credits;
use crate::ProtocolError;
use bincode::{Decode, Encode};
use bincode::{Decode, DecodeUntrusted, Encode};
use derive_more::From;
use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
use platform_value::Bytes32;
Expand All @@ -22,6 +22,7 @@ pub use v0::{AssetLockValueGettersV0, AssetLockValueSettersV0};
PartialEq,
serde::Serialize,
serde::Deserialize,
DecodeUntrusted,
)]
// Stored asset-lock values are decoded from GroveDB proof elements on the
// client before the quorum signature is checked, so the byte budget must be
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use crate::fee::Credits;
#[cfg(feature = "json-conversion")]
use crate::serialization::json_safe_fields;
use bincode::{Decode, Encode};
use bincode::{Decode, DecodeUntrusted, Encode};
use platform_value::Bytes32;

// `initial_credit_value` / `remaining_credit_value` are `Credits` (u64) and can
// exceed JS's `MAX_SAFE_INTEGER`; `#[json_safe_fields]` serializes them as
// strings in human-readable JSON to avoid precision loss when crossing to JS.
#[cfg_attr(feature = "json-conversion", json_safe_fields)]
#[derive(Debug, Clone, Encode, Decode, PartialEq, serde::Serialize, serde::Deserialize)]
#[derive(
Debug, Clone, Encode, Decode, PartialEq, serde::Serialize, serde::Deserialize, DecodeUntrusted,
)]
pub struct AssetLockValueV0 {
pub(super) initial_credit_value: Credits,
pub(super) tx_out_script: Vec<u8>,
Expand Down
5 changes: 3 additions & 2 deletions packages/rs-dpp/src/balances/credits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use crate::prelude::BlockHeight;
use crate::ProtocolError;
use bincode::{Decode, DecodeUntrusted, Encode};
use integer_encoding::VarInt;
use std::collections::BTreeMap;
use std::convert::TryFrom;
Expand Down Expand Up @@ -42,7 +43,7 @@ pub const MAX_CREDITS: Credits = 9223372036854775807 as Credits; //i64 Max
pub const CREDITS_PER_DUFF: Credits = 1000;

/// An enum for credit operations
#[derive(Debug, Clone, Copy, PartialEq, Eq, bincode::Encode, bincode::Decode)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode, DecodeUntrusted)]
pub enum CreditOperation {
/// We are setting credit amounts
SetCredits(Credits),
Expand All @@ -51,7 +52,7 @@ pub enum CreditOperation {
}

/// An enum for credit operations in compacted address blobs
#[derive(Debug, Clone, PartialEq, Eq, bincode::Encode, bincode::Decode)]
#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, DecodeUntrusted)]
pub enum BlockAwareCreditOperation {
/// We are setting credit amounts - the final value after all operations
SetCredits(Credits),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use crate::balances::credits::SignedTokenAmount;
use crate::ProtocolError;
#[cfg(feature = "fixtures-and-mocks")]
use bincode::Encode;
use bincode::{DecodeUntrusted, Encode};
#[cfg(feature = "fixtures-and-mocks")]
use platform_serialization::de::Decode;
use std::fmt;

/// A structure where the token supply and the aggregated token account balances should always be equal
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "fixtures-and-mocks", derive(Encode, Decode))]
#[cfg_attr(
feature = "fixtures-and-mocks",
derive(Encode, Decode, DecodeUntrusted)
)]
pub struct TotalSingleTokenBalance {
/// the token supply
pub token_supply: SignedTokenAmount,
Expand Down
16 changes: 14 additions & 2 deletions packages/rs-dpp/src/block/block_info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::serialization::json_safe_fields;
use crate::serialization::JsonConvertible;
#[cfg(feature = "value-conversion")]
use crate::serialization::ValueConvertible;
use bincode::{Decode, Encode};
use bincode::{Decode, DecodeUntrusted, Encode};
use serde::{Deserialize, Serialize};
use std::fmt;

Expand All @@ -23,7 +23,19 @@ pub const DEFAULT_BLOCK_INFO: BlockInfo = BlockInfo {
/// Block information
#[cfg_attr(feature = "json-conversion", json_safe_fields)]
#[cfg_attr(feature = "json-conversion", derive(JsonConvertible))]
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Encode, Decode, Serialize, Deserialize)]
#[derive(
Clone,
Copy,
Default,
Debug,
PartialEq,
Eq,
Encode,
Decode,
Serialize,
Deserialize,
DecodeUntrusted,
)]
#[cfg_attr(feature = "value-conversion", derive(ValueConvertible))]
#[serde(rename_all = "camelCase")]
pub struct BlockInfo {
Expand Down
25 changes: 17 additions & 8 deletions packages/rs-dpp/src/block/epoch/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{InvalidVectorSizeError, ProtocolError};
use bincode::{BorrowDecode, Decode, Encode};
use bincode::{BorrowDecode, Encode};
use serde::{Deserialize, Serialize};

/// Epoch key offset
Expand Down Expand Up @@ -100,14 +100,23 @@ impl<'de> Deserialize<'de> for Epoch {
}
}

impl<C> Decode<C> for Epoch {
fn decode<D: bincode::de::Decoder<Context = C>>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
let index = EpochIndex::decode(decoder)?;
Epoch::new(index).map_err(|e| bincode::error::DecodeError::OtherString(e.to_string()))
}
// Share the wire schema and domain checks across both decoding APIs.
macro_rules! impl_epoch_decode {
($decode:ident, $decoder:ident, $method:ident, $untrusted:expr) => {
impl<C> bincode::$decode<C> for Epoch {
fn $method<D: bincode::de::$decoder<Context = C>>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
let index = EpochIndex::$method(decoder)?;
Epoch::new(index)
.map_err(|e| bincode::error::DecodeError::OtherString(e.to_string()))
}
}
};
}
impl_epoch_decode!(Decode, Decoder, decode, false);
impl_epoch_decode!(DecodeUntrusted, UntrustedDecoder, decode_untrusted, true);
bincode::impl_borrow_decode_untrusted!(Epoch);

impl<'de, C> BorrowDecode<'de, C> for Epoch {
fn borrow_decode<D: bincode::de::BorrowDecoder<'de, Context = C>>(
Expand Down
3 changes: 2 additions & 1 deletion packages/rs-dpp/src/block/extended_block_info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::serialization::JsonConvertible;
#[cfg(feature = "value-conversion")]
use crate::serialization::ValueConvertible;
use crate::version::FeatureVersion;
use bincode::{Decode, Encode};
use bincode::{Decode, DecodeUntrusted, Encode};
use derive_more::From;
use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
use serde::{Deserialize, Serialize};
Expand All @@ -30,6 +30,7 @@ pub mod v0;
PlatformSerialize,
PlatformDeserialize,
From,
DecodeUntrusted,
)]
#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version
#[serde(tag = "$formatVersion")]
Expand Down
4 changes: 2 additions & 2 deletions packages/rs-dpp/src/block/extended_block_info/v0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ use crate::block::block_info::BlockInfo;
#[cfg(feature = "json-conversion")]
use crate::serialization::json_safe_fields;

use bincode::{Decode, Encode};
use bincode::{Decode, DecodeUntrusted, Encode};
use serde::{Deserialize, Serialize};

/// Extended Block information
#[cfg_attr(feature = "json-conversion", json_safe_fields)]
#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, Serialize, Deserialize, DecodeUntrusted)]
#[serde(rename_all = "camelCase")]
pub struct ExtendedBlockInfoV0 {
/// Basic block info
Expand Down
3 changes: 2 additions & 1 deletion packages/rs-dpp/src/block/extended_epoch_info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::serialization::JsonConvertible;
#[cfg(feature = "value-conversion")]
use crate::serialization::ValueConvertible;
use crate::util::deserializer::ProtocolVersion;
use bincode::{Decode, Encode};
use bincode::{Decode, DecodeUntrusted, Encode};
use derive_more::From;
use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
use serde::{Deserialize, Serialize};
Expand All @@ -27,6 +27,7 @@ use serde::{Deserialize, Serialize};
PlatformSerialize,
PlatformDeserialize,
From,
DecodeUntrusted,
)]
#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version
#[serde(tag = "$formatVersion")]
Expand Down
4 changes: 2 additions & 2 deletions packages/rs-dpp/src/block/extended_epoch_info/v0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ use crate::block::epoch::EpochIndex;
#[cfg(feature = "json-conversion")]
use crate::serialization::json_safe_fields;
use crate::util::deserializer::ProtocolVersion;
use bincode::{Decode, Encode};
use bincode::{Decode, DecodeUntrusted, Encode};
use serde::{Deserialize, Serialize};

/// Extended Epoch information
#[cfg_attr(feature = "json-conversion", json_safe_fields)]
#[derive(Clone, Debug, PartialEq, Encode, Decode, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Encode, Decode, Serialize, Deserialize, DecodeUntrusted)]
#[serde(rename_all = "camelCase")]
pub struct ExtendedEpochInfoV0 {
/// The index of the epoch
Expand Down
3 changes: 2 additions & 1 deletion packages/rs-dpp/src/block/finalized_epoch_info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::protocol_error::ProtocolError;
use crate::serialization::JsonConvertible;
#[cfg(feature = "value-conversion")]
use crate::serialization::ValueConvertible;
use bincode::{Decode, Encode};
use bincode::{Decode, DecodeUntrusted, Encode};
use derive_more::From;
use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
use serde::{Deserialize, Serialize};
Expand All @@ -26,6 +26,7 @@ use serde::{Deserialize, Serialize};
PlatformSerialize,
PlatformDeserialize,
From,
DecodeUntrusted,
)]
#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version
#[serde(tag = "$formatVersion")]
Expand Down
Loading
Loading