Browse Source

Merge pull request #2159 from tendermint/bucky/abci-validators

Bucky/abci validators
pull/2243/merge
Ethan Buchman 6 years ago
committed by GitHub
parent
commit
debe56326f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 938 additions and 558 deletions
  1. +4
    -0
      CHANGELOG_PENDING.md
  2. +7
    -4
      Makefile
  3. +4
    -6
      abci/example/kvstore/helpers.go
  4. +9
    -9
      abci/example/kvstore/kvstore_test.go
  5. +6
    -6
      abci/example/kvstore/persistent_kvstore.go
  6. +2
    -2
      abci/tests/server/client.go
  7. +2
    -2
      abci/types/pubkey.go
  8. +586
    -331
      abci/types/types.pb.go
  9. +20
    -13
      abci/types/types.proto
  10. +141
    -17
      abci/types/typespb_test.go
  11. +8
    -33
      abci/types/util.go
  12. +2
    -2
      consensus/common_test.go
  13. +1
    -1
      consensus/reactor_test.go
  14. +2
    -2
      consensus/replay.go
  15. +5
    -5
      consensus/replay_test.go
  16. +37
    -14
      docs/app-dev/abci-spec.md
  17. +22
    -14
      docs/architecture/adr-018-ABCI-Validators.md
  18. +4
    -8
      docs/spec/software/abci.md
  19. +23
    -19
      state/execution.go
  20. +11
    -11
      state/execution_test.go
  21. +7
    -7
      state/state_test.go
  22. +6
    -5
      types/proto3/block.proto
  23. +15
    -30
      types/protobuf.go
  24. +14
    -17
      types/protobuf_test.go

+ 4
- 0
CHANGELOG_PENDING.md View File

@ -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))


+ 7
- 4
Makefile View File

@ -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


+ 4
- 6
abci/example/kvstore/helpers.go View File

@ -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)
}


+ 9
- 9
abci/example/kvstore/kvstore_test.go View File

@ -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) ||


+ 6
- 6
abci/example/kvstore/persistent_kvstore.go View File

@ -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


+ 2
- 2
abci/tests/server/client.go View File

@ -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,


+ 2
- 2
abci/types/pubkey.go View File

@ -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,


+ 586
- 331
abci/types/types.pb.go
File diff suppressed because it is too large
View File


+ 20
- 13
abci/types/types.proto View File

@ -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;
}


+ 141
- 17
abci/types/typespb_test.go View File

@ -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 := 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 := NewPopulatedSigningValidator(popr, true)
p := NewPopulatedVoteInfo(popr, true)
size2 := github_com_gogo_protobuf_proto.Size(p)
dAtA, err := github_com_gogo_protobuf_proto.Marshal(p)
if err != nil {


+ 8
- 33
abci/types/util.go View File

@ -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"`
}

+ 2
- 2
consensus/common_test.go View File

@ -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)


+ 1
- 1
consensus/reactor_test.go View File

@ -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]


+ 2
- 2
consensus/replay.go View File

@ -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
}


+ 5
- 5
consensus/replay_test.go View File

@ -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 {


+ 37
- 14
docs/app-dev/abci-spec.md View File

@ -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.

+ 22
- 14
docs/architecture/adr-018-ABCI-Validators.md View File

@ -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


+ 4
- 8
docs/spec/software/abci.md View File

@ -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.


+ 23
- 19
state/execution.go View File

@ -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,
},
Hash: block.Hash(),
Header: types.TM2PB.Header(&block.Header),
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})
}


+ 11
- 11
state/execution_test.go View File

@ -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{}
}


+ 7
- 7
state/state_test.go View File

@ -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),
},
}
}


+ 6
- 5
types/proto3/block.proto View File

@ -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


+ 15
- 30
types/protobuf.go View File

@ -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,11 +77,10 @@ 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(),
PubKey: TM2PB.PubKey(val.PubKey),
Power: val.VotingPower,
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,12 +162,11 @@ 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(),
PubKey: pubkeyABCI,
Power: power,
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
}


+ 14
- 17
types/protobuf_test.go View File

@ -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…
Cancel
Save