Merge pull request #2159 from tendermint/bucky/abci-validators
Bucky/abci validators
This commit is contained in:
commit
debe56326f
|
@ -14,6 +14,10 @@ BREAKING CHANGES:
|
|||
- [crypto] Rename AminoRoute variables to no longer be prefixed by signature type.
|
||||
- [config] Replace MaxNumPeers with MaxNumInboundPeers and MaxNumOutboundPeers
|
||||
- [node] NewNode now accepts a `*p2p.NodeKey`
|
||||
- [abci] \#2159 Update use of `Validator` ala ADR-018:
|
||||
- Remove PubKey from `Validator` and introduce `ValidatorUpdate`
|
||||
- InitChain and EndBlock use ValidatorUpdate
|
||||
- Update field names and types in BeginBlock
|
||||
|
||||
FEATURES:
|
||||
- [types] allow genesis file to have 0 validators ([#2015](https://github.com/tendermint/tendermint/issues/2015))
|
||||
|
|
11
Makefile
11
Makefile
|
@ -10,6 +10,8 @@ INCLUDE = -I=. -I=${GOPATH}/src -I=${GOPATH}/src/github.com/gogo/protobuf/protob
|
|||
BUILD_TAGS?='tendermint'
|
||||
BUILD_FLAGS = -ldflags "-X github.com/tendermint/tendermint/version.GitCommit=`git rev-parse --short=8 HEAD`"
|
||||
|
||||
LINT_FLAGS = --exclude '.*\.pb\.go' --vendor --deadline=600s
|
||||
|
||||
all: check build test install
|
||||
|
||||
check: check_tools get_vendor_deps
|
||||
|
@ -36,13 +38,14 @@ protoc_all: protoc_libs protoc_abci protoc_grpc
|
|||
## If you get the following error,
|
||||
## "error while loading shared libraries: libprotobuf.so.14: cannot open shared object file: No such file or directory"
|
||||
## See https://stackoverflow.com/a/25518702
|
||||
## Note the $< here is substituted for the %.proto
|
||||
## Note the $@ here is substituted for the %.pb.go
|
||||
protoc $(INCLUDE) $< --gogo_out=Mgoogle/protobuf/timestamp.proto=github.com/golang/protobuf/ptypes/timestamp,plugins=grpc:.
|
||||
@echo "--> adding nolint declarations to protobuf generated files"
|
||||
@awk -i inplace '/^\s*package \w+/ { print "//nolint" }1' $@
|
||||
|
||||
########################################
|
||||
### Build ABCI
|
||||
|
||||
# see protobuf section above
|
||||
protoc_abci: abci/types/types.pb.go
|
||||
|
||||
build_abci:
|
||||
|
@ -216,7 +219,7 @@ fmt:
|
|||
|
||||
metalinter:
|
||||
@echo "--> Running linter"
|
||||
@gometalinter.v2 --vendor --deadline=600s --disable-all \
|
||||
@gometalinter.v2 $(LINT_FLAGS) --disable-all \
|
||||
--enable=deadcode \
|
||||
--enable=gosimple \
|
||||
--enable=misspell \
|
||||
|
@ -245,7 +248,7 @@ metalinter:
|
|||
|
||||
metalinter_all:
|
||||
@echo "--> Running linter (all)"
|
||||
gometalinter.v2 --vendor --deadline=600s --enable-all --disable=lll ./...
|
||||
gometalinter.v2 $(LINT_FLAGS) --enable-all --disable=lll ./...
|
||||
|
||||
DESTINATION = ./index.html.md
|
||||
|
||||
|
|
|
@ -7,12 +7,10 @@ import (
|
|||
|
||||
// RandVal creates one random validator, with a key derived
|
||||
// from the input value
|
||||
func RandVal(i int) types.Validator {
|
||||
addr := cmn.RandBytes(20)
|
||||
func RandVal(i int) types.ValidatorUpdate {
|
||||
pubkey := cmn.RandBytes(32)
|
||||
power := cmn.RandUint16() + 1
|
||||
v := types.Ed25519Validator(pubkey, int64(power))
|
||||
v.Address = addr
|
||||
v := types.Ed25519ValidatorUpdate(pubkey, int64(power))
|
||||
return v
|
||||
}
|
||||
|
||||
|
@ -20,8 +18,8 @@ func RandVal(i int) types.Validator {
|
|||
// the application. Note that the keys are deterministically
|
||||
// derived from the index in the array, while the power is
|
||||
// random (Change this if not desired)
|
||||
func RandVals(cnt int) []types.Validator {
|
||||
res := make([]types.Validator, cnt)
|
||||
func RandVals(cnt int) []types.ValidatorUpdate {
|
||||
res := make([]types.ValidatorUpdate, cnt)
|
||||
for i := 0; i < cnt; i++ {
|
||||
res[i] = RandVal(i)
|
||||
}
|
||||
|
|
|
@ -122,11 +122,11 @@ func TestValUpdates(t *testing.T) {
|
|||
vals1, vals2 := vals[:nInit], kvstore.Validators()
|
||||
valsEqual(t, vals1, vals2)
|
||||
|
||||
var v1, v2, v3 types.Validator
|
||||
var v1, v2, v3 types.ValidatorUpdate
|
||||
|
||||
// add some validators
|
||||
v1, v2 = vals[nInit], vals[nInit+1]
|
||||
diff := []types.Validator{v1, v2}
|
||||
diff := []types.ValidatorUpdate{v1, v2}
|
||||
tx1 := MakeValSetChangeTx(v1.PubKey, v1.Power)
|
||||
tx2 := MakeValSetChangeTx(v2.PubKey, v2.Power)
|
||||
|
||||
|
@ -140,7 +140,7 @@ func TestValUpdates(t *testing.T) {
|
|||
v1.Power = 0
|
||||
v2.Power = 0
|
||||
v3.Power = 0
|
||||
diff = []types.Validator{v1, v2, v3}
|
||||
diff = []types.ValidatorUpdate{v1, v2, v3}
|
||||
tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power)
|
||||
tx2 = MakeValSetChangeTx(v2.PubKey, v2.Power)
|
||||
tx3 := MakeValSetChangeTx(v3.PubKey, v3.Power)
|
||||
|
@ -158,18 +158,18 @@ func TestValUpdates(t *testing.T) {
|
|||
} else {
|
||||
v1.Power = 5
|
||||
}
|
||||
diff = []types.Validator{v1}
|
||||
diff = []types.ValidatorUpdate{v1}
|
||||
tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power)
|
||||
|
||||
makeApplyBlock(t, kvstore, 3, diff, tx1)
|
||||
|
||||
vals1 = append([]types.Validator{v1}, vals1[1:]...)
|
||||
vals1 = append([]types.ValidatorUpdate{v1}, vals1[1:]...)
|
||||
vals2 = kvstore.Validators()
|
||||
valsEqual(t, vals1, vals2)
|
||||
|
||||
}
|
||||
|
||||
func makeApplyBlock(t *testing.T, kvstore types.Application, heightInt int, diff []types.Validator, txs ...[]byte) {
|
||||
func makeApplyBlock(t *testing.T, kvstore types.Application, heightInt int, diff []types.ValidatorUpdate, txs ...[]byte) {
|
||||
// make and apply block
|
||||
height := int64(heightInt)
|
||||
hash := []byte("foo")
|
||||
|
@ -191,12 +191,12 @@ func makeApplyBlock(t *testing.T, kvstore types.Application, heightInt int, diff
|
|||
}
|
||||
|
||||
// order doesn't matter
|
||||
func valsEqual(t *testing.T, vals1, vals2 []types.Validator) {
|
||||
func valsEqual(t *testing.T, vals1, vals2 []types.ValidatorUpdate) {
|
||||
if len(vals1) != len(vals2) {
|
||||
t.Fatalf("vals dont match in len. got %d, expected %d", len(vals2), len(vals1))
|
||||
}
|
||||
sort.Sort(types.Validators(vals1))
|
||||
sort.Sort(types.Validators(vals2))
|
||||
sort.Sort(types.ValidatorUpdates(vals1))
|
||||
sort.Sort(types.ValidatorUpdates(vals2))
|
||||
for i, v1 := range vals1 {
|
||||
v2 := vals2[i]
|
||||
if !bytes.Equal(v1.PubKey.Data, v2.PubKey.Data) ||
|
||||
|
|
|
@ -25,7 +25,7 @@ type PersistentKVStoreApplication struct {
|
|||
app *KVStoreApplication
|
||||
|
||||
// validator set
|
||||
ValUpdates []types.Validator
|
||||
ValUpdates []types.ValidatorUpdate
|
||||
|
||||
logger log.Logger
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ func (app *PersistentKVStoreApplication) InitChain(req types.RequestInitChain) t
|
|||
// Track the block hash and header information
|
||||
func (app *PersistentKVStoreApplication) BeginBlock(req types.RequestBeginBlock) types.ResponseBeginBlock {
|
||||
// reset valset changes
|
||||
app.ValUpdates = make([]types.Validator, 0)
|
||||
app.ValUpdates = make([]types.ValidatorUpdate, 0)
|
||||
return types.ResponseBeginBlock{}
|
||||
}
|
||||
|
||||
|
@ -113,11 +113,11 @@ func (app *PersistentKVStoreApplication) EndBlock(req types.RequestEndBlock) typ
|
|||
//---------------------------------------------
|
||||
// update validators
|
||||
|
||||
func (app *PersistentKVStoreApplication) Validators() (validators []types.Validator) {
|
||||
func (app *PersistentKVStoreApplication) Validators() (validators []types.ValidatorUpdate) {
|
||||
itr := app.app.state.db.Iterator(nil, nil)
|
||||
for ; itr.Valid(); itr.Next() {
|
||||
if isValidatorTx(itr.Key()) {
|
||||
validator := new(types.Validator)
|
||||
validator := new(types.ValidatorUpdate)
|
||||
err := types.ReadMessage(bytes.NewBuffer(itr.Value()), validator)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -167,11 +167,11 @@ func (app *PersistentKVStoreApplication) execValidatorTx(tx []byte) types.Respon
|
|||
}
|
||||
|
||||
// update
|
||||
return app.updateValidator(types.Ed25519Validator(pubkey, int64(power)))
|
||||
return app.updateValidator(types.Ed25519ValidatorUpdate(pubkey, int64(power)))
|
||||
}
|
||||
|
||||
// add, update, or remove a validator
|
||||
func (app *PersistentKVStoreApplication) updateValidator(v types.Validator) types.ResponseDeliverTx {
|
||||
func (app *PersistentKVStoreApplication) updateValidator(v types.ValidatorUpdate) types.ResponseDeliverTx {
|
||||
key := []byte("val:" + string(v.PubKey.Data))
|
||||
if v.Power == 0 {
|
||||
// remove validator
|
||||
|
|
|
@ -12,11 +12,11 @@ import (
|
|||
|
||||
func InitChain(client abcicli.Client) error {
|
||||
total := 10
|
||||
vals := make([]types.Validator, total)
|
||||
vals := make([]types.ValidatorUpdate, total)
|
||||
for i := 0; i < total; i++ {
|
||||
pubkey := cmn.RandBytes(33)
|
||||
power := cmn.RandInt()
|
||||
vals[i] = types.Ed25519Validator(pubkey, int64(power))
|
||||
vals[i] = types.Ed25519ValidatorUpdate(pubkey, int64(power))
|
||||
}
|
||||
_, err := client.InitChainSync(types.RequestInitChain{
|
||||
Validators: vals,
|
||||
|
|
|
@ -4,8 +4,8 @@ const (
|
|||
PubKeyEd25519 = "ed25519"
|
||||
)
|
||||
|
||||
func Ed25519Validator(pubkey []byte, power int64) Validator {
|
||||
return Validator{
|
||||
func Ed25519ValidatorUpdate(pubkey []byte, power int64) ValidatorUpdate {
|
||||
return ValidatorUpdate{
|
||||
// Address:
|
||||
PubKey: PubKey{
|
||||
Type: PubKeyEd25519,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -60,7 +60,7 @@ message RequestInitChain {
|
|||
google.protobuf.Timestamp time = 1 [(gogoproto.nullable)=false, (gogoproto.stdtime)=true];
|
||||
string chain_id = 2;
|
||||
ConsensusParams consensus_params = 3;
|
||||
repeated Validator validators = 4 [(gogoproto.nullable)=false];
|
||||
repeated ValidatorUpdate validators = 4 [(gogoproto.nullable)=false];
|
||||
bytes app_state_bytes = 5;
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,7 @@ message ResponseSetOption {
|
|||
|
||||
message ResponseInitChain {
|
||||
ConsensusParams consensus_params = 1;
|
||||
repeated Validator validators = 2 [(gogoproto.nullable)=false];
|
||||
repeated ValidatorUpdate validators = 2 [(gogoproto.nullable)=false];
|
||||
}
|
||||
|
||||
message ResponseQuery {
|
||||
|
@ -183,7 +183,7 @@ message ResponseDeliverTx {
|
|||
}
|
||||
|
||||
message ResponseEndBlock {
|
||||
repeated Validator validator_updates = 1 [(gogoproto.nullable)=false];
|
||||
repeated ValidatorUpdate validator_updates = 1 [(gogoproto.nullable)=false];
|
||||
ConsensusParams consensus_param_updates = 2;
|
||||
repeated common.KVPair tags = 3 [(gogoproto.nullable)=false, (gogoproto.jsontag)="tags,omitempty"];
|
||||
}
|
||||
|
@ -225,8 +225,8 @@ message BlockGossip {
|
|||
}
|
||||
|
||||
message LastCommitInfo {
|
||||
int32 commit_round = 1;
|
||||
repeated SigningValidator validators = 2 [(gogoproto.nullable)=false];
|
||||
int32 round = 1;
|
||||
repeated VoteInfo votes = 2 [(gogoproto.nullable)=false];
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
@ -249,13 +249,14 @@ message Header {
|
|||
|
||||
// hashes from the app output from the prev block
|
||||
bytes validators_hash = 9; // validators for the current block
|
||||
bytes consensus_hash = 10; // consensus params for current block
|
||||
bytes app_hash = 11; // state after txs from the previous block
|
||||
bytes last_results_hash = 12;// root hash of all results from the txs from the previous block
|
||||
bytes next_validators_hash = 10; // validators for the next block
|
||||
bytes consensus_hash = 11; // consensus params for current block
|
||||
bytes app_hash = 12; // state after txs from the previous block
|
||||
bytes last_results_hash = 13;// root hash of all results from the txs from the previous block
|
||||
|
||||
// consensus info
|
||||
bytes evidence_hash = 13; // evidence included in the block
|
||||
bytes proposer_address = 14; // original proposer of the block
|
||||
bytes evidence_hash = 14; // evidence included in the block
|
||||
bytes proposer_address = 15; // original proposer of the block
|
||||
}
|
||||
|
||||
message BlockID {
|
||||
|
@ -271,12 +272,18 @@ message PartSetHeader {
|
|||
// Validator
|
||||
message Validator {
|
||||
bytes address = 1;
|
||||
PubKey pub_key = 2 [(gogoproto.nullable)=false];
|
||||
//PubKey pub_key = 2 [(gogoproto.nullable)=false];
|
||||
int64 power = 3;
|
||||
}
|
||||
|
||||
// Validator with an extra bool
|
||||
message SigningValidator {
|
||||
// ValidatorUpdate
|
||||
message ValidatorUpdate {
|
||||
PubKey pub_key = 1 [(gogoproto.nullable)=false];
|
||||
int64 power = 2;
|
||||
}
|
||||
|
||||
// VoteInfo
|
||||
message VoteInfo {
|
||||
Validator validator = 1 [(gogoproto.nullable)=false];
|
||||
bool signed_last_block = 2;
|
||||
}
|
||||
|
|
|
@ -1926,15 +1926,15 @@ func TestValidatorMarshalTo(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSigningValidatorProto(t *testing.T) {
|
||||
func TestValidatorUpdateProto(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedSigningValidator(popr, false)
|
||||
p := NewPopulatedValidatorUpdate(popr, false)
|
||||
dAtA, err := github_com_gogo_protobuf_proto.Marshal(p)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
msg := &SigningValidator{}
|
||||
msg := &ValidatorUpdate{}
|
||||
if err := github_com_gogo_protobuf_proto.Unmarshal(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
|
@ -1957,10 +1957,10 @@ func TestSigningValidatorProto(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSigningValidatorMarshalTo(t *testing.T) {
|
||||
func TestValidatorUpdateMarshalTo(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedSigningValidator(popr, false)
|
||||
p := NewPopulatedValidatorUpdate(popr, false)
|
||||
size := p.Size()
|
||||
dAtA := make([]byte, size)
|
||||
for i := range dAtA {
|
||||
|
@ -1970,7 +1970,63 @@ func TestSigningValidatorMarshalTo(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
msg := &SigningValidator{}
|
||||
msg := &ValidatorUpdate{}
|
||||
if err := github_com_gogo_protobuf_proto.Unmarshal(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
for i := range dAtA {
|
||||
dAtA[i] = byte(popr.Intn(256))
|
||||
}
|
||||
if !p.Equal(msg) {
|
||||
t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVoteInfoProto(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedVoteInfo(popr, false)
|
||||
dAtA, err := github_com_gogo_protobuf_proto.Marshal(p)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
msg := &VoteInfo{}
|
||||
if err := github_com_gogo_protobuf_proto.Unmarshal(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
littlefuzz := make([]byte, len(dAtA))
|
||||
copy(littlefuzz, dAtA)
|
||||
for i := range dAtA {
|
||||
dAtA[i] = byte(popr.Intn(256))
|
||||
}
|
||||
if !p.Equal(msg) {
|
||||
t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p)
|
||||
}
|
||||
if len(littlefuzz) > 0 {
|
||||
fuzzamount := 100
|
||||
for i := 0; i < fuzzamount; i++ {
|
||||
littlefuzz[popr.Intn(len(littlefuzz))] = byte(popr.Intn(256))
|
||||
littlefuzz = append(littlefuzz, byte(popr.Intn(256)))
|
||||
}
|
||||
// shouldn't panic
|
||||
_ = github_com_gogo_protobuf_proto.Unmarshal(littlefuzz, msg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVoteInfoMarshalTo(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedVoteInfo(popr, false)
|
||||
size := p.Size()
|
||||
dAtA := make([]byte, size)
|
||||
for i := range dAtA {
|
||||
dAtA[i] = byte(popr.Intn(256))
|
||||
}
|
||||
_, err := p.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
msg := &VoteInfo{}
|
||||
if err := github_com_gogo_protobuf_proto.Unmarshal(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
|
@ -2706,16 +2762,34 @@ func TestValidatorJSON(t *testing.T) {
|
|||
t.Fatalf("seed = %d, %#v !Json Equal %#v", seed, msg, p)
|
||||
}
|
||||
}
|
||||
func TestSigningValidatorJSON(t *testing.T) {
|
||||
func TestValidatorUpdateJSON(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedSigningValidator(popr, true)
|
||||
p := NewPopulatedValidatorUpdate(popr, true)
|
||||
marshaler := github_com_gogo_protobuf_jsonpb.Marshaler{}
|
||||
jsondata, err := marshaler.MarshalToString(p)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
msg := &SigningValidator{}
|
||||
msg := &ValidatorUpdate{}
|
||||
err = github_com_gogo_protobuf_jsonpb.UnmarshalString(jsondata, msg)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
if !p.Equal(msg) {
|
||||
t.Fatalf("seed = %d, %#v !Json Equal %#v", seed, msg, p)
|
||||
}
|
||||
}
|
||||
func TestVoteInfoJSON(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedVoteInfo(popr, true)
|
||||
marshaler := github_com_gogo_protobuf_jsonpb.Marshaler{}
|
||||
jsondata, err := marshaler.MarshalToString(p)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
msg := &VoteInfo{}
|
||||
err = github_com_gogo_protobuf_jsonpb.UnmarshalString(jsondata, msg)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
|
@ -3712,12 +3786,12 @@ func TestValidatorProtoCompactText(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSigningValidatorProtoText(t *testing.T) {
|
||||
func TestValidatorUpdateProtoText(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedSigningValidator(popr, true)
|
||||
p := NewPopulatedValidatorUpdate(popr, true)
|
||||
dAtA := github_com_gogo_protobuf_proto.MarshalTextString(p)
|
||||
msg := &SigningValidator{}
|
||||
msg := &ValidatorUpdate{}
|
||||
if err := github_com_gogo_protobuf_proto.UnmarshalText(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
|
@ -3726,12 +3800,40 @@ func TestSigningValidatorProtoText(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSigningValidatorProtoCompactText(t *testing.T) {
|
||||
func TestValidatorUpdateProtoCompactText(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedSigningValidator(popr, true)
|
||||
p := NewPopulatedValidatorUpdate(popr, true)
|
||||
dAtA := github_com_gogo_protobuf_proto.CompactTextString(p)
|
||||
msg := &SigningValidator{}
|
||||
msg := &ValidatorUpdate{}
|
||||
if err := github_com_gogo_protobuf_proto.UnmarshalText(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
if !p.Equal(msg) {
|
||||
t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVoteInfoProtoText(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedVoteInfo(popr, true)
|
||||
dAtA := github_com_gogo_protobuf_proto.MarshalTextString(p)
|
||||
msg := &VoteInfo{}
|
||||
if err := github_com_gogo_protobuf_proto.UnmarshalText(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
if !p.Equal(msg) {
|
||||
t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVoteInfoProtoCompactText(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedVoteInfo(popr, true)
|
||||
dAtA := github_com_gogo_protobuf_proto.CompactTextString(p)
|
||||
msg := &VoteInfo{}
|
||||
if err := github_com_gogo_protobuf_proto.UnmarshalText(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
|
@ -4544,10 +4646,32 @@ func TestValidatorSize(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSigningValidatorSize(t *testing.T) {
|
||||
func TestValidatorUpdateSize(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedSigningValidator(popr, true)
|
||||
p := NewPopulatedValidatorUpdate(popr, true)
|
||||
size2 := github_com_gogo_protobuf_proto.Size(p)
|
||||
dAtA, err := github_com_gogo_protobuf_proto.Marshal(p)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
size := p.Size()
|
||||
if len(dAtA) != size {
|
||||
t.Errorf("seed = %d, size %v != marshalled size %v", seed, size, len(dAtA))
|
||||
}
|
||||
if size2 != size {
|
||||
t.Errorf("seed = %d, size %v != before marshal proto.Size %v", seed, size, size2)
|
||||
}
|
||||
size3 := github_com_gogo_protobuf_proto.Size(p)
|
||||
if size3 != size {
|
||||
t.Errorf("seed = %d, size %v != after marshal proto.Size %v", seed, size, size3)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVoteInfoSize(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedVoteInfo(popr, true)
|
||||
size2 := github_com_gogo_protobuf_proto.Size(p)
|
||||
dAtA, err := github_com_gogo_protobuf_proto.Marshal(p)
|
||||
if err != nil {
|
||||
|
|
|
@ -2,58 +2,33 @@ package types
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"sort"
|
||||
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Validators is a list of validators that implements the Sort interface
|
||||
type Validators []Validator
|
||||
// ValidatorUpdates is a list of validators that implements the Sort interface
|
||||
type ValidatorUpdates []ValidatorUpdate
|
||||
|
||||
var _ sort.Interface = (Validators)(nil)
|
||||
var _ sort.Interface = (ValidatorUpdates)(nil)
|
||||
|
||||
// All these methods for Validators:
|
||||
// All these methods for ValidatorUpdates:
|
||||
// Len, Less and Swap
|
||||
// are for Validators to implement sort.Interface
|
||||
// are for ValidatorUpdates to implement sort.Interface
|
||||
// which will be used by the sort package.
|
||||
// See Issue https://github.com/tendermint/abci/issues/212
|
||||
|
||||
func (v Validators) Len() int {
|
||||
func (v ValidatorUpdates) Len() int {
|
||||
return len(v)
|
||||
}
|
||||
|
||||
// XXX: doesn't distinguish same validator with different power
|
||||
func (v Validators) Less(i, j int) bool {
|
||||
func (v ValidatorUpdates) Less(i, j int) bool {
|
||||
return bytes.Compare(v[i].PubKey.Data, v[j].PubKey.Data) <= 0
|
||||
}
|
||||
|
||||
func (v Validators) Swap(i, j int) {
|
||||
func (v ValidatorUpdates) Swap(i, j int) {
|
||||
v1 := v[i]
|
||||
v[i] = v[j]
|
||||
v[j] = v1
|
||||
}
|
||||
|
||||
func ValidatorsString(vs Validators) string {
|
||||
s := make([]validatorPretty, len(vs))
|
||||
for i, v := range vs {
|
||||
s[i] = validatorPretty{
|
||||
Address: v.Address,
|
||||
PubKey: v.PubKey.Data,
|
||||
Power: v.Power,
|
||||
}
|
||||
}
|
||||
b, err := json.Marshal(s)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
type validatorPretty struct {
|
||||
Address cmn.HexBytes `json:"address"`
|
||||
PubKey []byte `json:"pub_key"`
|
||||
Power int64 `json:"power"`
|
||||
}
|
||||
|
|
|
@ -354,7 +354,7 @@ func randConsensusNet(nValidators int, testName string, tickerFunc func() Timeou
|
|||
}
|
||||
ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
|
||||
app := appFunc()
|
||||
vals := types.TM2PB.Validators(state.Validators)
|
||||
vals := types.TM2PB.ValidatorUpdates(state.Validators)
|
||||
app.InitChain(abci.RequestInitChain{Validators: vals})
|
||||
|
||||
css[i] = newConsensusStateWithConfig(thisConfig, state, privVals[i], app)
|
||||
|
@ -386,7 +386,7 @@ func randConsensusNetWithPeers(nValidators, nPeers int, testName string, tickerF
|
|||
}
|
||||
|
||||
app := appFunc()
|
||||
vals := types.TM2PB.Validators(state.Validators)
|
||||
vals := types.TM2PB.ValidatorUpdates(state.Validators)
|
||||
app.InitChain(abci.RequestInitChain{Validators: vals})
|
||||
|
||||
css[i] = newConsensusStateWithConfig(thisConfig, state, privVal, app)
|
||||
|
|
|
@ -118,7 +118,7 @@ func TestReactorWithEvidence(t *testing.T) {
|
|||
thisConfig := ResetConfig(fmt.Sprintf("%s_%d", testName, i))
|
||||
ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
|
||||
app := appFunc()
|
||||
vals := types.TM2PB.Validators(state.Validators)
|
||||
vals := types.TM2PB.ValidatorUpdates(state.Validators)
|
||||
app.InitChain(abci.RequestInitChain{Validators: vals})
|
||||
|
||||
pv := privVals[i]
|
||||
|
|
|
@ -266,7 +266,7 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight
|
|||
|
||||
// If appBlockHeight == 0 it means that we are at genesis and hence should send InitChain.
|
||||
if appBlockHeight == 0 {
|
||||
nextVals := types.TM2PB.Validators(state.NextValidators) // state.Validators would work too.
|
||||
nextVals := types.TM2PB.ValidatorUpdates(state.NextValidators) // state.Validators would work too.
|
||||
csParams := types.TM2PB.ConsensusParams(h.genDoc.ConsensusParams)
|
||||
req := abci.RequestInitChain{
|
||||
Time: h.genDoc.GenesisTime,
|
||||
|
@ -282,7 +282,7 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight
|
|||
|
||||
// If the app returned validators or consensus params, update the state.
|
||||
if len(res.Validators) > 0 {
|
||||
vals, err := types.PB2TM.Validators(res.Validators)
|
||||
vals, err := types.PB2TM.ValidatorUpdates(res.Validators)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -416,7 +416,7 @@ func buildAppStateFromChain(proxyApp proxy.AppConns, stateDB dbm.DB,
|
|||
}
|
||||
defer proxyApp.Stop()
|
||||
|
||||
validators := types.TM2PB.Validators(state.Validators)
|
||||
validators := types.TM2PB.ValidatorUpdates(state.Validators)
|
||||
if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{
|
||||
Validators: validators,
|
||||
}); err != nil {
|
||||
|
@ -453,7 +453,7 @@ func buildTMStateFromChain(config *cfg.Config, stateDB dbm.DB, state sm.State, c
|
|||
}
|
||||
defer proxyApp.Stop()
|
||||
|
||||
validators := types.TM2PB.Validators(state.Validators)
|
||||
validators := types.TM2PB.ValidatorUpdates(state.Validators)
|
||||
if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{
|
||||
Validators: validators,
|
||||
}); err != nil {
|
||||
|
@ -639,7 +639,7 @@ func (bs *mockBlockStore) LoadSeenCommit(height int64) *types.Commit {
|
|||
func TestInitChainUpdateValidators(t *testing.T) {
|
||||
val, _ := types.RandValidator(true, 10)
|
||||
vals := types.NewValidatorSet([]*types.Validator{val})
|
||||
app := &initChainApp{vals: types.TM2PB.Validators(vals)}
|
||||
app := &initChainApp{vals: types.TM2PB.ValidatorUpdates(vals)}
|
||||
clientCreator := proxy.NewLocalClientCreator(app)
|
||||
|
||||
config := ResetConfig("proxy_test_")
|
||||
|
@ -666,7 +666,7 @@ func TestInitChainUpdateValidators(t *testing.T) {
|
|||
assert.Equal(t, newValAddr, expectValAddr)
|
||||
}
|
||||
|
||||
func newInitChainApp(vals []abci.Validator) *initChainApp {
|
||||
func newInitChainApp(vals []abci.ValidatorUpdate) *initChainApp {
|
||||
return &initChainApp{
|
||||
vals: vals,
|
||||
}
|
||||
|
@ -675,7 +675,7 @@ func newInitChainApp(vals []abci.Validator) *initChainApp {
|
|||
// returns the vals on InitChain
|
||||
type initChainApp struct {
|
||||
abci.BaseApplication
|
||||
vals []abci.Validator
|
||||
vals []abci.ValidatorUpdate
|
||||
}
|
||||
|
||||
func (ica *initChainApp) InitChain(req abci.RequestInitChain) abci.ResponseInitChain {
|
||||
|
|
|
@ -111,14 +111,21 @@ See below for more details on the message types and how they are used.
|
|||
- `Time (google.protobuf.Timestamp)`: Genesis time.
|
||||
- `ChainID (string)`: ID of the blockchain.
|
||||
- `ConsensusParams (ConsensusParams)`: Initial consensus-critical parameters.
|
||||
- `Validators ([]Validator)`: Initial genesis validators.
|
||||
- `Validators ([]ValidatorUpdate)`: Initial genesis validators.
|
||||
- `AppStateBytes ([]byte)`: Serialized initial application state. Amino-encoded JSON bytes.
|
||||
- **Response**:
|
||||
- `ConsensusParams (ConsensusParams)`: Initial
|
||||
consensus-critical parameters.
|
||||
- `Validators ([]Validator)`: Initial validator set.
|
||||
- `Validators ([]ValidatorUpdate)`: Initial validator set (if non empty).
|
||||
- **Usage**:
|
||||
- Called once upon genesis.
|
||||
- If ResponseInitChain.Validators is empty, the initial validator set will be the RequestInitChain.Validators
|
||||
- If ResponseInitChain.Validators is not empty, the initial validator set will be the
|
||||
ResponseInitChain.Validators (regardless of what is in RequestInitChain.Validators).
|
||||
- This allows the app to decide if it wants to accept the initial validator
|
||||
set proposed by tendermint (ie. in the genesis file), or if it wants to use
|
||||
a different one (perhaps computed based on some application specific
|
||||
information in the genesis file).
|
||||
|
||||
### Query
|
||||
|
||||
|
@ -161,9 +168,10 @@ See below for more details on the message types and how they are used.
|
|||
- `Hash ([]byte)`: The block's hash. This can be derived from the
|
||||
block header.
|
||||
- `Header (struct{})`: The block header.
|
||||
- `LastCommitInfo (LastCommitInfo)`: Info about the last commit.
|
||||
- `LastCommitInfo (LastCommitInfo)`: Info about the last commit, including the
|
||||
round, and the list of validators and which ones signed the last block.
|
||||
- `ByzantineValidators ([]Evidence)`: List of evidence of
|
||||
validators that acted maliciously
|
||||
validators that acted maliciously.
|
||||
- **Response**:
|
||||
- `Tags ([]cmn.KVPair)`: Key-Value tags for filtering and indexing
|
||||
- **Usage**:
|
||||
|
@ -237,7 +245,7 @@ See below for more details on the message types and how they are used.
|
|||
- **Request**:
|
||||
- `Height (int64)`: Height of the block just executed.
|
||||
- **Response**:
|
||||
- `ValidatorUpdates ([]Validator)`: Changes to validator set (set
|
||||
- `ValidatorUpdates ([]ValidatorUpdate)`: Changes to validator set (set
|
||||
voting power to 0 to remove).
|
||||
- `ConsensusParamUpdates (ConsensusParams)`: Changes to
|
||||
consensus-critical time, size, and other parameters.
|
||||
|
@ -246,7 +254,6 @@ See below for more details on the message types and how they are used.
|
|||
- Signals the end of a block.
|
||||
- Called prior to each Commit, after all transactions.
|
||||
- Validator set and consensus params are updated with the result.
|
||||
- Validator pubkeys are expected to be go-wire encoded.
|
||||
|
||||
### Commit
|
||||
|
||||
|
@ -271,12 +278,17 @@ See below for more details on the message types and how they are used.
|
|||
- `NumTxs (int32)`: Number of transactions in the block
|
||||
- `TotalTxs (int64)`: Total number of transactions in the blockchain until
|
||||
now
|
||||
- `LastBlockHash ([]byte)`: Hash of the previous (parent) block
|
||||
- `LastBlockID (BlockID)`: Hash of the previous (parent) block
|
||||
- `LastCommitHash ([]byte)`: Hash of the previous block's commit
|
||||
- `ValidatorsHash ([]byte)`: Hash of the validator set for this block
|
||||
- `NextValidatorsHash ([]byte)`: Hash of the validator set for the next block
|
||||
- `ConsensusHash ([]byte)`: Hash of the consensus parameters for this block
|
||||
- `AppHash ([]byte)`: Data returned by the last call to `Commit` - typically the
|
||||
Merkle root of the application state after executing the previous block's
|
||||
transactions
|
||||
- `Proposer (Validator)`: Original proposer for the block
|
||||
- `LastResultsHash ([]byte)`: Hash of the ABCI results returned by the last block
|
||||
- `EvidenceHash ([]byte)`: Hash of the evidence included in this block
|
||||
- `ProposerAddress ([]byte)`: Original proposer for the block
|
||||
- **Usage**:
|
||||
- Provided in RequestBeginBlock
|
||||
- Provides important context about the current state of the blockchain -
|
||||
|
@ -288,16 +300,27 @@ See below for more details on the message types and how they are used.
|
|||
|
||||
- **Fields**:
|
||||
- `Address ([]byte)`: Address of the validator (hash of the public key)
|
||||
- `Power (int64)`: Voting power of the validator
|
||||
- **Usage**:
|
||||
- Validator identified by address
|
||||
- Used in RequestBeginBlock as part of VoteInfo
|
||||
- Does not include PubKey to avoid sending potentially large quantum pubkeys
|
||||
over the ABCI
|
||||
|
||||
### ValidatorUpdate
|
||||
|
||||
- **Fields**:
|
||||
- `PubKey (PubKey)`: Public key of the validator
|
||||
- `Power (int64)`: Voting power of the validator
|
||||
- **Usage**:
|
||||
- Provides all identifying information about the validator
|
||||
- Validator identified by PubKey
|
||||
- Used to tell Tendermint to update the validator set
|
||||
|
||||
### SigningValidator
|
||||
### VoteInfo
|
||||
|
||||
- **Fields**:
|
||||
- `Validator (Validator)`: A validator
|
||||
- `SignedLastBlock (bool)`: Indicated whether or not the validator signed
|
||||
- `SignedLastBlock (bool)`: Indicates whether or not the validator signed
|
||||
the last block
|
||||
- **Usage**:
|
||||
- Indicates whether a validator signed the last block, allowing for rewards
|
||||
|
@ -330,6 +353,6 @@ See below for more details on the message types and how they are used.
|
|||
### LastCommitInfo
|
||||
|
||||
- **Fields**:
|
||||
- `CommitRound (int32)`: Commit round.
|
||||
- `Validators ([]SigningValidator)`: List of validators in the current
|
||||
validator set and whether or not they signed a vote.
|
||||
- `Round (int32)`: Commit round.
|
||||
- `Votes ([]VoteInfo)`: List of validators addresses in the last validator set
|
||||
with their voting power and whether or not they signed a vote.
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
## Changelog
|
||||
|
||||
016-08-2018: Follow up from review:
|
||||
- Revert changes to commit round
|
||||
- Remind about justification for removing pubkey
|
||||
- Update pros/cons
|
||||
05-08-2018: Initial draft
|
||||
|
||||
## Context
|
||||
|
@ -10,17 +14,14 @@ ADR 009 introduced major improvements to the ABCI around validators and the use
|
|||
of Amino. Here we follow up with some additional changes to improve the naming
|
||||
and expected use of Validator messages.
|
||||
|
||||
We also fix how we communicate the commit round - there is no defined commit
|
||||
round, as validators can commit the same block in different rounds, so we
|
||||
should communicate the round each validator committed in.
|
||||
|
||||
## Decision
|
||||
|
||||
### Validator
|
||||
|
||||
Currently a Validator contains address and `pub_key`, and one or the other is
|
||||
Currently a Validator contains `address` and `pub_key`, and one or the other is
|
||||
optional/not-sent depending on the use case. Instead, we should have a
|
||||
Validator (with just the address) and a ValidatorUpdate (with the pubkey):
|
||||
`Validator` (with just the address, used for RequestBeginBlock)
|
||||
and a `ValidatorUpdate` (with the pubkey, used for ResponseEndBlock):
|
||||
|
||||
```
|
||||
message Validator {
|
||||
|
@ -34,6 +35,13 @@ message ValidatorUpdate {
|
|||
}
|
||||
```
|
||||
|
||||
As noted in ADR-009[https://github.com/tendermint/tendermint/blob/develop/docs/architecture/adr-009-ABCI-design.md],
|
||||
the `Validator` does not contain a pubkey because quantum public keys are
|
||||
quite large and it would be wasteful to send them all over ABCI with every block.
|
||||
Thus, applications that want to take advantage of the information in BeginBlock
|
||||
are *required* to store pubkeys in state (or use much less efficient lazy means
|
||||
of verifying BeginBlock data).
|
||||
|
||||
### RequestBeginBlock
|
||||
|
||||
LastCommitInfo currently has an array of `SigningValidator` that contains
|
||||
|
@ -41,19 +49,17 @@ information for each validator in the entire validator set.
|
|||
Instead, this should be called `VoteInfo`, since it is information about the
|
||||
validator votes.
|
||||
|
||||
Additionally, we have a single CommitRound in the LastCommitInfo,
|
||||
but such a round does not exist. Instead, we
|
||||
should include the round associated with each commit vote:
|
||||
Note that all votes in a commit must be from the same round.
|
||||
|
||||
```
|
||||
message LastCommitInfo {
|
||||
int64 round
|
||||
repeated VoteInfo commit_votes
|
||||
}
|
||||
|
||||
message VoteInfo {
|
||||
Validator validator
|
||||
bool signed_last_block
|
||||
int64 round
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -62,6 +68,9 @@ message VoteInfo {
|
|||
Use ValidatorUpdates instead of Validators. Then it's clear we don't need an
|
||||
address, and we do need a pubkey.
|
||||
|
||||
We could require the address here as well as a sanity check, but it doesn't seem
|
||||
necessary.
|
||||
|
||||
### InitChain
|
||||
|
||||
Use ValidatorUpdates for both Request and Response. InitChain
|
||||
|
@ -76,16 +85,15 @@ Proposal.
|
|||
|
||||
### Positive
|
||||
|
||||
- Easier for developers to build on and understand the ABCI
|
||||
- Apps get more information about the votes (ie. the round they're from)
|
||||
- Clarifies the distinction between the different uses of validator information
|
||||
|
||||
### Negative
|
||||
|
||||
- There are two validator types
|
||||
- Apps must still store the public keys in state to utilize the RequestBeginBlock info
|
||||
|
||||
### Neutral
|
||||
|
||||
-
|
||||
- ResponseEndBlock does not require an address
|
||||
|
||||
## References
|
||||
|
||||
|
|
|
@ -52,14 +52,13 @@ objects in the `ResponseBeginBlock`:
|
|||
|
||||
```
|
||||
message Validator {
|
||||
bytes address = 1;
|
||||
PubKey pub_key = 2;
|
||||
int64 power = 3;
|
||||
PubKey pub_key
|
||||
int64 power
|
||||
}
|
||||
|
||||
message PubKey {
|
||||
string type = 1;
|
||||
bytes data = 2;
|
||||
string type
|
||||
bytes data
|
||||
}
|
||||
|
||||
```
|
||||
|
@ -99,9 +98,6 @@ If the list is not empty, Tendermint will adopt it for the validator set.
|
|||
This way the application can determine the initial validator set for the
|
||||
blockchain.
|
||||
|
||||
Note that if addressses are included in the returned validators, they must match
|
||||
the address of the public key.
|
||||
|
||||
ResponseInitChain also includes ConsensusParams, but these are presently
|
||||
ignored.
|
||||
|
||||
|
|
|
@ -184,16 +184,13 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
|||
}
|
||||
proxyAppConn.SetResponseCallback(proxyCb)
|
||||
|
||||
signVals, byzVals := getBeginBlockValidatorInfo(block, lastValSet, stateDB)
|
||||
commitInfo, byzVals := getBeginBlockValidatorInfo(block, lastValSet, stateDB)
|
||||
|
||||
// Begin block.
|
||||
_, err := proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
|
||||
Hash: block.Hash(),
|
||||
Header: types.TM2PB.Header(&block.Header),
|
||||
LastCommitInfo: abci.LastCommitInfo{
|
||||
CommitRound: int32(block.LastCommit.Round()),
|
||||
Validators: signVals,
|
||||
},
|
||||
LastCommitInfo: commitInfo,
|
||||
ByzantineValidators: byzVals,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -220,13 +217,14 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
|||
|
||||
valUpdates := abciResponses.EndBlock.ValidatorUpdates
|
||||
if len(valUpdates) > 0 {
|
||||
logger.Info("Updates to validators", "updates", abci.ValidatorsString(valUpdates))
|
||||
// TODO: cleanup the formatting
|
||||
logger.Info("Updates to validators", "updates", valUpdates)
|
||||
}
|
||||
|
||||
return abciResponses, nil
|
||||
}
|
||||
|
||||
func getBeginBlockValidatorInfo(block *types.Block, lastValSet *types.ValidatorSet, stateDB dbm.DB) ([]abci.SigningValidator, []abci.Evidence) {
|
||||
func getBeginBlockValidatorInfo(block *types.Block, lastValSet *types.ValidatorSet, stateDB dbm.DB) (abci.LastCommitInfo, []abci.Evidence) {
|
||||
|
||||
// Sanity check that commit length matches validator set size -
|
||||
// only applies after first block
|
||||
|
@ -240,18 +238,23 @@ func getBeginBlockValidatorInfo(block *types.Block, lastValSet *types.ValidatorS
|
|||
}
|
||||
}
|
||||
|
||||
// determine which validators did not sign last block.
|
||||
signVals := make([]abci.SigningValidator, len(lastValSet.Validators))
|
||||
// Collect the vote info (list of validators and whether or not they signed).
|
||||
voteInfos := make([]abci.VoteInfo, len(lastValSet.Validators))
|
||||
for i, val := range lastValSet.Validators {
|
||||
var vote *types.Vote
|
||||
if i < len(block.LastCommit.Precommits) {
|
||||
vote = block.LastCommit.Precommits[i]
|
||||
}
|
||||
val := abci.SigningValidator{
|
||||
Validator: types.TM2PB.ValidatorWithoutPubKey(val),
|
||||
voteInfo := abci.VoteInfo{
|
||||
Validator: types.TM2PB.Validator(val),
|
||||
SignedLastBlock: vote != nil,
|
||||
}
|
||||
signVals[i] = val
|
||||
voteInfos[i] = voteInfo
|
||||
}
|
||||
|
||||
commitInfo := abci.LastCommitInfo{
|
||||
Round: int32(block.LastCommit.Round()),
|
||||
Votes: voteInfos,
|
||||
}
|
||||
|
||||
byzVals := make([]abci.Evidence, len(block.Evidence.Evidence))
|
||||
|
@ -266,15 +269,15 @@ func getBeginBlockValidatorInfo(block *types.Block, lastValSet *types.ValidatorS
|
|||
byzVals[i] = types.TM2PB.Evidence(ev, valset, block.Time)
|
||||
}
|
||||
|
||||
return signVals, byzVals
|
||||
return commitInfo, byzVals
|
||||
|
||||
}
|
||||
|
||||
// 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, abciUpdates []abci.Validator) error {
|
||||
updates, err := types.PB2TM.Validators(abciUpdates)
|
||||
func updateValidators(currentSet *types.ValidatorSet, abciUpdates []abci.ValidatorUpdate) error {
|
||||
updates, err := types.PB2TM.ValidatorUpdates(abciUpdates)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -381,9 +384,10 @@ func fireEvents(logger log.Logger, eventBus types.BlockEventPublisher, block *ty
|
|||
}})
|
||||
}
|
||||
|
||||
if len(abciResponses.EndBlock.ValidatorUpdates) > 0 {
|
||||
abciValUpdates := abciResponses.EndBlock.ValidatorUpdates
|
||||
if len(abciValUpdates) > 0 {
|
||||
// if there were an error, we would've stopped in updateValidators
|
||||
updates, _ := types.PB2TM.Validators(abciResponses.EndBlock.ValidatorUpdates)
|
||||
updates, _ := types.PB2TM.ValidatorUpdates(abciValUpdates)
|
||||
eventBus.PublishEventValidatorSetUpdates(
|
||||
types.EventDataValidatorSetUpdates{ValidatorUpdates: updates})
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ func TestBeginBlockValidators(t *testing.T) {
|
|||
|
||||
// -> app receives a list of validators with a bool indicating if they signed
|
||||
ctr := 0
|
||||
for i, v := range app.Validators {
|
||||
for i, v := range app.CommitVotes {
|
||||
if ctr < len(tc.expectedAbsentValidators) &&
|
||||
tc.expectedAbsentValidators[ctr] == i {
|
||||
|
||||
|
@ -160,7 +160,7 @@ func TestUpdateValidators(t *testing.T) {
|
|||
name string
|
||||
|
||||
currentSet *types.ValidatorSet
|
||||
abciUpdates []abci.Validator
|
||||
abciUpdates []abci.ValidatorUpdate
|
||||
|
||||
resultingSet *types.ValidatorSet
|
||||
shouldErr bool
|
||||
|
@ -169,7 +169,7 @@ func TestUpdateValidators(t *testing.T) {
|
|||
"adding a validator is OK",
|
||||
|
||||
types.NewValidatorSet([]*types.Validator{val1}),
|
||||
[]abci.Validator{{Address: []byte{}, PubKey: types.TM2PB.PubKey(pubkey2), Power: 20}},
|
||||
[]abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey2), Power: 20}},
|
||||
|
||||
types.NewValidatorSet([]*types.Validator{val1, val2}),
|
||||
false,
|
||||
|
@ -178,7 +178,7 @@ func TestUpdateValidators(t *testing.T) {
|
|||
"updating a validator is OK",
|
||||
|
||||
types.NewValidatorSet([]*types.Validator{val1}),
|
||||
[]abci.Validator{{Address: []byte{}, PubKey: types.TM2PB.PubKey(pubkey1), Power: 20}},
|
||||
[]abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey1), Power: 20}},
|
||||
|
||||
types.NewValidatorSet([]*types.Validator{types.NewValidator(pubkey1, 20)}),
|
||||
false,
|
||||
|
@ -187,7 +187,7 @@ func TestUpdateValidators(t *testing.T) {
|
|||
"removing a validator is OK",
|
||||
|
||||
types.NewValidatorSet([]*types.Validator{val1, val2}),
|
||||
[]abci.Validator{{Address: []byte{}, PubKey: types.TM2PB.PubKey(pubkey2), Power: 0}},
|
||||
[]abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey2), Power: 0}},
|
||||
|
||||
types.NewValidatorSet([]*types.Validator{val1}),
|
||||
false,
|
||||
|
@ -197,7 +197,7 @@ func TestUpdateValidators(t *testing.T) {
|
|||
"removing a non-existing validator results in error",
|
||||
|
||||
types.NewValidatorSet([]*types.Validator{val1}),
|
||||
[]abci.Validator{{Address: []byte{}, PubKey: types.TM2PB.PubKey(pubkey2), Power: 0}},
|
||||
[]abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey2), Power: 0}},
|
||||
|
||||
types.NewValidatorSet([]*types.Validator{val1}),
|
||||
true,
|
||||
|
@ -207,7 +207,7 @@ func TestUpdateValidators(t *testing.T) {
|
|||
"adding a validator with negative power results in error",
|
||||
|
||||
types.NewValidatorSet([]*types.Validator{val1}),
|
||||
[]abci.Validator{{Address: []byte{}, PubKey: types.TM2PB.PubKey(pubkey2), Power: -100}},
|
||||
[]abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey2), Power: -100}},
|
||||
|
||||
types.NewValidatorSet([]*types.Validator{val1}),
|
||||
true,
|
||||
|
@ -260,7 +260,7 @@ func TestEndBlockValidatorUpdates(t *testing.T) {
|
|||
blockID := types.BlockID{block.Hash(), block.MakePartSet(testPartSize).Header()}
|
||||
|
||||
pubkey := ed25519.GenPrivKey().PubKey()
|
||||
app.ValidatorUpdates = []abci.Validator{
|
||||
app.ValidatorUpdates = []abci.ValidatorUpdate{
|
||||
{PubKey: types.TM2PB.PubKey(pubkey), Power: 10},
|
||||
}
|
||||
|
||||
|
@ -335,9 +335,9 @@ func makeBlock(state State, height int64) *types.Block {
|
|||
type testApp struct {
|
||||
abci.BaseApplication
|
||||
|
||||
Validators []abci.SigningValidator
|
||||
CommitVotes []abci.VoteInfo
|
||||
ByzantineValidators []abci.Evidence
|
||||
ValidatorUpdates []abci.Validator
|
||||
ValidatorUpdates []abci.ValidatorUpdate
|
||||
}
|
||||
|
||||
var _ abci.Application = (*testApp)(nil)
|
||||
|
@ -347,7 +347,7 @@ func (app *testApp) Info(req abci.RequestInfo) (resInfo abci.ResponseInfo) {
|
|||
}
|
||||
|
||||
func (app *testApp) BeginBlock(req abci.RequestBeginBlock) abci.ResponseBeginBlock {
|
||||
app.Validators = req.LastCommitInfo.Validators
|
||||
app.CommitVotes = req.LastCommitInfo.Votes
|
||||
app.ByzantineValidators = req.ByzantineValidators
|
||||
return abci.ResponseBeginBlock{}
|
||||
}
|
||||
|
|
|
@ -78,8 +78,8 @@ func TestABCIResponsesSaveLoad1(t *testing.T) {
|
|||
abciResponses := NewABCIResponses(block)
|
||||
abciResponses.DeliverTx[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Tags: nil}
|
||||
abciResponses.DeliverTx[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Tags: nil}
|
||||
abciResponses.EndBlock = &abci.ResponseEndBlock{ValidatorUpdates: []abci.Validator{
|
||||
types.TM2PB.ValidatorFromPubKeyAndPower(ed25519.GenPrivKey().PubKey(), 10),
|
||||
abciResponses.EndBlock = &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{
|
||||
types.TM2PB.NewValidatorUpdate(ed25519.GenPrivKey().PubKey(), 10),
|
||||
}}
|
||||
|
||||
saveABCIResponses(stateDB, block.Height, abciResponses)
|
||||
|
@ -454,9 +454,9 @@ func makeHeaderPartsResponsesValPubKeyChange(state State, height int64,
|
|||
_, val := state.NextValidators.GetByIndex(0)
|
||||
if !bytes.Equal(pubkey.Bytes(), val.PubKey.Bytes()) {
|
||||
abciResponses.EndBlock = &abci.ResponseEndBlock{
|
||||
ValidatorUpdates: []abci.Validator{
|
||||
types.TM2PB.ValidatorFromPubKeyAndPower(val.PubKey, 0),
|
||||
types.TM2PB.ValidatorFromPubKeyAndPower(pubkey, 10),
|
||||
ValidatorUpdates: []abci.ValidatorUpdate{
|
||||
types.TM2PB.NewValidatorUpdate(val.PubKey, 0),
|
||||
types.TM2PB.NewValidatorUpdate(pubkey, 10),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -476,8 +476,8 @@ func makeHeaderPartsResponsesValPowerChange(state State, height int64,
|
|||
_, val := state.NextValidators.GetByIndex(0)
|
||||
if val.VotingPower != power {
|
||||
abciResponses.EndBlock = &abci.ResponseEndBlock{
|
||||
ValidatorUpdates: []abci.Validator{
|
||||
types.TM2PB.ValidatorFromPubKeyAndPower(val.PubKey, power),
|
||||
ValidatorUpdates: []abci.ValidatorUpdate{
|
||||
types.TM2PB.NewValidatorUpdate(val.PubKey, power),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,13 +30,14 @@ message Header {
|
|||
|
||||
// hashes from the app output from the prev block
|
||||
bytes ValidatorsHash = 9; // validators for the current block
|
||||
bytes ConsensusHash = 10; // consensus params for current block
|
||||
bytes AppHash = 11; // state after txs from the previous block
|
||||
bytes LastResultsHash = 12; // root hash of all results from the txs from the previous block
|
||||
bytes NextValidatorsHash = 10; // validators for the next block
|
||||
bytes ConsensusHash = 11; // consensus params for current block
|
||||
bytes AppHash = 12; // state after txs from the previous block
|
||||
bytes LastResultsHash = 13; // root hash of all results from the txs from the previous block
|
||||
|
||||
// consensus info
|
||||
bytes EvidenceHash = 13; // evidence included in the block
|
||||
bytes ProposerAddress = 14; // original proposer of the block
|
||||
bytes EvidenceHash = 14; // evidence included in the block
|
||||
bytes ProposerAddress = 15; // original proposer of the block
|
||||
}
|
||||
|
||||
// Timestamp wraps how amino encodes time. Note that this is different from the protobuf well-known type
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
@ -56,7 +55,7 @@ func (tm2pb) Header(header *Header) abci.Header {
|
|||
}
|
||||
}
|
||||
|
||||
func (tm2pb) ValidatorWithoutPubKey(val *Validator) abci.Validator {
|
||||
func (tm2pb) Validator(val *Validator) abci.Validator {
|
||||
return abci.Validator{
|
||||
Address: val.PubKey.Address(),
|
||||
Power: val.VotingPower,
|
||||
|
@ -78,9 +77,8 @@ func (tm2pb) PartSetHeader(header PartSetHeader) abci.PartSetHeader {
|
|||
}
|
||||
|
||||
// XXX: panics on unknown pubkey type
|
||||
func (tm2pb) Validator(val *Validator) abci.Validator {
|
||||
return abci.Validator{
|
||||
Address: val.PubKey.Address(),
|
||||
func (tm2pb) ValidatorUpdate(val *Validator) abci.ValidatorUpdate {
|
||||
return abci.ValidatorUpdate{
|
||||
PubKey: TM2PB.PubKey(val.PubKey),
|
||||
Power: val.VotingPower,
|
||||
}
|
||||
|
@ -106,10 +104,10 @@ func (tm2pb) PubKey(pubKey crypto.PubKey) abci.PubKey {
|
|||
}
|
||||
|
||||
// XXX: panics on nil or unknown pubkey type
|
||||
func (tm2pb) Validators(vals *ValidatorSet) []abci.Validator {
|
||||
validators := make([]abci.Validator, vals.Size())
|
||||
func (tm2pb) ValidatorUpdates(vals *ValidatorSet) []abci.ValidatorUpdate {
|
||||
validators := make([]abci.ValidatorUpdate, vals.Size())
|
||||
for i, val := range vals.Validators {
|
||||
validators[i] = TM2PB.Validator(val)
|
||||
validators[i] = TM2PB.ValidatorUpdate(val)
|
||||
}
|
||||
return validators
|
||||
}
|
||||
|
@ -156,7 +154,7 @@ func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci.
|
|||
|
||||
return abci.Evidence{
|
||||
Type: evType,
|
||||
Validator: TM2PB.ValidatorWithoutPubKey(val),
|
||||
Validator: TM2PB.Validator(val),
|
||||
Height: ev.Height(),
|
||||
Time: evTime,
|
||||
TotalVotingPower: valSet.TotalVotingPower(),
|
||||
|
@ -164,10 +162,9 @@ func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci.
|
|||
}
|
||||
|
||||
// XXX: panics on nil or unknown pubkey type
|
||||
func (tm2pb) ValidatorFromPubKeyAndPower(pubkey crypto.PubKey, power int64) abci.Validator {
|
||||
func (tm2pb) NewValidatorUpdate(pubkey crypto.PubKey, power int64) abci.ValidatorUpdate {
|
||||
pubkeyABCI := TM2PB.PubKey(pubkey)
|
||||
return abci.Validator{
|
||||
Address: pubkey.Address(),
|
||||
return abci.ValidatorUpdate{
|
||||
PubKey: pubkeyABCI,
|
||||
Power: power,
|
||||
}
|
||||
|
@ -205,26 +202,14 @@ func (pb2tm) PubKey(pubKey abci.PubKey) (crypto.PubKey, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func (pb2tm) Validators(vals []abci.Validator) ([]*Validator, error) {
|
||||
func (pb2tm) ValidatorUpdates(vals []abci.ValidatorUpdate) ([]*Validator, error) {
|
||||
tmVals := make([]*Validator, len(vals))
|
||||
for i, v := range vals {
|
||||
pub, err := PB2TM.PubKey(v.PubKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// If the app provided an address too, it must match.
|
||||
// This is just a sanity check.
|
||||
if len(v.Address) > 0 {
|
||||
if !bytes.Equal(pub.Address(), v.Address) {
|
||||
return nil, fmt.Errorf("Validator.Address (%X) does not match PubKey.Address (%X)",
|
||||
v.Address, pub.Address())
|
||||
}
|
||||
}
|
||||
tmVals[i] = &Validator{
|
||||
Address: pub.Address(),
|
||||
PubKey: pub,
|
||||
VotingPower: v.Power,
|
||||
}
|
||||
tmVals[i] = NewValidator(pub, v.Power)
|
||||
}
|
||||
return tmVals, nil
|
||||
}
|
||||
|
|
|
@ -41,26 +41,26 @@ func TestABCIValidators(t *testing.T) {
|
|||
VotingPower: 10,
|
||||
}
|
||||
|
||||
abciVal := TM2PB.Validator(tmVal)
|
||||
tmVals, err := PB2TM.Validators([]abci.Validator{abciVal})
|
||||
abciVal := TM2PB.ValidatorUpdate(tmVal)
|
||||
tmVals, err := PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{abciVal})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tmValExpected, tmVals[0])
|
||||
|
||||
abciVals := TM2PB.Validators(NewValidatorSet(tmVals))
|
||||
assert.Equal(t, []abci.Validator{abciVal}, abciVals)
|
||||
abciVals := TM2PB.ValidatorUpdates(NewValidatorSet(tmVals))
|
||||
assert.Equal(t, []abci.ValidatorUpdate{abciVal}, abciVals)
|
||||
|
||||
// val with address
|
||||
tmVal.Address = pkEd.Address()
|
||||
|
||||
abciVal = TM2PB.Validator(tmVal)
|
||||
tmVals, err = PB2TM.Validators([]abci.Validator{abciVal})
|
||||
abciVal = TM2PB.ValidatorUpdate(tmVal)
|
||||
tmVals, err = PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{abciVal})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tmValExpected, tmVals[0])
|
||||
|
||||
// val with incorrect address
|
||||
abciVal = TM2PB.Validator(tmVal)
|
||||
abciVal.Address = []byte("incorrect!")
|
||||
tmVals, err = PB2TM.Validators([]abci.Validator{abciVal})
|
||||
// val with incorrect pubkey data
|
||||
abciVal = TM2PB.ValidatorUpdate(tmVal)
|
||||
abciVal.PubKey.Data = []byte("incorrect!")
|
||||
tmVals, err = PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{abciVal})
|
||||
assert.NotNil(t, err)
|
||||
assert.Nil(t, tmVals)
|
||||
}
|
||||
|
@ -104,9 +104,6 @@ func TestABCIEvidence(t *testing.T) {
|
|||
)
|
||||
|
||||
assert.Equal(t, "duplicate/vote", abciEv.Type)
|
||||
|
||||
// test we do not send pubkeys
|
||||
assert.Empty(t, abciEv.Validator.PubKey)
|
||||
}
|
||||
|
||||
type pubKeyEddie struct{}
|
||||
|
@ -119,17 +116,17 @@ func (pubKeyEddie) Equals(crypto.PubKey) bool { return false }
|
|||
func TestABCIValidatorFromPubKeyAndPower(t *testing.T) {
|
||||
pubkey := ed25519.GenPrivKey().PubKey()
|
||||
|
||||
abciVal := TM2PB.ValidatorFromPubKeyAndPower(pubkey, 10)
|
||||
abciVal := TM2PB.NewValidatorUpdate(pubkey, 10)
|
||||
assert.Equal(t, int64(10), abciVal.Power)
|
||||
|
||||
assert.Panics(t, func() { TM2PB.ValidatorFromPubKeyAndPower(nil, 10) })
|
||||
assert.Panics(t, func() { TM2PB.ValidatorFromPubKeyAndPower(pubKeyEddie{}, 10) })
|
||||
assert.Panics(t, func() { TM2PB.NewValidatorUpdate(nil, 10) })
|
||||
assert.Panics(t, func() { TM2PB.NewValidatorUpdate(pubKeyEddie{}, 10) })
|
||||
}
|
||||
|
||||
func TestABCIValidatorWithoutPubKey(t *testing.T) {
|
||||
pkEd := ed25519.GenPrivKey().PubKey()
|
||||
|
||||
abciVal := TM2PB.ValidatorWithoutPubKey(&Validator{
|
||||
abciVal := TM2PB.Validator(&Validator{
|
||||
Address: pkEd.Address(),
|
||||
PubKey: pkEd,
|
||||
VotingPower: 10,
|
||||
|
|
Loading…
Reference in New Issue