Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: remove NextVoters from state #100

Merged
merged 20 commits into from
Jul 8, 2020
Merged
6 changes: 4 additions & 2 deletions CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@
### BREAKING CHANGES:

- State
- [state] [\#92](https://github.com/line/tendermint/pull/92) Genesis state
- [state] [\#100](https://github.com/line/tendermint/pull/100) Remove `NextVoters` from state

- CLI/RPC/Config

- Apps

- P2P Protocol

- [abci] [\#100](https://github.com/line/tendermint/pull/100) Add `voters_hash` field, which is needed for verification of a block header

- Go API

- Blockchain Protocol

### FEATURES:
- [BLS] [\#81](https://github.com/line/tendermint/issues/81) Modify to generate at the same time as Ed25519 key generation
- [lite] [\#100](https://github.com/line/tendermint/pull/100) Lite calls `Genesis()` rpc when it starts up

### IMPROVEMENTS:

Expand Down
483 changes: 272 additions & 211 deletions abci/types/types.pb.go

Large diffs are not rendered by default.

19 changes: 10 additions & 9 deletions abci/types/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -267,19 +267,20 @@ message Header {
BlockID last_block_id = 5 [(gogoproto.nullable) = false];

// hashes of block data
bytes last_commit_hash = 6; // commit from validators from the last block
bytes data_hash = 7; // transactions
bytes last_commit_hash = 6; // commit from validators from the last block
bytes data_hash = 7; // transactions

// hashes from the app output from the prev block
bytes validators_hash = 8; // validators for the current block
bytes next_validators_hash = 9; // validators for the next 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 voters_hash = 8; // voters for the current block
bytes validators_hash = 9; // validators for the current 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property was added in #99. So, if #99 is merged, check it later, please.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I'll check it after merging


// 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 Version {
Expand Down
2 changes: 1 addition & 1 deletion cmd/contract_tests/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package main
import (
"encoding/json"
"fmt"
"github.com/tendermint/tendermint/cmd/contract_tests/unmarshaler"
"strings"

"github.com/snikch/goodman/hooks"
"github.com/snikch/goodman/transaction"
"github.com/tendermint/tendermint/cmd/contract_tests/unmarshaler"
)

func main() {
Expand Down
1 change: 1 addition & 0 deletions cmd/contract_tests/unmarshaler/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package unmarshaler

import (
"encoding/json"

"gopkg.in/yaml.v3"
)

Expand Down
20 changes: 16 additions & 4 deletions cmd/tendermint/commands/lite.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,20 @@ func runProxy(cmd *cobra.Command, args []string) error {
return errors.Wrap(err, "new goleveldb")
}

rpcClient, err := rpchttp.New(primaryAddr, "/websocket")
if err != nil {
return errors.Wrapf(err, "http client for %s", primaryAddr)
}
// start rpcClient to get genesis
if err := rpcClient.Start(); err != nil {
return errors.Wrapf(err, "cannot start rpc client")
}

genDocResult, err := rpcClient.Genesis()
if err != nil {
return errors.Wrapf(err, "cannot get genesis")
}

var c *lite.Client
if trustedHeight > 0 && len(trustedHash) > 0 { // fresh installation
c, err = lite.NewHTTPClient(
Expand All @@ -117,6 +131,7 @@ func runProxy(cmd *cobra.Command, args []string) error {
primaryAddr,
witnessesAddrs,
dbs.New(db, chainID),
genDocResult.Genesis.VoterParams,
lite.Logger(logger),
)
} else { // continue from latest state
Expand All @@ -126,17 +141,14 @@ func runProxy(cmd *cobra.Command, args []string) error {
primaryAddr,
witnessesAddrs,
dbs.New(db, chainID),
genDocResult.Genesis.VoterParams,
lite.Logger(logger),
)
}
if err != nil {
return err
}

rpcClient, err := rpchttp.New(primaryAddr, "/websocket")
if err != nil {
return errors.Wrapf(err, "http client for %s", primaryAddr)
}
p := lproxy.Proxy{
Addr: listenAddr,
Config: &rpcserver.Config{MaxOpenConnections: maxOpenConnections},
Expand Down
3 changes: 1 addition & 2 deletions consensus/replay.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,10 +329,9 @@ func (h *Handshaker) ReplayBlocks(
return nil, err
}
state.Validators = types.NewValidatorSet(vals)
state.Voters = types.ToVoterAll(state.Validators.Validators)
state.Voters = types.SelectVoter(state.Validators, h.genDoc.Hash(), state.VoterParams)
// Should sync it with MakeGenesisState()
state.NextValidators = types.NewValidatorSet(vals)
state.NextVoters = types.SelectVoter(state.NextValidators, h.genDoc.Hash(), state.VoterParams)
} else if len(h.genDoc.Validators) == 0 {
// If validator set is not set in genesis and still empty after InitChain, exit.
return nil, fmt.Errorf("validator set is nil in genesis and still empty after InitChain")
Expand Down
6 changes: 4 additions & 2 deletions crypto/bls/bls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package bls_test
import (
"bytes"
"fmt"
amino "github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/crypto/ed25519"

"testing"

"github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/crypto/ed25519"

b "github.com/herumi/bls-eth-go-binary/bls"

"github.com/stretchr/testify/assert"
Expand Down
4 changes: 4 additions & 0 deletions evidence/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/stretchr/testify/assert"
"github.com/tendermint/tendermint/libs/rand"

dbm "github.com/tendermint/tm-db"

Expand All @@ -30,10 +31,13 @@ func initializeValidatorState(valAddr []byte, height int64) dbm.DB {
{Address: valAddr, StakingPower: 1},
}
state := sm.State{
VoterParams: types.DefaultVoterParams(),
LastBlockHeight: 0,
LastBlockTime: tmtime.Now(),
LastProofHash: rand.Bytes(10),
Validators: types.NewValidatorSet(vals),
NextValidators: types.NewValidatorSet(vals),
Voters: types.ToVoterAll(vals),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't you use types.SelectVoter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existing test code used ToVoterAll uniformly to replace the a validator set with a voter set. I think it would be better to specify the meaning of changing all validators to voters.

LastHeightValidatorsChanged: 1,
ConsensusParams: types.ConsensusParams{
Evidence: types.EvidenceParams{
Expand Down
35 changes: 24 additions & 11 deletions lite/base_verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package lite
import (
"bytes"

"github.com/tendermint/tendermint/crypto/vrf"

"github.com/pkg/errors"

lerr "github.com/tendermint/tendermint/lite/errors"
Expand All @@ -17,21 +19,24 @@ var _ Verifier = (*BaseVerifier)(nil)
// use the DynamicVerifier.
// TODO: Handle unbonding time.
type BaseVerifier struct {
chainID string
height int64
voterSet *types.VoterSet
chainID string
height int64
valSet *types.ValidatorSet
voterParams *types.VoterParams
}

// NewBaseVerifier returns a new Verifier initialized with a validator set at
// some height.
func NewBaseVerifier(chainID string, height int64, valset *types.VoterSet) *BaseVerifier {
func NewBaseVerifier(chainID string, height int64, valset *types.ValidatorSet,
voterParams *types.VoterParams) *BaseVerifier {
if valset.IsNilOrEmpty() {
panic("NewBaseVerifier requires a valid voterSet")
}
return &BaseVerifier{
chainID: chainID,
height: height,
voterSet: valset,
chainID: chainID,
height: height,
valSet: valset,
voterParams: voterParams,
}
}

Expand All @@ -56,9 +61,8 @@ func (bv *BaseVerifier) Verify(signedHeader types.SignedHeader) error {
}

// We can't verify with the wrong validator set.
if !bytes.Equal(signedHeader.VotersHash,
bv.voterSet.Hash()) {
return lerr.ErrUnexpectedValidators(signedHeader.VotersHash, bv.voterSet.Hash())
if !bytes.Equal(signedHeader.ValidatorsHash, bv.valSet.Hash()) {
return lerr.ErrUnexpectedValidators(signedHeader.ValidatorsHash, bv.valSet.Hash())
}

// Do basic sanity checks.
Expand All @@ -67,8 +71,17 @@ func (bv *BaseVerifier) Verify(signedHeader types.SignedHeader) error {
return errors.Wrap(err, "in verify")
}

proofHash, err := vrf.ProofToHash(signedHeader.Proof.Bytes())
if err != nil {
return errors.Wrap(err, "in verify")
}
voters := types.SelectVoter(bv.valSet, proofHash, bv.voterParams)
if !bytes.Equal(signedHeader.VotersHash, voters.Hash()) {
return errors.Errorf("header's voter hash is %X, but voters hash is %X",
signedHeader.VotersHash, voters.Hash())
}
// Check commit signatures.
err = bv.voterSet.VerifyCommit(
err = voters.VerifyCommit(
bv.chainID, signedHeader.Commit.BlockID,
signedHeader.Height, signedHeader.Commit)
if err != nil {
Expand Down
19 changes: 7 additions & 12 deletions lite/base_verifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ func TestBaseCert(t *testing.T) {

keys := genPrivKeys(4)
// 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
vals := types.ToVoterAll(keys.ToValidators(20, 10).Validators)
vals := types.NewValidatorSet(keys.ToValidators(20, 10).Validators)
// and a Verifier based on our known set
chainID := "test-static"
cert := NewBaseVerifier(chainID, 2, vals)
cert := NewBaseVerifier(chainID, 2, vals, types.DefaultVoterParams())

cases := []struct {
keys privKeys
vals *types.VoterSet
vals *types.ValidatorSet
height int64
first, last int // who actually signs
proper bool // true -> expect no error
Expand All @@ -41,19 +41,14 @@ func TestBaseCert(t *testing.T) {
{keys, vals, 4, 0, len(keys) - 1, false, false},
// Changing the power a little bit breaks the static validator.
// The sigs are enough, but the validator hash is unknown.
{keys, types.ToVoterAll(keys.ToValidators(20, 11).Validators),
{keys, types.NewValidatorSet(keys.ToValidators(20, 11).Validators),
5, 0, len(keys), false, true},
}

for _, tc := range cases {
sh := tc.keys.GenSignedHeader(
chainID, tc.height, nil, tc.vals, tc.vals,
tmhash.Sum([]byte("foo")),
tmhash.Sum([]byte("params")),
tmhash.Sum([]byte("results")),
tc.first, tc.last,
)

sh := tc.keys.GenSignedHeader(chainID, tc.height, nil, types.ToVoterAll(tc.vals.Validators),
tc.vals, tc.vals, tmhash.Sum([]byte("foo")), tmhash.Sum([]byte("params")),
tmhash.Sum([]byte("results")), tc.first, tc.last)
err := cert.Verify(sh)
if tc.proper {
assert.Nil(err, "%+v", err)
Expand Down
16 changes: 8 additions & 8 deletions lite/client/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ func (p *provider) fetchLatestCommit(minHeight int64, maxHeight int64) (*ctypes.
}

// Implements Provider.
func (p *provider) VoterSet(chainID string, height int64) (valset *types.VoterSet, err error) {
return p.getVoterSet(chainID, height)
func (p *provider) ValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) {
return p.getValidatorSet(chainID, height)
}

func (p *provider) getVoterSet(chainID string, height int64) (valset *types.VoterSet, err error) {
func (p *provider) getValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) {
if chainID != p.chainID {
err = fmt.Errorf("expected chainID %s, got %s", p.chainID, chainID)
return
Expand All @@ -112,28 +112,28 @@ func (p *provider) getVoterSet(chainID string, height int64) (valset *types.Vote
return
}

var res *ctypes.ResultVoters
res, err = p.client.Voters(&height, 0, 0)
var res *ctypes.ResultValidators
res, err = p.client.Validators(&height, 0, 0)

if err != nil {
// TODO pass through other types of errors.
return nil, lerr.ErrUnknownValidators(chainID, height)
}
valset = types.WrapValidatorsToVoterSet(res.Voters)
valset = types.NewValidatorSet(res.Validators)
return
}

// This does no validation.
func (p *provider) fillFullCommit(signedHeader types.SignedHeader) (fc lite.FullCommit, err error) {

// Get the validators.
valset, err := p.getVoterSet(signedHeader.ChainID, signedHeader.Height)
valset, err := p.getValidatorSet(signedHeader.ChainID, signedHeader.Height)
if err != nil {
return lite.FullCommit{}, err
}

// Get the next validators.
nextValset, err := p.getVoterSet(signedHeader.ChainID, signedHeader.Height+1)
nextValset, err := p.getValidatorSet(signedHeader.ChainID, signedHeader.Height+1)
if err != nil {
return lite.FullCommit{}, err
}
Expand Down
2 changes: 1 addition & 1 deletion lite/client/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func TestProvider(t *testing.T) {
assert.True(sh < 5000)

// let's check this is valid somehow
assert.Nil(fc.ValidateFull(chainID))
assert.Nil(fc.ValidateFull(chainID, types.DefaultVoterParams()))

// historical queries now work :)
lower := sh - 5
Expand Down
Loading