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<TLinkAddress> 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):
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
fn default_internal(external: bool) -> RangeInclusive<T> {
if external { T::from_byte(1)..=Hybrid::half() } else { ... }
}
fn default_external(external: bool) -> Option<RangeInclusive<T>> {
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::<u32>::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<uint>(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:
Why it matters
doublets::data::LinksExtensions::exist branches on is_external first:
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:
fn default_external(external: bool) -> Option<RangeInclusive<T>> {
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 to doublets 0.5.0 (link-foundation/link-cli#100).
Summary
LinksConstants::external()builds an external-reference range that starts on thecontinueconstant, sois_external(constants.r#continue)istrue. The C#LinksConstants<TLinkAddress>this type mirrors starts the external range one address later and answersFalsefor the same query.Where it comes from
full_newreserves six service values at the top of the internal range and then takes the external range verbatim (src/constants.rs):and the defaults for
external()areinternal.end()isHybrid::half(), sor#continue == Hybrid::half()— which is also*external_range.start(). The two ranges overlap by exactly one address.Reproduction
LinksConstants::<u32>::external(), platform-data 2.0.0 via doublets 0.5.0:new LinksConstants<uint>(enableExternalReferencesSupport: true), Platform.Data.Doublets 0.18.1:Both programs, one per language, are runnable:
external-range/rust(./run.sh; exits 0 while the overlap reproduces, non-zero once it is fixed)external-range/csharp(./run.sh)Why it matters
doublets::data::LinksExtensions::existbranches onis_externalfirst:so on a store built with
LinksConstants::external(),exist(constants.r#continue)reportstruefor an address that is a control marker rather than a link. Any code that funnels aFlow-style constant through an existence check — or that hands out0 - valueexternal 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:
full_newcould also assert that the two ranges are disjoint, so a caller-supplied pair cannot reintroduce the overlap.Found while updating link-foundation/link-cli to doublets 0.5.0 (link-foundation/link-cli#100).