linksplatform / linksplatform/data-rs
LinksConstants::external() overlaps the external range with the `continue` constant
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 1
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
`LinksConstants::external()` builds an external-reference range that starts on the `continue` constant, so `is_external(constants.r#continue)` is `true`. The C# `LinksConstants` this type mirrors starts the external range one address later and answers `False` for the same query.
## Where it comes from
`full_new` reserves six service values at the top of the internal range and then takes the external range verbatim ([`src/constants.rs`](https://github.com/linksplatform/data-rs/blob/main/src/constants.rs)):
```rust
r#continue: *internal.end(),
r#break: *internal.end() - T::from_byte(1),
// ...
internal_range: *internal.start()..=*internal.end() - T::from_byte(6),
external_range: external,
```
and the defaults for `external()` are
```rust
fn default_internal(external: bool) -> RangeInclusive {
if external { T::from_byte(1)..=Hybrid::half() } else { ... }
}
fn default_external(external: bool) -> Option> {
if external { Some(Hybrid::half()..=T::MAX) } else { None }
}
```
`internal.end()` is `Hybrid::half()`, so `r#continue == Hybrid::half()` — which is also `*external_range.start()`. The two ranges overlap by exactly one address.
## Reproduction
`LinksConstants::::external()`, platform-data 2.0.0 via doublets 0.5.0:
```
continue = 2147483647
break = 2147483646
skip = 2147483645
any = 2147483644
itself = 2147483643
error = 2147483642
internal = 1..=2147483641
external = Some(2147483647..=4294967295)
is_external(continue) = true
```
`new LinksConstants(enableExternalReferencesSupport: true)`, Platform.Data.Doublets 0.18.1:
```
continue = 2147483647
break = 2147483646
skip = 2147483645
any = 2147483644
itself = 2147483643
error = 2147483642
internal = [1..2147483641]
external = [2147483648..4294967295]
IsExternalReference(continue) = False
```
Both programs, one per language, are runnable:
- Rust — [`external-range/rust`](https://github.com/link-foundation/link-cli/tree/3d53362125be47de595b0cad7a24fe4c3aeefd3d/docs/case-studies/issue-100/evidence/external-range/rust) (`./run.sh`; exits 0 while the overlap reproduces, non-zero once it is fixed)
- C# — [`external-range/csharp`](https://github.com/link-foundation/link-cli/tree/3d53362125be47de595b0cad7a24fe4c3aeefd3d/docs/case-studies/issue-100/evidence/external-range/csharp) (`./run.sh`)
## Why it matters
`doublets::data::LinksExtensions::exist` branches on `is_external` first:
```rust
let constants = self.constants();
if constants.is_external(link) {
true
} else {
constants.is_internal(link) && self.count_by([link]) != T::from_byte(0)
}
```
so on a store built with `LinksConstants::external()`, `exist(constants.r#continue)` reports `true` for an address that is a control marker rather than a link. Any code that funnels a `Flow`-style constant through an existence check — or that hands out `0 - value` external references and reasons about which addresses are reachable — sees one address classified the wrong way. C# does not.
## Suggested fix
Start the default external range one past the half:
```rust
fn default_external(external: bool) -> Option> {
if external {
Some(Hybrid::half() + T::from_byte(1)..=T::MAX)
} else {
None
}
}
```
`full_new` could also assert that the two ranges are disjoint, so a caller-supplied pair cannot reintroduce the overlap.
Found while updating [link-foundation/link-cli](https://github.com/link-foundation/link-cli) to doublets 0.5.0 (link-foundation/link-cli#100).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/constants.rs with default_external and compare its range boundary with the C# behavior described in the issue. Run docs/case-studies/issue-100/evidence/external-range/rust/run.sh; done means the external range starts one address after Hybrid::half() and is_external(constants.r#continue) no longer reports true.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 82/100