Part 3: Annotated Specification
def integer_squareroot(n: uint64) -> uint64: """ Return the largest integer ``x`` such that ``x**2 <= n``. """ x = n y = (x + 1) // 2 while y < x: x = y y = (x + n // x) // 2 return x
Validator rewards scale with the reciprocal of the square root of the total active balance of all validators. This is calculated in
integer_squareroot is also used in
get_attestation_participation_flag_indices(), to specify the maximum delay for source votes to receive a reward. But this is just the constant,
integer_squareroot(SLOTS_PER_EPOCH), which is
Newton's method is used which has pretty good convergence properties, but implementations may use any method that gives identical results.
def xor(bytes_1: Bytes32, bytes_2: Bytes32) -> Bytes32: """ Return the exclusive-or of two 32-byte strings. """ return Bytes32(a ^ b for a, b in zip(bytes_1, bytes_2))
xor of two 32-byte quantities is defined here in Python terms.
This is used only in
process_randao() when mixing in the new randao reveal.
Fun fact: if you
byte types in Java, the result is a 32 bit (signed) integer. This is one reason we need to define the "obvious" here. But mainly, because the spec is executable, we need to tell Python what it doesn't already know.
def uint_to_bytes(n: uint) -> bytesis a function for serializing the
uinttype object to bytes in
ENDIANNESS-endian. The expected length of the output is the byte-length of the
For the most part, integers are integers and bytes are bytes, and they don't mix much. But there are a few places where we need to convert from integers to bytes:
- several times in the
compute_proposer_index()for selecting a proposer weighted by stake;
get_seed()to mix the epoch number into the randao mix;
get_beacon_proposer_index()to mix the slot number into the per-epoch randao seed; and
You'll note that in every case, the purpose of the conversion is for the integer to form part of a byte string that is hashed to create (pseudo-)randomness.
The result of this conversion is dependent on our arbitrary choice of endianness, that is, how we choose to represent integers as strings of bytes. For Eth2, we have chosen little-endian: see the discussion of
ENDIANNESS for more background.
uint_to_bytes() function is not given an explicit implementation in the specification, which is unusual. This to avoid exposing the innards of the Python SSZ implementation (of
uint) to the rest of the spec. When running the spec as an executable, it uses the definition in the SSZ utilities.
def bytes_to_uint64(data: bytes) -> uint64: """ Return the integer deserialization of ``data`` interpreted as ``ENDIANNESS``-endian. """ return uint64(int.from_bytes(data, ENDIANNESS))
bytes_to_uint64() is the inverse of
uint_to_bytes(), and is used by the shuffling algorithm to create a random index from the output of a hash.
It is also used in the validator specification when selecting validators to aggregate attestations, and sync committee messages.
int.from_bytes is a built-in Python 3 method. The
uint64 cast is provided by the spec's SSZ implementation.
|See also||attestation aggregator selection, sync committee aggregator selection|