-
Notifications
You must be signed in to change notification settings - Fork 12
fix: prevent duplicate loaded contracts #854
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: v1.0-dev
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
|
|
@@ -16,6 +16,7 @@ use dash_sdk::dpp::consensus::state::state_error::StateError; | |
| use dash_sdk::dpp::dashcore; | ||
| use dash_sdk::dpp::dashcore::Network; | ||
| use dash_sdk::dpp::platform_value::string_encoding::Encoding; | ||
| use dash_sdk::dpp::prelude::Identifier; | ||
| use thiserror::Error; | ||
|
|
||
| /// Dash Core RPC error code: wallet file not specified (multi-wallet node). | ||
|
|
@@ -458,6 +459,43 @@ pub enum TaskError { | |
| )] | ||
| DataContractNotFound, | ||
|
|
||
| /// A user-driven mutation targeted a built-in system contract. System | ||
| /// contracts (DPNS, DashPay, withdrawals, token history, keyword search) | ||
| /// are managed by the application and cannot be modified or removed. | ||
| #[error( | ||
| "Contract {contract_id} is a built-in system contract and cannot be modified or removed. \ | ||
| Use a different contract." | ||
| )] | ||
| SystemContractImmutable { | ||
| /// Identifier of the system contract whose mutation was rejected. | ||
| /// Rendered as Base58 in the user-facing message via `Identifier`'s | ||
| /// `Display` implementation. | ||
| contract_id: Identifier, | ||
| }, | ||
|
|
||
| /// The same contract identifier appeared more than once in a single | ||
| /// add-contracts request. | ||
| #[error( | ||
| "Contract {contract_id} was entered more than once. Remove the duplicate entry before adding contracts." | ||
| )] | ||
| DuplicateContractInRequest { | ||
| /// Identifier of the duplicated contract. Rendered as Base58 in the | ||
| /// user-facing message via `Identifier`'s `Display` implementation. | ||
| contract_id: Identifier, | ||
| }, | ||
|
|
||
| /// An add-contracts request referenced a contract that is already loaded | ||
| /// (either persisted in the local database or one of the built-in system | ||
| /// contracts). | ||
| #[error( | ||
| "Contract {contract_id} is already loaded. Select it from the existing contracts list or enter a different contract ID." | ||
| )] | ||
| ContractAlreadyLoaded { | ||
| /// Identifier of the already-loaded contract. Rendered as Base58 in | ||
| /// the user-facing message via `Identifier`'s `Display` implementation. | ||
| contract_id: Identifier, | ||
| }, | ||
|
Comment on lines
+462
to
+497
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: New TaskError variants store Identifier as Base58 String, erasing the typed value SystemContractImmutable, DuplicateContractInRequest, and ContractAlreadyLoaded each carry contract_id: String. Every construction site (contract_token_db.rs:304/320, contract.rs:83/91/268/276) re-runs identifier.to_string(Encoding::Base58), so the typed Identifier is erased before the variant is built. Downstream consumers (future MCP tools, scripting, structural matching) cannot recover the original ID. Storing Identifier directly and formatting via Display in the #[error(...)] template (or a small wrapper) preserves the type, centralises Base58 encoding, and keeps the user-visible string identical. Storing typed IDs is consistent with the project rule allowing Base58 IDs in user-facing messages — the concern is the type erasure, not the encoding. source: ['claude'] 🤖 Fix this with AI agents |
||
|
|
||
| // ────────────────────────────────────────────────────────────────────────── | ||
| // Serialization errors | ||
| // ────────────────────────────────────────────────────────────────────────── | ||
|
|
||
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.
🔴 Blocking: SaveDataContract guard breaks importing a new token from an already-loaded contract
The new
SaveDataContractguard rejects every contract ID returned byloaded_contract_ids()before callinginsert_contract_if_not_exists.AddTokenByIdScreen(src/ui/tokens/add_token_by_id_screen.rs:147) dispatchesSaveDataContract(contract, None, SomeTokensShouldBeAdded(...))precisely to add a token to an existing contract — the DB helper handles this case correctly viaINSERT OR IGNOREon the contract row followed by token insertion at src/database/contracts.rs:59–93. With this guard in place, importing a token from a contract the user already has saved now errors withContractAlreadyLoadedand the token is never inserted. The guard should not fire when the caller passedInsertTokensToo::SomeTokensShouldBeAdded(or, more generally, when there is still token work to do on an existing contract row).source: ['codex']