mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 23:02:16 +00:00
change voting power change, not number of vals
This commit is contained in:
parent
cf0b5d3715
commit
0093f9877a
@ -347,7 +347,7 @@ func consensusLogger() log.Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func randConsensusNet(nValidators int, testName string, tickerFunc func() TimeoutTicker, appFunc func() abci.Application, configOpts ...func(*cfg.Config)) []*ConsensusState {
|
func randConsensusNet(nValidators int, testName string, tickerFunc func() TimeoutTicker, appFunc func() abci.Application, configOpts ...func(*cfg.Config)) []*ConsensusState {
|
||||||
genDoc, privVals := randGenesisDoc(nValidators, false, 10)
|
genDoc, privVals := randGenesisDoc(nValidators, false, 30)
|
||||||
css := make([]*ConsensusState, nValidators)
|
css := make([]*ConsensusState, nValidators)
|
||||||
logger := consensusLogger()
|
logger := consensusLogger()
|
||||||
for i := 0; i < nValidators; i++ {
|
for i := 0; i < nValidators; i++ {
|
||||||
|
@ -180,7 +180,7 @@ func TestReactorVotingPowerChange(t *testing.T) {
|
|||||||
t.Fatalf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[0].GetRoundState().LastValidators.TotalVotingPower())
|
t.Fatalf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[0].GetRoundState().LastValidators.TotalVotingPower())
|
||||||
}
|
}
|
||||||
|
|
||||||
updateValidatorTx = dummy.MakeValSetChangeTx(val1PubKey.Bytes(), 100)
|
updateValidatorTx = dummy.MakeValSetChangeTx(val1PubKey.Bytes(), 26)
|
||||||
previousTotalVotingPower = css[0].GetRoundState().LastValidators.TotalVotingPower()
|
previousTotalVotingPower = css[0].GetRoundState().LastValidators.TotalVotingPower()
|
||||||
|
|
||||||
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css, updateValidatorTx)
|
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css, updateValidatorTx)
|
||||||
@ -194,8 +194,8 @@ func TestReactorVotingPowerChange(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestReactorValidatorSetChanges(t *testing.T) {
|
func TestReactorValidatorSetChanges(t *testing.T) {
|
||||||
nPeers := 9
|
nPeers := 7
|
||||||
nVals := 6
|
nVals := 4
|
||||||
css := randConsensusNetWithPeers(nVals, nPeers, "consensus_val_set_changes_test", newMockTickerFunc(true), newPersistentDummy)
|
css := randConsensusNetWithPeers(nVals, nPeers, "consensus_val_set_changes_test", newMockTickerFunc(true), newPersistentDummy)
|
||||||
|
|
||||||
logger := log.TestingLogger()
|
logger := log.TestingLogger()
|
||||||
|
@ -408,11 +408,12 @@ Additionally, the response may contain a list of validators, which can be used
|
|||||||
to update the validator set. To add a new validator or update an existing one,
|
to update the validator set. To add a new validator or update an existing one,
|
||||||
simply include them in the list returned in the EndBlock response. To remove
|
simply include them in the list returned in the EndBlock response. To remove
|
||||||
one, include it in the list with a ``power`` equal to ``0``. Tendermint core
|
one, include it in the list with a ``power`` equal to ``0``. Tendermint core
|
||||||
will take care of updating the validator set. Note you can not update more than
|
will take care of updating the validator set. Note the change in voting power
|
||||||
1/3 of validators in one block because this will make it impossible for a light
|
must be strictly less than 1/3 because otherwise it will be impossible for a
|
||||||
client to prove the transition externally. See the `light client docs
|
light client to prove the transition externally. See the `light client docs
|
||||||
<https://godoc.org/github.com/tendermint/tendermint/lite#hdr-How_We_Track_Validators>`__
|
<https://godoc.org/github.com/tendermint/tendermint/lite#hdr-How_We_Track_Validators>`__
|
||||||
for details on how it tracks validators.
|
for details on how it tracks validators. Tendermint core will report an error
|
||||||
|
if that is the case.
|
||||||
|
|
||||||
.. container:: toggle
|
.. container:: toggle
|
||||||
|
|
||||||
|
@ -122,18 +122,15 @@ func execBlockOnProxyApp(txEventPublisher types.TxEventPublisher, proxyAppConn p
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateValidators(currentSet *types.ValidatorSet, updates []*abci.Validator) error {
|
func updateValidators(currentSet *types.ValidatorSet, updates []*abci.Validator) error {
|
||||||
// ## prevent update of 1/3+ at once
|
// If more or equal than 1/3 of total voting power changed in one block, then
|
||||||
//
|
// a light client could never prove the transition externally. See
|
||||||
// If more than 1/3 validators changed in one block, then a light
|
// ./lite/doc.go for details on how a light client tracks validators.
|
||||||
// client could never prove the transition externally. See
|
vp23, err := changeInVotingPowerMoreOrEqualToOneThird(currentSet, updates)
|
||||||
// ./lite/doc.go for details on how a light client tracks
|
if err != nil {
|
||||||
// validators.
|
return err
|
||||||
maxUpdates := currentSet.Size() / 3
|
|
||||||
if maxUpdates == 0 { // if current set size is less than 3
|
|
||||||
maxUpdates = 1
|
|
||||||
}
|
}
|
||||||
if len(updates) > maxUpdates {
|
if vp23 {
|
||||||
return errors.New("Can not update more than 1/3 of validators at once")
|
return errors.New("the change in voting power must be strictly less than 1/3")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range updates {
|
for _, v := range updates {
|
||||||
@ -174,6 +171,42 @@ func updateValidators(currentSet *types.ValidatorSet, updates []*abci.Validator)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func changeInVotingPowerMoreOrEqualToOneThird(currentSet *types.ValidatorSet, updates []*abci.Validator) (bool, error) {
|
||||||
|
threshold := currentSet.TotalVotingPower() * 1 / 3
|
||||||
|
acc := int64(0)
|
||||||
|
|
||||||
|
for _, v := range updates {
|
||||||
|
pubkey, err := crypto.PubKeyFromBytes(v.PubKey) // NOTE: expects go-wire encoded pubkey
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
address := pubkey.Address()
|
||||||
|
power := int64(v.Power)
|
||||||
|
// mind the overflow from int64
|
||||||
|
if power < 0 {
|
||||||
|
return false, fmt.Errorf("Power (%d) overflows int64", v.Power)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, val := currentSet.GetByAddress(address)
|
||||||
|
if val == nil {
|
||||||
|
acc += power
|
||||||
|
} else {
|
||||||
|
np := val.VotingPower - power
|
||||||
|
if np < 0 {
|
||||||
|
np = -np
|
||||||
|
}
|
||||||
|
acc += np
|
||||||
|
}
|
||||||
|
|
||||||
|
if acc >= threshold {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
// return a bit array of validators that signed the last commit
|
// return a bit array of validators that signed the last commit
|
||||||
// NOTE: assumes commits have already been authenticated
|
// NOTE: assumes commits have already been authenticated
|
||||||
/* function is currently unused
|
/* function is currently unused
|
||||||
|
@ -134,7 +134,7 @@ func TestValidatorSimpleSaveLoad(t *testing.T) {
|
|||||||
// TestValidatorChangesSaveLoad tests saving and loading a validator set with
|
// TestValidatorChangesSaveLoad tests saving and loading a validator set with
|
||||||
// changes.
|
// changes.
|
||||||
func TestValidatorChangesSaveLoad(t *testing.T) {
|
func TestValidatorChangesSaveLoad(t *testing.T) {
|
||||||
const valSetSize = 6
|
const valSetSize = 7
|
||||||
tearDown, _, state := setupTestCase(t)
|
tearDown, _, state := setupTestCase(t)
|
||||||
state.Validators = genValSet(valSetSize)
|
state.Validators = genValSet(valSetSize)
|
||||||
state.Save()
|
state.Save()
|
||||||
@ -171,16 +171,14 @@ func genValSet(size int) *types.ValidatorSet {
|
|||||||
// with changes.
|
// with changes.
|
||||||
func TestConsensusParamsChangesSaveLoad(t *testing.T) {
|
func TestConsensusParamsChangesSaveLoad(t *testing.T) {
|
||||||
tearDown, _, state := setupTestCase(t)
|
tearDown, _, state := setupTestCase(t)
|
||||||
const valSetSize = 20
|
|
||||||
state.Validators = genValSet(valSetSize)
|
|
||||||
state.Save()
|
|
||||||
defer tearDown(t)
|
defer tearDown(t)
|
||||||
|
|
||||||
// change vals at these heights
|
// change vals at these heights
|
||||||
changeHeights := []int64{1, 2, 4, 5, 10, 15, 16, 17, 20}
|
changeHeights := []int64{1, 2, 4, 5, 10, 15, 16, 17, 20}
|
||||||
N := len(changeHeights)
|
N := len(changeHeights)
|
||||||
|
|
||||||
// create list of new vals
|
// each valset is just one validator
|
||||||
|
// create list of them
|
||||||
params := make([]types.ConsensusParams, N+1)
|
params := make([]types.ConsensusParams, N+1)
|
||||||
params[0] = state.ConsensusParams
|
params[0] = state.ConsensusParams
|
||||||
for i := 1; i < N+1; i++ {
|
for i := 1; i < N+1; i++ {
|
||||||
@ -247,7 +245,7 @@ func makeParams(blockBytes, blockTx, blockGas, txBytes,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLessThanOneThirdOfValidatorUpdatesEnforced(t *testing.T) {
|
func TestLessThanOneThirdOfVotingPowerPerBlockEnforced(t *testing.T) {
|
||||||
tearDown, _, state := setupTestCase(t)
|
tearDown, _, state := setupTestCase(t)
|
||||||
defer tearDown(t)
|
defer tearDown(t)
|
||||||
|
|
||||||
@ -255,10 +253,13 @@ func TestLessThanOneThirdOfValidatorUpdatesEnforced(t *testing.T) {
|
|||||||
block := makeBlock(state, height)
|
block := makeBlock(state, height)
|
||||||
abciResponses := &ABCIResponses{
|
abciResponses := &ABCIResponses{
|
||||||
Height: height,
|
Height: height,
|
||||||
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []*abci.Validator{{PubKey: []byte("a"), Power: 10}}},
|
// 1 val (vp: 10) => less than 3 is ok
|
||||||
|
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []*abci.Validator{
|
||||||
|
{PubKey: crypto.GenPrivKeyEd25519().PubKey().Bytes(), Power: 3},
|
||||||
|
}},
|
||||||
}
|
}
|
||||||
err := state.SetBlockAndValidators(block.Header, types.PartSetHeader{}, abciResponses)
|
err := state.SetBlockAndValidators(block.Header, types.PartSetHeader{}, abciResponses)
|
||||||
assert.NotNil(t, err, "expected err when trying to update more than 1/3 of validators")
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestApplyUpdates(t *testing.T) {
|
func TestApplyUpdates(t *testing.T) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user