-
Notifications
You must be signed in to change notification settings - Fork 975
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Part 1 of Aligning Core Blockchain Package with Latest 2.1 Spec #371
Merged
terencechain
merged 29 commits into
prysmaticlabs:master
from
terencechain:new-2.1-changes
Aug 14, 2018
Merged
Changes from 26 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
2af62ad
sync functions for active and crystallized states
terencechain b98a8dd
merge with master
terencechain d353026
Merge branch 'master' of https://github.com/prysmaticlabs/prysm
terencechain b418efd
Merge branch 'master' of https://github.com/prysmaticlabs/prysm
terencechain f436b85
Merge branch 'master' of https://github.com/prysmaticlabs/prysm
terencechain 774a43c
first commit to sync 2.1 spec
terencechain 2c93f8e
Replace Cutoff with SplitIndicies function
terencechain a88411c
new function to select validators by height and shard
terencechain 33cdbc9
merged with master
terencechain 21c0d8c
queued/exicted validator pools no longer exist in 2.1
terencechain 70ef131
just one last function calculateRewardsFFG to fix!
terencechain a7fb434
just one last function calculateRewardsFFG to fix!
terencechain d22cc83
fixed tests and lint
terencechain 1aa0cd1
bazel
terencechain 692fd2e
merge 2.1 with Raul's attester fixes
terencechain 186f4cc
aligned state and block types with 2.1
terencechain d146f46
bazel
terencechain bc7809a
fixed protoc
terencechain 06233f4
fixed params
terencechain e4f8d3b
2.1 configs
terencechain 77fdae4
fixed tests
terencechain 12ca291
cross check with pyevm implementations
terencechain c5e20e9
merged with Raul's proposer code
terencechain 9b8c9ac
merged with master
terencechain 961a1df
merged with master
terencechain b24e2d9
fixed test
terencechain f36a349
Merge branch 'master' into new-2.1-changes
terencechain c43259d
comments and punchuations
terencechain 21bf3ed
Merge branch 'new-2.1-changes' of github.com:terenc3t/prysm into new-…
terencechain File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,11 @@ type beaconState struct { | |
CrystallizedState *types.CrystallizedState | ||
} | ||
|
||
type beaconCommittee struct { | ||
shardID int | ||
committee []int | ||
} | ||
|
||
// NewBeaconChain initializes a beacon chain using genesis state parameters if | ||
// none provided. | ||
func NewBeaconChain(db ethdb.Database) (*BeaconChain, error) { | ||
|
@@ -168,17 +173,14 @@ func (b *BeaconChain) PersistCrystallizedState() error { | |
return b.db.Put([]byte(crystallizedStateLookupKey), encodedState) | ||
} | ||
|
||
// IsEpochTransition checks if the current slotNumber divided | ||
// by the epoch length (64 slots) is greater than the current epoch. | ||
// IsEpochTransition checks if it's epoch transition time. | ||
func (b *BeaconChain) IsEpochTransition(slotNumber uint64) bool { | ||
currentEpoch := b.state.CrystallizedState.CurrentEpoch() | ||
isTransition := (slotNumber / params.EpochLength) > currentEpoch | ||
return isTransition | ||
return slotNumber >= b.CrystallizedState().LastStateRecalc()+params.CycleLength | ||
} | ||
|
||
// CanProcessBlock decides if an incoming p2p block can be processed into the chain's block trie. | ||
func (b *BeaconChain) CanProcessBlock(fetcher types.POWBlockFetcher, block *types.Block) (bool, error) { | ||
if _, err := fetcher.BlockByHash(context.Background(), block.MainChainRef()); err != nil { | ||
if _, err := fetcher.BlockByHash(context.Background(), block.PowChainRef()); err != nil { | ||
return false, fmt.Errorf("fetching PoW block corresponding to mainchain reference failed: %v", err) | ||
} | ||
|
||
|
@@ -249,99 +251,106 @@ func (b *BeaconChain) computeNewActiveState(seed common.Hash) (*types.ActiveStat | |
// TODO: Verify randao reveal from validator's hash pre image. | ||
|
||
return types.NewActiveState(&pb.ActiveState{ | ||
TotalAttesterDeposits: 0, | ||
AttesterBitfield: []byte{}, | ||
PendingAttestations: []*pb.AttestationRecord{}, | ||
RecentBlockHashes: [][]byte{}, | ||
}), nil | ||
} | ||
|
||
// rotateValidatorSet is called every dynasty transition. It's primary function is | ||
// to go through queued validators and induct them to be active, and remove bad | ||
// active validator whose balance is below threshold to the exit set. It also cross checks | ||
// every validator's switch dynasty before induct or remove. | ||
func (b *BeaconChain) rotateValidatorSet() ([]*pb.ValidatorRecord, []*pb.ValidatorRecord, []*pb.ValidatorRecord) { | ||
|
||
var newExitedValidators = b.CrystallizedState().ExitedValidators() | ||
var newActiveValidators []*pb.ValidatorRecord | ||
upperbound := b.CrystallizedState().ActiveValidatorsLength()/30 + 1 | ||
exitCount := 0 | ||
|
||
// Loop through active validator set, remove validator whose balance is below 50% and switch dynasty > current dynasty. | ||
for _, validator := range b.CrystallizedState().ActiveValidators() { | ||
if validator.Balance < params.DefaultBalance/2 { | ||
newExitedValidators = append(newExitedValidators, validator) | ||
} else if validator.SwitchDynasty == b.CrystallizedState().CurrentDynasty()+1 && exitCount < upperbound { | ||
newExitedValidators = append(newExitedValidators, validator) | ||
exitCount++ | ||
} else { | ||
newActiveValidators = append(newActiveValidators, validator) | ||
// rotateValidatorSet is called every dynasty transition. The primary functions are: | ||
// 1.) Go through queued validator indices and induct them to be active by setting start | ||
// dynasty to current epoch. | ||
// 2.) Remove bad active validator whose balance is below threshold to the exit set by | ||
// setting end dynasty to current epoch. | ||
func (b *BeaconChain) rotateValidatorSet() { | ||
|
||
validators := b.CrystallizedState().Validators() | ||
upperbound := len(b.activeValidatorIndices())/30 + 1 | ||
|
||
// Loop through active validator set, remove validator whose balance is below 50%. | ||
for _, index := range b.activeValidatorIndices() { | ||
if validators[index].Balance < params.DefaultBalance/2 { | ||
validators[index].EndDynasty = b.CrystallizedState().CurrentDynasty() | ||
} | ||
} | ||
// Get the total number of validator we can induct. | ||
inductNum := upperbound | ||
if b.CrystallizedState().QueuedValidatorsLength() < inductNum { | ||
inductNum = b.CrystallizedState().QueuedValidatorsLength() | ||
if len(b.queuedValidatorIndices()) < inductNum { | ||
inductNum = len(b.queuedValidatorIndices()) | ||
} | ||
|
||
// Induct queued validator to active validator set until the switch dynasty is greater than current number. | ||
for i := 0; i < inductNum; i++ { | ||
if b.CrystallizedState().QueuedValidators()[i].SwitchDynasty > b.CrystallizedState().CurrentDynasty()+1 { | ||
inductNum = i | ||
for _, index := range b.queuedValidatorIndices() { | ||
validators[index].StartDynasty = b.CrystallizedState().CurrentDynasty() | ||
inductNum-- | ||
if inductNum == 0 { | ||
break | ||
} | ||
newActiveValidators = append(newActiveValidators, b.CrystallizedState().QueuedValidators()[i]) | ||
} | ||
newQueuedValidators := b.CrystallizedState().QueuedValidators()[inductNum:] | ||
|
||
return newQueuedValidators, newActiveValidators, newExitedValidators | ||
} | ||
|
||
// getAttestersProposer returns lists of random sampled attesters and proposer indices. | ||
func (b *BeaconChain) getAttestersProposer(seed common.Hash) ([]int, int, error) { | ||
attesterCount := math.Min(params.AttesterCount, float64(b.CrystallizedState().ActiveValidatorsLength())) | ||
attesterCount := math.Min(params.MinCommiteeSize, float64(b.CrystallizedState().ValidatorsLength())) | ||
|
||
indices, err := utils.ShuffleIndices(seed, b.CrystallizedState().ActiveValidatorsLength()) | ||
indices, err := utils.ShuffleIndices(seed, b.activeValidatorIndices()) | ||
if err != nil { | ||
return nil, -1, err | ||
} | ||
return indices[:int(attesterCount)], indices[len(indices)-1], nil | ||
} | ||
|
||
// getAttestersTotalDeposit returns the total deposit combined by attesters. | ||
// TODO: Consider slashing condition | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. punctuation |
||
func (b *BeaconChain) getAttestersTotalDeposit() (uint64, error) { | ||
var numOfBits int | ||
for _, attestation := range b.ActiveState().PendingAttestations() { | ||
for _, byte := range attestation.AttesterBitfield { | ||
numOfBits += int(utils.BitSetCount(byte)) | ||
} | ||
} | ||
// Assume there's no slashing condition, the following logic will change later phase. | ||
return uint64(numOfBits) * params.DefaultBalance, nil | ||
} | ||
|
||
// calculateRewardsFFG adjusts validators balances by applying rewards or penalties | ||
// based on FFG incentive structure. | ||
func (b *BeaconChain) calculateRewardsFFG() error { | ||
func (b *BeaconChain) calculateRewardsFFG(block *types.Block) error { | ||
b.lock.Lock() | ||
defer b.lock.Unlock() | ||
activeValidators := b.state.CrystallizedState.ActiveValidators() | ||
attesterDeposits := b.state.ActiveState.TotalAttesterDeposits() | ||
validators := b.CrystallizedState().Validators() | ||
activeValidators := b.activeValidatorIndices() | ||
attesterDeposits, err := b.getAttestersTotalDeposit() | ||
if err != nil { | ||
return err | ||
} | ||
totalDeposit := b.state.CrystallizedState.TotalDeposits() | ||
|
||
attesterFactor := attesterDeposits * 3 | ||
totalFactor := uint64(totalDeposit * 2) | ||
|
||
println(attesterFactor) | ||
println(totalFactor) | ||
if attesterFactor >= totalFactor { | ||
log.Info("Setting justified epoch to current epoch: %v", b.CrystallizedState().CurrentEpoch()) | ||
b.state.CrystallizedState.UpdateJustifiedEpoch() | ||
log.Info("Setting justified epoch to current slot number: %v", block.SlotNumber()) | ||
b.state.CrystallizedState.UpdateJustifiedSlot(block.SlotNumber()) | ||
|
||
log.Info("Applying rewards and penalties for the validators from last epoch") | ||
for i := range activeValidators { | ||
voted, err := b.hasAttesterAtIndexVoted(i) | ||
|
||
for i, attesterIndex := range activeValidators { | ||
voted, err := utils.CheckBit(b.state.ActiveState.LatestPendingAttestation().AttesterBitfield, attesterIndex) | ||
if err != nil { | ||
return fmt.Errorf("exiting calculate rewards FFG due to %v", err) | ||
} | ||
if voted { | ||
activeValidators[i].Balance += params.AttesterReward | ||
validators[i].Balance += params.AttesterReward | ||
} else { | ||
activeValidators[i].Balance -= params.AttesterReward | ||
validators[i].Balance -= params.AttesterReward | ||
} | ||
} | ||
|
||
log.Info("Resetting attester bit field to all zeros") | ||
b.resetAttesterBitfield() | ||
|
||
log.Info("Resetting total attester deposit to zero") | ||
b.ActiveState().SetTotalAttesterDeposits(0) | ||
b.ActiveState().ClearPendingAttestations() | ||
|
||
b.CrystallizedState().SetActiveValidators(activeValidators) | ||
b.CrystallizedState().SetValidators(validators) | ||
err := b.PersistActiveState() | ||
if err != nil { | ||
return err | ||
|
@@ -354,33 +363,88 @@ func (b *BeaconChain) calculateRewardsFFG() error { | |
return nil | ||
} | ||
|
||
// hasAttesterAtIndexVoted checks if the attester at the passed index has voted by comparing its bit field. | ||
func (b *BeaconChain) hasAttesterAtIndexVoted(index int) (bool, error) { | ||
bitfield := b.state.ActiveState.AttesterBitfield() | ||
attesterBlock := (index + 1) / 8 | ||
attesterFieldIndex := (index + 1) % 8 | ||
if attesterFieldIndex == 0 { | ||
attesterFieldIndex = 8 | ||
} else { | ||
attesterBlock++ | ||
// activeValidatorIndices filters out active validators based on start and end dynasty | ||
// and returns their indices in a list. | ||
func (b *BeaconChain) activeValidatorIndices() []int { | ||
var indices []int | ||
validators := b.CrystallizedState().Validators() | ||
dynasty := b.CrystallizedState().CurrentDynasty() | ||
for i := 0; i < len(validators); i++ { | ||
if validators[i].StartDynasty <= dynasty && dynasty < validators[i].EndDynasty { | ||
indices = append(indices, i) | ||
} | ||
} | ||
return indices | ||
} | ||
|
||
if len(bitfield) < attesterBlock { | ||
return false, errors.New("attester index does not exist") | ||
// exitedValidatorIndices filters out exited validators based on start and end dynasty | ||
// and returns their indices in a list. | ||
func (b *BeaconChain) exitedValidatorIndices() []int { | ||
var indices []int | ||
validators := b.CrystallizedState().Validators() | ||
dynasty := b.CrystallizedState().CurrentDynasty() | ||
for i := 0; i < len(validators); i++ { | ||
if validators[i].StartDynasty < dynasty && validators[i].EndDynasty < dynasty { | ||
indices = append(indices, i) | ||
} | ||
} | ||
return indices | ||
} | ||
|
||
field := bitfield[attesterBlock-1] >> (8 - uint(attesterFieldIndex)) | ||
if field%2 != 0 { | ||
return true, nil | ||
// queuedValidatorIndices filters out queued validators based on start and end dynasty | ||
// and returns their indices in a list. | ||
func (b *BeaconChain) queuedValidatorIndices() []int { | ||
var indices []int | ||
validators := b.CrystallizedState().Validators() | ||
dynasty := b.CrystallizedState().CurrentDynasty() | ||
for i := 0; i < len(validators); i++ { | ||
if validators[i].StartDynasty > dynasty { | ||
indices = append(indices, i) | ||
} | ||
} | ||
|
||
return false, nil | ||
return indices | ||
} | ||
|
||
// resetAttesterBitfield resets the attester bit field of active state to zeros. | ||
func (b *BeaconChain) resetAttesterBitfield() { | ||
newbitfields := make([]byte, b.CrystallizedState().ActiveValidatorsLength()/8) | ||
b.state.ActiveState.SetAttesterBitfield(newbitfields) | ||
// validatorsByHeightShard splits a shuffled validator list by height and by shard, | ||
// it ensures there's enough validators per height and per shard, if not, it'll skip | ||
// some heights and shards. | ||
func (b *BeaconChain) validatorsByHeightShard() ([]*beaconCommittee, error) { | ||
indices := b.activeValidatorIndices() | ||
var committeesPerSlot int | ||
var slotsPerCommittee int | ||
var committees []*beaconCommittee | ||
|
||
if len(indices) >= params.CycleLength*params.MinCommiteeSize { | ||
committeesPerSlot = len(indices)/params.CycleLength/(params.MinCommiteeSize*2) + 1 | ||
slotsPerCommittee = 1 | ||
} else { | ||
committeesPerSlot = 1 | ||
slotsPerCommittee = 1 | ||
for len(indices)*slotsPerCommittee < params.MinCommiteeSize && slotsPerCommittee < params.CycleLength { | ||
slotsPerCommittee *= 2 | ||
} | ||
} | ||
|
||
// split the shuffled list for heights | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. punctuation |
||
shuffledList, err := utils.ShuffleIndices(b.state.CrystallizedState.DynastySeed(), indices) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
heightList := utils.SplitIndices(shuffledList, params.CycleLength) | ||
|
||
// split the shuffled height list for shards | ||
for i, subList := range heightList { | ||
shardList := utils.SplitIndices(subList, params.MinCommiteeSize) | ||
for _, shardIndex := range shardList { | ||
shardID := int(b.CrystallizedState().CrosslinkingStartShard()) + i*committeesPerSlot/slotsPerCommittee | ||
committees = append(committees, &beaconCommittee{ | ||
shardID: shardID, | ||
committee: shardIndex, | ||
}) | ||
} | ||
} | ||
return committees, nil | ||
} | ||
|
||
// saveBlock puts the passed block into the beacon chain db. | ||
|
@@ -396,6 +460,3 @@ func (b *BeaconChain) saveBlock(block *types.Block) error { | |
|
||
return b.db.Put(hash[:], encodedState) | ||
} | ||
|
||
// Slashing Condtions | ||
// TODO: Implement all the conditions and add in the methods once the spec is updated |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rauljordan thanks for the review! it's ready again!