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§
Sourcefn child(&self, number: u64) -> Self
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.
Sourcefn unordered(&self) -> (Self, Self)
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.