Browse Source

Merge pull request #1935 from tendermint/release/v0.22.2

Release/v0.22.2
pull/1971/head v0.22.2
Ethan Buchman 7 years ago
committed by GitHub
parent
commit
5ff65274b8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 918 additions and 678 deletions
  1. +1
    -2
      .circleci/config.yml
  2. +0
    -1
      .gitignore
  3. +25
    -4
      CHANGELOG.md
  4. +0
    -0
      DOCKER/Dockerfile.abci
  5. +3
    -3
      Gopkg.lock
  6. +1
    -1
      Gopkg.toml
  7. +81
    -7
      Makefile
  8. +0
    -174
      abci/Makefile
  9. +0
    -12
      abci/scripts/abci-builder/Dockerfile
  10. +0
    -52
      abci/scripts/dist.sh
  11. +0
    -53
      abci/scripts/dist_build.sh
  12. +0
    -7
      abci/scripts/publish.sh
  13. +0
    -13
      abci/tests/test_cover.sh
  14. +7
    -12
      blockchain/reactor.go
  15. +7
    -0
      config/config.go
  16. +6
    -0
      config/toml.go
  17. +5
    -8
      consensus/reactor.go
  18. +0
    -99
      crypto/Makefile
  19. +4
    -5
      docs/README.md
  20. +0
    -0
      docs/app-dev/abci-cli.md
  21. +0
    -0
      docs/app-dev/abci-spec.md
  22. +0
    -0
      docs/app-dev/app-architecture.md
  23. +0
    -0
      docs/app-dev/app-development.md
  24. +213
    -0
      docs/app-dev/ecosystem.json
  25. +1
    -1
      docs/app-dev/ecosystem.md
  26. +0
    -0
      docs/app-dev/getting-started.md
  27. +0
    -0
      docs/app-dev/indexing-transactions.md
  28. +0
    -0
      docs/app-dev/subscribing-to-events-via-websocket.md
  29. BIN
      docs/images/tmint-logo-blue.png
  30. +250
    -0
      docs/interviews/tendermint-bft.md
  31. +0
    -0
      docs/introduction/install.md
  32. +0
    -0
      docs/introduction/introduction.md
  33. +5
    -6
      docs/introduction/quick-start.md
  34. +0
    -0
      docs/networks/deploy-testnets.md
  35. +0
    -0
      docs/networks/terraform-and-ansible.md
  36. +0
    -0
      docs/research/determinism.md
  37. +0
    -0
      docs/research/transactional-semantics.md
  38. +6
    -0
      docs/tendermint-core/configuration.md
  39. +0
    -0
      docs/tendermint-core/how-to-read-logs.md
  40. +0
    -0
      docs/tendermint-core/metrics.md
  41. +0
    -0
      docs/tendermint-core/rpc.md
  42. +2
    -7
      docs/tendermint-core/running-in-production.md
  43. +0
    -0
      docs/tendermint-core/using-tendermint.md
  44. +80
    -0
      docs/tools/benchmarking.md
  45. +92
    -0
      docs/tools/monitoring.md
  46. +5
    -7
      evidence/reactor.go
  47. +0
    -137
      libs/Makefile
  48. +3
    -5
      mempool/reactor.go
  49. +8
    -2
      node/node.go
  50. +6
    -8
      p2p/pex/pex_reactor.go
  51. +5
    -5
      p2p/pex/pex_reactor_test.go
  52. +52
    -14
      rpc/lib/server/handlers.go
  53. +1
    -0
      rpc/lib/server/http_params.go
  54. +46
    -1
      rpc/lib/server/parse_test.go
  55. +0
    -14
      scripts/dep_utils/parse.sh
  56. +0
    -12
      scripts/install_abci_apps.sh
  57. +1
    -4
      test/docker/Dockerfile
  58. +2
    -2
      version/version.go

+ 1
- 2
.circleci/config.yml View File

@ -31,8 +31,7 @@ jobs:
name: binaries name: binaries
command: | command: |
export PATH="$GOBIN:$PATH" export PATH="$GOBIN:$PATH"
make install
cd abci && make install
make install install_abci
- persist_to_workspace: - persist_to_workspace:
root: /tmp/workspace root: /tmp/workspace
paths: paths:


+ 0
- 1
.gitignore View File

@ -14,7 +14,6 @@ test/p2p/data/
test/logs test/logs
coverage.txt coverage.txt
docs/_build docs/_build
docs/tools
*.log *.log
abci-cli abci-cli
abci/types/types.pb.go abci/types/types.pb.go


+ 25
- 4
CHANGELOG.md View File

@ -1,5 +1,22 @@
# Changelog # Changelog
## 0.22.2
*July 10th, 2018*
IMPROVEMENTS
- More cleanup post repo merge!
- [docs] Include `ecosystem.json` and `tendermint-bft.md` from deprecated `aib-data` repository.
- [config] Add `instrumentation.max_open_connections`, which limits the number
of requests in flight to Prometheus server (if enabled). Default: 3.
BUG FIXES
- [rpc] Allow unquoted integers in requests
- NOTE: this is only for URI requests. JSONRPC requests and all responses
will use quoted integers (the proto3 JSON standard).
- [consensus] Fix halt on shutdown
## 0.22.1 ## 0.22.1
*July 5th, 2018* *July 5th, 2018*
@ -20,7 +37,14 @@ BUG FIXES
*July 2nd, 2018* *July 2nd, 2018*
BREAKING CHANGES: BREAKING CHANGES:
- [config] Rename `skip_upnp` to `upnp`, and turn it off by default.
- [config]
* Remove `max_block_size_txs` and `max_block_size_bytes` in favor of
consensus params from the genesis file.
* Rename `skip_upnp` to `upnp`, and turn it off by default.
* Change `max_packet_msg_size` back to `max_packet_msg_payload_size`
- [rpc]
* All integers are encoded as strings (part of the update for Amino v0.10.1)
* `syncing` is now called `catching_up`
- [types] Update Amino to v0.10.1 - [types] Update Amino to v0.10.1
* Amino is now fully proto3 compatible for the basic types * Amino is now fully proto3 compatible for the basic types
* JSON-encoded types now use the type name instead of the prefix bytes * JSON-encoded types now use the type name instead of the prefix bytes
@ -31,9 +55,6 @@ BREAKING CHANGES:
* `tmlibs/merkle` -> `crypto/merkle`. Uses SHA256 instead of RIPEMD160 * `tmlibs/merkle` -> `crypto/merkle`. Uses SHA256 instead of RIPEMD160
- [tmlibs] Update to v0.9.0 and merge into `libs` - [tmlibs] Update to v0.9.0 and merge into `libs`
* remove `merkle` package (moved to `crypto/merkle`) * remove `merkle` package (moved to `crypto/merkle`)
- [rpc]
* All integers are encoded as strings (part of the update for Amino v0.10.1)
* `syncing` is now called `catching_up`
FEATURES FEATURES
- [cmd] Added metrics (served under `/metrics` using a Prometheus client; - [cmd] Added metrics (served under `/metrics` using a Prometheus client;


abci/Dockerfile.develop → DOCKER/Dockerfile.abci View File


+ 3
- 3
Gopkg.lock View File

@ -180,13 +180,13 @@
version = "v1.0.0" version = "v1.0.0"
[[projects]] [[projects]]
branch = "master"
name = "github.com/prometheus/client_golang" name = "github.com/prometheus/client_golang"
packages = [ packages = [
"prometheus", "prometheus",
"prometheus/promhttp" "prometheus/promhttp"
] ]
revision = "c5b7fccd204277076155f10851dad72b76a49317"
version = "v0.8.0"
revision = "d6a9817c4afc94d51115e4a30d449056a3fbf547"
[[projects]] [[projects]]
branch = "master" branch = "master"
@ -414,6 +414,6 @@
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "71753a9d4ece4252d23941f116f5ff66c0d5da730a099e5a9867491d223ed93b"
inputs-digest = "6e854634d6c203278ce83bef7725cecbcf90023b0d0e440fb3374acedacbd5ad"
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

+ 1
- 1
Gopkg.toml View File

@ -88,7 +88,7 @@
[[constraint]] [[constraint]]
name = "github.com/prometheus/client_golang" name = "github.com/prometheus/client_golang"
version = "0.8.0"
branch = "master"
[[constraint]] [[constraint]]
branch = "master" branch = "master"


+ 81
- 7
Makefile View File

@ -1,7 +1,12 @@
GOTOOLS = \ GOTOOLS = \
github.com/mitchellh/gox \
github.com/golang/dep/cmd/dep \ github.com/golang/dep/cmd/dep \
gopkg.in/alecthomas/gometalinter.v2
gopkg.in/alecthomas/gometalinter.v2 \
github.com/gogo/protobuf/protoc-gen-gogo \
github.com/gogo/protobuf/gogoproto \
github.com/square/certstrap
PACKAGES=$(shell go list ./... | grep -v '/vendor/') PACKAGES=$(shell go list ./... | grep -v '/vendor/')
INCLUDE = -I=. -I=${GOPATH}/src -I=${GOPATH}/src/github.com/gogo/protobuf/protobuf
BUILD_TAGS?=tendermint BUILD_TAGS?=tendermint
BUILD_FLAGS = -ldflags "-X github.com/tendermint/tendermint/version.GitCommit=`git rev-parse --short=8 HEAD`" BUILD_FLAGS = -ldflags "-X github.com/tendermint/tendermint/version.GitCommit=`git rev-parse --short=8 HEAD`"
@ -11,7 +16,7 @@ check: check_tools ensure_deps
######################################## ########################################
### Build
### Build Tendermint
build: build:
CGO_ENABLED=0 go build $(BUILD_FLAGS) -tags '$(BUILD_TAGS)' -o build/tendermint ./cmd/tendermint/ CGO_ENABLED=0 go build $(BUILD_FLAGS) -tags '$(BUILD_TAGS)' -o build/tendermint ./cmd/tendermint/
@ -22,10 +27,29 @@ build_race:
install: install:
CGO_ENABLED=0 go install $(BUILD_FLAGS) -tags '$(BUILD_TAGS)' ./cmd/tendermint CGO_ENABLED=0 go install $(BUILD_FLAGS) -tags '$(BUILD_TAGS)' ./cmd/tendermint
########################################
### Build ABCI
protoc_abci:
## If you get the following error,
## "error while loading shared libraries: libprotobuf.so.14: cannot open shared object file: No such file or directory"
## See https://stackoverflow.com/a/25518702
protoc $(INCLUDE) --gogo_out=plugins=grpc:. abci/types/*.proto
@echo "--> adding nolint declarations to protobuf generated files"
@awk '/package abci/types/ { print "//nolint: gas"; print; next }1' abci/types/types.pb.go > abci/types/types.pb.go.new
@mv abci/types/types.pb.go.new abci/types/types.pb.go
build_abci:
@go build -i ./abci/cmd/...
install_abci:
@go install ./abci/cmd/...
######################################## ########################################
### Distribution ### Distribution
# dist builds binaries for all platforms and packages them for distribution # dist builds binaries for all platforms and packages them for distribution
# TODO add abci to these scripts
dist: dist:
@BUILD_TAGS='$(BUILD_TAGS)' sh -c "'$(CURDIR)/scripts/dist.sh'" @BUILD_TAGS='$(BUILD_TAGS)' sh -c "'$(CURDIR)/scripts/dist.sh'"
@ -59,6 +83,17 @@ ensure_deps:
@echo "--> Running dep" @echo "--> Running dep"
@dep ensure @dep ensure
#For ABCI and libs
get_protoc:
@# https://github.com/google/protobuf/releases
curl -L https://github.com/google/protobuf/releases/download/v3.4.1/protobuf-cpp-3.4.1.tar.gz | tar xvz && \
cd protobuf-3.4.1 && \
DIST_LANG=cpp ./configure && \
make && \
make install && \
cd .. && \
rm -rf protobuf-3.4.1
draw_deps: draw_deps:
@# requires brew install graphviz or apt-get install graphviz @# requires brew install graphviz or apt-get install graphviz
go get github.com/RobotsAndPencils/goviz go get github.com/RobotsAndPencils/goviz
@ -70,6 +105,37 @@ get_deps_bin_size:
@find $(WORK) -type f -name "*.a" | xargs -I{} du -hxs "{}" | sort -rh | sed -e s:${WORK}/::g > deps_bin_size.log @find $(WORK) -type f -name "*.a" | xargs -I{} du -hxs "{}" | sort -rh | sed -e s:${WORK}/::g > deps_bin_size.log
@echo "Results can be found here: $(CURDIR)/deps_bin_size.log" @echo "Results can be found here: $(CURDIR)/deps_bin_size.log"
########################################
### Libs
protoc_libs:
## If you get the following error,
## "error while loading shared libraries: libprotobuf.so.14: cannot open shared object file: No such file or directory"
## See https://stackoverflow.com/a/25518702
protoc $(INCLUDE) --go_out=plugins=grpc:. libs/common/*.proto
@echo "--> adding nolint declarations to protobuf generated files"
@awk '/package libs/common/ { print "//nolint: gas"; print; next }1' libs/common/types.pb.go > libs/common/types.pb.go.new
@mv libs/common/types.pb.go.new libs/common/types.pb.go
gen_certs: clean_certs
## Generating certificates for TLS testing...
certstrap init --common-name "tendermint.com" --passphrase ""
certstrap request-cert -ip "::" --passphrase ""
certstrap sign "::" --CA "tendermint.com" --passphrase ""
mv out/::.crt out/::.key db/remotedb
clean_certs:
## Cleaning TLS testing certificates...
rm -rf out
rm -f db/remotedb/::.crt db/remotedb/::.key
test_libs: gen_certs
GOCACHE=off go test -tags gcc $(shell go list ./... | grep -v vendor)
make clean_certs
grpc_dbserver:
protoc -I db/remotedb/proto/ db/remotedb/proto/defs.proto --go_out=plugins=grpc:db/remotedb/proto
######################################## ########################################
### Testing ### Testing
@ -87,6 +153,15 @@ test_apps:
# requires `abci-cli` and `tendermint` binaries installed # requires `abci-cli` and `tendermint` binaries installed
bash test/app/test.sh bash test/app/test.sh
test_abci_apps:
bash abci/tests/test_app/test.sh
test_abci_cli:
# test the cli against the examples in the tutorial at:
# ./docs/abci-cli.md
# if test fails, update the docs ^
@ bash abci/tests/test_cli/test.sh
test_persistence: test_persistence:
# run the persistence tests using bash # run the persistence tests using bash
# requires `abci-cli` installed # requires `abci-cli` installed
@ -105,17 +180,16 @@ test_p2p:
# requires 'tester' the image from above # requires 'tester' the image from above
bash test/p2p/test.sh tester bash test/p2p/test.sh tester
need_abci:
bash scripts/install_abci_apps.sh
test_integrations: test_integrations:
make build_docker_test_image make build_docker_test_image
make get_tools make get_tools
make get_vendor_deps make get_vendor_deps
make install make install
make need_abci
make test_cover make test_cover
make test_apps make test_apps
make test_abci_apps
make test_abci_cli
make test_libs
make test_persistence make test_persistence
make test_p2p make test_p2p
@ -233,4 +307,4 @@ build-slate:
# To avoid unintended conflicts with file names, always add to .PHONY # To avoid unintended conflicts with file names, always add to .PHONY
# unless there is a reason not to. # unless there is a reason not to.
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html # https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
.PHONY: check build build_race dist install check_tools get_tools update_tools get_vendor_deps draw_deps test_cover test_apps test_persistence test_p2p test test_race test_integrations test_release test100 vagrant_test fmt build-linux localnet-start localnet-stop build-docker build-docker-localnode sentry-start sentry-config sentry-stop build-slate
.PHONY: check build build_race build_abci dist install install_abci 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 build-linux localnet-start localnet-stop build-docker build-docker-localnode sentry-start sentry-config sentry-stop build-slate

+ 0
- 174
abci/Makefile View File

@ -1,174 +0,0 @@
GOTOOLS = \
github.com/mitchellh/gox \
github.com/golang/dep/cmd/dep \
gopkg.in/alecthomas/gometalinter.v2 \
github.com/gogo/protobuf/protoc-gen-gogo \
github.com/gogo/protobuf/gogoproto
GOTOOLS_CHECK = gox dep gometalinter.v2 protoc protoc-gen-gogo
PACKAGES=$(shell go list ./... | grep -v '/vendor/')
INCLUDE = -I=. -I=${GOPATH}/src -I=${GOPATH}/src/github.com/gogo/protobuf/protobuf
all: check get_vendor_deps protoc build test install metalinter
check: check_tools
########################################
### Build
protoc:
## If you get the following error,
## "error while loading shared libraries: libprotobuf.so.14: cannot open shared object file: No such file or directory"
## See https://stackoverflow.com/a/25518702
protoc $(INCLUDE) --gogo_out=plugins=grpc:. types/*.proto
@echo "--> adding nolint declarations to protobuf generated files"
@awk '/package types/ { print "//nolint: gas"; print; next }1' types/types.pb.go > types/types.pb.go.new
@mv types/types.pb.go.new types/types.pb.go
build:
@go build -i ./cmd/...
dist:
@bash scripts/dist.sh
@bash scripts/publish.sh
install:
@go install ./cmd/...
########################################
### Tools & dependencies
check_tools:
@# https://stackoverflow.com/a/25668869
@echo "Found tools: $(foreach tool,$(GOTOOLS_CHECK),\
$(if $(shell which $(tool)),$(tool),$(error "No $(tool) in PATH")))"
get_tools:
@echo "--> Installing tools"
go get -u -v $(GOTOOLS)
@gometalinter.v2 --install
get_protoc:
@# https://github.com/google/protobuf/releases
curl -L https://github.com/google/protobuf/releases/download/v3.4.1/protobuf-cpp-3.4.1.tar.gz | tar xvz && \
cd protobuf-3.4.1 && \
DIST_LANG=cpp ./configure && \
make && \
make install && \
cd .. && \
rm -rf protobuf-3.4.1
update_tools:
@echo "--> Updating tools"
@go get -u $(GOTOOLS)
get_vendor_deps:
@rm -rf vendor/
@echo "--> Running dep ensure"
@dep ensure
########################################
### Testing
test:
@find . -path ./vendor -prune -o -name "*.sock" -exec rm {} \;
@echo "==> Running go test"
@go test $(PACKAGES)
test_race:
@find . -path ./vendor -prune -o -name "*.sock" -exec rm {} \;
@echo "==> Running go test --race"
@go test -v -race $(PACKAGES)
### three tests tested by Jenkins
test_cover:
@ bash tests/test_cover.sh
test_apps:
# test the counter using a go test script
@ bash tests/test_app/test.sh
test_cli:
# test the cli against the examples in the tutorial at:
# http://tendermint.readthedocs.io/projects/tools/en/master/abci-cli.html
#
# XXX: if this test fails, fix it and update the docs at:
# https://github.com/tendermint/tendermint/blob/develop/docs/abci-cli.rst
@ bash tests/test_cli/test.sh
########################################
### Formatting, linting, and vetting
fmt:
@go fmt ./...
metalinter:
@echo "==> Running linter"
gometalinter.v2 --vendor --deadline=600s --disable-all \
--enable=maligned \
--enable=deadcode \
--enable=goconst \
--enable=goimports \
--enable=gosimple \
--enable=ineffassign \
--enable=megacheck \
--enable=misspell \
--enable=staticcheck \
--enable=safesql \
--enable=structcheck \
--enable=unconvert \
--enable=unused \
--enable=varcheck \
--enable=vetshadow \
./...
#--enable=gas \
#--enable=dupl \
#--enable=errcheck \
#--enable=gocyclo \
#--enable=golint \ <== comments on anything exported
#--enable=gotype \
#--enable=interfacer \
#--enable=unparam \
#--enable=vet \
metalinter_all:
protoc $(INCLUDE) --lint_out=. types/*.proto
gometalinter.v2 --vendor --deadline=600s --enable-all --disable=lll ./...
########################################
### Docker
DEVDOC_SAVE = docker commit `docker ps -a -n 1 -q` devdoc:local
docker_build:
docker build -t "tendermint/abci-dev" -f Dockerfile.develop .
docker_run:
docker run -it -v "$(CURDIR):/go/src/github.com/tendermint/abci" -w "/go/src/github.com/tendermint/abci" "tendermint/abci-dev" /bin/bash
docker_run_rm:
docker run -it --rm -v "$(CURDIR):/go/src/github.com/tendermint/abci" -w "/go/src/github.com/tendermint/abci" "tendermint/abci-dev" /bin/bash
devdoc_init:
docker run -it -v "$(CURDIR):/go/src/github.com/tendermint/abci" -w "/go/src/github.com/tendermint/abci" tendermint/devdoc echo
# TODO make this safer
$(call DEVDOC_SAVE)
devdoc:
docker run -it -v "$(CURDIR):/go/src/github.com/tendermint/abci" -w "/go/src/github.com/tendermint/abci" devdoc:local bash
devdoc_save:
# TODO make this safer
$(call DEVDOC_SAVE)
devdoc_clean:
docker rmi $$(docker images -f "dangling=true" -q)
# 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 protoc build dist install check_tools get_tools get_protoc update_tools get_vendor_deps test test_race fmt metalinter metalinter_all docker_build docker_run docker_run_rm devdoc_init devdoc devdoc_save devdoc_clean

+ 0
- 12
abci/scripts/abci-builder/Dockerfile View File

@ -1,12 +0,0 @@
FROM golang:1.9.2
RUN apt-get update && apt-get install -y --no-install-recommends \
zip \
&& rm -rf /var/lib/apt/lists/*
# We want to ensure that release builds never have any cgo dependencies so we
# switch that off at the highest level.
ENV CGO_ENABLED 0
RUN mkdir -p $GOPATH/src/github.com/tendermint/abci
WORKDIR $GOPATH/src/github.com/tendermint/abci

+ 0
- 52
abci/scripts/dist.sh View File

@ -1,52 +0,0 @@
#!/usr/bin/env bash
set -e
REPO_NAME="abci"
# Get the version from the environment, or try to figure it out.
if [ -z $VERSION ]; then
VERSION=$(awk -F\" '/Version =/ { print $2; exit }' < version/version.go)
fi
if [ -z "$VERSION" ]; then
echo "Please specify a version."
exit 1
fi
echo "==> Building version $VERSION..."
# Get the parent directory of where this script is.
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )"
# Change into that dir because we expect that.
cd "$DIR"
# Delete the old dir
echo "==> Removing old directory..."
rm -rf build/pkg
mkdir -p build/pkg
# Do a hermetic build inside a Docker container.
docker build -t tendermint/${REPO_NAME}-builder scripts/${REPO_NAME}-builder/
docker run --rm -e "BUILD_TAGS=$BUILD_TAGS" -v "$(pwd)":/go/src/github.com/tendermint/${REPO_NAME} tendermint/${REPO_NAME}-builder ./scripts/dist_build.sh
# Add $REPO_NAME and $VERSION prefix to package name.
rm -rf ./build/dist
mkdir -p ./build/dist
for FILENAME in $(find ./build/pkg -mindepth 1 -maxdepth 1 -type f); do
FILENAME=$(basename "$FILENAME")
cp "./build/pkg/${FILENAME}" "./build/dist/${REPO_NAME}_${VERSION}_${FILENAME}"
done
# Make the checksums.
pushd ./build/dist
shasum -a256 ./* > "./${REPO_NAME}_${VERSION}_SHA256SUMS"
popd
# Done
echo
echo "==> Results:"
ls -hl ./build/dist
exit 0

+ 0
- 53
abci/scripts/dist_build.sh View File

@ -1,53 +0,0 @@
#!/usr/bin/env bash
set -e
# Get the parent directory of where this script is.
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )"
# Change into that dir because we expect that.
cd "$DIR"
# Get the git commit
GIT_COMMIT="$(git rev-parse --short HEAD)"
GIT_DESCRIBE="$(git describe --tags --always)"
GIT_IMPORT="github.com/tendermint/abci/version"
# Determine the arch/os combos we're building for
XC_ARCH=${XC_ARCH:-"386 amd64 arm"}
XC_OS=${XC_OS:-"solaris darwin freebsd linux windows"}
# Make sure build tools are available.
make get_tools
# Get VENDORED dependencies
make get_vendor_deps
BINARY="abci-cli"
# Build!
echo "==> Building..."
"$(which gox)" \
-os="${XC_OS}" \
-arch="${XC_ARCH}" \
-osarch="!darwin/arm !solaris/amd64 !freebsd/amd64" \
-ldflags "-X ${GIT_IMPORT}.GitCommit='${GIT_COMMIT}' -X ${GIT_IMPORT}.GitDescribe='${GIT_DESCRIBE}'" \
-output "build/pkg/{{.OS}}_{{.Arch}}/$BINARY" \
-tags="${BUILD_TAGS}" \
github.com/tendermint/abci/cmd/$BINARY
# Zip all the files.
echo "==> Packaging..."
for PLATFORM in $(find ./build/pkg -mindepth 1 -maxdepth 1 -type d); do
OSARCH=$(basename "${PLATFORM}")
echo "--> ${OSARCH}"
pushd "$PLATFORM" >/dev/null 2>&1
zip "../${OSARCH}.zip" ./*
popd >/dev/null 2>&1
done
exit 0

+ 0
- 7
abci/scripts/publish.sh View File

@ -1,7 +0,0 @@
#! /bin/bash
# Get the version from the environment, or try to figure it out.
if [ -z $VERSION ]; then
VERSION=$(awk -F\" '/Version =/ { print $2; exit }' < version/version.go)
fi
aws s3 cp --recursive build/dist s3://tendermint/binaries/abci/v${VERSION} --acl public-read

+ 0
- 13
abci/tests/test_cover.sh View File

@ -1,13 +0,0 @@
#!/usr/bin/env bash
set -e
echo "" > coverage.txt
echo "==> Running unit tests"
for d in $(go list ./... | grep -v vendor); do
go test -race -coverprofile=profile.out -covermode=atomic "$d"
if [ -f profile.out ]; then
cat profile.out >> coverage.txt
rm profile.out
fi
done

+ 7
- 12
blockchain/reactor.go View File

@ -5,12 +5,13 @@ import (
"reflect" "reflect"
"time" "time"
"github.com/tendermint/go-amino"
amino "github.com/tendermint/go-amino"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/p2p"
sm "github.com/tendermint/tendermint/state" sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/libs/log"
) )
const ( const (
@ -174,7 +175,7 @@ func (bcR *BlockchainReactor) respondToPeer(msg *bcBlockRequestMessage,
// Receive implements Reactor by handling 4 types of messages (look below). // Receive implements Reactor by handling 4 types of messages (look below).
func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) { func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
msg, err := DecodeMessage(msgBytes)
msg, err := decodeMsg(msgBytes)
if err != nil { if err != nil {
bcR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes) bcR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
bcR.Switch.StopPeerForError(src, err) bcR.Switch.StopPeerForError(src, err)
@ -342,17 +343,11 @@ func RegisterBlockchainMessages(cdc *amino.Codec) {
cdc.RegisterConcrete(&bcStatusRequestMessage{}, "tendermint/mempool/StatusRequest", nil) cdc.RegisterConcrete(&bcStatusRequestMessage{}, "tendermint/mempool/StatusRequest", nil)
} }
// DecodeMessage decodes BlockchainMessage.
// TODO: ensure that bz is completely read.
func DecodeMessage(bz []byte) (msg BlockchainMessage, err error) {
func decodeMsg(bz []byte) (msg BlockchainMessage, err error) {
if len(bz) > maxMsgSize { if len(bz) > maxMsgSize {
return msg, fmt.Errorf("Msg exceeds max size (%d > %d)",
len(bz), maxMsgSize)
return msg, fmt.Errorf("Msg exceeds max size (%d > %d)", len(bz), maxMsgSize)
} }
err = cdc.UnmarshalBinaryBare(bz, &msg) err = cdc.UnmarshalBinaryBare(bz, &msg)
if err != nil {
err = cmn.ErrorWrap(err, "DecodeMessage() had bytes left over")
}
return return
} }


+ 7
- 0
config/config.go View File

@ -606,6 +606,12 @@ type InstrumentationConfig struct {
// Address to listen for Prometheus collector(s) connections. // Address to listen for Prometheus collector(s) connections.
PrometheusListenAddr string `mapstructure:"prometheus_listen_addr"` PrometheusListenAddr string `mapstructure:"prometheus_listen_addr"`
// Maximum number of simultaneous connections.
// If you want to accept more significant number than the default, make sure
// you increase your OS limits.
// 0 - unlimited.
MaxOpenConnections int `mapstructure:"max_open_connections"`
} }
// DefaultInstrumentationConfig returns a default configuration for metrics // DefaultInstrumentationConfig returns a default configuration for metrics
@ -614,6 +620,7 @@ func DefaultInstrumentationConfig() *InstrumentationConfig {
return &InstrumentationConfig{ return &InstrumentationConfig{
Prometheus: false, Prometheus: false,
PrometheusListenAddr: ":26660", PrometheusListenAddr: ":26660",
MaxOpenConnections: 3,
} }
} }


+ 6
- 0
config/toml.go View File

@ -262,6 +262,12 @@ prometheus = {{ .Instrumentation.Prometheus }}
# Address to listen for Prometheus collector(s) connections # Address to listen for Prometheus collector(s) connections
prometheus_listen_addr = "{{ .Instrumentation.PrometheusListenAddr }}" prometheus_listen_addr = "{{ .Instrumentation.PrometheusListenAddr }}"
# Maximum number of simultaneous connections.
# If you want to accept more significant number than the default, make sure
# you increase your OS limits.
# 0 - unlimited.
max_open_connections = {{ .Instrumentation.MaxOpenConnections }}
` `
/****** these are for test settings ***********/ /****** these are for test settings ***********/


+ 5
- 8
consensus/reactor.go View File

@ -9,11 +9,11 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
amino "github.com/tendermint/go-amino" amino "github.com/tendermint/go-amino"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/libs/log"
cstypes "github.com/tendermint/tendermint/consensus/types" cstypes "github.com/tendermint/tendermint/consensus/types"
cmn "github.com/tendermint/tendermint/libs/common"
tmevents "github.com/tendermint/tendermint/libs/events" tmevents "github.com/tendermint/tendermint/libs/events"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/p2p"
sm "github.com/tendermint/tendermint/state" sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
@ -80,7 +80,6 @@ func (conR *ConsensusReactor) OnStop() {
conR.BaseReactor.OnStop() conR.BaseReactor.OnStop()
conR.unsubscribeFromBroadcastEvents() conR.unsubscribeFromBroadcastEvents()
conR.conS.Stop() conR.conS.Stop()
conR.conS.Wait()
} }
// SwitchToConsensus switches from fast_sync mode to consensus mode. // SwitchToConsensus switches from fast_sync mode to consensus mode.
@ -184,7 +183,7 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
return return
} }
msg, err := DecodeMessage(msgBytes)
msg, err := decodeMsg(msgBytes)
if err != nil { if err != nil {
conR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes) conR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
conR.Switch.StopPeerForError(src, err) conR.Switch.StopPeerForError(src, err)
@ -1307,11 +1306,9 @@ func RegisterConsensusMessages(cdc *amino.Codec) {
cdc.RegisterConcrete(&ProposalHeartbeatMessage{}, "tendermint/ProposalHeartbeat", nil) cdc.RegisterConcrete(&ProposalHeartbeatMessage{}, "tendermint/ProposalHeartbeat", nil)
} }
// DecodeMessage decodes the given bytes into a ConsensusMessage.
func DecodeMessage(bz []byte) (msg ConsensusMessage, err error) {
func decodeMsg(bz []byte) (msg ConsensusMessage, err error) {
if len(bz) > maxMsgSize { if len(bz) > maxMsgSize {
return msg, fmt.Errorf("Msg exceeds max size (%d > %d)",
len(bz), maxMsgSize)
return msg, fmt.Errorf("Msg exceeds max size (%d > %d)", len(bz), maxMsgSize)
} }
err = cdc.UnmarshalBinaryBare(bz, &msg) err = cdc.UnmarshalBinaryBare(bz, &msg)
return return


+ 0
- 99
crypto/Makefile View File

@ -1,99 +0,0 @@
GOTOOLS = \
github.com/golang/dep/cmd/dep \
# gopkg.in/alecthomas/gometalinter.v2 \
GOTOOLS_CHECK = dep #gometalinter.v2
all: check get_vendor_deps build test install
check: check_tools
########################################
### Build
# Command to generate the workd list (kept here for documentation purposes only):
wordlist:
# To re-generate wordlist.go run:
# go-bindata -ignore ".*\.go" -o keys/words/bip39/wordlist.go -pkg "wordlist" keys/bip39/wordlist/...
build: wordlist
# Nothing else to build!
install:
# Nothing to install!
########################################
### Tools & dependencies
check_tools:
@# https://stackoverflow.com/a/25668869
@echo "Found tools: $(foreach tool,$(GOTOOLS_CHECK),\
$(if $(shell which $(tool)),$(tool),$(error "No $(tool) in PATH")))"
get_tools:
@echo "--> Installing tools"
go get -u -v $(GOTOOLS)
#@gometalinter.v2 --install
update_tools:
@echo "--> Updating tools"
@go get -u $(GOTOOLS)
get_vendor_deps:
@rm -rf vendor/
@echo "--> Running dep ensure"
@dep ensure
########################################
### Testing
test:
CGO_ENABLED=0 go test -p 1 $(shell go list ./... | grep -v vendor)
########################################
### Formatting, linting, and vetting
fmt:
@go fmt ./...
metalinter:
@echo "==> Running linter"
gometalinter.v2 --vendor --deadline=600s --disable-all \
--enable=maligned \
--enable=deadcode \
--enable=goconst \
--enable=goimports \
--enable=gosimple \
--enable=ineffassign \
--enable=megacheck \
--enable=misspell \
--enable=staticcheck \
--enable=safesql \
--enable=structcheck \
--enable=unconvert \
--enable=unused \
--enable=varcheck \
--enable=vetshadow \
./...
#--enable=gas \
#--enable=dupl \
#--enable=errcheck \
#--enable=gocyclo \
#--enable=golint \ <== comments on anything exported
#--enable=gotype \
#--enable=interfacer \
#--enable=unparam \
#--enable=vet \
metalinter_all:
protoc $(INCLUDE) --lint_out=. types/*.proto
gometalinter.v2 --vendor --deadline=600s --enable-all --disable=lll ./...
# 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
.PHONEY: check build install check_tools get_tools update_tools get_vendor_deps test fmt metalinter metalinter_all

+ 4
- 5
docs/README.md View File

@ -11,18 +11,17 @@ replicates it on many machines. In other words, a blockchain.
Tendermint requires an application running over the Application Blockchain Tendermint requires an application running over the Application Blockchain
Interface (ABCI) - and comes packaged with an example application to do so. Interface (ABCI) - and comes packaged with an example application to do so.
Follow the [installation instructions](./install) to get up and running
quickly. For more details on [using tendermint](./using-tendermint) see that
Follow the [installation instructions](./introduction/install) to get up and running
quickly. For more details on [using tendermint](./tendermint-core/using-tendermint) see that
and the following sections. and the following sections.
## Networks ## Networks
Testnets can be setup manually on one or more machines, or automatically on one Testnets can be setup manually on one or more machines, or automatically on one
or more machine, using a variety of methods described in the [deploy testnets or more machine, using a variety of methods described in the [deploy testnets
section](./deploy-testnets). For more information (and to join) about the
Cosmos Network testnets, see [here](/getting-started/full-node.md).
section](./networks/deploy-testnets).
## Application Development ## Application Development
The first step to building application on Tendermint is to [install The first step to building application on Tendermint is to [install
ABCI-CLI](./getting-started) and play with the example applications.
ABCI-CLI](./app-dev/getting-started) and play with the example applications.

docs/abci-cli.md → docs/app-dev/abci-cli.md View File


docs/abci-spec.md → docs/app-dev/abci-spec.md View File


docs/app-architecture.md → docs/app-dev/app-architecture.md View File


docs/app-development.md → docs/app-dev/app-development.md View File


+ 213
- 0
docs/app-dev/ecosystem.json View File

@ -0,0 +1,213 @@
{
"abciApps": [
{
"name": "Cosmos SDK",
"url": "https://github.com/cosmos/cosmos-sdk",
"language": "Go",
"author": "Cosmos",
"description":
"A prototypical account based crypto currency state machine supporting plugins"
},
{
"name": "cb-ledger",
"url": "https://github.com/block-finance/cpp-abci",
"language": "C++",
"author": "Block Finance",
"description":
"Custodian Bank Ledger, integrating central banking with the blockchains of tomorrow"
},
{
"name": "Clearchain",
"url": "https://github.com/tendermint/clearchain",
"language": "Go",
"author": "FXCLR",
"description":
"Application to manage a distributed ledger for money transfers that support multi-currency accounts"
},
{
"name": "Ethermint",
"url": "https://github.com/tendermint/ethermint",
"language": "Go",
"author": "Tendermint",
"description": "The go-ethereum state machine run as an ABCI app"
},
{
"name": "Merkle AVL Tree",
"url": "https://github.com/tendermint/merkleeyes",
"language": "Go",
"author": "Tendermint",
"description": "Tendermint IAVL tree implemented as an ABCI app"
},
{
"name": "Burrow",
"url": "https://github.com/hyperledger/burrow",
"language": "Go",
"author": "Monax Industries",
"description":
"Ethereum Virtual Machine augmented with native permissioning scheme and global key-value store"
},
{
"name": "Merkle AVL Tree",
"url": "https://github.com/jTMSP/MerkleTree",
"language": "Java",
"author": "jTMSP",
"description": "Tendermint IAVL tree implemented as an ABCI app"
},
{
"name": "TMChat",
"url": "https://github.com/wolfposd/TMChat",
"language": "Java",
"author": "jTMSP",
"description": "P2P chat using Tendermint"
},
{
"name": "Comit",
"url": "https://github.com/zballs/comit",
"language": "Go",
"author": "Zach Balder",
"description": "Public service reporting and tracking"
},
{
"name": "Passchain",
"url": "https://github.com/trusch/passchain",
"language": "Go",
"author": "trusch",
"description":
"Tool to securely store and share passwords, tokens and other short secrets"
},
{
"name": "Passwerk",
"url": "https://github.com/rigelrozanski/passwerk",
"language": "Go",
"author": "Rigel Rozanski",
"description": "Encrypted storage web-utility backed by Tendermint"
},
{
"name": "py-tendermint",
"url": "https://github.com/davebryson/py-tendermint",
"language": "Python",
"author": "Dave Bryson",
"description":
"A Python microframework for building blockchain applications with Tendermint"
},
{
"name": "Stratumn SDK",
"url": "https://github.com/stratumn/sdk",
"language": "Go",
"author": "Stratumn",
"description": "SDK for Proof-of-Process networks"
},
{
"name": "Lotion",
"url": "https://github.com/keppel/lotion",
"language": "Javascript",
"author": "Judd Keppel",
"description":
"A Javascript microframework for building blockchain applications with Tendermint"
},
{
"name": "Tendermint Blockchain Chat App",
"url": "https://github.com/SaifRehman/tendermint-chat-app/",
"language": "Javascript",
"author": "Saif Rehman",
"description":
"This is a minimal chat application based on Tendermint using Lotion.js in 30 lines of code!. It also includes web/mobile application built using Ionic 3."
},
{
"name": "BigchainDB",
"url": "https://github.com/bigchaindb/bigchaindb",
"language": "Python",
"author": "BigchainDB GmbH and the BigchainDB community",
"description": "Blockchain database"
},
{
"name": "Mint",
"url": "https://github.com/Hashnode/mint",
"language": "Go",
"author": "Hashnode",
"description": "Build blockchain-powered social apps"
}
],
"abciServers": [
{
"name": "abci",
"url": "https://github.com/tendermint/abci",
"language": "Go",
"author": "Tendermint"
},
{
"name": "js-abci",
"url": "https://github.com/tendermint/js-abci",
"language": "Javascript",
"author": "Tendermint"
},
{
"name": "cpp-tmsp",
"url": "https://github.com/mdyring/cpp-tmsp",
"language": "C++",
"author": "Martin Dyring"
},
{
"name": "jabci",
"url": "https://github.com/jTendermint/jabci",
"language": "Java",
"author": "jTendermint"
},
{
"name": "ocaml-tmsp",
"url": "https://github.com/zballs/ocaml-tmsp",
"language": "Ocaml",
"author": "Zach Balder"
},
{
"name": "abci_server",
"url": "https://github.com/KrzysiekJ/abci_server",
"language": "Erlang",
"author": "Krzysztof Jurewicz"
},
{
"name": "py-abci",
"url": "https://github.com/davebryson/py-abci",
"language": "Python",
"author": "Dave Bryson"
},
{
"name": "Spearmint",
"url": "https://github.com/dennismckinnon/spearmint",
"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 "
}
]
}

docs/ecosystem.md → docs/app-dev/ecosystem.md View File


docs/getting-started.md → docs/app-dev/getting-started.md View File


docs/indexing-transactions.md → docs/app-dev/indexing-transactions.md View File


docs/subscribing-to-events-via-websocket.md → docs/app-dev/subscribing-to-events-via-websocket.md View File


BIN
docs/images/tmint-logo-blue.png View File

Before After
Width: 2048  |  Height: 2048  |  Size: 52 KiB

+ 250
- 0
docs/interviews/tendermint-bft.md View File

@ -0,0 +1,250 @@
# Interview Transcript with Tendermint core researcher, Zarko Milosevic, by Chjango
**ZM**: Regarding leader election, it's round robin, but a weighted one. You
take into account the amount of bonded tokens. Depending on how much weight
they have of voting power, they would be elected more frequently. So we do
rotate, but just the guys who are having more voting power would be elected
more frequently. We are having 4 validators, and 1 of them have 2 times more
voting power, they have 2 times more elected as a leader.
**CC**: 2x more absolute voting power or probabilistic voting power?
**ZM**: It's actually very deterministic. It's not probabilistic at all. See
[Tendermint proposal election specification][1]. In Tendermint, there is no
pseudorandom leader election. It's a deterministic protocol. So leader election
is a built-in function in the code, so you know exactly—depending on the voting
power in the validator set, you'd know who exactly would be the leader in round
x, x + 1, and so on. There is nothing random there; we are not trying to hide
who would be the leader. It's really well known. It's just that there is a
function, it's a mathematical function, and it's just basically—it's kind of an
implementation detail—it starts from the voting power, and when you are
elected, you get decreased some number, and in each round you keep increasing
depending on your voting power, so that you are elected after k rounds again.
But knowing the validator set and the voting power, it's very simple function,
you can calculate yourself to know exactly who would be next. For each round,
this function will return you the leader for that round. In every round, we do
this computation. It's all part of the same flow. It enforces the properties
which are: proportional to your voting power, you will be elected, and we keep
changing the leaders. So it can't happen to have one guy being more elected
than other guys, if they have the same voting power. So one time it will be guy
B, and next time it will be guy B1. So it's not random.
**CC**: Assuming the validator set remains unchanged for a month, then if you
run this function, are you able to know exactly who is going to go for that
entire month?
**ZM**: Yes.
**CC**: What're the attack scenarios for this?
**ZM**: This is something which is easily attacked by people who argue that
Tendermint is not decentralized enough. They say that by knowing the leader,
you can DDoS the leader. And by DDoSing the leader, you are able to stop the
progress. Because it's true. If you would be able to DDoS the leader, the
leader would not be able to propose and then effectively will not be making
progress. How we are addressing this thing is Sentry Architecture. So the
validator—or at least a proper validator—will never be available. You don't
know the ip address of the validator. You are never able to open the connection
to the validator. So validator is spawning sentry nodes and this is the single
administration domain and there is only connection from validator in the sense
of sentry nodes. And ip address of validator is not shared in the p2p network.
It’s completely private. This is our answer to DDoS attack. By playing clever
at this sentry node architecture and spawning additional sentry nodes in case,
for ex your sentry nodes are being DDoS’d, bc your sentry nodes are public,
then you will be able to connect to sentry nodes. this is where we will expect
the validator to be clever enough that so that in case they are DDoS’d at the
sentry level, they will spawn a different sentry node and then you communicate
through them. We are in a sense pushing the responsibility on the validator.
**CC**: So if I understand this correctly, the public identity of the validator
doesn’t even matter because that entity can obfuscate where their real full
nodes reside via a proxy through this sentry architecture.
**ZM**: Exactly. So you do know what is the address or identity of the validator
but you don’t know the network address of it; you’re not able to attack it
because you don’t know where they are. They are completely obfuscated by the
sentry nodes. There is now, if you really want to figure out….There is the
Tendermint protocol, the structure of the protocol is not fully decentralized
in the sense that the flow of information is going from the round proposer, or
the round coordinator, to other nodes, and then after they receive this it’s
basically like [inaudible: “O to 1”]. So by tracking where this information is
coming from, you might be able to identify who are the sentry nodes behind it.
So if you are doing some network analysis, you might be able to deduce
something. If the thing would be completely stuck, where the validator would
never change their sentry nodes or ip addresses of sentry nodes, it could be
possible to deduce something. This is where economic game comes into play. We
are doing an economics game there. We say that it’s a validator business. If
they are not able to hide themselves well enough, they’ll be DDoS’d and they
will be kicked out of the active validator set. So it’s in their interest.
[Proposer Selection Procedure in Tendermint][1]. This is how it should work no
matter what implementation.
**CC**: Going back to the proposer, lets say the validator does get DDoS’d, then
the proposer goes down. What happens?
**ZM**: How the proposal mechanism works—there’s nothing special there—it goes
through a sequence of rounds. Normal execution of Tendermint is that for each
height, we are going through a sequence of rounds, starting from round 0, and
then we are incrementing through the rounds. The nodes are moving through the
rounds as part of normal procedure until they decide to commit. In case you
have one proposer—the proposer of a single round—being DDoS’d, we will probably
not decide in that round, because he will not be able to send his proposal. So
we will go to the next round, and hopefully the next proposer will be able to
communicate with the validators and then we’ll decide in the next round.
**CC**: Are there timeouts between one round to another, if a round gets
skipped?
**ZM**: There are timeouts. It’s a bit more complex. I think we have 5 timeouts.
We may be able to simplify this a bit. What is important to understand is: The
only condition which needs to be satisfied so we can go to the next round is
that your validator is able to communicate with more than 2/3rds of voting
power. To be able to move to the next round, you need to receive more than
2/3rd of voting power equivalent of pre-commit messages.
We have two kinds of messages: 1) Proposal: Where the current round proposer is
suggesting how the next block should look like. This is first one. Every round
starts with proposer sending a proposal. And then there are two more rounds of
voting, where the validator is trying to agree whether they will commit the
proposal or not. And the first of such vote messages is called `pre-vote` and
the second one is `pre-commit`. Now, to be able to move between steps, between
a `pre-vote` and `pre-commit` step, you need to receive enough number of
messages where if message is sent by validator A, then also this message has a
weight, or voting power which is equal to the voting power of the validator who
sent this message. Before you receive more than 2/3 of voting power messages, you are not
able to move to the higher round. Only when you receive more than 2/3 of
messages, you actually start the timeout. The timeout is happening only after
you receive enough messages. And it happens because of the asynchrony of the
message communication so you give more time to guys with this timeout to
receive some messages which are maybe delayed.
**CC**: In this way that you just described via the whole network gossiping
before we commit a block, that is what makes Tendermint BFT deterministic in a
partially synchronous setting vs Bitcoin which has synchrony assumptions
whereby blocks are first mined and then gossiped to the network.
**ZM**: It's true that in Bitcoin, this is where the synchrony assumption comes
to play because if they're not able to communicate timely, they are not able to
converge to a single longest chain. Why are they not able to decrease timeout
in Bitcoin? Because if they would decrease, there would be so many forks that
they won't be able to converge to a single chain. By increasing this
complexity and the block time, they're able to have not so many forks. This is
effectively the timing assumption—the block duration in a sense because it's
enough time so that the decided block is propagated through the network before
someone else start deciding on the same block and creating forks. It's very
different from the consensus algorithms in a distributed computing setup where
Tendermint fits. In Tendermint, where we talk about the timing dependency, they
are really part of this 3-communication step protocol I just explained. We have
the following assumption: If the good guys are not able to communicate timely
and reliably without having message loss within a round, the Tendermint will
not make progress—it will not be making blocks. So if you are in a completely
asynchronous network where messages get lost or delayed unpredictably,
Tendermint will not make progress, it will not create forks, but it will not
decide, it will not tell you what is the next block. For termination, it's a
liveness property of consensus. It's a guarantee to decide. We do need timing
assumptions. Within a round, correct validators are able to communicate to each
other the consensus messages, not the transactions, but consensus messages.
They need to communicate in a timely and reliable fashion. But this doesn't
need to hold forever. It's just that what we are assuming when we say it's a
partially synchronous system, we assume that the system will be going through a
period of asynchrony, where we don't have this guarantee; the messages will be
delayed or some will be lost and then will not make progress for some period of
time, or we're not guaranteed to make progress. And the period of synchrony
where these guarantees hold. And if we think about internet, internet is best
described using such a model. Sometimes when we send a message to SF to
Belgrade, it takes 100 ms, sometimes it takes 300 ms, sometimes it takes 1 s.
But in most cases, it takes 100 ms or less than this.
There is one thing which would be really nice if you understand it. In a global
wide area network, we can't make assumption on the communication unless we are
very conservative about this. If you want to be very fast, then we can't make
assumption and say we'll be for sure communicating with 1 ms communication
delay. Because of the complexity and various congestion issues on the network,
it might happen that during a short period of time, this doesn't hold. If this
doesn't hold and you depend on this for correctness of your protocol, you will
have a fork. So the partially synchronous protocol, most of them like
Tendermint, they don't depend on the timing assumption from the internet for
correctness. This is where we state: safety always. So we never make a fork no
matter how bad our estimates about the internet communication delays are. We'll
never make a fork, but we do make some assumptions, and these assumptions are
built-in our timeouts in our protocol which are actually adaptive. So we are
adapting to the current condition and this is where we're saying...We do assume
some properties, or some communication delays, to eventually hold on the
network. During this period, we guarantee that we will be deciding and
committing blocks. And we will be doing this very fast. We will be basically on
the speed of the current network.
**CC**: We make liveness assumptions based on the integrity of the validator
businesses, assuming they're up and running fine.
**ZM**: This is where we are saying, the protocol will be live if we have at
most 1/3, or a bit less than 1/3, of faulty validators. Which means that all
other guys should be online and available. This is also for liveness. This is
related to the condition that we are not able to make progress in rounds if we
don't receive enough messages. If half of our voting power, or half of our
validators are down, we don't have enough messages, so the protocol is
completely blocked. It doesn't make progress in a round, which means it's not
able to be signed. So it's completely critical for Tendermint that we make
progress in rounds. It's like breathing. Tendermint is breathing. If there is
no progress, it's dead; it's blocked, we're not able to breathe, that's why
we're not able to make progress.
**CC**: How does Tendermint compare to other consensus algos?
**ZM**: Tendermint is a very interesting protocol. From an academic point of
view, I'm convinced that there is value there. Hopefully, we prove it by
publishing it on some good conference. What is novel is, if we compare first
Tendermint to this existing BFT problem, it's a continuation of academic
research on BFT consensus. What is novel in Tendermint is that it somehow
merges consensus protocol with gossip. This is completely novel idea.
Originally, in BFT, people were assuming the single administration domain,
small number of nodes, local area network, 4-7 nodes max. If you look at the
research paper, 99% of them have this kind of setup. Wide area was studied but
there is significantly less work in wide area networks. No one studied how to
scale those protocols to hundreds or thousands of nodes before blockchain. It
was always a single administration domain. So in Tendermint now, you are able
to reach consensus among different administration domains which are potentially
hundreds of them in wide area network. The system model is potentially harder
because we have more nodes and wide area network. The second thing is that:
normally, in bft protocols, the protocol itself are normally designed in a way
that has two phases, or two parts. The one which is called normal case, which
is normally quite simple, in this normal case. In spite of some failures, which
are part of the normal execution of the protocol, like for example leader
crashes or leader being DDoS'd, they need to go through a quite complex
protocol, which is like being called view change or leader election or
whatever. These two parts of the same protocol are having quite different
complexity. And most of the people only understand this normal case. In
Tendermint, there is no this difference. We have only one protocol, there are
not two protocols. It's always the same steps and they are much closer to the
normal case than this complex view change protocol.
_This is a bit too technical but this is on a high level things to remember,
that: The system it addresses it's harder than the others and the algorithm
complexity in Tendermint is simpler._ The initial goal of Jae and Bucky which
is inspired by Raft, is that it's simpler so normal engineers could understand.
**CC**: Can you expand on the termination requirement?
_Important point about Liveness in Tendermint_
**ZM**: In Tendermint, we are saying, for termination, we are making assumption
that the system is partially synchronous. And in a partially synchronous system
model, we are able to mathematically prove that the protocol will make
decisions; it will decide.
**CC**: What is a persistent peer?
**ZM**: It's a list of peer identities, which you will try to establish
connection to them, in case connection is broken, Tendermint will automatically
try to reestablish connection. These are important peers, you will really try
persistently to establish connection to them. For other peers, you just drop it
and try from your address book to connect to someone else. The address book is a
list of peers which you discover that they exist, because we are talking about a
very dynamic network—so the nodes are coming and going away—and the gossiping
protocol is discovering new nodes and gossiping them around. So every node will
keep the list of new nodes it discovers, and when you need to establish
connection to a peer, you'll look to address book and get some addresses from
there. There's categorization/ranking of nodes there.
[1]: https://github.com/tendermint/tendermint/blob/master/docs/spec/reactors/consensus/proposer-selection.md

docs/install.md → docs/introduction/install.md View File


docs/introduction.md → docs/introduction/introduction.md View File


docs/examples/getting-started.md → docs/introduction/quick-start.md View File


docs/deploy-testnets.md → docs/networks/deploy-testnets.md View File


docs/terraform-and-ansible.md → docs/networks/terraform-and-ansible.md View File


docs/determinism.md → docs/research/determinism.md View File


docs/transactional-semantics.md → docs/research/transactional-semantics.md View File


docs/specification/configuration.md → docs/tendermint-core/configuration.md View File


docs/how-to-read-logs.md → docs/tendermint-core/how-to-read-logs.md View File


docs/metrics.md → docs/tendermint-core/metrics.md View File


docs/specification/rpc.md → docs/tendermint-core/rpc.md View File


docs/running-in-production.md → docs/tendermint-core/running-in-production.md View File


docs/using-tendermint.md → docs/tendermint-core/using-tendermint.md View File


+ 80
- 0
docs/tools/benchmarking.md View File

@ -0,0 +1,80 @@
# tm-bench
Tendermint blockchain benchmarking tool:
- https://github.com/tendermint/tools/tree/master/tm-bench
For example, the following:
```
tm-bench -T 10 -r 1000 localhost:26657
```
will output:
```
Stats Avg StdDev Max Total
Txs/sec 818 532 1549 9000
Blocks/sec 0.818 0.386 1 9
```
## Quick Start
[Install Tendermint](../introduction/install)
This currently is setup to work on tendermint's develop branch. Please ensure
you are on that. (If not, update `tendermint` and `tmlibs` in gopkg.toml to use
the master branch.)
then run:
```
tendermint init
tendermint node --proxy_app=kvstore
```
```
tm-bench localhost:26657
```
with the last command being in a seperate window.
## Usage
```
tm-bench [-c 1] [-T 10] [-r 1000] [-s 250] [endpoints]
Examples:
tm-bench localhost:26657
Flags:
-T int
Exit after the specified amount of time in seconds (default 10)
-c int
Connections to keep open per endpoint (default 1)
-r int
Txs per second to send in a connection (default 1000)
-s int
Size per tx in bytes
-v Verbose output
```
## How stats are collected
These stats are derived by having each connection send transactions at the
specified rate (or as close as it can get) for the specified time. After the
specified time, it iterates over all of the blocks that were created in that
time. The average and stddev per second are computed based off of that, by
grouping the data by second.
To send transactions at the specified rate in each connection, we loop
through the number of transactions. If its too slow, the loop stops at one second.
If its too fast, we wait until the one second mark ends. The transactions per
second stat is computed based off of what ends up in the block.
Each of the connections is handled via two separate goroutines.
## Development
```
make get_vendor_deps
make test
```

+ 92
- 0
docs/tools/monitoring.md View File

@ -0,0 +1,92 @@
# tm-monitor
Tendermint blockchain monitoring tool; watches over one or more nodes,
collecting and providing various statistics to the user:
- https://github.com/tendermint/tools/tree/master/tm-monitor
## Quick Start
### Docker
Assuming your application is running in another container with the name
`app`:
```
docker run -it --rm -v "/tmp:/tendermint" tendermint/tendermint init
docker run -it --rm -v "/tmp:/tendermint" -p "26657:26657" --name=tm --link=app tendermint/tendermint node --proxy_app=tcp://app:26658
docker run -it --rm -p "26670:26670" --link=tm tendermint/monitor tm:26657
```
If you don't have an application yet, but still want to try monitor out,
use `kvstore`:
```
docker run -it --rm -v "/tmp:/tendermint" tendermint/tendermint init
docker run -it --rm -v "/tmp:/tendermint" -p "26657:26657" --name=tm tendermint/tendermint node --proxy_app=kvstore
```
```
docker run -it --rm -p "26670:26670" --link=tm tendermint/monitor tm:26657
```
### Using Binaries
[Install Tendermint](https://github.com/tendermint/tendermint#install)
then run:
```
tendermint init
tendermint node --proxy_app=kvstore
```
```
tm-monitor localhost:26657
```
with the last command being in a seperate window.
## Usage
```
tm-monitor [-v] [-no-ton] [-listen-addr="tcp://0.0.0.0:26670"] [endpoints]
Examples:
# monitor single instance
tm-monitor localhost:26657
# monitor a few instances by providing comma-separated list of RPC endpoints
tm-monitor host1:26657,host2:26657
Flags:
-listen-addr string
HTTP and Websocket server listen address (default "tcp://0.0.0.0:26670")
-no-ton
Do not show ton (table of nodes)
-v verbose logging
```
### RPC UI
Run `tm-monitor` and visit http://localhost:26670 You should see the
list of the available RPC endpoints:
```
http://localhost:26670/status
http://localhost:26670/status/network
http://localhost:26670/monitor?endpoint=_
http://localhost:26670/status/node?name=_
http://localhost:26670/unmonitor?endpoint=_
```
The API is available as GET requests with URI encoded parameters, or as
JSONRPC POST requests. The JSONRPC methods are also exposed over
websocket.
## Development
```
make get_tools
make get_vendor_deps
make test
```

+ 5
- 7
evidence/reactor.go View File

@ -5,10 +5,10 @@ import (
"reflect" "reflect"
"time" "time"
"github.com/tendermint/go-amino"
amino "github.com/tendermint/go-amino"
clist "github.com/tendermint/tendermint/libs/clist" clist "github.com/tendermint/tendermint/libs/clist"
"github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
) )
@ -73,7 +73,7 @@ func (evR *EvidenceReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
// Receive implements Reactor. // Receive implements Reactor.
// It adds any received evidence to the evpool. // It adds any received evidence to the evpool.
func (evR *EvidenceReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) { func (evR *EvidenceReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
msg, err := DecodeMessage(msgBytes)
msg, err := decodeMsg(msgBytes)
if err != nil { if err != nil {
evR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes) evR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
evR.Switch.StopPeerForError(src, err) evR.Switch.StopPeerForError(src, err)
@ -204,11 +204,9 @@ func RegisterEvidenceMessages(cdc *amino.Codec) {
"tendermint/evidence/EvidenceListMessage", nil) "tendermint/evidence/EvidenceListMessage", nil)
} }
// DecodeMessage decodes a byte-array into a EvidenceMessage.
func DecodeMessage(bz []byte) (msg EvidenceMessage, err error) {
func decodeMsg(bz []byte) (msg EvidenceMessage, err error) {
if len(bz) > maxMsgSize { if len(bz) > maxMsgSize {
return msg, fmt.Errorf("Msg exceeds max size (%d > %d)",
len(bz), maxMsgSize)
return msg, fmt.Errorf("Msg exceeds max size (%d > %d)", len(bz), maxMsgSize)
} }
err = cdc.UnmarshalBinaryBare(bz, &msg) err = cdc.UnmarshalBinaryBare(bz, &msg)
return return


+ 0
- 137
libs/Makefile View File

@ -1,137 +0,0 @@
GOTOOLS = \
github.com/golang/dep/cmd/dep \
github.com/golang/protobuf/protoc-gen-go \
github.com/square/certstrap
# github.com/alecthomas/gometalinter.v2 \
GOTOOLS_CHECK = dep gometalinter.v2 protoc protoc-gen-go
INCLUDE = -I=. -I=${GOPATH}/src
all: check get_vendor_deps protoc grpc_dbserver build test install metalinter
check: check_tools
########################################
### Build
protoc:
## If you get the following error,
## "error while loading shared libraries: libprotobuf.so.14: cannot open shared object file: No such file or directory"
## See https://stackoverflow.com/a/25518702
protoc $(INCLUDE) --go_out=plugins=grpc:. common/*.proto
@echo "--> adding nolint declarations to protobuf generated files"
@awk '/package common/ { print "//nolint: gas"; print; next }1' common/types.pb.go > common/types.pb.go.new
@mv common/types.pb.go.new common/types.pb.go
build:
# Nothing to build!
install:
# Nothing to install!
########################################
### Tools & dependencies
check_tools:
@# https://stackoverflow.com/a/25668869
@echo "Found tools: $(foreach tool,$(GOTOOLS_CHECK),\
$(if $(shell which $(tool)),$(tool),$(error "No $(tool) in PATH")))"
get_tools:
@echo "--> Installing tools"
go get -u -v $(GOTOOLS)
# @gometalinter.v2 --install
get_protoc:
@# https://github.com/google/protobuf/releases
curl -L https://github.com/google/protobuf/releases/download/v3.4.1/protobuf-cpp-3.4.1.tar.gz | tar xvz && \
cd protobuf-3.4.1 && \
DIST_LANG=cpp ./configure && \
make && \
make install && \
cd .. && \
rm -rf protobuf-3.4.1
update_tools:
@echo "--> Updating tools"
@go get -u $(GOTOOLS)
get_vendor_deps:
@rm -rf vendor/
@echo "--> Running dep ensure"
@dep ensure
########################################
### Testing
gen_certs: clean_certs
## Generating certificates for TLS testing...
certstrap init --common-name "tendermint.com" --passphrase ""
certstrap request-cert -ip "::" --passphrase ""
certstrap sign "::" --CA "tendermint.com" --passphrase ""
mv out/::.crt out/::.key db/remotedb
clean_certs:
## Cleaning TLS testing certificates...
rm -rf out
rm -f db/remotedb/::.crt db/remotedb/::.key
test: gen_certs
GOCACHE=off go test -tags gcc $(shell go list ./... | grep -v vendor)
make clean_certs
test100:
@for i in {1..100}; do make test; done
########################################
### Formatting, linting, and vetting
fmt:
@go fmt ./...
metalinter:
@echo "==> Running linter"
gometalinter.v2 --vendor --deadline=600s --disable-all \
--enable=deadcode \
--enable=goconst \
--enable=goimports \
--enable=gosimple \
--enable=ineffassign \
--enable=megacheck \
--enable=misspell \
--enable=staticcheck \
--enable=safesql \
--enable=structcheck \
--enable=unconvert \
--enable=unused \
--enable=varcheck \
--enable=vetshadow \
./...
#--enable=maligned \
#--enable=gas \
#--enable=aligncheck \
#--enable=dupl \
#--enable=errcheck \
#--enable=gocyclo \
#--enable=golint \ <== comments on anything exported
#--enable=gotype \
#--enable=interfacer \
#--enable=unparam \
#--enable=vet \
metalinter_all:
protoc $(INCLUDE) --lint_out=. types/*.proto
gometalinter.v2 --vendor --deadline=600s --enable-all --disable=lll ./...
# 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 protoc build check_tools get_tools get_protoc update_tools get_vendor_deps test fmt metalinter metalinter_all gen_certs clean_certs
grpc_dbserver:
protoc -I db/remotedb/proto/ db/remotedb/proto/defs.proto --go_out=plugins=grpc:db/remotedb/proto

+ 3
- 5
mempool/reactor.go View File

@ -78,7 +78,7 @@ func (memR *MempoolReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
// Receive implements Reactor. // Receive implements Reactor.
// It adds any received transactions to the mempool. // It adds any received transactions to the mempool.
func (memR *MempoolReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) { func (memR *MempoolReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
msg, err := DecodeMessage(msgBytes)
msg, err := decodeMsg(msgBytes)
if err != nil { if err != nil {
memR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes) memR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
memR.Switch.StopPeerForError(src, err) memR.Switch.StopPeerForError(src, err)
@ -174,11 +174,9 @@ func RegisterMempoolMessages(cdc *amino.Codec) {
cdc.RegisterConcrete(&TxMessage{}, "tendermint/mempool/TxMessage", nil) cdc.RegisterConcrete(&TxMessage{}, "tendermint/mempool/TxMessage", nil)
} }
// DecodeMessage decodes a byte-array into a MempoolMessage.
func DecodeMessage(bz []byte) (msg MempoolMessage, err error) {
func decodeMsg(bz []byte) (msg MempoolMessage, err error) {
if len(bz) > maxMsgSize { if len(bz) > maxMsgSize {
return msg, fmt.Errorf("Msg exceeds max size (%d > %d)",
len(bz), maxMsgSize)
return msg, fmt.Errorf("Msg exceeds max size (%d > %d)", len(bz), maxMsgSize)
} }
err = cdc.UnmarshalBinaryBare(bz, &msg) err = cdc.UnmarshalBinaryBare(bz, &msg)
return return


+ 8
- 2
node/node.go View File

@ -8,6 +8,7 @@ import (
"net" "net"
"net/http" "net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
amino "github.com/tendermint/go-amino" amino "github.com/tendermint/go-amino"
@ -599,8 +600,13 @@ func (n *Node) startRPC() ([]net.Listener, error) {
// collectors on addr. // collectors on addr.
func (n *Node) startPrometheusServer(addr string) *http.Server { func (n *Node) startPrometheusServer(addr string) *http.Server {
srv := &http.Server{ srv := &http.Server{
Addr: addr,
Handler: promhttp.Handler(),
Addr: addr,
Handler: promhttp.InstrumentMetricHandler(
prometheus.DefaultRegisterer, promhttp.HandlerFor(
prometheus.DefaultGatherer,
promhttp.HandlerOpts{MaxRequestsInFlight: n.config.Instrumentation.MaxOpenConnections},
),
),
} }
go func() { go func() {
if err := srv.ListenAndServe(); err != http.ErrServerClosed { if err := srv.ListenAndServe(); err != http.ErrServerClosed {


+ 6
- 8
p2p/pex/pex_reactor.go View File

@ -206,7 +206,7 @@ func (r *PEXReactor) RemovePeer(p Peer, reason interface{}) {
// Receive implements Reactor by handling incoming PEX messages. // Receive implements Reactor by handling incoming PEX messages.
func (r *PEXReactor) Receive(chID byte, src Peer, msgBytes []byte) { func (r *PEXReactor) Receive(chID byte, src Peer, msgBytes []byte) {
msg, err := DecodeMessage(msgBytes)
msg, err := decodeMsg(msgBytes)
if err != nil { if err != nil {
r.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes) r.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
r.Switch.StopPeerForError(src, err) r.Switch.StopPeerForError(src, err)
@ -287,7 +287,7 @@ func (r *PEXReactor) RequestAddrs(p Peer) {
return return
} }
r.requestsSent.Set(id, struct{}{}) r.requestsSent.Set(id, struct{}{})
p.Send(PexChannel, cdc.MustMarshalBinary(&pexRequestMessage{}))
p.Send(PexChannel, cdc.MustMarshalBinaryBare(&pexRequestMessage{}))
} }
// ReceiveAddrs adds the given addrs to the addrbook if theres an open // ReceiveAddrs adds the given addrs to the addrbook if theres an open
@ -324,7 +324,7 @@ func (r *PEXReactor) ReceiveAddrs(addrs []*p2p.NetAddress, src Peer) error {
// SendAddrs sends addrs to the peer. // SendAddrs sends addrs to the peer.
func (r *PEXReactor) SendAddrs(p Peer, netAddrs []*p2p.NetAddress) { func (r *PEXReactor) SendAddrs(p Peer, netAddrs []*p2p.NetAddress) {
p.Send(PexChannel, cdc.MustMarshalBinary(&pexAddrsMessage{Addrs: netAddrs}))
p.Send(PexChannel, cdc.MustMarshalBinaryBare(&pexAddrsMessage{Addrs: netAddrs}))
} }
// SetEnsurePeersPeriod sets period to ensure peers connected. // SetEnsurePeersPeriod sets period to ensure peers connected.
@ -670,13 +670,11 @@ func RegisterPexMessage(cdc *amino.Codec) {
cdc.RegisterConcrete(&pexAddrsMessage{}, "tendermint/p2p/PexAddrsMessage", nil) cdc.RegisterConcrete(&pexAddrsMessage{}, "tendermint/p2p/PexAddrsMessage", nil)
} }
// DecodeMessage implements interface registered above.
func DecodeMessage(bz []byte) (msg PexMessage, err error) {
func decodeMsg(bz []byte) (msg PexMessage, err error) {
if len(bz) > maxMsgSize { if len(bz) > maxMsgSize {
return msg, fmt.Errorf("Msg exceeds max size (%d > %d)",
len(bz), maxMsgSize)
return msg, fmt.Errorf("Msg exceeds max size (%d > %d)", len(bz), maxMsgSize)
} }
err = cdc.UnmarshalBinary(bz, &msg)
err = cdc.UnmarshalBinaryBare(bz, &msg)
return return
} }


+ 5
- 5
p2p/pex/pex_reactor_test.go View File

@ -134,11 +134,11 @@ func TestPEXReactorReceive(t *testing.T) {
size := book.Size() size := book.Size()
addrs := []*p2p.NetAddress{peer.NodeInfo().NetAddress()} addrs := []*p2p.NetAddress{peer.NodeInfo().NetAddress()}
msg := cdc.MustMarshalBinary(&pexAddrsMessage{Addrs: addrs})
msg := cdc.MustMarshalBinaryBare(&pexAddrsMessage{Addrs: addrs})
r.Receive(PexChannel, peer, msg) r.Receive(PexChannel, peer, msg)
assert.Equal(t, size+1, book.Size()) assert.Equal(t, size+1, book.Size())
msg = cdc.MustMarshalBinary(&pexRequestMessage{})
msg = cdc.MustMarshalBinaryBare(&pexRequestMessage{})
r.Receive(PexChannel, peer, msg) // should not panic. r.Receive(PexChannel, peer, msg) // should not panic.
} }
@ -154,7 +154,7 @@ func TestPEXReactorRequestMessageAbuse(t *testing.T) {
assert.True(t, sw.Peers().Has(peer.ID())) assert.True(t, sw.Peers().Has(peer.ID()))
id := string(peer.ID()) id := string(peer.ID())
msg := cdc.MustMarshalBinary(&pexRequestMessage{})
msg := cdc.MustMarshalBinaryBare(&pexRequestMessage{})
// first time creates the entry // first time creates the entry
r.Receive(PexChannel, peer, msg) r.Receive(PexChannel, peer, msg)
@ -191,7 +191,7 @@ func TestPEXReactorAddrsMessageAbuse(t *testing.T) {
assert.True(t, sw.Peers().Has(peer.ID())) assert.True(t, sw.Peers().Has(peer.ID()))
addrs := []*p2p.NetAddress{peer.NodeInfo().NetAddress()} addrs := []*p2p.NetAddress{peer.NodeInfo().NetAddress()}
msg := cdc.MustMarshalBinary(&pexAddrsMessage{Addrs: addrs})
msg := cdc.MustMarshalBinaryBare(&pexAddrsMessage{Addrs: addrs})
// receive some addrs. should clear the request // receive some addrs. should clear the request
r.Receive(PexChannel, peer, msg) r.Receive(PexChannel, peer, msg)
@ -303,7 +303,7 @@ func TestPEXReactorDoesNotAddPrivatePeersToAddrBook(t *testing.T) {
size := book.Size() size := book.Size()
addrs := []*p2p.NetAddress{peer.NodeInfo().NetAddress()} addrs := []*p2p.NetAddress{peer.NodeInfo().NetAddress()}
msg := cdc.MustMarshalBinary(&pexAddrsMessage{Addrs: addrs})
msg := cdc.MustMarshalBinaryBare(&pexAddrsMessage{Addrs: addrs})
pexR.Receive(PexChannel, peer, msg) pexR.Receive(PexChannel, peer, msg)
assert.Equal(t, size, book.Size()) assert.Equal(t, size, book.Size())


+ 52
- 14
rpc/lib/server/handlers.go View File

@ -18,9 +18,9 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
amino "github.com/tendermint/go-amino" amino "github.com/tendermint/go-amino"
types "github.com/tendermint/tendermint/rpc/lib/types"
cmn "github.com/tendermint/tendermint/libs/common" cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/log"
types "github.com/tendermint/tendermint/rpc/lib/types"
) )
// RegisterRPCFuncs adds a route for each function in the funcMap, as well as general jsonrpc and websocket handlers for all functions. // RegisterRPCFuncs adds a route for each function in the funcMap, as well as general jsonrpc and websocket handlers for all functions.
@ -294,7 +294,7 @@ func httpParamsToArgs(rpcFunc *RPCFunc, cdc *amino.Codec, r *http.Request) ([]re
continue continue
} }
v, err, ok := nonJSONToArg(cdc, argType, arg)
v, err, ok := nonJSONStringToArg(cdc, argType, arg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -303,7 +303,7 @@ func httpParamsToArgs(rpcFunc *RPCFunc, cdc *amino.Codec, r *http.Request) ([]re
continue continue
} }
values[i], err = _jsonStringToArg(cdc, argType, arg)
values[i], err = jsonStringToArg(cdc, argType, arg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -312,26 +312,64 @@ func httpParamsToArgs(rpcFunc *RPCFunc, cdc *amino.Codec, r *http.Request) ([]re
return values, nil return values, nil
} }
func _jsonStringToArg(cdc *amino.Codec, ty reflect.Type, arg string) (reflect.Value, error) {
v := reflect.New(ty)
err := cdc.UnmarshalJSON([]byte(arg), v.Interface())
func jsonStringToArg(cdc *amino.Codec, rt reflect.Type, arg string) (reflect.Value, error) {
rv := reflect.New(rt)
err := cdc.UnmarshalJSON([]byte(arg), rv.Interface())
if err != nil { if err != nil {
return v, err
return rv, err
}
rv = rv.Elem()
return rv, nil
}
func nonJSONStringToArg(cdc *amino.Codec, rt reflect.Type, arg string) (reflect.Value, error, bool) {
if rt.Kind() == reflect.Ptr {
rv_, err, ok := nonJSONStringToArg(cdc, rt.Elem(), arg)
if err != nil {
return reflect.Value{}, err, false
} else if ok {
rv := reflect.New(rt.Elem())
rv.Elem().Set(rv_)
return rv, nil, true
} else {
return reflect.Value{}, nil, false
}
} else {
return _nonJSONStringToArg(cdc, rt, arg)
} }
v = v.Elem()
return v, nil
} }
func nonJSONToArg(cdc *amino.Codec, ty reflect.Type, arg string) (reflect.Value, error, bool) {
// NOTE: rt.Kind() isn't a pointer.
func _nonJSONStringToArg(cdc *amino.Codec, rt reflect.Type, arg string) (reflect.Value, error, bool) {
isIntString := RE_INT.Match([]byte(arg))
isQuotedString := strings.HasPrefix(arg, `"`) && strings.HasSuffix(arg, `"`) isQuotedString := strings.HasPrefix(arg, `"`) && strings.HasSuffix(arg, `"`)
isHexString := strings.HasPrefix(strings.ToLower(arg), "0x") isHexString := strings.HasPrefix(strings.ToLower(arg), "0x")
expectingString := ty.Kind() == reflect.String
expectingByteSlice := ty.Kind() == reflect.Slice && ty.Elem().Kind() == reflect.Uint8
var expectingString, expectingByteSlice, expectingInt bool
switch rt.Kind() {
case reflect.Int, reflect.Uint, reflect.Int8, reflect.Uint8, reflect.Int16, reflect.Uint16, reflect.Int32, reflect.Uint32, reflect.Int64, reflect.Uint64:
expectingInt = true
case reflect.String:
expectingString = true
case reflect.Slice:
expectingByteSlice = rt.Elem().Kind() == reflect.Uint8
}
if isIntString && expectingInt {
qarg := `"` + arg + `"`
// jsonStringToArg
rv, err := jsonStringToArg(cdc, rt, qarg)
if err != nil {
return rv, err, false
} else {
return rv, nil, true
}
}
if isHexString { if isHexString {
if !expectingString && !expectingByteSlice { if !expectingString && !expectingByteSlice {
err := errors.Errorf("Got a hex string arg, but expected '%s'", err := errors.Errorf("Got a hex string arg, but expected '%s'",
ty.Kind().String())
rt.Kind().String())
return reflect.ValueOf(nil), err, false return reflect.ValueOf(nil), err, false
} }
@ -340,7 +378,7 @@ func nonJSONToArg(cdc *amino.Codec, ty reflect.Type, arg string) (reflect.Value,
if err != nil { if err != nil {
return reflect.ValueOf(nil), err, false return reflect.ValueOf(nil), err, false
} }
if ty.Kind() == reflect.String {
if rt.Kind() == reflect.String {
return reflect.ValueOf(string(value)), nil, true return reflect.ValueOf(string(value)), nil, true
} }
return reflect.ValueOf([]byte(value)), nil, true return reflect.ValueOf([]byte(value)), nil, true


+ 1
- 0
rpc/lib/server/http_params.go View File

@ -15,6 +15,7 @@ var (
dotAtom = atom + `(?:\.` + atom + `)*` dotAtom = atom + `(?:\.` + atom + `)*`
domain = `[A-Z0-9.-]+\.[A-Z]{2,4}` domain = `[A-Z0-9.-]+\.[A-Z]{2,4}`
RE_INT = regexp.MustCompile(`^-?[0-9]+$`)
RE_HEX = regexp.MustCompile(`^(?i)[a-f0-9]+$`) RE_HEX = regexp.MustCompile(`^(?i)[a-f0-9]+$`)
RE_EMAIL = regexp.MustCompile(`^(?i)(` + dotAtom + `)@(` + dotAtom + `)$`) RE_EMAIL = regexp.MustCompile(`^(?i)(` + dotAtom + `)@(` + dotAtom + `)$`)
RE_ADDRESS = regexp.MustCompile(`^(?i)[a-z0-9]{25,34}$`) RE_ADDRESS = regexp.MustCompile(`^(?i)[a-z0-9]{25,34}$`)


+ 46
- 1
rpc/lib/server/parse_test.go View File

@ -2,6 +2,8 @@ package rpcserver
import ( import (
"encoding/json" "encoding/json"
"fmt"
"net/http"
"strconv" "strconv"
"testing" "testing"
@ -134,7 +136,7 @@ func TestParseJSONArray(t *testing.T) {
} }
} }
func TestParseRPC(t *testing.T) {
func TestParseJSONRPC(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
demo := func(height int, name string) {} demo := func(height int, name string) {}
@ -172,5 +174,48 @@ func TestParseRPC(t *testing.T) {
} }
} }
}
func TestParseURI(t *testing.T) {
demo := func(height int, name string) {}
call := NewRPCFunc(demo, "height,name")
cdc := amino.NewCodec()
cases := []struct {
raw []string
height int64
name string
fail bool
}{
// can parse numbers unquoted and strings quoted
{[]string{"7", `"flew"`}, 7, "flew", false},
{[]string{"22", `"john"`}, 22, "john", false},
{[]string{"-10", `"bob"`}, -10, "bob", false},
// can parse numbers quoted, too
{[]string{`"7"`, `"flew"`}, 7, "flew", false},
{[]string{`"-10"`, `"bob"`}, -10, "bob", false},
// cant parse strings uquoted
{[]string{`"-10"`, `bob`}, -10, "bob", true},
}
for idx, tc := range cases {
i := strconv.Itoa(idx)
// data := []byte(tc.raw)
url := fmt.Sprintf(
"test.com/method?height=%v&name=%v",
tc.raw[0], tc.raw[1])
req, err := http.NewRequest("GET", url, nil)
assert.NoError(t, err)
vals, err := httpParamsToArgs(call, cdc, req)
if tc.fail {
assert.NotNil(t, err, i)
} else {
assert.Nil(t, err, "%s: %+v", i, err)
if assert.Equal(t, 2, len(vals), i) {
assert.Equal(t, tc.height, vals[0].Int(), i)
assert.Equal(t, tc.name, vals[1].String(), i)
}
}
}
} }

+ 0
- 14
scripts/dep_utils/parse.sh View File

@ -1,14 +0,0 @@
#! /bin/bash
set +u
if [[ "$DEP" == "" ]]; then
DEP=$GOPATH/src/github.com/tendermint/tendermint/Gopkg.lock
fi
set -u
set -euo pipefail
LIB=$1
grep -A100 "$LIB" "$DEP" | grep revision | head -n1 | grep -o '"[^"]\+"' | cut -d '"' -f 2

+ 0
- 12
scripts/install_abci_apps.sh View File

@ -1,12 +0,0 @@
#! /bin/bash
# get the abci commit used by tendermint
COMMIT=$(bash scripts/dep_utils/parse.sh abci)
echo "Checking out vendored commit for abci: $COMMIT"
go get -d github.com/tendermint/abci
cd "$GOPATH/src/github.com/tendermint/abci" || exit
git checkout "$COMMIT"
make get_tools
make get_vendor_deps
make install

+ 1
- 4
test/docker/Dockerfile View File

@ -21,15 +21,12 @@ ADD Makefile Makefile
RUN make get_tools RUN make get_tools
RUN make get_vendor_deps RUN make get_vendor_deps
# Install the apps
ADD scripts scripts
RUN bash scripts/install_abci_apps.sh
# Now copy in the code # Now copy in the code
# NOTE: this will overwrite whatever is in vendor/ # NOTE: this will overwrite whatever is in vendor/
COPY . $REPO COPY . $REPO
RUN go install ./cmd/tendermint RUN go install ./cmd/tendermint
RUN go install ./abci/cmd/abci-cli
# expose the volume for debugging # expose the volume for debugging
VOLUME $REPO VOLUME $REPO


+ 2
- 2
version/version.go View File

@ -4,13 +4,13 @@ package version
const ( const (
Maj = "0" Maj = "0"
Min = "22" Min = "22"
Fix = "1"
Fix = "2"
) )
var ( var (
// Version is the current version of Tendermint // Version is the current version of Tendermint
// Must be a string because scripts like dist.sh read this file. // Must be a string because scripts like dist.sh read this file.
Version = "0.22.1"
Version = "0.22.2"
// GitCommit is the current HEAD set using ldflags. // GitCommit is the current HEAD set using ldflags.
GitCommit string GitCommit string


Loading…
Cancel
Save