[Security] GetReferenceMemo silently returns zero-value on not-found, enabling phantom state writes

Resolve #2602

This MR implements the changes described in issue #2602.

Summary

  • Add ReferenceMemoExists checks in fetchMemoFromReference and trackReferenceMemoUsage to prevent phantom state writes when transactions reference non-existent reference IDs
  • Without these guards, GetReferenceMemo returns a zero-value record (Height=0, Memo="") for missing references, and trackReferenceMemoUsage writes this phantom record to state via SetReferenceMemo, polluting the KV store
  • Add corresponding ReferenceMemoExists method to the mock keeper in tests

Test plan

  • All existing unit tests pass (make test)
  • Linter passes (make lint)
  • Blockchain consensus safety review: no non-deterministic patterns, no float math, no map iteration, no goroutines in consensus code
  • The fix uses the existing deterministic ReferenceMemoExists KV store lookup
  • Verified that fetchMemoFromReference returns empty string for non-existent references (preventing further processing)
  • Verified that trackReferenceMemoUsage skips writing for non-existent references (preventing phantom state writes)

🤖 Generated with Claude Code

Merge request reports

Loading
Loading