Summary
We found two defects in the execution payload envelope duty. Each one alone stops Anchor from
publishing the envelope.
- When the beacon node answers
BLOCK_ERROR_ALREADY_KNOWN to the block publication, Anchor stops the
full task. It then does not do the envelope duty for that slot.
- When Anchor does the envelope duty, it asks the beacon node for the envelope of its own local
candidate block, and not of the block that the committee decided.
Together, at most one Anchor operator joins each envelope consensus instance. In a committee where
two of the three operators in the quorum are Anchor operators, the envelope duty then never completes,
and the blocks are empty. See issue #1294, "A committee with two Anchor operators and one Go SSV operator
makes empty blocks".
Test environment
- Network:
ssv-mini, a local Kurtosis testnet with 4 SSV operators. The quorum is 3 of 4.
- Operators 1 and 2 run Anchor, commit
52ba589 on branch epbs (Anchor/v1.3.1-52ba589).
- Operators 3 and 4 run the Go SSV node, commit
613dd52c9 on branch epbs-gloas.
- Consensus client: Lodestar
v1.46.0/aa8303e. All 4 operators use the same beacon node.
- Execution client: go-ethereum,
glamsterdam-devnet-8 image.
- Gloas fork epoch: 4 (slot 128). The Boole fork is not scheduled.
Note: all 4 operators use one beacon node. Thus every operator builds the same block and the same
envelope, and every operator sends the block to the same beacon node. Only the first operator gets a
success answer.
Defect 1: BLOCK_ERROR_ALREADY_KNOWN stops the full task
All operators of the committee send the same reconstructed block. The beacon node accepts the first
block and answers BLOCK_ERROR_ALREADY_KNOWN to the others. This answer is normal.
Anchor treats this answer as Irrecoverable:
11:52:33.134036 INFO Publishing signed block slot=205
11:52:33.147757 DEBUG Request to beacon node failed
error=Irrecoverable("... message: \"BLOCK_ERROR_ALREADY_KNOWN\" ...")
11:52:33.150819 ERROR Error whilst producing block error="Some endpoints failed, num_failed: 2 ..."
After this error there is no Fetching execution payload envelope line for slot 205, and Anchor does
not join the envelope consensus instance of that slot.
The correlation is exact and opposite on the two Anchor nodes. One node stopped the task on slots 128,
134, 166, 175, 203 and 205, and did the envelope duty on slots 139, 143, 153, 202 and 217. The other
node did the opposite.
The Go SSV node treats BLOCK_ERROR_ALREADY_KNOWN as a success on the Gloas path
(beacon/goclient/gloas_proposer.go). In the same window the beacon node gave this answer 172 times,
and all Go SSV block proposals were a success.
What we expect
Treat BLOCK_ERROR_ALREADY_KNOWN as a success. Continue with the envelope duty.
Defect 2: the envelope request uses the local candidate root
Anchor asks for the envelope of the block root of its own candidate block:
anchor-node-0 11:38:21.233871 INFO Fetching execution payload envelope
slot=134 beacon_block_root=0xfc43256b6aff...
canonical root of slot 134 = 0x9bcce65952...
The beacon node answers HTTP 404 for the root 0xfc43256b6aff....
8 of the 12 envelope requests used a root that the beacon node does not know. The root was correct
only when an Anchor operator was the leader of the block proposal consensus (slots 128, 153, 205 and
217).
Lodestar writes the root of the request into the envelope that it gives:
Produced execution payload envelope slot=134, blockRoot=0xfc43256b...
Produced execution payload envelope slot=134, blockRoot=0x9bcce659... (two times)
All three envelopes have the same blockHash=0x9327.... Thus the cached envelope of Anchor has a
different root from the value that the committee decided. The content check then stops the
publication.
This is not an error of the root calculation. The partial signature of Anchor for the decided block
was a part of a valid signature in every block that the chain accepted, and also in the blocks where a
Go SSV operator was the leader.
What we expect
Ask for the envelope of the block root that the committee decided.
Defect 3 (small): the correct skip is also an error
Anchor has a correct message for the condition "another operator built the decided envelope":
INFO Cluster decided another operator's envelope, skipping publish (expected) (4 times)
But the same condition also gives an error message:
ERROR Error whilst producing block
error="Error signing execution payload envelope:
SpecificError(EnvelopeNotBuiltLocally { local_root: 0x..., decided_root: 0x... })"
We counted 8 of these error messages. The blocks of those slots are on the chain. Please use only the
INFO message for this condition.
Effect
In a committee with 2 Anchor operators and 2 Go SSV operators, the envelope duty completed 11 of 11.
The Anchor operator that won the block publication race always joined the instance, so the quorum of 3
was possible.
In a committee with 2 Anchor operators and 1 Go SSV operator, the envelope duty completed 0 of 4, and
all 4 blocks are empty on the chain.
Summary
We found two defects in the execution payload envelope duty. Each one alone stops Anchor from
publishing the envelope.
BLOCK_ERROR_ALREADY_KNOWNto the block publication, Anchor stops thefull task. It then does not do the envelope duty for that slot.
candidate block, and not of the block that the committee decided.
Together, at most one Anchor operator joins each envelope consensus instance. In a committee where
two of the three operators in the quorum are Anchor operators, the envelope duty then never completes,
and the blocks are empty. See issue #1294, "A committee with two Anchor operators and one Go SSV operator
makes empty blocks".
Test environment
ssv-mini, a local Kurtosis testnet with 4 SSV operators. The quorum is 3 of 4.52ba589on branchepbs(Anchor/v1.3.1-52ba589).613dd52c9on branchepbs-gloas.v1.46.0/aa8303e. All 4 operators use the same beacon node.glamsterdam-devnet-8image.Note: all 4 operators use one beacon node. Thus every operator builds the same block and the same
envelope, and every operator sends the block to the same beacon node. Only the first operator gets a
success answer.
Defect 1: BLOCK_ERROR_ALREADY_KNOWN stops the full task
All operators of the committee send the same reconstructed block. The beacon node accepts the first
block and answers
BLOCK_ERROR_ALREADY_KNOWNto the others. This answer is normal.Anchor treats this answer as
Irrecoverable:After this error there is no
Fetching execution payload envelopeline for slot 205, and Anchor doesnot join the envelope consensus instance of that slot.
The correlation is exact and opposite on the two Anchor nodes. One node stopped the task on slots 128,
134, 166, 175, 203 and 205, and did the envelope duty on slots 139, 143, 153, 202 and 217. The other
node did the opposite.
The Go SSV node treats
BLOCK_ERROR_ALREADY_KNOWNas a success on the Gloas path(
beacon/goclient/gloas_proposer.go). In the same window the beacon node gave this answer 172 times,and all Go SSV block proposals were a success.
What we expect
Treat
BLOCK_ERROR_ALREADY_KNOWNas a success. Continue with the envelope duty.Defect 2: the envelope request uses the local candidate root
Anchor asks for the envelope of the block root of its own candidate block:
The beacon node answers HTTP 404 for the root
0xfc43256b6aff....8 of the 12 envelope requests used a root that the beacon node does not know. The root was correct
only when an Anchor operator was the leader of the block proposal consensus (slots 128, 153, 205 and
217).
Lodestar writes the root of the request into the envelope that it gives:
All three envelopes have the same
blockHash=0x9327.... Thus the cached envelope of Anchor has adifferent root from the value that the committee decided. The content check then stops the
publication.
This is not an error of the root calculation. The partial signature of Anchor for the decided block
was a part of a valid signature in every block that the chain accepted, and also in the blocks where a
Go SSV operator was the leader.
What we expect
Ask for the envelope of the block root that the committee decided.
Defect 3 (small): the correct skip is also an error
Anchor has a correct message for the condition "another operator built the decided envelope":
But the same condition also gives an error message:
We counted 8 of these error messages. The blocks of those slots are on the chain. Please use only the
INFOmessage for this condition.Effect
In a committee with 2 Anchor operators and 2 Go SSV operators, the envelope duty completed 11 of 11.
The Anchor operator that won the block publication race always joined the instance, so the quorum of 3
was possible.
In a committee with 2 Anchor operators and 1 Go SSV operator, the envelope duty completed 0 of 4, and
all 4 blocks are empty on the chain.