[PM-21801] fix: return BeneficiaryNotFound for absent beneficiaries in get_unclaimed_amount#1359
Merged
m2ux merged 5 commits intoApr 30, 2026
Conversation
Branch for fix: get_unclaimed_amount returns BeneficiaryNotFound for absent beneficiaries. Jira: PM-21801 Signed-off-by: Mike Clay <mike.clay@shielded.io>
- Add Beneficiary alias for clarifying benefit recipient distinction - Implement explicit Err(DispatchError::CannotLookup) for missing ledger entries - Add comprehensive error handling tests for missing beneficiary scenarios - Return proper error type instead of ambiguous Ok(0) fallback Signed-off-by: Mike Clay <mike.clay@shielded.io>
LGLO
approved these changes
Apr 23, 2026
Contributor
Author
|
/bot rebuild-metadata |
Contributor
|
✅ Metadata rebuild complete! Changes have been committed. |
Signed-off-by: Mike Clay <mike.clay@shielded.io>
ozgb
added a commit
that referenced
this pull request
May 1, 2026
Post-merge: `LedgerApiError::BeneficiaryNotFound` was added on `main` (#1359). The flattened `From<LedgerApiError> for Error<T>` impls in `cnight-observation` and `midnight-system` need a matching arm now that they enumerate variants explicitly rather than wrapping the whole type. Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>
RomarQ
pushed a commit
to RomarQ/midnight-node
that referenced
this pull request
May 5, 2026
* feat(ledger): surface nested error variants in flat ledger error enums Variants like MalformedTransaction::EffectsCheckFailure(EffectsCheckError) were previously collapsed to a single flat code, hiding the inner cause from end-users. Flatten the inner enums (EffectsCheckError, SequencingCheckError, DisjointCheckError, FeeCalculationError, MalformedContractDeploy, TransactionApplicationError, zswap MalformedOffer and TransactionInvalid) into granular variants in InvalidError, MalformedError, and SystemTransactionError, with stable u8 codes in the free 212-250 range. Add version-specific error_ext modules (versions/error_ext/ledger_7.rs, ledger_8.rs) wired through lib.rs in the same style as block_context. Each version maps only the variants it knows about; unknown variants fall through to UnknownError + log rather than being silently misclassified. This replaces the prior '_ => Ste::MerkleTreeError' pattern, which would have masked any future ledger 9+ additions as MerkleTreeError. Adds InvalidError variants for ledger 8's MerkleTreeError (top-level and zswap-nested) and DivideByZero (present in both versions). Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com> * fix: add missing error fallback warning log Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com> * chore: add change files for granular ledger error codes Covers both the node-side host conversion changes and the runtime-side pallet error variants exposed to end-users. Runtime metadata rebuild is required as a result of the new variants. Fixes: midnightntwrk#1374 Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com> * chore: change file Fixes -> Helps with for issue 1374 Granular error codes don't resolve the underlying issue, just make it easier to debug. Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com> * docs: update change files with PR links Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com> * docs: update comments Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com> * chore: rebuild metadata * feat(ledger): nest granular ledger error variants Replace flattened variant names like `EffectsCheckRealCallsSubsetCheckFailure` with nested wrappers like `MalformedError::EffectsCheck(EffectsCheckErrorCode::RealCallsSubsetCheckFailure)`. Variant names now mirror upstream `mn_ledger` types directly. Each sub-enum gets its own 256-variant budget, and the compile-time `MAX_MODULE_ERROR_ENCODED_SIZE` check enforces correctness. Flatten `LedgerApiError` into `cnight-observation::Error<T>` and `midnight-system::Error<T>` (mirroring the `midnight` pallet pattern). The previous `Error::LedgerApiError(LedgerApiError)` wrapper added an extra byte that, combined with the new nesting, exceeded the 4-byte module error budget. u8 codes via `From<LedgerApiError>` are preserved for all reachable variants. Two fallback paths now produce more specific bytes: unmapped upstream ZswapTransactionInvalid -> 103 (was 109) and unmapped MalformedOffer -> 127 (was 139), reusing what were previously vestigial flat catch-all bytes. SCALE pallet error encoding for granular variants changes shape: e.g. `Error::Transaction(Malformed(EffectsCheck(RealCallsSubsetCheckFailure)))` is 4 bytes vs the previous 3-byte flat encoding. Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com> * feat(ledger): reserve retired u8 error codes Codes 168, 182, 186, 187, 188, 193, 205 were assigned to flat catch-all variants (`MalformedError::FeeCalculation` etc.) on `main` and were observable to mempool clients via `InvalidTransaction::Custom`. They are no longer produced by the nested encoding, but reusing them for new variants would silently collide on the wire. Document the reservation in `RETIRED_U8_ERROR_CODES` and assert at test time that no `LedgerApiError` value encodes to one of them. Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com> * fix(pallets): handle BeneficiaryNotFound in wrapper Error conversions Post-merge: `LedgerApiError::BeneficiaryNotFound` was added on `main` (midnightntwrk#1359). The flattened `From<LedgerApiError> for Error<T>` impls in `cnight-observation` and `midnight-system` need a matching arm now that they enumerate variants explicitly rather than wrapping the whole type. Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com> * chore: rebuild metadata --------- Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fix absent-entity ambiguity in `get_unclaimed_amount`: non-existent beneficiaries now return `Err(LedgerApiError::BeneficiaryNotFound)` instead of `Ok(0)`, allowing RPC consumers to distinguish a missing beneficiary from one with zero unclaimed rewards.
🎫 PM-21801 📐 Engineering
Motivation
`Bridge::get_unclaimed_amount` used `unwrap_or(&0)` when looking up a beneficiary in the ledger state map. A caller querying an address that has never been registered received `Ok(0)` — the same response as a known beneficiary with zero unclaimed. There was no way to distinguish the two cases.
This is the absent-entity ambiguity pattern (AI Audit Finding R-009, severity Medium). The sibling function `get_contract_state` was fixed by the same pattern in PM-19973.
Changes
📌 Submission Checklist
🔱 Fork Strategy
🗹 TODO before merging