Compare commits

...

22 Commits

Author SHA1 Message Date
Ismail Khoffi
8eef647bfb test that showcases panic when PubKeyMultisigThreshold are used in sdk:
- deserialization will fail in `readInfo` which tries to read a
 `crypto.PubKey` into a `localInfo` (called by
  cosmos-sdk/client/keys.GetKeyInfo)
2019-01-10 12:56:30 +01:00
srmo
616c3a4bae cs: prettify logging of ignored votes (#3086)
Refs #3038
2019-01-06 12:00:12 +03:00
Piotr Husiatyński
04e97f599a fix build scripts (#3085)
* fix build scripts

Search for the right variable when introspecting Go code. `Version` was
renamed to `TMCoreSemVer`.

This is regression introduced in
b95ac688af

* fix all `Version` introspections.

Use `TMCoreSemVer` instead of `Version`
2019-01-06 11:40:15 +03:00
Ethan Buchman
56a4fb4d72 add signing spec (#3061)
* add signing spec

* fixes from review

* more fixes

* fixes from review
2019-01-02 17:18:45 -08:00
srmo
49017a5787 3070 [docs] unindent text as it is supposed to behave the same as the parts before (#3075) 2019-01-01 10:42:39 +03:00
Ismail Khoffi
6a80412a01 Remove privval.GetAddress(), memoize pubkey (#2948)
privval: remove GetAddress(), memoize pubkey
2018-12-22 00:36:45 -05:00
needkane
2348f38927 Update node_info.go (#3059) 2018-12-21 17:37:28 -05:00
yutianwu
41e2eeee9c R4R: Split immutable and mutable parts of priv_validator.json (#2870)
* split immutable and mutable parts of priv_validator.json

* fix bugs

* minor changes

* retrig test

* delete scripts/wire2amino.go

* fix test

* fixes from review

* privval: remove mtx

* rearrange priv_validator.go

* upgrade path

* write tests for the upgrade

* fix for unsafe_reset_all

* add test

* add reset test
2018-12-21 16:58:27 -05:00
Ethan Buchman
a88e283a9d Merge pull request #3063 from tendermint/master
Merge master back to develop
2018-12-21 16:39:02 -05:00
Ethan Buchman
1e1ca15bcc Merge pull request #3062 from tendermint/release/v0.27.4
Release/v0.27.4
2018-12-21 16:35:45 -05:00
Ethan Buchman
c6604b5a9b changelog and version 2018-12-21 16:31:28 -05:00
Anton Kaliaev
c510f823e7 mempool: move tx to back, not front (#3036)
because we pop txs from the front if the cache is full

Refs #3035
2018-12-21 16:28:21 -05:00
Zach
daddebac29 circleci: update go version (#3051) 2018-12-19 21:45:12 +04:00
Zach
30f346fe44 docs: add rpc link to docs navbar and re-org sidebar (#3041)
* add rpc to docs navbar and close #3000

* Update config.js
2018-12-17 23:02:26 +04:00
Anton Kaliaev
4d8f29f79c set allow_duplicate_ip to false (#2992)
* config: cors options are arrays of strings, not strings

Fixes #2980

* docs: update tendermint-core/configuration.html page

* set allow_duplicate_ip to false

* in `tendermint testnet`, set allow_duplicate_ip to true

Refs #2712

* fixes after Ismail's review
2018-12-17 11:52:33 -05:00
Zach
2182f6a702 update go version & other cleanup (#3018)
* update go version & other cleanup

* fix lints

* go one.eleven.four

* keep circle on 1.11.3 for now
2018-12-17 11:51:53 -05:00
Anton Kaliaev
a06912b579 mempool: move tx to back, not front (#3036)
because we pop txs from the front if the cache is full

Refs #3035
2018-12-17 11:35:05 -05:00
Zach
0ff715125b fix docs / proxy app (#2988)
* fix docs / proxy app, closes #2986

* counter_serial

* review comments

* list all possible options

* add changelog entries
2018-12-16 23:34:13 -05:00
Ethan Buchman
385977d5e8 Merge pull request #3033 from tendermint/master
Merge pull request #3032 from tendermint/release/v0.27.3
2018-12-16 14:30:46 -05:00
Ethan Buchman
0138530df2 Merge pull request #3032 from tendermint/release/v0.27.3
Release/v0.27.3
2018-12-16 14:30:23 -05:00
Ethan Buchman
0533c73a50 crypto: revert to mainline Go crypto lib (#3027)
* crypto: revert to mainline Go crypto lib

We used to use a fork for a modified bcrypt so we could pass our own
randomness but this was largely unecessary, unused, and a burden.
So now we just use the mainline Go crypto lib.

* changelog

* fix tests

* version and changelog
2018-12-16 14:19:38 -05:00
Ethan Buchman
1beb45511c Merge pull request #3031 from tendermint/master
Merge pull request #3030 from tendermint/release/v0.27.2
2018-12-16 14:13:57 -05:00
76 changed files with 1328 additions and 8023 deletions

View File

@@ -3,7 +3,7 @@ version: 2
defaults: &defaults defaults: &defaults
working_directory: /go/src/github.com/tendermint/tendermint working_directory: /go/src/github.com/tendermint/tendermint
docker: docker:
- image: circleci/golang:1.10.3 - image: circleci/golang:1.11.4
environment: environment:
GOBIN: /tmp/workspace/bin GOBIN: /tmp/workspace/bin

View File

@@ -1,5 +1,26 @@
# Changelog # Changelog
## v0.27.4
*December 21st, 2018*
### BUG FIXES:
- [mempool] [\#3036](https://github.com/tendermint/tendermint/issues/3036) Fix
LRU cache by popping the least recently used item when the cache is full,
not the most recently used one!
## v0.27.3
*December 16th, 2018*
### BREAKING CHANGES:
* Go API
- [dep] [\#3027](https://github.com/tendermint/tendermint/issues/3027) Revert to mainline Go crypto library, eliminating the modified
`bcrypt.GenerateFromPassword`
## v0.27.2 ## v0.27.2
*December 16th, 2018* *December 16th, 2018*
@@ -84,17 +105,17 @@ message.
### IMPROVEMENTS: ### IMPROVEMENTS:
- [state] [\#2929](https://github.com/tendermint/tendermint/issues/2929) Minor refactor of updateState logic (@danil-lashin) - [state] [\#2929](https://github.com/tendermint/tendermint/issues/2929) Minor refactor of updateState logic (@danil-lashin)
- [node] \#2959 Allow node to start even if software's BlockProtocol is - [node] [\#2959](https://github.com/tendermint/tendermint/issues/2959) Allow node to start even if software's BlockProtocol is
different from state's BlockProtocol different from state's BlockProtocol
- [pex] \#2959 Pex reactor logger uses `module=pex` - [pex] [\#2959](https://github.com/tendermint/tendermint/issues/2959) Pex reactor logger uses `module=pex`
### BUG FIXES: ### BUG FIXES:
- [p2p] \#2968 Panic on transport error rather than continuing to run but not - [p2p] [\#2968](https://github.com/tendermint/tendermint/issues/2968) Panic on transport error rather than continuing to run but not
accept new connections accept new connections
- [p2p] \#2969 Fix mismatch in peer count between `/net_info` and the prometheus - [p2p] [\#2969](https://github.com/tendermint/tendermint/issues/2969) Fix mismatch in peer count between `/net_info` and the prometheus
metrics metrics
- [rpc] \#2408 `/broadcast_tx_commit`: Fix "interface conversion: interface {} in nil, not EventDataTx" panic (could happen if somebody sent a tx using `/broadcast_tx_commit` while Tendermint was being stopped) - [rpc] [\#2408](https://github.com/tendermint/tendermint/issues/2408) `/broadcast_tx_commit`: Fix "interface conversion: interface {} in nil, not EventDataTx" panic (could happen if somebody sent a tx using `/broadcast_tx_commit` while Tendermint was being stopped)
- [state] [\#2785](https://github.com/tendermint/tendermint/issues/2785) Fix accum for new validators to be `-1.125*totalVotingPower` - [state] [\#2785](https://github.com/tendermint/tendermint/issues/2785) Fix accum for new validators to be `-1.125*totalVotingPower`
instead of 0, forcing them to wait before becoming the proposer. Also: instead of 0, forcing them to wait before becoming the proposer. Also:
- do not batch clip - do not batch clip

View File

@@ -1,4 +1,4 @@
## v0.27.3 ## v0.27.4
*TBD* *TBD*
@@ -7,18 +7,28 @@ Special thanks to external contributors on this release:
### BREAKING CHANGES: ### BREAKING CHANGES:
* CLI/RPC/Config * CLI/RPC/Config
- [cli] Removed `node` `--proxy_app=dummy` option. Use `kvstore` (`persistent_kvstore`) instead.
- [cli] Renamed `node` `--proxy_app=nilapp` to `--proxy_app=noop`.
- [config] \#2992 `allow_duplicate_ip` is now set to false
- [privval] \#2926 split up `PubKeyMsg` into `PubKeyRequest` and `PubKeyResponse` to be consistent with other message types
* Apps * Apps
* Go API * Go API
- [types] \#2926 memoize consensus public key on initialization of remote signer and return the memoized key on
`PrivValidator.GetPubKey()` instead of requesting it again
- [types] \#2981 Remove `PrivValidator.GetAddress()`
* Blockchain Protocol * Blockchain Protocol
* P2P Protocol * P2P Protocol
- multiple connections from the same IP are now disabled by default (see `allow_duplicate_ip` config option)
### FEATURES: ### FEATURES:
- [privval] \#1181 Split immutable and mutable parts of priv_validator.json
### IMPROVEMENTS: ### IMPROVEMENTS:
### BUG FIXES: ### BUG FIXES:
- [types] \#2926 do not panic if retrieving the private validator's public key fails

View File

@@ -3,7 +3,7 @@ set -e
# Get the tag from the version, or try to figure it out. # Get the tag from the version, or try to figure it out.
if [ -z "$TAG" ]; then if [ -z "$TAG" ]; then
TAG=$(awk -F\" '/Version =/ { print $2; exit }' < ../version/version.go) TAG=$(awk -F\" '/TMCoreSemVer =/ { print $2; exit }' < ../version/version.go)
fi fi
if [ -z "$TAG" ]; then if [ -z "$TAG" ]; then
echo "Please specify a tag." echo "Please specify a tag."

View File

@@ -3,7 +3,7 @@ set -e
# Get the tag from the version, or try to figure it out. # Get the tag from the version, or try to figure it out.
if [ -z "$TAG" ]; then if [ -z "$TAG" ]; then
TAG=$(awk -F\" '/Version =/ { print $2; exit }' < ../version/version.go) TAG=$(awk -F\" '/TMCoreSemVer =/ { print $2; exit }' < ../version/version.go)
fi fi
if [ -z "$TAG" ]; then if [ -z "$TAG" ]; then
echo "Please specify a tag." echo "Please specify a tag."

5
Gopkg.lock generated
View File

@@ -376,7 +376,7 @@
version = "v0.14.1" version = "v0.14.1"
[[projects]] [[projects]]
digest = "1:72b71e3a29775e5752ed7a8012052a3dee165e27ec18cedddae5288058f09acf" digest = "1:00d2b3e64cdc3fa69aa250dfbe4cc38c4837d4f37e62279be2ae52107ffbbb44"
name = "golang.org/x/crypto" name = "golang.org/x/crypto"
packages = [ packages = [
"bcrypt", "bcrypt",
@@ -397,8 +397,7 @@
"salsa20/salsa", "salsa20/salsa",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "3764759f34a542a3aef74d6b02e35be7ab893bba" revision = "505ab145d0a99da450461ae2c1a9f6cd10d1f447"
source = "github.com/tendermint/crypto"
[[projects]] [[projects]]
digest = "1:d36f55a999540d29b6ea3c2ea29d71c76b1d9853fdcd3e5c5cb4836f2ba118f1" digest = "1:d36f55a999540d29b6ea3c2ea29d71c76b1d9853fdcd3e5c5cb4836f2ba118f1"

View File

@@ -81,8 +81,7 @@
[[constraint]] [[constraint]]
name = "golang.org/x/crypto" name = "golang.org/x/crypto"
source = "github.com/tendermint/crypto" revision = "505ab145d0a99da450461ae2c1a9f6cd10d1f447"
revision = "3764759f34a542a3aef74d6b02e35be7ab893bba"
[[override]] [[override]]
name = "github.com/jmhodges/levigo" name = "github.com/jmhodges/levigo"

View File

@@ -49,7 +49,7 @@ For examples of the kinds of bugs we're looking for, see [SECURITY.md](SECURITY.
Requirement|Notes Requirement|Notes
---|--- ---|---
Go version | Go1.10 or higher Go version | Go1.11.4 or higher
## Documentation ## Documentation

View File

@@ -58,7 +58,7 @@ var RootCmd = &cobra.Command{
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
switch cmd.Use { switch cmd.Use {
case "counter", "kvstore", "dummy": // for the examples apps, don't pre-run case "counter", "kvstore": // for the examples apps, don't pre-run
return nil return nil
case "version": // skip running for version command case "version": // skip running for version command
return nil return nil
@@ -127,10 +127,6 @@ func addCounterFlags() {
counterCmd.PersistentFlags().BoolVarP(&flagSerial, "serial", "", false, "enforce incrementing (serial) transactions") counterCmd.PersistentFlags().BoolVarP(&flagSerial, "serial", "", false, "enforce incrementing (serial) transactions")
} }
func addDummyFlags() {
dummyCmd.PersistentFlags().StringVarP(&flagPersist, "persist", "", "", "directory to use for a database")
}
func addKVStoreFlags() { func addKVStoreFlags() {
kvstoreCmd.PersistentFlags().StringVarP(&flagPersist, "persist", "", "", "directory to use for a database") kvstoreCmd.PersistentFlags().StringVarP(&flagPersist, "persist", "", "", "directory to use for a database")
} }
@@ -152,10 +148,6 @@ func addCommands() {
// examples // examples
addCounterFlags() addCounterFlags()
RootCmd.AddCommand(counterCmd) RootCmd.AddCommand(counterCmd)
// deprecated, left for backwards compatibility
addDummyFlags()
RootCmd.AddCommand(dummyCmd)
// replaces dummy, see issue #196
addKVStoreFlags() addKVStoreFlags()
RootCmd.AddCommand(kvstoreCmd) RootCmd.AddCommand(kvstoreCmd)
} }
@@ -291,18 +283,6 @@ var counterCmd = &cobra.Command{
}, },
} }
// deprecated, left for backwards compatibility
var dummyCmd = &cobra.Command{
Use: "dummy",
Deprecated: "use: [abci-cli kvstore] instead",
Short: "ABCI demo example",
Long: "ABCI demo example",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
return cmdKVStore(cmd, args)
},
}
var kvstoreCmd = &cobra.Command{ var kvstoreCmd = &cobra.Command{
Use: "kvstore", Use: "kvstore",
Short: "ABCI demo example", Short: "ABCI demo example",

View File

@@ -432,11 +432,7 @@ type bcBlockResponseMessage struct {
// ValidateBasic performs basic validation. // ValidateBasic performs basic validation.
func (m *bcBlockResponseMessage) ValidateBasic() error { func (m *bcBlockResponseMessage) ValidateBasic() error {
if err := m.Block.ValidateBasic(); err != nil { return m.Block.ValidateBasic()
return err
}
return nil
} }
func (m *bcBlockResponseMessage) String() string { func (m *bcBlockResponseMessage) String() string {

View File

@@ -42,7 +42,7 @@ func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.G
} }
func makeVote(header *types.Header, blockID types.BlockID, valset *types.ValidatorSet, privVal types.PrivValidator) *types.Vote { func makeVote(header *types.Header, blockID types.BlockID, valset *types.ValidatorSet, privVal types.PrivValidator) *types.Vote {
addr := privVal.GetAddress() addr := privVal.GetPubKey().Address()
idx, _ := valset.GetByAddress(addr) idx, _ := valset.GetByAddress(addr)
vote := &types.Vote{ vote := &types.Vote{
ValidatorAddress: addr, ValidatorAddress: addr,

View File

@@ -13,9 +13,10 @@ import (
func main() { func main() {
var ( var (
addr = flag.String("addr", ":26659", "Address of client to connect to") addr = flag.String("addr", ":26659", "Address of client to connect to")
chainID = flag.String("chain-id", "mychain", "chain id") chainID = flag.String("chain-id", "mychain", "chain id")
privValPath = flag.String("priv", "", "priv val file path") privValKeyPath = flag.String("priv-key", "", "priv val key file path")
privValStatePath = flag.String("priv-state", "", "priv val state file path")
logger = log.NewTMLogger( logger = log.NewTMLogger(
log.NewSyncWriter(os.Stdout), log.NewSyncWriter(os.Stdout),
@@ -27,10 +28,11 @@ func main() {
"Starting private validator", "Starting private validator",
"addr", *addr, "addr", *addr,
"chainID", *chainID, "chainID", *chainID,
"privPath", *privValPath, "privKeyPath", *privValKeyPath,
"privStatePath", *privValStatePath,
) )
pv := privval.LoadFilePV(*privValPath) pv := privval.LoadFilePV(*privValKeyPath, *privValStatePath)
rs := privval.NewRemoteSigner( rs := privval.NewRemoteSigner(
logger, logger,

View File

@@ -17,7 +17,7 @@ var GenValidatorCmd = &cobra.Command{
} }
func genValidator(cmd *cobra.Command, args []string) { func genValidator(cmd *cobra.Command, args []string) {
pv := privval.GenFilePV("") pv := privval.GenFilePV("", "")
jsbz, err := cdc.MarshalJSON(pv) jsbz, err := cdc.MarshalJSON(pv)
if err != nil { if err != nil {
panic(err) panic(err)

View File

@@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
cfg "github.com/tendermint/tendermint/config" cfg "github.com/tendermint/tendermint/config"
cmn "github.com/tendermint/tendermint/libs/common" cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/p2p"
@@ -26,15 +25,18 @@ func initFiles(cmd *cobra.Command, args []string) error {
func initFilesWithConfig(config *cfg.Config) error { func initFilesWithConfig(config *cfg.Config) error {
// private validator // private validator
privValFile := config.PrivValidatorFile() privValKeyFile := config.PrivValidatorKeyFile()
privValStateFile := config.PrivValidatorStateFile()
var pv *privval.FilePV var pv *privval.FilePV
if cmn.FileExists(privValFile) { if cmn.FileExists(privValKeyFile) {
pv = privval.LoadFilePV(privValFile) pv = privval.LoadFilePV(privValKeyFile, privValStateFile)
logger.Info("Found private validator", "path", privValFile) logger.Info("Found private validator", "keyFile", privValKeyFile,
"stateFile", privValStateFile)
} else { } else {
pv = privval.GenFilePV(privValFile) pv = privval.GenFilePV(privValKeyFile, privValStateFile)
pv.Save() pv.Save()
logger.Info("Generated private validator", "path", privValFile) logger.Info("Generated private validator", "keyFile", privValKeyFile,
"stateFile", privValStateFile)
} }
nodeKeyFile := config.NodeKeyFile() nodeKeyFile := config.NodeKeyFile()
@@ -57,9 +59,10 @@ func initFilesWithConfig(config *cfg.Config) error {
GenesisTime: tmtime.Now(), GenesisTime: tmtime.Now(),
ConsensusParams: types.DefaultConsensusParams(), ConsensusParams: types.DefaultConsensusParams(),
} }
key := pv.GetPubKey()
genDoc.Validators = []types.GenesisValidator{{ genDoc.Validators = []types.GenesisValidator{{
Address: pv.GetPubKey().Address(), Address: key.Address(),
PubKey: pv.GetPubKey(), PubKey: key,
Power: 10, Power: 10,
}} }}

View File

@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/privval" "github.com/tendermint/tendermint/privval"
) )
@@ -27,36 +28,41 @@ var ResetPrivValidatorCmd = &cobra.Command{
// XXX: this is totally unsafe. // XXX: this is totally unsafe.
// it's only suitable for testnets. // it's only suitable for testnets.
func resetAll(cmd *cobra.Command, args []string) { func resetAll(cmd *cobra.Command, args []string) {
ResetAll(config.DBDir(), config.P2P.AddrBookFile(), config.PrivValidatorFile(), logger) ResetAll(config.DBDir(), config.P2P.AddrBookFile(), config.PrivValidatorKeyFile(),
config.PrivValidatorStateFile(), logger)
} }
// XXX: this is totally unsafe. // XXX: this is totally unsafe.
// it's only suitable for testnets. // it's only suitable for testnets.
func resetPrivValidator(cmd *cobra.Command, args []string) { func resetPrivValidator(cmd *cobra.Command, args []string) {
resetFilePV(config.PrivValidatorFile(), logger) resetFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile(), logger)
} }
// ResetAll removes the privValidator and address book files plus all data. // ResetAll removes address book files plus all data, and resets the privValdiator data.
// Exported so other CLI tools can use it. // Exported so other CLI tools can use it.
func ResetAll(dbDir, addrBookFile, privValFile string, logger log.Logger) { func ResetAll(dbDir, addrBookFile, privValKeyFile, privValStateFile string, logger log.Logger) {
resetFilePV(privValFile, logger)
removeAddrBook(addrBookFile, logger) removeAddrBook(addrBookFile, logger)
if err := os.RemoveAll(dbDir); err == nil { if err := os.RemoveAll(dbDir); err == nil {
logger.Info("Removed all blockchain history", "dir", dbDir) logger.Info("Removed all blockchain history", "dir", dbDir)
} else { } else {
logger.Error("Error removing all blockchain history", "dir", dbDir, "err", err) logger.Error("Error removing all blockchain history", "dir", dbDir, "err", err)
} }
// recreate the dbDir since the privVal state needs to live there
cmn.EnsureDir(dbDir, 0700)
resetFilePV(privValKeyFile, privValStateFile, logger)
} }
func resetFilePV(privValFile string, logger log.Logger) { func resetFilePV(privValKeyFile, privValStateFile string, logger log.Logger) {
if _, err := os.Stat(privValFile); err == nil { if _, err := os.Stat(privValKeyFile); err == nil {
pv := privval.LoadFilePV(privValFile) pv := privval.LoadFilePVEmptyState(privValKeyFile, privValStateFile)
pv.Reset() pv.Reset()
logger.Info("Reset private validator file to genesis state", "file", privValFile) logger.Info("Reset private validator file to genesis state", "keyFile", privValKeyFile,
"stateFile", privValStateFile)
} else { } else {
pv := privval.GenFilePV(privValFile) pv := privval.GenFilePV(privValKeyFile, privValStateFile)
pv.Save() pv.Save()
logger.Info("Generated private validator file", "file", privValFile) logger.Info("Generated private validator file", "file", "keyFile", privValKeyFile,
"stateFile", privValStateFile)
} }
} }

View File

@@ -24,7 +24,7 @@ func AddNodeFlags(cmd *cobra.Command) {
cmd.Flags().Bool("fast_sync", config.FastSync, "Fast blockchain syncing") cmd.Flags().Bool("fast_sync", config.FastSync, "Fast blockchain syncing")
// abci flags // abci flags
cmd.Flags().String("proxy_app", config.ProxyApp, "Proxy app address, or 'nilapp' or 'kvstore' for local testing.") cmd.Flags().String("proxy_app", config.ProxyApp, "Proxy app address, or one of: 'kvstore', 'persistent_kvstore', 'counter', 'counter_serial' or 'noop' for local testing.")
cmd.Flags().String("abci", config.ABCI, "Specify abci transport (socket | grpc)") cmd.Flags().String("abci", config.ABCI, "Specify abci transport (socket | grpc)")
// rpc flags // rpc flags

View File

@@ -16,7 +16,7 @@ var ShowValidatorCmd = &cobra.Command{
} }
func showValidator(cmd *cobra.Command, args []string) { func showValidator(cmd *cobra.Command, args []string) {
privValidator := privval.LoadOrGenFilePV(config.PrivValidatorFile()) privValidator := privval.LoadOrGenFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
pubKeyJSONBytes, _ := cdc.MarshalJSON(privValidator.GetPubKey()) pubKeyJSONBytes, _ := cdc.MarshalJSON(privValidator.GetPubKey())
fmt.Println(string(pubKeyJSONBytes)) fmt.Println(string(pubKeyJSONBytes))
} }

View File

@@ -85,11 +85,18 @@ func testnetFiles(cmd *cobra.Command, args []string) error {
_ = os.RemoveAll(outputDir) _ = os.RemoveAll(outputDir)
return err return err
} }
err = os.MkdirAll(filepath.Join(nodeDir, "data"), nodeDirPerm)
if err != nil {
_ = os.RemoveAll(outputDir)
return err
}
initFilesWithConfig(config) initFilesWithConfig(config)
pvFile := filepath.Join(nodeDir, config.BaseConfig.PrivValidator) pvKeyFile := filepath.Join(nodeDir, config.BaseConfig.PrivValidatorKey)
pv := privval.LoadFilePV(pvFile) pvStateFile := filepath.Join(nodeDir, config.BaseConfig.PrivValidatorState)
pv := privval.LoadFilePV(pvKeyFile, pvStateFile)
genVals[i] = types.GenesisValidator{ genVals[i] = types.GenesisValidator{
Address: pv.GetPubKey().Address(), Address: pv.GetPubKey().Address(),
PubKey: pv.GetPubKey(), PubKey: pv.GetPubKey(),
@@ -145,6 +152,7 @@ func testnetFiles(cmd *cobra.Command, args []string) error {
nodeDir := filepath.Join(outputDir, fmt.Sprintf("%s%d", nodeDirPrefix, i)) nodeDir := filepath.Join(outputDir, fmt.Sprintf("%s%d", nodeDirPrefix, i))
config.SetRoot(nodeDir) config.SetRoot(nodeDir)
config.P2P.AddrBookStrict = false config.P2P.AddrBookStrict = false
config.P2P.AllowDuplicateIP = true
if populatePersistentPeers { if populatePersistentPeers {
config.P2P.PersistentPeers = persistentPeers config.P2P.PersistentPeers = persistentPeers
} }

View File

@@ -35,15 +35,24 @@ var (
defaultConfigFileName = "config.toml" defaultConfigFileName = "config.toml"
defaultGenesisJSONName = "genesis.json" defaultGenesisJSONName = "genesis.json"
defaultPrivValName = "priv_validator.json" defaultPrivValKeyName = "priv_validator_key.json"
defaultPrivValStateName = "priv_validator_state.json"
defaultNodeKeyName = "node_key.json" defaultNodeKeyName = "node_key.json"
defaultAddrBookName = "addrbook.json" defaultAddrBookName = "addrbook.json"
defaultConfigFilePath = filepath.Join(defaultConfigDir, defaultConfigFileName) defaultConfigFilePath = filepath.Join(defaultConfigDir, defaultConfigFileName)
defaultGenesisJSONPath = filepath.Join(defaultConfigDir, defaultGenesisJSONName) defaultGenesisJSONPath = filepath.Join(defaultConfigDir, defaultGenesisJSONName)
defaultPrivValPath = filepath.Join(defaultConfigDir, defaultPrivValName) defaultPrivValKeyPath = filepath.Join(defaultConfigDir, defaultPrivValKeyName)
defaultNodeKeyPath = filepath.Join(defaultConfigDir, defaultNodeKeyName) defaultPrivValStatePath = filepath.Join(defaultDataDir, defaultPrivValStateName)
defaultAddrBookPath = filepath.Join(defaultConfigDir, defaultAddrBookName)
defaultNodeKeyPath = filepath.Join(defaultConfigDir, defaultNodeKeyName)
defaultAddrBookPath = filepath.Join(defaultConfigDir, defaultAddrBookName)
)
var (
oldPrivVal = "priv_validator.json"
oldPrivValPath = filepath.Join(defaultConfigDir, oldPrivVal)
) )
// Config defines the top level configuration for a Tendermint node // Config defines the top level configuration for a Tendermint node
@@ -160,7 +169,10 @@ type BaseConfig struct {
Genesis string `mapstructure:"genesis_file"` Genesis string `mapstructure:"genesis_file"`
// Path to the JSON file containing the private key to use as a validator in the consensus protocol // Path to the JSON file containing the private key to use as a validator in the consensus protocol
PrivValidator string `mapstructure:"priv_validator_file"` PrivValidatorKey string `mapstructure:"priv_validator_key_file"`
// Path to the JSON file containing the last sign state of a validator
PrivValidatorState string `mapstructure:"priv_validator_state_file"`
// TCP or UNIX socket address for Tendermint to listen on for // TCP or UNIX socket address for Tendermint to listen on for
// connections from an external PrivValidator process // connections from an external PrivValidator process
@@ -183,19 +195,20 @@ type BaseConfig struct {
// DefaultBaseConfig returns a default base configuration for a Tendermint node // DefaultBaseConfig returns a default base configuration for a Tendermint node
func DefaultBaseConfig() BaseConfig { func DefaultBaseConfig() BaseConfig {
return BaseConfig{ return BaseConfig{
Genesis: defaultGenesisJSONPath, Genesis: defaultGenesisJSONPath,
PrivValidator: defaultPrivValPath, PrivValidatorKey: defaultPrivValKeyPath,
NodeKey: defaultNodeKeyPath, PrivValidatorState: defaultPrivValStatePath,
Moniker: defaultMoniker, NodeKey: defaultNodeKeyPath,
ProxyApp: "tcp://127.0.0.1:26658", Moniker: defaultMoniker,
ABCI: "socket", ProxyApp: "tcp://127.0.0.1:26658",
LogLevel: DefaultPackageLogLevels(), ABCI: "socket",
LogFormat: LogFormatPlain, LogLevel: DefaultPackageLogLevels(),
ProfListenAddress: "", LogFormat: LogFormatPlain,
FastSync: true, ProfListenAddress: "",
FilterPeers: false, FastSync: true,
DBBackend: "leveldb", FilterPeers: false,
DBPath: "data", DBBackend: "leveldb",
DBPath: "data",
} }
} }
@@ -218,9 +231,20 @@ func (cfg BaseConfig) GenesisFile() string {
return rootify(cfg.Genesis, cfg.RootDir) return rootify(cfg.Genesis, cfg.RootDir)
} }
// PrivValidatorFile returns the full path to the priv_validator.json file // PrivValidatorKeyFile returns the full path to the priv_validator_key.json file
func (cfg BaseConfig) PrivValidatorFile() string { func (cfg BaseConfig) PrivValidatorKeyFile() string {
return rootify(cfg.PrivValidator, cfg.RootDir) return rootify(cfg.PrivValidatorKey, cfg.RootDir)
}
// PrivValidatorFile returns the full path to the priv_validator_state.json file
func (cfg BaseConfig) PrivValidatorStateFile() string {
return rootify(cfg.PrivValidatorState, cfg.RootDir)
}
// OldPrivValidatorFile returns the full path of the priv_validator.json from pre v0.28.0.
// TODO: eventually remove.
func (cfg BaseConfig) OldPrivValidatorFile() string {
return rootify(oldPrivValPath, cfg.RootDir)
} }
// NodeKeyFile returns the full path to the node_key.json file // NodeKeyFile returns the full path to the node_key.json file
@@ -434,7 +458,7 @@ func DefaultP2PConfig() *P2PConfig {
RecvRate: 5120000, // 5 mB/s RecvRate: 5120000, // 5 mB/s
PexReactor: true, PexReactor: true,
SeedMode: false, SeedMode: false,
AllowDuplicateIP: true, // so non-breaking yet AllowDuplicateIP: false,
HandshakeTimeout: 20 * time.Second, HandshakeTimeout: 20 * time.Second,
DialTimeout: 3 * time.Second, DialTimeout: 3 * time.Second,
TestDialFail: false, TestDialFail: false,

View File

@@ -95,7 +95,10 @@ log_format = "{{ .BaseConfig.LogFormat }}"
genesis_file = "{{ js .BaseConfig.Genesis }}" genesis_file = "{{ js .BaseConfig.Genesis }}"
# Path to the JSON file containing the private key to use as a validator in the consensus protocol # Path to the JSON file containing the private key to use as a validator in the consensus protocol
priv_validator_file = "{{ js .BaseConfig.PrivValidator }}" priv_validator_key_file = "{{ js .BaseConfig.PrivValidatorKey }}"
# Path to the JSON file containing the last sign state of a validator
priv_validator_state_file = "{{ js .BaseConfig.PrivValidatorState }}"
# TCP or UNIX socket address for Tendermint to listen on for # TCP or UNIX socket address for Tendermint to listen on for
# connections from an external PrivValidator process # connections from an external PrivValidator process
@@ -342,7 +345,8 @@ func ResetTestRoot(testName string) *Config {
baseConfig := DefaultBaseConfig() baseConfig := DefaultBaseConfig()
configFilePath := filepath.Join(rootDir, defaultConfigFilePath) configFilePath := filepath.Join(rootDir, defaultConfigFilePath)
genesisFilePath := filepath.Join(rootDir, baseConfig.Genesis) genesisFilePath := filepath.Join(rootDir, baseConfig.Genesis)
privFilePath := filepath.Join(rootDir, baseConfig.PrivValidator) privKeyFilePath := filepath.Join(rootDir, baseConfig.PrivValidatorKey)
privStateFilePath := filepath.Join(rootDir, baseConfig.PrivValidatorState)
// Write default config file if missing. // Write default config file if missing.
if !cmn.FileExists(configFilePath) { if !cmn.FileExists(configFilePath) {
@@ -352,7 +356,8 @@ func ResetTestRoot(testName string) *Config {
cmn.MustWriteFile(genesisFilePath, []byte(testGenesis), 0644) cmn.MustWriteFile(genesisFilePath, []byte(testGenesis), 0644)
} }
// we always overwrite the priv val // we always overwrite the priv val
cmn.MustWriteFile(privFilePath, []byte(testPrivValidator), 0644) cmn.MustWriteFile(privKeyFilePath, []byte(testPrivValidatorKey), 0644)
cmn.MustWriteFile(privStateFilePath, []byte(testPrivValidatorState), 0644)
config := TestConfig().SetRoot(rootDir) config := TestConfig().SetRoot(rootDir)
return config return config
@@ -374,7 +379,7 @@ var testGenesis = `{
"app_hash": "" "app_hash": ""
}` }`
var testPrivValidator = `{ var testPrivValidatorKey = `{
"address": "A3258DCBF45DCA0DF052981870F2D1441A36D145", "address": "A3258DCBF45DCA0DF052981870F2D1441A36D145",
"pub_key": { "pub_key": {
"type": "tendermint/PubKeyEd25519", "type": "tendermint/PubKeyEd25519",
@@ -383,8 +388,11 @@ var testPrivValidator = `{
"priv_key": { "priv_key": {
"type": "tendermint/PrivKeyEd25519", "type": "tendermint/PrivKeyEd25519",
"value": "EVkqJO/jIXp3rkASXfh9YnyToYXRXhBr6g9cQVxPFnQBP/5povV4HTjvsy530kybxKHwEi85iU8YL0qQhSYVoQ==" "value": "EVkqJO/jIXp3rkASXfh9YnyToYXRXhBr6g9cQVxPFnQBP/5povV4HTjvsy530kybxKHwEi85iU8YL0qQhSYVoQ=="
}, }
"last_height": "0", }`
"last_round": "0",
"last_step": 0 var testPrivValidatorState = `{
"height": "0",
"round": "0",
"step": 0
}` }`

View File

@@ -60,7 +60,7 @@ func TestEnsureTestRoot(t *testing.T) {
// TODO: make sure the cfg returned and testconfig are the same! // TODO: make sure the cfg returned and testconfig are the same!
baseConfig := DefaultBaseConfig() baseConfig := DefaultBaseConfig()
ensureFiles(t, rootDir, defaultDataDir, baseConfig.Genesis, baseConfig.PrivValidator) ensureFiles(t, rootDir, defaultDataDir, baseConfig.Genesis, baseConfig.PrivValidatorKey, baseConfig.PrivValidatorState)
} }
func checkConfig(configFile string) bool { func checkConfig(configFile string) bool {

View File

@@ -6,14 +6,18 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path" "path/filepath"
"reflect" "reflect"
"sort" "sort"
"sync" "sync"
"testing" "testing"
"time" "time"
"github.com/go-kit/kit/log/term"
abcicli "github.com/tendermint/tendermint/abci/client" abcicli "github.com/tendermint/tendermint/abci/client"
"github.com/tendermint/tendermint/abci/example/counter"
"github.com/tendermint/tendermint/abci/example/kvstore"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
bc "github.com/tendermint/tendermint/blockchain" bc "github.com/tendermint/tendermint/blockchain"
cfg "github.com/tendermint/tendermint/config" cfg "github.com/tendermint/tendermint/config"
@@ -27,11 +31,6 @@ import (
sm "github.com/tendermint/tendermint/state" sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time" tmtime "github.com/tendermint/tendermint/types/time"
"github.com/tendermint/tendermint/abci/example/counter"
"github.com/tendermint/tendermint/abci/example/kvstore"
"github.com/go-kit/kit/log/term"
) )
const ( const (
@@ -72,9 +71,10 @@ func NewValidatorStub(privValidator types.PrivValidator, valIndex int) *validato
} }
func (vs *validatorStub) signVote(voteType types.SignedMsgType, hash []byte, header types.PartSetHeader) (*types.Vote, error) { func (vs *validatorStub) signVote(voteType types.SignedMsgType, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
addr := vs.PrivValidator.GetPubKey().Address()
vote := &types.Vote{ vote := &types.Vote{
ValidatorIndex: vs.Index, ValidatorIndex: vs.Index,
ValidatorAddress: vs.PrivValidator.GetAddress(), ValidatorAddress: addr,
Height: vs.Height, Height: vs.Height,
Round: vs.Round, Round: vs.Round,
Timestamp: tmtime.Now(), Timestamp: tmtime.Now(),
@@ -151,8 +151,9 @@ func signAddVotes(to *ConsensusState, voteType types.SignedMsgType, hash []byte,
func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *validatorStub, blockHash []byte) { func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *validatorStub, blockHash []byte) {
prevotes := cs.Votes.Prevotes(round) prevotes := cs.Votes.Prevotes(round)
address := privVal.GetPubKey().Address()
var vote *types.Vote var vote *types.Vote
if vote = prevotes.GetByAddress(privVal.GetAddress()); vote == nil { if vote = prevotes.GetByAddress(address); vote == nil {
panic("Failed to find prevote from validator") panic("Failed to find prevote from validator")
} }
if blockHash == nil { if blockHash == nil {
@@ -168,8 +169,9 @@ func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *valid
func validateLastPrecommit(t *testing.T, cs *ConsensusState, privVal *validatorStub, blockHash []byte) { func validateLastPrecommit(t *testing.T, cs *ConsensusState, privVal *validatorStub, blockHash []byte) {
votes := cs.LastCommit votes := cs.LastCommit
address := privVal.GetPubKey().Address()
var vote *types.Vote var vote *types.Vote
if vote = votes.GetByAddress(privVal.GetAddress()); vote == nil { if vote = votes.GetByAddress(address); vote == nil {
panic("Failed to find precommit from validator") panic("Failed to find precommit from validator")
} }
if !bytes.Equal(vote.BlockID.Hash, blockHash) { if !bytes.Equal(vote.BlockID.Hash, blockHash) {
@@ -179,8 +181,9 @@ func validateLastPrecommit(t *testing.T, cs *ConsensusState, privVal *validatorS
func validatePrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *validatorStub, votedBlockHash, lockedBlockHash []byte) { func validatePrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *validatorStub, votedBlockHash, lockedBlockHash []byte) {
precommits := cs.Votes.Precommits(thisRound) precommits := cs.Votes.Precommits(thisRound)
address := privVal.GetPubKey().Address()
var vote *types.Vote var vote *types.Vote
if vote = precommits.GetByAddress(privVal.GetAddress()); vote == nil { if vote = precommits.GetByAddress(address); vote == nil {
panic("Failed to find precommit from validator") panic("Failed to find precommit from validator")
} }
@@ -281,9 +284,10 @@ func newConsensusStateWithConfigAndBlockStore(thisConfig *cfg.Config, state sm.S
} }
func loadPrivValidator(config *cfg.Config) *privval.FilePV { func loadPrivValidator(config *cfg.Config) *privval.FilePV {
privValidatorFile := config.PrivValidatorFile() privValidatorKeyFile := config.PrivValidatorKeyFile()
ensureDir(path.Dir(privValidatorFile), 0700) ensureDir(filepath.Dir(privValidatorKeyFile), 0700)
privValidator := privval.LoadOrGenFilePV(privValidatorFile) privValidatorStateFile := config.PrivValidatorStateFile()
privValidator := privval.LoadOrGenFilePV(privValidatorKeyFile, privValidatorStateFile)
privValidator.Reset() privValidator.Reset()
return privValidator return privValidator
} }
@@ -591,7 +595,7 @@ func randConsensusNet(nValidators int, testName string, tickerFunc func() Timeou
for _, opt := range configOpts { for _, opt := range configOpts {
opt(thisConfig) opt(thisConfig)
} }
ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal ensureDir(filepath.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
app := appFunc() app := appFunc()
vals := types.TM2PB.ValidatorUpdates(state.Validators) vals := types.TM2PB.ValidatorUpdates(state.Validators)
app.InitChain(abci.RequestInitChain{Validators: vals}) app.InitChain(abci.RequestInitChain{Validators: vals})
@@ -612,16 +616,21 @@ func randConsensusNetWithPeers(nValidators, nPeers int, testName string, tickerF
stateDB := dbm.NewMemDB() // each state needs its own db stateDB := dbm.NewMemDB() // each state needs its own db
state, _ := sm.LoadStateFromDBOrGenesisDoc(stateDB, genDoc) state, _ := sm.LoadStateFromDBOrGenesisDoc(stateDB, genDoc)
thisConfig := ResetConfig(fmt.Sprintf("%s_%d", testName, i)) thisConfig := ResetConfig(fmt.Sprintf("%s_%d", testName, i))
ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal ensureDir(filepath.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
var privVal types.PrivValidator var privVal types.PrivValidator
if i < nValidators { if i < nValidators {
privVal = privVals[i] privVal = privVals[i]
} else { } else {
tempFile, err := ioutil.TempFile("", "priv_validator_") tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_")
if err != nil { if err != nil {
panic(err) panic(err)
} }
privVal = privval.GenFilePV(tempFile.Name()) tempStateFile, err := ioutil.TempFile("", "priv_validator_state_")
if err != nil {
panic(err)
}
privVal = privval.GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
} }
app := appFunc() app := appFunc()

View File

@@ -143,7 +143,8 @@ func TestReactorWithEvidence(t *testing.T) {
// mock the evidence pool // mock the evidence pool
// everyone includes evidence of another double signing // everyone includes evidence of another double signing
vIdx := (i + 1) % nValidators vIdx := (i + 1) % nValidators
evpool := newMockEvidencePool(privVals[vIdx].GetAddress()) addr := privVals[vIdx].GetPubKey().Address()
evpool := newMockEvidencePool(addr)
// Make ConsensusState // Make ConsensusState
blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyAppConnCon, mempool, evpool) blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyAppConnCon, mempool, evpool)
@@ -268,7 +269,8 @@ func TestReactorVotingPowerChange(t *testing.T) {
// map of active validators // map of active validators
activeVals := make(map[string]struct{}) activeVals := make(map[string]struct{})
for i := 0; i < nVals; i++ { for i := 0; i < nVals; i++ {
activeVals[string(css[i].privValidator.GetAddress())] = struct{}{} addr := css[i].privValidator.GetPubKey().Address()
activeVals[string(addr)] = struct{}{}
} }
// wait till everyone makes block 1 // wait till everyone makes block 1
@@ -331,7 +333,8 @@ func TestReactorValidatorSetChanges(t *testing.T) {
// map of active validators // map of active validators
activeVals := make(map[string]struct{}) activeVals := make(map[string]struct{})
for i := 0; i < nVals; i++ { for i := 0; i < nVals; i++ {
activeVals[string(css[i].privValidator.GetAddress())] = struct{}{} addr := css[i].privValidator.GetPubKey().Address()
activeVals[string(addr)] = struct{}{}
} }
// wait till everyone makes block 1 // wait till everyone makes block 1

View File

@@ -319,7 +319,7 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
walFile := tempWALWithData(walBody) walFile := tempWALWithData(walBody)
config.Consensus.SetWalFile(walFile) config.Consensus.SetWalFile(walFile)
privVal := privval.LoadFilePV(config.PrivValidatorFile()) privVal := privval.LoadFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
wal, err := NewWAL(walFile) wal, err := NewWAL(walFile)
require.NoError(t, err) require.NoError(t, err)
@@ -633,7 +633,7 @@ func TestInitChainUpdateValidators(t *testing.T) {
clientCreator := proxy.NewLocalClientCreator(app) clientCreator := proxy.NewLocalClientCreator(app)
config := ResetConfig("proxy_test_") config := ResetConfig("proxy_test_")
privVal := privval.LoadFilePV(config.PrivValidatorFile()) privVal := privval.LoadFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
stateDB, state, store := stateAndStore(config, privVal.GetPubKey(), 0x0) stateDB, state, store := stateAndStore(config, privVal.GetPubKey(), 0x0)
oldValAddr := state.Validators.Validators[0].Address oldValAddr := state.Validators.Validators[0].Address
@@ -659,12 +659,6 @@ func TestInitChainUpdateValidators(t *testing.T) {
assert.Equal(t, newValAddr, expectValAddr) assert.Equal(t, newValAddr, expectValAddr)
} }
func newInitChainApp(vals []abci.ValidatorUpdate) *initChainApp {
return &initChainApp{
vals: vals,
}
}
// returns the vals on InitChain // returns the vals on InitChain
type initChainApp struct { type initChainApp struct {
abci.BaseApplication abci.BaseApplication

View File

@@ -2,13 +2,14 @@ package consensus
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"reflect" "reflect"
"runtime/debug" "runtime/debug"
"sync" "sync"
"time" "time"
"github.com/pkg/errors"
cmn "github.com/tendermint/tendermint/libs/common" cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/libs/fail" "github.com/tendermint/tendermint/libs/fail"
"github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/log"
@@ -829,13 +830,14 @@ func (cs *ConsensusState) enterPropose(height int64, round int) {
} }
// if not a validator, we're done // if not a validator, we're done
if !cs.Validators.HasAddress(cs.privValidator.GetAddress()) { address := cs.privValidator.GetPubKey().Address()
logger.Debug("This node is not a validator", "addr", cs.privValidator.GetAddress(), "vals", cs.Validators) if !cs.Validators.HasAddress(address) {
logger.Debug("This node is not a validator", "addr", address, "vals", cs.Validators)
return return
} }
logger.Debug("This node is a validator") logger.Debug("This node is a validator")
if cs.isProposer() { if cs.isProposer(address) {
logger.Info("enterPropose: Our turn to propose", "proposer", cs.Validators.GetProposer().Address, "privValidator", cs.privValidator) logger.Info("enterPropose: Our turn to propose", "proposer", cs.Validators.GetProposer().Address, "privValidator", cs.privValidator)
cs.decideProposal(height, round) cs.decideProposal(height, round)
} else { } else {
@@ -843,8 +845,8 @@ func (cs *ConsensusState) enterPropose(height int64, round int) {
} }
} }
func (cs *ConsensusState) isProposer() bool { func (cs *ConsensusState) isProposer(address []byte) bool {
return bytes.Equal(cs.Validators.GetProposer().Address, cs.privValidator.GetAddress()) return bytes.Equal(cs.Validators.GetProposer().Address, address)
} }
func (cs *ConsensusState) defaultDecideProposal(height int64, round int) { func (cs *ConsensusState) defaultDecideProposal(height int64, round int) {
@@ -929,7 +931,7 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts
cs.state.Validators.Size(), cs.state.Validators.Size(),
len(evidence), len(evidence),
), maxGas) ), maxGas)
proposerAddr := cs.privValidator.GetAddress() proposerAddr := cs.privValidator.GetPubKey().Address()
block, parts := cs.state.MakeBlock(cs.Height, txs, commit, evidence, proposerAddr) block, parts := cs.state.MakeBlock(cs.Height, txs, commit, evidence, proposerAddr)
return block, parts return block, parts
@@ -1474,7 +1476,8 @@ func (cs *ConsensusState) tryAddVote(vote *types.Vote, peerID p2p.ID) (bool, err
if err == ErrVoteHeightMismatch { if err == ErrVoteHeightMismatch {
return added, err return added, err
} else if voteErr, ok := err.(*types.ErrVoteConflictingVotes); ok { } else if voteErr, ok := err.(*types.ErrVoteConflictingVotes); ok {
if bytes.Equal(vote.ValidatorAddress, cs.privValidator.GetAddress()) { addr := cs.privValidator.GetPubKey().Address()
if bytes.Equal(vote.ValidatorAddress, addr) {
cs.Logger.Error("Found conflicting vote from ourselves. Did you unsafe_reset a validator?", "height", vote.Height, "round", vote.Round, "type", vote.Type) cs.Logger.Error("Found conflicting vote from ourselves. Did you unsafe_reset a validator?", "height", vote.Height, "round", vote.Round, "type", vote.Type)
return added, err return added, err
} }
@@ -1526,7 +1529,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
// Not necessarily a bad peer, but not favourable behaviour. // Not necessarily a bad peer, but not favourable behaviour.
if vote.Height != cs.Height { if vote.Height != cs.Height {
err = ErrVoteHeightMismatch err = ErrVoteHeightMismatch
cs.Logger.Info("Vote ignored and not added", "voteHeight", vote.Height, "csHeight", cs.Height, "err", err) cs.Logger.Info("Vote ignored and not added", "voteHeight", vote.Height, "csHeight", cs.Height, "peerID", peerID)
return return
} }
@@ -1639,7 +1642,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
} }
func (cs *ConsensusState) signVote(type_ types.SignedMsgType, hash []byte, header types.PartSetHeader) (*types.Vote, error) { func (cs *ConsensusState) signVote(type_ types.SignedMsgType, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
addr := cs.privValidator.GetAddress() addr := cs.privValidator.GetPubKey().Address()
valIndex, _ := cs.Validators.GetByAddress(addr) valIndex, _ := cs.Validators.GetByAddress(addr)
vote := &types.Vote{ vote := &types.Vote{
@@ -1675,7 +1678,7 @@ func (cs *ConsensusState) voteTime() time.Time {
// sign the vote and publish on internalMsgQueue // sign the vote and publish on internalMsgQueue
func (cs *ConsensusState) signAddVote(type_ types.SignedMsgType, hash []byte, header types.PartSetHeader) *types.Vote { func (cs *ConsensusState) signAddVote(type_ types.SignedMsgType, hash []byte, header types.PartSetHeader) *types.Vote {
// if we don't have a key or we're not in the validator set, do nothing // if we don't have a key or we're not in the validator set, do nothing
if cs.privValidator == nil || !cs.Validators.HasAddress(cs.privValidator.GetAddress()) { if cs.privValidator == nil || !cs.Validators.HasAddress(cs.privValidator.GetPubKey().Address()) {
return nil return nil
} }
vote, err := cs.signVote(type_, hash, header) vote, err := cs.signVote(type_, hash, header)

View File

@@ -73,7 +73,8 @@ func TestStateProposerSelection0(t *testing.T) {
// Commit a block and ensure proposer for the next height is correct. // Commit a block and ensure proposer for the next height is correct.
prop := cs1.GetRoundState().Validators.GetProposer() prop := cs1.GetRoundState().Validators.GetProposer()
if !bytes.Equal(prop.Address, cs1.privValidator.GetAddress()) { address := cs1.privValidator.GetPubKey().Address()
if !bytes.Equal(prop.Address, address) {
t.Fatalf("expected proposer to be validator %d. Got %X", 0, prop.Address) t.Fatalf("expected proposer to be validator %d. Got %X", 0, prop.Address)
} }
@@ -87,7 +88,8 @@ func TestStateProposerSelection0(t *testing.T) {
ensureNewRound(newRoundCh, height+1, 0) ensureNewRound(newRoundCh, height+1, 0)
prop = cs1.GetRoundState().Validators.GetProposer() prop = cs1.GetRoundState().Validators.GetProposer()
if !bytes.Equal(prop.Address, vss[1].GetAddress()) { addr := vss[1].GetPubKey().Address()
if !bytes.Equal(prop.Address, addr) {
panic(fmt.Sprintf("expected proposer to be validator %d. Got %X", 1, prop.Address)) panic(fmt.Sprintf("expected proposer to be validator %d. Got %X", 1, prop.Address))
} }
} }
@@ -110,7 +112,8 @@ func TestStateProposerSelection2(t *testing.T) {
// everyone just votes nil. we get a new proposer each round // everyone just votes nil. we get a new proposer each round
for i := 0; i < len(vss); i++ { for i := 0; i < len(vss); i++ {
prop := cs1.GetRoundState().Validators.GetProposer() prop := cs1.GetRoundState().Validators.GetProposer()
correctProposer := vss[(i+round)%len(vss)].GetAddress() addr := vss[(i+round)%len(vss)].GetPubKey().Address()
correctProposer := addr
if !bytes.Equal(prop.Address, correctProposer) { if !bytes.Equal(prop.Address, correctProposer) {
panic(fmt.Sprintf("expected RoundState.Validators.GetProposer() to be validator %d. Got %X", (i+2)%len(vss), prop.Address)) panic(fmt.Sprintf("expected RoundState.Validators.GetProposer() to be validator %d. Got %X", (i+2)%len(vss), prop.Address))
} }
@@ -505,7 +508,8 @@ func TestStateLockPOLRelock(t *testing.T) {
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait) timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) addr := cs1.privValidator.GetPubKey().Address()
voteCh := subscribeToVoter(cs1, addr)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound) newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
newBlockCh := subscribe(cs1.eventBus, types.EventQueryNewBlockHeader) newBlockCh := subscribe(cs1.eventBus, types.EventQueryNewBlockHeader)
@@ -596,7 +600,8 @@ func TestStateLockPOLUnlock(t *testing.T) {
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait) timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound) newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock) unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) addr := cs1.privValidator.GetPubKey().Address()
voteCh := subscribeToVoter(cs1, addr)
// everything done from perspective of cs1 // everything done from perspective of cs1
@@ -689,7 +694,8 @@ func TestStateLockPOLSafety1(t *testing.T) {
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait) timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound) newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) addr := cs1.privValidator.GetPubKey().Address()
voteCh := subscribeToVoter(cs1, addr)
// start round and wait for propose and prevote // start round and wait for propose and prevote
startTestRound(cs1, cs1.Height, round) startTestRound(cs1, cs1.Height, round)
@@ -805,7 +811,8 @@ func TestStateLockPOLSafety2(t *testing.T) {
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait) timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound) newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock) unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) addr := cs1.privValidator.GetPubKey().Address()
voteCh := subscribeToVoter(cs1, addr)
// the block for R0: gets polkad but we miss it // the block for R0: gets polkad but we miss it
// (even though we signed it, shhh) // (even though we signed it, shhh)
@@ -896,7 +903,8 @@ func TestProposeValidBlock(t *testing.T) {
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound) newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock) unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) addr := cs1.privValidator.GetPubKey().Address()
voteCh := subscribeToVoter(cs1, addr)
// start round and wait for propose and prevote // start round and wait for propose and prevote
startTestRound(cs1, cs1.Height, round) startTestRound(cs1, cs1.Height, round)
@@ -982,7 +990,8 @@ func TestSetValidBlockOnDelayedPrevote(t *testing.T) {
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait) timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound) newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock) validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) addr := cs1.privValidator.GetPubKey().Address()
voteCh := subscribeToVoter(cs1, addr)
// start round and wait for propose and prevote // start round and wait for propose and prevote
startTestRound(cs1, cs1.Height, round) startTestRound(cs1, cs1.Height, round)
@@ -1041,7 +1050,8 @@ func TestSetValidBlockOnDelayedProposal(t *testing.T) {
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound) newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock) validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) addr := cs1.privValidator.GetPubKey().Address()
voteCh := subscribeToVoter(cs1, addr)
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
round = round + 1 // move to round in which P0 is not proposer round = round + 1 // move to round in which P0 is not proposer
@@ -1111,7 +1121,8 @@ func TestWaitingTimeoutProposeOnNewRound(t *testing.T) {
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound) newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) addr := cs1.privValidator.GetPubKey().Address()
voteCh := subscribeToVoter(cs1, addr)
// start round // start round
startTestRound(cs1, height, round) startTestRound(cs1, height, round)
@@ -1144,7 +1155,8 @@ func TestRoundSkipOnNilPolkaFromHigherRound(t *testing.T) {
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait) timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound) newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) addr := cs1.privValidator.GetPubKey().Address()
voteCh := subscribeToVoter(cs1, addr)
// start round // start round
startTestRound(cs1, height, round) startTestRound(cs1, height, round)
@@ -1177,7 +1189,8 @@ func TestWaitTimeoutProposeOnNilPolkaForTheCurrentRound(t *testing.T) {
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound) newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) addr := cs1.privValidator.GetPubKey().Address()
voteCh := subscribeToVoter(cs1, addr)
// start round in which PO is not proposer // start round in which PO is not proposer
startTestRound(cs1, height, round) startTestRound(cs1, height, round)
@@ -1361,7 +1374,8 @@ func TestStateHalt1(t *testing.T) {
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait) timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound) newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
newBlockCh := subscribe(cs1.eventBus, types.EventQueryNewBlock) newBlockCh := subscribe(cs1.eventBus, types.EventQueryNewBlock)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress()) addr := cs1.privValidator.GetPubKey().Address()
voteCh := subscribeToVoter(cs1, addr)
// start round and wait for propose and prevote // start round and wait for propose and prevote
startTestRound(cs1, height, round) startTestRound(cs1, height, round)

View File

@@ -50,8 +50,9 @@ func TestPeerCatchupRounds(t *testing.T) {
func makeVoteHR(t *testing.T, height int64, round int, privVals []types.PrivValidator, valIndex int) *types.Vote { func makeVoteHR(t *testing.T, height int64, round int, privVals []types.PrivValidator, valIndex int) *types.Vote {
privVal := privVals[valIndex] privVal := privVals[valIndex]
addr := privVal.GetPubKey().Address()
vote := &types.Vote{ vote := &types.Vote{
ValidatorAddress: privVal.GetAddress(), ValidatorAddress: addr,
ValidatorIndex: valIndex, ValidatorIndex: valIndex,
Height: height, Height: height,
Round: round, Round: round,

View File

@@ -40,8 +40,9 @@ func WALGenerateNBlocks(wr io.Writer, numBlocks int) (err error) {
// COPY PASTE FROM node.go WITH A FEW MODIFICATIONS // COPY PASTE FROM node.go WITH A FEW MODIFICATIONS
// NOTE: we can't import node package because of circular dependency. // NOTE: we can't import node package because of circular dependency.
// NOTE: we don't do handshake so need to set state.Version.Consensus.App directly. // NOTE: we don't do handshake so need to set state.Version.Consensus.App directly.
privValidatorFile := config.PrivValidatorFile() privValidatorKeyFile := config.PrivValidatorKeyFile()
privValidator := privval.LoadOrGenFilePV(privValidatorFile) privValidatorStateFile := config.PrivValidatorStateFile()
privValidator := privval.LoadOrGenFilePV(privValidatorKeyFile, privValidatorStateFile)
genDoc, err := types.GenesisDocFromFile(config.GenesisFile()) genDoc, err := types.GenesisDocFromFile(config.GenesisFile())
if err != nil { if err != nil {
return errors.Wrap(err, "failed to read genesis file") return errors.Wrap(err, "failed to read genesis file")

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"golang.org/x/crypto/openpgp/armor" // forked to github.com/tendermint/crypto "golang.org/x/crypto/openpgp/armor"
) )
func EncodeArmor(blockType string, headers map[string]string, data []byte) string { func EncodeArmor(blockType string, headers map[string]string, data []byte) string {

View File

@@ -7,7 +7,7 @@ import (
"io" "io"
amino "github.com/tendermint/go-amino" amino "github.com/tendermint/go-amino"
"golang.org/x/crypto/ed25519" // forked to github.com/tendermint/crypto "golang.org/x/crypto/ed25519"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/crypto/tmhash"

View File

@@ -3,7 +3,7 @@ package crypto
import ( import (
"crypto/sha256" "crypto/sha256"
"golang.org/x/crypto/ripemd160" // forked to github.com/tendermint/crypto "golang.org/x/crypto/ripemd160"
) )
func Sha256(bytes []byte) []byte { func Sha256(bytes []byte) []byte {

View File

@@ -95,6 +95,22 @@ func TestMultiSigPubKeyEquality(t *testing.T) {
require.False(t, multisigKey.Equals(multisigKey2)) require.False(t, multisigKey.Equals(multisigKey2))
} }
func TestPubKeyMultisigThresholdAminoToIface(t *testing.T) {
msg := []byte{1, 2, 3, 4}
pubkeys, _ := generatePubKeysAndSignatures(5, msg)
multisigKey := NewPubKeyMultisigThreshold(2, pubkeys)
ab, err := cdc.MarshalBinaryLengthPrefixed(multisigKey)
require.NoError(t, err)
// like other crypto.Pubkey implementations (e.g. ed25519.PubKeyEd25519),
// PubKeyMultisigThreshold should be deserializable into a crypto.PubKey:
var pubKey crypto.PubKey
err = cdc.UnmarshalBinaryLengthPrefixed(ab, &pubKey)
require.NoError(t, err)
require.Equal(t, multisigKey, pubKey)
}
func generatePubKeysAndSignatures(n int, msg []byte) (pubkeys []crypto.PubKey, signatures [][]byte) { func generatePubKeysAndSignatures(n int, msg []byte) (pubkeys []crypto.PubKey, signatures [][]byte) {
pubkeys = make([]crypto.PubKey, n) pubkeys = make([]crypto.PubKey, n)
signatures = make([][]byte, n) signatures = make([][]byte, n)

View File

@@ -9,7 +9,7 @@ import (
secp256k1 "github.com/tendermint/btcd/btcec" secp256k1 "github.com/tendermint/btcd/btcec"
amino "github.com/tendermint/go-amino" amino "github.com/tendermint/go-amino"
"golang.org/x/crypto/ripemd160" // forked to github.com/tendermint/crypto "golang.org/x/crypto/ripemd160"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
) )

View File

@@ -8,7 +8,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"golang.org/x/crypto/chacha20poly1305" // forked to github.com/tendermint/crypto "golang.org/x/crypto/chacha20poly1305"
) )
// Implements crypto.AEAD // Implements crypto.AEAD

View File

@@ -4,7 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"golang.org/x/crypto/nacl/secretbox" // forked to github.com/tendermint/crypto "golang.org/x/crypto/nacl/secretbox"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
cmn "github.com/tendermint/tendermint/libs/common" cmn "github.com/tendermint/tendermint/libs/common"

View File

@@ -6,7 +6,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/crypto/bcrypt" // forked to github.com/tendermint/crypto "golang.org/x/crypto/bcrypt"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
) )
@@ -30,9 +30,7 @@ func TestSimpleWithKDF(t *testing.T) {
plaintext := []byte("sometext") plaintext := []byte("sometext")
secretPass := []byte("somesecret") secretPass := []byte("somesecret")
salt := []byte("somesaltsomesalt") // len 16 secret, err := bcrypt.GenerateFromPassword(secretPass, 12)
// NOTE: we use a fork of x/crypto so we can inject our own randomness for salt
secret, err := bcrypt.GenerateFromPassword(salt, secretPass, 12)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

View File

@@ -19,7 +19,10 @@ module.exports = {
indexName: 'tendermint', indexName: 'tendermint',
debug: false debug: false
}, },
nav: [{ text: "Back to Tendermint", link: "https://tendermint.com" }], nav: [
{ text: "Back to Tendermint", link: "https://tendermint.com" },
{ text: "RPC", link: "../rpc/" }
],
sidebar: [ sidebar: [
{ {
title: "Introduction", title: "Introduction",
@@ -31,6 +34,20 @@ module.exports = {
"/introduction/what-is-tendermint" "/introduction/what-is-tendermint"
] ]
}, },
{
title: "Apps",
collapsable: false,
children: [
"/app-dev/getting-started",
"/app-dev/abci-cli",
"/app-dev/app-architecture",
"/app-dev/app-development",
"/app-dev/subscribing-to-events-via-websocket",
"/app-dev/indexing-transactions",
"/app-dev/abci-spec",
"/app-dev/ecosystem"
]
},
{ {
title: "Tendermint Core", title: "Tendermint Core",
collapsable: false, collapsable: false,
@@ -49,15 +66,6 @@ module.exports = {
"/tendermint-core/validators" "/tendermint-core/validators"
] ]
}, },
{
title: "Tools",
collapsable: false,
children: [
"/tools/",
"/tools/benchmarking",
"/tools/monitoring"
]
},
{ {
title: "Networks", title: "Networks",
collapsable: false, collapsable: false,
@@ -68,18 +76,13 @@ module.exports = {
] ]
}, },
{ {
title: "Apps", title: "Tools",
collapsable: false, collapsable: false,
children: [ children: [
"/app-dev/getting-started", "/tools/",
"/app-dev/abci-cli", "/tools/benchmarking",
"/app-dev/app-architecture", "/tools/monitoring"
"/app-dev/app-development", ]
"/app-dev/subscribing-to-events-via-websocket",
"/app-dev/indexing-transactions",
"/app-dev/abci-spec",
"/app-dev/ecosystem"
]
}, },
{ {
title: "Tendermint Spec", title: "Tendermint Spec",

4670
docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,40 +0,0 @@
{
"dependencies": {
"prettier": "^1.13.7",
"remark-cli": "^5.0.0",
"remark-lint-no-dead-urls": "^0.3.0",
"remark-lint-write-good": "^1.0.3",
"textlint": "^10.2.1",
"textlint-rule-stop-words": "^1.0.3"
},
"name": "tendermint",
"description": "Tendermint Core Documentation",
"version": "0.0.1",
"main": "README.md",
"devDependencies": {},
"scripts": {
"lint:json": "prettier \"**/*.json\" --write",
"lint:md": "prettier \"**/*.md\" --write && remark . && textlint \"md/**\"",
"lint": "yarn lint:json && yarn lint:md"
},
"repository": {
"type": "git",
"url": "git+https://github.com/tendermint/tendermint.git"
},
"keywords": [
"tendermint",
"blockchain"
],
"author": "Tendermint",
"license": "ISC",
"bugs": {
"url": "https://github.com/tendermint/tendermint/issues"
},
"homepage": "https://tendermint.com/docs/",
"remarkConfig": {
"plugins": [
"remark-lint-no-dead-urls",
"remark-lint-write-good"
]
}
}

View File

@@ -407,21 +407,22 @@ If `storeBlockHeight == stateBlockHeight && appBlockHeight < storeBlockHeight`,
replay all blocks in full from `appBlockHeight` to `storeBlockHeight`. replay all blocks in full from `appBlockHeight` to `storeBlockHeight`.
This happens if we completed processing the block, but the app forgot its height. This happens if we completed processing the block, but the app forgot its height.
If `storeBlockHeight == stateBlockHeight && appBlockHeight == storeBlockHeight`, we're done If `storeBlockHeight == stateBlockHeight && appBlockHeight == storeBlockHeight`, we're done.
This happens if we crashed at an opportune spot. This happens if we crashed at an opportune spot.
If `storeBlockHeight == stateBlockHeight+1` If `storeBlockHeight == stateBlockHeight+1`
This happens if we started processing the block but didn't finish. This happens if we started processing the block but didn't finish.
If `appBlockHeight < stateBlockHeight` If `appBlockHeight < stateBlockHeight`
replay all blocks in full from `appBlockHeight` to `storeBlockHeight-1`, replay all blocks in full from `appBlockHeight` to `storeBlockHeight-1`,
and replay the block at `storeBlockHeight` using the WAL. and replay the block at `storeBlockHeight` using the WAL.
This happens if the app forgot the last block it committed. This happens if the app forgot the last block it committed.
If `appBlockHeight == stateBlockHeight`, If `appBlockHeight == stateBlockHeight`,
replay the last block (storeBlockHeight) in full. replay the last block (storeBlockHeight) in full.
This happens if we crashed before the app finished Commit This happens if we crashed before the app finished Commit
If `appBlockHeight == storeBlockHeight`
update the state using the saved ABCI responses but dont run the block against the real app.
This happens if we crashed after the app finished Commit but before Tendermint saved the state.
If appBlockHeight == storeBlockHeight {
update the state using the saved ABCI responses but dont run the block against the real app.
This happens if we crashed after the app finished Commit but before Tendermint saved the state.

View File

@@ -230,7 +230,7 @@ The block version must match the state version.
len(block.ChainID) < 50 len(block.ChainID) < 50
``` ```
ChainID must be maximum 50 UTF-8 symbols. ChainID must be less than 50 bytes.
### Height ### Height

View File

@@ -0,0 +1,205 @@
# Validator Signing
Here we specify the rules for validating a proposal and vote before signing.
First we include some general notes on validating data structures common to both types.
We then provide specific validation rules for each. Finally, we include validation rules to prevent double-sigining.
## SignedMsgType
The `SignedMsgType` is a single byte that refers to the type of the message
being signed. It is defined in Go as follows:
```
// SignedMsgType is a type of signed message in the consensus.
type SignedMsgType byte
const (
// Votes
PrevoteType SignedMsgType = 0x01
PrecommitType SignedMsgType = 0x02
// Proposals
ProposalType SignedMsgType = 0x20
)
```
All signed messages must correspond to one of these types.
## Timestamp
Timestamp validation is subtle and there are currently no bounds placed on the
timestamp included in a proposal or vote. It is expected that validators will honestly
report their local clock time. The median of all timestamps
included in a commit is used as the timestamp for the next block height.
Timestamps are expected to be strictly monotonic for a given validator, though
this is not currently enforced.
## ChainID
ChainID is an unstructured string with a max length of 50-bytes.
In the future, the ChainID may become structured, and may take on longer lengths.
For now, it is recommended that signers be configured for a particular ChainID,
and to only sign votes and proposals corresponding to that ChainID.
## BlockID
BlockID is the structure used to represent the block:
```
type BlockID struct {
Hash []byte
PartsHeader PartSetHeader
}
type PartSetHeader struct {
Hash []byte
Total int
}
```
To be included in a valid vote or proposal, BlockID must either represent a `nil` block, or a complete one.
We introduce two methods, `BlockID.IsNil()` and `BlockID.IsComplete()` for these cases, respectively.
`BlockID.IsNil()` returns true for BlockID `b` if each of the following
are true:
```
b.Hash == nil
b.PartsHeader.Total == 0
b.PartsHeader.Hash == nil
```
`BlockID.IsComplete()` returns true for BlockID `b` if each of the following
are true:
```
len(b.Hash) == 32
b.PartsHeader.Total > 0
len(b.PartsHeader.Hash) == 32
```
## Proposals
The structure of a propsal for signing looks like:
```
type CanonicalProposal struct {
Type SignedMsgType // type alias for byte
Height int64 `binary:"fixed64"`
Round int64 `binary:"fixed64"`
POLRound int64 `binary:"fixed64"`
BlockID BlockID
Timestamp time.Time
ChainID string
}
```
A proposal is valid if each of the following lines evaluates to true for proposal `p`:
```
p.Type == 0x20
p.Height > 0
p.Round >= 0
p.POLRound >= -1
p.BlockID.IsComplete()
```
In other words, a proposal is valid for signing if it contains the type of a Proposal
(0x20), has a positive, non-zero height, a
non-negative round, a POLRound not less than -1, and a complete BlockID.
## Votes
The structure of a vote for signing looks like:
```
type CanonicalVote struct {
Type SignedMsgType // type alias for byte
Height int64 `binary:"fixed64"`
Round int64 `binary:"fixed64"`
Timestamp time.Time
BlockID BlockID
ChainID string
}
```
A vote is valid if each of the following lines evaluates to true for vote `v`:
```
v.Type == 0x1 || v.Type == 0x2
v.Height > 0
v.Round >= 0
v.BlockID.IsNil() || v.BlockID.IsValid()
```
In other words, a vote is valid for signing if it contains the type of a Prevote
or Precommit (0x1 or 0x2, respectively), has a positive, non-zero height, a
non-negative round, and an empty or valid BlockID.
## Invalid Votes and Proposals
Votes and proposals which do not satisfy the above rules are considered invalid.
Peers gossipping invalid votes and proposals may be disconnected from other peers on the network.
Note, however, that there is not currently any explicit mechanism to punish validators signing votes or proposals that fail
these basic validation rules.
## Double Signing
Signers must be careful not to sign conflicting messages, also known as "double signing" or "equivocating".
Tendermint has mechanisms to publish evidence of validators that signed conflicting votes, so they can be punished
by the application. Note Tendermint does not currently handle evidence of conflciting proposals, though it may in the future.
### State
To prevent such double signing, signers must track the height, round, and type of the last message signed.
Assume the signer keeps the following state, `s`:
```
type LastSigned struct {
Height int64
Round int64
Type SignedMsgType // byte
}
```
After signing a vote or proposal `m`, the signer sets:
```
s.Height = m.Height
s.Round = m.Round
s.Type = m.Type
```
### Proposals
A signer should only sign a proposal `p` if any of the following lines are true:
```
p.Height > s.Height
p.Height == s.Height && p.Round > s.Round
```
In other words, a proposal should only be signed if it's at a higher height, or a higher round for the same height.
Once a proposal or vote has been signed for a given height and round, a proposal should never be signed for the same height and round.
### Votes
A signer should only sign a vote `v` if any of the following lines are true:
```
v.Height > s.Height
v.Height == s.Height && v.Round > s.Round
v.Height == s.Height && v.Round == s.Round && v.Step == 0x1 && s.Step == 0x20
v.Height == s.Height && v.Round == s.Round && v.Step == 0x2 && s.Step != 0x2
```
In other words, a vote should only be signed if it's:
- at a higher height
- at a higher round for the same height
- a prevote for the same height and round where we haven't signed a prevote or precommit (but have signed a proposal)
- a precommit for the same height and round where we haven't signed a precommit (but have signed a proposal and/or a prevote)
This means that once a validator signs a prevote for a given height and round, the only other message it can sign for that height and round is a precommit.
And once a validator signs a precommit for a given height and round, it must not sign any other message for that same height and round.

View File

@@ -170,7 +170,7 @@ seed_mode = false
private_peer_ids = "" private_peer_ids = ""
# Toggle to disable guard against peers connecting from the same ip. # Toggle to disable guard against peers connecting from the same ip.
allow_duplicate_ip = true allow_duplicate_ip = false
# Peer connection configuration. # Peer connection configuration.
handshake_timeout = "20s" handshake_timeout = "20s"

View File

@@ -113,7 +113,7 @@ blocks are produced regularly, even if there are no transactions. See
_No Empty Blocks_, below, to modify this setting. _No Empty Blocks_, below, to modify this setting.
Tendermint supports in-process versions of the `counter`, `kvstore` and Tendermint supports in-process versions of the `counter`, `kvstore` and
`nil` apps that ship as examples with `abci-cli`. It's easy to compile `noop` apps that ship as examples with `abci-cli`. It's easy to compile
your own app in-process with Tendermint if it's written in Go. If your your own app in-process with Tendermint if it's written in Go. If your
app is not written in Go, simply run it in another process, and use the app is not written in Go, simply run it in another process, and use the
`--proxy_app` flag to specify the address of the socket it is listening `--proxy_app` flag to specify the address of the socket it is listening

File diff suppressed because it is too large Load Diff

View File

@@ -676,7 +676,7 @@ func (cache *mapTxCache) Push(tx types.Tx) bool {
// Use the tx hash in the cache // Use the tx hash in the cache
txHash := sha256.Sum256(tx) txHash := sha256.Sum256(tx)
if moved, exists := cache.map_[txHash]; exists { if moved, exists := cache.map_[txHash]; exists {
cache.list.MoveToFront(moved) cache.list.MoveToBack(moved)
return false return false
} }

View File

@@ -7,6 +7,7 @@ import (
"net" "net"
"net/http" "net/http"
_ "net/http/pprof" _ "net/http/pprof"
"os"
"strings" "strings"
"time" "time"
@@ -86,8 +87,26 @@ func DefaultNewNode(config *cfg.Config, logger log.Logger) (*Node, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Convert old PrivValidator if it exists.
oldPrivVal := config.OldPrivValidatorFile()
newPrivValKey := config.PrivValidatorKeyFile()
newPrivValState := config.PrivValidatorStateFile()
if _, err := os.Stat(oldPrivVal); !os.IsNotExist(err) {
oldPV, err := privval.LoadOldFilePV(oldPrivVal)
if err != nil {
return nil, fmt.Errorf("Error reading OldPrivValidator from %v: %v\n", oldPrivVal, err)
}
logger.Info("Upgrading PrivValidator file",
"old", oldPrivVal,
"newKey", newPrivValKey,
"newState", newPrivValState,
)
oldPV.Upgrade(newPrivValKey, newPrivValState)
}
return NewNode(config, return NewNode(config,
privval.LoadOrGenFilePV(config.PrivValidatorFile()), privval.LoadOrGenFilePV(newPrivValKey, newPrivValState),
nodeKey, nodeKey,
proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()), proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()),
DefaultGenesisDocProviderFunc(config), DefaultGenesisDocProviderFunc(config),
@@ -240,16 +259,19 @@ func NewNode(config *cfg.Config,
fastSync := config.FastSync fastSync := config.FastSync
if state.Validators.Size() == 1 { if state.Validators.Size() == 1 {
addr, _ := state.Validators.GetByIndex(0) addr, _ := state.Validators.GetByIndex(0)
if bytes.Equal(privValidator.GetAddress(), addr) { privValAddr := privValidator.GetPubKey().Address()
if bytes.Equal(privValAddr, addr) {
fastSync = false fastSync = false
} }
} }
pubKey := privValidator.GetPubKey()
addr := pubKey.Address()
// Log whether this node is a validator or an observer // Log whether this node is a validator or an observer
if state.Validators.HasAddress(privValidator.GetAddress()) { if state.Validators.HasAddress(addr) {
consensusLogger.Info("This node is a validator", "addr", privValidator.GetAddress(), "pubKey", privValidator.GetPubKey()) consensusLogger.Info("This node is a validator", "addr", addr, "pubKey", pubKey)
} else { } else {
consensusLogger.Info("This node is not a validator", "addr", privValidator.GetAddress(), "pubKey", privValidator.GetPubKey()) consensusLogger.Info("This node is not a validator", "addr", addr, "pubKey", pubKey)
} }
csMetrics, p2pMetrics, memplMetrics, smMetrics := metricsProvider() csMetrics, p2pMetrics, memplMetrics, smMetrics := metricsProvider()
@@ -617,7 +639,8 @@ func (n *Node) ConfigureRPC() {
rpccore.SetEvidencePool(n.evidencePool) rpccore.SetEvidencePool(n.evidencePool)
rpccore.SetP2PPeers(n.sw) rpccore.SetP2PPeers(n.sw)
rpccore.SetP2PTransport(n) rpccore.SetP2PTransport(n)
rpccore.SetPubKey(n.privValidator.GetPubKey()) pubKey := n.privValidator.GetPubKey()
rpccore.SetPubKey(pubKey)
rpccore.SetGenesisDoc(n.genesisDoc) rpccore.SetGenesisDoc(n.genesisDoc)
rpccore.SetAddrBook(n.addrBook) rpccore.SetAddrBook(n.addrBook)
rpccore.SetProxyAppQuery(n.proxyApp.Query()) rpccore.SetProxyAppQuery(n.proxyApp.Query())

View File

@@ -10,7 +10,6 @@ import (
"net" "net"
"time" "time"
// forked to github.com/tendermint/crypto
"golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/curve25519" "golang.org/x/crypto/curve25519"
"golang.org/x/crypto/nacl/box" "golang.org/x/crypto/nacl/box"

View File

@@ -9,7 +9,7 @@ import (
) )
const ( const (
maxNodeInfoSize = 10240 // 10Kb maxNodeInfoSize = 10240 // 10KB
maxNumChannels = 16 // plenty of room for upgrades, for now maxNumChannels = 16 // plenty of room for upgrades, for now
) )

View File

@@ -67,7 +67,10 @@ func (sc *IPCVal) OnStart() error {
return err return err
} }
sc.RemoteSignerClient = NewRemoteSignerClient(sc.conn) sc.RemoteSignerClient, err = NewRemoteSignerClient(sc.conn)
if err != nil {
return err
}
// Start a routine to keep the connection alive // Start a routine to keep the connection alive
sc.cancelPing = make(chan struct{}, 1) sc.cancelPing = make(chan struct{}, 1)

View File

@@ -0,0 +1,80 @@
package privval
import (
"io/ioutil"
"os"
"github.com/tendermint/tendermint/crypto"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/types"
)
// OldFilePV is the old version of the FilePV, pre v0.28.0.
type OldFilePV struct {
Address types.Address `json:"address"`
PubKey crypto.PubKey `json:"pub_key"`
LastHeight int64 `json:"last_height"`
LastRound int `json:"last_round"`
LastStep int8 `json:"last_step"`
LastSignature []byte `json:"last_signature,omitempty"`
LastSignBytes cmn.HexBytes `json:"last_signbytes,omitempty"`
PrivKey crypto.PrivKey `json:"priv_key"`
filePath string
}
// LoadOldFilePV loads an OldFilePV from the filePath.
func LoadOldFilePV(filePath string) (*OldFilePV, error) {
pvJSONBytes, err := ioutil.ReadFile(filePath)
if err != nil {
return nil, err
}
pv := &OldFilePV{}
err = cdc.UnmarshalJSON(pvJSONBytes, &pv)
if err != nil {
return nil, err
}
// overwrite pubkey and address for convenience
pv.PubKey = pv.PrivKey.PubKey()
pv.Address = pv.PubKey.Address()
pv.filePath = filePath
return pv, nil
}
// Upgrade convets the OldFilePV to the new FilePV, separating the immutable and mutable components,
// and persisting them to the keyFilePath and stateFilePath, respectively.
// It renames the original file by adding ".bak".
func (oldFilePV *OldFilePV) Upgrade(keyFilePath, stateFilePath string) *FilePV {
privKey := oldFilePV.PrivKey
pvKey := FilePVKey{
PrivKey: privKey,
PubKey: privKey.PubKey(),
Address: privKey.PubKey().Address(),
filePath: keyFilePath,
}
pvState := FilePVLastSignState{
Height: oldFilePV.LastHeight,
Round: oldFilePV.LastRound,
Step: oldFilePV.LastStep,
Signature: oldFilePV.LastSignature,
SignBytes: oldFilePV.LastSignBytes,
filePath: stateFilePath,
}
// Save the new PV files
pv := &FilePV{
Key: pvKey,
LastSignState: pvState,
}
pv.Save()
// Rename the old PV file
err := os.Rename(oldFilePV.filePath, oldFilePV.filePath+".bak")
if err != nil {
panic(err)
}
return pv
}

View File

@@ -0,0 +1,77 @@
package privval_test
import (
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/privval"
)
const oldPrivvalContent = `{
"address": "1D8089FAFDFAE4A637F3D616E17B92905FA2D91D",
"pub_key": {
"type": "tendermint/PubKeyEd25519",
"value": "r3Yg2AhDZ745CNTpavsGU+mRZ8WpRXqoJuyqjN8mJq0="
},
"last_height": "5",
"last_round": "0",
"last_step": 3,
"last_signature": "CTr7b9ZQlrJJf+12rPl5t/YSCUc/KqV7jQogCfFJA24e7hof69X6OMT7eFLVQHyodPjD/QTA298XHV5ejxInDQ==",
"last_signbytes": "750802110500000000000000220B08B398F3E00510F48DA6402A480A20FC258973076512999C3E6839A22E9FBDB1B77CF993E8A9955412A41A59D4CAD312240A20C971B286ACB8AAA6FCA0365EB0A660B189EDC08B46B5AF2995DEFA51A28D215B10013211746573742D636861696E2D533245415533",
"priv_key": {
"type": "tendermint/PrivKeyEd25519",
"value": "7MwvTGEWWjsYwjn2IpRb+GYsWi9nnFsw8jPLLY1UtP6vdiDYCENnvjkI1Olq+wZT6ZFnxalFeqgm7KqM3yYmrQ=="
}
}`
func TestLoadAndUpgrade(t *testing.T) {
oldFilePath := initTmpOldFile(t)
defer os.Remove(oldFilePath)
newStateFile, err := ioutil.TempFile("", "priv_validator_state*.json")
defer os.Remove(newStateFile.Name())
require.NoError(t, err)
newKeyFile, err := ioutil.TempFile("", "priv_validator_key*.json")
defer os.Remove(newKeyFile.Name())
require.NoError(t, err)
oldPV, err := privval.LoadOldFilePV(oldFilePath)
assert.NoError(t, err)
newPV := oldPV.Upgrade(newKeyFile.Name(), newStateFile.Name())
assertEqualPV(t, oldPV, newPV)
assert.NoError(t, err)
upgradedPV := privval.LoadFilePV(newKeyFile.Name(), newStateFile.Name())
assertEqualPV(t, oldPV, upgradedPV)
oldPV, err = privval.LoadOldFilePV(oldFilePath + ".bak")
require.NoError(t, err)
assertEqualPV(t, oldPV, upgradedPV)
}
func assertEqualPV(t *testing.T, oldPV *privval.OldFilePV, newPV *privval.FilePV) {
assert.Equal(t, oldPV.Address, newPV.Key.Address)
assert.Equal(t, oldPV.Address, newPV.GetAddress())
assert.Equal(t, oldPV.PubKey, newPV.Key.PubKey)
assert.Equal(t, oldPV.PubKey, newPV.GetPubKey())
assert.Equal(t, oldPV.PrivKey, newPV.Key.PrivKey)
assert.Equal(t, oldPV.LastHeight, newPV.LastSignState.Height)
assert.Equal(t, oldPV.LastRound, newPV.LastSignState.Round)
assert.Equal(t, oldPV.LastSignature, newPV.LastSignState.Signature)
assert.Equal(t, oldPV.LastSignBytes, newPV.LastSignState.SignBytes)
assert.Equal(t, oldPV.LastStep, newPV.LastSignState.Step)
}
func initTmpOldFile(t *testing.T) string {
tmpfile, err := ioutil.TempFile("", "priv_validator_*.json")
require.NoError(t, err)
t.Logf("created test file %s", tmpfile.Name())
_, err = tmpfile.WriteString(oldPrivvalContent)
require.NoError(t, err)
return tmpfile.Name()
}

View File

@@ -5,7 +5,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"sync"
"time" "time"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
@@ -35,100 +34,90 @@ func voteToStep(vote *types.Vote) int8 {
} }
} }
// FilePV implements PrivValidator using data persisted to disk //-------------------------------------------------------------------------------
// to prevent double signing.
// NOTE: the directory containing the pv.filePath must already exist. // FilePVKey stores the immutable part of PrivValidator.
// It includes the LastSignature and LastSignBytes so we don't lose the signature type FilePVKey struct {
// if the process crashes after signing but before the resulting consensus message is processed. Address types.Address `json:"address"`
type FilePV struct { PubKey crypto.PubKey `json:"pub_key"`
Address types.Address `json:"address"` PrivKey crypto.PrivKey `json:"priv_key"`
PubKey crypto.PubKey `json:"pub_key"`
LastHeight int64 `json:"last_height"`
LastRound int `json:"last_round"`
LastStep int8 `json:"last_step"`
LastSignature []byte `json:"last_signature,omitempty"`
LastSignBytes cmn.HexBytes `json:"last_signbytes,omitempty"`
PrivKey crypto.PrivKey `json:"priv_key"`
// For persistence.
// Overloaded for testing.
filePath string filePath string
mtx sync.Mutex
} }
// GetAddress returns the address of the validator. // Save persists the FilePVKey to its filePath.
// Implements PrivValidator. func (pvKey FilePVKey) Save() {
func (pv *FilePV) GetAddress() types.Address { outFile := pvKey.filePath
return pv.Address
}
// GetPubKey returns the public key of the validator.
// Implements PrivValidator.
func (pv *FilePV) GetPubKey() crypto.PubKey {
return pv.PubKey
}
// GenFilePV generates a new validator with randomly generated private key
// and sets the filePath, but does not call Save().
func GenFilePV(filePath string) *FilePV {
privKey := ed25519.GenPrivKey()
return &FilePV{
Address: privKey.PubKey().Address(),
PubKey: privKey.PubKey(),
PrivKey: privKey,
LastStep: stepNone,
filePath: filePath,
}
}
// LoadFilePV loads a FilePV from the filePath. The FilePV handles double
// signing prevention by persisting data to the filePath. If the filePath does
// not exist, the FilePV must be created manually and saved.
func LoadFilePV(filePath string) *FilePV {
pvJSONBytes, err := ioutil.ReadFile(filePath)
if err != nil {
cmn.Exit(err.Error())
}
pv := &FilePV{}
err = cdc.UnmarshalJSON(pvJSONBytes, &pv)
if err != nil {
cmn.Exit(fmt.Sprintf("Error reading PrivValidator from %v: %v\n", filePath, err))
}
// overwrite pubkey and address for convenience
pv.PubKey = pv.PrivKey.PubKey()
pv.Address = pv.PubKey.Address()
pv.filePath = filePath
return pv
}
// LoadOrGenFilePV loads a FilePV from the given filePath
// or else generates a new one and saves it to the filePath.
func LoadOrGenFilePV(filePath string) *FilePV {
var pv *FilePV
if cmn.FileExists(filePath) {
pv = LoadFilePV(filePath)
} else {
pv = GenFilePV(filePath)
pv.Save()
}
return pv
}
// Save persists the FilePV to disk.
func (pv *FilePV) Save() {
pv.mtx.Lock()
defer pv.mtx.Unlock()
pv.save()
}
func (pv *FilePV) save() {
outFile := pv.filePath
if outFile == "" { if outFile == "" {
panic("Cannot save PrivValidator: filePath not set") panic("Cannot save PrivValidator key: filePath not set")
} }
jsonBytes, err := cdc.MarshalJSONIndent(pv, "", " ")
jsonBytes, err := cdc.MarshalJSONIndent(pvKey, "", " ")
if err != nil {
panic(err)
}
err = cmn.WriteFileAtomic(outFile, jsonBytes, 0600)
if err != nil {
panic(err)
}
}
//-------------------------------------------------------------------------------
// FilePVLastSignState stores the mutable part of PrivValidator.
type FilePVLastSignState struct {
Height int64 `json:"height"`
Round int `json:"round"`
Step int8 `json:"step"`
Signature []byte `json:"signature,omitempty"`
SignBytes cmn.HexBytes `json:"signbytes,omitempty"`
filePath string
}
// CheckHRS checks the given height, round, step (HRS) against that of the
// FilePVLastSignState. It returns an error if the arguments constitute a regression,
// or if they match but the SignBytes are empty.
// The returned boolean indicates whether the last Signature should be reused -
// it returns true if the HRS matches the arguments and the SignBytes are not empty (indicating
// we have already signed for this HRS, and can reuse the existing signature).
// It panics if the HRS matches the arguments, there's a SignBytes, but no Signature.
func (lss *FilePVLastSignState) CheckHRS(height int64, round int, step int8) (bool, error) {
if lss.Height > height {
return false, errors.New("Height regression")
}
if lss.Height == height {
if lss.Round > round {
return false, errors.New("Round regression")
}
if lss.Round == round {
if lss.Step > step {
return false, errors.New("Step regression")
} else if lss.Step == step {
if lss.SignBytes != nil {
if lss.Signature == nil {
panic("pv: Signature is nil but SignBytes is not!")
}
return true, nil
}
return false, errors.New("No SignBytes found")
}
}
}
return false, nil
}
// Save persists the FilePvLastSignState to its filePath.
func (lss *FilePVLastSignState) Save() {
outFile := lss.filePath
if outFile == "" {
panic("Cannot save FilePVLastSignState: filePath not set")
}
jsonBytes, err := cdc.MarshalJSONIndent(lss, "", " ")
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -138,23 +127,115 @@ func (pv *FilePV) save() {
} }
} }
// Reset resets all fields in the FilePV. //-------------------------------------------------------------------------------
// NOTE: Unsafe!
func (pv *FilePV) Reset() { // FilePV implements PrivValidator using data persisted to disk
var sig []byte // to prevent double signing.
pv.LastHeight = 0 // NOTE: the directories containing pv.Key.filePath and pv.LastSignState.filePath must already exist.
pv.LastRound = 0 // It includes the LastSignature and LastSignBytes so we don't lose the signature
pv.LastStep = 0 // if the process crashes after signing but before the resulting consensus message is processed.
pv.LastSignature = sig type FilePV struct {
pv.LastSignBytes = nil Key FilePVKey
pv.Save() LastSignState FilePVLastSignState
}
// GenFilePV generates a new validator with randomly generated private key
// and sets the filePaths, but does not call Save().
func GenFilePV(keyFilePath, stateFilePath string) *FilePV {
privKey := ed25519.GenPrivKey()
return &FilePV{
Key: FilePVKey{
Address: privKey.PubKey().Address(),
PubKey: privKey.PubKey(),
PrivKey: privKey,
filePath: keyFilePath,
},
LastSignState: FilePVLastSignState{
Step: stepNone,
filePath: stateFilePath,
},
}
}
// LoadFilePV loads a FilePV from the filePaths. The FilePV handles double
// signing prevention by persisting data to the stateFilePath. If either file path
// does not exist, the program will exit.
func LoadFilePV(keyFilePath, stateFilePath string) *FilePV {
return loadFilePV(keyFilePath, stateFilePath, true)
}
// LoadFilePVEmptyState loads a FilePV from the given keyFilePath, with an empty LastSignState.
// If the keyFilePath does not exist, the program will exit.
func LoadFilePVEmptyState(keyFilePath, stateFilePath string) *FilePV {
return loadFilePV(keyFilePath, stateFilePath, false)
}
// If loadState is true, we load from the stateFilePath. Otherwise, we use an empty LastSignState.
func loadFilePV(keyFilePath, stateFilePath string, loadState bool) *FilePV {
keyJSONBytes, err := ioutil.ReadFile(keyFilePath)
if err != nil {
cmn.Exit(err.Error())
}
pvKey := FilePVKey{}
err = cdc.UnmarshalJSON(keyJSONBytes, &pvKey)
if err != nil {
cmn.Exit(fmt.Sprintf("Error reading PrivValidator key from %v: %v\n", keyFilePath, err))
}
// overwrite pubkey and address for convenience
pvKey.PubKey = pvKey.PrivKey.PubKey()
pvKey.Address = pvKey.PubKey.Address()
pvKey.filePath = keyFilePath
pvState := FilePVLastSignState{}
if loadState {
stateJSONBytes, err := ioutil.ReadFile(stateFilePath)
if err != nil {
cmn.Exit(err.Error())
}
err = cdc.UnmarshalJSON(stateJSONBytes, &pvState)
if err != nil {
cmn.Exit(fmt.Sprintf("Error reading PrivValidator state from %v: %v\n", stateFilePath, err))
}
}
pvState.filePath = stateFilePath
return &FilePV{
Key: pvKey,
LastSignState: pvState,
}
}
// LoadOrGenFilePV loads a FilePV from the given filePaths
// or else generates a new one and saves it to the filePaths.
func LoadOrGenFilePV(keyFilePath, stateFilePath string) *FilePV {
var pv *FilePV
if cmn.FileExists(keyFilePath) {
pv = LoadFilePV(keyFilePath, stateFilePath)
} else {
pv = GenFilePV(keyFilePath, stateFilePath)
pv.Save()
}
return pv
}
// GetAddress returns the address of the validator.
// Implements PrivValidator.
func (pv *FilePV) GetAddress() types.Address {
return pv.Key.Address
}
// GetPubKey returns the public key of the validator.
// Implements PrivValidator.
func (pv *FilePV) GetPubKey() crypto.PubKey {
return pv.Key.PubKey
} }
// SignVote signs a canonical representation of the vote, along with the // SignVote signs a canonical representation of the vote, along with the
// chainID. Implements PrivValidator. // chainID. Implements PrivValidator.
func (pv *FilePV) SignVote(chainID string, vote *types.Vote) error { func (pv *FilePV) SignVote(chainID string, vote *types.Vote) error {
pv.mtx.Lock()
defer pv.mtx.Unlock()
if err := pv.signVote(chainID, vote); err != nil { if err := pv.signVote(chainID, vote); err != nil {
return fmt.Errorf("Error signing vote: %v", err) return fmt.Errorf("Error signing vote: %v", err)
} }
@@ -164,65 +245,63 @@ func (pv *FilePV) SignVote(chainID string, vote *types.Vote) error {
// SignProposal signs a canonical representation of the proposal, along with // SignProposal signs a canonical representation of the proposal, along with
// the chainID. Implements PrivValidator. // the chainID. Implements PrivValidator.
func (pv *FilePV) SignProposal(chainID string, proposal *types.Proposal) error { func (pv *FilePV) SignProposal(chainID string, proposal *types.Proposal) error {
pv.mtx.Lock()
defer pv.mtx.Unlock()
if err := pv.signProposal(chainID, proposal); err != nil { if err := pv.signProposal(chainID, proposal); err != nil {
return fmt.Errorf("Error signing proposal: %v", err) return fmt.Errorf("Error signing proposal: %v", err)
} }
return nil return nil
} }
// returns error if HRS regression or no LastSignBytes. returns true if HRS is unchanged // Save persists the FilePV to disk.
func (pv *FilePV) checkHRS(height int64, round int, step int8) (bool, error) { func (pv *FilePV) Save() {
if pv.LastHeight > height { pv.Key.Save()
return false, errors.New("Height regression") pv.LastSignState.Save()
}
if pv.LastHeight == height {
if pv.LastRound > round {
return false, errors.New("Round regression")
}
if pv.LastRound == round {
if pv.LastStep > step {
return false, errors.New("Step regression")
} else if pv.LastStep == step {
if pv.LastSignBytes != nil {
if pv.LastSignature == nil {
panic("pv: LastSignature is nil but LastSignBytes is not!")
}
return true, nil
}
return false, errors.New("No LastSignature found")
}
}
}
return false, nil
} }
// Reset resets all fields in the FilePV.
// NOTE: Unsafe!
func (pv *FilePV) Reset() {
var sig []byte
pv.LastSignState.Height = 0
pv.LastSignState.Round = 0
pv.LastSignState.Step = 0
pv.LastSignState.Signature = sig
pv.LastSignState.SignBytes = nil
pv.Save()
}
// String returns a string representation of the FilePV.
func (pv *FilePV) String() string {
return fmt.Sprintf("PrivValidator{%v LH:%v, LR:%v, LS:%v}", pv.GetAddress(), pv.LastSignState.Height, pv.LastSignState.Round, pv.LastSignState.Step)
}
//------------------------------------------------------------------------------------
// signVote checks if the vote is good to sign and sets the vote signature. // signVote checks if the vote is good to sign and sets the vote signature.
// It may need to set the timestamp as well if the vote is otherwise the same as // It may need to set the timestamp as well if the vote is otherwise the same as
// a previously signed vote (ie. we crashed after signing but before the vote hit the WAL). // a previously signed vote (ie. we crashed after signing but before the vote hit the WAL).
func (pv *FilePV) signVote(chainID string, vote *types.Vote) error { func (pv *FilePV) signVote(chainID string, vote *types.Vote) error {
height, round, step := vote.Height, vote.Round, voteToStep(vote) height, round, step := vote.Height, vote.Round, voteToStep(vote)
signBytes := vote.SignBytes(chainID)
sameHRS, err := pv.checkHRS(height, round, step) lss := pv.LastSignState
sameHRS, err := lss.CheckHRS(height, round, step)
if err != nil { if err != nil {
return err return err
} }
signBytes := vote.SignBytes(chainID)
// We might crash before writing to the wal, // We might crash before writing to the wal,
// causing us to try to re-sign for the same HRS. // causing us to try to re-sign for the same HRS.
// If signbytes are the same, use the last signature. // If signbytes are the same, use the last signature.
// If they only differ by timestamp, use last timestamp and signature // If they only differ by timestamp, use last timestamp and signature
// Otherwise, return error // Otherwise, return error
if sameHRS { if sameHRS {
if bytes.Equal(signBytes, pv.LastSignBytes) { if bytes.Equal(signBytes, lss.SignBytes) {
vote.Signature = pv.LastSignature vote.Signature = lss.Signature
} else if timestamp, ok := checkVotesOnlyDifferByTimestamp(pv.LastSignBytes, signBytes); ok { } else if timestamp, ok := checkVotesOnlyDifferByTimestamp(lss.SignBytes, signBytes); ok {
vote.Timestamp = timestamp vote.Timestamp = timestamp
vote.Signature = pv.LastSignature vote.Signature = lss.Signature
} else { } else {
err = fmt.Errorf("Conflicting data") err = fmt.Errorf("Conflicting data")
} }
@@ -230,7 +309,7 @@ func (pv *FilePV) signVote(chainID string, vote *types.Vote) error {
} }
// It passed the checks. Sign the vote // It passed the checks. Sign the vote
sig, err := pv.PrivKey.Sign(signBytes) sig, err := pv.Key.PrivKey.Sign(signBytes)
if err != nil { if err != nil {
return err return err
} }
@@ -244,24 +323,27 @@ func (pv *FilePV) signVote(chainID string, vote *types.Vote) error {
// a previously signed proposal ie. we crashed after signing but before the proposal hit the WAL). // a previously signed proposal ie. we crashed after signing but before the proposal hit the WAL).
func (pv *FilePV) signProposal(chainID string, proposal *types.Proposal) error { func (pv *FilePV) signProposal(chainID string, proposal *types.Proposal) error {
height, round, step := proposal.Height, proposal.Round, stepPropose height, round, step := proposal.Height, proposal.Round, stepPropose
signBytes := proposal.SignBytes(chainID)
sameHRS, err := pv.checkHRS(height, round, step) lss := pv.LastSignState
sameHRS, err := lss.CheckHRS(height, round, step)
if err != nil { if err != nil {
return err return err
} }
signBytes := proposal.SignBytes(chainID)
// We might crash before writing to the wal, // We might crash before writing to the wal,
// causing us to try to re-sign for the same HRS. // causing us to try to re-sign for the same HRS.
// If signbytes are the same, use the last signature. // If signbytes are the same, use the last signature.
// If they only differ by timestamp, use last timestamp and signature // If they only differ by timestamp, use last timestamp and signature
// Otherwise, return error // Otherwise, return error
if sameHRS { if sameHRS {
if bytes.Equal(signBytes, pv.LastSignBytes) { if bytes.Equal(signBytes, lss.SignBytes) {
proposal.Signature = pv.LastSignature proposal.Signature = lss.Signature
} else if timestamp, ok := checkProposalsOnlyDifferByTimestamp(pv.LastSignBytes, signBytes); ok { } else if timestamp, ok := checkProposalsOnlyDifferByTimestamp(lss.SignBytes, signBytes); ok {
proposal.Timestamp = timestamp proposal.Timestamp = timestamp
proposal.Signature = pv.LastSignature proposal.Signature = lss.Signature
} else { } else {
err = fmt.Errorf("Conflicting data") err = fmt.Errorf("Conflicting data")
} }
@@ -269,7 +351,7 @@ func (pv *FilePV) signProposal(chainID string, proposal *types.Proposal) error {
} }
// It passed the checks. Sign the proposal // It passed the checks. Sign the proposal
sig, err := pv.PrivKey.Sign(signBytes) sig, err := pv.Key.PrivKey.Sign(signBytes)
if err != nil { if err != nil {
return err return err
} }
@@ -282,20 +364,15 @@ func (pv *FilePV) signProposal(chainID string, proposal *types.Proposal) error {
func (pv *FilePV) saveSigned(height int64, round int, step int8, func (pv *FilePV) saveSigned(height int64, round int, step int8,
signBytes []byte, sig []byte) { signBytes []byte, sig []byte) {
pv.LastHeight = height pv.LastSignState.Height = height
pv.LastRound = round pv.LastSignState.Round = round
pv.LastStep = step pv.LastSignState.Step = step
pv.LastSignature = sig pv.LastSignState.Signature = sig
pv.LastSignBytes = signBytes pv.LastSignState.SignBytes = signBytes
pv.save() pv.LastSignState.Save()
} }
// String returns a string representation of the FilePV. //-----------------------------------------------------------------------------------------
func (pv *FilePV) String() string {
return fmt.Sprintf("PrivValidator{%v LH:%v, LR:%v, LS:%v}", pv.GetAddress(), pv.LastHeight, pv.LastRound, pv.LastStep)
}
//-------------------------------------
// returns the timestamp from the lastSignBytes. // returns the timestamp from the lastSignBytes.
// returns true if the only difference in the votes is their timestamp. // returns true if the only difference in the votes is their timestamp.

View File

@@ -18,36 +18,100 @@ import (
func TestGenLoadValidator(t *testing.T) { func TestGenLoadValidator(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
tempFile, err := ioutil.TempFile("", "priv_validator_") tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_")
require.Nil(t, err) require.Nil(t, err)
privVal := GenFilePV(tempFile.Name()) tempStateFile, err := ioutil.TempFile("", "priv_validator_state_")
require.Nil(t, err)
privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
height := int64(100) height := int64(100)
privVal.LastHeight = height privVal.LastSignState.Height = height
privVal.Save() privVal.Save()
addr := privVal.GetAddress() addr := privVal.GetAddress()
privVal = LoadFilePV(tempFile.Name()) privVal = LoadFilePV(tempKeyFile.Name(), tempStateFile.Name())
assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same") assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same")
assert.Equal(height, privVal.LastHeight, "expected privval.LastHeight to have been saved") assert.Equal(height, privVal.LastSignState.Height, "expected privval.LastHeight to have been saved")
}
func TestResetValidator(t *testing.T) {
tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_")
require.Nil(t, err)
tempStateFile, err := ioutil.TempFile("", "priv_validator_state_")
require.Nil(t, err)
privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
emptyState := FilePVLastSignState{filePath: tempStateFile.Name()}
// new priv val has empty state
assert.Equal(t, privVal.LastSignState, emptyState)
// test vote
height, round := int64(10), 1
voteType := byte(types.PrevoteType)
blockID := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{}}
vote := newVote(privVal.Key.Address, 0, height, round, voteType, blockID)
err = privVal.SignVote("mychainid", vote)
assert.NoError(t, err, "expected no error signing vote")
// priv val after signing is not same as empty
assert.NotEqual(t, privVal.LastSignState, emptyState)
// priv val after reset is same as empty
privVal.Reset()
assert.Equal(t, privVal.LastSignState, emptyState)
} }
func TestLoadOrGenValidator(t *testing.T) { func TestLoadOrGenValidator(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
tempFile, err := ioutil.TempFile("", "priv_validator_") tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_")
require.Nil(t, err) require.Nil(t, err)
tempFilePath := tempFile.Name() tempStateFile, err := ioutil.TempFile("", "priv_validator_state_")
if err := os.Remove(tempFilePath); err != nil { require.Nil(t, err)
tempKeyFilePath := tempKeyFile.Name()
if err := os.Remove(tempKeyFilePath); err != nil {
t.Error(err) t.Error(err)
} }
privVal := LoadOrGenFilePV(tempFilePath) tempStateFilePath := tempStateFile.Name()
if err := os.Remove(tempStateFilePath); err != nil {
t.Error(err)
}
privVal := LoadOrGenFilePV(tempKeyFilePath, tempStateFilePath)
addr := privVal.GetAddress() addr := privVal.GetAddress()
privVal = LoadOrGenFilePV(tempFilePath) privVal = LoadOrGenFilePV(tempKeyFilePath, tempStateFilePath)
assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same") assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same")
} }
func TestUnmarshalValidator(t *testing.T) { func TestUnmarshalValidatorState(t *testing.T) {
assert, require := assert.New(t), require.New(t)
// create some fixed values
serialized := `{
"height": "1",
"round": "1",
"step": 1
}`
val := FilePVLastSignState{}
err := cdc.UnmarshalJSON([]byte(serialized), &val)
require.Nil(err, "%+v", err)
// make sure the values match
assert.EqualValues(val.Height, 1)
assert.EqualValues(val.Round, 1)
assert.EqualValues(val.Step, 1)
// export it and make sure it is the same
out, err := cdc.MarshalJSON(val)
require.Nil(err, "%+v", err)
assert.JSONEq(serialized, string(out))
}
func TestUnmarshalValidatorKey(t *testing.T) {
assert, require := assert.New(t), require.New(t) assert, require := assert.New(t), require.New(t)
// create some fixed values // create some fixed values
@@ -67,22 +131,19 @@ func TestUnmarshalValidator(t *testing.T) {
"type": "tendermint/PubKeyEd25519", "type": "tendermint/PubKeyEd25519",
"value": "%s" "value": "%s"
}, },
"last_height": "0",
"last_round": "0",
"last_step": 0,
"priv_key": { "priv_key": {
"type": "tendermint/PrivKeyEd25519", "type": "tendermint/PrivKeyEd25519",
"value": "%s" "value": "%s"
} }
}`, addr, pubB64, privB64) }`, addr, pubB64, privB64)
val := FilePV{} val := FilePVKey{}
err := cdc.UnmarshalJSON([]byte(serialized), &val) err := cdc.UnmarshalJSON([]byte(serialized), &val)
require.Nil(err, "%+v", err) require.Nil(err, "%+v", err)
// make sure the values match // make sure the values match
assert.EqualValues(addr, val.GetAddress()) assert.EqualValues(addr, val.Address)
assert.EqualValues(pubKey, val.GetPubKey()) assert.EqualValues(pubKey, val.PubKey)
assert.EqualValues(privKey, val.PrivKey) assert.EqualValues(privKey, val.PrivKey)
// export it and make sure it is the same // export it and make sure it is the same
@@ -94,9 +155,12 @@ func TestUnmarshalValidator(t *testing.T) {
func TestSignVote(t *testing.T) { func TestSignVote(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
tempFile, err := ioutil.TempFile("", "priv_validator_") tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_")
require.Nil(t, err) require.Nil(t, err)
privVal := GenFilePV(tempFile.Name()) tempStateFile, err := ioutil.TempFile("", "priv_validator_state_")
require.Nil(t, err)
privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
block1 := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{}} block1 := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{}}
block2 := types.BlockID{[]byte{3, 2, 1}, types.PartSetHeader{}} block2 := types.BlockID{[]byte{3, 2, 1}, types.PartSetHeader{}}
@@ -104,7 +168,7 @@ func TestSignVote(t *testing.T) {
voteType := byte(types.PrevoteType) voteType := byte(types.PrevoteType)
// sign a vote for first time // sign a vote for first time
vote := newVote(privVal.Address, 0, height, round, voteType, block1) vote := newVote(privVal.Key.Address, 0, height, round, voteType, block1)
err = privVal.SignVote("mychainid", vote) err = privVal.SignVote("mychainid", vote)
assert.NoError(err, "expected no error signing vote") assert.NoError(err, "expected no error signing vote")
@@ -114,10 +178,10 @@ func TestSignVote(t *testing.T) {
// now try some bad votes // now try some bad votes
cases := []*types.Vote{ cases := []*types.Vote{
newVote(privVal.Address, 0, height, round-1, voteType, block1), // round regression newVote(privVal.Key.Address, 0, height, round-1, voteType, block1), // round regression
newVote(privVal.Address, 0, height-1, round, voteType, block1), // height regression newVote(privVal.Key.Address, 0, height-1, round, voteType, block1), // height regression
newVote(privVal.Address, 0, height-2, round+4, voteType, block1), // height regression and different round newVote(privVal.Key.Address, 0, height-2, round+4, voteType, block1), // height regression and different round
newVote(privVal.Address, 0, height, round, voteType, block2), // different block newVote(privVal.Key.Address, 0, height, round, voteType, block2), // different block
} }
for _, c := range cases { for _, c := range cases {
@@ -136,9 +200,12 @@ func TestSignVote(t *testing.T) {
func TestSignProposal(t *testing.T) { func TestSignProposal(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
tempFile, err := ioutil.TempFile("", "priv_validator_") tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_")
require.Nil(t, err) require.Nil(t, err)
privVal := GenFilePV(tempFile.Name()) tempStateFile, err := ioutil.TempFile("", "priv_validator_state_")
require.Nil(t, err)
privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
block1 := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{5, []byte{1, 2, 3}}} block1 := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{5, []byte{1, 2, 3}}}
block2 := types.BlockID{[]byte{3, 2, 1}, types.PartSetHeader{10, []byte{3, 2, 1}}} block2 := types.BlockID{[]byte{3, 2, 1}, types.PartSetHeader{10, []byte{3, 2, 1}}}
@@ -175,9 +242,12 @@ func TestSignProposal(t *testing.T) {
} }
func TestDifferByTimestamp(t *testing.T) { func TestDifferByTimestamp(t *testing.T) {
tempFile, err := ioutil.TempFile("", "priv_validator_") tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_")
require.Nil(t, err) require.Nil(t, err)
privVal := GenFilePV(tempFile.Name()) tempStateFile, err := ioutil.TempFile("", "priv_validator_state_")
require.Nil(t, err)
privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
block1 := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{5, []byte{1, 2, 3}}} block1 := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{5, []byte{1, 2, 3}}}
height, round := int64(10), 1 height, round := int64(10), 1
@@ -208,7 +278,7 @@ func TestDifferByTimestamp(t *testing.T) {
{ {
voteType := byte(types.PrevoteType) voteType := byte(types.PrevoteType)
blockID := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{}} blockID := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{}}
vote := newVote(privVal.Address, 0, height, round, voteType, blockID) vote := newVote(privVal.Key.Address, 0, height, round, voteType, blockID)
err := privVal.SignVote("mychainid", vote) err := privVal.SignVote("mychainid", vote)
assert.NoError(t, err, "expected no error signing vote") assert.NoError(t, err, "expected no error signing vote")

View File

@@ -6,6 +6,8 @@ import (
"net" "net"
"sync" "sync"
"github.com/pkg/errors"
"github.com/tendermint/go-amino" "github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
cmn "github.com/tendermint/tendermint/libs/common" cmn "github.com/tendermint/tendermint/libs/common"
@@ -15,8 +17,9 @@ import (
// RemoteSignerClient implements PrivValidator, it uses a socket to request signatures // RemoteSignerClient implements PrivValidator, it uses a socket to request signatures
// from an external process. // from an external process.
type RemoteSignerClient struct { type RemoteSignerClient struct {
conn net.Conn conn net.Conn
lock sync.Mutex consensusPubKey crypto.PubKey
mtx sync.Mutex
} }
// Check that RemoteSignerClient implements PrivValidator. // Check that RemoteSignerClient implements PrivValidator.
@@ -25,38 +28,29 @@ var _ types.PrivValidator = (*RemoteSignerClient)(nil)
// NewRemoteSignerClient returns an instance of RemoteSignerClient. // NewRemoteSignerClient returns an instance of RemoteSignerClient.
func NewRemoteSignerClient( func NewRemoteSignerClient(
conn net.Conn, conn net.Conn,
) *RemoteSignerClient { ) (*RemoteSignerClient, error) {
sc := &RemoteSignerClient{ sc := &RemoteSignerClient{
conn: conn, conn: conn,
} }
return sc
}
// GetAddress implements PrivValidator.
func (sc *RemoteSignerClient) GetAddress() types.Address {
pubKey, err := sc.getPubKey() pubKey, err := sc.getPubKey()
if err != nil { if err != nil {
panic(err) return nil, cmn.ErrorWrap(err, "error while retrieving public key for remote signer")
} }
// retrieve and memoize the consensus public key once:
return pubKey.Address() sc.consensusPubKey = pubKey
return sc, nil
} }
// GetPubKey implements PrivValidator. // GetPubKey implements PrivValidator.
func (sc *RemoteSignerClient) GetPubKey() crypto.PubKey { func (sc *RemoteSignerClient) GetPubKey() crypto.PubKey {
pubKey, err := sc.getPubKey() return sc.consensusPubKey
if err != nil {
panic(err)
}
return pubKey
} }
func (sc *RemoteSignerClient) getPubKey() (crypto.PubKey, error) { func (sc *RemoteSignerClient) getPubKey() (crypto.PubKey, error) {
sc.lock.Lock() sc.mtx.Lock()
defer sc.lock.Unlock() defer sc.mtx.Unlock()
err := writeMsg(sc.conn, &PubKeyMsg{}) err := writeMsg(sc.conn, &PubKeyRequest{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -65,14 +59,22 @@ func (sc *RemoteSignerClient) getPubKey() (crypto.PubKey, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
pubKeyResp, ok := res.(*PubKeyResponse)
if !ok {
return nil, errors.Wrap(ErrUnexpectedResponse, "response is not PubKeyResponse")
}
return res.(*PubKeyMsg).PubKey, nil if pubKeyResp.Error != nil {
return nil, errors.Wrap(pubKeyResp.Error, "failed to get private validator's public key")
}
return pubKeyResp.PubKey, nil
} }
// SignVote implements PrivValidator. // SignVote implements PrivValidator.
func (sc *RemoteSignerClient) SignVote(chainID string, vote *types.Vote) error { func (sc *RemoteSignerClient) SignVote(chainID string, vote *types.Vote) error {
sc.lock.Lock() sc.mtx.Lock()
defer sc.lock.Unlock() defer sc.mtx.Unlock()
err := writeMsg(sc.conn, &SignVoteRequest{Vote: vote}) err := writeMsg(sc.conn, &SignVoteRequest{Vote: vote})
if err != nil { if err != nil {
@@ -101,8 +103,8 @@ func (sc *RemoteSignerClient) SignProposal(
chainID string, chainID string,
proposal *types.Proposal, proposal *types.Proposal,
) error { ) error {
sc.lock.Lock() sc.mtx.Lock()
defer sc.lock.Unlock() defer sc.mtx.Unlock()
err := writeMsg(sc.conn, &SignProposalRequest{Proposal: proposal}) err := writeMsg(sc.conn, &SignProposalRequest{Proposal: proposal})
if err != nil { if err != nil {
@@ -127,8 +129,8 @@ func (sc *RemoteSignerClient) SignProposal(
// Ping is used to check connection health. // Ping is used to check connection health.
func (sc *RemoteSignerClient) Ping() error { func (sc *RemoteSignerClient) Ping() error {
sc.lock.Lock() sc.mtx.Lock()
defer sc.lock.Unlock() defer sc.mtx.Unlock()
err := writeMsg(sc.conn, &PingRequest{}) err := writeMsg(sc.conn, &PingRequest{})
if err != nil { if err != nil {
@@ -152,7 +154,8 @@ type RemoteSignerMsg interface{}
func RegisterRemoteSignerMsg(cdc *amino.Codec) { func RegisterRemoteSignerMsg(cdc *amino.Codec) {
cdc.RegisterInterface((*RemoteSignerMsg)(nil), nil) cdc.RegisterInterface((*RemoteSignerMsg)(nil), nil)
cdc.RegisterConcrete(&PubKeyMsg{}, "tendermint/remotesigner/PubKeyMsg", nil) cdc.RegisterConcrete(&PubKeyRequest{}, "tendermint/remotesigner/PubKeyRequest", nil)
cdc.RegisterConcrete(&PubKeyResponse{}, "tendermint/remotesigner/PubKeyResponse", nil)
cdc.RegisterConcrete(&SignVoteRequest{}, "tendermint/remotesigner/SignVoteRequest", nil) cdc.RegisterConcrete(&SignVoteRequest{}, "tendermint/remotesigner/SignVoteRequest", nil)
cdc.RegisterConcrete(&SignedVoteResponse{}, "tendermint/remotesigner/SignedVoteResponse", nil) cdc.RegisterConcrete(&SignedVoteResponse{}, "tendermint/remotesigner/SignedVoteResponse", nil)
cdc.RegisterConcrete(&SignProposalRequest{}, "tendermint/remotesigner/SignProposalRequest", nil) cdc.RegisterConcrete(&SignProposalRequest{}, "tendermint/remotesigner/SignProposalRequest", nil)
@@ -161,9 +164,13 @@ func RegisterRemoteSignerMsg(cdc *amino.Codec) {
cdc.RegisterConcrete(&PingResponse{}, "tendermint/remotesigner/PingResponse", nil) cdc.RegisterConcrete(&PingResponse{}, "tendermint/remotesigner/PingResponse", nil)
} }
// PubKeyMsg is a PrivValidatorSocket message containing the public key. // PubKeyRequest requests the consensus public key from the remote signer.
type PubKeyMsg struct { type PubKeyRequest struct{}
// PubKeyResponse is a PrivValidatorSocket message containing the public key.
type PubKeyResponse struct {
PubKey crypto.PubKey PubKey crypto.PubKey
Error *RemoteSignerError
} }
// SignVoteRequest is a PrivValidatorSocket message containing a vote. // SignVoteRequest is a PrivValidatorSocket message containing a vote.
@@ -227,10 +234,10 @@ func handleRequest(req RemoteSignerMsg, chainID string, privVal types.PrivValida
var err error var err error
switch r := req.(type) { switch r := req.(type) {
case *PubKeyMsg: case *PubKeyRequest:
var p crypto.PubKey var p crypto.PubKey
p = privVal.GetPubKey() p = privVal.GetPubKey()
res = &PubKeyMsg{p} res = &PubKeyResponse{p, nil}
case *SignVoteRequest: case *SignVoteRequest:
err = privVal.SignVote(chainID, r.Vote) err = privVal.SignVote(chainID, r.Vote)
if err != nil { if err != nil {

View File

@@ -107,8 +107,10 @@ func (sc *TCPVal) OnStart() error {
} }
sc.conn = conn sc.conn = conn
sc.RemoteSignerClient, err = NewRemoteSignerClient(sc.conn)
sc.RemoteSignerClient = NewRemoteSignerClient(sc.conn) if err != nil {
return err
}
// Start a routine to keep the connection alive // Start a routine to keep the connection alive
sc.cancelPing = make(chan struct{}, 1) sc.cancelPing = make(chan struct{}, 1)

View File

@@ -25,15 +25,10 @@ func TestSocketPVAddress(t *testing.T) {
defer sc.Stop() defer sc.Stop()
defer rs.Stop() defer rs.Stop()
serverAddr := rs.privVal.GetAddress() serverAddr := rs.privVal.GetPubKey().Address()
clientAddr := sc.GetPubKey().Address()
clientAddr := sc.GetAddress()
assert.Equal(t, serverAddr, clientAddr) assert.Equal(t, serverAddr, clientAddr)
// TODO(xla): Remove when PrivValidator2 replaced PrivValidator.
assert.Equal(t, serverAddr, sc.GetAddress())
} }
func TestSocketPVPubKey(t *testing.T) { func TestSocketPVPubKey(t *testing.T) {
@@ -47,12 +42,9 @@ func TestSocketPVPubKey(t *testing.T) {
clientKey, err := sc.getPubKey() clientKey, err := sc.getPubKey()
require.NoError(t, err) require.NoError(t, err)
privKey := rs.privVal.GetPubKey() privvalPubKey := rs.privVal.GetPubKey()
assert.Equal(t, privKey, clientKey) assert.Equal(t, privvalPubKey, clientKey)
// TODO(xla): Remove when PrivValidator2 replaced PrivValidator.
assert.Equal(t, privKey, sc.GetPubKey())
} }
func TestSocketPVProposal(t *testing.T) { func TestSocketPVProposal(t *testing.T) {
@@ -153,9 +145,9 @@ func TestSocketPVDeadline(t *testing.T) {
go func(sc *TCPVal) { go func(sc *TCPVal) {
defer close(listenc) defer close(listenc)
require.NoError(t, sc.Start()) assert.Equal(t, sc.Start().(cmn.Error).Data(), ErrConnTimeout)
assert.True(t, sc.IsRunning()) assert.False(t, sc.IsRunning())
}(sc) }(sc)
for { for {
@@ -174,9 +166,6 @@ func TestSocketPVDeadline(t *testing.T) {
} }
<-listenc <-listenc
_, err := sc.getPubKey()
assert.Equal(t, err.(cmn.Error).Data(), ErrConnTimeout)
} }
func TestRemoteSignerRetry(t *testing.T) { func TestRemoteSignerRetry(t *testing.T) {
@@ -310,14 +299,15 @@ func TestErrUnexpectedResponse(t *testing.T) {
testStartSocketPV(t, readyc, sc) testStartSocketPV(t, readyc, sc)
defer sc.Stop() defer sc.Stop()
RemoteSignerConnDeadline(time.Millisecond)(rs) RemoteSignerConnDeadline(time.Millisecond)(rs)
RemoteSignerConnRetries(1e6)(rs) RemoteSignerConnRetries(100)(rs)
// we do not want to Start() the remote signer here and instead use the connection to // we do not want to Start() the remote signer here and instead use the connection to
// reply with intentionally wrong replies below: // reply with intentionally wrong replies below:
rsConn, err := rs.connect() rsConn, err := rs.connect()
defer rsConn.Close() defer rsConn.Close()
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, rsConn) require.NotNil(t, rsConn)
// send over public key to get the remote signer running:
go testReadWriteResponse(t, &PubKeyResponse{}, rsConn)
<-readyc <-readyc
// Proposal: // Proposal:

View File

@@ -6,6 +6,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
abcicli "github.com/tendermint/tendermint/abci/client" abcicli "github.com/tendermint/tendermint/abci/client"
"github.com/tendermint/tendermint/abci/example/counter"
"github.com/tendermint/tendermint/abci/example/kvstore" "github.com/tendermint/tendermint/abci/example/kvstore"
"github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/abci/types"
) )
@@ -64,15 +65,15 @@ func (r *remoteClientCreator) NewABCIClient() (abcicli.Client, error) {
func DefaultClientCreator(addr, transport, dbDir string) ClientCreator { func DefaultClientCreator(addr, transport, dbDir string) ClientCreator {
switch addr { switch addr {
case "counter":
return NewLocalClientCreator(counter.NewCounterApplication(false))
case "counter_serial":
return NewLocalClientCreator(counter.NewCounterApplication(true))
case "kvstore": case "kvstore":
fallthrough
case "dummy":
return NewLocalClientCreator(kvstore.NewKVStoreApplication()) return NewLocalClientCreator(kvstore.NewKVStoreApplication())
case "persistent_kvstore": case "persistent_kvstore":
fallthrough
case "persistent_dummy":
return NewLocalClientCreator(kvstore.NewPersistentKVStoreApplication(dbDir)) return NewLocalClientCreator(kvstore.NewPersistentKVStoreApplication(dbDir))
case "nilapp": case "noop":
return NewLocalClientCreator(types.NewBaseApplication()) return NewLocalClientCreator(types.NewBaseApplication())
default: default:
mustConnect := false // loop retrying mustConnect := false // loop retrying

View File

@@ -119,8 +119,9 @@ func NewTendermint(app abci.Application) *nm.Node {
config := GetConfig() config := GetConfig()
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger = log.NewFilter(logger, log.AllowError()) logger = log.NewFilter(logger, log.AllowError())
pvFile := config.PrivValidatorFile() pvKeyFile := config.PrivValidatorKeyFile()
pv := privval.LoadOrGenFilePV(pvFile) pvKeyStateFile := config.PrivValidatorStateFile()
pv := privval.LoadOrGenFilePV(pvKeyFile, pvKeyStateFile)
papp := proxy.NewLocalClientCreator(app) papp := proxy.NewLocalClientCreator(app)
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
if err != nil { if err != nil {

View File

@@ -6,7 +6,7 @@ set -e
# Get the version from the environment, or try to figure it out. # Get the version from the environment, or try to figure it out.
if [ -z $VERSION ]; then if [ -z $VERSION ]; then
VERSION=$(awk -F\" '/Version =/ { print $2; exit }' < version/version.go) VERSION=$(awk -F\" 'TMCoreSemVer =/ { print $2; exit }' < version/version.go)
fi fi
if [ -z "$VERSION" ]; then if [ -z "$VERSION" ]; then
echo "Please specify a version." echo "Please specify a version."

View File

@@ -1,19 +1,11 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# XXX: this script is intended to be run from
# a fresh Digital Ocean droplet with Ubuntu
# upon its completion, you must either reset
# your terminal or run `source ~/.profile`
# as written, this script will install
# tendermint core from master branch
REPO=github.com/tendermint/tendermint REPO=github.com/tendermint/tendermint
# change this to a specific release or branch # change this to a specific release or branch
BRANCH=master BRANCH=master
GO_VERSION=1.11.2 GO_VERSION=1.11.4
sudo apt-get update -y sudo apt-get update -y

View File

@@ -16,7 +16,7 @@
set BRANCH=master set BRANCH=master
set REPO=github.com/tendermint/tendermint set REPO=github.com/tendermint/tendermint
set GO_VERSION=1.11.2 set GO_VERSION=1.11.4
sudo pkg update sudo pkg update

View File

@@ -13,7 +13,7 @@ REPO=github.com/tendermint/tendermint
# change this to a specific release or branch # change this to a specific release or branch
BRANCH=master BRANCH=master
GO_VERSION=1.11.2 GO_VERSION=1.11.4
sudo apt-get update -y sudo apt-get update -y
sudo apt-get install -y make sudo apt-get install -y make

41
scripts/privValUpgrade.go Normal file
View File

@@ -0,0 +1,41 @@
package main
import (
"fmt"
"os"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/privval"
)
var (
logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
)
func main() {
args := os.Args[1:]
if len(args) != 3 {
fmt.Println("Expected three args: <old path> <new key path> <new state path>")
fmt.Println("Eg. ~/.tendermint/config/priv_validator.json ~/.tendermint/config/priv_validator_key.json ~/.tendermint/data/priv_validator_state.json")
os.Exit(1)
}
err := loadAndUpgrade(args[0], args[1], args[2])
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func loadAndUpgrade(oldPVPath, newPVKeyPath, newPVStatePath string) error {
oldPV, err := privval.LoadOldFilePV(oldPVPath)
if err != nil {
return fmt.Errorf("Error reading OldPrivValidator from %v: %v\n", oldPVPath, err)
}
logger.Info("Upgrading PrivValidator file",
"old", oldPVPath,
"newKey", newPVKeyPath,
"newState", newPVStatePath,
)
oldPV.Upgrade(newPVKeyPath, newPVStatePath)
return nil
}

View File

@@ -0,0 +1,121 @@
package main
import (
"fmt"
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/privval"
)
const oldPrivvalContent = `{
"address": "1D8089FAFDFAE4A637F3D616E17B92905FA2D91D",
"pub_key": {
"type": "tendermint/PubKeyEd25519",
"value": "r3Yg2AhDZ745CNTpavsGU+mRZ8WpRXqoJuyqjN8mJq0="
},
"last_height": "5",
"last_round": "0",
"last_step": 3,
"last_signature": "CTr7b9ZQlrJJf+12rPl5t/YSCUc/KqV7jQogCfFJA24e7hof69X6OMT7eFLVQHyodPjD/QTA298XHV5ejxInDQ==",
"last_signbytes": "750802110500000000000000220B08B398F3E00510F48DA6402A480A20FC258973076512999C3E6839A22E9FBDB1B77CF993E8A9955412A41A59D4CAD312240A20C971B286ACB8AAA6FCA0365EB0A660B189EDC08B46B5AF2995DEFA51A28D215B10013211746573742D636861696E2D533245415533",
"priv_key": {
"type": "tendermint/PrivKeyEd25519",
"value": "7MwvTGEWWjsYwjn2IpRb+GYsWi9nnFsw8jPLLY1UtP6vdiDYCENnvjkI1Olq+wZT6ZFnxalFeqgm7KqM3yYmrQ=="
}
}`
func TestLoadAndUpgrade(t *testing.T) {
oldFilePath := initTmpOldFile(t)
defer os.Remove(oldFilePath)
newStateFile, err := ioutil.TempFile("", "priv_validator_state*.json")
defer os.Remove(newStateFile.Name())
require.NoError(t, err)
newKeyFile, err := ioutil.TempFile("", "priv_validator_key*.json")
defer os.Remove(newKeyFile.Name())
require.NoError(t, err)
emptyOldFile, err := ioutil.TempFile("", "priv_validator_empty*.json")
require.NoError(t, err)
defer os.Remove(emptyOldFile.Name())
type args struct {
oldPVPath string
newPVKeyPath string
newPVStatePath string
}
tests := []struct {
name string
args args
wantErr bool
wantPanic bool
}{
{"successful upgrade",
args{oldPVPath: oldFilePath, newPVKeyPath: newKeyFile.Name(), newPVStatePath: newStateFile.Name()},
false, false,
},
{"unsuccessful upgrade: empty old privval file",
args{oldPVPath: emptyOldFile.Name(), newPVKeyPath: newKeyFile.Name(), newPVStatePath: newStateFile.Name()},
true, false,
},
{"unsuccessful upgrade: invalid new paths (1/3)",
args{oldPVPath: oldFilePath, newPVKeyPath: "", newPVStatePath: newStateFile.Name()},
false, true,
},
{"unsuccessful upgrade: invalid new paths (2/3)",
args{oldPVPath: oldFilePath, newPVKeyPath: newKeyFile.Name(), newPVStatePath: ""},
false, true,
},
{"unsuccessful upgrade: invalid new paths (3/3)",
args{oldPVPath: oldFilePath, newPVKeyPath: "", newPVStatePath: ""},
false, true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// need to re-write the file everytime because upgrading renames it
err := ioutil.WriteFile(oldFilePath, []byte(oldPrivvalContent), 0600)
require.NoError(t, err)
if tt.wantPanic {
require.Panics(t, func() { loadAndUpgrade(tt.args.oldPVPath, tt.args.newPVKeyPath, tt.args.newPVStatePath) })
} else {
err = loadAndUpgrade(tt.args.oldPVPath, tt.args.newPVKeyPath, tt.args.newPVStatePath)
if tt.wantErr {
assert.Error(t, err)
fmt.Println("ERR", err)
} else {
assert.NoError(t, err)
upgradedPV := privval.LoadFilePV(tt.args.newPVKeyPath, tt.args.newPVStatePath)
oldPV, err := privval.LoadOldFilePV(tt.args.oldPVPath + ".bak")
require.NoError(t, err)
assert.Equal(t, oldPV.Address, upgradedPV.Key.Address)
assert.Equal(t, oldPV.Address, upgradedPV.GetAddress())
assert.Equal(t, oldPV.PubKey, upgradedPV.Key.PubKey)
assert.Equal(t, oldPV.PubKey, upgradedPV.GetPubKey())
assert.Equal(t, oldPV.PrivKey, upgradedPV.Key.PrivKey)
assert.Equal(t, oldPV.LastHeight, upgradedPV.LastSignState.Height)
assert.Equal(t, oldPV.LastRound, upgradedPV.LastSignState.Round)
assert.Equal(t, oldPV.LastSignature, upgradedPV.LastSignState.Signature)
assert.Equal(t, oldPV.LastSignBytes, upgradedPV.LastSignState.SignBytes)
assert.Equal(t, oldPV.LastStep, upgradedPV.LastSignState.Step)
}
}
})
}
}
func initTmpOldFile(t *testing.T) string {
tmpfile, err := ioutil.TempFile("", "priv_validator_*.json")
require.NoError(t, err)
t.Logf("created test file %s", tmpfile.Name())
_, err = tmpfile.WriteString(oldPrivvalContent)
require.NoError(t, err)
return tmpfile.Name()
}

View File

@@ -6,7 +6,7 @@ DIST_DIR=./build/dist
# Get the version from the environment, or try to figure it out. # Get the version from the environment, or try to figure it out.
if [ -z $VERSION ]; then if [ -z $VERSION ]; then
VERSION=$(awk -F\" '/Version =/ { print $2; exit }' < version/version.go) VERSION=$(awk -F\" 'TMCoreSemVer =/ { print $2; exit }' < version/version.go)
fi fi
if [ -z "$VERSION" ]; then if [ -z "$VERSION" ]; then
echo "Please specify a version." echo "Please specify a version."

View File

@@ -3,7 +3,7 @@ set -e
# Get the version from the environment, or try to figure it out. # Get the version from the environment, or try to figure it out.
if [ -z $VERSION ]; then if [ -z $VERSION ]; then
VERSION=$(awk -F\" '/Version =/ { print $2; exit }' < version/version.go) VERSION=$(awk -F\" 'TMCoreSemVer =/ { print $2; exit }' < version/version.go)
fi fi
if [ -z "$VERSION" ]; then if [ -z "$VERSION" ]; then
echo "Please specify a version." echo "Please specify a version."

View File

@@ -1,182 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"time"
"github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/crypto/ed25519"
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/types"
)
type GenesisValidator struct {
PubKey Data `json:"pub_key"`
Power int64 `json:"power"`
Name string `json:"name"`
}
type Genesis struct {
GenesisTime time.Time `json:"genesis_time"`
ChainID string `json:"chain_id"`
ConsensusParams *types.ConsensusParams `json:"consensus_params,omitempty"`
Validators []GenesisValidator `json:"validators"`
AppHash cmn.HexBytes `json:"app_hash"`
AppState json.RawMessage `json:"app_state,omitempty"`
AppOptions json.RawMessage `json:"app_options,omitempty"` // DEPRECATED
}
type NodeKey struct {
PrivKey Data `json:"priv_key"`
}
type PrivVal struct {
Address cmn.HexBytes `json:"address"`
LastHeight int64 `json:"last_height"`
LastRound int `json:"last_round"`
LastStep int8 `json:"last_step"`
PubKey Data `json:"pub_key"`
PrivKey Data `json:"priv_key"`
}
type Data struct {
Type string `json:"type"`
Data cmn.HexBytes `json:"data"`
}
func convertNodeKey(cdc *amino.Codec, jsonBytes []byte) ([]byte, error) {
var nodeKey NodeKey
err := json.Unmarshal(jsonBytes, &nodeKey)
if err != nil {
return nil, err
}
var privKey ed25519.PrivKeyEd25519
copy(privKey[:], nodeKey.PrivKey.Data)
nodeKeyNew := p2p.NodeKey{privKey}
bz, err := cdc.MarshalJSON(nodeKeyNew)
if err != nil {
return nil, err
}
return bz, nil
}
func convertPrivVal(cdc *amino.Codec, jsonBytes []byte) ([]byte, error) {
var privVal PrivVal
err := json.Unmarshal(jsonBytes, &privVal)
if err != nil {
return nil, err
}
var privKey ed25519.PrivKeyEd25519
copy(privKey[:], privVal.PrivKey.Data)
var pubKey ed25519.PubKeyEd25519
copy(pubKey[:], privVal.PubKey.Data)
privValNew := privval.FilePV{
Address: pubKey.Address(),
PubKey: pubKey,
LastHeight: privVal.LastHeight,
LastRound: privVal.LastRound,
LastStep: privVal.LastStep,
PrivKey: privKey,
}
bz, err := cdc.MarshalJSON(privValNew)
if err != nil {
return nil, err
}
return bz, nil
}
func convertGenesis(cdc *amino.Codec, jsonBytes []byte) ([]byte, error) {
var genesis Genesis
err := json.Unmarshal(jsonBytes, &genesis)
if err != nil {
return nil, err
}
genesisNew := types.GenesisDoc{
GenesisTime: genesis.GenesisTime,
ChainID: genesis.ChainID,
ConsensusParams: genesis.ConsensusParams,
// Validators
AppHash: genesis.AppHash,
AppState: genesis.AppState,
}
if genesis.AppOptions != nil {
genesisNew.AppState = genesis.AppOptions
}
for _, v := range genesis.Validators {
var pubKey ed25519.PubKeyEd25519
copy(pubKey[:], v.PubKey.Data)
genesisNew.Validators = append(
genesisNew.Validators,
types.GenesisValidator{
PubKey: pubKey,
Power: v.Power,
Name: v.Name,
},
)
}
bz, err := cdc.MarshalJSON(genesisNew)
if err != nil {
return nil, err
}
return bz, nil
}
func main() {
cdc := amino.NewCodec()
cryptoAmino.RegisterAmino(cdc)
args := os.Args[1:]
if len(args) != 1 {
fmt.Println("Please specify a file to convert")
os.Exit(1)
}
filePath := args[0]
fileName := filepath.Base(filePath)
fileBytes, err := ioutil.ReadFile(filePath)
if err != nil {
panic(err)
}
var bz []byte
switch fileName {
case "node_key.json":
bz, err = convertNodeKey(cdc, fileBytes)
case "priv_validator.json":
bz, err = convertPrivVal(cdc, fileBytes)
case "genesis.json":
bz, err = convertGenesis(cdc, fileBytes)
default:
fmt.Println("Expected file name to be in (node_key.json, priv_validator.json, genesis.json)")
os.Exit(1)
}
if err != nil {
panic(err)
}
fmt.Println(string(bz))
}

View File

@@ -17,8 +17,9 @@ type voteData struct {
} }
func makeVote(val PrivValidator, chainID string, valIndex int, height int64, round, step int, blockID BlockID) *Vote { func makeVote(val PrivValidator, chainID string, valIndex int, height int64, round, step int, blockID BlockID) *Vote {
addr := val.GetPubKey().Address()
v := &Vote{ v := &Vote{
ValidatorAddress: val.GetAddress(), ValidatorAddress: addr,
ValidatorIndex: valIndex, ValidatorIndex: valIndex,
Height: height, Height: height,
Round: round, Round: round,

View File

@@ -12,7 +12,6 @@ import (
// PrivValidator defines the functionality of a local Tendermint validator // PrivValidator defines the functionality of a local Tendermint validator
// that signs votes and proposals, and never double signs. // that signs votes and proposals, and never double signs.
type PrivValidator interface { type PrivValidator interface {
GetAddress() Address // redundant since .PubKey().Address()
GetPubKey() crypto.PubKey GetPubKey() crypto.PubKey
SignVote(chainID string, vote *Vote) error SignVote(chainID string, vote *Vote) error
@@ -29,7 +28,7 @@ func (pvs PrivValidatorsByAddress) Len() int {
} }
func (pvs PrivValidatorsByAddress) Less(i, j int) bool { func (pvs PrivValidatorsByAddress) Less(i, j int) bool {
return bytes.Compare(pvs[i].GetAddress(), pvs[j].GetAddress()) == -1 return bytes.Compare(pvs[i].GetPubKey().Address(), pvs[j].GetPubKey().Address()) == -1
} }
func (pvs PrivValidatorsByAddress) Swap(i, j int) { func (pvs PrivValidatorsByAddress) Swap(i, j int) {
@@ -51,11 +50,6 @@ func NewMockPV() *MockPV {
return &MockPV{ed25519.GenPrivKey()} return &MockPV{ed25519.GenPrivKey()}
} }
// Implements PrivValidator.
func (pv *MockPV) GetAddress() Address {
return pv.privKey.PubKey().Address()
}
// Implements PrivValidator. // Implements PrivValidator.
func (pv *MockPV) GetPubKey() crypto.PubKey { func (pv *MockPV) GetPubKey() crypto.PubKey {
return pv.privKey.PubKey() return pv.privKey.PubKey()
@@ -85,7 +79,8 @@ func (pv *MockPV) SignProposal(chainID string, proposal *Proposal) error {
// String returns a string representation of the MockPV. // String returns a string representation of the MockPV.
func (pv *MockPV) String() string { func (pv *MockPV) String() string {
return fmt.Sprintf("MockPV{%v}", pv.GetAddress()) addr := pv.GetPubKey().Address()
return fmt.Sprintf("MockPV{%v}", addr)
} }
// XXX: Implement. // XXX: Implement.

View File

@@ -142,14 +142,15 @@ func TestABCIEvidence(t *testing.T) {
blockID := makeBlockID([]byte("blockhash"), 1000, []byte("partshash")) blockID := makeBlockID([]byte("blockhash"), 1000, []byte("partshash"))
blockID2 := makeBlockID([]byte("blockhash2"), 1000, []byte("partshash")) blockID2 := makeBlockID([]byte("blockhash2"), 1000, []byte("partshash"))
const chainID = "mychain" const chainID = "mychain"
pubKey := val.GetPubKey()
ev := &DuplicateVoteEvidence{ ev := &DuplicateVoteEvidence{
PubKey: val.GetPubKey(), PubKey: pubKey,
VoteA: makeVote(val, chainID, 0, 10, 2, 1, blockID), VoteA: makeVote(val, chainID, 0, 10, 2, 1, blockID),
VoteB: makeVote(val, chainID, 0, 10, 2, 1, blockID2), VoteB: makeVote(val, chainID, 0, 10, 2, 1, blockID2),
} }
abciEv := TM2PB.Evidence( abciEv := TM2PB.Evidence(
ev, ev,
NewValidatorSet([]*Validator{NewValidator(val.GetPubKey(), 10)}), NewValidatorSet([]*Validator{NewValidator(pubKey, 10)}),
time.Now(), time.Now(),
) )

View File

@@ -10,9 +10,9 @@ func MakeCommit(blockID BlockID, height int64, round int,
// all sign // all sign
for i := 0; i < len(validators); i++ { for i := 0; i < len(validators); i++ {
addr := validators[i].GetPubKey().Address()
vote := &Vote{ vote := &Vote{
ValidatorAddress: validators[i].GetAddress(), ValidatorAddress: addr,
ValidatorIndex: i, ValidatorIndex: i,
Height: height, Height: height,
Round: round, Round: round,

View File

@@ -103,9 +103,9 @@ func TestComputeTxsOverhead(t *testing.T) {
}{ }{
{Txs{[]byte{6, 6, 6, 6, 6, 6}}, 2}, {Txs{[]byte{6, 6, 6, 6, 6, 6}}, 2},
// one 21 Mb transaction: // one 21 Mb transaction:
{Txs{make([]byte, 22020096, 22020096)}, 5}, {Txs{make([]byte, 22020096)}, 5},
// two 21Mb/2 sized transactions: // two 21Mb/2 sized transactions:
{Txs{make([]byte, 11010048, 11010048), make([]byte, 11010048, 11010048)}, 10}, {Txs{make([]byte, 11010048), make([]byte, 11010048)}, 10},
{Txs{[]byte{1, 2, 3}, []byte{1, 2, 3}, []byte{4, 5, 6}}, 6}, {Txs{[]byte{1, 2, 3}, []byte{1, 2, 3}, []byte{4, 5, 6}}, 6},
{Txs{[]byte{100, 5, 64}, []byte{42, 116, 118}, []byte{6, 6, 6}, []byte{6, 6, 6}}, 8}, {Txs{[]byte{100, 5, 64}, []byte{42, 116, 118}, []byte{6, 6, 6}, []byte{6, 6, 6}}, 8},
} }

View File

@@ -101,6 +101,7 @@ func RandValidator(randPower bool, minPower int64) (*Validator, PrivValidator) {
if randPower { if randPower {
votePower += int64(cmn.RandUint32()) votePower += int64(cmn.RandUint32())
} }
val := NewValidator(privVal.GetPubKey(), votePower) pubKey := privVal.GetPubKey()
val := NewValidator(pubKey, votePower)
return val, privVal return val, privVal
} }

View File

@@ -66,7 +66,8 @@ func TestAddVote(t *testing.T) {
// t.Logf(">> %v", voteSet) // t.Logf(">> %v", voteSet)
if voteSet.GetByAddress(val0.GetAddress()) != nil { val0Addr := val0.GetPubKey().Address()
if voteSet.GetByAddress(val0Addr) != nil {
t.Errorf("Expected GetByAddress(val0.Address) to be nil") t.Errorf("Expected GetByAddress(val0.Address) to be nil")
} }
if voteSet.BitArray().GetIndex(0) { if voteSet.BitArray().GetIndex(0) {
@@ -78,7 +79,7 @@ func TestAddVote(t *testing.T) {
} }
vote := &Vote{ vote := &Vote{
ValidatorAddress: val0.GetAddress(), ValidatorAddress: val0Addr,
ValidatorIndex: 0, // since privValidators are in order ValidatorIndex: 0, // since privValidators are in order
Height: height, Height: height,
Round: round, Round: round,
@@ -91,7 +92,7 @@ func TestAddVote(t *testing.T) {
t.Error(err) t.Error(err)
} }
if voteSet.GetByAddress(val0.GetAddress()) == nil { if voteSet.GetByAddress(val0Addr) == nil {
t.Errorf("Expected GetByAddress(val0.Address) to be present") t.Errorf("Expected GetByAddress(val0.Address) to be present")
} }
if !voteSet.BitArray().GetIndex(0) { if !voteSet.BitArray().GetIndex(0) {
@@ -118,7 +119,8 @@ func Test2_3Majority(t *testing.T) {
} }
// 6 out of 10 voted for nil. // 6 out of 10 voted for nil.
for i := 0; i < 6; i++ { for i := 0; i < 6; i++ {
vote := withValidator(voteProto, privValidators[i].GetAddress(), i) addr := privValidators[i].GetPubKey().Address()
vote := withValidator(voteProto, addr, i)
_, err := signAddVote(privValidators[i], vote, voteSet) _, err := signAddVote(privValidators[i], vote, voteSet)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@@ -131,7 +133,8 @@ func Test2_3Majority(t *testing.T) {
// 7th validator voted for some blockhash // 7th validator voted for some blockhash
{ {
vote := withValidator(voteProto, privValidators[6].GetAddress(), 6) addr := privValidators[6].GetPubKey().Address()
vote := withValidator(voteProto, addr, 6)
_, err := signAddVote(privValidators[6], withBlockHash(vote, cmn.RandBytes(32)), voteSet) _, err := signAddVote(privValidators[6], withBlockHash(vote, cmn.RandBytes(32)), voteSet)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@@ -144,7 +147,8 @@ func Test2_3Majority(t *testing.T) {
// 8th validator voted for nil. // 8th validator voted for nil.
{ {
vote := withValidator(voteProto, privValidators[7].GetAddress(), 7) addr := privValidators[7].GetPubKey().Address()
vote := withValidator(voteProto, addr, 7)
_, err := signAddVote(privValidators[7], vote, voteSet) _, err := signAddVote(privValidators[7], vote, voteSet)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@@ -176,7 +180,8 @@ func Test2_3MajorityRedux(t *testing.T) {
// 66 out of 100 voted for nil. // 66 out of 100 voted for nil.
for i := 0; i < 66; i++ { for i := 0; i < 66; i++ {
vote := withValidator(voteProto, privValidators[i].GetAddress(), i) addr := privValidators[i].GetPubKey().Address()
vote := withValidator(voteProto, addr, i)
_, err := signAddVote(privValidators[i], vote, voteSet) _, err := signAddVote(privValidators[i], vote, voteSet)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@@ -189,7 +194,8 @@ func Test2_3MajorityRedux(t *testing.T) {
// 67th validator voted for nil // 67th validator voted for nil
{ {
vote := withValidator(voteProto, privValidators[66].GetAddress(), 66) adrr := privValidators[66].GetPubKey().Address()
vote := withValidator(voteProto, adrr, 66)
_, err := signAddVote(privValidators[66], withBlockHash(vote, nil), voteSet) _, err := signAddVote(privValidators[66], withBlockHash(vote, nil), voteSet)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@@ -202,7 +208,8 @@ func Test2_3MajorityRedux(t *testing.T) {
// 68th validator voted for a different BlockParts PartSetHeader // 68th validator voted for a different BlockParts PartSetHeader
{ {
vote := withValidator(voteProto, privValidators[67].GetAddress(), 67) addr := privValidators[67].GetPubKey().Address()
vote := withValidator(voteProto, addr, 67)
blockPartsHeader := PartSetHeader{blockPartsTotal, crypto.CRandBytes(32)} blockPartsHeader := PartSetHeader{blockPartsTotal, crypto.CRandBytes(32)}
_, err := signAddVote(privValidators[67], withBlockPartsHeader(vote, blockPartsHeader), voteSet) _, err := signAddVote(privValidators[67], withBlockPartsHeader(vote, blockPartsHeader), voteSet)
if err != nil { if err != nil {
@@ -216,7 +223,8 @@ func Test2_3MajorityRedux(t *testing.T) {
// 69th validator voted for different BlockParts Total // 69th validator voted for different BlockParts Total
{ {
vote := withValidator(voteProto, privValidators[68].GetAddress(), 68) addr := privValidators[68].GetPubKey().Address()
vote := withValidator(voteProto, addr, 68)
blockPartsHeader := PartSetHeader{blockPartsTotal + 1, blockPartsHeader.Hash} blockPartsHeader := PartSetHeader{blockPartsTotal + 1, blockPartsHeader.Hash}
_, err := signAddVote(privValidators[68], withBlockPartsHeader(vote, blockPartsHeader), voteSet) _, err := signAddVote(privValidators[68], withBlockPartsHeader(vote, blockPartsHeader), voteSet)
if err != nil { if err != nil {
@@ -230,7 +238,8 @@ func Test2_3MajorityRedux(t *testing.T) {
// 70th validator voted for different BlockHash // 70th validator voted for different BlockHash
{ {
vote := withValidator(voteProto, privValidators[69].GetAddress(), 69) addr := privValidators[69].GetPubKey().Address()
vote := withValidator(voteProto, addr, 69)
_, err := signAddVote(privValidators[69], withBlockHash(vote, cmn.RandBytes(32)), voteSet) _, err := signAddVote(privValidators[69], withBlockHash(vote, cmn.RandBytes(32)), voteSet)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@@ -243,7 +252,8 @@ func Test2_3MajorityRedux(t *testing.T) {
// 71st validator voted for the right BlockHash & BlockPartsHeader // 71st validator voted for the right BlockHash & BlockPartsHeader
{ {
vote := withValidator(voteProto, privValidators[70].GetAddress(), 70) addr := privValidators[70].GetPubKey().Address()
vote := withValidator(voteProto, addr, 70)
_, err := signAddVote(privValidators[70], vote, voteSet) _, err := signAddVote(privValidators[70], vote, voteSet)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@@ -271,7 +281,8 @@ func TestBadVotes(t *testing.T) {
// val0 votes for nil. // val0 votes for nil.
{ {
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0) addr := privValidators[0].GetPubKey().Address()
vote := withValidator(voteProto, addr, 0)
added, err := signAddVote(privValidators[0], vote, voteSet) added, err := signAddVote(privValidators[0], vote, voteSet)
if !added || err != nil { if !added || err != nil {
t.Errorf("Expected VoteSet.Add to succeed") t.Errorf("Expected VoteSet.Add to succeed")
@@ -280,7 +291,8 @@ func TestBadVotes(t *testing.T) {
// val0 votes again for some block. // val0 votes again for some block.
{ {
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0) addr := privValidators[0].GetPubKey().Address()
vote := withValidator(voteProto, addr, 0)
added, err := signAddVote(privValidators[0], withBlockHash(vote, cmn.RandBytes(32)), voteSet) added, err := signAddVote(privValidators[0], withBlockHash(vote, cmn.RandBytes(32)), voteSet)
if added || err == nil { if added || err == nil {
t.Errorf("Expected VoteSet.Add to fail, conflicting vote.") t.Errorf("Expected VoteSet.Add to fail, conflicting vote.")
@@ -289,7 +301,8 @@ func TestBadVotes(t *testing.T) {
// val1 votes on another height // val1 votes on another height
{ {
vote := withValidator(voteProto, privValidators[1].GetAddress(), 1) addr := privValidators[1].GetPubKey().Address()
vote := withValidator(voteProto, addr, 1)
added, err := signAddVote(privValidators[1], withHeight(vote, height+1), voteSet) added, err := signAddVote(privValidators[1], withHeight(vote, height+1), voteSet)
if added || err == nil { if added || err == nil {
t.Errorf("Expected VoteSet.Add to fail, wrong height") t.Errorf("Expected VoteSet.Add to fail, wrong height")
@@ -298,7 +311,8 @@ func TestBadVotes(t *testing.T) {
// val2 votes on another round // val2 votes on another round
{ {
vote := withValidator(voteProto, privValidators[2].GetAddress(), 2) addr := privValidators[2].GetPubKey().Address()
vote := withValidator(voteProto, addr, 2)
added, err := signAddVote(privValidators[2], withRound(vote, round+1), voteSet) added, err := signAddVote(privValidators[2], withRound(vote, round+1), voteSet)
if added || err == nil { if added || err == nil {
t.Errorf("Expected VoteSet.Add to fail, wrong round") t.Errorf("Expected VoteSet.Add to fail, wrong round")
@@ -307,7 +321,8 @@ func TestBadVotes(t *testing.T) {
// val3 votes of another type. // val3 votes of another type.
{ {
vote := withValidator(voteProto, privValidators[3].GetAddress(), 3) addr := privValidators[3].GetPubKey().Address()
vote := withValidator(voteProto, addr, 3)
added, err := signAddVote(privValidators[3], withType(vote, byte(PrecommitType)), voteSet) added, err := signAddVote(privValidators[3], withType(vote, byte(PrecommitType)), voteSet)
if added || err == nil { if added || err == nil {
t.Errorf("Expected VoteSet.Add to fail, wrong type") t.Errorf("Expected VoteSet.Add to fail, wrong type")
@@ -331,9 +346,10 @@ func TestConflicts(t *testing.T) {
BlockID: BlockID{nil, PartSetHeader{}}, BlockID: BlockID{nil, PartSetHeader{}},
} }
val0Addr := privValidators[0].GetPubKey().Address()
// val0 votes for nil. // val0 votes for nil.
{ {
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0) vote := withValidator(voteProto, val0Addr, 0)
added, err := signAddVote(privValidators[0], vote, voteSet) added, err := signAddVote(privValidators[0], vote, voteSet)
if !added || err != nil { if !added || err != nil {
t.Errorf("Expected VoteSet.Add to succeed") t.Errorf("Expected VoteSet.Add to succeed")
@@ -342,7 +358,7 @@ func TestConflicts(t *testing.T) {
// val0 votes again for blockHash1. // val0 votes again for blockHash1.
{ {
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0) vote := withValidator(voteProto, val0Addr, 0)
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet) added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet)
if added { if added {
t.Errorf("Expected VoteSet.Add to fail, conflicting vote.") t.Errorf("Expected VoteSet.Add to fail, conflicting vote.")
@@ -357,7 +373,7 @@ func TestConflicts(t *testing.T) {
// val0 votes again for blockHash1. // val0 votes again for blockHash1.
{ {
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0) vote := withValidator(voteProto, val0Addr, 0)
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet) added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet)
if !added { if !added {
t.Errorf("Expected VoteSet.Add to succeed, called SetPeerMaj23().") t.Errorf("Expected VoteSet.Add to succeed, called SetPeerMaj23().")
@@ -372,7 +388,7 @@ func TestConflicts(t *testing.T) {
// val0 votes again for blockHash1. // val0 votes again for blockHash1.
{ {
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0) vote := withValidator(voteProto, val0Addr, 0)
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash2), voteSet) added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash2), voteSet)
if added { if added {
t.Errorf("Expected VoteSet.Add to fail, duplicate SetPeerMaj23() from peerA") t.Errorf("Expected VoteSet.Add to fail, duplicate SetPeerMaj23() from peerA")
@@ -384,7 +400,8 @@ func TestConflicts(t *testing.T) {
// val1 votes for blockHash1. // val1 votes for blockHash1.
{ {
vote := withValidator(voteProto, privValidators[1].GetAddress(), 1) addr := privValidators[1].GetPubKey().Address()
vote := withValidator(voteProto, addr, 1)
added, err := signAddVote(privValidators[1], withBlockHash(vote, blockHash1), voteSet) added, err := signAddVote(privValidators[1], withBlockHash(vote, blockHash1), voteSet)
if !added || err != nil { if !added || err != nil {
t.Errorf("Expected VoteSet.Add to succeed") t.Errorf("Expected VoteSet.Add to succeed")
@@ -401,7 +418,8 @@ func TestConflicts(t *testing.T) {
// val2 votes for blockHash2. // val2 votes for blockHash2.
{ {
vote := withValidator(voteProto, privValidators[2].GetAddress(), 2) addr := privValidators[2].GetPubKey().Address()
vote := withValidator(voteProto, addr, 2)
added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash2), voteSet) added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash2), voteSet)
if !added || err != nil { if !added || err != nil {
t.Errorf("Expected VoteSet.Add to succeed") t.Errorf("Expected VoteSet.Add to succeed")
@@ -421,7 +439,8 @@ func TestConflicts(t *testing.T) {
// val2 votes for blockHash1. // val2 votes for blockHash1.
{ {
vote := withValidator(voteProto, privValidators[2].GetAddress(), 2) addr := privValidators[2].GetPubKey().Address()
vote := withValidator(voteProto, addr, 2)
added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash1), voteSet) added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash1), voteSet)
if !added { if !added {
t.Errorf("Expected VoteSet.Add to succeed") t.Errorf("Expected VoteSet.Add to succeed")
@@ -462,7 +481,8 @@ func TestMakeCommit(t *testing.T) {
// 6 out of 10 voted for some block. // 6 out of 10 voted for some block.
for i := 0; i < 6; i++ { for i := 0; i < 6; i++ {
vote := withValidator(voteProto, privValidators[i].GetAddress(), i) addr := privValidators[i].GetPubKey().Address()
vote := withValidator(voteProto, addr, i)
_, err := signAddVote(privValidators[i], vote, voteSet) _, err := signAddVote(privValidators[i], vote, voteSet)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@@ -474,7 +494,8 @@ func TestMakeCommit(t *testing.T) {
// 7th voted for some other block. // 7th voted for some other block.
{ {
vote := withValidator(voteProto, privValidators[6].GetAddress(), 6) addr := privValidators[6].GetPubKey().Address()
vote := withValidator(voteProto, addr, 6)
vote = withBlockHash(vote, cmn.RandBytes(32)) vote = withBlockHash(vote, cmn.RandBytes(32))
vote = withBlockPartsHeader(vote, PartSetHeader{123, cmn.RandBytes(32)}) vote = withBlockPartsHeader(vote, PartSetHeader{123, cmn.RandBytes(32)})
@@ -486,7 +507,8 @@ func TestMakeCommit(t *testing.T) {
// The 8th voted like everyone else. // The 8th voted like everyone else.
{ {
vote := withValidator(voteProto, privValidators[7].GetAddress(), 7) addr := privValidators[7].GetPubKey().Address()
vote := withValidator(voteProto, addr, 7)
_, err := signAddVote(privValidators[7], vote, voteSet) _, err := signAddVote(privValidators[7], vote, voteSet)
if err != nil { if err != nil {
t.Error(err) t.Error(err)

View File

@@ -18,7 +18,7 @@ const (
// TMCoreSemVer is the current version of Tendermint Core. // TMCoreSemVer is the current version of Tendermint Core.
// It's the Semantic Version of the software. // It's the Semantic Version of the software.
// Must be a string because scripts like dist.sh read this file. // Must be a string because scripts like dist.sh read this file.
TMCoreSemVer = "0.27.2" TMCoreSemVer = "0.27.4"
// ABCISemVer is the semantic version of the ABCI library // ABCISemVer is the semantic version of the ABCI library
ABCISemVer = "0.15.0" ABCISemVer = "0.15.0"