FieldAddress

Trait FieldAddress 

Source
pub trait FieldAddress: Sized {
    // Required methods
    fn root() -> Self;
    fn child(&self, number: u64) -> Self;
    fn unordered(&self) -> (Self, Self);
}
Expand description

Tracks the path from the root of a struct to a member value. For example, within the value vec![ { num: 0, string: “Alice” }, { num: 1, string: “Bob” } ], the value Alice exists at the path:

FieldAddress::root() // Vec .child(0) // [0] .child(1) // .string

Because default values do not contribute to the final hash in order to support backward compatibility, this concept is necessary to disambiguate in cases where default values exist in a struct with multiple fields. For example given the struct:

Struct { a: 0, b: 1, }

and

Struct { a: 1, b: 0, }

if we naively write out the struct as a series of fields without addresses each would produce the following encoded stream (default values omitted):

{1} {1}

But, with field addresses you get this encoding instead:

{(1, 0)} {(0, 1)}

which fixes the collision.

Required Methods§

Source

fn root() -> Self

The starting value

Source

fn child(&self, number: u64) -> Self

A nesting along the path. When calling this function, a consistent number should be supplied to identify a given field. To maintain backward compatibility, this number should remain consistent even as fields are added, removed, or re-ordered.

Source

fn unordered(&self) -> (Self, Self)

This one is tricky, as it involves hashing a set online. In this case, each member of the set has the same FieldAddress, but work must be done to relate multiple field addresses within the same set. The first return value is for a member of the set, and the second for relating members within the set. This is confusing. Consider the following example without having two values returned here:

{ (“a”, 1), (“b”, 2) } { (“b”, 1), (“a”, 2) }

See that these collide unless we do something to “relate” children within different members of the same set even while the members must have the same address to keep the set unordered.

Understand ye, and despair. The other option was to sort the set. But, this has two drawbacks. First, it would require StableHash: Ord. (Ironically, unordered sets like HashMap and HashSet where this is relevant do not implement Ord… so this is a no-go but even if they did we still would prefer to not have this constraint). The second problem with sorting is that it is less online. Within the graph-node Proof of Indexing (the flagship use-case which this crate was implemented for) we need to be able to add and remove items from very large unordered sets without re-sorting and re-calculating everything up to the root. This ability becomes necessary when indexing off-chain data sources with unreliable availability.

Please avoid implementing or calling this function unless you know what you are doing. See also a817fb02-7c77-41d6-98e4-dee123884287

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementations on Foreign Types§

Source§

impl FieldAddress for u128

Source§

fn root() -> Self

Source§

fn child(&self, number: u64) -> Self

Source§

fn unordered(&self) -> (Self, Self)

Implementors§