mirror of
https://github.com/fluencelabs/tendermint
synced 2025-07-23 00:01:58 +00:00
Compare commits
31 Commits
v0.29.1
...
wrap_eth/c
Author | SHA1 | Date | |
---|---|---|---|
|
df4850cad5 | ||
|
8d71786f32 | ||
|
f610d42136 | ||
|
f589134369 | ||
|
a5fbf493a4 | ||
|
51ce32e936 | ||
|
35c3405fbc | ||
|
7fd9bf914f | ||
|
155caf982c | ||
|
a149a9d2b2 | ||
|
d470945503 | ||
|
17f2873b7c | ||
|
8985a1fa63 | ||
|
6dd817cbbc | ||
|
0b3a87a323 | ||
|
e1edd2aa6a | ||
|
074d5bb08c | ||
|
673c0b85cf | ||
|
9a0bfafef6 | ||
|
a335caaedb | ||
|
ff3c4bfc76 | ||
|
8d2dd7e554 | ||
|
71e5939441 | ||
|
d91ea9b59d | ||
|
9b6b792ce7 | ||
|
57af99d901 | ||
|
a58d5897e4 | ||
|
ddbdffb4e5 | ||
|
d6dd43cdaa | ||
|
75cbe4a1c1 | ||
|
27c1563bf0 |
@@ -19,5 +19,7 @@ Special thanks to external contributors on this release:
|
||||
### FEATURES:
|
||||
|
||||
### IMPROVEMENTS:
|
||||
- [tools] add go-deadlock tool to help detect deadlocks
|
||||
|
||||
### BUG FIXES:
|
||||
- [node] \#3186 EventBus and indexerService should be started before first block (for replay last block on handshake) execution
|
||||
|
24
Gopkg.lock
generated
24
Gopkg.lock
generated
@@ -10,12 +10,11 @@
|
||||
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:c0decf632843204d2b8781de7b26e7038584e2dcccc7e2f401e88ae85b1df2b7"
|
||||
digest = "1:093bf93a65962e8191e3e8cd8fc6c363f83d43caca9739c906531ba7210a9904"
|
||||
name = "github.com/btcsuite/btcd"
|
||||
packages = ["btcec"]
|
||||
pruneopts = "UT"
|
||||
revision = "67e573d211ace594f1366b4ce9d39726c4b19bd0"
|
||||
revision = "ed77733ec07dfc8a513741138419b8d9d3de9d2d"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1d8e1cb71c33a9470bbbae09bfec09db43c6bf358dfcae13cd8807c4e2a9a2bf"
|
||||
@@ -35,6 +34,14 @@
|
||||
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b42be5a3601f833e0b9f2d6625d887ec1309764bfcac3d518f3db425dcd4ec5c"
|
||||
name = "github.com/ethereum/go-ethereum"
|
||||
packages = ["crypto/secp256k1"]
|
||||
pruneopts = "T"
|
||||
revision = "9dc5d1a915ac0e0bd8429d6ac41df50eec91de5f"
|
||||
version = "v1.8.21"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:544229a3ca0fb2dd5ebc2896d3d2ff7ce096d9751635301e44e37e761349ee70"
|
||||
name = "github.com/fortytw2/leaktest"
|
||||
@@ -360,14 +367,6 @@
|
||||
pruneopts = "UT"
|
||||
revision = "6b91fda63f2e36186f1c9d0e48578defb69c5d43"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:83f5e189eea2baad419a6a410984514266ff690075759c87e9ede596809bd0b8"
|
||||
name = "github.com/tendermint/btcd"
|
||||
packages = ["btcec"]
|
||||
pruneopts = "UT"
|
||||
revision = "80daadac05d1cd29571fccf27002d79667a88b58"
|
||||
version = "v0.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ad9c4c1a4e7875330b1f62906f2830f043a23edb5db997e3a5ac5d3e6eadf80a"
|
||||
name = "github.com/tendermint/go-amino"
|
||||
@@ -504,8 +503,10 @@
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/btcsuite/btcd/btcec",
|
||||
"github.com/btcsuite/btcutil/base58",
|
||||
"github.com/btcsuite/btcutil/bech32",
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1",
|
||||
"github.com/fortytw2/leaktest",
|
||||
"github.com/go-kit/kit/log",
|
||||
"github.com/go-kit/kit/log/level",
|
||||
@@ -535,7 +536,6 @@
|
||||
"github.com/syndtr/goleveldb/leveldb/errors",
|
||||
"github.com/syndtr/goleveldb/leveldb/iterator",
|
||||
"github.com/syndtr/goleveldb/leveldb/opt",
|
||||
"github.com/tendermint/btcd/btcec",
|
||||
"github.com/tendermint/go-amino",
|
||||
"golang.org/x/crypto/bcrypt",
|
||||
"golang.org/x/crypto/chacha20poly1305",
|
||||
|
16
Gopkg.toml
16
Gopkg.toml
@@ -75,14 +75,26 @@
|
||||
name = "github.com/prometheus/client_golang"
|
||||
version = "^0.9.1"
|
||||
|
||||
# we use the secp256k1 implementation:
|
||||
[[constraint]]
|
||||
name = "github.com/tendermint/btcd"
|
||||
version = "v0.1.1"
|
||||
name = "github.com/ethereum/go-ethereum"
|
||||
version = "^v1.8.21"
|
||||
|
||||
# Prevent dep from pruning build scripts and codegen templates
|
||||
# note: this leaves the whole go-ethereum package in vendor
|
||||
# can be removed when https://github.com/golang/dep/issues/1847 is resolved
|
||||
[[prune.project]]
|
||||
name = "github.com/ethereum/go-ethereum"
|
||||
unused-packages = false
|
||||
|
||||
###################################
|
||||
## Some repos dont have releases.
|
||||
## Pin to revision
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/btcsuite/btcd"
|
||||
revision = "ed77733ec07dfc8a513741138419b8d9d3de9d2d"
|
||||
|
||||
[[constraint]]
|
||||
name = "golang.org/x/crypto"
|
||||
revision = "505ab145d0a99da450461ae2c1a9f6cd10d1f447"
|
||||
|
59
Makefile
59
Makefile
@@ -21,7 +21,7 @@ check: check_tools get_vendor_deps
|
||||
### Build Tendermint
|
||||
|
||||
build:
|
||||
CGO_ENABLED=0 go build $(BUILD_FLAGS) -tags $(BUILD_TAGS) -o build/tendermint ./cmd/tendermint/
|
||||
CGO_ENABLED=0 go build $(BUILD_FLAGS) -tags "$(BUILD_TAGS) nocgo" -o build/tendermint ./cmd/tendermint/
|
||||
|
||||
build_c:
|
||||
CGO_ENABLED=1 go build $(BUILD_FLAGS) -tags "$(BUILD_TAGS) gcc" -o build/tendermint ./cmd/tendermint/
|
||||
@@ -30,7 +30,7 @@ build_race:
|
||||
CGO_ENABLED=0 go build -race $(BUILD_FLAGS) -tags $(BUILD_TAGS) -o build/tendermint ./cmd/tendermint
|
||||
|
||||
install:
|
||||
CGO_ENABLED=0 go install $(BUILD_FLAGS) -tags $(BUILD_TAGS) ./cmd/tendermint
|
||||
CGO_ENABLED=0 go install $(BUILD_FLAGS) -tags "$(BUILD_TAGS) nocgo" ./cmd/tendermint
|
||||
|
||||
install_c:
|
||||
CGO_ENABLED=1 go install $(BUILD_FLAGS) -tags "$(BUILD_TAGS) gcc" ./cmd/tendermint
|
||||
@@ -226,6 +226,19 @@ test_race:
|
||||
@echo "--> Running go test --race"
|
||||
@GOCACHE=off go test -p 1 -v -race $(PACKAGES)
|
||||
|
||||
# uses https://github.com/sasha-s/go-deadlock/ to detect potential deadlocks
|
||||
test_with_deadlock:
|
||||
find . -name "*.go" | grep -v "vendor/" | xargs -n 1 sed -i.bak 's/sync.RWMutex/deadlock.RWMutex/'
|
||||
find . -name "*.go" | grep -v "vendor/" | xargs -n 1 sed -i.bak 's/sync.Mutex/deadlock.Mutex/'
|
||||
find . -name "*.go" | grep -v "vendor/" | xargs -n 1 goimports -w
|
||||
make test
|
||||
make cleanup_after_test_with_deadlock
|
||||
|
||||
# cleanes up after you ran test_with_deadlock
|
||||
cleanup_after_test_with_deadlock:
|
||||
find . -name "*.go" | grep -v "vendor/" | xargs -n 1 sed -i.bak 's/deadlock.RWMutex/sync.RWMutex/'
|
||||
find . -name "*.go" | grep -v "vendor/" | xargs -n 1 sed -i.bak 's/deadlock.Mutex/sync.Mutex/'
|
||||
find . -name "*.go" | grep -v "vendor/" | xargs -n 1 goimports -w
|
||||
|
||||
########################################
|
||||
### Formatting, linting, and vetting
|
||||
@@ -236,31 +249,31 @@ fmt:
|
||||
metalinter:
|
||||
@echo "--> Running linter"
|
||||
@gometalinter $(LINT_FLAGS) --disable-all \
|
||||
--enable=vet \
|
||||
--enable=vetshadow \
|
||||
--enable=deadcode \
|
||||
--enable=gosimple \
|
||||
--enable=varcheck \
|
||||
--enable=structcheck \
|
||||
--enable=misspell \
|
||||
--enable=safesql \
|
||||
--enable=gosec \
|
||||
--enable=goimports \
|
||||
--enable=gofmt \
|
||||
./...
|
||||
#--enable=gas \
|
||||
#--enable=maligned \
|
||||
#--enable=dupl \
|
||||
#--enable=errcheck \
|
||||
#--enable=goconst \
|
||||
#--enable=gocyclo \
|
||||
#--enable=goimports \
|
||||
#--enable=golint \ <== comments on anything exported
|
||||
#--enable=gotype \
|
||||
#--enable=ineffassign \
|
||||
#--enable=interfacer \
|
||||
#--enable=megacheck \
|
||||
#--enable=staticcheck \
|
||||
#--enable=structcheck \
|
||||
#--enable=unconvert \
|
||||
#--enable=unparam \
|
||||
#--enable=unused \
|
||||
#--enable=varcheck \
|
||||
#--enable=vet \
|
||||
#--enable=vetshadow \
|
||||
#--enable=gotypex \
|
||||
#--enable=gocyclo \
|
||||
#--enable=golint \
|
||||
#--enable=maligned \
|
||||
#--enable=errcheck \
|
||||
#--enable=staticcheck \
|
||||
#--enable=dupl \
|
||||
#--enable=ineffassign \
|
||||
#--enable=interfacer \
|
||||
#--enable=unconvert \
|
||||
#--enable=goconst \
|
||||
#--enable=unparam \
|
||||
#--enable=nakedret \
|
||||
|
||||
metalinter_all:
|
||||
@echo "--> Running linter (all)"
|
||||
@@ -330,4 +343,4 @@ build-slate:
|
||||
# To avoid unintended conflicts with file names, always add to .PHONY
|
||||
# unless there is a reason not to.
|
||||
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
|
||||
.PHONY: check build build_race build_abci dist install install_abci check_dep check_tools get_tools get_dev_tools update_tools get_vendor_deps draw_deps get_protoc protoc_abci protoc_libs gen_certs clean_certs grpc_dbserver test_cover test_apps test_persistence test_p2p test test_race test_integrations test_release test100 vagrant_test fmt rpc-docs build-linux localnet-start localnet-stop build-docker build-docker-localnode sentry-start sentry-config sentry-stop build-slate protoc_grpc protoc_all build_c install_c
|
||||
.PHONY: check build build_race build_abci dist install install_abci check_dep check_tools get_tools get_dev_tools update_tools get_vendor_deps draw_deps get_protoc protoc_abci protoc_libs gen_certs clean_certs grpc_dbserver test_cover test_apps test_persistence test_p2p test test_race test_integrations test_release test100 vagrant_test fmt rpc-docs build-linux localnet-start localnet-stop build-docker build-docker-localnode sentry-start sentry-config sentry-stop build-slate protoc_grpc protoc_all build_c install_c test_with_deadlock cleanup_after_test_with_deadlock metalinter metalinter_all
|
||||
|
158
PHILOSOPHY.md
Normal file
158
PHILOSOPHY.md
Normal file
@@ -0,0 +1,158 @@
|
||||
## Design goals
|
||||
|
||||
The design goals for Tendermint (and the SDK and related libraries) are:
|
||||
|
||||
* Simplicity and Legibility
|
||||
* Parallel performance, namely ability to utilize multicore architecture
|
||||
* Ability to evolve the codebase bug-free
|
||||
* Debuggability
|
||||
* Complete correctness that considers all edge cases, esp in concurrency
|
||||
* Future-proof modular architecture, message protocol, APIs, and encapsulation
|
||||
|
||||
|
||||
### Justification
|
||||
|
||||
Legibility is key to maintaining bug-free software as it evolves toward more
|
||||
optimizations, more ease of debugging, and additional features.
|
||||
|
||||
It is too easy to introduce bugs over time by replacing lines of code with
|
||||
those that may panic, which means ideally locks are unlocked by defer
|
||||
statements.
|
||||
|
||||
For example,
|
||||
|
||||
```go
|
||||
func (obj *MyObj) something() {
|
||||
mtx.Lock()
|
||||
obj.something = other
|
||||
mtx.Unlock()
|
||||
}
|
||||
```
|
||||
|
||||
It is too easy to refactor the codebase in the future to replace `other` with
|
||||
`other.String()` for example, and this may introduce a bug that causes a
|
||||
deadlock. So as much as reasonably possible, we need to be using defer
|
||||
statements, even though it introduces additional overhead.
|
||||
|
||||
If it is necessary to optimize the unlocking of mutex locks, the solution is
|
||||
more modularity via smaller functions, so that defer'd unlocks are scoped
|
||||
within a smaller function.
|
||||
|
||||
Similarly, idiomatic for-loops should always be preferred over those that use
|
||||
custom counters, because it is too easy to evolve the body of a for-loop to
|
||||
become more complicated over time, and it becomes more and more difficult to
|
||||
assess the correctness of such a for-loop by visual inspection.
|
||||
|
||||
|
||||
### On performance
|
||||
|
||||
It doesn't matter whether there are alternative implementations that are 2x or
|
||||
3x more performant, when the software doesn't work, deadlocks, or if bugs
|
||||
cannot be debugged. By taking advantage of multicore concurrency, the
|
||||
Tendermint implementation will at least be an order of magnitude within the
|
||||
range of what is theoretically possible. The design philosophy of Tendermint,
|
||||
and the choice of Go as implementation language, is designed to make Tendermint
|
||||
implementation the standard specification for concurrent BFT software.
|
||||
|
||||
By focusing on the message protocols (e.g. ABCI, p2p messages), and
|
||||
encapsulation e.g. IAVL module, (relatively) independent reactors, we are both
|
||||
implementing a standard implementation to be used as the specification for
|
||||
future implementations in more optimizable languages like Rust, Java, and C++;
|
||||
as well as creating sufficiently performant software. Tendermint Core will
|
||||
never be as fast as future implementations of the Tendermint Spec, because Go
|
||||
isn't designed to be as fast as possible. The advantage of using Go is that we
|
||||
can develop the whole stack of modular components **faster** than in other
|
||||
languages.
|
||||
|
||||
Furthermore, the real bottleneck is in the application layer, and it isn't
|
||||
necessary to support more than a sufficiently decentralized set of validators
|
||||
(e.g. 100 ~ 300 validators is sufficient, with delegated bonded PoS).
|
||||
|
||||
Instead of optimizing Tendermint performance down to the metal, lets focus on
|
||||
optimizing on other matters, namely ability to push feature complete software
|
||||
that works well enough, can be debugged and maintained, and can serve as a spec
|
||||
for future implementations.
|
||||
|
||||
|
||||
### On encapsulation
|
||||
|
||||
In order to create maintainable, forward-optimizable software, it is critical
|
||||
to develop well-encapsulated objects that have well understood properties, and
|
||||
to re-use these easy-to-use-correctly components as building blocks for further
|
||||
encapsulated meta-objects.
|
||||
|
||||
For example, mutexes are cheap enough for Tendermint's design goals when there
|
||||
isn't goroutine contention, so it is encouraged to create concurrency safe
|
||||
structures with struct-level mutexes. If they are used in the context of
|
||||
non-concurrent logic, then the performance is good enough. If they are used in
|
||||
the context of concurrent logic, then it will still perform correctly.
|
||||
|
||||
Examples of this design principle can be seen in the types.ValidatorSet struct,
|
||||
and the cmn.Rand struct. It's one single struct declaration that can be used
|
||||
in both concurrent and non-concurrent logic, and due to its well encapsulation,
|
||||
it's easy to get the usage of the mutex right.
|
||||
|
||||
#### example: cmn.Rand:
|
||||
|
||||
`The default Source is safe for concurrent use by multiple goroutines, but
|
||||
Sources created by NewSource are not`. The reason why the default
|
||||
package-level source is safe for concurrent use is because it is protected (see
|
||||
`lockedSource` in https://golang.org/src/math/rand/rand.go).
|
||||
|
||||
But we shouldn't rely on the global source, we should be creating our own
|
||||
Rand/Source instances and using them, especially for determinism in testing.
|
||||
So it is reasonable to have cmn.Rand be protected by a mutex. Whether we want
|
||||
our own implementation of Rand is another question, but the answer there is
|
||||
also in the affirmative. Sometimes you want to know where Rand is being used
|
||||
in your code, so it becomes a simple matter of dropping in a log statement to
|
||||
inject inspectability into Rand usage. Also, it is nice to be able to extend
|
||||
the functionality of Rand with custom methods. For these reasons, and for the
|
||||
reasons which is outlined in this design philosophy document, we should
|
||||
continue to use the cmn.Rand object, with mutex protection.
|
||||
|
||||
Another key aspect of good encapsulation is the choice of exposed vs unexposed
|
||||
methods. It should be clear to the reader of the code, which methods are
|
||||
intended to be used in what context, and what safe usage is. Part of this is
|
||||
solved by hiding methods via unexported methods. Another part of this is
|
||||
naming conventions on the methods (e.g. underscores) with good documentation,
|
||||
and code organization. If there are too many exposed methods and it isn't
|
||||
clear what methods have what side effects, then there is something wrong about
|
||||
the design of abstractions that should be revisited.
|
||||
|
||||
|
||||
### On concurrency
|
||||
|
||||
In order for Tendermint to remain relevant in the years to come, it is vital
|
||||
for Tendermint to take advantage of multicore architectures. Due to the nature
|
||||
of the problem, namely consensus across a concurrent p2p gossip network, and to
|
||||
handle RPC requests for a large number of consuming subscribers, it is
|
||||
unavoidable for Tendermint development to require expertise in concurrency
|
||||
design, especially when it comes to the reactor design, and also for RPC
|
||||
request handling.
|
||||
|
||||
|
||||
## Guidelines
|
||||
|
||||
Here are some guidelines for designing for (sufficient) performance and concurrency:
|
||||
|
||||
* Mutex locks are cheap enough when there isn't contention.
|
||||
* Do not optimize code without analytical or observed proof that it is in a hot path.
|
||||
* Don't over-use channels when mutex locks w/ encapsulation are sufficient.
|
||||
* The need to drain channels are often a hint of unconsidered edge cases.
|
||||
* The creation of O(N) one-off goroutines is generally technical debt that
|
||||
needs to get addressed sooner than later. Avoid creating too many
|
||||
goroutines as a patch around incomplete concurrency design, or at least be
|
||||
aware of the debt and do not invest in the debt. On the other hand, Tendermint
|
||||
is designed to have a limited number of peers (e.g. 10 or 20), so the creation
|
||||
of O(C) goroutines per O(P) peers is still O(C\*P=constant).
|
||||
* Use defer statements to unlock as much as possible. If you want to unlock sooner,
|
||||
try to create more modular functions that do make use of defer statements.
|
||||
|
||||
## Matras
|
||||
|
||||
* Premature optimization kills
|
||||
* Readability is paramount
|
||||
* Beautiful is better than fast.
|
||||
* In the face of ambiguity, refuse the temptation to guess.
|
||||
* In the face of bugs, refuse the temptation to cover the bug.
|
||||
* There should be one-- and preferably only one --obvious way to do it.
|
@@ -83,7 +83,7 @@ func TestWriteReadMessage2(t *testing.T) {
|
||||
Log: phrase,
|
||||
GasWanted: 10,
|
||||
Tags: []cmn.KVPair{
|
||||
cmn.KVPair{Key: []byte("abc"), Value: []byte("def")},
|
||||
{Key: []byte("abc"), Value: []byte("def")},
|
||||
},
|
||||
},
|
||||
// TODO: add the rest
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
|
||||
proto "github.com/tendermint/tendermint/benchmarks/proto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
|
@@ -22,10 +22,6 @@ var (
|
||||
defaultRoot = os.ExpandEnv("$HOME/.some/test/dir")
|
||||
)
|
||||
|
||||
const (
|
||||
rootName = "root"
|
||||
)
|
||||
|
||||
// clearConfig clears env vars, the given root dir, and resets viper.
|
||||
func clearConfig(dir string) {
|
||||
if err := os.Unsetenv("TMHOME"); err != nil {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||
)
|
||||
|
||||
|
@@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
@@ -317,6 +318,10 @@ namespace = "{{ .Instrumentation.Namespace }}"
|
||||
/****** these are for test settings ***********/
|
||||
|
||||
func ResetTestRoot(testName string) *Config {
|
||||
return ResetTestRootWithChainID(testName, "")
|
||||
}
|
||||
|
||||
func ResetTestRootWithChainID(testName string, chainID string) *Config {
|
||||
rootDir := os.ExpandEnv("$HOME/.tendermint_test")
|
||||
rootDir = filepath.Join(rootDir, testName)
|
||||
// Remove ~/.tendermint_test_bak
|
||||
@@ -353,6 +358,10 @@ func ResetTestRoot(testName string) *Config {
|
||||
writeDefaultConfigFile(configFilePath)
|
||||
}
|
||||
if !cmn.FileExists(genesisFilePath) {
|
||||
if chainID == "" {
|
||||
chainID = "tendermint_test"
|
||||
}
|
||||
testGenesis := fmt.Sprintf(testGenesisFmt, chainID)
|
||||
cmn.MustWriteFile(genesisFilePath, []byte(testGenesis), 0644)
|
||||
}
|
||||
// we always overwrite the priv val
|
||||
@@ -363,9 +372,9 @@ func ResetTestRoot(testName string) *Config {
|
||||
return config
|
||||
}
|
||||
|
||||
var testGenesis = `{
|
||||
var testGenesisFmt = `{
|
||||
"genesis_time": "2018-10-10T08:20:13.695936996Z",
|
||||
"chain_id": "tendermint_test",
|
||||
"chain_id": "%s",
|
||||
"validators": [
|
||||
{
|
||||
"pub_key": {
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
tmevents "github.com/tendermint/tendermint/libs/events"
|
||||
@@ -438,9 +438,9 @@ func (conR *ConsensusReactor) broadcastHasVoteMessage(vote *types.Vote) {
|
||||
|
||||
func makeRoundStepMessage(rs *cstypes.RoundState) (nrsMsg *NewRoundStepMessage) {
|
||||
nrsMsg = &NewRoundStepMessage{
|
||||
Height: rs.Height,
|
||||
Round: rs.Round,
|
||||
Step: rs.Step,
|
||||
Height: rs.Height,
|
||||
Round: rs.Round,
|
||||
Step: rs.Step,
|
||||
SecondsSinceStartTime: int(time.Since(rs.StartTime).Seconds()),
|
||||
LastCommitRound: rs.LastCommit.Round(),
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/abci/client"
|
||||
abcicli "github.com/tendermint/tendermint/abci/client"
|
||||
"github.com/tendermint/tendermint/abci/example/kvstore"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
bc "github.com/tendermint/tendermint/blockchain"
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
//"strconv"
|
||||
//"strings"
|
||||
"time"
|
||||
@@ -196,6 +197,7 @@ type Handshaker struct {
|
||||
stateDB dbm.DB
|
||||
initialState sm.State
|
||||
store sm.BlockStore
|
||||
eventBus types.BlockEventPublisher
|
||||
genDoc *types.GenesisDoc
|
||||
logger log.Logger
|
||||
|
||||
@@ -209,6 +211,7 @@ func NewHandshaker(stateDB dbm.DB, state sm.State,
|
||||
stateDB: stateDB,
|
||||
initialState: state,
|
||||
store: store,
|
||||
eventBus: types.NopEventBus{},
|
||||
genDoc: genDoc,
|
||||
logger: log.NewNopLogger(),
|
||||
nBlocks: 0,
|
||||
@@ -219,6 +222,12 @@ func (h *Handshaker) SetLogger(l log.Logger) {
|
||||
h.logger = l
|
||||
}
|
||||
|
||||
// SetEventBus - sets the event bus for publishing block related events.
|
||||
// If not called, it defaults to types.NopEventBus.
|
||||
func (h *Handshaker) SetEventBus(eventBus types.BlockEventPublisher) {
|
||||
h.eventBus = eventBus
|
||||
}
|
||||
|
||||
func (h *Handshaker) NBlocks() int {
|
||||
return h.nBlocks
|
||||
}
|
||||
@@ -432,6 +441,7 @@ func (h *Handshaker) replayBlock(state sm.State, height int64, proxyApp proxy.Ap
|
||||
meta := h.store.LoadBlockMeta(height)
|
||||
|
||||
blockExec := sm.NewBlockExecutor(h.stateDB, h.logger, proxyApp, sm.MockMempool{}, sm.MockEvidencePool{})
|
||||
blockExec.SetEventBus(h.eventBus)
|
||||
|
||||
var err error
|
||||
state, err = blockExec.ApplyBlock(state, meta.BlockID, block)
|
||||
|
@@ -326,17 +326,18 @@ func newConsensusStateForReplay(config cfg.BaseConfig, csConfig *cfg.ConsensusCo
|
||||
cmn.Exit(fmt.Sprintf("Error starting proxy app conns: %v", err))
|
||||
}
|
||||
|
||||
handshaker := NewHandshaker(stateDB, state, blockStore, gdoc)
|
||||
err = handshaker.Handshake(proxyApp)
|
||||
if err != nil {
|
||||
cmn.Exit(fmt.Sprintf("Error on handshake: %v", err))
|
||||
}
|
||||
|
||||
eventBus := types.NewEventBus()
|
||||
if err := eventBus.Start(); err != nil {
|
||||
cmn.Exit(fmt.Sprintf("Failed to start event bus: %v", err))
|
||||
}
|
||||
|
||||
handshaker := NewHandshaker(stateDB, state, blockStore, gdoc)
|
||||
handshaker.SetEventBus(eventBus)
|
||||
err = handshaker.Handshake(proxyApp)
|
||||
if err != nil {
|
||||
cmn.Exit(fmt.Sprintf("Error on handshake: %v", err))
|
||||
}
|
||||
|
||||
mempool, evpool := sm.MockMempool{}, sm.MockEvidencePool{}
|
||||
blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool)
|
||||
|
||||
|
@@ -94,7 +94,7 @@ type ConsensusState struct {
|
||||
// internal state
|
||||
mtx sync.RWMutex
|
||||
cstypes.RoundState
|
||||
state sm.State // State until height-1.
|
||||
state sm.State // State until height-1.
|
||||
|
||||
// state changes may be triggered by: msgs from peers,
|
||||
// msgs from ourself, or by timeouts
|
||||
|
@@ -3,7 +3,7 @@ package types
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
// "sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -67,8 +68,8 @@ func TestWALTruncate(t *testing.T) {
|
||||
func TestWALEncoderDecoder(t *testing.T) {
|
||||
now := tmtime.Now()
|
||||
msgs := []TimedWALMessage{
|
||||
TimedWALMessage{Time: now, Msg: EndHeightMessage{0}},
|
||||
TimedWALMessage{Time: now, Msg: timeoutInfo{Duration: time.Second, Height: 1, Round: 1, Step: types.RoundStepPropose}},
|
||||
{Time: now, Msg: EndHeightMessage{0}},
|
||||
{Time: now, Msg: timeoutInfo{Duration: time.Second, Height: 1, Round: 1, Step: types.RoundStepPropose}},
|
||||
}
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package consensus
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
|
@@ -25,9 +25,8 @@ func checkAminoBinary(t *testing.T, src, dst interface{}, size int) {
|
||||
assert.Equal(t, byterSrc.Bytes(), bz, "Amino binary vs Bytes() mismatch")
|
||||
}
|
||||
// Make sure we have the expected length.
|
||||
if size != -1 {
|
||||
assert.Equal(t, size, len(bz), "Amino binary size mismatch")
|
||||
}
|
||||
assert.Equal(t, size, len(bz), "Amino binary size mismatch")
|
||||
|
||||
// Unmarshal.
|
||||
err = cdc.UnmarshalBinaryBare(bz, dst)
|
||||
require.Nil(t, err, "%+v", err)
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
|
@@ -26,7 +26,7 @@ import (
|
||||
func TestRFC6962Hasher(t *testing.T) {
|
||||
_, leafHashTrail := trailsFromByteSlices([][]byte{[]byte("L123456")})
|
||||
leafHash := leafHashTrail.Hash
|
||||
_, leafHashTrail = trailsFromByteSlices([][]byte{[]byte{}})
|
||||
_, leafHashTrail = trailsFromByteSlices([][]byte{{}})
|
||||
emptyLeafHash := leafHashTrail.Hash
|
||||
for _, tc := range []struct {
|
||||
desc string
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package merkle
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
)
|
||||
|
||||
var cdc *amino.Codec
|
||||
|
@@ -7,10 +7,13 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
secp256k1 "github.com/tendermint/btcd/btcec"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"golang.org/x/crypto/ripemd160"
|
||||
|
||||
secp256k1 "github.com/btcsuite/btcd/btcec"
|
||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
amino "github.com/tendermint/go-amino"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
)
|
||||
|
||||
@@ -44,16 +47,6 @@ func (privKey PrivKeySecp256k1) Bytes() []byte {
|
||||
return cdc.MustMarshalBinaryBare(privKey)
|
||||
}
|
||||
|
||||
// Sign creates an ECDSA signature on curve Secp256k1, using SHA256 on the msg.
|
||||
func (privKey PrivKeySecp256k1) Sign(msg []byte) ([]byte, error) {
|
||||
priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey[:])
|
||||
sig, err := priv.Sign(crypto.Sha256(msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sig.Serialize(), nil
|
||||
}
|
||||
|
||||
// PubKey performs the point-scalar multiplication from the privKey on the
|
||||
// generator point to get the pubkey.
|
||||
func (privKey PrivKeySecp256k1) PubKey() crypto.PubKey {
|
||||
@@ -137,20 +130,6 @@ func (pubKey PubKeySecp256k1) Bytes() []byte {
|
||||
return bz
|
||||
}
|
||||
|
||||
func (pubKey PubKeySecp256k1) VerifyBytes(msg []byte, sig []byte) bool {
|
||||
pub, err := secp256k1.ParsePubKey(pubKey[:], secp256k1.S256())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
parsedSig, err := secp256k1.ParseSignature(sig[:], secp256k1.S256())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
// Underlying library ensures that this signature is in canonical form, to
|
||||
// prevent Secp256k1 malleability from altering the sign of the s term.
|
||||
return parsedSig.Verify(crypto.Sha256(msg), pub)
|
||||
}
|
||||
|
||||
func (pubKey PubKeySecp256k1) String() string {
|
||||
return fmt.Sprintf("PubKeySecp256k1{%X}", pubKey[:])
|
||||
}
|
||||
@@ -161,3 +140,22 @@ func (pubKey PubKeySecp256k1) Equals(other crypto.PubKey) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Sign creates an ECDSA signature on curve Secp256k1, using SHA256 on the msg.
|
||||
func (privKey PrivKeySecp256k1) Sign(msg []byte) ([]byte, error) {
|
||||
priv, err := ethcrypto.ToECDSA(privKey[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rsv, err := ethcrypto.Sign(crypto.Sha256(msg), priv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// we do not need v in r||s||v:
|
||||
rs := rsv[:len(rsv)-1]
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
func (pubKey PubKeySecp256k1) VerifyBytes(msg []byte, sig []byte) bool {
|
||||
return ethcrypto.VerifySignature(pubKey[:], crypto.Sha256(msg), sig)
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
|
||||
underlyingSecp256k1 "github.com/tendermint/btcd/btcec"
|
||||
underlyingSecp256k1 "github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
type keyData struct {
|
||||
|
@@ -21,7 +21,7 @@ module.exports = {
|
||||
},
|
||||
nav: [
|
||||
{ text: "Back to Tendermint", link: "https://tendermint.com" },
|
||||
{ text: "RPC", link: "../rpc/" }
|
||||
{ text: "RPC", link: "https://tendermint.com/rpc/" }
|
||||
],
|
||||
sidebar: [
|
||||
{
|
||||
|
@@ -5,13 +5,17 @@ Author: Anton Kaliaev (@melekes)
|
||||
## Changelog
|
||||
|
||||
02-10-2018: Initial draft
|
||||
|
||||
16-01-2019: Second version based on our conversation with Jae
|
||||
|
||||
17-01-2019: Third version explaining how new design solves current issues
|
||||
|
||||
25-01-2019: Fourth version to treat buffered and unbuffered channels differently
|
||||
|
||||
## Context
|
||||
|
||||
Since the initial version of the pubsub, there's been a number of issues
|
||||
raised: #951, #1879, #1880. Some of them are high-level issues questioning the
|
||||
raised: [#951], [#1879], [#1880]. Some of them are high-level issues questioning the
|
||||
core design choices made. Others are minor and mostly about the interface of
|
||||
`Subscribe()` / `Publish()` functions.
|
||||
|
||||
@@ -51,7 +55,10 @@ channels to distribute msg to these goroutines).
|
||||
|
||||
### Non-blocking send
|
||||
|
||||
There is also a question whenever we should have a non-blocking send:
|
||||
There is also a question whenever we should have a non-blocking send.
|
||||
Currently, sends are blocking, so publishing to one client can block on
|
||||
publishing to another. This means a slow or unresponsive client can halt the
|
||||
system. Instead, we can use a non-blocking send:
|
||||
|
||||
```go
|
||||
for each subscriber {
|
||||
@@ -87,11 +94,26 @@ Go channels are de-facto standard for carrying data between goroutines.
|
||||
### Why `Subscribe()` accepts an `out` channel?
|
||||
|
||||
Because in our tests, we create buffered channels (cap: 1). Alternatively, we
|
||||
can make capacity an argument.
|
||||
can make capacity an argument and return a channel.
|
||||
|
||||
## Decision
|
||||
|
||||
Change Subscribe() function to return a `Subscription` struct:
|
||||
### MsgAndTags
|
||||
|
||||
Use a `MsgAndTags` struct on the subscription channel to indicate what tags the
|
||||
msg matched.
|
||||
|
||||
```go
|
||||
type MsgAndTags struct {
|
||||
Msg interface{}
|
||||
Tags TagMap
|
||||
}
|
||||
```
|
||||
|
||||
### Subscription Struct
|
||||
|
||||
|
||||
Change `Subscribe()` function to return a `Subscription` struct:
|
||||
|
||||
```go
|
||||
type Subscription struct {
|
||||
@@ -103,18 +125,18 @@ func (s *Subscription) Cancelled() <-chan struct{}
|
||||
func (s *Subscription) Err() error
|
||||
```
|
||||
|
||||
Out returns a channel onto which messages and tags are published.
|
||||
Unsubscribe/UnsubscribeAll does not close the channel to avoid clients from
|
||||
`Out()` returns a channel onto which messages and tags are published.
|
||||
`Unsubscribe`/`UnsubscribeAll` does not close the channel to avoid clients from
|
||||
receiving a nil message.
|
||||
|
||||
Cancelled returns a channel that's closed when the subscription is terminated
|
||||
`Cancelled()` returns a channel that's closed when the subscription is terminated
|
||||
and supposed to be used in a select statement.
|
||||
|
||||
If Cancelled is not closed yet, Err() returns nil.
|
||||
If Cancelled is closed, Err returns a non-nil error explaining why:
|
||||
Unsubscribed if the subscriber choose to unsubscribe,
|
||||
OutOfCapacity if the subscriber is not pulling messages fast enough and the Out channel become full.
|
||||
After Err returns a non-nil error, successive calls to Err() return the same error.
|
||||
If the channel returned by `Cancelled()` is not closed yet, `Err()` returns nil.
|
||||
If the channel is closed, `Err()` returns a non-nil error explaining why:
|
||||
`ErrUnsubscribed` if the subscriber choose to unsubscribe,
|
||||
`ErrOutOfCapacity` if the subscriber is not pulling messages fast enough and the channel returned by `Out()` became full.
|
||||
After `Err()` returns a non-nil error, successive calls to `Err() return the same error.
|
||||
|
||||
```go
|
||||
subscription, err := pubsub.Subscribe(...)
|
||||
@@ -130,42 +152,68 @@ select {
|
||||
}
|
||||
```
|
||||
|
||||
Make Out() channel buffered (cap: 1) by default. In most cases, we want to
|
||||
### Capacity and Subscriptions
|
||||
|
||||
Make the `Out()` channel buffered (with capacity 1) by default. In most cases, we want to
|
||||
terminate the slow subscriber. Only in rare cases, we want to block the pubsub
|
||||
(e.g. when debugging consensus). This should lower the chances of the pubsub
|
||||
being frozen.
|
||||
|
||||
```go
|
||||
// outCap can be used to set capacity of Out channel (1 by default). Set to 0
|
||||
for unbuffered channel (WARNING: it may block the pubsub).
|
||||
// outCap can be used to set capacity of Out channel
|
||||
// (1 by default, must be greater than 0).
|
||||
Subscribe(ctx context.Context, clientID string, query Query, outCap... int) (Subscription, error) {
|
||||
```
|
||||
|
||||
Also, Out() channel should return tags along with a message:
|
||||
Use a different function for an unbuffered channel:
|
||||
|
||||
```go
|
||||
type MsgAndTags struct {
|
||||
Msg interface{}
|
||||
Tags TagMap
|
||||
}
|
||||
// Subscription uses an unbuffered channel. Publishing will block.
|
||||
SubscribeUnbuffered(ctx context.Context, clientID string, query Query) (Subscription, error) {
|
||||
```
|
||||
|
||||
to inform clients of which Tags were used with Msg.
|
||||
SubscribeUnbuffered should not be exposed to users.
|
||||
|
||||
### Blocking/Nonblocking
|
||||
|
||||
The publisher should treat these kinds of channels separately.
|
||||
It should block on unbuffered channels (for use with internal consensus events
|
||||
in the consensus tests) and not block on the buffered ones. If a client is too
|
||||
slow to keep up with it's messages, it's subscription is terminated:
|
||||
|
||||
for each subscription {
|
||||
out := subscription.outChan
|
||||
if cap(out) == 0 {
|
||||
// block on unbuffered channel
|
||||
out <- msg
|
||||
} else {
|
||||
// don't block on buffered channels
|
||||
select {
|
||||
case out <- msg:
|
||||
default:
|
||||
// set the error, notify on the cancel chan
|
||||
subscription.err = fmt.Errorf("client is too slow for msg)
|
||||
close(subscription.cancelChan)
|
||||
|
||||
// ... unsubscribe and close out
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
### How this new design solves the current issues?
|
||||
|
||||
https://github.com/tendermint/tendermint/issues/951 (https://github.com/tendermint/tendermint/issues/1880)
|
||||
[#951] ([#1880]):
|
||||
|
||||
Because of non-blocking send, situation where we'll deadlock is not possible
|
||||
anymore. If the client stops reading messages, it will be removed.
|
||||
|
||||
https://github.com/tendermint/tendermint/issues/1879
|
||||
[#1879]:
|
||||
|
||||
MsgAndTags is used now instead of a plain message.
|
||||
|
||||
### Future problems and their possible solutions
|
||||
|
||||
https://github.com/tendermint/tendermint/issues/2826
|
||||
[#2826]
|
||||
|
||||
One question I am still pondering about: how to prevent pubsub from slowing
|
||||
down consensus. We can increase the pubsub queue size (which is 0 now). Also,
|
||||
@@ -191,3 +239,9 @@ In review
|
||||
- (since v1) no concurrency when it comes to publishing messages
|
||||
|
||||
### Neutral
|
||||
|
||||
|
||||
[#951]: https://github.com/tendermint/tendermint/issues/951
|
||||
[#1879]: https://github.com/tendermint/tendermint/issues/1879
|
||||
[#1880]: https://github.com/tendermint/tendermint/issues/1880
|
||||
[#2826]: https://github.com/tendermint/tendermint/issues/2826
|
||||
|
@@ -2,6 +2,6 @@
|
||||
|
||||
The RPC documentation is hosted here:
|
||||
|
||||
- https://tendermint.com/rpc/
|
||||
- [https://tendermint.com/rpc/](https://tendermint.com/rpc/)
|
||||
|
||||
To update the documentation, edit the relevant `godoc` comments in the [rpc/core directory](https://github.com/tendermint/tendermint/tree/develop/rpc/core).
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
Tendermint blockchain benchmarking tool:
|
||||
|
||||
- https://github.com/tendermint/tools/tree/master/tm-bench
|
||||
- [https://github.com/tendermint/tendermint/tree/master/tools/tm-bench](https://github.com/tendermint/tendermint/tree/master/tools/tm-bench)
|
||||
|
||||
For example, the following:
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
Tendermint blockchain monitoring tool; watches over one or more nodes,
|
||||
collecting and providing various statistics to the user:
|
||||
|
||||
- https://github.com/tendermint/tendermint/tree/master/tools/tm-monitor
|
||||
- [https://github.com/tendermint/tendermint/tree/master/tools/tm-monitor](https://github.com/tendermint/tendermint/tree/master/tools/tm-monitor)
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
@@ -13,8 +13,6 @@ import (
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
)
|
||||
|
||||
var mockState = sm.State{}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
types.RegisterMockEvidences(cdc)
|
||||
|
||||
|
@@ -48,7 +48,7 @@ func (evR *EvidenceReactor) SetLogger(l log.Logger) {
|
||||
// It returns the list of channels for this reactor.
|
||||
func (evR *EvidenceReactor) GetChannels() []*p2p.ChannelDescriptor {
|
||||
return []*p2p.ChannelDescriptor{
|
||||
&p2p.ChannelDescriptor{
|
||||
{
|
||||
ID: EvidenceChannel,
|
||||
Priority: 5,
|
||||
},
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package evidence
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
@@ -81,12 +81,12 @@ func TestReader(t *testing.T) {
|
||||
|
||||
// Active, Start, Duration, Idle, Bytes, Samples, InstRate, CurRate, AvgRate, PeakRate, BytesRem, TimeRem, Progress
|
||||
want := []Status{
|
||||
Status{true, start, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
Status{true, start, _100ms, 0, 10, 1, 100, 100, 100, 100, 0, 0, 0},
|
||||
Status{true, start, _200ms, _100ms, 20, 2, 100, 100, 100, 100, 0, 0, 0},
|
||||
Status{true, start, _300ms, _200ms, 20, 3, 0, 90, 67, 100, 0, 0, 0},
|
||||
Status{false, start, _300ms, 0, 20, 3, 0, 0, 67, 100, 0, 0, 0},
|
||||
Status{false, start, _300ms, 0, 20, 3, 0, 0, 67, 100, 0, 0, 0},
|
||||
{true, start, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{true, start, _100ms, 0, 10, 1, 100, 100, 100, 100, 0, 0, 0},
|
||||
{true, start, _200ms, _100ms, 20, 2, 100, 100, 100, 100, 0, 0, 0},
|
||||
{true, start, _300ms, _200ms, 20, 3, 0, 90, 67, 100, 0, 0, 0},
|
||||
{false, start, _300ms, 0, 20, 3, 0, 0, 67, 100, 0, 0, 0},
|
||||
{false, start, _300ms, 0, 20, 3, 0, 0, 67, 100, 0, 0, 0},
|
||||
}
|
||||
for i, s := range status {
|
||||
if !statusesAreEqual(&s, &want[i]) {
|
||||
@@ -139,8 +139,8 @@ func TestWriter(t *testing.T) {
|
||||
|
||||
// Active, Start, Duration, Idle, Bytes, Samples, InstRate, CurRate, AvgRate, PeakRate, BytesRem, TimeRem, Progress
|
||||
want := []Status{
|
||||
Status{true, start, _400ms, 0, 80, 4, 200, 200, 200, 200, 20, _100ms, 80000},
|
||||
Status{true, start, _500ms, _100ms, 100, 5, 200, 200, 200, 200, 0, 0, 100000},
|
||||
{true, start, _400ms, 0, 80, 4, 200, 200, 200, 200, 20, _100ms, 80000},
|
||||
{true, start, _500ms, _100ms, 100, 5, 200, 200, 200, 200, 0, 0, 100000},
|
||||
}
|
||||
for i, s := range status {
|
||||
if !statusesAreEqual(&s, &want[i]) {
|
||||
|
@@ -101,7 +101,7 @@ type Server struct {
|
||||
cmdsCap int
|
||||
|
||||
mtx sync.RWMutex
|
||||
subscriptions map[string]map[string]Query // subscriber -> query (string) -> Query
|
||||
subscriptions map[string]map[string]struct{} // subscriber -> query (string) -> empty struct
|
||||
}
|
||||
|
||||
// Option sets a parameter for the server.
|
||||
@@ -143,7 +143,7 @@ func (ts tagMap) Len() int {
|
||||
// provided, the resulting server's queue is unbuffered.
|
||||
func NewServer(options ...Option) *Server {
|
||||
s := &Server{
|
||||
subscriptions: make(map[string]map[string]Query),
|
||||
subscriptions: make(map[string]map[string]struct{}),
|
||||
}
|
||||
s.BaseService = *cmn.NewBaseService(nil, "PubSub", s)
|
||||
|
||||
@@ -193,11 +193,9 @@ func (s *Server) Subscribe(ctx context.Context, clientID string, query Query, ou
|
||||
case s.cmds <- cmd{op: sub, clientID: clientID, query: query, ch: out}:
|
||||
s.mtx.Lock()
|
||||
if _, ok = s.subscriptions[clientID]; !ok {
|
||||
s.subscriptions[clientID] = make(map[string]Query)
|
||||
s.subscriptions[clientID] = make(map[string]struct{})
|
||||
}
|
||||
// preserve original query
|
||||
// see Unsubscribe
|
||||
s.subscriptions[clientID][query.String()] = query
|
||||
s.subscriptions[clientID][query.String()] = struct{}{}
|
||||
s.mtx.Unlock()
|
||||
return nil
|
||||
case <-ctx.Done():
|
||||
@@ -211,22 +209,23 @@ func (s *Server) Subscribe(ctx context.Context, clientID string, query Query, ou
|
||||
// returned to the caller if the context is canceled or if subscription does
|
||||
// not exist.
|
||||
func (s *Server) Unsubscribe(ctx context.Context, clientID string, query Query) error {
|
||||
var origQuery Query
|
||||
s.mtx.RLock()
|
||||
clientSubscriptions, ok := s.subscriptions[clientID]
|
||||
if ok {
|
||||
origQuery, ok = clientSubscriptions[query.String()]
|
||||
_, ok = clientSubscriptions[query.String()]
|
||||
}
|
||||
s.mtx.RUnlock()
|
||||
if !ok {
|
||||
return ErrSubscriptionNotFound
|
||||
}
|
||||
|
||||
// original query is used here because we're using pointers as map keys
|
||||
select {
|
||||
case s.cmds <- cmd{op: unsub, clientID: clientID, query: origQuery}:
|
||||
case s.cmds <- cmd{op: unsub, clientID: clientID, query: query}:
|
||||
s.mtx.Lock()
|
||||
delete(clientSubscriptions, query.String())
|
||||
if len(clientSubscriptions) == 0 {
|
||||
delete(s.subscriptions, clientID)
|
||||
}
|
||||
s.mtx.Unlock()
|
||||
return nil
|
||||
case <-ctx.Done():
|
||||
@@ -286,17 +285,27 @@ func (s *Server) OnStop() {
|
||||
|
||||
// NOTE: not goroutine safe
|
||||
type state struct {
|
||||
// query -> client -> ch
|
||||
queries map[Query]map[string]chan<- interface{}
|
||||
// client -> query -> struct{}
|
||||
clients map[string]map[Query]struct{}
|
||||
// query string -> client -> ch
|
||||
queryToChanMap map[string]map[string]chan<- interface{}
|
||||
// client -> query string -> struct{}
|
||||
clientToQueryMap map[string]map[string]struct{}
|
||||
// query string -> queryPlusRefCount
|
||||
queries map[string]*queryPlusRefCount
|
||||
}
|
||||
|
||||
// queryPlusRefCount holds a pointer to a query and reference counter. When
|
||||
// refCount is zero, query will be removed.
|
||||
type queryPlusRefCount struct {
|
||||
q Query
|
||||
refCount int
|
||||
}
|
||||
|
||||
// OnStart implements Service.OnStart by starting the server.
|
||||
func (s *Server) OnStart() error {
|
||||
go s.loop(state{
|
||||
queries: make(map[Query]map[string]chan<- interface{}),
|
||||
clients: make(map[string]map[Query]struct{}),
|
||||
queryToChanMap: make(map[string]map[string]chan<- interface{}),
|
||||
clientToQueryMap: make(map[string]map[string]struct{}),
|
||||
queries: make(map[string]*queryPlusRefCount),
|
||||
})
|
||||
return nil
|
||||
}
|
||||
@@ -317,7 +326,7 @@ loop:
|
||||
state.removeAll(cmd.clientID)
|
||||
}
|
||||
case shutdown:
|
||||
for clientID := range state.clients {
|
||||
for clientID := range state.clientToQueryMap {
|
||||
state.removeAll(clientID)
|
||||
}
|
||||
break loop
|
||||
@@ -330,66 +339,99 @@ loop:
|
||||
}
|
||||
|
||||
func (state *state) add(clientID string, q Query, ch chan<- interface{}) {
|
||||
qStr := q.String()
|
||||
|
||||
// initialize clientToChannelMap per query if needed
|
||||
if _, ok := state.queries[q]; !ok {
|
||||
state.queries[q] = make(map[string]chan<- interface{})
|
||||
if _, ok := state.queryToChanMap[qStr]; !ok {
|
||||
state.queryToChanMap[qStr] = make(map[string]chan<- interface{})
|
||||
}
|
||||
|
||||
// create subscription
|
||||
state.queries[q][clientID] = ch
|
||||
state.queryToChanMap[qStr][clientID] = ch
|
||||
|
||||
// initialize queries if needed
|
||||
if _, ok := state.queries[qStr]; !ok {
|
||||
state.queries[qStr] = &queryPlusRefCount{q: q, refCount: 0}
|
||||
}
|
||||
// increment reference counter
|
||||
state.queries[qStr].refCount++
|
||||
|
||||
// add client if needed
|
||||
if _, ok := state.clients[clientID]; !ok {
|
||||
state.clients[clientID] = make(map[Query]struct{})
|
||||
if _, ok := state.clientToQueryMap[clientID]; !ok {
|
||||
state.clientToQueryMap[clientID] = make(map[string]struct{})
|
||||
}
|
||||
state.clients[clientID][q] = struct{}{}
|
||||
state.clientToQueryMap[clientID][qStr] = struct{}{}
|
||||
}
|
||||
|
||||
func (state *state) remove(clientID string, q Query) {
|
||||
clientToChannelMap, ok := state.queries[q]
|
||||
qStr := q.String()
|
||||
|
||||
clientToChannelMap, ok := state.queryToChanMap[qStr]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
ch, ok := clientToChannelMap[clientID]
|
||||
if ok {
|
||||
close(ch)
|
||||
|
||||
delete(state.clients[clientID], q)
|
||||
|
||||
// if it not subscribed to anything else, remove the client
|
||||
if len(state.clients[clientID]) == 0 {
|
||||
delete(state.clients, clientID)
|
||||
}
|
||||
|
||||
delete(state.queries[q], clientID)
|
||||
if len(state.queries[q]) == 0 {
|
||||
delete(state.queries, q)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (state *state) removeAll(clientID string) {
|
||||
queryMap, ok := state.clients[clientID]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for q := range queryMap {
|
||||
ch := state.queries[q][clientID]
|
||||
close(ch)
|
||||
|
||||
// remove the query from client map.
|
||||
// if client is not subscribed to anything else, remove it.
|
||||
delete(state.clientToQueryMap[clientID], qStr)
|
||||
if len(state.clientToQueryMap[clientID]) == 0 {
|
||||
delete(state.clientToQueryMap, clientID)
|
||||
}
|
||||
|
||||
// remove the client from query map.
|
||||
// if query has no other clients subscribed, remove it.
|
||||
delete(state.queryToChanMap[qStr], clientID)
|
||||
if len(state.queryToChanMap[qStr]) == 0 {
|
||||
delete(state.queryToChanMap, qStr)
|
||||
}
|
||||
|
||||
// decrease ref counter in queries
|
||||
state.queries[qStr].refCount--
|
||||
// remove the query if nobody else is using it
|
||||
if state.queries[qStr].refCount == 0 {
|
||||
delete(state.queries, qStr)
|
||||
}
|
||||
}
|
||||
|
||||
func (state *state) removeAll(clientID string) {
|
||||
queryMap, ok := state.clientToQueryMap[clientID]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for qStr := range queryMap {
|
||||
ch := state.queryToChanMap[qStr][clientID]
|
||||
close(ch)
|
||||
|
||||
delete(state.queries[q], clientID)
|
||||
if len(state.queries[q]) == 0 {
|
||||
delete(state.queries, q)
|
||||
// remove the client from query map.
|
||||
// if query has no other clients subscribed, remove it.
|
||||
delete(state.queryToChanMap[qStr], clientID)
|
||||
if len(state.queryToChanMap[qStr]) == 0 {
|
||||
delete(state.queryToChanMap, qStr)
|
||||
}
|
||||
|
||||
// decrease ref counter in queries
|
||||
state.queries[qStr].refCount--
|
||||
// remove the query if nobody else is using it
|
||||
if state.queries[qStr].refCount == 0 {
|
||||
delete(state.queries, qStr)
|
||||
}
|
||||
}
|
||||
delete(state.clients, clientID)
|
||||
|
||||
// remove the client.
|
||||
delete(state.clientToQueryMap, clientID)
|
||||
}
|
||||
|
||||
func (state *state) send(msg interface{}, tags TagMap) {
|
||||
for q, clientToChannelMap := range state.queries {
|
||||
for qStr, clientToChannelMap := range state.queryToChanMap {
|
||||
q := state.queries[qStr].q
|
||||
if q.Matches(tags) {
|
||||
for _, ch := range clientToChannelMap {
|
||||
ch <- msg
|
||||
|
@@ -115,6 +115,25 @@ func TestUnsubscribe(t *testing.T) {
|
||||
assert.False(t, ok)
|
||||
}
|
||||
|
||||
func TestClientUnsubscribesTwice(t *testing.T) {
|
||||
s := pubsub.NewServer()
|
||||
s.SetLogger(log.TestingLogger())
|
||||
s.Start()
|
||||
defer s.Stop()
|
||||
|
||||
ctx := context.Background()
|
||||
ch := make(chan interface{})
|
||||
err := s.Subscribe(ctx, clientID, query.MustParse("tm.events.type='NewBlock'"), ch)
|
||||
require.NoError(t, err)
|
||||
err = s.Unsubscribe(ctx, clientID, query.MustParse("tm.events.type='NewBlock'"))
|
||||
require.NoError(t, err)
|
||||
|
||||
err = s.Unsubscribe(ctx, clientID, query.MustParse("tm.events.type='NewBlock'"))
|
||||
assert.Equal(t, pubsub.ErrSubscriptionNotFound, err)
|
||||
err = s.UnsubscribeAll(ctx, clientID)
|
||||
assert.Equal(t, pubsub.ErrSubscriptionNotFound, err)
|
||||
}
|
||||
|
||||
func TestResubscribe(t *testing.T) {
|
||||
s := pubsub.NewServer()
|
||||
s.SetLogger(log.TestingLogger())
|
||||
|
@@ -73,9 +73,9 @@ func TestConditions(t *testing.T) {
|
||||
s string
|
||||
conditions []query.Condition
|
||||
}{
|
||||
{s: "tm.events.type='NewBlock'", conditions: []query.Condition{query.Condition{Tag: "tm.events.type", Op: query.OpEqual, Operand: "NewBlock"}}},
|
||||
{s: "tx.gas > 7 AND tx.gas < 9", conditions: []query.Condition{query.Condition{Tag: "tx.gas", Op: query.OpGreater, Operand: int64(7)}, query.Condition{Tag: "tx.gas", Op: query.OpLess, Operand: int64(9)}}},
|
||||
{s: "tx.time >= TIME 2013-05-03T14:45:00Z", conditions: []query.Condition{query.Condition{Tag: "tx.time", Op: query.OpGreaterEqual, Operand: txTime}}},
|
||||
{s: "tm.events.type='NewBlock'", conditions: []query.Condition{{Tag: "tm.events.type", Op: query.OpEqual, Operand: "NewBlock"}}},
|
||||
{s: "tx.gas > 7 AND tx.gas < 9", conditions: []query.Condition{{Tag: "tx.gas", Op: query.OpGreater, Operand: int64(7)}, {Tag: "tx.gas", Op: query.OpLess, Operand: int64(9)}}},
|
||||
{s: "tx.time >= TIME 2013-05-03T14:45:00Z", conditions: []query.Condition{{Tag: "tx.time", Op: query.OpGreaterEqual, Operand: txTime}}},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
@@ -408,14 +408,11 @@ func (mem *Mempool) resCbRecheck(req *abci.Request, res *abci.Response) {
|
||||
case *abci.Response_CheckTx:
|
||||
tx := req.GetCheckTx().Tx
|
||||
memTx := mem.recheckCursor.Value.(*mempoolTx)
|
||||
if !bytes.Equal(req.GetCheckTx().Tx, memTx.tx) {
|
||||
cmn.PanicSanity(
|
||||
fmt.Sprintf(
|
||||
"Unexpected tx response from proxy during recheck\nExpected %X, got %X",
|
||||
r.CheckTx.Data,
|
||||
memTx.tx,
|
||||
),
|
||||
)
|
||||
if !bytes.Equal(tx, memTx.tx) {
|
||||
panic(fmt.Sprintf(
|
||||
"Unexpected tx response from proxy during recheck\nExpected %X, got %X",
|
||||
memTx.tx,
|
||||
tx))
|
||||
}
|
||||
var postCheckErr error
|
||||
if mem.postCheck != nil {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
)
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
|
75
node/node.go
75
node/node.go
@@ -34,7 +34,7 @@ import (
|
||||
rpccore "github.com/tendermint/tendermint/rpc/core"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
grpccore "github.com/tendermint/tendermint/rpc/grpc"
|
||||
"github.com/tendermint/tendermint/rpc/lib/server"
|
||||
rpcserver "github.com/tendermint/tendermint/rpc/lib/server"
|
||||
sm "github.com/tendermint/tendermint/state"
|
||||
"github.com/tendermint/tendermint/state/txindex"
|
||||
"github.com/tendermint/tendermint/state/txindex/kv"
|
||||
@@ -217,11 +217,51 @@ func NewNode(config *cfg.Config,
|
||||
return nil, fmt.Errorf("Error starting proxy app connections: %v", err)
|
||||
}
|
||||
|
||||
// EventBus and IndexerService must be started before the handshake because
|
||||
// we might need to index the txs of the replayed block as this might not have happened
|
||||
// when the node stopped last time (i.e. the node stopped after it saved the block
|
||||
// but before it indexed the txs, or, endblocker panicked)
|
||||
eventBus := types.NewEventBus()
|
||||
eventBus.SetLogger(logger.With("module", "events"))
|
||||
|
||||
err = eventBus.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Transaction indexing
|
||||
var txIndexer txindex.TxIndexer
|
||||
switch config.TxIndex.Indexer {
|
||||
case "kv":
|
||||
store, err := dbProvider(&DBContext{"tx_index", config})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.TxIndex.IndexTags != "" {
|
||||
txIndexer = kv.NewTxIndex(store, kv.IndexTags(splitAndTrimEmpty(config.TxIndex.IndexTags, ",", " ")))
|
||||
} else if config.TxIndex.IndexAllTags {
|
||||
txIndexer = kv.NewTxIndex(store, kv.IndexAllTags())
|
||||
} else {
|
||||
txIndexer = kv.NewTxIndex(store)
|
||||
}
|
||||
default:
|
||||
txIndexer = &null.TxIndex{}
|
||||
}
|
||||
|
||||
indexerService := txindex.NewIndexerService(txIndexer, eventBus)
|
||||
indexerService.SetLogger(logger.With("module", "txindex"))
|
||||
|
||||
err = indexerService.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create the handshaker, which calls RequestInfo, sets the AppVersion on the state,
|
||||
// and replays any blocks as necessary to sync tendermint with the app.
|
||||
consensusLogger := logger.With("module", "consensus")
|
||||
handshaker := cs.NewHandshaker(stateDB, state, blockStore, genDoc)
|
||||
handshaker.SetLogger(consensusLogger)
|
||||
handshaker.SetEventBus(eventBus)
|
||||
if err := handshaker.Handshake(proxyApp); err != nil {
|
||||
return nil, fmt.Errorf("Error during handshake: %v", err)
|
||||
}
|
||||
@@ -343,35 +383,10 @@ func NewNode(config *cfg.Config,
|
||||
consensusReactor := cs.NewConsensusReactor(consensusState, fastSync, cs.ReactorMetrics(csMetrics))
|
||||
consensusReactor.SetLogger(consensusLogger)
|
||||
|
||||
eventBus := types.NewEventBus()
|
||||
eventBus.SetLogger(logger.With("module", "events"))
|
||||
|
||||
// services which will be publishing and/or subscribing for messages (events)
|
||||
// consensusReactor will set it on consensusState and blockExecutor
|
||||
consensusReactor.SetEventBus(eventBus)
|
||||
|
||||
// Transaction indexing
|
||||
var txIndexer txindex.TxIndexer
|
||||
switch config.TxIndex.Indexer {
|
||||
case "kv":
|
||||
store, err := dbProvider(&DBContext{"tx_index", config})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.TxIndex.IndexTags != "" {
|
||||
txIndexer = kv.NewTxIndex(store, kv.IndexTags(splitAndTrimEmpty(config.TxIndex.IndexTags, ",", " ")))
|
||||
} else if config.TxIndex.IndexAllTags {
|
||||
txIndexer = kv.NewTxIndex(store, kv.IndexAllTags())
|
||||
} else {
|
||||
txIndexer = kv.NewTxIndex(store)
|
||||
}
|
||||
default:
|
||||
txIndexer = &null.TxIndex{}
|
||||
}
|
||||
|
||||
indexerService := txindex.NewIndexerService(txIndexer, eventBus)
|
||||
indexerService.SetLogger(logger.With("module", "txindex"))
|
||||
|
||||
p2pLogger := logger.With("module", "p2p")
|
||||
nodeInfo, err := makeNodeInfo(
|
||||
config,
|
||||
@@ -534,11 +549,6 @@ func (n *Node) OnStart() error {
|
||||
time.Sleep(genTime.Sub(now))
|
||||
}
|
||||
|
||||
err := n.eventBus.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Add private IDs to addrbook to block those peers being added
|
||||
n.addrBook.AddPrivateIDs(splitAndTrimEmpty(n.config.P2P.PrivatePeerIDs, ",", " "))
|
||||
|
||||
@@ -582,8 +592,7 @@ func (n *Node) OnStart() error {
|
||||
}
|
||||
}
|
||||
|
||||
// start tx indexer
|
||||
return n.indexerService.Start()
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnStop stops the Node. It implements cmn.Service.
|
||||
|
@@ -30,7 +30,7 @@ func createMConnectionWithCallbacks(conn net.Conn, onReceive func(chID byte, msg
|
||||
cfg := DefaultMConnConfig()
|
||||
cfg.PingInterval = 90 * time.Millisecond
|
||||
cfg.PongTimeout = 45 * time.Millisecond
|
||||
chDescs := []*ChannelDescriptor{&ChannelDescriptor{ID: 0x01, Priority: 1, SendQueueCapacity: 1}}
|
||||
chDescs := []*ChannelDescriptor{{ID: 0x01, Priority: 1, SendQueueCapacity: 1}}
|
||||
c := NewMConnectionWithConfig(conn, chDescs, onReceive, onError, cfg)
|
||||
c.SetLogger(log.TestingLogger())
|
||||
return c
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
crand "crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
@@ -28,6 +29,8 @@ const aeadSizeOverhead = 16 // overhead of poly 1305 authentication tag
|
||||
const aeadKeySize = chacha20poly1305.KeySize
|
||||
const aeadNonceSize = chacha20poly1305.NonceSize
|
||||
|
||||
var ErrSmallOrderRemotePubKey = errors.New("detected low order point from remote peer")
|
||||
|
||||
// SecretConnection implements net.Conn.
|
||||
// It is an implementation of the STS protocol.
|
||||
// See https://github.com/tendermint/tendermint/blob/0.1/docs/sts-final.pdf for
|
||||
@@ -251,6 +254,9 @@ func shareEphPubKey(conn io.ReadWriteCloser, locEphPub *[32]byte) (remEphPub *[3
|
||||
if err2 != nil {
|
||||
return nil, err2, true // abort
|
||||
}
|
||||
if hasSmallOrder(_remEphPub) {
|
||||
return nil, ErrSmallOrderRemotePubKey, true
|
||||
}
|
||||
return _remEphPub, nil, false
|
||||
},
|
||||
)
|
||||
@@ -266,6 +272,52 @@ func shareEphPubKey(conn io.ReadWriteCloser, locEphPub *[32]byte) (remEphPub *[3
|
||||
return &_remEphPub, nil
|
||||
}
|
||||
|
||||
// use the samne blacklist as lib sodium (see https://eprint.iacr.org/2017/806.pdf for reference):
|
||||
// https://github.com/jedisct1/libsodium/blob/536ed00d2c5e0c65ac01e29141d69a30455f2038/src/libsodium/crypto_scalarmult/curve25519/ref10/x25519_ref10.c#L11-L17
|
||||
var blacklist = [][32]byte{
|
||||
// 0 (order 4)
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
// 1 (order 1)
|
||||
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
// 325606250916557431795983626356110631294008115727848805560023387167927233504
|
||||
// (order 8)
|
||||
{0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3,
|
||||
0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32,
|
||||
0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00},
|
||||
// 39382357235489614581723060781553021112529911719440698176882885853963445705823
|
||||
// (order 8)
|
||||
{0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, 0xb1, 0xd0, 0xb1,
|
||||
0x55, 0x9c, 0x83, 0xef, 0x5b, 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c,
|
||||
0x8e, 0x86, 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57},
|
||||
// p-1 (order 2)
|
||||
{0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f},
|
||||
// p (=0, order 4)
|
||||
{0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f},
|
||||
// p+1 (=1, order 1)
|
||||
{0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f},
|
||||
}
|
||||
|
||||
func hasSmallOrder(pubKey [32]byte) bool {
|
||||
isSmallOrderPoint := false
|
||||
for _, bl := range blacklist {
|
||||
if subtle.ConstantTimeCompare(pubKey[:], bl[:]) == 1 {
|
||||
isSmallOrderPoint = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return isSmallOrderPoint
|
||||
}
|
||||
|
||||
func deriveSecretAndChallenge(dhSecret *[32]byte, locIsLeast bool) (recvSecret, sendSecret *[aeadKeySize]byte, challenge *[32]byte) {
|
||||
hash := sha256.New
|
||||
hkdf := hkdf.New(hash, dhSecret[:], nil, []byte("TENDERMINT_SECRET_CONNECTION_KEY_AND_CHALLENGE_GEN"))
|
||||
|
@@ -100,6 +100,32 @@ func TestSecretConnectionHandshake(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestShareLowOrderPubkey(t *testing.T) {
|
||||
var fooConn, barConn = makeKVStoreConnPair()
|
||||
locEphPub, _ := genEphKeys()
|
||||
|
||||
// all blacklisted low order points:
|
||||
for _, remLowOrderPubKey := range blacklist {
|
||||
_, _ = cmn.Parallel(
|
||||
func(_ int) (val interface{}, err error, abort bool) {
|
||||
_, err = shareEphPubKey(fooConn, locEphPub)
|
||||
|
||||
require.Error(t, err)
|
||||
require.Equal(t, err, ErrSmallOrderRemotePubKey)
|
||||
|
||||
return nil, nil, false
|
||||
},
|
||||
func(_ int) (val interface{}, err error, abort bool) {
|
||||
readRemKey, err := shareEphPubKey(barConn, &remLowOrderPubKey)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, locEphPub, readRemKey)
|
||||
|
||||
return nil, nil, false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConcurrentWrite(t *testing.T) {
|
||||
fooSecConn, barSecConn := makeSecretConnPair(t)
|
||||
fooWriteText := cmn.RandStr(dataMaxSize)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package conn
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||
)
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package pex
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
)
|
||||
|
||||
var cdc *amino.Codec = amino.NewCodec()
|
||||
|
@@ -498,13 +498,13 @@ func TestTransportConnDuplicateIPFilter(t *testing.T) {
|
||||
)
|
||||
|
||||
cs.Set(c, []net.IP{
|
||||
net.IP{10, 0, 10, 1},
|
||||
net.IP{10, 0, 10, 2},
|
||||
net.IP{10, 0, 10, 3},
|
||||
{10, 0, 10, 1},
|
||||
{10, 0, 10, 2},
|
||||
{10, 0, 10, 3},
|
||||
})
|
||||
|
||||
if err := filter(cs, c, []net.IP{
|
||||
net.IP{10, 0, 10, 2},
|
||||
{10, 0, 10, 2},
|
||||
}); err == nil {
|
||||
t.Errorf("expected Peer to be rejected as duplicate")
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package p2p
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||
)
|
||||
|
||||
|
@@ -37,11 +37,11 @@ func socketTestCases(t *testing.T) []socketTestCase {
|
||||
require.NoError(t, err)
|
||||
unixAddr := fmt.Sprintf("unix://%s", unixFilePath)
|
||||
return []socketTestCase{
|
||||
socketTestCase{
|
||||
{
|
||||
addr: tcpAddr,
|
||||
dialer: DialTCPFn(tcpAddr, testConnDeadline, ed25519.GenPrivKey()),
|
||||
},
|
||||
socketTestCase{
|
||||
{
|
||||
addr: unixAddr,
|
||||
dialer: DialUnixFn(unixFilePath),
|
||||
},
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
|
@@ -98,36 +98,29 @@ func TestListenerAcceptDeadlines(t *testing.T) {
|
||||
|
||||
func TestListenerConnectDeadlines(t *testing.T) {
|
||||
for _, tc := range listenerTestCases(t, time.Second, time.Millisecond) {
|
||||
readyc := make(chan struct{})
|
||||
donec := make(chan struct{})
|
||||
go func(ln net.Listener) {
|
||||
defer close(donec)
|
||||
|
||||
c, err := ln.Accept()
|
||||
go func(dialer Dialer) {
|
||||
_, err := dialer()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
panic(err)
|
||||
}
|
||||
<-readyc
|
||||
}(tc.dialer)
|
||||
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
|
||||
msg := make([]byte, 200)
|
||||
_, err = c.Read(msg)
|
||||
opErr, ok := err.(*net.OpError)
|
||||
if !ok {
|
||||
t.Fatalf("for %s listener, have %v, want *net.OpError", tc.description, err)
|
||||
}
|
||||
|
||||
if have, want := opErr.Op, "read"; have != want {
|
||||
t.Errorf("for %s listener, have %v, want %v", tc.description, have, want)
|
||||
}
|
||||
}(tc.listener)
|
||||
|
||||
_, err := tc.dialer()
|
||||
c, err := tc.listener.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
close(readyc)
|
||||
<-donec
|
||||
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
|
||||
msg := make([]byte, 200)
|
||||
_, err = c.Read(msg)
|
||||
opErr, ok := err.(*net.OpError)
|
||||
if !ok {
|
||||
t.Fatalf("for %s listener, have %v, want *net.OpError", tc.description, err)
|
||||
}
|
||||
|
||||
if have, want := opErr.Op, "read"; have != want {
|
||||
t.Errorf("for %s listener, have %v, want %v", tc.description, have, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package privval
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||
)
|
||||
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"github.com/tendermint/tendermint/rpc/client"
|
||||
"github.com/tendermint/tendermint/rpc/test"
|
||||
rpctest "github.com/tendermint/tendermint/rpc/test"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package core_types
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
|
@@ -8,8 +8,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/abci/example/kvstore"
|
||||
"github.com/tendermint/tendermint/rpc/grpc"
|
||||
"github.com/tendermint/tendermint/rpc/test"
|
||||
core_grpc "github.com/tendermint/tendermint/rpc/grpc"
|
||||
rpctest "github.com/tendermint/tendermint/rpc/test"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
@@ -5,8 +5,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
)
|
||||
|
||||
type Tx []byte
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
|
||||
types "github.com/tendermint/tendermint/rpc/lib/types"
|
||||
)
|
||||
|
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
metrics "github.com/rcrowley/go-metrics"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
types "github.com/tendermint/tendermint/rpc/lib/types"
|
||||
)
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
)
|
||||
|
||||
type SampleResult struct {
|
||||
|
@@ -47,7 +47,12 @@ installFromGithub() {
|
||||
|
||||
installFromGithub mitchellh/gox 51ed453898ca5579fea9ad1f08dff6b121d9f2e8
|
||||
installFromGithub golang/dep 22125cfaa6ddc71e145b1535d4b7ee9744fefff2 cmd/dep
|
||||
## gometalinter v2.0.11
|
||||
installFromGithub alecthomas/gometalinter 17a7ffa42374937bfecabfb8d2efbd4db0c26741
|
||||
## gometalinter v3.0.0
|
||||
installFromGithub alecthomas/gometalinter df395bfa67c5d0630d936c0044cf07ff05086655
|
||||
installFromGithub gogo/protobuf 61dbc136cf5d2f08d68a011382652244990a53a9 protoc-gen-gogo
|
||||
installFromGithub square/certstrap e27060a3643e814151e65b9807b6b06d169580a7
|
||||
|
||||
## make test_with_deadlock
|
||||
installFromGithub petermattis/goid b0b1615b78e5ee59739545bb38426383b2cda4c9
|
||||
installFromGithub sasha-s/go-deadlock d68e2bc52ae3291765881b9056f2c1527f245f1e
|
||||
go get golang.org/x/tools/cmd/goimports
|
||||
|
@@ -14,7 +14,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
cs "github.com/tendermint/tendermint/consensus"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
cs "github.com/tendermint/tendermint/consensus"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
@@ -49,8 +49,7 @@ func BlockExecutorWithMetrics(metrics *Metrics) BlockExecutorOption {
|
||||
|
||||
// NewBlockExecutor returns a new BlockExecutor with a NopEventBus.
|
||||
// Call SetEventBus to provide one.
|
||||
func NewBlockExecutor(db dbm.DB, logger log.Logger, proxyApp proxy.AppConnConsensus,
|
||||
mempool Mempool, evpool EvidencePool, options ...BlockExecutorOption) *BlockExecutor {
|
||||
func NewBlockExecutor(db dbm.DB, logger log.Logger, proxyApp proxy.AppConnConsensus, mempool Mempool, evpool EvidencePool, options ...BlockExecutorOption) *BlockExecutor {
|
||||
res := &BlockExecutor{
|
||||
db: db,
|
||||
proxyApp: proxyApp,
|
||||
|
@@ -309,8 +309,8 @@ func TestEndBlockValidatorUpdates(t *testing.T) {
|
||||
|
||||
state, stateDB := state(1, 1)
|
||||
|
||||
blockExec := NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(),
|
||||
MockMempool{}, MockEvidencePool{})
|
||||
blockExec := NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(), MockMempool{}, MockEvidencePool{})
|
||||
|
||||
eventBus := types.NewEventBus()
|
||||
err = eventBus.Start()
|
||||
require.NoError(t, err)
|
||||
|
@@ -184,8 +184,8 @@ func TestIndexAllTags(t *testing.T) {
|
||||
indexer := NewTxIndex(db.NewMemDB(), IndexAllTags())
|
||||
|
||||
txResult := txResultWithTags([]cmn.KVPair{
|
||||
cmn.KVPair{Key: []byte("account.owner"), Value: []byte("Ivan")},
|
||||
cmn.KVPair{Key: []byte("account.number"), Value: []byte("1")},
|
||||
{Key: []byte("account.owner"), Value: []byte("Ivan")},
|
||||
{Key: []byte("account.number"), Value: []byte("1")},
|
||||
})
|
||||
|
||||
err := indexer.Index(txResult)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package kv
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
)
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||
)
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
Tendermint blockchain benchmarking tool:
|
||||
|
||||
- https://github.com/tendermint/tools/tree/master/tm-bench
|
||||
- [https://github.com/tendermint/tendermint/tree/master/tools/tm-bench](https://github.com/tendermint/tendermint/tree/master/tools/tm-bench)
|
||||
|
||||
For example, the following: `tm-bench -T 30 -r 10000 localhost:26657`
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
Tendermint blockchain monitoring tool; watches over one or more nodes,
|
||||
collecting and providing various statistics to the user:
|
||||
|
||||
- https://github.com/tendermint/tools/tree/master/tm-monitor
|
||||
- [https://github.com/tendermint/tendermint/tree/master/tools/tm-monitor](https://github.com/tendermint/tendermint/tree/master/tools/tm-monitor)
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
@@ -196,7 +196,7 @@ func (em *EventMeter) RegisterDisconnectCallback(f DisconnectCallbackFunc) {
|
||||
// Private
|
||||
|
||||
func (em *EventMeter) subscribe() error {
|
||||
for query, _ := range em.queryToMetricMap {
|
||||
for query := range em.queryToMetricMap {
|
||||
if err := em.wsc.Subscribe(context.TODO(), query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
stdlog "log"
|
||||
"reflect"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
em "github.com/tendermint/tendermint/tools/tm-monitor/eventmeter"
|
||||
)
|
||||
|
@@ -46,7 +46,7 @@ func NewMonitor(options ...func(*Monitor)) *Monitor {
|
||||
nodeQuit: make(map[string]chan struct{}),
|
||||
recalculateNetworkUptimeEvery: 10 * time.Second,
|
||||
numValidatorsUpdateInterval: 5 * time.Second,
|
||||
logger: log.NewNopLogger(),
|
||||
logger: log.NewNopLogger(),
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
mock "github.com/tendermint/tendermint/tools/tm-monitor/mock"
|
||||
|
@@ -55,13 +55,13 @@ func NewNode(rpcAddr string, options ...func(*Node)) *Node {
|
||||
|
||||
func NewNodeWithEventMeterAndRpcClient(rpcAddr string, em eventMeter, rpcClient rpc_client.HTTPClient, options ...func(*Node)) *Node {
|
||||
n := &Node{
|
||||
rpcAddr: rpcAddr,
|
||||
em: em,
|
||||
rpcClient: rpcClient,
|
||||
Name: rpcAddr,
|
||||
quit: make(chan struct{}),
|
||||
rpcAddr: rpcAddr,
|
||||
em: em,
|
||||
rpcClient: rpcClient,
|
||||
Name: rpcAddr,
|
||||
quit: make(chan struct{}),
|
||||
checkIsValidatorInterval: 5 * time.Second,
|
||||
logger: log.NewNopLogger(),
|
||||
logger: log.NewNopLogger(),
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
|
@@ -11,21 +11,30 @@ import (
|
||||
|
||||
// Reserved event types (alphabetically sorted).
|
||||
const (
|
||||
EventCompleteProposal = "CompleteProposal"
|
||||
EventLock = "Lock"
|
||||
// Block level events for mass consumption by users.
|
||||
// These events are triggered from the state package,
|
||||
// after a block has been committed.
|
||||
// These are also used by the tx indexer for async indexing.
|
||||
// All of this data can be fetched through the rpc.
|
||||
EventNewBlock = "NewBlock"
|
||||
EventNewBlockHeader = "NewBlockHeader"
|
||||
EventNewRound = "NewRound"
|
||||
EventNewRoundStep = "NewRoundStep"
|
||||
EventPolka = "Polka"
|
||||
EventRelock = "Relock"
|
||||
EventTimeoutPropose = "TimeoutPropose"
|
||||
EventTimeoutWait = "TimeoutWait"
|
||||
EventTx = "Tx"
|
||||
EventUnlock = "Unlock"
|
||||
EventValidBlock = "ValidBlock"
|
||||
EventValidatorSetUpdates = "ValidatorSetUpdates"
|
||||
EventVote = "Vote"
|
||||
|
||||
// Internal consensus events.
|
||||
// These are used for testing the consensus state machine.
|
||||
// They can also be used to build real-time consensus visualizers.
|
||||
EventCompleteProposal = "CompleteProposal"
|
||||
EventLock = "Lock"
|
||||
EventNewRound = "NewRound"
|
||||
EventNewRoundStep = "NewRoundStep"
|
||||
EventPolka = "Polka"
|
||||
EventRelock = "Relock"
|
||||
EventTimeoutPropose = "TimeoutPropose"
|
||||
EventTimeoutWait = "TimeoutWait"
|
||||
EventUnlock = "Unlock"
|
||||
EventValidBlock = "ValidBlock"
|
||||
EventVote = "Vote"
|
||||
)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@@ -15,9 +15,9 @@ import (
|
||||
func TestGenesisBad(t *testing.T) {
|
||||
// test some bad ones from raw json
|
||||
testCases := [][]byte{
|
||||
[]byte{}, // empty
|
||||
[]byte{1, 1, 1, 1, 1}, // junk
|
||||
[]byte(`{}`), // empty
|
||||
{}, // empty
|
||||
{1, 1, 1, 1, 1}, // junk
|
||||
[]byte(`{}`), // empty
|
||||
[]byte(`{"chain_id":"mychain","validators":[{}]}`), // invalid validator
|
||||
// missing pub_key type
|
||||
[]byte(`{"validators":[{"pub_key":{"value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="},"power":"10","name":""}]}`),
|
||||
|
@@ -21,9 +21,6 @@ type Part struct {
|
||||
Index int `json:"index"`
|
||||
Bytes cmn.HexBytes `json:"bytes"`
|
||||
Proof merkle.SimpleProof `json:"proof"`
|
||||
|
||||
// Cache
|
||||
hash []byte
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
|
@@ -7,8 +7,7 @@ import (
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
|
||||
amino "github.com/tendermint/go-amino"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto/merkle"
|
||||
|
@@ -2,7 +2,7 @@ package types
|
||||
|
||||
import (
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||
)
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
|
@@ -18,6 +18,8 @@ const (
|
||||
// TMCoreSemVer is the current version of Tendermint Core.
|
||||
// It's the Semantic Version of the software.
|
||||
// Must be a string because scripts like dist.sh read this file.
|
||||
// XXX: Don't change the name of this variable or you will break
|
||||
// automation :)
|
||||
TMCoreSemVer = "0.29.1"
|
||||
|
||||
// ABCISemVer is the semantic version of the ABCI library
|
||||
|
Reference in New Issue
Block a user