Skip to content

enhance(LargeSmtForest tests): expand LargeSmtForest property test coverage#886

Open
AlexWaker wants to merge 5 commits into0xMiden:nextfrom
AlexWaker:issue879
Open

enhance(LargeSmtForest tests): expand LargeSmtForest property test coverage#886
AlexWaker wants to merge 5 commits into0xMiden:nextfrom
AlexWaker:issue879

Conversation

@AlexWaker
Copy link

@AlexWaker AlexWaker commented Mar 10, 2026

This PR expands the property-based test coverage for LargeSmtForest.

Previously, the forest-level property tests were mostly limited to entries(). This change adds a broader set of reference-model-driven property tests covering core query, mutation, metadata, constructor, and truncation behavior.

The new tests now exercise:

  • query consistency for get(), entries(), and entry_count()
  • selected open() consistency checks against a reference Smt
  • metadata consistency for latest_version(), latest_root(), lineage_roots(), roots(), and root_info()
  • mutation behavior for add_lineage(), update_tree(), and update_forest()
  • failure semantics, including duplicate lineages, bad version transitions, and invalid forest batches
  • constructor behavior when initializing a forest from a pre-populated backend
  • retention and visibility semantics for with_config() and truncate()

In addition, the property test helpers and generators were refactored to make the coverage easier to extend and maintain.

Closes #879.

@AlexWaker AlexWaker changed the title enhance(): xpand LargeSmtForest property test coverage enhance(LargeSmtForest tests): expand LargeSmtForest property test coverage Mar 10, 2026
@huitseeker huitseeker self-requested a review March 18, 2026 09:10
.operations(unknown_lineage)
.add_insert(query_key, invalid_value);
let invalid_result = forest.update_forest(version + 2, invalid_updates);
prop_assert!(invalid_result.is_err());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we also assert metadata is unchanged after this error path? Right now we re-check entries and queries, but a partial apply bug could still move latest_version or create a new root_info at version + 2 and this test would still pass.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand. I'll fix it as soon as possible

let bad_version = forest.update_tree(lineage, version, extra_entries);
prop_assert!(bad_version.is_err());
prop_assert_eq!(
bad_version.unwrap_err().to_string(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be safer to assert the error variant instead of exact to_string() text? Matching full message strings can make this test fail on wording-only changes.

@AlexWaker
Copy link
Author

Resolved the merge conflict by aligning property_tests.rs with the upstream API changes, including the new fallible entries() usage.

Also addressed the two review comments:

  • replaced string-based error assertions with matching on concrete error variants
  • added post-error metadata checks to ensure failed updates do not change lineage/tree metadata or create new root_info entries

Finally, ran formatting checks and applied rustfmt fixes (cargo +nightly fmt --all and cargo +nightly fmt --all --check).

@AlexWaker
Copy link
Author

Would this PR need a changelog entry?

My understanding is that it probably does not, since this change only expands internal test coverage and adapts the tests to upstream API changes, without introducing any user-facing behavior change or public API change. From the current CHANGELOG.md, it also seems like entries are generally reserved for externally visible features, fixes, and breaking changes.

That said, if you would still prefer one to be added, I can update the changelog right away.

@huitseeker huitseeker added the no changelog This PR does not require an entry in the `CHANGELOG.md` file label Mar 23, 2026
@huitseeker huitseeker requested a review from iamrecursion March 23, 2026 10:35
Copy link
Contributor

@huitseeker huitseeker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is shaping up nicely! See comments inline.

TreeId::new(lineage, version),
&tree_v1,
&sample_keys,
false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper skips open() on the historical tree by passing false here. Can we also property-test historical open() against the reference Smt? That feels like the trickiest query path in LargeSmtForest, and right now it still looks like it only has the hand-written unit test coverage in tests.rs.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this should 100% test historical openings as well.

@@ -0,0 +1 @@
cc abf493f7aece0d6db6c370e3c95651effc9f46f7a2f97e2dccddacfce2afd16d No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any behavioral fixes in this PR. We usually only keep regression seeds like this when they allowed us to identify an interesting failure, which required fixing. This seems like it was just a development artifact and so does not need keeping.

Copy link
Collaborator

@iamrecursion iamrecursion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks reasonable in general! I've left a few comments in-line.

One thing I would love to see for every single potential modification is that we assert complete correctness with regards to the state change. Some of these—like the one @huitseeker commented on—do not assert the complete soundness of all propertiess should a bug arise.

Perhaps this is out of scope for this PR, but I would also be interested in expanding the FallibleEntriesBackend to be a more general mechanism for testing state coherence in the face of a number of different kinds of failure. @huitseeker, thoughts?

};

// ENTRIES
// HELPERS
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these helpers should be moved to large_forest::test_utils like the other strategies are. I would also expect them to have doc comments, as that is the first line of understanding for someone reading the property test after a failure.


fn apply_batch(tree: &mut Smt, batch: SmtUpdateBatch) -> core::result::Result<(), TestCaseError> {
let mutations = tree
.compute_mutations(Vec::<(Word, Word)>::from(batch).into_iter())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should call batch.consume().into_iter() instead. That guarantees the correct deduplication behaviouor.

}

fn sorted_forest_entries(
forest: &LargeSmtForest<ForestInMemoryBackend>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Realistically, this and all subsequent cases that take a forest should be parametric in the backend. While we currently only do these with the in-memory backend, there is no reason that has to remain the case forever.

.collect::<crate::merkle::smt::large_forest::Result<Vec<_>>>()
.map_err(to_fail)?
.into_iter()
.sorted()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of sorting them? Does the default derived Ord implementation order them correctly?

Ok(())
}

// PROPERTY TESTS
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, please reorder these property tests to match the method order in the large forest itself. It makes for easier code navigation.

TreeId::new(lineage, version),
&tree_v1,
&sample_keys,
false,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this should 100% test historical openings as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no changelog This PR does not require an entry in the `CHANGELOG.md` file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve property tests for LargeSmtForest

3 participants