Update DepositRoot to Eth1Data (#1403)

* update proto fileds

* Start writing ProcessETH1Data function

* More progress on tests

* Continue more work on tests

* Fix almost all the tests

* Fix all tests

* Fix everything

* Fix after rebase

* Fix for suggestions and fix per-epoch operation

* Remove method usage

* Fix build

* Fix suggestions

* Fix merge issues and suggestions

* Fix rebase issues

* Remove the error from ProcessETH1Data

* WIP write test

* Update test to reach crosslinks

* Revert "Update test to reach crosslinks"

This reverts commit 5ff9177f96.

* Revert "WIP write test"

This reverts commit f7e7ed715c.
This commit is contained in:
Ivan Martinez
2019-02-02 16:24:42 -05:00
committed by Preston Van Loon
parent d06f5ac163
commit 5b209a2b18
19 changed files with 1106 additions and 676 deletions

View File

@@ -255,9 +255,12 @@ func TestRunningChainServiceFaultyPOWChain(t *testing.T) {
} }
block := &pb.BeaconBlock{ block := &pb.BeaconBlock{
Slot: 2, Slot: 2,
ParentRootHash32: parentHash[:], ParentRootHash32: parentHash[:],
DepositRootHash32: []byte("a"), Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte("a"),
BlockHash32: []byte("b"),
},
} }
exitRoutine := make(chan bool) exitRoutine := make(chan bool)
@@ -347,10 +350,13 @@ func TestRunningChainService(t *testing.T) {
attestationSlot := uint64(0) attestationSlot := uint64(0)
block := &pb.BeaconBlock{ block := &pb.BeaconBlock{
Slot: currentSlot + 1, Slot: currentSlot + 1,
StateRootHash32: stateRoot[:], StateRootHash32: stateRoot[:],
ParentRootHash32: parentHash[:], ParentRootHash32: parentHash[:],
DepositRootHash32: []byte("a"), Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte("a"),
BlockHash32: []byte("b"),
},
Body: &pb.BeaconBlockBody{ Body: &pb.BeaconBlockBody{
Attestations: []*pb.Attestation{{ Attestations: []*pb.Attestation{{
ParticipationBitfield: []byte{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ParticipationBitfield: []byte{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -402,7 +408,7 @@ func TestDoesPOWBlockExist(t *testing.T) {
} }
// Using a faulty client should throw error. // Using a faulty client should throw error.
powHash := bytesutil.ToBytes32(beaconState.LatestDepositRootHash32) powHash := bytesutil.ToBytes32(beaconState.LatestEth1Data.DepositRootHash32)
exists := chainService.doesPoWBlockExist(powHash) exists := chainService.doesPoWBlockExist(powHash)
if exists { if exists {
t.Error("Block corresponding to nil powchain reference should not exist") t.Error("Block corresponding to nil powchain reference should not exist")
@@ -465,10 +471,13 @@ func TestUpdateHead(t *testing.T) {
enc, _ := proto.Marshal(tt.state) enc, _ := proto.Marshal(tt.state)
stateRoot := hashutil.Hash(enc) stateRoot := hashutil.Hash(enc)
block := &pb.BeaconBlock{ block := &pb.BeaconBlock{
Slot: tt.blockSlot, Slot: tt.blockSlot,
StateRootHash32: stateRoot[:], StateRootHash32: stateRoot[:],
ParentRootHash32: genesisHash[:], ParentRootHash32: genesisHash[:],
DepositRootHash32: []byte("a"), Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte("a"),
BlockHash32: []byte("b"),
},
} }
if err := chainService.beaconDB.SaveBlock(block); err != nil { if err := chainService.beaconDB.SaveBlock(block); err != nil {
t.Fatal(err) t.Fatal(err)
@@ -527,18 +536,23 @@ func TestIsBlockReadyForProcessing(t *testing.T) {
t.Fatal("block processing succeeded despite block slot being invalid") t.Fatal("block processing succeeded despite block slot being invalid")
} }
h := bytesutil.ToBytes32([]byte("a")) beaconState.LatestEth1Data = &pb.Eth1Data{
beaconState.LatestDepositRootHash32 = h[:] DepositRootHash32: []byte{2},
BlockHash32: []byte{3},
}
beaconState.Slot = 0 beaconState.Slot = 0
currentSlot := uint64(1) currentSlot := uint64(1)
attestationSlot := uint64(0) attestationSlot := uint64(0)
block3 := &pb.BeaconBlock{ block3 := &pb.BeaconBlock{
Slot: currentSlot, Slot: currentSlot,
StateRootHash32: stateRoot[:], StateRootHash32: stateRoot[:],
ParentRootHash32: parentHash[:], ParentRootHash32: parentHash[:],
DepositRootHash32: []byte("a"), Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte("a"),
BlockHash32: []byte("b"),
},
Body: &pb.BeaconBlockBody{ Body: &pb.BeaconBlockBody{
Attestations: []*pb.Attestation{{ Attestations: []*pb.Attestation{{
ParticipationBitfield: []byte{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ParticipationBitfield: []byte{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

View File

@@ -37,6 +37,10 @@ func generateSimulatedBlock(
RandaoRevealHash32: randaoReveal[:], RandaoRevealHash32: randaoReveal[:],
ParentRootHash32: prevBlockRoot[:], ParentRootHash32: prevBlockRoot[:],
StateRootHash32: stateRoot[:], StateRootHash32: stateRoot[:],
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{1},
BlockHash32: []byte{2},
},
Body: &pb.BeaconBlockBody{ Body: &pb.BeaconBlockBody{
ProposerSlashings: []*pb.ProposerSlashing{}, ProposerSlashings: []*pb.ProposerSlashing{},
AttesterSlashings: []*pb.AttesterSlashing{}, AttesterSlashings: []*pb.AttesterSlashing{},

View File

@@ -234,7 +234,10 @@ func (sb *SimulatedBackend) RunStateTransitionTest(testCase *StateTestCase) erro
return fmt.Errorf("could not generate simulated beacon block %v", err) return fmt.Errorf("could not generate simulated beacon block %v", err)
} }
latestRoot := depositsTrie.Root() latestRoot := depositsTrie.Root()
beaconState.LatestDepositRootHash32 = latestRoot[:] beaconState.LatestEth1Data = &pb.Eth1Data{
DepositRootHash32: latestRoot[:],
BlockHash32: []byte{},
}
startTime := time.Now() startTime := time.Now()
newState, err := state.ExecuteStateTransition( newState, err := state.ExecuteStateTransition(

View File

@@ -35,36 +35,35 @@ func VerifyProposerSignature(
return nil return nil
} }
// ProcessDepositRoots processes the proof-of-work chain's receipts // ProcessEth1Data is an operation performed on each
// contained in a beacon block and appends them as candidate receipt roots // beacon block to ensure the ETH1 data votes are processed
// in the beacon state. // into the beacon state.
// //
// Official spec definition for processing deposit roots: // Official spec definition of ProcessEth1Data
// If block.deposit_root is deposit_root_vote.deposit_root // If block.eth1_data equals eth1_data_vote.eth1_data for some eth1_data_vote
// for some deposit_root_vote in state.deposit_root_votes, // in state.eth1_data_votes, set eth1_data_vote.vote_count += 1.
// set deposit_root_vote.vote_count += 1. // Otherwise, append to state.eth1_data_votes a new Eth1DataVote(eth1_data=block.eth1_data, vote_count=1).
// Otherwise, append to state.deposit_root_votes a func ProcessEth1Data(beaconState *pb.BeaconState, block *pb.BeaconBlock) *pb.BeaconState {
// new DepositRootVote( var eth1DataVoteAdded bool
// deposit_root=block.deposit_root,
// vote_count=1 for _, Eth1DataVote := range beaconState.Eth1DataVotes {
// ) if bytes.Equal(Eth1DataVote.Eth1Data.BlockHash32, block.Eth1Data.BlockHash32) && bytes.Equal(Eth1DataVote.Eth1Data.DepositRootHash32, block.Eth1Data.DepositRootHash32) {
func ProcessDepositRoots( Eth1DataVote.VoteCount++
beaconState *pb.BeaconState, eth1DataVoteAdded = true
block *pb.BeaconBlock, break
) *pb.BeaconState {
var newCandidateReceiptRoots []*pb.DepositRootVote
currentCandidateReceiptRoots := beaconState.DepositRootVotes
for idx, root := range currentCandidateReceiptRoots {
if bytes.Equal(block.DepositRootHash32, root.DepositRootHash32) {
currentCandidateReceiptRoots[idx].VoteCount++
} else {
newCandidateReceiptRoots = append(newCandidateReceiptRoots, &pb.DepositRootVote{
DepositRootHash32: block.DepositRootHash32,
VoteCount: 1,
})
} }
} }
beaconState.DepositRootVotes = append(currentCandidateReceiptRoots, newCandidateReceiptRoots...)
if !eth1DataVoteAdded {
beaconState.Eth1DataVotes = append(
beaconState.Eth1DataVotes,
&pb.Eth1DataVote{
Eth1Data: block.Eth1Data,
VoteCount: 1,
},
)
}
return beaconState return beaconState
} }
@@ -623,7 +622,7 @@ func ProcessValidatorDeposits(
func verifyDeposit(beaconState *pb.BeaconState, deposit *pb.Deposit) error { func verifyDeposit(beaconState *pb.BeaconState, deposit *pb.Deposit) error {
// Verify Merkle proof of deposit and deposit trie root. // Verify Merkle proof of deposit and deposit trie root.
receiptRoot := bytesutil.ToBytes32(beaconState.LatestDepositRootHash32) receiptRoot := bytesutil.ToBytes32(beaconState.LatestEth1Data.DepositRootHash32)
if ok := trieutil.VerifyMerkleBranch( if ok := trieutil.VerifyMerkleBranch(
hashutil.Hash(deposit.DepositData), hashutil.Hash(deposit.DepositData),
deposit.MerkleBranchHash32S, deposit.MerkleBranchHash32S,

View File

@@ -15,57 +15,6 @@ import (
"github.com/prysmaticlabs/prysm/shared/trieutil" "github.com/prysmaticlabs/prysm/shared/trieutil"
) )
func TestProcessPOWReceiptRoots_SameRootHash(t *testing.T) {
beaconState := &pb.BeaconState{
DepositRootVotes: []*pb.DepositRootVote{
{
DepositRootHash32: []byte{1},
VoteCount: 5,
},
},
}
block := &pb.BeaconBlock{
DepositRootHash32: []byte{1},
}
beaconState = ProcessDepositRoots(beaconState, block)
newRoots := beaconState.DepositRootVotes
if newRoots[0].VoteCount != 6 {
t.Errorf("expected votes to increase from 5 to 6, received %d", newRoots[0].VoteCount)
}
}
func TestProcessPOWReceiptRoots_NewCandidateRecord(t *testing.T) {
beaconState := &pb.BeaconState{
DepositRootVotes: []*pb.DepositRootVote{
{
DepositRootHash32: []byte{0},
VoteCount: 5,
},
},
}
block := &pb.BeaconBlock{
DepositRootHash32: []byte{1},
}
beaconState = ProcessDepositRoots(beaconState, block)
newRoots := beaconState.DepositRootVotes
if len(newRoots) == 1 {
t.Error("expected new receipt roots to have length > 1")
}
if newRoots[1].VoteCount != 1 {
t.Errorf(
"expected new receipt roots to have a new element with votes = 1, received votes = %d",
newRoots[1].VoteCount,
)
}
if !bytes.Equal(newRoots[1].DepositRootHash32, []byte{1}) {
t.Errorf(
"expected new receipt roots to have a new element with root = %#x, received root = %#x",
[]byte{1},
newRoots[1].DepositRootHash32,
)
}
}
func TestProcessBlockRandao_UnequalBlockAndProposerRandao(t *testing.T) { func TestProcessBlockRandao_UnequalBlockAndProposerRandao(t *testing.T) {
validators := make([]*pb.ValidatorRecord, config.EpochLength*2) validators := make([]*pb.ValidatorRecord, config.EpochLength*2)
for i := 0; i < len(validators); i++ { for i := 0; i < len(validators); i++ {
@@ -136,6 +85,71 @@ func TestProcessBlockRandao_CreateRandaoMixAndUpdateProposer(t *testing.T) {
} }
} }
func TestProcessEth1Data_SameRootHash(t *testing.T) {
beaconState := &pb.BeaconState{
Eth1DataVotes: []*pb.Eth1DataVote{
&pb.Eth1DataVote{
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{1},
BlockHash32: []byte{2},
},
VoteCount: 5,
},
},
}
block := &pb.BeaconBlock{
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{1},
BlockHash32: []byte{2},
},
}
beaconState = ProcessEth1Data(beaconState, block)
newETH1DataVotes := beaconState.Eth1DataVotes
if newETH1DataVotes[0].VoteCount != 6 {
t.Errorf("expected votes to increase from 5 to 6, received %d", newETH1DataVotes[0].VoteCount)
}
}
func TestProcessEth1Data_NewDepositRootHash(t *testing.T) {
beaconState := &pb.BeaconState{
Eth1DataVotes: []*pb.Eth1DataVote{
&pb.Eth1DataVote{
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{0},
BlockHash32: []byte{1},
},
VoteCount: 5,
},
},
}
block := &pb.BeaconBlock{
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{2},
BlockHash32: []byte{3},
},
}
beaconState = ProcessEth1Data(beaconState, block)
newETH1DataVotes := beaconState.Eth1DataVotes
if len(newETH1DataVotes) <= 1 {
t.Error("expected new ETH1 data votes to have length > 1")
}
if newETH1DataVotes[1].VoteCount != 1 {
t.Errorf(
"expected new ETH1 data votes to have a new element with votes = 1, received votes = %d",
newETH1DataVotes[1].VoteCount,
)
}
if !bytes.Equal(newETH1DataVotes[1].Eth1Data.DepositRootHash32, []byte{2}) {
t.Errorf(
"expected new ETH1 data votes to have a new element with deposit root = %#x, received deposit root = %#x",
[]byte{1},
newETH1DataVotes[1].Eth1Data.DepositRootHash32,
)
}
}
func TestProcessProposerSlashings_ThresholdReached(t *testing.T) { func TestProcessProposerSlashings_ThresholdReached(t *testing.T) {
slashings := make([]*pb.ProposerSlashing, config.MaxProposerSlashings+1) slashings := make([]*pb.ProposerSlashing, config.MaxProposerSlashings+1)
registry := []*pb.ValidatorRecord{} registry := []*pb.ValidatorRecord{}
@@ -1190,7 +1204,10 @@ func TestProcessValidatorDeposits_MerkleBranchFailsVerification(t *testing.T) {
}, },
} }
beaconState := &pb.BeaconState{ beaconState := &pb.BeaconState{
LatestDepositRootHash32: []byte{}, LatestEth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{0},
BlockHash32: []byte{1},
},
} }
want := "merkle branch of deposit root did not verify" want := "merkle branch of deposit root did not verify"
if _, err := ProcessValidatorDeposits( if _, err := ProcessValidatorDeposits(
@@ -1267,11 +1284,14 @@ func TestProcessValidatorDeposits_ProcessDepositHelperFuncFails(t *testing.T) {
balances := []uint64{0} balances := []uint64{0}
root := depositTrie.Root() root := depositTrie.Root()
beaconState := &pb.BeaconState{ beaconState := &pb.BeaconState{
ValidatorRegistry: registry, ValidatorRegistry: registry,
ValidatorBalances: balances, ValidatorBalances: balances,
LatestDepositRootHash32: root[:], LatestEth1Data: &pb.Eth1Data{
Slot: currentSlot, DepositRootHash32: root[:],
GenesisTime: uint64(genesisTime), BlockHash32: root[:],
},
Slot: currentSlot,
GenesisTime: uint64(genesisTime),
} }
want := "expected withdrawal credentials to match" want := "expected withdrawal credentials to match"
if _, err := ProcessValidatorDeposits( if _, err := ProcessValidatorDeposits(
@@ -1344,11 +1364,14 @@ func TestProcessValidatorDeposits_ProcessCorrectly(t *testing.T) {
balances := []uint64{0} balances := []uint64{0}
root := depositTrie.Root() root := depositTrie.Root()
beaconState := &pb.BeaconState{ beaconState := &pb.BeaconState{
ValidatorRegistry: registry, ValidatorRegistry: registry,
ValidatorBalances: balances, ValidatorBalances: balances,
LatestDepositRootHash32: root[:], LatestEth1Data: &pb.Eth1Data{
Slot: currentSlot, DepositRootHash32: root[:],
GenesisTime: uint64(genesisTime), BlockHash32: root[:],
},
Slot: currentSlot,
GenesisTime: uint64(genesisTime),
} }
newState, err := ProcessValidatorDeposits( newState, err := ProcessValidatorDeposits(
beaconState, beaconState,

View File

@@ -47,7 +47,7 @@ func IsValidBlock(
} }
if enablePOWChain { if enablePOWChain {
h := common.BytesToHash(state.LatestDepositRootHash32) h := common.BytesToHash(state.LatestEth1Data.DepositRootHash32)
powBlock, err := GetPOWBlock(ctx, h) powBlock, err := GetPOWBlock(ctx, h)
if err != nil { if err != nil {
return fmt.Errorf("unable to retrieve POW chain reference block %v", err) return fmt.Errorf("unable to retrieve POW chain reference block %v", err)
@@ -57,7 +57,7 @@ func IsValidBlock(
// The block pointed to by the state in state.processed_pow_receipt_root has // The block pointed to by the state in state.processed_pow_receipt_root has
// been processed in the ETH 1.0 chain. // been processed in the ETH 1.0 chain.
if powBlock == nil { if powBlock == nil {
return fmt.Errorf("proof-of-Work chain reference in state does not exist %#x", state.LatestDepositRootHash32) return fmt.Errorf("proof-of-Work chain reference in state does not exist %#x", state.LatestEth1Data.DepositRootHash32)
} }
} }

View File

@@ -74,6 +74,10 @@ func TestBadBlock(t *testing.T) {
block.Slot = 4 block.Slot = 4
powClient.blockExists = false powClient.blockExists = false
beaconState.LatestEth1Data = &pb.Eth1Data{
DepositRootHash32: []byte{2},
BlockHash32: []byte{3},
}
if err := IsValidBlock(ctx, beaconState, block, true, if err := IsValidBlock(ctx, beaconState, block, true,
db.HasBlock, powClient.BlockByHash, genesisTime); err == nil { db.HasBlock, powClient.BlockByHash, genesisTime); err == nil {
@@ -107,9 +111,13 @@ func TestValidBlock(t *testing.T) {
genesisTime := params.BeaconConfig().GenesisTime genesisTime := params.BeaconConfig().GenesisTime
powClient.blockExists = true powClient.blockExists = true
beaconState.LatestEth1Data = &pb.Eth1Data{
DepositRootHash32: []byte{2},
BlockHash32: []byte{3},
}
if err := IsValidBlock(ctx, beaconState, block, true, if err := IsValidBlock(ctx, beaconState, block, true,
db.HasBlock, powClient.BlockByHash, genesisTime); err != nil { db.HasBlock, powClient.BlockByHash, genesisTime); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }

View File

@@ -25,13 +25,13 @@ func CanProcessEpoch(state *pb.BeaconState) bool {
return state.Slot%config.EpochLength == 0 return state.Slot%config.EpochLength == 0
} }
// CanProcessDepositRoots checks the eligibility to process deposit root. // CanProcessEth1Data checks the eligibility to process the eth1 data.
// The deposit root can be processed every DEPOSIT_ROOT_VOTING_PERIOD. // The eth1 data can be processed every ETH1_DATA_VOTING_PERIOD.
// //
// Spec pseudocode definition: // Spec pseudocode definition:
// If state.slot % DEPOSIT_ROOT_VOTING_PERIOD == 0: // If state.slot % ETH1_DATA_VOTING_PERIOD == 0:
func CanProcessDepositRoots(state *pb.BeaconState) bool { func CanProcessEth1Data(state *pb.BeaconState) bool {
return state.Slot%config.DepositRootVotingPeriod == 0 return state.Slot%config.Eth1DataVotingPeriod == 0
} }
// CanProcessValidatorRegistry checks the eligibility to process validator registry. // CanProcessValidatorRegistry checks the eligibility to process validator registry.
@@ -61,16 +61,27 @@ func CanProcessValidatorRegistry(state *pb.BeaconState) bool {
return true return true
} }
// ProcessDeposits processes deposit roots by checking its vote count. // ProcessEth1Data processes eth1 block deposit roots by checking its vote count.
// With sufficient votes (>2*DEPOSIT_ROOT_VOTING_PERIOD), it then // With sufficient votes (>2*ETH1_DATA_VOTING_PERIOD), it then
// assigns root hash to processed receipt vote in state. // marks the voted Eth1 data as the latest data set.
func ProcessDeposits(state *pb.BeaconState) *pb.BeaconState { //
for _, receiptRoot := range state.DepositRootVotes { // Official spec definition:
if receiptRoot.VoteCount*2 > config.DepositRootVotingPeriod { // if state.slot % ETH1_DATA_VOTING_PERIOD == 0:
state.LatestDepositRootHash32 = receiptRoot.DepositRootHash32 // Set state.latest_eth1_data = eth1_data_vote.data
// if eth1_data_vote.vote_count * 2 > ETH1_DATA_VOTING_PERIOD for
// some eth1_data_vote in state.eth1_data_votes.
// Set state.eth1_data_votes = [].
//
func ProcessEth1Data(state *pb.BeaconState) *pb.BeaconState {
if state.Slot%config.Eth1DataVotingPeriod == 0 {
for _, eth1DataVote := range state.Eth1DataVotes {
if eth1DataVote.VoteCount*2 > config.Eth1DataVotingPeriod {
state.LatestEth1Data.DepositRootHash32 = eth1DataVote.Eth1Data.DepositRootHash32
state.LatestEth1Data.BlockHash32 = eth1DataVote.Eth1Data.BlockHash32
}
} }
state.Eth1DataVotes = make([]*pb.Eth1DataVote, 0)
} }
state.DepositRootVotes = make([]*pb.DepositRootVote, 0)
return state return state
} }

View File

@@ -51,78 +51,152 @@ func TestCanProcessEpoch(t *testing.T) {
} }
} }
func TestCanProcessReceiptRoots(t *testing.T) { func TestCanProcessEth1Data(t *testing.T) {
if config.DepositRootVotingPeriod != 1024 { if config.Eth1DataVotingPeriod != 1024 {
t.Errorf("PowReceiptRootVotingPeriod should be 1024 for these tests to pass") t.Errorf("Eth1DataVotingPeriod should be 1024 for these tests to pass")
} }
tests := []struct { tests := []struct {
slot uint64 slot uint64
canProcessReceiptRoots bool canProcessEth1Data bool
}{ }{
{ {
slot: 1, slot: 1,
canProcessReceiptRoots: false, canProcessEth1Data: false,
}, },
{ {
slot: 1022, slot: 1022,
canProcessReceiptRoots: false, canProcessEth1Data: false,
}, },
{ {
slot: 1024, slot: 1024,
canProcessReceiptRoots: true, canProcessEth1Data: true,
}, { },
slot: 4096, {
canProcessReceiptRoots: true, slot: 4096,
}, { canProcessEth1Data: true,
slot: 234234, },
canProcessReceiptRoots: false, {
slot: 234234,
canProcessEth1Data: false,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
state := &pb.BeaconState{Slot: tt.slot} state := &pb.BeaconState{Slot: tt.slot}
if CanProcessDepositRoots(state) != tt.canProcessReceiptRoots { if CanProcessEth1Data(state) != tt.canProcessEth1Data {
t.Errorf( t.Errorf(
"CanProcessReceiptRoots(%d) = %v. Wanted %v", "CanProcessEth1Data(%d) = %v. Wanted %v",
tt.slot, tt.slot,
CanProcessDepositRoots(state), CanProcessEth1Data(state),
tt.canProcessReceiptRoots, tt.canProcessEth1Data,
) )
} }
} }
} }
func TestProcessReceipt(t *testing.T) { func TestProcessEth1Data(t *testing.T) {
if config.DepositRootVotingPeriod != 1024 { if config.Eth1DataVotingPeriod != 1024 {
t.Errorf("PowReceiptRootVotingPeriod should be 1024 for these tests to pass") t.Errorf("Eth1DataVotingPeriod should be 1024 for these tests to pass")
} }
requiredVoteCount := config.DepositRootVotingPeriod requiredVoteCount := config.Eth1DataVotingPeriod
state := &pb.BeaconState{ state := &pb.BeaconState{
DepositRootVotes: []*pb.DepositRootVote{ LatestEth1Data: &pb.Eth1Data{
{VoteCount: 0, DepositRootHash32: []byte{'A'}}, DepositRootHash32: nil,
BlockHash32: nil,
},
Eth1DataVotes: []*pb.Eth1DataVote{
{
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{'A'},
BlockHash32: []byte{'B'},
},
VoteCount: 0,
},
// DepositRootHash32 ['B'] gets to process with sufficient vote count. // DepositRootHash32 ['B'] gets to process with sufficient vote count.
{VoteCount: requiredVoteCount/2 + 1, DepositRootHash32: []byte{'B'}}, {
{VoteCount: requiredVoteCount / 2, DepositRootHash32: []byte{'C'}}, Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{'C'},
BlockHash32: []byte{'D'},
},
VoteCount: requiredVoteCount/2 + 1,
},
{
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{'E'},
BlockHash32: []byte{'F'},
},
VoteCount: requiredVoteCount / 2,
},
}, },
} }
newState := ProcessDeposits(state) newState := ProcessEth1Data(state)
if !bytes.Equal(newState.LatestDepositRootHash32, []byte{'B'}) { if !bytes.Equal(newState.LatestEth1Data.DepositRootHash32, []byte{'C'}) {
t.Errorf("Incorrect LatestDepositRootHash32. Wanted: %v, got: %v", t.Errorf("Incorrect DepositRootHash32. Wanted: %v, got: %v",
[]byte{'B'}, newState.LatestDepositRootHash32) []byte{'C'}, newState.LatestEth1Data.DepositRootHash32)
} }
// Adding a new receipt root ['D'] which should be the new processed receipt root. // Adding a new receipt root ['D'] which should be the new processed receipt root.
state.DepositRootVotes = append(state.DepositRootVotes, state.Eth1DataVotes = append(state.Eth1DataVotes,
&pb.DepositRootVote{VoteCount: requiredVoteCount, &pb.Eth1DataVote{
DepositRootHash32: []byte{'D'}}) Eth1Data: &pb.Eth1Data{
newState = ProcessDeposits(state) DepositRootHash32: []byte{'G'},
if !bytes.Equal(newState.LatestDepositRootHash32, []byte{'D'}) { BlockHash32: []byte{'H'},
t.Errorf("Incorrect LatestDepositRootHash32. Wanted: %v, got: %v", },
[]byte{'D'}, newState.LatestDepositRootHash32) VoteCount: requiredVoteCount,
},
)
newState = ProcessEth1Data(state)
if !bytes.Equal(newState.LatestEth1Data.DepositRootHash32, []byte{'G'}) {
t.Errorf("Incorrect DepositRootHash32. Wanted: %v, got: %v",
[]byte{'G'}, newState.LatestEth1Data.DepositRootHash32)
} }
if len(newState.DepositRootVotes) != 0 { if len(newState.Eth1DataVotes) != 0 {
t.Errorf("Failed to clean up DepositRootVotes slice. Length: %d", t.Errorf("Failed to clean up Eth1DataVotes slice. Length: %d",
len(newState.DepositRootVotes)) len(newState.Eth1DataVotes))
}
}
func TestProcessEth1Data_InactionSlot(t *testing.T) {
if config.Eth1DataVotingPeriod != 1024 {
t.Errorf("Eth1DataVotingPeriod should be 1024 for these tests to pass")
}
requiredVoteCount := config.Eth1DataVotingPeriod
state := &pb.BeaconState{
Slot: 4,
LatestEth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{'A'},
BlockHash32: []byte{'B'},
},
Eth1DataVotes: []*pb.Eth1DataVote{
{
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{'C'},
BlockHash32: []byte{'D'},
},
VoteCount: requiredVoteCount/2 + 1,
},
{
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{'E'},
BlockHash32: []byte{'F'},
},
VoteCount: requiredVoteCount / 2,
},
{
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{'G'},
BlockHash32: []byte{'H'},
},
VoteCount: requiredVoteCount,
},
},
}
// Adding a new receipt root ['D'] which should be the new processed receipt root.
newState := ProcessEth1Data(state)
if !bytes.Equal(newState.LatestEth1Data.DepositRootHash32, []byte{'A'}) {
t.Errorf("Incorrect DepositRootHash32. Wanted: %v, got: %v",
[]byte{'A'}, newState.LatestEth1Data.DepositRootHash32)
} }
} }

View File

@@ -119,9 +119,12 @@ func InitialBeaconState(
LatestAttestations: []*pb.PendingAttestationRecord{}, LatestAttestations: []*pb.PendingAttestationRecord{},
BatchedBlockRootHash32S: [][]byte{}, BatchedBlockRootHash32S: [][]byte{},
// deposit root. // Eth1 data.
LatestDepositRootHash32: processedPowReceiptRoot, LatestEth1Data: &pb.Eth1Data{
DepositRootVotes: []*pb.DepositRootVote{}, DepositRootHash32: processedPowReceiptRoot,
BlockHash32: []byte{},
},
Eth1DataVotes: []*pb.Eth1DataVote{},
} }
// Process initial deposits. // Process initial deposits.

View File

@@ -150,11 +150,11 @@ func TestInitialBeaconState_Ok(t *testing.T) {
} }
// deposit root checks. // deposit root checks.
if !bytes.Equal(state.LatestDepositRootHash32, processedPowReceiptRoot) { if !bytes.Equal(state.LatestEth1Data.DepositRootHash32, processedPowReceiptRoot) {
t.Error("LatestDepositRootHash32 was not correctly initialized") t.Error("LatestEth1Data DepositRootHash32 was not correctly initialized")
} }
if !reflect.DeepEqual(state.DepositRootVotes, []*pb.DepositRootVote{}) { if !reflect.DeepEqual(state.Eth1DataVotes, []*pb.Eth1DataVote{}) {
t.Error("DepositRootVotes was not correctly initialized") t.Error("Eth1DataVotes was not correctly initialized")
} }
} }

View File

@@ -74,7 +74,6 @@ func ProcessBlock(state *pb.BeaconState, block *pb.BeaconBlock, verifySignatures
} }
} }
var err error var err error
state = b.ProcessDepositRoots(state, block)
state, err = b.ProcessBlockRandao(state, block) state, err = b.ProcessBlockRandao(state, block)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not verify and process block randao: %v", err) return nil, fmt.Errorf("could not verify and process block randao: %v", err)
@@ -83,6 +82,7 @@ func ProcessBlock(state *pb.BeaconState, block *pb.BeaconBlock, verifySignatures
if err != nil { if err != nil {
return nil, fmt.Errorf("could not verify block proposer slashings: %v", err) return nil, fmt.Errorf("could not verify block proposer slashings: %v", err)
} }
state = b.ProcessEth1Data(state, block)
state, err = b.ProcessAttesterSlashings(state, block, verifySignatures) state, err = b.ProcessAttesterSlashings(state, block, verifySignatures)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not verify block attester slashings: %v", err) return nil, fmt.Errorf("could not verify block attester slashings: %v", err)
@@ -175,9 +175,9 @@ func ProcessEpoch(state *pb.BeaconState) (*pb.BeaconState, error) {
} }
prevHeadAttestingBalances := e.TotalBalance(state, prevHeadAttesterIndices) prevHeadAttestingBalances := e.TotalBalance(state, prevHeadAttesterIndices)
// Process receipt roots. // Process eth1 data
if e.CanProcessDepositRoots(state) { if e.CanProcessEth1Data(state) {
e.ProcessDeposits(state) state = e.ProcessEth1Data(state)
} }
// Update justification. // Update justification.

View File

@@ -58,6 +58,10 @@ func TestProcessBlock_IncorrectProposerSlashing(t *testing.T) {
block := &pb.BeaconBlock{ block := &pb.BeaconBlock{
Slot: 5, Slot: 5,
RandaoRevealHash32: []byte{}, RandaoRevealHash32: []byte{},
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{2},
BlockHash32: []byte{3},
},
Body: &pb.BeaconBlockBody{ Body: &pb.BeaconBlockBody{
ProposerSlashings: slashings, ProposerSlashings: slashings,
}, },
@@ -96,6 +100,10 @@ func TestProcessBlock_IncorrectAttesterSlashing(t *testing.T) {
block := &pb.BeaconBlock{ block := &pb.BeaconBlock{
Slot: 5, Slot: 5,
RandaoRevealHash32: []byte{}, RandaoRevealHash32: []byte{},
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{2},
BlockHash32: []byte{3},
},
Body: &pb.BeaconBlockBody{ Body: &pb.BeaconBlockBody{
ProposerSlashings: slashings, ProposerSlashings: slashings,
AttesterSlashings: attesterSlashings, AttesterSlashings: attesterSlashings,
@@ -157,6 +165,10 @@ func TestProcessBlock_IncorrectProcessBlockAttestations(t *testing.T) {
block := &pb.BeaconBlock{ block := &pb.BeaconBlock{
Slot: 5, Slot: 5,
RandaoRevealHash32: []byte{}, RandaoRevealHash32: []byte{},
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{2},
BlockHash32: []byte{3},
},
Body: &pb.BeaconBlockBody{ Body: &pb.BeaconBlockBody{
ProposerSlashings: proposerSlashings, ProposerSlashings: proposerSlashings,
AttesterSlashings: attesterSlashings, AttesterSlashings: attesterSlashings,
@@ -243,6 +255,10 @@ func TestProcessBlock_IncorrectProcessExits(t *testing.T) {
block := &pb.BeaconBlock{ block := &pb.BeaconBlock{
Slot: 64, Slot: 64,
RandaoRevealHash32: []byte{}, RandaoRevealHash32: []byte{},
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{2},
BlockHash32: []byte{3},
},
Body: &pb.BeaconBlockBody{ Body: &pb.BeaconBlockBody{
ProposerSlashings: proposerSlashings, ProposerSlashings: proposerSlashings,
AttesterSlashings: attesterSlashings, AttesterSlashings: attesterSlashings,
@@ -335,6 +351,10 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
block := &pb.BeaconBlock{ block := &pb.BeaconBlock{
Slot: 64, Slot: 64,
RandaoRevealHash32: []byte{}, RandaoRevealHash32: []byte{},
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{2},
BlockHash32: []byte{3},
},
Body: &pb.BeaconBlockBody{ Body: &pb.BeaconBlockBody{
ProposerSlashings: proposerSlashings, ProposerSlashings: proposerSlashings,
AttesterSlashings: attesterSlashings, AttesterSlashings: attesterSlashings,

View File

@@ -7,6 +7,7 @@ package validators
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/bytesutil"

View File

@@ -83,10 +83,13 @@ func TestSetBlockForInitialSync(t *testing.T) {
genericHash[0] = 'a' genericHash[0] = 'a'
block := &pb.BeaconBlock{ block := &pb.BeaconBlock{
DepositRootHash32: []byte{1, 2, 3}, Eth1Data: &pb.Eth1Data{
ParentRootHash32: genericHash, DepositRootHash32: []byte{1, 2, 3},
Slot: uint64(1), BlockHash32: []byte{4, 5, 6},
StateRootHash32: genericHash, },
ParentRootHash32: genericHash,
Slot: uint64(1),
StateRootHash32: genericHash,
} }
blockResponse := &pb.BeaconBlockResponse{Block: block} blockResponse := &pb.BeaconBlockResponse{Block: block}
@@ -163,10 +166,13 @@ func TestSavingBlocksInSync(t *testing.T) {
getBlockResponseMsg := func(Slot uint64) p2p.Message { getBlockResponseMsg := func(Slot uint64) p2p.Message {
block := &pb.BeaconBlock{ block := &pb.BeaconBlock{
DepositRootHash32: []byte{1, 2, 3}, Eth1Data: &pb.Eth1Data{
ParentRootHash32: genericHash, DepositRootHash32: []byte{1, 2, 3},
Slot: Slot, BlockHash32: []byte{4, 5, 6},
StateRootHash32: beaconStateRootHash32[:], },
ParentRootHash32: genericHash,
Slot: Slot,
StateRootHash32: beaconStateRootHash32[:],
} }
blockResponse := &pb.BeaconBlockResponse{ blockResponse := &pb.BeaconBlockResponse{
@@ -273,10 +279,13 @@ func TestDelayChan(t *testing.T) {
beaconStateRootHash32 := hashutil.Hash(enc) beaconStateRootHash32 := hashutil.Hash(enc)
block := &pb.BeaconBlock{ block := &pb.BeaconBlock{
DepositRootHash32: []byte{1, 2, 3}, Eth1Data: &pb.Eth1Data{
ParentRootHash32: genericHash, DepositRootHash32: []byte{1, 2, 3},
Slot: uint64(1), BlockHash32: []byte{4, 5, 6},
StateRootHash32: beaconStateRootHash32[:], },
ParentRootHash32: genericHash,
Slot: uint64(1),
StateRootHash32: beaconStateRootHash32[:],
} }
blockResponse := &pb.BeaconBlockResponse{ blockResponse := &pb.BeaconBlockResponse{
@@ -353,10 +362,13 @@ func TestRequestBlocksBySlot(t *testing.T) {
getBlockResponseMsg := func(Slot uint64) (p2p.Message, [32]byte) { getBlockResponseMsg := func(Slot uint64) (p2p.Message, [32]byte) {
block := &pb.BeaconBlock{ block := &pb.BeaconBlock{
DepositRootHash32: []byte{1, 2, 3}, Eth1Data: &pb.Eth1Data{
ParentRootHash32: genericHash, DepositRootHash32: []byte{1, 2, 3},
Slot: Slot, BlockHash32: []byte{4, 5, 6},
StateRootHash32: nil, },
ParentRootHash32: genericHash,
Slot: Slot,
StateRootHash32: nil,
} }
blockResponse := &pb.BeaconBlockResponse{ blockResponse := &pb.BeaconBlockResponse{

View File

@@ -155,9 +155,12 @@ func TestProcessBlock(t *testing.T) {
} }
data := &pb.BeaconBlock{ data := &pb.BeaconBlock{
DepositRootHash32: []byte{1, 2, 3, 4, 5}, Eth1Data: &pb.Eth1Data{
ParentRootHash32: parentHash[:], DepositRootHash32: []byte{1, 2, 3, 4, 5},
Slot: 1, BlockHash32: []byte{6, 7, 8, 9, 10},
},
ParentRootHash32: parentHash[:],
Slot: 1,
} }
attestation := &pb.Attestation{ attestation := &pb.Attestation{
Data: &pb.AttestationData{ Data: &pb.AttestationData{
@@ -235,9 +238,12 @@ func TestProcessMultipleBlocks(t *testing.T) {
} }
data1 := &pb.BeaconBlock{ data1 := &pb.BeaconBlock{
DepositRootHash32: []byte{1, 2, 3, 4, 5}, Eth1Data: &pb.Eth1Data{
ParentRootHash32: parentHash[:], DepositRootHash32: []byte{1, 2, 3, 4, 5},
Slot: 1, BlockHash32: []byte{6, 7, 8, 9, 10},
},
ParentRootHash32: parentHash[:],
Slot: 1,
} }
responseBlock1 := &pb.BeaconBlockResponse{ responseBlock1 := &pb.BeaconBlockResponse{
@@ -258,9 +264,12 @@ func TestProcessMultipleBlocks(t *testing.T) {
} }
data2 := &pb.BeaconBlock{ data2 := &pb.BeaconBlock{
DepositRootHash32: []byte{6, 7, 8, 9, 10}, Eth1Data: &pb.Eth1Data{
ParentRootHash32: []byte{}, DepositRootHash32: []byte{11, 12, 13, 14, 15},
Slot: 1, BlockHash32: []byte{16, 17, 18, 19, 20},
},
ParentRootHash32: []byte{},
Slot: 1,
} }
responseBlock2 := &pb.BeaconBlockResponse{ responseBlock2 := &pb.BeaconBlockResponse{

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@ package ethereum.beacon.p2p.v1;
import "proto/common/messages.proto"; import "proto/common/messages.proto";
message BeaconState { message BeaconState {
// Validator registry [1-1000] // Validator registry [1-1000]
repeated ValidatorRecord validator_registry = 1; repeated ValidatorRecord validator_registry = 1;
uint64 validator_registry_update_slot = 2; uint64 validator_registry_update_slot = 2;
bytes validator_registry_delta_chain_tip_hash32 = 3; bytes validator_registry_delta_chain_tip_hash32 = 3;
@@ -20,7 +20,7 @@ message BeaconState {
bytes previous_epoch_seed_hash32 = 1009; bytes previous_epoch_seed_hash32 = 1009;
bytes current_epoch_seed_hash32 = 1010; bytes current_epoch_seed_hash32 = 1010;
// Finality [2001-3000] // Finality [2001-3000]
uint64 previous_justified_slot = 2001; uint64 previous_justified_slot = 2001;
uint64 justified_slot = 2002; uint64 justified_slot = 2002;
uint64 justification_bitfield = 2003; uint64 justification_bitfield = 2003;
@@ -34,9 +34,9 @@ message BeaconState {
repeated PendingAttestationRecord latest_attestations = 3006; repeated PendingAttestationRecord latest_attestations = 3006;
repeated bytes latest_index_root_hash32s = 3007; repeated bytes latest_index_root_hash32s = 3007;
// Ethereum 1.0 deposit root [4001-5000] // Ethereum 1.0 chain data [4001-5000]
bytes latest_deposit_root_hash32 = 4001; Eth1Data latest_eth1_data = 4001;
repeated DepositRootVote deposit_root_votes = 4002; repeated Eth1DataVote eth1_data_votes = 4002;
// Miscellaneous [5001-6000] // Miscellaneous [5001-6000]
uint64 genesis_time = 5001; uint64 genesis_time = 5001;
@@ -50,11 +50,6 @@ message Fork {
uint64 slot = 3; uint64 slot = 3;
} }
message DepositRootVote {
bytes deposit_root_hash32 = 1;
uint64 vote_count = 2;
}
message PendingAttestationRecord { message PendingAttestationRecord {
AttestationData data = 1; AttestationData data = 1;
bytes participation_bitfield = 2; bytes participation_bitfield = 2;
@@ -126,7 +121,7 @@ message BeaconBlock {
bytes parent_root_hash32 = 2; bytes parent_root_hash32 = 2;
bytes state_root_hash32 = 3; bytes state_root_hash32 = 3;
bytes randao_reveal_hash32 = 4; bytes randao_reveal_hash32 = 4;
bytes deposit_root_hash32 = 5; Eth1Data eth1_data = 5;
repeated bytes signature = 6; // Type of [uint384]? repeated bytes signature = 6; // Type of [uint384]?
// Block Body // Block Body
@@ -205,3 +200,13 @@ message ValidatorRegistryDeltaBlock {
} }
ValidatorRegistryDeltaFlags flag = 5; ValidatorRegistryDeltaFlags flag = 5;
} }
message Eth1Data {
bytes deposit_root_hash32 = 1;
bytes block_hash32 = 2;
}
message Eth1DataVote {
Eth1Data eth1_data = 1;
uint64 vote_count = 2;
}

View File

@@ -50,7 +50,7 @@ type BeaconChainConfig struct {
EpochLength uint64 // EpochLength is the number of slots in an epoch. EpochLength uint64 // EpochLength is the number of slots in an epoch.
SeedLookahead uint64 // SeedLookahead is the duration of randao look ahead seed. SeedLookahead uint64 // SeedLookahead is the duration of randao look ahead seed.
EntryExitDelay uint64 // EntryExitDelay is the duration a validator has to wait for entry and exit. EntryExitDelay uint64 // EntryExitDelay is the duration a validator has to wait for entry and exit.
DepositRootVotingPeriod uint64 // DepositRootVotingPeriod defines how often the merkle root of deposit receipts get updated in beacon node. Eth1DataVotingPeriod uint64 // Eth1DataVotingPeriod defines how often the merkle root of deposit receipts get updated in beacon node.
MinValidatorWithdrawalTime uint64 // MinValidatorWithdrawalTime is the shortest amount of time a validator can get the deposit out. MinValidatorWithdrawalTime uint64 // MinValidatorWithdrawalTime is the shortest amount of time a validator can get the deposit out.
FarFutureSlot uint64 // FarFutureSlot represents a slot extremely far away in the future used as the default penalization slot for validators. FarFutureSlot uint64 // FarFutureSlot represents a slot extremely far away in the future used as the default penalization slot for validators.
@@ -122,7 +122,7 @@ var defaultBeaconConfig = &BeaconChainConfig{
EpochLength: 64, EpochLength: 64,
SeedLookahead: 64, SeedLookahead: 64,
EntryExitDelay: 256, EntryExitDelay: 256,
DepositRootVotingPeriod: 1024, Eth1DataVotingPeriod: 1024,
// Reward and penalty quotients constants. // Reward and penalty quotients constants.
BaseRewardQuotient: 32, BaseRewardQuotient: 32,
@@ -178,7 +178,7 @@ var demoBeaconConfig = &BeaconChainConfig{
EpochLength: defaultBeaconConfig.EpochLength, EpochLength: defaultBeaconConfig.EpochLength,
SeedLookahead: defaultBeaconConfig.SeedLookahead, SeedLookahead: defaultBeaconConfig.SeedLookahead,
EntryExitDelay: defaultBeaconConfig.EntryExitDelay, EntryExitDelay: defaultBeaconConfig.EntryExitDelay,
DepositRootVotingPeriod: defaultBeaconConfig.DepositRootVotingPeriod, Eth1DataVotingPeriod: defaultBeaconConfig.Eth1DataVotingPeriod,
// Reward and penalty quotients constants. // Reward and penalty quotients constants.
BaseRewardQuotient: defaultBeaconConfig.BaseRewardQuotient, BaseRewardQuotient: defaultBeaconConfig.BaseRewardQuotient,