As a complement to
https://github.com/ethereum/consensus-specs/pull/3787, this PR
introduces a `SingleAttestation` type used for network propagation only.
In Electra, the on-chain attestation format introduced in
[EIP-7549](https://github.com/ethereum/consensus-specs/pull/3559)
presents several difficulties - not only are the new fields to be
interpreted differently during network processing and onchain which adds
complexity in clients, they also introduce inefficiency both in hash
computation and bandwidth.
The new type puts the validator and committee indices directly in the
attestation type, this simplifying processing and increasing security.
* placing the validator index directly in the attestation allows
verifying the signature without computing a shuffling - this closes a
loophole where clients either must drop attestations or risk being
overwhelmed by shuffling computations during attestation verification
* the simpler "structure" of the attestation saves several hash calls
during processing (a single-item List has significant hashing overhead
compared to a field)
* we save a few bytes here and there - we can also put stricter bounds
on message size on the attestation topic because `SingleAttestation` is
now fixed-size
* the ambiguity of interpreting the `attestation_bits` list indices
which became contextual under EIP-7549 is removed
Because this change only affects the network encoding (and not block
contents), the implementation impact on clients should be minimal.
* update python to 3.12
* drop down to 3.12.4 for compatibility
* setup rust toolchain for deps
* fix typo
* fix linter
* fixing linter
* adding rust dep
* trying to fix circleci
* trying to fix circleci
* trying to fix circleci
* trying to fix circleci
* trying to fix circleci
* trying to fix circleci
* trying to fix circleci
* trying to fix circleci
* trying to fix circleci
* trying to fix circleci
* trying to fix circleci
* trying to fix circleci
* trying to fix circleci
* trying to fix circleci
* trying to fix circleci
* trying to fix circleci
* trying new image
* trying new image
* trying new image
* trying new image
* invalidate cache
* bump reqs
* remove cache invalidation
* fix cache name
* update to use latest image
This also removes references to the "extended matrix" in favor of just "matrix"
which I think is better. It's not an extended matrix, it's a matrix of extended
blobs. Technically it's just a matrix of cells/proofs.
As part of `newPayload` block hash verification, the `transactionsRoot`
is computed by the EL. Because Merkle-Patricia Tries cannot contain `[]`
entries, MPT implementations typically treat setting a key to `[]` as
deleting the entry for the key. This means that if a CL receives a block
with `transactions` containing one or more zero-length transactions,
that such transactions will effectively be skipped when computing the
`transactionsRoot`. Note that `transactions` are opaque to the CL and
zero-length transactions are not filtered out before `newPayload`.
```python
# https://eips.ethereum.org/EIPS/eip-2718
def compute_trie_root_from_indexed_data(data):
"""
Computes the root hash of `patriciaTrie(rlp(Index) => Data)` for a data array.
"""
t = HexaryTrie(db={})
for i, obj in enumerate(data):
k = encode(i, big_endian_int)
t.set(k, obj) # Implicitly skipped if `obj == b''` (invalid RLP)
return t.root_hash
```
In any case, the `blockHash` validation may still succeed, resulting in
a potential `SYNCING/ACCEPTED` result to `newPayload` by spec.
Note, however, that there is an effective hash collision if a payload is
modified by appending one or more zero-length transactions to the end of
`transactions` list: In the trivial case, a block with zero transactions
has the same `transactionsRoot` (and `blockHash`) as one of a block with
one `[]` transaction (as that one is skipped).
This means that the same `blockHash` can refer to a valid block (without
extra `[]` transactions added), but also can refer to an invalid block.
Because `forkchoiceUpdated` refers to blocks by `blockHash`, outcome may
be nondeterministic and implementation dependent. If `forkchoiceUpdated`
deems the `blockHash` to refer to a `VALID` object (obtained from a src
that does not have the extra `[]` transactions, e.g., devp2p), then this
could result in honest attestations to a CL beacon block with invalid
`[]` transactions in its `ExecutionPayload`, risking finalizing it.
The problem can be avoided by returning `INVALID` in `newPayload` if
there are any zero-length `transactions` entries, preventing optimistic
import of such blocks by the CL.
Transactions cannot be empty, they always have at least 1 byte.
Random tests should produce valid CL data by default.
There are still individual tests for invalid transactions.