do not enforce 1/3 validator power change
leave it to the app Refs #1022
This commit is contained in:
parent
e7bc946760
commit
106cdb74e5
|
@ -409,11 +409,10 @@ 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
|
||||
one, include it in the list with a ``power`` equal to ``0``. Tendermint core
|
||||
will take care of updating the validator set. Note the change in voting power
|
||||
must be strictly less than 1/3 per block. Otherwise it will be impossible for a
|
||||
light client to prove the transition externally. See the `light client docs
|
||||
must be strictly less than 1/3 per block if you want a light client to be able
|
||||
to prove the transition externally. See the `light client docs
|
||||
<https://godoc.org/github.com/tendermint/tendermint/lite#hdr-How_We_Track_Validators>`__
|
||||
for details on how it tracks validators. Tendermint core will fail with an
|
||||
error if the change in voting power is more or equal than 1/3.
|
||||
for details on how it tracks validators.
|
||||
|
||||
.. container:: toggle
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
fail "github.com/ebuchman/fail-test"
|
||||
|
@ -238,18 +237,10 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
|||
return abciResponses, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
// ./lite/doc.go for details on how a light client tracks validators.
|
||||
func updateValidators(currentSet *types.ValidatorSet, updates []abci.Validator) error {
|
||||
// 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
|
||||
// ./lite/doc.go for details on how a light client tracks validators.
|
||||
vp23, err := changeInVotingPowerMoreOrEqualToOneThird(currentSet, updates)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if vp23 {
|
||||
return errors.New("the change in voting power must be strictly less than 1/3")
|
||||
}
|
||||
|
||||
for _, v := range updates {
|
||||
pubkey, err := crypto.PubKeyFromBytes(v.PubKey) // NOTE: expects go-wire encoded pubkey
|
||||
if err != nil {
|
||||
|
@ -288,42 +279,6 @@ func updateValidators(currentSet *types.ValidatorSet, updates []abci.Validator)
|
|||
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
|
||||
}
|
||||
|
||||
// updateState returns a new State updated according to the header and responses.
|
||||
func updateState(s State, blockID types.BlockID, header *types.Header,
|
||||
abciResponses *ABCIResponses) (State, error) {
|
||||
|
|
|
@ -375,73 +375,6 @@ func makeParams(blockBytes, blockTx, blockGas, txBytes,
|
|||
}
|
||||
}
|
||||
|
||||
func TestLessThanOneThirdOfVotingPowerPerBlockEnforced(t *testing.T) {
|
||||
testCases := []struct {
|
||||
initialValSetSize int
|
||||
shouldErr bool
|
||||
valUpdatesFn func(vals *types.ValidatorSet) []abci.Validator
|
||||
}{
|
||||
///////////// 1 val (vp: 10) => less than 3 is ok ////////////////////////
|
||||
// adding 1 validator => 10
|
||||
0: {1, false, func(vals *types.ValidatorSet) []abci.Validator {
|
||||
return []abci.Validator{
|
||||
{PubKey: pk(), Power: 2},
|
||||
}
|
||||
}},
|
||||
1: {1, true, func(vals *types.ValidatorSet) []abci.Validator {
|
||||
return []abci.Validator{
|
||||
{PubKey: pk(), Power: 3},
|
||||
}
|
||||
}},
|
||||
2: {1, true, func(vals *types.ValidatorSet) []abci.Validator {
|
||||
return []abci.Validator{
|
||||
{PubKey: pk(), Power: 100},
|
||||
}
|
||||
}},
|
||||
|
||||
///////////// 3 val (vp: 30) => less than 10 is ok ////////////////////////
|
||||
// adding and removing validator => 20
|
||||
3: {3, true, func(vals *types.ValidatorSet) []abci.Validator {
|
||||
_, firstVal := vals.GetByIndex(0)
|
||||
return []abci.Validator{
|
||||
{PubKey: firstVal.PubKey.Bytes(), Power: 0},
|
||||
{PubKey: pk(), Power: 10},
|
||||
}
|
||||
}},
|
||||
// adding 1 validator => 10
|
||||
4: {3, true, func(vals *types.ValidatorSet) []abci.Validator {
|
||||
return []abci.Validator{
|
||||
{PubKey: pk(), Power: 10},
|
||||
}
|
||||
}},
|
||||
// adding 2 validators => 8
|
||||
5: {3, false, func(vals *types.ValidatorSet) []abci.Validator {
|
||||
return []abci.Validator{
|
||||
{PubKey: pk(), Power: 4},
|
||||
{PubKey: pk(), Power: 4},
|
||||
}
|
||||
}},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
tearDown, stateDB, state := setupTestCase(t)
|
||||
state.Validators = genValSet(tc.initialValSetSize)
|
||||
SaveState(stateDB, state)
|
||||
height := state.LastBlockHeight + 1
|
||||
block := makeBlock(state, height)
|
||||
abciResponses := &ABCIResponses{
|
||||
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: tc.valUpdatesFn(state.Validators)},
|
||||
}
|
||||
state, err := updateState(state, types.BlockID{block.Hash(), types.PartSetHeader{}}, block.Header, abciResponses)
|
||||
if tc.shouldErr {
|
||||
assert.Error(t, err, "#%d", i)
|
||||
} else {
|
||||
assert.NoError(t, err, "#%d", i)
|
||||
}
|
||||
tearDown(t)
|
||||
}
|
||||
}
|
||||
|
||||
func pk() []byte {
|
||||
return crypto.GenPrivKeyEd25519().PubKey().Bytes()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue