Skip to content

Commit 72fede5

Browse files
committed
WIP NOT REVIEWED VALIDATION OF REFERENCES
1 parent 69bb293 commit 72fede5

File tree

20 files changed

+392
-6
lines changed

20 files changed

+392
-6
lines changed

TODO.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Reference Validation (`refersTo`) Implementation Checklist
2+
3+
## Schema / Compatibility
4+
- [x] Update document meta-schema (`packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json`) to allow `refersTo` object with `type`/`mustExist` (default true, false disables validation).
5+
- [x] Extend JSON schema compatibility rules (`packages/rs-json-schema-compatibility-validator/src/rules/rule_set.rs`) to allow `refersTo` keyword (disallow changes post-creation).
6+
7+
## DPP Parsing / Model
8+
- [x] Parse `refersTo` in property handling (`packages/rs-dpp/src/data_contract/document_type/property/mod.rs`) and store metadata (path → {target, mustExist}).
9+
- [x] Keep `identifier_paths`/`binary_paths` behavior unchanged; access `refersTo` via existing property structures (no dedicated references map).
10+
- [x] Ensure `DocumentType::try_from_schema` (v0/v1) validates `refersTo` placement (identifier fields only) and rejects in updates (mutability rule).
11+
- [x] Expose `refersTo` in serialization (Value/JSON) and bindings (WASM/JS) so clients can introspect.
12+
13+
## Errors
14+
- [x] Add consensus state error for missing referenced entity (includes type, path, id) and wire to error codes (new code without shifting existing ones).
15+
16+
## Validation (Drive / ABCI)
17+
- [ ] Implement reference existence checks in advanced structure v1 validators:
18+
- `document_create_transition_action/advanced_structure_v1`
19+
- `document_replace_transition_action/advanced_structure_v1`
20+
- [ ] Hook checks into `validate_advanced_structure_from_state` flow; applied in CheckTx/PrepareProposal/ProcessProposal.
21+
- [ ] Gate enforcement by protocol/platform version; legacy nodes reject contracts with `refersTo` pre-activation.
22+
- [ ] Count identity lookups in execution context fee accounting.
23+
24+
## Versioning / Config
25+
- [ ] Bump/introduce version constants to select v1 advanced structure validators for reference validation.
26+
- [ ] Add protocol feature flag to ignore `refersTo` pre-activation.
27+
28+
## Tests
29+
- [ ] Meta-schema and compatibility tests for `refersTo`.
30+
- [ ] DPP unit tests: parsing/serialization of `refersTo`, placement validation, defaults (`mustExist` default true, false skips checks).
31+
- [ ] Drive/ABCI tests: create/replace transitions with missing/exists identities, nested fields, version gating.
32+
- [ ] WASM/JS binding tests to ensure `refersTo` surfaces correctly.
33+
34+
## Docs
35+
- [ ] Update `docs/specs/reference-validation.md` if behavior diverges; add any developer notes in code as needed.

packages/rs-dpp/src/data_contract/document_type/property/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::convert::TryInto;
33

44
use std::io::{BufReader, Cursor, Read};
55

6-
use bincode::{Decode, Encode};
76
use crate::data_contract::errors::DataContractError;
7+
use bincode::{Decode, Encode};
88

99
use crate::consensus::basic::decode::DecodingError;
1010
use crate::data_contract::config::v1::DataContractConfigGettersV1;

packages/rs-dpp/src/errors/consensus/basic/basic_error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::consensus::state::document::referenced_entity_not_found_error::ReferencedEntityNotFoundError;
12
use crate::errors::ProtocolError;
23
use bincode::{Decode, Encode};
34
use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
@@ -273,6 +274,9 @@ pub enum BasicError {
273274
#[error(transparent)]
274275
MaxDocumentsTransitionsExceededError(MaxDocumentsTransitionsExceededError),
275276

277+
#[error(transparent)]
278+
ReferencedEntityNotFoundError(ReferencedEntityNotFoundError),
279+
276280
// Identity
277281
#[error(transparent)]
278282
DuplicatedIdentityPublicKeyBasicError(DuplicatedIdentityPublicKeyBasicError),

packages/rs-dpp/src/errors/consensus/codes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ impl ErrorWithCode for BasicError {
153153
Self::DocumentCreationNotAllowedError(_) => 10416,
154154
Self::DocumentFieldMaxSizeExceededError(_) => 10417,
155155
Self::ContestedDocumentsTemporarilyNotAllowedError(_) => 10418,
156+
Self::ReferencedEntityNotFoundError(_) => 10419,
156157

157158
// Token Errors: 10450-10499
158159
Self::InvalidTokenIdError(_) => 10450,

packages/rs-drive-abci/src/execution/validation/state_transition/check_tx_verification/v0/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::error::Error;
22
use crate::execution::types::execution_event::ExecutionEvent;
33
use crate::execution::validation::state_transition::transformer::StateTransitionActionTransformer;
44
use crate::platform_types::platform::PlatformRef;
5+
use crate::platform_types::platform::PlatformStateRef;
56
use crate::platform_types::platform_state::PlatformStateV0Methods;
67
use crate::rpc::core::CoreRPCLike;
78
use dpp::identity::state_transition::OptionallyAssetLockProved;
@@ -242,11 +243,14 @@ pub(super) fn state_transition_to_execution_event_for_check_tx_v0<'a, C: CoreRPC
242243
let action = state_transition_action_result.into_data()?;
243244

244245
// Validating structure
246+
let platform_state_ref: PlatformStateRef = platform.into();
245247
let result = state_transition.validate_advanced_structure_from_state(
246248
platform.state.last_block_info(),
247249
platform.config.network,
248250
&action,
249251
maybe_identity.as_ref(),
252+
&platform_state_ref,
253+
None,
250254
&mut state_transition_execution_context,
251255
platform_version,
252256
)?;

packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/advanced_structure_with_state.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ use crate::execution::types::state_transition_execution_context::StateTransition
44
use crate::execution::validation::state_transition::address_funding_from_asset_lock::StateTransitionStructureKnownInStateValidationForAddressFundingFromAssetLockTransition;
55
use crate::execution::validation::state_transition::identity_create::StateTransitionStructureKnownInStateValidationForIdentityCreateTransitionV0;
66
use crate::execution::validation::state_transition::identity_create_from_addresses::StateTransitionStructureKnownInStateValidationForIdentityCreateFromAddressesTransitionV0;
7+
use crate::platform_types::platform::PlatformStateRef;
78
use dpp::block::block_info::BlockInfo;
89
use dpp::dashcore::Network;
910
use dpp::identity::PartialIdentity;
1011
use dpp::prelude::ConsensusValidationResult;
1112
use dpp::serialization::Signable;
1213
use dpp::state_transition::StateTransition;
1314
use dpp::version::PlatformVersion;
15+
use drive::grovedb::TransactionArg;
1416
use drive::state_transition_action::StateTransitionAction;
1517

1618
/// A trait for validating state transitions within a blockchain.
@@ -31,6 +33,8 @@ pub(crate) trait StateTransitionStructureKnownInStateValidationV0 {
3133
network: Network,
3234
action: &StateTransitionAction,
3335
maybe_identity: Option<&PartialIdentity>,
36+
platform: &PlatformStateRef,
37+
transaction: TransactionArg,
3438
execution_context: &mut StateTransitionExecutionContext,
3539
platform_version: &PlatformVersion,
3640
) -> Result<ConsensusValidationResult<StateTransitionAction>, Error>;
@@ -49,6 +53,8 @@ impl StateTransitionStructureKnownInStateValidationV0 for StateTransition {
4953
network: Network,
5054
action: &StateTransitionAction,
5155
maybe_identity: Option<&PartialIdentity>,
56+
platform: &PlatformStateRef,
57+
transaction: TransactionArg,
5258
execution_context: &mut StateTransitionExecutionContext,
5359
platform_version: &PlatformVersion,
5460
) -> Result<ConsensusValidationResult<StateTransitionAction>, Error> {
@@ -58,6 +64,8 @@ impl StateTransitionStructureKnownInStateValidationV0 for StateTransition {
5864
network,
5965
action,
6066
maybe_identity,
67+
platform,
68+
transaction,
6169
execution_context,
6270
platform_version,
6371
),
@@ -72,6 +80,8 @@ impl StateTransitionStructureKnownInStateValidationV0 for StateTransition {
7280
st.validate_advanced_structure_from_state_for_identity_create_transition(
7381
identity_create_action,
7482
signable_bytes,
83+
platform,
84+
transaction,
7585
execution_context,
7686
platform_version,
7787
)
@@ -81,6 +91,8 @@ impl StateTransitionStructureKnownInStateValidationV0 for StateTransition {
8191
network,
8292
action,
8393
maybe_identity,
94+
platform,
95+
transaction,
8496
execution_context,
8597
platform_version,
8698
),
@@ -94,6 +106,8 @@ impl StateTransitionStructureKnownInStateValidationV0 for StateTransition {
94106
};
95107
st.validate_advanced_structure_from_state_for_address_funding_from_asset_lock_transition(
96108
address_funding_action,
109+
platform,
110+
transaction,
97111
execution_context,
98112
platform_version,
99113
)
@@ -102,6 +116,8 @@ impl StateTransitionStructureKnownInStateValidationV0 for StateTransition {
102116
let signable_bytes = self.signable_bytes()?;
103117
st.validate_advanced_structure_from_state_for_identity_create_from_addresses_transition(
104118
signable_bytes,
119+
platform,
120+
transaction,
105121
execution_context,
106122
platform_version,
107123
)

packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::execution::validation::state_transition::processor::state::StateTrans
2020
use crate::execution::validation::state_transition::transformer::StateTransitionActionTransformer;
2121
use crate::execution::validation::state_transition::ValidationMode;
2222
use crate::platform_types::platform::PlatformRef;
23+
use crate::platform_types::platform::PlatformStateRef;
2324
use crate::platform_types::platform_state::PlatformStateV0Methods;
2425
use crate::rpc::core::CoreRPCLike;
2526
use dpp::block::block_info::BlockInfo;
@@ -270,11 +271,14 @@ pub(super) fn process_state_transition_v0<'a, C: CoreRPCLike>(
270271
let action = state_transition_action_result.into_data()?;
271272

272273
// Validating structure
274+
let platform_state_ref: PlatformStateRef = platform.into();
273275
let result = state_transition.validate_advanced_structure_from_state(
274276
block_info,
275277
platform.config.network,
276278
&action,
277279
maybe_identity.as_ref(),
280+
&platform_state_ref,
281+
transaction,
278282
&mut state_transition_execution_context,
279283
platform_version,
280284
)?;

packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/address_funding_from_asset_lock/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::error::execution::ExecutionError;
1818
use crate::error::Error;
1919
use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext;
2020
use crate::execution::validation::state_transition::address_funding_from_asset_lock::advanced_structure::v0::AddressFundingFromAssetLockStateTransitionAdvancedStructureValidationV0;
21+
use crate::platform_types::platform::PlatformStateRef;
2122
use crate::execution::validation::state_transition::address_funding_from_asset_lock::transform_into_action::v0::AddressFundingFromAssetLockStateTransitionTransformIntoActionValidationV0;
2223
use crate::platform_types::platform::PlatformRef;
2324
use crate::rpc::core::CoreRPCLike;
@@ -85,6 +86,8 @@ pub trait StateTransitionStructureKnownInStateValidationForAddressFundingFromAss
8586
fn validate_advanced_structure_from_state_for_address_funding_from_asset_lock_transition(
8687
&self,
8788
action: AddressFundingFromAssetLockTransitionAction,
89+
_platform: &PlatformStateRef,
90+
_transaction: TransactionArg,
8891
execution_context: &mut StateTransitionExecutionContext,
8992
platform_version: &PlatformVersion,
9093
) -> Result<ConsensusValidationResult<StateTransitionAction>, Error>;
@@ -96,6 +99,8 @@ impl StateTransitionStructureKnownInStateValidationForAddressFundingFromAssetLoc
9699
fn validate_advanced_structure_from_state_for_address_funding_from_asset_lock_transition(
97100
&self,
98101
action: AddressFundingFromAssetLockTransitionAction,
102+
_platform: &PlatformStateRef,
103+
_transaction: TransactionArg,
99104
execution_context: &mut StateTransitionExecutionContext,
100105
platform_version: &PlatformVersion,
101106
) -> Result<ConsensusValidationResult<StateTransitionAction>, Error> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
use dpp::block::block_info::BlockInfo;
2+
use dpp::dashcore::Network;
3+
use dpp::identifier::Identifier;
4+
use dpp::validation::SimpleConsensusValidationResult;
5+
use dpp::data_contract::accessors::v0::DataContractV0Getters;
6+
use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters;
7+
use dpp::data_contract::document_type::DocumentPropertyReferenceTarget;
8+
use dpp::errors::consensus::ConsensusError;
9+
use dpp::errors::consensus::state::document::referenced_entity_not_found_error::ReferencedEntityNotFoundError;
10+
use dpp::platform_value::btreemap_extensions::BTreeValueMapPathHelper;
11+
use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0;
12+
use drive::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::{
13+
DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0,
14+
};
15+
use dpp::version::PlatformVersion;
16+
use crate::error::Error;
17+
use crate::execution::types::state_transition_execution_context::{
18+
StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0,
19+
};
20+
use crate::platform_types::platform::PlatformStateRef;
21+
use crate::execution::types::execution_operation::{RetrieveIdentityInfo, ValidationOperation};
22+
use drive::grovedb::TransactionArg;
23+
use crate::execution::validation::state_transition::batch::action_validation::document::document_create_transition_action::advanced_structure_v0::DocumentCreateTransitionActionStructureValidationV0;
24+
25+
/// Advanced structure validation for document create transitions (v1).
26+
/// This version is where reference validation and other new checks will be added.
27+
pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait DocumentCreateTransitionActionStructureValidationV1 {
28+
fn validate_structure_v1(
29+
&self,
30+
owner_id: Identifier,
31+
block_info: &BlockInfo,
32+
network: Network,
33+
platform: &PlatformStateRef,
34+
transaction: TransactionArg,
35+
execution_context: &mut StateTransitionExecutionContext,
36+
platform_version: &PlatformVersion,
37+
) -> Result<SimpleConsensusValidationResult, Error>;
38+
}
39+
40+
impl DocumentCreateTransitionActionStructureValidationV1 for DocumentCreateTransitionAction {
41+
fn validate_structure_v1(
42+
&self,
43+
owner_id: Identifier,
44+
block_info: &BlockInfo,
45+
network: Network,
46+
platform: &PlatformStateRef,
47+
transaction: TransactionArg,
48+
execution_context: &mut StateTransitionExecutionContext,
49+
platform_version: &PlatformVersion,
50+
) -> Result<SimpleConsensusValidationResult, Error> {
51+
// Run existing v0 validation first (covers schema checks, contested flows, etc.)
52+
let base_result =
53+
self.validate_structure_v0(owner_id, block_info, network, platform_version)?;
54+
if !base_result.is_valid() {
55+
return Ok(base_result);
56+
}
57+
58+
let contract_fetch_info = self.base().data_contract_fetch_info();
59+
let data_contract = &contract_fetch_info.contract;
60+
let document_type_name = self.base().document_type_name();
61+
62+
// Safe to unwrap thanks to v0 validation
63+
let document_type = data_contract
64+
.document_type_optional_for_name(document_type_name)
65+
.expect("document type must exist after v0 validation");
66+
67+
// Check referenced identities if requested
68+
for (path, property) in document_type.flattened_properties() {
69+
let Some(reference) = &property.reference else {
70+
continue;
71+
};
72+
if !reference.must_exist
73+
|| reference.target != DocumentPropertyReferenceTarget::Identity
74+
{
75+
continue;
76+
}
77+
78+
let Some(identity_bytes) = self
79+
.data()
80+
.get_optional_identifier_at_path(path)
81+
.map_err(|e| Error::Protocol(e.into()))?
82+
else {
83+
continue;
84+
};
85+
86+
// account for the lookup cost
87+
execution_context.add_operation(ValidationOperation::RetrieveIdentity(
88+
RetrieveIdentityInfo::only_balance(),
89+
));
90+
91+
let Some(_) = platform.drive.fetch_identity_balance(
92+
identity_bytes,
93+
transaction,
94+
platform_version,
95+
)?
96+
else {
97+
let missing_id = Identifier::from_bytes(&identity_bytes)
98+
.map_err(|e| Error::Protocol(e.into()))?;
99+
100+
return Ok(SimpleConsensusValidationResult::new_with_error(
101+
ConsensusError::from(ReferencedEntityNotFoundError::new(
102+
missing_id,
103+
reference.target.clone(),
104+
path.to_string(),
105+
)),
106+
));
107+
};
108+
}
109+
110+
Ok(SimpleConsensusValidationResult::new())
111+
}
112+
}

packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_create_transition_action/mod.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ use crate::execution::types::state_transition_execution_context::StateTransition
1111
use crate::execution::validation::state_transition::batch::action_validation::document::document_create_transition_action::state_v0::DocumentCreateTransitionActionStateValidationV0;
1212
use crate::execution::validation::state_transition::batch::action_validation::document::document_create_transition_action::state_v1::DocumentCreateTransitionActionStateValidationV1;
1313
use crate::execution::validation::state_transition::batch::action_validation::document::document_create_transition_action::advanced_structure_v0::DocumentCreateTransitionActionStructureValidationV0;
14+
use crate::execution::validation::state_transition::batch::action_validation::document::document_create_transition_action::advanced_structure_v1::DocumentCreateTransitionActionStructureValidationV1;
1415
use crate::platform_types::platform::PlatformStateRef;
1516

1617
mod advanced_structure_v0;
18+
mod advanced_structure_v1;
1719
mod state_v0;
1820
mod state_v1;
1921

@@ -23,6 +25,9 @@ pub trait DocumentCreateTransitionActionValidation {
2325
owner_id: Identifier,
2426
block_info: &BlockInfo,
2527
network: Network,
28+
platform: &PlatformStateRef,
29+
transaction: TransactionArg,
30+
execution_context: &mut StateTransitionExecutionContext,
2631
platform_version: &PlatformVersion,
2732
) -> Result<SimpleConsensusValidationResult, Error>;
2833

@@ -43,6 +48,9 @@ impl DocumentCreateTransitionActionValidation for DocumentCreateTransitionAction
4348
owner_id: Identifier,
4449
block_info: &BlockInfo,
4550
network: Network,
51+
platform: &PlatformStateRef,
52+
transaction: TransactionArg,
53+
execution_context: &mut StateTransitionExecutionContext,
4654
platform_version: &PlatformVersion,
4755
) -> Result<SimpleConsensusValidationResult, Error> {
4856
match platform_version
@@ -53,9 +61,18 @@ impl DocumentCreateTransitionActionValidation for DocumentCreateTransitionAction
5361
.document_create_transition_structure_validation
5462
{
5563
0 => self.validate_structure_v0(owner_id, block_info, network, platform_version),
64+
1 => self.validate_structure_v1(
65+
owner_id,
66+
block_info,
67+
network,
68+
platform,
69+
transaction,
70+
execution_context,
71+
platform_version,
72+
),
5673
version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch {
5774
method: "DocumentCreateTransitionAction::validate_structure".to_string(),
58-
known_versions: vec![0],
75+
known_versions: vec![0, 1],
5976
received: version,
6077
})),
6178
}

0 commit comments

Comments
 (0)