Skip to content

LinksConstants::external() overlaps the external range with the continue constant #18

Description

@konard

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).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions