-
Notifications
You must be signed in to change notification settings - Fork 53
feat(sdk): add client-side validation to state transition construction methods #3096
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v3.1-dev
Are you sure you want to change the base?
Changes from all commits
fc97d54
5318ac6
432d57f
8f8259c
62e4014
cb44fc0
ba23aa3
30b2ac5
6b49a36
a17e51c
a72e0e7
a2d190f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,8 @@ use crate::serialization::Signable; | |
| use crate::state_transition::address_credit_withdrawal_transition::methods::AddressCreditWithdrawalTransitionMethodsV0; | ||
| use crate::state_transition::address_credit_withdrawal_transition::v0::AddressCreditWithdrawalTransitionV0; | ||
| #[cfg(feature = "state-transition-signing")] | ||
| use crate::state_transition::first_consensus_error_as_protocol_error; | ||
| #[cfg(feature = "state-transition-signing")] | ||
| use crate::withdrawal::Pooling; | ||
| #[cfg(feature = "state-transition-signing")] | ||
| use crate::{ | ||
|
|
@@ -35,7 +37,7 @@ impl AddressCreditWithdrawalTransitionMethodsV0 for AddressCreditWithdrawalTrans | |
| output_script: CoreScript, | ||
| signer: &S, | ||
| user_fee_increase: UserFeeIncrease, | ||
| _platform_version: &PlatformVersion, | ||
| platform_version: &PlatformVersion, | ||
| ) -> Result<StateTransition, ProtocolError> { | ||
| tracing::debug!("try_from_inputs_with_signer: Started"); | ||
| tracing::debug!( | ||
|
|
@@ -57,6 +59,15 @@ impl AddressCreditWithdrawalTransitionMethodsV0 for AddressCreditWithdrawalTrans | |
| input_witnesses: Vec::new(), | ||
| }; | ||
|
|
||
| // Pre-signing structure check: validate everything except the witness | ||
| // count, so structural errors fail fast before performing any async | ||
| // signer work. | ||
| let pre_validation_result = address_credit_withdrawal_transition | ||
| .validate_structure_without_input_witnesses(platform_version); | ||
| if let Some(error) = first_consensus_error_as_protocol_error(pre_validation_result) { | ||
| return Err(error); | ||
| } | ||
|
|
||
| let state_transition: StateTransition = address_credit_withdrawal_transition.clone().into(); | ||
|
|
||
| let signable_bytes = state_transition.signable_bytes()?; | ||
|
|
@@ -67,6 +78,14 @@ impl AddressCreditWithdrawalTransitionMethodsV0 for AddressCreditWithdrawalTrans | |
| } | ||
| address_credit_withdrawal_transition.input_witnesses = input_witnesses; | ||
|
|
||
| // After signing, only the witness count needs (re-)validation; the rest | ||
| // of the structure was already verified above. | ||
| let validation_result = | ||
| address_credit_withdrawal_transition.validate_input_witnesses_count(); | ||
| if let Some(error) = first_consensus_error_as_protocol_error(validation_result) { | ||
| return Err(error); | ||
| } | ||
|
Comment on lines
+83
to
+87
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: The same six-line block — call source: ['claude'] 🤖 Fix this with AI agents |
||
|
|
||
| tracing::debug!("try_from_inputs_with_signer: Successfully created transition"); | ||
| Ok(address_credit_withdrawal_transition.into()) | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Suggestion: Structure validation runs after async signing — invalid transitions still incur N signer round-trips
validate_structure()is called only after the loop that awaitssigner.sign_create_witness(...)for every input. None of the structural checks (max inputs, fee strategy, output script, input/output amounts) actually depend on the witnesses; only the witness-count check does, and it is tautologically satisfied here because the loop produces exactlyinputs.len()witnesses. The same pattern exists inaddress_funds_transfer_transition/v0/v0_methods.rs,address_funding_from_asset_lock_transition/v0/v0_methods.rs,identity_create_from_addresses_transition/v0/v0_methods.rs, andidentity_topup_from_addresses_transition/v0/v0_methods.rs. WhenSigneris backed by a hardware wallet, secure enclave, or remote KMS — the SDK's primary use case — every input requires a user prompt or network round-trip. The whole point of this PR is to fail fast client-side before broadcast; failing fast after N HSM confirmations defeats much of the benefit. Add a pre-signing structure check (skipping only the witness-count assertion) in addition to the existing post-signing call.source: ['claude']
🤖 Fix this with AI agents