Skip to content

Commit

Permalink
kaiax/valet: Rename LowestScannedVoteNum
Browse files Browse the repository at this point in the history
  • Loading branch information
blukat29 committed Dec 17, 2024
1 parent 2b6c097 commit cc9bf4f
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 73 deletions.
47 changes: 4 additions & 43 deletions kaiax/valset/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,9 +412,9 @@ proposer x 1 3 2 0 3 2 3 1 2 3
```
"council" || Uint64BE(num) => JSON.Marshal([addr1, addr2, ...])
```
- `lowestCheckpointScannedBlockNum`: The lowest block number whose vote data and council is calculated from the legacy istanbul snapshot schema. That is, only vote block numbers are greater than or equal to this value are stored in `validatorVoteBlockNums`. It grows downwards by `istanbulCheckpointInterval` blocks.
- `lowestScannedValidatorVoteNum`: The lowest block number whose vote data and council is calculated and stored. That is, only vote block numbers are greater than or equal to this value are stored in `validatorVoteBlockNums`. It grows downwards by `istanbulCheckpointInterval` blocks.
```
"lowestCheckpointScannedBlockNum" => Uint64BE(num)
"lowestScannedValidatorVoteNum" => Uint64BE(num)
```
- `istanbulSnapshot`: The legacy schema that periodically (every `istanbulCheckpointInterval` block) commits the council and other fields. Council at an arbitrary block can be recovered by accumulating the validator votes from the nearest istanbul snapshot.
```
Expand Down Expand Up @@ -480,7 +480,7 @@ type committeeContext struct {

### Start and stop

This module maintains a background thread that migrates `istanbulCheckpoint` schema into the new `valsetVoteBlockNums` and `council` schemas.
This module maintains a background thread that migrates `istanbulSnapshot` schema into the new `validatorVoteBlockNums` and `council` schemas. The progress is stored in `lowestScannedValidatorVoteNum`.

## Block processing

Expand All @@ -506,7 +506,7 @@ This module does not expose APIs.
```
GetCouncil(num) -> []common.Address
```
- `GetValidators(num)`: Returns the demoted validators at block `num`. Note that you can calculate the qualified validators as Council.Subtract(DemotedValidators).
- `GetDemotedValidators(num)`: Returns the demoted validators at block `num`. Note that you can calculate the qualified validators as Council.Subtract(DemotedValidators).
```
GetDemotedValidators(num) -> []common.Address
```
Expand All @@ -518,42 +518,3 @@ This module does not expose APIs.
```
GetProposer(num, round) -> common.Address
```

### Implementation outline

```
# getters
GetCouncil
getCouncilGenesis
getCouncilLegacyDB
getCouncilDB
GetValidators
GetCouncil
getStakingDemoted
GetCommittee
GetValidators
selectRandomCommittee
selectRandaoCommittee
GetProposer
GetValidators
selectRoundRobinProposer
selectStickyProposer
selectWeightedRandomProposer
selectUniformRandomProposer
selectRandaoProposer
# types
AddressSet
Add
Remove
Has
ToSortedList
AddressList
At
IndexOf
Swap
Sort
ShuffleLegacy
ShuffleRandao
```
11 changes: 6 additions & 5 deletions kaiax/valset/impl/getter.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (v *ValsetModule) getCouncil(num uint64) (*valset.AddressSet, error) {
return v.getCouncilGenesis()
}

pBorder := ReadLowestScannedSnapshotNum(v.ChainKv)
pBorder := ReadLowestScannedVoteNum(v.ChainKv)
if pBorder == nil || *pBorder > 0 { // migration not started or migration not completed.
council, _, err := v.getCouncilFromIstanbulSnapshot(num, false)
return council, err
Expand Down Expand Up @@ -57,14 +57,15 @@ func (v *ValsetModule) getCouncilDB(num uint64) (*valset.AddressSet, error) {
if nums == nil {
return nil, errEmptyVoteBlock
}
voteNum := lastVoteBlockNum(nums, num)
voteNum := lastNumLessThan(nums, num)
council := valset.NewAddressSet(ReadCouncil(v.ChainKv, voteNum))
return council, nil
}

// lastVoteBlockNum returns the last block number in the list that is less than the given block number.
// For instance, if nums = [0, 10, 20, 30] and num = 25, the result is 20.
func lastVoteBlockNum(nums []uint64, num uint64) uint64 {
// lastNumLessThan returns the last (rightmost) number in the list that is less than the given number.
// If no such number exists, it returns 0.
// Suppose nums = [10, 20, 30]. If num = 25, the result is 20. If num = 7, the result is 0.
func lastNumLessThan(nums []uint64, num uint64) uint64 {
// idx is the smallest index that is greater than or equal to `num`.
// idx-1 is the largest index that is less than `num`.
idx := sort.Search(len(nums), func(i int) bool {
Expand Down
2 changes: 1 addition & 1 deletion kaiax/valset/impl/getter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func TestGetCouncilDB(t *testing.T) {
{8, 6, council6},
}
for _, tc := range testcases {
voteNum := lastVoteBlockNum(voteNums, tc.num)
voteNum := lastNumLessThan(voteNums, tc.num)
assert.Equal(t, tc.voteNum, voteNum, tc.num)

v := &ValsetModule{InitOpts: InitOpts{ChainKv: db}}
Expand Down
20 changes: 10 additions & 10 deletions kaiax/valset/impl/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,14 @@ func (v *ValsetModule) initSchema() error {
}

// Ensure mandatory schema lowestScannedCheckpointInterval
if pBorder := ReadLowestScannedSnapshotNum(v.ChainKv); pBorder == nil {
if pMinVoteNum := ReadLowestScannedVoteNum(v.ChainKv); pMinVoteNum == nil {
// migration not started. Migrating the last interval and leave the rest to be migrated by background thread.
currentNum := v.Chain.CurrentBlock().NumberU64()
_, snapshotNum, err := v.getCouncilFromIstanbulSnapshot(currentNum, true)
if err != nil {
return err
}
writeLowestScannedSnapshotNum(v.ChainKv, snapshotNum)
writeLowestScannedVoteNum(v.ChainKv, snapshotNum)
}

return nil
Expand Down Expand Up @@ -135,24 +135,24 @@ func (v *ValsetModule) Stop() {
func (v *ValsetModule) migrate() {
defer v.wg.Done()

pBorder := ReadLowestScannedSnapshotNum(v.ChainKv)
if pBorder == nil {
pMinVoteNum := ReadLowestScannedVoteNum(v.ChainKv)
if pMinVoteNum == nil {
logger.Error("No lowest scanned snapshot num")
return
}

border := *pBorder
for border > 0 {
targetNum := *pMinVoteNum
for targetNum > 0 {
if v.quit.Load() == 1 {
break
}
_, snapshotNum, err := v.getCouncilFromIstanbulSnapshot(border, true)
_, snapshotNum, err := v.getCouncilFromIstanbulSnapshot(targetNum, true)
if err != nil {
logger.Error("Failed to migrate", "targetNum", border, "err", err)
logger.Error("Failed to migrate", "targetNum", targetNum, "err", err)
break
}
border = snapshotNum
writeLowestScannedSnapshotNum(v.ChainKv, border)
targetNum = snapshotNum
writeLowestScannedVoteNum(v.ChainKv, targetNum)
}
}

Expand Down
4 changes: 2 additions & 2 deletions kaiax/valset/impl/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func TestMigration(t *testing.T) {
}))
// After initSchema: DB has mandatory schema + last istanbul snapshot interval (2048..2050)
assert.Equal(t, []uint64{0, 2049}, ReadValidatorVoteBlockNums(db))
assert.Equal(t, uint64(2048), *ReadLowestScannedSnapshotNum(db))
assert.Equal(t, uint64(2048), *ReadLowestScannedVoteNum(db))
assert.Equal(t, numsToAddrs(2, 3, 5), ReadCouncil(db, 0))
assert.Equal(t, numsToAddrs(1, 2, 3, 4, 5), ReadCouncil(db, 2049))

Expand All @@ -186,7 +186,7 @@ func TestMigration(t *testing.T) {
v.wg.Add(1)
v.migrate()
assert.Equal(t, []uint64{0, 1024, 1025, 1027, 2049}, ReadValidatorVoteBlockNums(db)) // valid votes
assert.Equal(t, uint64(0), *ReadLowestScannedSnapshotNum(db))
assert.Equal(t, uint64(0), *ReadLowestScannedVoteNum(db))
assert.Equal(t, numsToAddrs(2, 3, 5), ReadCouncil(db, 0)) // genesis council
assert.Equal(t, numsToAddrs(1, 2, 3, 5), ReadCouncil(db, 1024)) // after vote at 1024 (+1)
assert.Equal(t, numsToAddrs(1, 3, 5), ReadCouncil(db, 1025)) // after vote at 1025 (-2)
Expand Down
16 changes: 8 additions & 8 deletions kaiax/valset/impl/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (
)

var (
validatorVoteBlockNums = []byte("validatorVoteBlockNums")
lowestScannedSnapshotNumKey = []byte("lowestScannedSnapshotNum")
councilPrefix = []byte("council")
istanbulSnapshotKeyPrefix = []byte("snapshot")
validatorVoteBlockNums = []byte("validatorVoteBlockNums")
lowestScannedValidatorVoteNumKey = []byte("lowestScannedValidatorVoteNum")
councilPrefix = []byte("council")
istanbulSnapshotKeyPrefix = []byte("snapshot")

mu = &sync.RWMutex{}
)
Expand Down Expand Up @@ -114,8 +114,8 @@ func deleteCouncil(db database.Database, num uint64) {
}
}

func ReadLowestScannedSnapshotNum(db database.Database) *uint64 {
b, err := db.Get(lowestScannedSnapshotNumKey)
func ReadLowestScannedVoteNum(db database.Database) *uint64 {
b, err := db.Get(lowestScannedValidatorVoteNumKey)
if err != nil || len(b) == 0 {
return nil
}
Expand All @@ -127,10 +127,10 @@ func ReadLowestScannedSnapshotNum(db database.Database) *uint64 {
return &ret
}

func writeLowestScannedSnapshotNum(db database.Database, num uint64) {
func writeLowestScannedVoteNum(db database.Database, num uint64) {
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, num)
if err := db.Put(lowestScannedSnapshotNumKey, b); err != nil {
if err := db.Put(lowestScannedValidatorVoteNumKey, b); err != nil {
logger.Crit("Failed to write lowest scanned snapshot num", "num", num, "err", err)
}
}
Expand Down
8 changes: 4 additions & 4 deletions kaiax/valset/impl/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ func TestSchema_IstanbulSnapshot(t *testing.T) {
), addrs)
}

func TestSchema_LowestScannedSnapshotNum(t *testing.T) {
func TestSchema_LowestScannedVoteNum(t *testing.T) {
db := database.NewMemDB()

assert.Nil(t, ReadLowestScannedSnapshotNum(db))
assert.Nil(t, ReadLowestScannedVoteNum(db))

num := uint64(10)
writeLowestScannedSnapshotNum(db, num)
pNum := ReadLowestScannedSnapshotNum(db)
writeLowestScannedVoteNum(db, num)
pNum := ReadLowestScannedVoteNum(db)
require.NotNil(t, pNum)
assert.Equal(t, num, *pNum)
}

0 comments on commit cc9bf4f

Please sign in to comment.