Compare commits

..

2 Commits

Author SHA1 Message Date
Jae Kwon
48ab899923 Do not shut down peer immediately after sending pex addrs in SeedMode 2018-11-09 19:31:59 -08:00
Jae Kwon
58574b7372 Require addressbook to only store addresses with valid ID 2018-11-09 15:51:56 -08:00
69 changed files with 539 additions and 1038 deletions

View File

@@ -92,7 +92,6 @@ jobs:
command: |
export PATH="$GOBIN:$PATH"
make get_tools
make get_dev_tools
- run:
name: dependencies
command: |

View File

@@ -1,50 +1,5 @@
# Changelog
## v0.26.2
*November 15th, 2018*
Special thanks to external contributors on this release: @hleb-albau, @zhuzeyu
Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermint).
### FEATURES:
- [rpc] [\#2582](https://github.com/tendermint/tendermint/issues/2582) Enable CORS on RPC API (@hleb-albau)
### BUG FIXES:
- [abci] [\#2748](https://github.com/tendermint/tendermint/issues/2748) Unlock mutex in localClient so even when app panics (e.g. during CheckTx), consensus continue working
- [abci] [\#2748](https://github.com/tendermint/tendermint/issues/2748) Fix DATA RACE in localClient
- [amino] [\#2822](https://github.com/tendermint/tendermint/issues/2822) Update to v0.14.1 to support compiling on 32-bit platforms
- [rpc] [\#2748](https://github.com/tendermint/tendermint/issues/2748) Drain channel before calling Unsubscribe(All) in `/broadcast_tx_commit`
## v0.26.1
*November 11, 2018*
Special thanks to external contributors on this release: @katakonst
Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermint).
### IMPROVEMENTS:
- [consensus] [\#2704](https://github.com/tendermint/tendermint/issues/2704) Simplify valid POL round logic
- [docs] [\#2749](https://github.com/tendermint/tendermint/issues/2749) Deduplicate some ABCI docs
- [mempool] More detailed log messages
- [\#2724](https://github.com/tendermint/tendermint/issues/2724)
- [\#2762](https://github.com/tendermint/tendermint/issues/2762)
### BUG FIXES:
- [autofile] [\#2703](https://github.com/tendermint/tendermint/issues/2703) Do not panic when checking Head size
- [crypto/merkle] [\#2756](https://github.com/tendermint/tendermint/issues/2756) Fix crypto/merkle ProofOperators.Verify to check bounds on keypath parts.
- [mempool] fix a bug where we create a WAL despite `wal_dir` being empty
- [p2p] [\#2771](https://github.com/tendermint/tendermint/issues/2771) Fix `peer-id` label name to `peer_id` in prometheus metrics
- [p2p] [\#2797](https://github.com/tendermint/tendermint/pull/2797) Fix IDs in peer NodeInfo and require them for addresses
in AddressBook
- [p2p] [\#2797](https://github.com/tendermint/tendermint/pull/2797) Do not close conn immediately after sending pex addrs in seed mode. Partial fix for [\#2092](https://github.com/tendermint/tendermint/issues/2092).
## v0.26.0
*November 2, 2018*
@@ -153,8 +108,6 @@ increasing attention to backwards compatibility. Thanks for bearing with us!
- [abci] [\#2557](https://github.com/tendermint/tendermint/issues/2557) Add `Codespace` field to `Response{CheckTx, DeliverTx, Query}`
- [abci] [\#2662](https://github.com/tendermint/tendermint/issues/2662) Add `BlockVersion` and `P2PVersion` to `RequestInfo`
- [crypto/merkle] [\#2298](https://github.com/tendermint/tendermint/issues/2298) General Merkle Proof scheme for chaining various types of Merkle trees together
- [docs/architecture] [\#1181](https://github.com/tendermint/tendermint/issues/1181) S
plit immutable and mutable parts of priv_validator.json
### IMPROVEMENTS:
- Additional Metrics
@@ -187,6 +140,8 @@ plit immutable and mutable parts of priv_validator.json
- [state] [\#2616](https://github.com/tendermint/tendermint/issues/2616) Pass nil to NewValidatorSet() when genesis file's Validators field is nil
- [p2p] [\#2555](https://github.com/tendermint/tendermint/issues/2555) Fix p2p switch FlushThrottle value (@goolAdapter)
- [p2p] [\#2668](https://github.com/tendermint/tendermint/issues/2668) Reconnect to originally dialed address (not self-reported address) for persistent peers
- [p2p] [\#2797](https://github.com/tendermint/tendermint/pull/2797) AddressBook requires addresses to have IDs; Do not crap out immediately after sending pex addrs in seed mode
## v0.25.0
@@ -352,8 +307,8 @@ BUG FIXES:
*August 22nd, 2018*
BUG FIXES:
- [libs/autofile] [\#2261](https://github.com/tendermint/tendermint/issues/2261) Fix log rotation so it actually happens.
- Fixes issues with consensus WAL growing unbounded ala [\#2259](https://github.com/tendermint/tendermint/issues/2259)
- [libs/autofile] \#2261 Fix log rotation so it actually happens.
- Fixes issues with consensus WAL growing unbounded ala \#2259
## 0.23.0

View File

@@ -1,13 +1,12 @@
# Pending
## v0.26.3
## v0.26.1
*TBD*
*TBA*
Special thanks to external contributors on this release:
Friendly reminder, we have a [bug bounty
program](https://hackerone.com/tendermint).
Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermint).
### BREAKING CHANGES:
@@ -21,9 +20,12 @@ program](https://hackerone.com/tendermint).
* P2P Protocol
### FEATURES:
### IMPROVEMENTS:
### BUG FIXES:
- [crypto/merkle] [\#2756](https://github.com/tendermint/tendermint/issues/2756) Fix crypto/merkle ProofOperators.Verify to check bounds on keypath parts.
- [mempool] fix a bug where we create a WAL despite `wal_dir` being empty
- [p2p] \#2771 Fix `peer-id` label name in prometheus metrics

View File

@@ -6,7 +6,7 @@ This code of conduct applies to all projects run by the Tendermint/COSMOS team a
# Conduct
## Contact: conduct@tendermint.com
## Contact: adrian@tendermint.com
* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.

View File

@@ -27,8 +27,8 @@ Of course, replace `ebuchman` with your git handle.
To pull in updates from the origin repo, run
* `git fetch upstream`
* `git rebase upstream/master` (or whatever branch you want)
* `git fetch upstream`
* `git rebase upstream/master` (or whatever branch you want)
Please don't make Pull Requests to `master`.
@@ -50,11 +50,6 @@ as apps, tools, and the core, should use dep.
Run `dep status` to get a list of vendor dependencies that may not be
up-to-date.
When updating dependencies, please only update the particular dependencies you
need. Instead of running `dep ensure -update`, which will update anything,
specify exactly the dependency you want to update, eg.
`dep ensure -update github.com/tendermint/go-amino`.
## Vagrant
If you are a [Vagrant](https://www.vagrantup.com/) user, you can get started
@@ -78,41 +73,34 @@ tested by circle using `go test -v -race ./...`. If not, they will need a
`circle.yml`. Ideally, every repo has a `Makefile` that defines `make test` and
includes its continuous integration status using a badge in the `README.md`.
## Changelog
## Branching Model and Release
All repos should adhere to the branching model: http://nvie.com/posts/a-successful-git-branching-model/.
This means that all pull-requests should be made against develop. Any merge to
master constitutes a tagged release.
User-facing repos should adhere to the branching model: http://nvie.com/posts/a-successful-git-branching-model/.
That is, these repos should be well versioned, and any merge to master requires a version bump and tagged release.
Libraries need not follow the model strictly, but would be wise to,
especially `go-p2p` and `go-rpc`, as their versions are referenced in tendermint core.
### Development Procedure:
- the latest state of development is on `develop`
- `develop` must never fail `make test`
- never --force onto `develop` (except when reverting a broken commit, which should seldom happen)
- no --force onto `develop` (except when reverting a broken commit, which should seldom happen)
- create a development branch either on github.com/tendermint/tendermint, or your fork (using `git remote add origin`)
- make changes and update the `CHANGELOG_PENDING.md` to record your change
- before submitting a pull request, run `git rebase` on top of the latest `develop`
- before submitting a pull request, begin `git rebase` on top of `develop`
### Pull Merge Procedure:
- ensure pull branch is based on a recent develop
- ensure pull branch is rebased on develop
- run `make test` to ensure that all tests pass
- merge pull request
- the `unstable` branch may be used to aggregate pull merges before fixing tests
- the `unstable` branch may be used to aggregate pull merges before testing once
- push master may request that pull requests be rebased on top of `unstable`
### Release Procedure:
- start on `develop`
- run integration tests (see `test_integrations` in Makefile)
- prepare changelog:
- copy `CHANGELOG_PENDING.md` to `CHANGELOG.md`
- run `python ./scripts/linkify_changelog.py CHANGELOG.md` to add links for
all issues
- run `bash ./scripts/authors.sh` to get a list of authors since the latest
release, and add the github aliases of external contributors to the top of
the changelog. To lookup an alias from an email, try `bash
./scripts/authors.sh <email>`
- prepare changelog/release issue
- bump versions
- push to release/vX.X.X to run the extended integration tests on the CI
- push to release-vX.X.X to run the extended integration tests on the CI
- merge to master
- merge master back to develop

14
Gopkg.lock generated
View File

@@ -128,14 +128,6 @@
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
version = "v1.2.0"
[[projects]]
digest = "1:b0c25f00bad20d783d259af2af8666969e2fc343fa0dc9efe52936bbd67fb758"
name = "github.com/rs/cors"
packages = ["."]
pruneopts = "UT"
revision = "9a47f48565a795472d43519dd49aac781f3034fb"
version = "v1.6.0"
[[projects]]
digest = "1:ea40c24cdbacd054a6ae9de03e62c5f252479b96c716375aace5c120d68647c8"
name = "github.com/hashicorp/hcl"
@@ -366,12 +358,12 @@
revision = "e5840949ff4fff0c56f9b6a541e22b63581ea9df"
[[projects]]
digest = "1:ad9c4c1a4e7875330b1f62906f2830f043a23edb5db997e3a5ac5d3e6eadf80a"
digest = "1:10b3a599325740c84a7c81f3f3cb2e1fdb70b3ea01b7fa28495567a2519df431"
name = "github.com/tendermint/go-amino"
packages = ["."]
pruneopts = "UT"
revision = "dc14acf9ef15f85828bfbc561ed9dd9d2a284885"
version = "v0.14.1"
revision = "6dcc6ddc143e116455c94b25c1004c99e0d0ca12"
version = "v0.14.0"
[[projects]]
digest = "1:72b71e3a29775e5752ed7a8012052a3dee165e27ec18cedddae5288058f09acf"

View File

@@ -40,10 +40,6 @@
name = "github.com/gorilla/websocket"
version = "=1.2.0"
[[constraint]]
name = "github.com/rs/cors"
version = "1.6.0"
[[constraint]]
name = "github.com/pkg/errors"
version = "=0.8.0"
@@ -62,7 +58,7 @@
[[constraint]]
name = "github.com/tendermint/go-amino"
version = "v0.14.1"
version = "v0.14.0"
[[constraint]]
name = "google.golang.org/grpc"

View File

@@ -17,6 +17,7 @@ all: check build test install
check: check_tools get_vendor_deps
########################################
### Build Tendermint
@@ -78,8 +79,6 @@ check_tools:
get_tools:
@echo "--> Installing tools"
./scripts/get_tools.sh
get_dev_tools:
@echo "--> Downloading linters (this may take awhile)"
$(GOPATH)/src/github.com/alecthomas/gometalinter/scripts/install.sh -b $(GOBIN)
@@ -328,4 +327,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
.PHONY: check build build_race build_abci dist install install_abci check_dep check_tools get_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

View File

@@ -41,7 +41,7 @@ please [contact us](mailto:partners@tendermint.com) and [join the chat](https://
## Security
To report a security vulnerability, see our [bug bounty
program](https://hackerone.com/tendermint)
program](https://tendermint.com/security).
For examples of the kinds of bugs we're looking for, see [SECURITY.md](SECURITY.md)
@@ -51,18 +51,14 @@ Requirement|Notes
---|---
Go version | Go1.10 or higher
## Documentation
Complete documentation can be found on the [website](https://tendermint.com/docs/).
### Install
## Install
See the [install instructions](/docs/introduction/install.md)
### Quick Start
## Quick Start
- [Single node](/docs/introduction/quick-start.md)
- [Local cluster using docker-compose](/docs/networks/docker-compose.md)
- [Single node](/docs/tendermint-core/using-tendermint.md)
- [Local cluster using docker-compose](/networks/local)
- [Remote cluster using terraform and ansible](/docs/networks/terraform-and-ansible.md)
- [Join the Cosmos testnet](https://cosmos.network/testnet)
@@ -95,7 +91,6 @@ Additional documentation is found [here](/docs/tools).
### Research
* [The latest gossip on BFT consensus](https://arxiv.org/abs/1807.04938)
* [Master's Thesis on Tendermint](https://atrium.lib.uoguelph.ca/xmlui/handle/10214/9769)
* [Original Whitepaper](https://tendermint.com/static/docs/tendermint.pdf)
* [Blog](https://blog.cosmos.network/tendermint/home)

View File

@@ -1,8 +1,7 @@
# Security
As part of our [Coordinated Vulnerability Disclosure
Policy](https://tendermint.com/security), we operate a [bug
bounty](https://hackerone.com/tendermint).
Policy](https://tendermint.com/security), we operate a bug bounty.
See the policy for more details on submissions and rewards.
Here is a list of examples of the kinds of bugs we're most interested in:

View File

@@ -1,5 +1,7 @@
# Application BlockChain Interface (ABCI)
[![CircleCI](https://circleci.com/gh/tendermint/abci.svg?style=svg)](https://circleci.com/gh/tendermint/abci)
Blockchains are systems for multi-master state machine replication.
**ABCI** is an interface that defines the boundary between the replication engine (the blockchain),
and the state machine (the application).
@@ -10,28 +12,160 @@ Previously, the ABCI was referred to as TMSP.
The community has provided a number of addtional implementations, see the [Tendermint Ecosystem](https://tendermint.com/ecosystem)
## Installation & Usage
To get up and running quickly, see the [getting started guide](../docs/app-dev/getting-started.md) along with the [abci-cli documentation](../docs/app-dev/abci-cli.md) which will go through the examples found in the [examples](./example/) directory.
## Specification
A detailed description of the ABCI methods and message types is contained in:
- [The main spec](../docs/spec/abci/abci.md)
- [A protobuf file](./types/types.proto)
- [A Go interface](./types/application.go)
- [A prose specification](specification.md)
- [A protobuf file](https://github.com/tendermint/tendermint/blob/master/abci/types/types.proto)
- [A Go interface](https://github.com/tendermint/tendermint/blob/master/abci/types/application.go).
For more background information on ABCI, motivations, and tendermint, please visit [the documentation](https://tendermint.com/docs/).
The two guides to focus on are the `Application Development Guide` and `Using ABCI-CLI`.
## Protocol Buffers
To compile the protobuf file, run (from the root of the repo):
To compile the protobuf file, run:
```
make protoc_abci
cd $GOPATH/src/github.com/tendermint/tendermint/; make protoc_abci
```
See `protoc --help` and [the Protocol Buffers site](https://developers.google.com/protocol-buffers)
for details on compiling for other languages. Note we also include a [GRPC](https://www.grpc.io/docs)
for details on compiling for other languages. Note we also include a [GRPC](http://www.grpc.io/docs)
service definition.
## Install ABCI-CLI
The `abci-cli` is a simple tool for debugging ABCI servers and running some
example apps. To install it:
```
mkdir -p $GOPATH/src/github.com/tendermint
cd $GOPATH/src/github.com/tendermint
git clone https://github.com/tendermint/tendermint.git
cd tendermint
make get_tools
make get_vendor_deps
make install_abci
```
## Implementation
We provide three implementations of the ABCI in Go:
- Golang in-process
- ABCI-socket
- GRPC
Note the GRPC version is maintained primarily to simplify onboarding and prototyping and is not receiving the same
attention to security and performance as the others
### In Process
The simplest implementation just uses function calls within Go.
This means ABCI applications written in Golang can be compiled with TendermintCore and run as a single binary.
See the [examples](#examples) below for more information.
### Socket (TSP)
ABCI is best implemented as a streaming protocol.
The socket implementation provides for asynchronous, ordered message passing over unix or tcp.
Messages are serialized using Protobuf3 and length-prefixed with a [signed Varint](https://developers.google.com/protocol-buffers/docs/encoding?csw=1#signed-integers)
For example, if the Protobuf3 encoded ABCI message is `0xDEADBEEF` (4 bytes), the length-prefixed message is `0x08DEADBEEF`, since `0x08` is the signed varint
encoding of `4`. If the Protobuf3 encoded ABCI message is 65535 bytes long, the length-prefixed message would be like `0xFEFF07...`.
Note the benefit of using this `varint` encoding over the old version (where integers were encoded as `<len of len><big endian len>` is that
it is the standard way to encode integers in Protobuf. It is also generally shorter.
### GRPC
GRPC is an rpc framework native to Protocol Buffers with support in many languages.
Implementing the ABCI using GRPC can allow for faster prototyping, but is expected to be much slower than
the ordered, asynchronous socket protocol. The implementation has also not received as much testing or review.
Note the length-prefixing used in the socket implementation does not apply for GRPC.
## Usage
The `abci-cli` tool wraps an ABCI client and can be used for probing/testing an ABCI server.
For instance, `abci-cli test` will run a test sequence against a listening server running the Counter application (see below).
It can also be used to run some example applications.
See [the documentation](https://tendermint.com/docs/) for more details.
### Examples
Check out the variety of example applications in the [example directory](example/).
It also contains the code refered to by the `counter` and `kvstore` apps; these apps come
built into the `abci-cli` binary.
#### Counter
The `abci-cli counter` application illustrates nonce checking in transactions. It's code looks like:
```golang
func cmdCounter(cmd *cobra.Command, args []string) error {
app := counter.NewCounterApplication(flagSerial)
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
// Start the listener
srv, err := server.NewServer(flagAddrC, flagAbci, app)
if err != nil {
return err
}
srv.SetLogger(logger.With("module", "abci-server"))
if err := srv.Start(); err != nil {
return err
}
// Wait forever
cmn.TrapSignal(func() {
// Cleanup
srv.Stop()
})
return nil
}
```
and can be found in [this file](cmd/abci-cli/abci-cli.go).
#### kvstore
The `abci-cli kvstore` application, which illustrates a simple key-value Merkle tree
```golang
func cmdKVStore(cmd *cobra.Command, args []string) error {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
// Create the application - in memory or persisted to disk
var app types.Application
if flagPersist == "" {
app = kvstore.NewKVStoreApplication()
} else {
app = kvstore.NewPersistentKVStoreApplication(flagPersist)
app.(*kvstore.PersistentKVStoreApplication).SetLogger(logger.With("module", "kvstore"))
}
// Start the listener
srv, err := server.NewServer(flagAddrD, flagAbci, app)
if err != nil {
return err
}
srv.SetLogger(logger.With("module", "abci-server"))
if err := srv.Start(); err != nil {
return err
}
// Wait forever
cmn.TrapSignal(func() {
// Cleanup
srv.Stop()
})
return nil
}
```

View File

@@ -105,8 +105,8 @@ func (reqRes *ReqRes) SetCallback(cb func(res *types.Response)) {
return
}
defer reqRes.mtx.Unlock()
reqRes.cb = cb
reqRes.mtx.Unlock()
}
func (reqRes *ReqRes) GetCallback() func(*types.Response) {

View File

@@ -111,8 +111,8 @@ func (cli *grpcClient) Error() error {
// NOTE: callback may get internally generated flush responses.
func (cli *grpcClient) SetResponseCallback(resCb Callback) {
cli.mtx.Lock()
defer cli.mtx.Unlock()
cli.resCb = resCb
cli.mtx.Unlock()
}
//----------------------------------------

View File

@@ -9,13 +9,8 @@ import (
var _ Client = (*localClient)(nil)
// NOTE: use defer to unlock mutex because Application might panic (e.g., in
// case of malicious tx or query). It only makes sense for publicly exposed
// methods like CheckTx (/broadcast_tx_* RPC endpoint) or Query (/abci_query
// RPC endpoint), but defers are used everywhere for the sake of consistency.
type localClient struct {
cmn.BaseService
mtx *sync.Mutex
types.Application
Callback
@@ -35,8 +30,8 @@ func NewLocalClient(mtx *sync.Mutex, app types.Application) *localClient {
func (app *localClient) SetResponseCallback(cb Callback) {
app.mtx.Lock()
defer app.mtx.Unlock()
app.Callback = cb
app.mtx.Unlock()
}
// TODO: change types.Application to include Error()?
@@ -50,9 +45,6 @@ func (app *localClient) FlushAsync() *ReqRes {
}
func (app *localClient) EchoAsync(msg string) *ReqRes {
app.mtx.Lock()
defer app.mtx.Unlock()
return app.callback(
types.ToRequestEcho(msg),
types.ToResponseEcho(msg),
@@ -61,9 +53,8 @@ func (app *localClient) EchoAsync(msg string) *ReqRes {
func (app *localClient) InfoAsync(req types.RequestInfo) *ReqRes {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.Info(req)
app.mtx.Unlock()
return app.callback(
types.ToRequestInfo(req),
types.ToResponseInfo(res),
@@ -72,9 +63,8 @@ func (app *localClient) InfoAsync(req types.RequestInfo) *ReqRes {
func (app *localClient) SetOptionAsync(req types.RequestSetOption) *ReqRes {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.SetOption(req)
app.mtx.Unlock()
return app.callback(
types.ToRequestSetOption(req),
types.ToResponseSetOption(res),
@@ -83,9 +73,8 @@ func (app *localClient) SetOptionAsync(req types.RequestSetOption) *ReqRes {
func (app *localClient) DeliverTxAsync(tx []byte) *ReqRes {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.DeliverTx(tx)
app.mtx.Unlock()
return app.callback(
types.ToRequestDeliverTx(tx),
types.ToResponseDeliverTx(res),
@@ -94,9 +83,8 @@ func (app *localClient) DeliverTxAsync(tx []byte) *ReqRes {
func (app *localClient) CheckTxAsync(tx []byte) *ReqRes {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.CheckTx(tx)
app.mtx.Unlock()
return app.callback(
types.ToRequestCheckTx(tx),
types.ToResponseCheckTx(res),
@@ -105,9 +93,8 @@ func (app *localClient) CheckTxAsync(tx []byte) *ReqRes {
func (app *localClient) QueryAsync(req types.RequestQuery) *ReqRes {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.Query(req)
app.mtx.Unlock()
return app.callback(
types.ToRequestQuery(req),
types.ToResponseQuery(res),
@@ -116,9 +103,8 @@ func (app *localClient) QueryAsync(req types.RequestQuery) *ReqRes {
func (app *localClient) CommitAsync() *ReqRes {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.Commit()
app.mtx.Unlock()
return app.callback(
types.ToRequestCommit(),
types.ToResponseCommit(res),
@@ -127,20 +113,19 @@ func (app *localClient) CommitAsync() *ReqRes {
func (app *localClient) InitChainAsync(req types.RequestInitChain) *ReqRes {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.InitChain(req)
return app.callback(
reqRes := app.callback(
types.ToRequestInitChain(req),
types.ToResponseInitChain(res),
)
app.mtx.Unlock()
return reqRes
}
func (app *localClient) BeginBlockAsync(req types.RequestBeginBlock) *ReqRes {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.BeginBlock(req)
app.mtx.Unlock()
return app.callback(
types.ToRequestBeginBlock(req),
types.ToResponseBeginBlock(res),
@@ -149,9 +134,8 @@ func (app *localClient) BeginBlockAsync(req types.RequestBeginBlock) *ReqRes {
func (app *localClient) EndBlockAsync(req types.RequestEndBlock) *ReqRes {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.EndBlock(req)
app.mtx.Unlock()
return app.callback(
types.ToRequestEndBlock(req),
types.ToResponseEndBlock(res),
@@ -170,73 +154,64 @@ func (app *localClient) EchoSync(msg string) (*types.ResponseEcho, error) {
func (app *localClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, error) {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.Info(req)
app.mtx.Unlock()
return &res, nil
}
func (app *localClient) SetOptionSync(req types.RequestSetOption) (*types.ResponseSetOption, error) {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.SetOption(req)
app.mtx.Unlock()
return &res, nil
}
func (app *localClient) DeliverTxSync(tx []byte) (*types.ResponseDeliverTx, error) {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.DeliverTx(tx)
app.mtx.Unlock()
return &res, nil
}
func (app *localClient) CheckTxSync(tx []byte) (*types.ResponseCheckTx, error) {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.CheckTx(tx)
app.mtx.Unlock()
return &res, nil
}
func (app *localClient) QuerySync(req types.RequestQuery) (*types.ResponseQuery, error) {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.Query(req)
app.mtx.Unlock()
return &res, nil
}
func (app *localClient) CommitSync() (*types.ResponseCommit, error) {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.Commit()
app.mtx.Unlock()
return &res, nil
}
func (app *localClient) InitChainSync(req types.RequestInitChain) (*types.ResponseInitChain, error) {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.InitChain(req)
app.mtx.Unlock()
return &res, nil
}
func (app *localClient) BeginBlockSync(req types.RequestBeginBlock) (*types.ResponseBeginBlock, error) {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.BeginBlock(req)
app.mtx.Unlock()
return &res, nil
}
func (app *localClient) EndBlockSync(req types.RequestEndBlock) (*types.ResponseEndBlock, error) {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.EndBlock(req)
app.mtx.Unlock()
return &res, nil
}

View File

@@ -118,8 +118,8 @@ func (cli *socketClient) Error() error {
// NOTE: callback may get internally generated flush responses.
func (cli *socketClient) SetResponseCallback(resCb Callback) {
cli.mtx.Lock()
defer cli.mtx.Unlock()
cli.resCb = resCb
cli.mtx.Unlock()
}
//----------------------------------------

View File

@@ -242,18 +242,6 @@ type RPCConfig struct {
// TCP or UNIX socket address for the RPC server to listen on
ListenAddress string `mapstructure:"laddr"`
// A list of origins a cross-domain request can be executed from.
// If the special '*' value is present in the list, all origins will be allowed.
// An origin may contain a wildcard (*) to replace 0 or more characters (i.e.: http://*.domain.com).
// Only one wildcard can be used per origin.
CORSAllowedOrigins []string `mapstructure:"cors_allowed_origins"`
// A list of methods the client is allowed to use with cross-domain requests.
CORSAllowedMethods []string `mapstructure:"cors_allowed_methods"`
// A list of non simple headers the client is allowed to use with cross-domain requests.
CORSAllowedHeaders []string `mapstructure:"cors_allowed_headers"`
// TCP or UNIX socket address for the gRPC server to listen on
// NOTE: This server only supports /broadcast_tx_commit
GRPCListenAddress string `mapstructure:"grpc_laddr"`
@@ -281,10 +269,8 @@ type RPCConfig struct {
// DefaultRPCConfig returns a default configuration for the RPC server
func DefaultRPCConfig() *RPCConfig {
return &RPCConfig{
ListenAddress: "tcp://0.0.0.0:26657",
CORSAllowedOrigins: []string{},
CORSAllowedMethods: []string{"HEAD", "GET", "POST"},
CORSAllowedHeaders: []string{"Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time"},
ListenAddress: "tcp://0.0.0.0:26657",
GRPCListenAddress: "",
GRPCMaxOpenConnections: 900,
@@ -314,11 +300,6 @@ func (cfg *RPCConfig) ValidateBasic() error {
return nil
}
// IsCorsEnabled returns true if cross-origin resource sharing is enabled.
func (cfg *RPCConfig) IsCorsEnabled() bool {
return len(cfg.CORSAllowedOrigins) != 0
}
//-----------------------------------------------------------------------------
// P2PConfig

View File

@@ -119,17 +119,6 @@ filter_peers = {{ .BaseConfig.FilterPeers }}
# TCP or UNIX socket address for the RPC server to listen on
laddr = "{{ .RPC.ListenAddress }}"
# A list of origins a cross-domain request can be executed from
# Default value '[]' disables cors support
# Use '["*"]' to allow any origin
cors_allowed_origins = "{{ .RPC.CORSAllowedOrigins }}"
# A list of methods the client is allowed to use with cross-domain requests
cors_allowed_methods = "{{ .RPC.CORSAllowedMethods }}"
# A list of non simple headers the client is allowed to use with cross-domain requests
cors_allowed_headers = "{{ .RPC.CORSAllowedHeaders }}"
# TCP or UNIX socket address for the gRPC server to listen on
# NOTE: This server only supports /broadcast_tx_commit
grpc_laddr = "{{ .RPC.GRPCListenAddress }}"

View File

@@ -183,11 +183,7 @@ func (conR *ConsensusReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
return
}
// TODO
// ps, ok := peer.Get(PeerStateKey).(*PeerState)
// if !ok {
// panic(fmt.Sprintf("Peer %v has no state", peer))
// }
// ps.Disconnect()
//peer.Get(PeerStateKey).(*PeerState).Disconnect()
}
// Receive implements Reactor
@@ -218,10 +214,7 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
conR.Logger.Debug("Receive", "src", src, "chId", chID, "msg", msg)
// Get peer states
ps, ok := src.Get(types.PeerStateKey).(*PeerState)
if !ok {
panic(fmt.Sprintf("Peer %v has no state", src))
}
ps := src.Get(types.PeerStateKey).(*PeerState)
switch chID {
case StateChannel:
@@ -300,9 +293,9 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
switch msg := msg.(type) {
case *VoteMessage:
cs := conR.conS
cs.mtx.RLock()
cs.mtx.Lock()
height, valSize, lastCommitSize := cs.Height, cs.Validators.Size(), cs.LastCommit.Size()
cs.mtx.RUnlock()
cs.mtx.Unlock()
ps.EnsureVoteBitArrays(height, valSize)
ps.EnsureVoteBitArrays(height-1, lastCommitSize)
ps.SetHasVote(msg.Vote)
@@ -435,10 +428,7 @@ func (conR *ConsensusReactor) broadcastHasVoteMessage(vote *types.Vote) {
/*
// TODO: Make this broadcast more selective.
for _, peer := range conR.Switch.Peers().List() {
ps, ok := peer.Get(PeerStateKey).(*PeerState)
if !ok {
panic(fmt.Sprintf("Peer %v has no state", peer))
}
ps := peer.Get(PeerStateKey).(*PeerState)
prs := ps.GetRoundState()
if prs.Height == vote.Height {
// TODO: Also filter on round?
@@ -836,10 +826,7 @@ func (conR *ConsensusReactor) peerStatsRoutine() {
continue
}
// Get peer state
ps, ok := peer.Get(types.PeerStateKey).(*PeerState)
if !ok {
panic(fmt.Sprintf("Peer %v has no state", peer))
}
ps := peer.Get(types.PeerStateKey).(*PeerState)
switch msg.Msg.(type) {
case *VoteMessage:
if numVotes := ps.RecordVote(); numVotes%votesToContributeToBecomeGoodPeer == 0 {
@@ -872,10 +859,7 @@ func (conR *ConsensusReactor) StringIndented(indent string) string {
s := "ConsensusReactor{\n"
s += indent + " " + conR.conS.StringIndented(indent+" ") + "\n"
for _, peer := range conR.Switch.Peers().List() {
ps, ok := peer.Get(types.PeerStateKey).(*PeerState)
if !ok {
panic(fmt.Sprintf("Peer %v has no state", peer))
}
ps := peer.Get(types.PeerStateKey).(*PeerState)
s += indent + " " + ps.StringIndented(indent+" ") + "\n"
}
s += indent + "}"
@@ -1033,11 +1017,7 @@ func (ps *PeerState) PickSendVote(votes types.VoteSetReader) bool {
if vote, ok := ps.PickVoteToSend(votes); ok {
msg := &VoteMessage{vote}
ps.logger.Debug("Sending vote message", "ps", ps, "vote", vote)
if ps.peer.Send(VoteChannel, cdc.MustMarshalBinaryBare(msg)) {
ps.SetHasVote(vote)
return true
}
return false
return ps.peer.Send(VoteChannel, cdc.MustMarshalBinaryBare(msg))
}
return false
}
@@ -1066,6 +1046,7 @@ func (ps *PeerState) PickVoteToSend(votes types.VoteSetReader) (vote *types.Vote
return nil, false // Not something worth sending
}
if index, ok := votes.BitArray().Sub(psVotes).PickRandom(); ok {
ps.setHasVote(height, round, type_, index)
return votes.GetByIndex(index), true
}
return nil, false

View File

@@ -58,18 +58,7 @@ func (cs *ConsensusState) ReplayFile(file string, console bool) error {
if err != nil {
return errors.Errorf("failed to subscribe %s to %v", subscriber, types.EventQueryNewRoundStep)
}
defer func() {
// drain newStepCh to make sure we don't block
LOOP:
for {
select {
case <-newStepCh:
default:
break LOOP
}
}
cs.eventBus.Unsubscribe(ctx, subscriber, types.EventQueryNewRoundStep)
}()
defer cs.eventBus.Unsubscribe(ctx, subscriber, types.EventQueryNewRoundStep)
// just open the file for reading, no need to use wal
fp, err := os.OpenFile(file, os.O_RDONLY, 0600)
@@ -232,18 +221,7 @@ func (pb *playback) replayConsoleLoop() int {
if err != nil {
cmn.Exit(fmt.Sprintf("failed to subscribe %s to %v", subscriber, types.EventQueryNewRoundStep))
}
defer func() {
// drain newStepCh to make sure we don't block
LOOP:
for {
select {
case <-newStepCh:
default:
break LOOP
}
}
pb.cs.eventBus.Unsubscribe(ctx, subscriber, types.EventQueryNewRoundStep)
}()
defer pb.cs.eventBus.Unsubscribe(ctx, subscriber, types.EventQueryNewRoundStep)
if len(tokens) == 1 {
if err := pb.replayReset(1, newStepCh); err != nil {

View File

@@ -207,16 +207,18 @@ func (cs *ConsensusState) GetState() sm.State {
// GetLastHeight returns the last height committed.
// If there were no blocks, returns 0.
func (cs *ConsensusState) GetLastHeight() int64 {
cs.mtx.RLock()
defer cs.mtx.RUnlock()
cs.mtx.Lock()
defer cs.mtx.Unlock()
return cs.RoundState.Height - 1
}
// GetRoundState returns a shallow copy of the internal consensus state.
func (cs *ConsensusState) GetRoundState() *cstypes.RoundState {
cs.mtx.RLock()
defer cs.mtx.RUnlock()
rs := cs.RoundState // copy
cs.mtx.RUnlock()
return &rs
}
@@ -224,6 +226,7 @@ func (cs *ConsensusState) GetRoundState() *cstypes.RoundState {
func (cs *ConsensusState) GetRoundStateJSON() ([]byte, error) {
cs.mtx.RLock()
defer cs.mtx.RUnlock()
return cdc.MarshalJSON(cs.RoundState)
}
@@ -231,6 +234,7 @@ func (cs *ConsensusState) GetRoundStateJSON() ([]byte, error) {
func (cs *ConsensusState) GetRoundStateSimpleJSON() ([]byte, error) {
cs.mtx.RLock()
defer cs.mtx.RUnlock()
return cdc.MarshalJSON(cs.RoundState.RoundStateSimple())
}
@@ -244,15 +248,15 @@ func (cs *ConsensusState) GetValidators() (int64, []*types.Validator) {
// SetPrivValidator sets the private validator account for signing votes.
func (cs *ConsensusState) SetPrivValidator(priv types.PrivValidator) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
cs.privValidator = priv
cs.mtx.Unlock()
}
// SetTimeoutTicker sets the local timer. It may be useful to overwrite for testing.
func (cs *ConsensusState) SetTimeoutTicker(timeoutTicker TimeoutTicker) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
cs.timeoutTicker = timeoutTicker
cs.mtx.Unlock()
}
// LoadCommit loads the commit for a given height.

View File

@@ -13,7 +13,6 @@ import (
amino "github.com/tendermint/go-amino"
auto "github.com/tendermint/tendermint/libs/autofile"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
)
@@ -96,11 +95,6 @@ func (wal *baseWAL) Group() *auto.Group {
return wal.group
}
func (wal *baseWAL) SetLogger(l log.Logger) {
wal.BaseService.Logger = l
wal.group.SetLogger(l)
}
func (wal *baseWAL) OnStart() error {
size, err := wal.group.Head.Size()
if err != nil {

View File

@@ -47,6 +47,90 @@ The mempool and consensus logic act as clients, and each maintains an
open ABCI connection with the application, which hosts an ABCI server.
Shown are the request and response types sent on each connection.
## Message Protocol
The message protocol consists of pairs of requests and responses. Some
messages have no fields, while others may include byte-arrays, strings,
or integers. See the `message Request` and `message Response`
definitions in [the protobuf definition
file](https://github.com/tendermint/tendermint/blob/develop/abci/types/types.proto),
and the [protobuf
documentation](https://developers.google.com/protocol-buffers/docs/overview)
for more details.
For each request, a server should respond with the corresponding
response, where order of requests is preserved in the order of
responses.
## Server
To use ABCI in your programming language of choice, there must be a ABCI
server in that language. Tendermint supports two kinds of implementation
of the server:
- Asynchronous, raw socket server (Tendermint Socket Protocol, also
known as TSP or Teaspoon)
- GRPC
Both can be tested using the `abci-cli` by setting the `--abci` flag
appropriately (ie. to `socket` or `grpc`).
See examples, in various stages of maintenance, in
[Go](https://github.com/tendermint/tendermint/tree/develop/abci/server),
[JavaScript](https://github.com/tendermint/js-abci),
[Python](https://github.com/tendermint/tendermint/tree/develop/abci/example/python3/abci),
[C++](https://github.com/mdyring/cpp-tmsp), and
[Java](https://github.com/jTendermint/jabci).
### GRPC
If GRPC is available in your language, this is the easiest approach,
though it will have significant performance overhead.
To get started with GRPC, copy in the [protobuf
file](https://github.com/tendermint/tendermint/blob/develop/abci/types/types.proto)
and compile it using the GRPC plugin for your language. For instance,
for golang, the command is `protoc --go_out=plugins=grpc:. types.proto`.
See the [grpc documentation for more details](http://www.grpc.io/docs/).
`protoc` will autogenerate all the necessary code for ABCI client and
server in your language, including whatever interface your application
must satisfy to be used by the ABCI server for handling requests.
### TSP
If GRPC is not available in your language, or you require higher
performance, or otherwise enjoy programming, you may implement your own
ABCI server using the Tendermint Socket Protocol, known affectionately
as Teaspoon. The first step is still to auto-generate the relevant data
types and codec in your language using `protoc`. Messages coming over
the socket are proto3 encoded, but additionally length-prefixed to
facilitate use as a streaming protocol. proto3 doesn't have an
official length-prefix standard, so we use our own. The first byte in
the prefix represents the length of the Big Endian encoded length. The
remaining bytes in the prefix are the Big Endian encoded length.
For example, if the proto3 encoded ABCI message is 0xDEADBEEF (4
bytes), the length-prefixed message is 0x0104DEADBEEF. If the proto3
encoded ABCI message is 65535 bytes long, the length-prefixed message
would be like 0x02FFFF....
Note this prefixing does not apply for grpc.
An ABCI server must also be able to support multiple connections, as
Tendermint uses three connections.
## Client
There are currently two use-cases for an ABCI client. One is a testing
tool, as in the `abci-cli`, which allows ABCI requests to be sent via
command line. The other is a consensus engine, such as Tendermint Core,
which makes requests to the application every time a new transaction is
received or a block is committed.
It is unlikely that you will need to implement a client. For details of
our client, see
[here](https://github.com/tendermint/tendermint/tree/develop/abci/client).
Most of the examples below are from [kvstore
application](https://github.com/tendermint/tendermint/blob/develop/abci/example/kvstore/kvstore.go),
which is a part of the abci repo. [persistent_kvstore

View File

@@ -175,5 +175,35 @@
"language": "Javascript",
"author": "Dennis McKinnon"
}
],
"deploymentTools": [
{
"name": "mintnet-kubernetes",
"url": "https://github.com/tendermint/tools",
"technology": "Docker and Kubernetes",
"author": "Tendermint",
"description": "Deploy a Tendermint test network using Google's kubernetes"
},
{
"name": "terraforce",
"url": "https://github.com/tendermint/tools",
"technology": "Terraform",
"author": "Tendermint",
"description": "Terraform + our custom terraforce tool; deploy a production Tendermint network with load balancing over multiple AWS availability zones"
},
{
"name": "ansible-tendermint",
"url": "https://github.com/tendermint/tools",
"technology": "Ansible",
"author": "Tendermint",
"description": "Ansible playbooks + Tendermint"
},
{
"name": "brooklyn-tendermint",
"url": "https://github.com/cloudsoft/brooklyn-tendermint",
"technology": "Clocker for Apache Brooklyn ",
"author": "Cloudsoft",
"description": "Deploy a tendermint test network in docker containers "
}
]
}

View File

@@ -9,3 +9,13 @@ We thank the community for their contributions thus far and welcome the
addition of new projects. A pull request can be submitted to [this
file](https://github.com/tendermint/tendermint/blob/master/docs/app-dev/ecosystem.json)
to include your project.
## Other Tools
See [deploy testnets](./deploy-testnets) for information about all
the tools built by Tendermint. We have Kubernetes, Ansible, and
Terraform integrations.
For upgrading from older to newer versions of tendermint and to migrate
your chain data, see [tm-migrator](https://github.com/hxzqlh/tm-tools)
written by @hxzqlh.

View File

@@ -1,72 +0,0 @@
# ADR 034: PrivValidator file structure
## Changelog
03-11-2018: Initial Draft
## Context
For now, the PrivValidator file `priv_validator.json` contains mutable and immutable parts.
Even in an insecure mode which does not encrypt private key on disk, it is reasonable to separate
the mutable part and immutable part.
References:
[#1181](https://github.com/tendermint/tendermint/issues/1181)
[#2657](https://github.com/tendermint/tendermint/issues/2657)
[#2313](https://github.com/tendermint/tendermint/issues/2313)
## Proposed Solution
We can split mutable and immutable parts with two structs:
```go
// FilePVKey stores the immutable part of PrivValidator
type FilePVKey struct {
Address types.Address `json:"address"`
PubKey crypto.PubKey `json:"pub_key"`
PrivKey crypto.PrivKey `json:"priv_key"`
filePath string
}
// FilePVState 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
mtx sync.Mutex
}
```
Then we can combine `FilePVKey` with `FilePVLastSignState` and will get the original `FilePV`.
```go
type FilePV struct {
Key FilePVKey
LastSignState FilePVLastSignState
}
```
As discussed, `FilePV` should be located in `config`, and `FilePVLastSignState` should be stored in `data`. The
store path of each file should be specified in `config.yml`.
What we need to do next is changing the methods of `FilePV`.
## Status
Draft.
## Consequences
### Positive
- separate the mutable and immutable of PrivValidator
### Negative
- need to add more config for file path
### Neutral

View File

@@ -3,8 +3,12 @@
This section is for those looking to implement their own ABCI Server, perhaps in
a new programming language.
You are expected to have read [ABCI Methods and Types](./abci.md) and [ABCI
Applications](./apps.md).
You are expected to have read [ABCI Methods and Types](abci.md) and [ABCI
Applications](apps.md).
See additional details in the [ABCI
readme](https://github.com/tendermint/tendermint/blob/develop/abci/README.md)(TODO: deduplicate
those details).
## Message Protocol
@@ -20,16 +24,17 @@ For each request, a server should respond with the corresponding
response, where the order of requests is preserved in the order of
responses.
## Server Implementations
## Server
To use ABCI in your programming language of choice, there must be a ABCI
server in that language. Tendermint supports three implementations of the ABCI, written in Go:
server in that language. Tendermint supports two kinds of implementation
of the server:
- In-process (Golang only)
- ABCI-socket
- Asynchronous, raw socket server (Tendermint Socket Protocol, also
known as TSP or Teaspoon)
- GRPC
The latter two can be tested using the `abci-cli` by setting the `--abci` flag
Both can be tested using the `abci-cli` by setting the `--abci` flag
appropriately (ie. to `socket` or `grpc`).
See examples, in various stages of maintenance, in
@@ -39,12 +44,6 @@ See examples, in various stages of maintenance, in
[C++](https://github.com/mdyring/cpp-tmsp), and
[Java](https://github.com/jTendermint/jabci).
### In Process
The simplest implementation uses function calls within Golang.
This means ABCI applications written in Golang can be compiled with TendermintCore and run as a single binary.
### GRPC
If GRPC is available in your language, this is the easiest approach,
@@ -59,18 +58,15 @@ See the [grpc documentation for more details](http://www.grpc.io/docs/).
server in your language, including whatever interface your application
must satisfy to be used by the ABCI server for handling requests.
Note the length-prefixing used in the socket implementation (TSP) does not apply for GRPC.
### TSP
Tendermint Socket Protocol is an asynchronous, raw socket server which provides ordered message passing over unix or tcp.
Messages are serialized using Protobuf3 and length-prefixed with a [signed Varint](https://developers.google.com/protocol-buffers/docs/encoding?csw=1#signed-integers)
If GRPC is not available in your language, or you require higher
performance, or otherwise enjoy programming, you may implement your own
ABCI server using the Tendermint Socket Protocol. The first step is still to auto-generate the relevant data
types and codec in your language using `protoc`. In addition to being proto3 encoded, messages coming over
the socket are length-prefixed to facilitate use as a streaming protocol. proto3 doesn't have an
ABCI server using the Tendermint Socket Protocol, known affectionately
as Teaspoon. The first step is still to auto-generate the relevant data
types and codec in your language using `protoc`. Messages coming over
the socket are proto3 encoded, but additionally length-prefixed to
facilitate use as a streaming protocol. proto3 doesn't have an
official length-prefix standard, so we use our own. The first byte in
the prefix represents the length of the Big Endian encoded length. The
remaining bytes in the prefix are the Big Endian encoded length.
@@ -80,14 +76,12 @@ bytes), the length-prefixed message is 0x0104DEADBEEF. If the proto3
encoded ABCI message is 65535 bytes long, the length-prefixed message
would be like 0x02FFFF....
The benefit of using this `varint` encoding over the old version (where integers were encoded as `<len of len><big endian len>` is that
it is the standard way to encode integers in Protobuf. It is also generally shorter.
As noted above, this prefixing does not apply for GRPC.
Note this prefixing does not apply for grpc.
An ABCI server must also be able to support multiple connections, as
Tendermint uses three connections.
### Async vs Sync
The main ABCI server (ie. non-GRPC) provides ordered asynchronous messages.

View File

@@ -68,17 +68,6 @@ filter_peers = false
# TCP or UNIX socket address for the RPC server to listen on
laddr = "tcp://0.0.0.0:26657"
# A list of origins a cross-domain request can be executed from
# Default value '[]' disables cors support
# Use '["*"]' to allow any origin
cors_allowed_origins = "[]"
# A list of methods the client is allowed to use with cross-domain requests
cors_allowed_methods = "[HEAD GET POST]"
# A list of non simple headers the client is allowed to use with cross-domain requests
cors_allowed_headers = "[Origin Accept Content-Type X-Requested-With X-Server-Time]"
# TCP or UNIX socket address for the gRPC server to listen on
# NOTE: This server only supports /broadcast_tx_commit
grpc_laddr = ""

View File

@@ -60,34 +60,42 @@ definition](https://github.com/tendermint/tendermint/blob/master/types/genesis.g
```
{
"genesis_time": "2018-11-13T18:11:50.277637Z",
"chain_id": "test-chain-s4ui7D",
"consensus_params": {
"block_size": {
"max_bytes": "22020096",
"max_gas": "-1"
},
"evidence": {
"max_age": "100000"
},
"validator": {
"pub_key_types": [
"ed25519"
]
}
},
"genesis_time": "2018-07-09T22:43:06.255718641Z",
"chain_id": "chain-IAkWsK",
"validators": [
{
"address": "39C04A480B54AB258A45355A5E48ADDED9956C65",
"pub_key": {
"type": "tendermint/PubKeyEd25519",
"value": "DMEMMj1+thrkUCGocbvvKzXeaAtRslvX9MWtB+smuIA="
"value": "oX8HhKsErMluxI0QWNSR8djQMSupDvHdAYrHwP7n73k="
},
"power": "10",
"name": ""
"power": "1",
"name": "node0"
},
{
"pub_key": {
"type": "tendermint/PubKeyEd25519",
"value": "UZNSJA9zmeFQj36Rs296lY+WFQ4Rt6s7snPpuKypl5I="
},
"power": "1",
"name": "node1"
},
{
"pub_key": {
"type": "tendermint/PubKeyEd25519",
"value": "i9GrM6/MHB4zjCelMZBUYHNXYIzl4n0RkDCVmmLhS/o="
},
"power": "1",
"name": "node2"
},
{
"pub_key": {
"type": "tendermint/PubKeyEd25519",
"value": "0qq7954l87trEqbQV9c7d1gurnjTGMxreXc848ZZ5aw="
},
"power": "1",
"name": "node3"
}
],
"app_hash": ""
]
}
```

View File

@@ -160,15 +160,12 @@ func (evR *EvidenceReactor) broadcastEvidenceRoutine(peer p2p.Peer) {
// Returns the message to send the peer, or nil if the evidence is invalid for the peer.
// If message is nil, return true if we should sleep and try again.
func (evR EvidenceReactor) checkSendEvidenceMessage(peer p2p.Peer, ev types.Evidence) (msg EvidenceMessage, retry bool) {
// make sure the peer is up to date
evHeight := ev.Height()
peerState, ok := peer.Get(types.PeerStateKey).(PeerState)
if !ok {
// Peer does not have a state yet. We set it in the consensus reactor, but
// when we add peer in Switch, the order we call reactors#AddPeer is
// different every time due to us using a map. Sometimes other reactors
// will be initialized before the consensus reactor. We should wait a few
// milliseconds and retry.
if !ok {
evR.Logger.Info("Found peer without PeerState", "peer", peer)
return nil, true
}

View File

@@ -10,7 +10,6 @@ import (
"github.com/stretchr/testify/assert"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto/secp256k1"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/p2p"
@@ -165,16 +164,6 @@ func TestReactorSelectiveBroadcast(t *testing.T) {
// make reactors from statedb
reactors := makeAndConnectEvidenceReactors(config, []dbm.DB{stateDB1, stateDB2})
// set the peer height on each reactor
for _, r := range reactors {
for _, peer := range r.Switch.Peers().List() {
ps := peerState{height1}
peer.Set(types.PeerStateKey, ps)
}
}
// update the first reactor peer's height to be very small
peer := reactors[0].Switch.Peers().List()[0]
ps := peerState{height2}
peer.Set(types.PeerStateKey, ps)
@@ -189,30 +178,3 @@ func TestReactorSelectiveBroadcast(t *testing.T) {
peers := reactors[1].Switch.Peers().List()
assert.Equal(t, 1, len(peers))
}
func TestEvidenceListMessageValidationBasic(t *testing.T) {
testCases := []struct {
testName string
malleateEvListMsg func(*EvidenceListMessage)
expectErr bool
}{
{"Good EvidenceListMessage", func(evList *EvidenceListMessage) {}, false},
{"Invalid EvidenceListMessage", func(evList *EvidenceListMessage) {
evList.Evidence = append(evList.Evidence,
&types.DuplicateVoteEvidence{PubKey: secp256k1.GenPrivKey().PubKey()})
}, true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
evListMsg := &EvidenceListMessage{}
n := 3
valAddr := []byte("myval")
evListMsg.Evidence = make([]types.Evidence, n)
for i := 0; i < n; i++ {
evListMsg.Evidence[i] = types.NewMockGoodEvidence(int64(i+1), 0, valAddr)
}
tc.malleateEvListMsg(evListMsg)
assert.Equal(t, tc.expectErr, evListMsg.ValidateBasic() != nil, "Validate Basic had an unexpected result")
})
}
}

View File

@@ -83,8 +83,6 @@ func OpenAutoFile(path string) (*AutoFile, error) {
return af, nil
}
// Close shuts down the closing goroutine, SIGHUP handler and closes the
// AutoFile.
func (af *AutoFile) Close() error {
af.closeTicker.Stop()
close(af.closeTickerStopc)
@@ -118,10 +116,6 @@ func (af *AutoFile) closeFile() (err error) {
return file.Close()
}
// Write writes len(b) bytes to the AutoFile. It returns the number of bytes
// written and an error, if any. Write returns a non-nil error when n !=
// len(b).
// Opens AutoFile if needed.
func (af *AutoFile) Write(b []byte) (n int, err error) {
af.mtx.Lock()
defer af.mtx.Unlock()
@@ -136,10 +130,6 @@ func (af *AutoFile) Write(b []byte) (n int, err error) {
return
}
// Sync commits the current contents of the file to stable storage. Typically,
// this means flushing the file system's in-memory copy of recently written
// data to disk.
// Opens AutoFile if needed.
func (af *AutoFile) Sync() error {
af.mtx.Lock()
defer af.mtx.Unlock()
@@ -168,22 +158,23 @@ func (af *AutoFile) openFile() error {
return nil
}
// Size returns the size of the AutoFile. It returns -1 and an error if fails
// get stats or open file.
// Opens AutoFile if needed.
func (af *AutoFile) Size() (int64, error) {
af.mtx.Lock()
defer af.mtx.Unlock()
if af.file == nil {
if err := af.openFile(); err != nil {
err := af.openFile()
if err != nil {
if err == os.ErrNotExist {
return 0, nil
}
return -1, err
}
}
stat, err := af.file.Stat()
if err != nil {
return -1, err
}
return stat.Size(), nil
}

View File

@@ -84,40 +84,3 @@ func TestOpenAutoFilePerms(t *testing.T) {
t.Errorf("unexpected error %v", e)
}
}
func TestAutoFileSize(t *testing.T) {
// First, create an AutoFile writing to a tempfile dir
f, err := ioutil.TempFile("", "sighup_test")
require.NoError(t, err)
err = f.Close()
require.NoError(t, err)
// Here is the actual AutoFile.
af, err := OpenAutoFile(f.Name())
require.NoError(t, err)
// 1. Empty file
size, err := af.Size()
require.Zero(t, size)
require.NoError(t, err)
// 2. Not empty file
data := []byte("Maniac\n")
_, err = af.Write(data)
require.NoError(t, err)
size, err = af.Size()
require.EqualValues(t, len(data), size)
require.NoError(t, err)
// 3. Not existing file
err = af.Close()
require.NoError(t, err)
err = os.Remove(f.Name())
require.NoError(t, err)
size, err = af.Size()
require.EqualValues(t, 0, size, "Expected a new file to be empty")
require.NoError(t, err)
// Cleanup
_ = os.Remove(f.Name())
}

View File

@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"io"
"log"
"os"
"path"
"path/filepath"
@@ -230,8 +231,7 @@ func (g *Group) checkHeadSizeLimit() {
}
size, err := g.Head.Size()
if err != nil {
g.Logger.Error("Group's head may grow without bound", "head", g.Head.Path, "err", err)
return
panic(err)
}
if size >= limit {
g.RotateFile()
@@ -253,21 +253,21 @@ func (g *Group) checkTotalSizeLimit() {
}
if index == gInfo.MaxIndex {
// Special degenerate case, just do nothing.
g.Logger.Error("Group's head may grow without bound", "head", g.Head.Path)
log.Println("WARNING: Group's head " + g.Head.Path + "may grow without bound")
return
}
pathToRemove := filePathForIndex(g.Head.Path, index, gInfo.MaxIndex)
fInfo, err := os.Stat(pathToRemove)
fileInfo, err := os.Stat(pathToRemove)
if err != nil {
g.Logger.Error("Failed to fetch info for file", "file", pathToRemove)
log.Println("WARNING: Failed to fetch info for file @" + pathToRemove)
continue
}
err = os.Remove(pathToRemove)
if err != nil {
g.Logger.Error("Failed to remove path", "path", pathToRemove)
log.Println(err)
return
}
totalSize -= fInfo.Size()
totalSize -= fileInfo.Size()
}
}

View File

@@ -30,15 +30,9 @@
//
// s.Subscribe(ctx, sub, qry, out)
// defer func() {
// // drain out to make sure we don't block
// LOOP:
// for {
// select {
// case <-out:
// default:
// break LOOP
// }
// }
// for range out {
// // drain out to make sure we don't block
// }
// s.UnsubscribeAll(ctx, sub)
// }()
// for msg := range out {

View File

@@ -11,6 +11,7 @@ import (
"github.com/pkg/errors"
amino "github.com/tendermint/go-amino"
abci "github.com/tendermint/tendermint/abci/types"
cfg "github.com/tendermint/tendermint/config"
auto "github.com/tendermint/tendermint/libs/autofile"
@@ -87,12 +88,8 @@ func IsPreCheckError(err error) bool {
func PreCheckAminoMaxBytes(maxBytes int64) PreCheckFunc {
return func(tx types.Tx) error {
// We have to account for the amino overhead in the tx size as well
// NOTE: fieldNum = 1 as types.Block.Data contains Txs []Tx as first field.
// If this field order ever changes this needs to updated here accordingly.
// NOTE: if some []Tx are encoded without a parenting struct, the
// fieldNum is also equal to 1.
aminoOverhead := types.ComputeAminoOverhead(tx, 1)
txSize := int64(len(tx)) + aminoOverhead
aminoOverhead := amino.UvarintSize(uint64(len(tx)))
txSize := int64(len(tx) + aminoOverhead)
if txSize > maxBytes {
return fmt.Errorf("Tx size (including amino overhead) is too big: %d, max: %d",
txSize, maxBytes)
@@ -300,7 +297,6 @@ func (mem *Mempool) TxsWaitChan() <-chan struct{} {
// CONTRACT: Either cb will get called, or err returned.
func (mem *Mempool) CheckTx(tx types.Tx, cb func(*abci.Response)) (err error) {
mem.proxyMtx.Lock()
// use defer to unlock mutex because application (*local client*) might panic
defer mem.proxyMtx.Unlock()
if mem.Size() >= mem.config.Size {
@@ -486,7 +482,7 @@ func (mem *Mempool) ReapMaxBytesMaxGas(maxBytes, maxGas int64) types.Txs {
for e := mem.txs.Front(); e != nil; e = e.Next() {
memTx := e.Value.(*mempoolTx)
// Check total size requirement
aminoOverhead := types.ComputeAminoOverhead(memTx.tx, 1)
aminoOverhead := int64(amino.UvarintSize(uint64(len(memTx.tx))))
if maxBytes > -1 && totalBytes+int64(len(memTx.tx))+aminoOverhead > maxBytes {
return txs
}

View File

@@ -107,11 +107,11 @@ func TestReapMaxBytesMaxGas(t *testing.T) {
{20, 0, -1, 0},
{20, 0, 10, 0},
{20, 10, 10, 0},
{20, 22, 10, 1},
{20, 220, -1, 10},
{20, 220, 5, 5},
{20, 220, 10, 10},
{20, 220, 15, 10},
{20, 21, 10, 1},
{20, 210, -1, 10},
{20, 210, 5, 5},
{20, 210, 10, 10},
{20, 210, 15, 10},
{20, 20000, -1, 20},
{20, 20000, 5, 5},
{20, 20000, 30, 20},
@@ -145,15 +145,15 @@ func TestMempoolFilters(t *testing.T) {
{10, nopPreFilter, nopPostFilter, 10},
{10, PreCheckAminoMaxBytes(10), nopPostFilter, 0},
{10, PreCheckAminoMaxBytes(20), nopPostFilter, 0},
{10, PreCheckAminoMaxBytes(22), nopPostFilter, 10},
{10, PreCheckAminoMaxBytes(21), nopPostFilter, 10},
{10, nopPreFilter, PostCheckMaxGas(-1), 10},
{10, nopPreFilter, PostCheckMaxGas(0), 0},
{10, nopPreFilter, PostCheckMaxGas(1), 10},
{10, nopPreFilter, PostCheckMaxGas(3000), 10},
{10, PreCheckAminoMaxBytes(10), PostCheckMaxGas(20), 0},
{10, PreCheckAminoMaxBytes(30), PostCheckMaxGas(20), 10},
{10, PreCheckAminoMaxBytes(22), PostCheckMaxGas(1), 10},
{10, PreCheckAminoMaxBytes(22), PostCheckMaxGas(0), 0},
{10, PreCheckAminoMaxBytes(21), PostCheckMaxGas(1), 10},
{10, PreCheckAminoMaxBytes(21), PostCheckMaxGas(0), 0},
}
for tcIndex, tt := range tests {
mempool.Update(1, emptyTxArr, tt.preFilter, tt.postFilter)

View File

@@ -133,23 +133,16 @@ func (memR *MempoolReactor) broadcastTxRoutine(peer p2p.Peer) {
}
memTx := next.Value.(*mempoolTx)
// make sure the peer is up to date
peerState, ok := peer.Get(types.PeerStateKey).(PeerState)
if !ok {
// Peer does not have a state yet. We set it in the consensus reactor, but
// when we add peer in Switch, the order we call reactors#AddPeer is
// different every time due to us using a map. Sometimes other reactors
// will be initialized before the consensus reactor. We should wait a few
// milliseconds and retry.
time.Sleep(peerCatchupSleepIntervalMS * time.Millisecond)
continue
height := memTx.Height()
if peerState_i := peer.Get(types.PeerStateKey); peerState_i != nil {
peerState := peerState_i.(PeerState)
peerHeight := peerState.GetHeight()
if peerHeight < height-1 { // Allow for a lag of 1 block
time.Sleep(peerCatchupSleepIntervalMS * time.Millisecond)
continue
}
}
if peerState.GetHeight() < memTx.Height()-1 { // Allow for a lag of 1 block
time.Sleep(peerCatchupSleepIntervalMS * time.Millisecond)
continue
}
// send memTx
msg := &TxMessage{Tx: memTx.tx}
success := peer.Send(MempoolChannel, cdc.MustMarshalBinaryBare(msg))

View File

@@ -21,14 +21,6 @@ import (
"github.com/tendermint/tendermint/types"
)
type peerState struct {
height int64
}
func (ps peerState) GetHeight() int64 {
return ps.height
}
// mempoolLogger is a TestingLogger which uses a different
// color for each validator ("validator" key must exist).
func mempoolLogger() log.Logger {
@@ -115,11 +107,6 @@ func TestReactorBroadcastTxMessage(t *testing.T) {
r.Stop()
}
}()
for _, r := range reactors {
for _, peer := range r.Switch.Peers().List() {
peer.Set(types.PeerStateKey, peerState{1})
}
}
// send a bunch of txs to the first reactor's mempool
// and wait for them all to be received in the others

View File

@@ -13,9 +13,8 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/rs/cors"
"github.com/tendermint/go-amino"
amino "github.com/tendermint/go-amino"
abci "github.com/tendermint/tendermint/abci/types"
bc "github.com/tendermint/tendermint/blockchain"
cfg "github.com/tendermint/tendermint/config"
@@ -266,8 +265,17 @@ func NewNode(config *cfg.Config,
proxyApp.Mempool(),
state.LastBlockHeight,
mempl.WithMetrics(memplMetrics),
mempl.WithPreCheck(sm.TxPreCheck(state)),
mempl.WithPostCheck(sm.TxPostCheck(state)),
mempl.WithPreCheck(
mempl.PreCheckAminoMaxBytes(
types.MaxDataBytesUnknownEvidence(
state.ConsensusParams.BlockSize.MaxBytes,
state.Validators.Size(),
),
),
),
mempl.WithPostCheck(
mempl.PostCheckMaxGas(state.ConsensusParams.BlockSize.MaxGas),
),
)
mempoolLogger := logger.With("module", "mempool")
mempool.SetLogger(mempoolLogger)
@@ -652,20 +660,9 @@ func (n *Node) startRPC() ([]net.Listener, error) {
wm.SetLogger(rpcLogger.With("protocol", "websocket"))
mux.HandleFunc("/websocket", wm.WebsocketHandler)
rpcserver.RegisterRPCFuncs(mux, rpccore.Routes, coreCodec, rpcLogger)
var rootHandler http.Handler = mux
if n.config.RPC.IsCorsEnabled() {
corsMiddleware := cors.New(cors.Options{
AllowedOrigins: n.config.RPC.CORSAllowedOrigins,
AllowedMethods: n.config.RPC.CORSAllowedMethods,
AllowedHeaders: n.config.RPC.CORSAllowedHeaders,
})
rootHandler = corsMiddleware.Handler(mux)
}
listener, err := rpcserver.StartHTTPServer(
listenAddr,
rootHandler,
mux,
rpcLogger,
rpcserver.Config{MaxOpenConnections: n.config.RPC.MaxOpenConnections},
)

View File

@@ -32,10 +32,8 @@ type NetAddress struct {
str string
}
// IDAddressString returns id@hostPort. It strips the leading
// protocol from protocolHostPort if it exists.
func IDAddressString(id ID, protocolHostPort string) string {
hostPort := removeProtocolIfDefined(protocolHostPort)
// IDAddressString returns id@hostPort.
func IDAddressString(id ID, hostPort string) string {
return fmt.Sprintf("%s@%s", id, hostPort)
}

View File

@@ -216,8 +216,7 @@ OUTER_LOOP:
// ListenAddr. Note that the ListenAddr is not authenticated and
// may not match that address actually dialed if its an outbound peer.
func (info DefaultNodeInfo) NetAddress() *NetAddress {
idAddr := IDAddressString(info.ID(), info.ListenAddr)
netAddr, err := NewNetAddressString(idAddr)
netAddr, err := NewNetAddressString(IDAddressString(info.ID(), info.ListenAddr))
if err != nil {
switch err.(type) {
case ErrNetAddressLookup:

View File

@@ -162,10 +162,10 @@ func (a *addrBook) FilePath() string {
// AddOurAddress one of our addresses.
func (a *addrBook) AddOurAddress(addr *p2p.NetAddress) {
a.Logger.Info("Add our address to book", "addr", addr)
a.mtx.Lock()
defer a.mtx.Unlock()
a.Logger.Info("Add our address to book", "addr", addr)
a.ourAddrs[addr.String()] = struct{}{}
a.mtx.Unlock()
}
// OurAddress returns true if it is our address.
@@ -178,10 +178,10 @@ func (a *addrBook) OurAddress(addr *p2p.NetAddress) bool {
func (a *addrBook) AddPrivateIDs(IDs []string) {
a.mtx.Lock()
defer a.mtx.Unlock()
for _, id := range IDs {
a.privateIDs[p2p.ID(id)] = struct{}{}
}
a.mtx.Unlock()
}
// AddAddress implements AddrBook
@@ -202,7 +202,7 @@ func (a *addrBook) RemoveAddress(addr *p2p.NetAddress) {
if ka == nil {
return
}
a.Logger.Info("Remove address from book", "addr", addr)
a.Logger.Info("Remove address from book", "addr", ka.Addr, "ID", ka.ID())
a.removeFromAllBuckets(ka)
}
@@ -217,8 +217,8 @@ func (a *addrBook) IsGood(addr *p2p.NetAddress) bool {
// HasAddress returns true if the address is in the book.
func (a *addrBook) HasAddress(addr *p2p.NetAddress) bool {
a.mtx.Lock()
defer a.mtx.Unlock()
ka := a.addrLookup[addr.ID]
a.mtx.Unlock()
return ka != nil
}
@@ -461,12 +461,13 @@ ADDRS_LOOP:
// ListOfKnownAddresses returns the new and old addresses.
func (a *addrBook) ListOfKnownAddresses() []*knownAddress {
addrs := []*knownAddress{}
a.mtx.Lock()
defer a.mtx.Unlock()
addrs := []*knownAddress{}
for _, addr := range a.addrLookup {
addrs = append(addrs, addr.copy())
}
a.mtx.Unlock()
return addrs
}

View File

@@ -221,11 +221,8 @@ func (r *PEXReactor) Receive(chID byte, src Peer, msgBytes []byte) {
// 2) limit the output size
if r.config.SeedMode {
r.SendAddrs(src, r.book.GetSelectionWithBias(biasToSelectNewPeers))
go func() {
// TODO Fix properly #2092
time.Sleep(time.Second * 5)
r.Switch.StopPeerGracefully(src)
}()
time.Sleep(time.Second * 3) // TODO Rethink this. Without it, above may not actually send.
r.Switch.StopPeerGracefully(src)
} else {
r.SendAddrs(src, r.book.GetSelection())
}

View File

@@ -328,11 +328,6 @@ func (sw *Switch) reconnectToPeer(addr *NetAddress) {
return
}
if sw.IsDialingOrExistingAddress(addr) {
sw.Logger.Debug("Peer connection has been established or dialed while we waiting next try", "addr", addr)
return
}
err := sw.DialPeerWithAddress(addr, true)
if err == nil {
return // success
@@ -420,15 +415,12 @@ func (sw *Switch) DialPeersAsync(addrBook AddrBook, peers []string, persistent b
if addr.Same(ourAddr) {
sw.Logger.Debug("Ignore attempt to connect to ourselves", "addr", addr, "ourAddr", ourAddr)
return
}
sw.randomSleep(0)
if sw.IsDialingOrExistingAddress(addr) {
} else if sw.IsDialingOrExistingAddress(addr) {
sw.Logger.Debug("Ignore attempt to connect to an existing peer", "addr", addr)
return
}
sw.randomSleep(0)
err := sw.DialPeerWithAddress(addr, persistent)
if err != nil {
switch err.(type) {
@@ -624,7 +616,7 @@ func (sw *Switch) addPeer(p Peer) error {
return err
}
p.SetLogger(sw.Logger.With("peer", p.NodeInfo().NetAddress()))
p.SetLogger(sw.Logger.With("peer", p.NodeInfo().NetAddress().String))
// All good. Start peer
if sw.IsRunning() {

View File

@@ -69,18 +69,7 @@ func WaitForOneEvent(c EventsClient, evtTyp string, timeout time.Duration) (type
}
// make sure to unregister after the test is over
defer func() {
// drain evts to make sure we don't block
LOOP:
for {
select {
case <-evts:
default:
break LOOP
}
}
c.UnsubscribeAll(ctx, subscriber)
}()
defer c.UnsubscribeAll(ctx, subscriber)
select {
case evt := <-evts:

View File

@@ -2,7 +2,6 @@ package client_test
import (
"fmt"
"net/http"
"strings"
"testing"
@@ -12,7 +11,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"
)
@@ -33,21 +32,6 @@ func GetClients() []client.Client {
}
}
func TestCorsEnabled(t *testing.T) {
origin := rpctest.GetConfig().RPC.CORSAllowedOrigins[0]
remote := strings.Replace(rpctest.GetConfig().RPC.ListenAddress, "tcp", "http", -1)
req, err := http.NewRequest("GET", remote, nil)
require.Nil(t, err, "%+v", err)
req.Header.Set("Origin", origin)
c := &http.Client{}
resp, err := c.Do(req)
defer resp.Body.Close()
require.Nil(t, err, "%+v", err)
assert.Equal(t, resp.Header.Get("Access-Control-Allow-Origin"), origin)
}
// Make sure status is correct (we connect properly)
func TestStatus(t *testing.T) {
for i, c := range GetClients() {

View File

@@ -193,10 +193,7 @@ func DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) {
peers := p2pPeers.Peers().List()
peerStates := make([]ctypes.PeerStateInfo, len(peers))
for i, peer := range peers {
peerState, ok := peer.Get(types.PeerStateKey).(*cm.PeerState)
if !ok { // peer does not have a state yet
continue
}
peerState := peer.Get(types.PeerStateKey).(*cm.PeerState)
peerStateJSON, err := peerState.ToJSON()
if err != nil {
return nil, err

View File

@@ -12,10 +12,7 @@ See it here: https://github.com/tendermint/tendermint/tree/master/rpc/lib
## Configuration
RPC can be configured by tuning parameters under `[rpc]` table in the `$TMHOME/config/config.toml` file or by using the `--rpc.X` command-line flags.
Default rpc listen address is `tcp://0.0.0.0:26657`. To set another address, set the `laddr` config parameter to desired value.
CORS (Cross-Origin Resource Sharing) can be enabled by setting `cors_allowed_origins`, `cors_allowed_methods`, `cors_allowed_headers` config parameters.
Set the `laddr` config parameter under `[rpc]` table in the `$TMHOME/config/config.toml` file or the `--rpc.laddr` command-line flag to the desired protocol://host:port setting. Default: `tcp://0.0.0.0:26657`.
## Arguments

View File

@@ -8,6 +8,7 @@ import (
"github.com/pkg/errors"
abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/types"
)
@@ -50,7 +51,7 @@ import (
func BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
err := mempool.CheckTx(tx, nil)
if err != nil {
return nil, err
return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
}
return &ctypes.ResultBroadcastTx{Hash: tx.Hash()}, nil
}
@@ -93,7 +94,7 @@ func BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
resCh <- res
})
if err != nil {
return nil, err
return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
}
res := <-resCh
r := res.GetCheckTx()
@@ -105,9 +106,8 @@ func BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
}, nil
}
// CONTRACT: only returns error if mempool.CheckTx() errs or if we timeout
// waiting for tx to commit.
//
// CONTRACT: only returns error if mempool.BroadcastTx errs (ie. problem with the app)
// or if we timeout waiting for tx to commit.
// If CheckTx or DeliverTx fail, no error will be returned, but the returned result
// will contain a non-OK ABCI code.
//
@@ -150,31 +150,20 @@ func BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
// |-----------+------+---------+----------+-----------------|
// | tx | Tx | nil | true | The transaction |
func BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
// Subscribe to tx being committed in block.
// subscribe to tx being committed in block
ctx, cancel := context.WithTimeout(context.Background(), subscribeTimeout)
defer cancel()
deliverTxResCh := make(chan interface{}, 1)
deliverTxResCh := make(chan interface{})
q := types.EventQueryTxFor(tx)
err := eventBus.Subscribe(ctx, "mempool", q, deliverTxResCh)
if err != nil {
err = errors.Wrap(err, "failed to subscribe to tx")
logger.Error("Error on broadcast_tx_commit", "err", err)
return nil, err
logger.Error("Error on broadcastTxCommit", "err", err)
return nil, fmt.Errorf("Error on broadcastTxCommit: %v", err)
}
defer func() {
// drain deliverTxResCh to make sure we don't block
LOOP:
for {
select {
case <-deliverTxResCh:
default:
break LOOP
}
}
eventBus.Unsubscribe(context.Background(), "mempool", q)
}()
defer eventBus.Unsubscribe(context.Background(), "mempool", q)
// Broadcast tx and wait for CheckTx result
// broadcast the tx and register checktx callback
checkTxResCh := make(chan *abci.Response, 1)
err = mempool.CheckTx(tx, func(res *abci.Response) {
checkTxResCh <- res
@@ -183,35 +172,40 @@ func BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
logger.Error("Error on broadcastTxCommit", "err", err)
return nil, fmt.Errorf("Error on broadcastTxCommit: %v", err)
}
checkTxResMsg := <-checkTxResCh
checkTxRes := checkTxResMsg.GetCheckTx()
if checkTxRes.Code != abci.CodeTypeOK {
checkTxRes := <-checkTxResCh
checkTxR := checkTxRes.GetCheckTx()
if checkTxR.Code != abci.CodeTypeOK {
// CheckTx failed!
return &ctypes.ResultBroadcastTxCommit{
CheckTx: *checkTxRes,
CheckTx: *checkTxR,
DeliverTx: abci.ResponseDeliverTx{},
Hash: tx.Hash(),
}, nil
}
// Wait for the tx to be included in a block or timeout.
var deliverTxTimeout = 10 * time.Second // TODO: configurable?
// Wait for the tx to be included in a block,
// timeout after something reasonable.
// TODO: configurable?
timer := time.NewTimer(60 * 2 * time.Second)
select {
case deliverTxResMsg := <-deliverTxResCh: // The tx was included in a block.
case deliverTxResMsg := <-deliverTxResCh:
deliverTxRes := deliverTxResMsg.(types.EventDataTx)
// The tx was included in a block.
deliverTxR := deliverTxRes.Result
logger.Info("DeliverTx passed ", "tx", cmn.HexBytes(tx), "response", deliverTxR)
return &ctypes.ResultBroadcastTxCommit{
CheckTx: *checkTxRes,
DeliverTx: deliverTxRes.Result,
CheckTx: *checkTxR,
DeliverTx: deliverTxR,
Hash: tx.Hash(),
Height: deliverTxRes.Height,
}, nil
case <-time.After(deliverTxTimeout):
err = errors.New("Timed out waiting for tx to be included in a block")
logger.Error("Error on broadcastTxCommit", "err", err)
case <-timer.C:
logger.Error("failed to include tx")
return &ctypes.ResultBroadcastTxCommit{
CheckTx: *checkTxRes,
CheckTx: *checkTxR,
DeliverTx: abci.ResponseDeliverTx{},
Hash: tx.Hash(),
}, err
}, fmt.Errorf("Timed out waiting for transaction to be included in a block")
}
}

View File

@@ -151,6 +151,11 @@ func RecoverAndLogHandler(handler http.Handler, logger log.Logger) http.Handler
rww := &ResponseWriterWrapper{-1, w}
begin := time.Now()
// Common headers
origin := r.Header.Get("Origin")
rww.Header().Set("Access-Control-Allow-Origin", origin)
rww.Header().Set("Access-Control-Allow-Credentials", "true")
rww.Header().Set("Access-Control-Expose-Headers", "X-Server-Time")
rww.Header().Set("X-Server-Time", fmt.Sprintf("%v", begin.Unix()))
defer func() {

View File

@@ -84,7 +84,6 @@ func GetConfig() *cfg.Config {
tm, rpc, grpc := makeAddrs()
globalConfig.P2P.ListenAddress = tm
globalConfig.RPC.ListenAddress = rpc
globalConfig.RPC.CORSAllowedOrigins = []string{"https://tendermint.com/"}
globalConfig.RPC.GRPCListenAddress = grpc
globalConfig.TxIndex.IndexTags = "app.creator,tx.height" // see kvstore application
}

View File

@@ -1,48 +0,0 @@
#!/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
# change this to a specific release or branch
BRANCH=master
GO_VERSION=1.11.2
sudo apt-get update -y
# get and unpack golang
curl -O https://storage.googleapis.com/golang/go$GO_VERSION.linux-armv6l.tar.gz
tar -xvf go$GO_VERSION.linux-armv6l.tar.gz
# move go folder and add go binary to path
sudo mv go /usr/local
echo "export PATH=\$PATH:/usr/local/go/bin" >> ~/.profile
# create the go directory, set GOPATH, and put it on PATH
mkdir go
echo "export GOPATH=$HOME/go" >> ~/.profile
echo "export PATH=\$PATH:\$GOPATH/bin" >> ~/.profile
source ~/.profile
# get the code and move into repo
go get $REPO
cd "$GOPATH/src/$REPO"
# build & install
git checkout $BRANCH
# XXX: uncomment if branch isn't master
# git fetch origin $BRANCH
make get_tools
make get_vendor_deps
make install
# the binary is located in $GOPATH/bin
# run `source ~/.profile` or reset your terminal
# to persist the changes

View File

@@ -14,9 +14,6 @@
# change this to a specific release or branch
set BRANCH=master
set REPO=github.com/tendermint/tendermint
set GO_VERSION=1.11.2
sudo pkg update
@@ -24,8 +21,8 @@ sudo pkg install -y gmake
sudo pkg install -y git
# get and unpack golang
curl -O https://storage.googleapis.com/golang/go$GO_VERSION.freebsd-amd64.tar.gz
tar -xvf go$GO_VERSION.freebsd-amd64.tar.gz
curl -O https://storage.googleapis.com/golang/go1.11.freebsd-amd64.tar.gz
tar -xvf go1.11.freebsd-amd64.tar.gz
# move go folder and add go binary to path
sudo mv go /usr/local
@@ -41,6 +38,7 @@ echo "set path=($path $GOPATH/bin)" >> ~/.tcshrc
source ~/.tcshrc
# get the code and move into repo
set REPO=github.com/tendermint/tendermint
go get $REPO
cd "$GOPATH/src/$REPO"

View File

@@ -13,22 +13,20 @@ REPO=github.com/tendermint/tendermint
# change this to a specific release or branch
BRANCH=master
GO_VERSION=1.11.2
sudo apt-get update -y
sudo apt-get install -y make
# get and unpack golang
curl -O https://storage.googleapis.com/golang/go$GO_VERSION.linux-amd64.tar.gz
tar -xvf go$GO_VERSION.linux-amd64.tar.gz
curl -O https://storage.googleapis.com/golang/go1.11.linux-amd64.tar.gz
tar -xvf go1.11.linux-amd64.tar.gz
# move go folder and add go binary to path
sudo mv go /usr/local
echo "export PATH=\$PATH:/usr/local/go/bin" >> ~/.profile
# create the go directory, set GOPATH, and put it on PATH
mkdir go
echo "export GOPATH=$HOME/go" >> ~/.profile
# create the goApps directory, set GOPATH, and put it on PATH
mkdir goApps
echo "export GOPATH=$HOME/goApps" >> ~/.profile
echo "export PATH=\$PATH:\$GOPATH/bin" >> ~/.profile
source ~/.profile

View File

@@ -8,6 +8,7 @@ import (
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/fail"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/mempool"
"github.com/tendermint/tendermint/proxy"
"github.com/tendermint/tendermint/types"
)
@@ -179,8 +180,13 @@ func (blockExec *BlockExecutor) Commit(
err = blockExec.mempool.Update(
block.Height,
block.Txs,
TxPreCheck(state),
TxPostCheck(state),
mempool.PreCheckAminoMaxBytes(
types.MaxDataBytesUnknownEvidence(
state.ConsensusParams.BlockSize.MaxBytes,
state.Validators.Size(),
),
),
mempool.PostCheckMaxGas(state.ConsensusParams.BlockSize.MaxGas),
)
return res.Data, err

View File

@@ -96,7 +96,7 @@ func saveState(db dbm.DB, state State, key []byte) {
saveValidatorsInfo(db, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators)
// Save next consensus params.
saveConsensusParamsInfo(db, nextHeight, state.LastHeightConsensusParamsChanged, state.ConsensusParams)
db.SetSync(key, state.Bytes())
db.SetSync(stateKey, state.Bytes())
}
//------------------------------------------------------------------------

View File

@@ -1,22 +1,15 @@
package state
import (
mempl "github.com/tendermint/tendermint/mempool"
"github.com/tendermint/tendermint/types"
)
// TxPreCheck returns a function to filter transactions before processing.
// The function limits the size of a transaction to the block's maximum data size.
func TxPreCheck(state State) mempl.PreCheckFunc {
// TxFilter returns a function to filter transactions. The function limits the
// size of a transaction to the maximum block's data size.
func TxFilter(state State) func(tx types.Tx) bool {
maxDataBytes := types.MaxDataBytesUnknownEvidence(
state.ConsensusParams.BlockSize.MaxBytes,
state.Validators.Size(),
)
return mempl.PreCheckAminoMaxBytes(maxDataBytes)
}
// TxPostCheck returns a function to filter transactions after processing.
// The function limits the gas wanted by a transaction to the block's maximum total gas.
func TxPostCheck(state State) mempl.PostCheckFunc {
return mempl.PostCheckMaxGas(state.ConsensusParams.BlockSize.MaxGas)
return func(tx types.Tx) bool { return int64(len(tx)) <= maxDataBytes }
}

View File

@@ -18,18 +18,12 @@ func TestTxFilter(t *testing.T) {
genDoc := randomGenesisDoc()
genDoc.ConsensusParams.BlockSize.MaxBytes = 3000
// Max size of Txs is much smaller than size of block,
// since we need to account for commits and evidence.
testCases := []struct {
tx types.Tx
isErr bool
tx types.Tx
isTxValid bool
}{
{types.Tx(cmn.RandBytes(250)), false},
{types.Tx(cmn.RandBytes(1809)), false},
{types.Tx(cmn.RandBytes(1810)), false},
{types.Tx(cmn.RandBytes(1811)), true},
{types.Tx(cmn.RandBytes(1812)), true},
{types.Tx(cmn.RandBytes(3000)), true},
{types.Tx(cmn.RandBytes(250)), true},
{types.Tx(cmn.RandBytes(3001)), false},
}
for i, tc := range testCases {
@@ -37,12 +31,8 @@ func TestTxFilter(t *testing.T) {
state, err := LoadStateFromDBOrGenesisDoc(stateDB, genDoc)
require.NoError(t, err)
f := TxPreCheck(state)
if tc.isErr {
assert.NotNil(t, f(tc.tx), "#%v", i)
} else {
assert.Nil(t, f(tc.tx), "#%v", i)
}
f := TxFilter(state)
assert.Equal(t, tc.isTxValid, f(tc.tx), "#%v", i)
}
}

View File

@@ -21,8 +21,6 @@ const (
// MaxAminoOverheadForBlock - maximum amino overhead to encode a block (up to
// MaxBlockSizeBytes in size) not including it's parts except Data.
// This means it also excludes the overhead for individual transactions.
// To compute individual transactions' overhead use types.ComputeAminoOverhead(tx types.Tx, fieldNum int).
//
// Uvarint length of MaxBlockSizeBytes: 4 bytes
// 2 fields (2 embedded): 2 bytes

View File

@@ -250,7 +250,7 @@ func TestMaxHeaderBytes(t *testing.T) {
timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC)
h := Header{
Version: version.Consensus{Block: math.MaxInt64, App: math.MaxInt64},
Version: version.Consensus{math.MaxInt64, math.MaxInt64},
ChainID: maxChainID,
Height: math.MaxInt64,
Time: timestamp,

View File

@@ -61,7 +61,7 @@ func TestEvidence(t *testing.T) {
{vote1, makeVote(val, chainID, 0, 10, 3, 1, blockID2), false}, // wrong round
{vote1, makeVote(val, chainID, 0, 10, 2, 2, blockID2), false}, // wrong step
{vote1, makeVote(val2, chainID, 0, 10, 2, 1, blockID), false}, // wrong validator
{vote1, badVote, false}, // signed by wrong key
{vote1, badVote, false}, // signed by wrong key
}
pubKey := val.GetPubKey()
@@ -121,38 +121,3 @@ func randomDuplicatedVoteEvidence() *DuplicateVoteEvidence {
VoteB: makeVote(val, chainID, 0, 10, 2, 1, blockID2),
}
}
func TestDuplicateVoteEvidenceValidation(t *testing.T) {
val := NewMockPV()
blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt64, tmhash.Sum([]byte("partshash")))
blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt64, tmhash.Sum([]byte("partshash")))
const chainID = "mychain"
testCases := []struct {
testName string
malleateEvidence func(*DuplicateVoteEvidence)
expectErr bool
}{
{"Good DuplicateVoteEvidence", func(ev *DuplicateVoteEvidence) {}, false},
{"Nil vote A", func(ev *DuplicateVoteEvidence) { ev.VoteA = nil }, true},
{"Nil vote B", func(ev *DuplicateVoteEvidence) { ev.VoteB = nil }, true},
{"Nil votes", func(ev *DuplicateVoteEvidence) {
ev.VoteA = nil
ev.VoteB = nil
}, true},
{"Invalid vote type", func(ev *DuplicateVoteEvidence) {
ev.VoteA = makeVote(val, chainID, math.MaxInt64, math.MaxInt64, math.MaxInt64, 0, blockID2)
}, true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
ev := &DuplicateVoteEvidence{
PubKey: secp256k1.GenPrivKey().PubKey(),
VoteA: makeVote(val, chainID, math.MaxInt64, math.MaxInt64, math.MaxInt64, 0x02, blockID),
VoteB: makeVote(val, chainID, math.MaxInt64, math.MaxInt64, math.MaxInt64, 0x02, blockID2),
}
tc.malleateEvidence(ev)
assert.Equal(t, tc.expectErr, ev.ValidateBasic() != nil, "Validate Basic had an unexpected result")
})
}
}

View File

@@ -19,9 +19,6 @@ const (
//------------------------------------------------------------
// core types for a genesis definition
// NOTE: any changes to the genesis definition should
// be reflected in the documentation:
// docs/tendermint-core/using-tendermint.md
// GenesisValidator is an initial validator.
type GenesisValidator struct {

View File

@@ -3,10 +3,8 @@ package types
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/secp256k1"
)
func TestHeartbeatCopy(t *testing.T) {
@@ -60,45 +58,3 @@ func TestHeartbeatWriteSignBytes(t *testing.T) {
require.Equal(t, string(signBytes), "null")
})
}
func TestHeartbeatValidateBasic(t *testing.T) {
testCases := []struct {
testName string
malleateHeartBeat func(*Heartbeat)
expectErr bool
}{
{"Good HeartBeat", func(hb *Heartbeat) {}, false},
{"Invalid address size", func(hb *Heartbeat) {
hb.ValidatorAddress = nil
}, true},
{"Negative validator index", func(hb *Heartbeat) {
hb.ValidatorIndex = -1
}, true},
{"Negative height", func(hb *Heartbeat) {
hb.Height = -1
}, true},
{"Negative round", func(hb *Heartbeat) {
hb.Round = -1
}, true},
{"Negative sequence", func(hb *Heartbeat) {
hb.Sequence = -1
}, true},
{"Missing signature", func(hb *Heartbeat) {
hb.Signature = nil
}, true},
{"Signature too big", func(hb *Heartbeat) {
hb.Signature = make([]byte, MaxSignatureSize+1)
}, true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
hb := &Heartbeat{
ValidatorAddress: secp256k1.GenPrivKey().PubKey().Address(),
Signature: make([]byte, 4),
ValidatorIndex: 1, Height: 10, Round: 1}
tc.malleateHeartBeat(hb)
assert.Equal(t, tc.expectErr, hb.ValidateBasic() != nil, "Validate Basic had an unexpected result")
})
}
}

View File

@@ -83,48 +83,3 @@ func TestWrongProof(t *testing.T) {
t.Errorf("Expected to fail adding a part with bad bytes.")
}
}
func TestPartSetHeaderSetValidateBasic(t *testing.T) {
testCases := []struct {
testName string
malleatePartSetHeader func(*PartSetHeader)
expectErr bool
}{
{"Good PartSet", func(psHeader *PartSetHeader) {}, false},
{"Negative Total", func(psHeader *PartSetHeader) { psHeader.Total = -2 }, true},
{"Invalid Hash", func(psHeader *PartSetHeader) { psHeader.Hash = make([]byte, 1) }, true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
data := cmn.RandBytes(testPartSize * 100)
ps := NewPartSetFromData(data, testPartSize)
psHeader := ps.Header()
tc.malleatePartSetHeader(&psHeader)
assert.Equal(t, tc.expectErr, psHeader.ValidateBasic() != nil, "Validate Basic had an unexpected result")
})
}
}
func TestPartValidateBasic(t *testing.T) {
testCases := []struct {
testName string
malleatePart func(*Part)
expectErr bool
}{
{"Good Part", func(pt *Part) {}, false},
{"Negative index", func(pt *Part) { pt.Index = -1 }, true},
{"Too big part", func(pt *Part) { pt.Bytes = make([]byte, BlockPartSizeBytes+1) }, true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
data := cmn.RandBytes(testPartSize * 100)
ps := NewPartSetFromData(data, testPartSize)
part := ps.GetPart(0)
tc.malleatePart(part)
assert.Equal(t, tc.expectErr, part.ValidateBasic() != nil, "Validate Basic had an unexpected result")
})
}
}

View File

@@ -1,13 +1,10 @@
package types
import (
"math"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto/tmhash"
)
var testProposal *Proposal
@@ -100,41 +97,3 @@ func BenchmarkProposalVerifySignature(b *testing.B) {
pubKey.VerifyBytes(testProposal.SignBytes("test_chain_id"), testProposal.Signature)
}
}
func TestProposalValidateBasic(t *testing.T) {
privVal := NewMockPV()
testCases := []struct {
testName string
malleateProposal func(*Proposal)
expectErr bool
}{
{"Good Proposal", func(p *Proposal) {}, false},
{"Invalid Type", func(p *Proposal) { p.Type = PrecommitType }, true},
{"Invalid Height", func(p *Proposal) { p.Height = -1 }, true},
{"Invalid Round", func(p *Proposal) { p.Round = -1 }, true},
{"Invalid POLRound", func(p *Proposal) { p.POLRound = -2 }, true},
{"Invalid BlockId", func(p *Proposal) {
p.BlockID = BlockID{[]byte{1, 2, 3}, PartSetHeader{111, []byte("blockparts")}}
}, true},
{"Invalid Signature", func(p *Proposal) {
p.Signature = make([]byte, 0)
}, true},
{"Too big Signature", func(p *Proposal) {
p.Signature = make([]byte, MaxSignatureSize+1)
}, true},
}
blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt64, tmhash.Sum([]byte("partshash")))
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
prop := NewProposal(
4, 2, 2,
blockID)
err := privVal.SignProposal("test_chain_id", prop)
require.NoError(t, err)
tc.malleateProposal(prop)
assert.Equal(t, tc.expectErr, prop.ValidateBasic() != nil, "Validate Basic had an unexpected result")
})
}
}

View File

@@ -5,8 +5,6 @@ import (
"errors"
"fmt"
"github.com/tendermint/go-amino"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/merkle"
"github.com/tendermint/tendermint/crypto/tmhash"
@@ -120,18 +118,3 @@ type TxResult struct {
Tx Tx `json:"tx"`
Result abci.ResponseDeliverTx `json:"result"`
}
// ComputeAminoOverhead calculates the overhead for amino encoding a transaction.
// The overhead consists of varint encoding the field number and the wire type
// (= length-delimited = 2), and another varint encoding the length of the
// transaction.
// The field number can be the field number of the particular transaction, or
// the field number of the parenting struct that contains the transactions []Tx
// as a field (this field number is repeated for each contained Tx).
// If some []Tx are encoded directly (without a parenting struct), the default
// fieldNum is also 1 (see BinFieldNum in amino.MarshalBinaryBare).
func ComputeAminoOverhead(tx Tx, fieldNum int) int64 {
fnum := uint64(fieldNum)
typ3AndFieldNum := (uint64(fnum) << 3) | uint64(amino.Typ3_ByteLength)
return int64(amino.UvarintSize(typ3AndFieldNum)) + int64(amino.UvarintSize(uint64(len(tx))))
}

View File

@@ -96,63 +96,6 @@ func TestTxProofUnchangable(t *testing.T) {
}
}
func TestComputeTxsOverhead(t *testing.T) {
cases := []struct {
txs Txs
wantOverhead int
}{
{Txs{[]byte{6, 6, 6, 6, 6, 6}}, 2},
// one 21 Mb transaction:
{Txs{make([]byte, 22020096, 22020096)}, 5},
// two 21Mb/2 sized transactions:
{Txs{make([]byte, 11010048, 11010048), make([]byte, 11010048, 11010048)}, 10},
{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},
}
for _, tc := range cases {
totalBytes := int64(0)
totalOverhead := int64(0)
for _, tx := range tc.txs {
aminoOverhead := ComputeAminoOverhead(tx, 1)
totalOverhead += aminoOverhead
totalBytes += aminoOverhead + int64(len(tx))
}
bz, err := cdc.MarshalBinaryBare(tc.txs)
assert.EqualValues(t, tc.wantOverhead, totalOverhead)
assert.NoError(t, err)
assert.EqualValues(t, len(bz), totalBytes)
}
}
func TestComputeAminoOverhead(t *testing.T) {
cases := []struct {
tx Tx
fieldNum int
want int
}{
{[]byte{6, 6, 6}, 1, 2},
{[]byte{6, 6, 6}, 16, 3},
{[]byte{6, 6, 6}, 32, 3},
{[]byte{6, 6, 6}, 64, 3},
{[]byte{6, 6, 6}, 512, 3},
{[]byte{6, 6, 6}, 1024, 3},
{[]byte{6, 6, 6}, 2048, 4},
{make([]byte, 64), 1, 2},
{make([]byte, 65), 1, 2},
{make([]byte, 127), 1, 2},
{make([]byte, 128), 1, 3},
{make([]byte, 256), 1, 3},
{make([]byte, 512), 1, 3},
{make([]byte, 1024), 1, 3},
{make([]byte, 128), 16, 4},
}
for _, tc := range cases {
got := ComputeAminoOverhead(tc.tx, tc.fieldNum)
assert.EqualValues(t, tc.want, got)
}
}
func testTxProofUnchangable(t *testing.T) {
// make some proof
txs := makeTxs(randInt(2, 100), randInt(16, 128))

View File

@@ -250,31 +250,3 @@ func TestVoteString(t *testing.T) {
t.Errorf("Got unexpected string for Vote. Expected:\n%v\nGot:\n%v", expected, str2)
}
}
func TestVoteValidateBasic(t *testing.T) {
privVal := NewMockPV()
testCases := []struct {
testName string
malleateVote func(*Vote)
expectErr bool
}{
{"Good Vote", func(v *Vote) {}, false},
{"Negative Height", func(v *Vote) { v.Height = -1 }, true},
{"Negative Round", func(v *Vote) { v.Round = -1 }, true},
{"Invalid BlockID", func(v *Vote) { v.BlockID = BlockID{[]byte{1, 2, 3}, PartSetHeader{111, []byte("blockparts")}} }, true},
{"Invalid Address", func(v *Vote) { v.ValidatorAddress = make([]byte, 1) }, true},
{"Invalid ValidatorIndex", func(v *Vote) { v.ValidatorIndex = -1 }, true},
{"Invalid Signature", func(v *Vote) { v.Signature = nil }, true},
{"Too big Signature", func(v *Vote) { v.Signature = make([]byte, MaxSignatureSize+1) }, true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
vote := examplePrecommit()
err := privVal.SignVote("test_chain_id", vote)
require.NoError(t, err)
tc.malleateVote(vote)
assert.Equal(t, tc.expectErr, vote.ValidateBasic() != nil, "Validate Basic had an unexpected result")
})
}
}

View File

@@ -18,7 +18,7 @@ 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.
TMCoreSemVer = "0.26.2"
TMCoreSemVer = "0.26.0"
// ABCISemVer is the semantic version of the ABCI library
ABCISemVer = "0.15.0"