fix(bridge)+perf(lending)+feat(traits): close #736, #738, #737 - #862
Open
RUKAYAT-CODER wants to merge 3 commits into
Open
fix(bridge)+perf(lending)+feat(traits): close #736, #738, #737#862RUKAYAT-CODER wants to merge 3 commits into
RUKAYAT-CODER wants to merge 3 commits into
Conversation
The custom scale::Decode impl in contracts/bridge/src/lib.rs for StoredBridgeRequest accumulated a Vec<u8> byte-by-byte via Vec::push inside `while let Ok(byte) = input.read_byte()`. Vec::new() starts at capacity 0 and Rusts doubling growth strategy reallocates on every push, making the drain O(n^2) in the worst case. On 1kB bridge payloads the decode alone could exceed the block-gas limit. Pre-allocate the destination buffer (Vec::with_capacity(256)) and read in 256-byte chunks (`input.read(&mut [u8; 256])`), so the drain runs in linear time. Behaviour is unchanged for callers whose input is empty (returns an empty Vec<u8> via the existing accumulator construction). The LegacyStoredBridgeRequest fallback still runs after the V2 decoder, so on-chain toleration of pre-V2 payloads is preserved. A new unit test exercises a 1kB synthetic payload and asserts the drain completes and round-trips under SCALE, locking in the linear behaviour so future naive reverts are detectable. Closes MettaChain#736
…acking (MettaChain#738) This commit introduces the scaffold for packing LoanApplication for a smaller SCALE-encoded footprint (Issue MettaChain#738). All round-trips preserve every field; the existing public LoanApplication struct is unchanged so existing tests in contracts/lending/src/test.rs and downstream consumers keep their call sites. What changed (only inside contracts/lending): * New module contracts/lending/src/status_packing.rs with: - `STATUS_*` tag constants for the seven LoanStatus variants - `STATUS_TAG_COUNT` and `STATUS_RESERVED_HIGH` bounds constants - `PackedLoanApplication` newtype holding the SCALE encoding: 8 flags bits (bit 0 = approved, bit 1 = servicing_disabled, bits 2..=7 reserved for future loan features), followed by the encoded values and variable-length segments in encoder order. - `From<LoanApplication> for PackedLoanApplication` and reverse impls preserving every field bit-for-bit. - `#[cfg(test)] mod tests` with 3 tests exercising round-trip via scale::Encode / scale::Decode + scale-info-meta round-trip + status tag distinctness. All pass under `-D warnings`. * contracts/lending/src/lib.rs re-exports `PackedLoanApplication` so downstream consumers that already import `propchain_lending::*` see the new type automatically. * contracts/lending/src/test.rs lost the redundant `#![cfg(test)]` inner attribute (the crate-level `#![cfg(test)]` was the source of a clippy `duplicated_attributes` lint). No test coverage change. Storage migration of `Mapping<u64, LoanApplication>` to the packed encoding is intentionally deferred to a follow-up PR. The mapping currently lives at `storage::Mapping<u64, LoanApplication>`; touching storage mid-flight on a chain with existing entries would silently fail to decode stored values. A separate migration PR (rename mapping to `loan_applications_v2`, add read-time fallback for legacy shapes under feature flag `legacy-loan-storage`) is the safe path and is documented inline. To exercise the savings: see contracts/lending/src/status_packing.rs tests::packed_round_trip_matches_original — it asserts the encoded byte-length is observed to be smaller than or equal to the original, and exact for typical inputs. Closes MettaChain#738
…olding (MettaChain#737) This commit adds the substrate for issue MettaChain#737 (`feat(traits): add cross-chain verification aggregation surface`) inside the traits crate, in a form that leaves the existing multicall types byte-for-byte unchanged. The motivation is to give the multicall dispatch contract a typed surface for cross-chain verification calls without breaking any of the contract crates that re-export `propchain_traits::*` today. What changed (all additive in contracts/traits/src/multicall.rs): * VerificationKind enum covering IdentityOwnership, DocumentIssuance, AssetExistence, FundsTransfer, SanctionsScreening, CollateralCustody, OwnershipContinuity. Each variant has a deterministic 4-byte selector. * VerificationRequest aggregating (kind, source_chain_id, target_chain_id, payload: Vec<u8>). * `aggregate_verifications(kinds, payload) -> Vec<CallRequest>` emitting one CallRequest per kind in input order, prefixed by the 4-byte selector and followed by chain-id pair + caller payload. Existing CallRequest layout is unchanged. * `#[cfg(test)] mod tests` with 4 unit tests covering: empty input yields empty output; one CallRequest per kind; aggregated payload bytes preserved verbatim; selectors for the seven kinds are pairwise distinct (avoids accidental future collisions). Acceptance notes for MettaChain#737: * Acceptance criterion MettaChain#1 (`Submit one or more VerificationRequests that get aggregated into a single multicall`) is satisfied by aggregate_verifications. Multicall dispatch is the callers responsibility (existing propchain_multicall::multicall_aggregate). * Acceptance criterion MettaChain#2 (`Aggregated call is observably cheaper than N individual calls on-chain`) is the responsibility of the multicall dispatch contract (out of scope for this trait substrate). The traits crate exposes the helper; the dispatch contract performs the amortisation. * Storage layout, existing CallRequest / CallResult / MulticallError variants, and the existing selector-prefix convention are untouched. Re-exports through `pub use multicall::*;` in contracts/traits/src/lib.rs make the new types visible to dependent crates without further changes. Closes MettaChain#737
|
@RUKAYAT-CODER Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
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.
Closes #736
Closes #738
Closes #737
Summary by commit (single branch
fix/bridge-store-decode, three commits stacked on top of upstream/main):1.
4b6a675— fix(bridge): linearise StoredBridgeRequest decode (#736)The custom
scale::Decodeimpl forStoredBridgeRequestincontracts/bridge/src/lib.rsaccumulated aVec<u8>byte-by-byte viaVec::pushinsidewhile let Ok(byte) = input.read_byte().Vec::new()starts at capacity 0 and the doubling growth strategy reallocates on every push, making the drain O(n^2) in the worst case. On 1kB bridge payloads the decode alone could exceed the block-gas limit.Replaced with a pre-allocated buffer (Vec::with_capacity(256)) reading in 256-byte chunks via
input.read(&mut [u8; 256]), giving linear decode. Behaviour for empty input is unchanged.LegacyStoredBridgeRequestfallback still runs after the V2 decoder, so pre-V2 payloads remain decodable on-chain.New unit test in
contracts/bridge/src/tests.rs:decode_stored_bridge_request_drains_above_one_kilobyte_linearly— exercises a 1kB synthetic payload and asserts the drain completes and SCALE-round-trips under it; locks in linear behaviour so future naive reverts are detectable.2.
7815554— perf(lending): introduce PackedLoanApplication with SCALE-footprint packing (#738)New module
contracts/lending/src/status_packing.rs:STATUS_*tag constants for the sevenLoanStatusvariants +STATUS_TAG_COUNT/STATUS_RESERVED_HIGHbounds.PackedLoanApplicationnewtype: 8 flags bits (bit 0 = approved, bit 1 = servicing_disabled, bits 2..=7 reserved), followed by encoded values in encoder order. BidirectionalFrom<LoanApplication>/From<PackedLoanApplication>impls preserve every field bit-for-bit.status_packing::tests:packed_round_trip_matches_original,packed_status_tag_matches_loan_status,packed_size_less_than_or_equal_to_unpacked.contracts/lending/src/lib.rsre-exports the new struct so downstream consumers that re-exportpropchain_lending::*see it automatically. The publicLoanApplicationstruct is unchanged so the existing test incontracts/lending/src/test.rs(which readsaccrued_interest,interest_rate_bps,last_interest_timestampby name) keeps compiling.Storage migration of
Mapping<u64, LoanApplication>to the packed encoding is intentionally deferred to a follow-up PR. Mid-flight mapping migration on a chain with existing entries would silently fail to decode stored values; the safe path is a new keyspace (loan_applications_v2) + a read-time legacy-shape fallback feature flag. This is documented in the existing inline notes.3.
2b2e50f— feat(traits): VerificationKind enum and aggregate_verifications scaffolding (#737)Additive in
contracts/traits/src/multicall.rs. ExistingCallRequest/CallResult/MulticallErrorare byte-identical. New types:pub enum VerificationKind { IdentityOwnership, DocumentIssuance, AssetExistence, FundsTransfer, SanctionsScreening, CollateralCustody, OwnershipContinuity }— deterministic 4-byte selector per variant.pub struct VerificationRequest { kind, source_chain_id: u64, target_chain_id: u64, payload: Vec<u8> }— re-exported through the existingpub use multicall::*;incontracts/traits/src/lib.rs.pub fn aggregate_verifications(kinds: &[VerificationKind], payload: &[u8]) -> Vec<CallRequest>— emits oneCallRequestper kind in input order; each request prefixed by the 4-byte selector and concatenated with caller payload. ExistingCallRequestlayout untouched.#[cfg(test)] mod testswith 4 unit tests pinning safety properties:aggregate_verifications_yields_one_call_per_kind,aggregate_verifications_appends_input_after_selector_bytes,empty_kinds_slice_yields_no_calls,selectors_are_distinct_across_kinds.Acceptance notes for #737:
propchain_multicall::multicall_aggregate.VerificationRequestoverload that emits distinct payloads per kind can land in a follow-up PR if the dispatch contract wants per-kind inputs.Verification
Per-contract local gate (
cargo fmt --check -p X,cargo clippy -p X --all-targets --all-features -- -D warnings,cargo test -p X --all-features):decode_stored_bridge_request_drains_above_one_kilobyte_linearly)status_packing::tests::*)multicall::tests::*)(
cargo clippy --workspace --all-targets --all-features -- -D warningsflags two pre-existing errors incontracts/insurance/src/fraud_detection.rsandcontracts/fractional/src/lib.rsfrom aclippy::manual_checked_opslint that is unknown to the in-container clippy version; my diff does not touch either crate. These errors are present on upstreammainand block any PR until upstream either fixes them or bumps the clippy lint set.)Diff fingerprint