mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-26 13:40:05 +00:00
Implement ProcessEth1Data (#6445)
Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#eth1-data Part of https://github.com/ledgerwatch/erigon/issues/5965
This commit is contained in:
parent
05f715ca51
commit
f0be116bc2
@ -18,6 +18,7 @@ const (
|
|||||||
EPOCHS_PER_HISTORICAL_VECTOR = uint64(1 << 16)
|
EPOCHS_PER_HISTORICAL_VECTOR = uint64(1 << 16)
|
||||||
MIN_SEED_LOOKAHEAD = uint64(1)
|
MIN_SEED_LOOKAHEAD = uint64(1)
|
||||||
SLOTS_PER_EPOCH = uint64(1 << 5)
|
SLOTS_PER_EPOCH = uint64(1 << 5)
|
||||||
|
EPOCHS_PER_ETH1_VOTING_PERIOD = uint64(1 << 6)
|
||||||
)
|
)
|
||||||
|
|
||||||
func ComputeShuffledIndex(ind, ind_count uint64, seed [32]byte) (uint64, error) {
|
func ComputeShuffledIndex(ind, ind_count uint64, seed [32]byte) (uint64, error) {
|
||||||
@ -240,3 +241,35 @@ func ProcessRandao(state *state.BeaconState, body *cltypes.BeaconBody) error {
|
|||||||
state.RandaoMixes()[epoch%EPOCHS_PER_HISTORICAL_VECTOR] = mix
|
state.RandaoMixes()[epoch%EPOCHS_PER_HISTORICAL_VECTOR] = mix
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ProcessEth1Data(state *state.BeaconState, body *cltypes.BeaconBody) error {
|
||||||
|
newVotes := append(state.Eth1DataVotes(), body.Eth1Data)
|
||||||
|
state.SetEth1DataVotes(newVotes)
|
||||||
|
|
||||||
|
ethDataHash, err := body.Eth1Data.HashTreeRoot()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to get hash tree root of eth1data: %v", err)
|
||||||
|
}
|
||||||
|
// Count how many times body.Eth1Data appears in the votes by comparing their hashes.
|
||||||
|
numVotes := 0
|
||||||
|
for i := 0; i < len(newVotes); i++ {
|
||||||
|
candidateHash, err := newVotes[i].HashTreeRoot()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to get hash tree root of eth1data: %v", err)
|
||||||
|
}
|
||||||
|
// Check if hash bytes are equal.
|
||||||
|
match := true
|
||||||
|
for i := 0; i < len(candidateHash); i++ {
|
||||||
|
if candidateHash[i] != ethDataHash[i] {
|
||||||
|
match = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if match {
|
||||||
|
numVotes += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if uint64(numVotes*2) > EPOCHS_PER_ETH1_VOTING_PERIOD*SLOTS_PER_EPOCH {
|
||||||
|
state.SetEth1Data(body.Eth1Data)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -415,3 +415,79 @@ func TestProcessRandao(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProcessEth1Data(t *testing.T) {
|
||||||
|
Eth1DataA := &cltypes.Eth1Data{
|
||||||
|
Root: [32]byte{1, 2, 3},
|
||||||
|
DepositCount: 42,
|
||||||
|
BlockHash: [32]byte{4, 5, 6},
|
||||||
|
}
|
||||||
|
eth1dataAHash, err := Eth1DataA.HashTreeRoot()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to hash expected eth1data: %v", err)
|
||||||
|
}
|
||||||
|
Eth1DataB := &cltypes.Eth1Data{
|
||||||
|
Root: [32]byte{3, 2, 1},
|
||||||
|
DepositCount: 43,
|
||||||
|
BlockHash: [32]byte{6, 5, 4},
|
||||||
|
}
|
||||||
|
eth1dataBHash, err := Eth1DataB.HashTreeRoot()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to hash expected eth1data: %v", err)
|
||||||
|
}
|
||||||
|
successState := state.FromBellatrixState(&cltypes.BeaconStateBellatrix{
|
||||||
|
Eth1DataVotes: []*cltypes.Eth1Data{},
|
||||||
|
Eth1Data: Eth1DataB,
|
||||||
|
})
|
||||||
|
// Fill all votes.
|
||||||
|
for i := 0; i < int(EPOCHS_PER_ETH1_VOTING_PERIOD)*int(SLOTS_PER_EPOCH)-1; i++ {
|
||||||
|
successState.SetEth1DataVotes(append(successState.Eth1DataVotes(), Eth1DataA))
|
||||||
|
}
|
||||||
|
successBody := &cltypes.BeaconBody{
|
||||||
|
Eth1Data: Eth1DataA,
|
||||||
|
}
|
||||||
|
|
||||||
|
noUpdateState := state.FromBellatrixState(&cltypes.BeaconStateBellatrix{
|
||||||
|
Eth1DataVotes: []*cltypes.Eth1Data{},
|
||||||
|
Eth1Data: Eth1DataB,
|
||||||
|
})
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
state *state.BeaconState
|
||||||
|
body *cltypes.BeaconBody
|
||||||
|
expectedHash [32]byte
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "success_update",
|
||||||
|
state: successState,
|
||||||
|
body: successBody,
|
||||||
|
expectedHash: eth1dataAHash,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "success_no_update",
|
||||||
|
state: noUpdateState,
|
||||||
|
body: successBody,
|
||||||
|
expectedHash: eth1dataBHash,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
err := ProcessEth1Data(tc.state, tc.body)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
gotEth1Data := tc.state.Eth1Data()
|
||||||
|
gotHash, err := gotEth1Data.HashTreeRoot()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to hash output eth1data: %v", err)
|
||||||
|
}
|
||||||
|
for i := 0; i < len(tc.expectedHash); i++ {
|
||||||
|
if gotHash[i] != tc.expectedHash[i] {
|
||||||
|
t.Errorf("unexpected output byte: got %x, want %x", gotHash[i], tc.expectedHash[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user