Merge pull request #4161 from tendermint/release/v0.32.8

Release/v0.32.8
This commit is contained in:
Tess Rinearson
2019-11-19 15:03:24 +01:00
committed by GitHub
284 changed files with 15031 additions and 6397 deletions
+18 -32
View File
@@ -11,7 +11,7 @@ executors:
machine: true
docs:
docker:
- image: tendermintdev/jq_curl
- image: tendermintdev/docker-website-deployment
environment:
AWS_REGION: us-east-1
@@ -80,7 +80,7 @@ jobs:
script_path: abci/tests/test_app/test.sh
# if this test fails, fix it and update the docs at:
# https://github.com/tendermint/tendermint/blob/develop/docs/abci-cli.md
# https://github.com/tendermint/tendermint/blob/master/docs/abci-cli.md
test_abci_cli:
executor: golang
steps:
@@ -191,30 +191,13 @@ jobs:
deploy_docs:
executor: docs
steps:
- restore_cache:
name: "Restore source code cache"
keys:
- go-src-v1-{{ .Revision }}
- checkout
- run:
name: Trigger website build
command: |
curl --silent \
--show-error \
-X POST \
--header "Content-Type: application/json" \
-d "{\"branch\": \"$CIRCLE_BRANCH\"}" \
"https://circleci.com/api/v1.1/project/github/$CIRCLE_PROJECT_USERNAME/$WEBSITE_REPO_NAME/build?circle-token=$TENDERBOT_API_TOKEN" > response.json
RESULT=`jq -r '.status' response.json`
MESSAGE=`jq -r '.message' response.json`
if [[ ${RESULT} == "null" ]] || [[ ${RESULT} -ne "200" ]]; then
echo "CircleCI API call failed: $MESSAGE"
exit 1
else
echo "Website build started"
fi
name: "Build docs"
command: make build-docs
- run:
name: "Sync to S3"
command: make sync-docs
prepare_build:
executor: golang
@@ -314,10 +297,6 @@ jobs:
machine:
image: ubuntu-1604:201903-01
steps:
- restore_cache:
name: "Restore source code cache"
keys:
- go-src-v1-{{ .Revision }}
- checkout
- attach_workspace:
at: /tmp/workspace
@@ -337,10 +316,6 @@ jobs:
steps:
- attach_workspace:
at: /tmp/workspace
- restore_cache:
name: "Restore source code cache"
keys:
- go-src-v1-{{ .Revision }}
- checkout
- setup_remote_docker:
docker_layer_caching: true
@@ -398,10 +373,20 @@ workflows:
test-suite:
jobs:
- deploy_docs:
context: tendermint-docs
filters:
branches:
only:
- master
tags:
only:
- /^v.*/
- deploy_docs:
context: tendermint-docs-staging
filters:
branches:
only:
- docs-theme-latest
- setup_dependencies
- test_abci_apps:
requires:
@@ -457,3 +442,4 @@ workflows:
branches:
only:
- /v[0-9]+\.[0-9]+/
- master
+2 -2
View File
@@ -1,7 +1,7 @@
# CODEOWNERS: https://help.github.com/articles/about-codeowners/
# Everything goes through Bucky, Anton, Alex. For now.
* @ebuchman @melekes @xla
# Everything goes through Bucky, Anton, Tess. For now.
* @ebuchman @melekes @tessr
# Precious documentation
/docs/README.md @zramsay
+47
View File
@@ -0,0 +1,47 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 60
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 9
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels: []
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- major-release
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: true
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: true
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: false
# Label to use when marking as stale
staleLabel: stale
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
Limit to only `issues` or `pulls`
only: pulls
Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
pulls:
daysUntilStale: 30
markComment: >
This pull request has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
+1
View File
@@ -15,6 +15,7 @@ test/logs
coverage.txt
docs/_build
docs/dist
docs/.vuepress/dist
*.log
abci-cli
docs/node_modules/
+52 -15
View File
@@ -1,20 +1,58 @@
run:
deadline: 1m
linters:
enable-all: true
disable:
- gocyclo
- golint
- maligned
- errcheck
enable:
- bodyclose
- deadcode
- depguard
- dogsled
- dupl
# - errcheck
# - funlen
# - gochecknoglobals
# - gochecknoinits
- goconst
- gocritic
# - gocyclo
# - godox
- gofmt
- goimports
# - golint
- gosec
- gosimple
- govet
- ineffassign
- interfacer
- unparam
- lll
- gochecknoglobals
- gochecknoinits
- stylecheck
# linters-settings:
- misspell
- maligned
- nakedret
- prealloc
- scopelint
- staticcheck
- structcheck
# - stylecheck
- typecheck
- unconvert
# - unparam
- unused
- varcheck
# - whitespace
# - wsl
# - gocognit
disable:
- errcheck
issues:
exclude-rules:
- linters:
- lll
source: "https://"
linters-settings:
dogsled:
max-blank-identifiers: 3
maligned:
# print struct with more effective memory layout or not, false by default
suggest-new: true
# govet:
# check-shadowing: true
# golint:
@@ -45,4 +83,3 @@ linters:
# disabled-checks:
# - wrapperFunc
# - commentFormatting # https://github.com/go-critic/go-critic/issues/755
+577 -328
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
## v0.32.8
## v0.32.9
\*\*
+1 -1
View File
@@ -185,7 +185,7 @@ includes its continuous integration status using a badge in the `README.md`.
### RPC Testing
If you contribute to the RPC endpoints it's important to document your changes in the [Swagger file](./docs/spec/rpc/swagger.yaml)
If you contribute to the RPC endpoints it's important to document your changes in the [Swagger file](./rpc/swagger/swagger.yaml)
To test your changes you should install `nodejs` and run:
```bash
-1
View File
@@ -36,4 +36,3 @@ STOPSIGNAL SIGTERM
ARG BINARY=tendermint
COPY $BINARY /usr/bin/tendermint
-23
View File
@@ -1,23 +0,0 @@
FROM golang:latest
RUN mkdir -p /go/src/github.com/tendermint/abci
WORKDIR /go/src/github.com/tendermint/abci
COPY Makefile /go/src/github.com/tendermint/abci/
# see make protoc for details on ldconfig
RUN make get_protoc && ldconfig
# killall is used in tests
RUN apt-get update && apt-get install -y \
psmisc \
&& rm -rf /var/lib/apt/lists/*
COPY Gopkg.toml /go/src/github.com/tendermint/abci/
COPY Gopkg.lock /go/src/github.com/tendermint/abci/
RUN make tools
# see https://github.com/golang/dep/issues/1312
RUN dep ensure -vendor-only
COPY . /go/src/github.com/tendermint/abci
+1 -3
View File
@@ -1,5 +1,4 @@
FROM golang:1.12
FROM golang:latest
# Grab deps (jq, hexdump, xxd, killall)
RUN apt-get update && \
@@ -15,4 +14,3 @@ VOLUME /go
EXPOSE 26656
EXPOSE 26657
+1 -7
View File
@@ -4,16 +4,10 @@ build:
push:
@sh -c "'$(CURDIR)/push.sh'"
build_develop:
docker build -t "tendermint/tendermint:develop" -f Dockerfile.develop .
build_testing:
docker build --tag tendermint/testing -f ./Dockerfile.testing .
push_develop:
docker push "tendermint/tendermint:develop"
build_amazonlinux_buildimage:
docker build -t "tendermint/tendermint:build_c-amazonlinux" -f Dockerfile.build_c-amazonlinux .
.PHONY: build build_develop push push_develop
.PHONY: build push build_testing build_amazonlinux_buildimage
+10 -18
View File
@@ -2,27 +2,19 @@
## Supported tags and respective `Dockerfile` links
- `0.17.1`, `latest` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/208ac32fa266657bd6c304e84ec828aa252bb0b8/DOCKER/Dockerfile)
- `0.15.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/170777300ea92dc21a8aec1abc16cb51812513a4/DOCKER/Dockerfile)
- `0.13.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/a28b3fff49dce2fb31f90abb2fc693834e0029c2/DOCKER/Dockerfile)
- `0.12.1` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/457c688346b565e90735431619ca3ca597ef9007/DOCKER/Dockerfile)
- `0.12.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/70d8afa6e952e24c573ece345560a5971bf2cc0e/DOCKER/Dockerfile)
- `0.11.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/9177cc1f64ca88a4a0243c5d1773d10fba67e201/DOCKER/Dockerfile)
- `0.10.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/e5342f4054ab784b2cd6150e14f01053d7c8deb2/DOCKER/Dockerfile)
- `0.9.1`, `0.9`, [(Dockerfile)](https://github.com/tendermint/tendermint/blob/809e0e8c5933604ba8b2d096803ada7c5ec4dfd3/DOCKER/Dockerfile)
- `0.9.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/d474baeeea6c22b289e7402449572f7c89ee21da/DOCKER/Dockerfile)
- `0.8.0`, `0.8` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/bf64dd21fdb193e54d8addaaaa2ecf7ac371de8c/DOCKER/Dockerfile)
DockerHub tags for official releases are [here](https://hub.docker.com/r/tendermint/tendermint/tags/). The "latest" tag will always point to the highest version number.
Official releases can be found [here](https://github.com/tendermint/tendermint/releases).
The Dockerfile for tendermint is not expected to change in the near future. The master file used for all builds can be found [here](https://raw.githubusercontent.com/tendermint/tendermint/master/DOCKER/Dockerfile).
Respective versioned files can be found https://raw.githubusercontent.com/tendermint/tendermint/vX.XX.XX/DOCKER/Dockerfile (replace the Xs with the version number).
## Quick reference
- **Where to get help:**
[cosmos.network/ecosystem](https://cosmos.network/ecosystem)
- **Where to file issues:**
[Tendermint Issues](https://github.com/tendermint/tendermint/issues)
- **Supported Docker versions:**
[the latest release](https://github.com/moby/moby/releases) (down to 1.6 on a best-effort basis)
- **Where to get help:** https://tendermint.com/
- **Where to file issues:** https://github.com/tendermint/tendermint/issues
- **Supported Docker versions:** [the latest release](https://github.com/moby/moby/releases) (down to 1.6 on a best-effort basis)
## Tendermint
+21 -1
View File
@@ -153,6 +153,26 @@ lint:
DESTINATION = ./index.html.md
###########################################################
### Documentation
build-docs:
cd docs && \
while read p; do \
(git checkout $${p} && npm install && VUEPRESS_BASE="/$${p}/" npm run build) ; \
mkdir -p ~/output/$${p} ; \
cp -r .vuepress/dist/* ~/output/$${p}/ ; \
cp ~/output/$${p}/index.html ~/output ; \
done < versions ;
sync-docs:
cd ~/output && \
echo "role_arn = ${DEPLOYMENT_ROLE_ARN}" >> /root/.aws/config ; \
echo "CI job = ${CIRCLE_BUILD_URL}" >> version.html ; \
aws s3 sync . s3://${WEBSITE_BUCKET} --profile terraform --delete ; \
aws cloudfront create-invalidation --distribution-id ${CF_DISTRIBUTION_ID} --profile terraform --path "/*" ;
.PHONY: sync-docs
###########################################################
### Docker image
@@ -227,7 +247,7 @@ contract-tests:
# 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_tools tools update_tools draw_deps \
get_protoc protoc_abci protoc_libs gen_certs clean_certs grpc_dbserver fmt rpc-docs build-linux localnet-start \
get_protoc protoc_abci protoc_libs gen_certs clean_certs grpc_dbserver fmt build-linux localnet-start \
localnet-stop build-docker build-docker-localnode sentry-start sentry-config sentry-stop protoc_grpc protoc_all \
build_c install_c test_with_deadlock cleanup_after_test_with_deadlock lint build-contract-tests-hooks contract-tests \
build_c-amazonlinux
+1 -1
View File
@@ -78,7 +78,7 @@ Sessions](/docs/DEV_SESSIONS.md) and read some [Architectural Decision
Records](https://github.com/tendermint/tendermint/tree/master/docs/architecture).
Learn more by reading the code and comparing it to the
[specification](https://github.com/tendermint/tendermint/tree/develop/docs/spec).
[specification](https://github.com/tendermint/tendermint/tree/master/docs/spec).
## Versioning
+3 -3
View File
@@ -110,7 +110,6 @@ The ABCI Application interface changed slightly so the CheckTx and DeliverTx
methods now take Request structs. The contents of these structs are just the raw
tx bytes, which were previously passed in as the argument.
## v0.31.6
There are no breaking changes in this release except Go API of p2p and
@@ -193,13 +192,15 @@ due to changes in how various data structures are hashed.
Any implementations of Tendermint blockchain verification, including lite clients,
will need to be updated. For specific details:
- [Merkle tree](./docs/spec/blockchain/encoding.md#merkle-trees)
- [ConsensusParams](./docs/spec/blockchain/state.md#consensusparams)
There was also a small change to field ordering in the vote struct. Any
implementations of an out-of-process validator (like a Key-Management Server)
will need to be updated. For specific details:
- [Vote](https://github.com/tendermint/tendermint/blob/develop/docs/spec/consensus/signing.md#votes)
- [Vote](https://github.com/tendermint/tendermint/blob/master/docs/spec/consensus/signing.md#votes)
Finally, the proposer selection algorithm continues to evolve. See the
[work-in-progress
@@ -438,7 +439,6 @@ required to maintain a map from validator addresses to pubkeys since v0.23 (when
pubkeys were removed from RequestBeginBlock), but now they may need to track
multiple validator sets at once to accomodate this delay.
### Block Size
The `ConsensusParams.BlockSize.MaxTxs` was removed in favour of
+3 -2
View File
@@ -5,6 +5,7 @@ import (
"container/list"
"errors"
"fmt"
"io"
"net"
"reflect"
"sync"
@@ -119,7 +120,7 @@ func (cli *socketClient) SetResponseCallback(resCb Callback) {
//----------------------------------------
func (cli *socketClient) sendRequestsRoutine(conn net.Conn) {
func (cli *socketClient) sendRequestsRoutine(conn io.Writer) {
w := bufio.NewWriter(conn)
for {
@@ -151,7 +152,7 @@ func (cli *socketClient) sendRequestsRoutine(conn net.Conn) {
}
}
func (cli *socketClient) recvResponseRoutine(conn net.Conn) {
func (cli *socketClient) recvResponseRoutine(conn io.Reader) {
r := bufio.NewReader(conn) // Buffer reads
for {
+15 -3
View File
@@ -111,16 +111,28 @@ func Execute() error {
}
func addGlobalFlags() {
RootCmd.PersistentFlags().StringVarP(&flagAddress, "address", "", "tcp://0.0.0.0:26658", "address of application socket")
RootCmd.PersistentFlags().StringVarP(&flagAddress,
"address",
"",
"tcp://0.0.0.0:26658",
"address of application socket")
RootCmd.PersistentFlags().StringVarP(&flagAbci, "abci", "", "socket", "either socket or grpc")
RootCmd.PersistentFlags().BoolVarP(&flagVerbose, "verbose", "v", false, "print the command and results as if it were a console session")
RootCmd.PersistentFlags().BoolVarP(&flagVerbose,
"verbose",
"v",
false,
"print the command and results as if it were a console session")
RootCmd.PersistentFlags().StringVarP(&flagLogLevel, "log_level", "", "debug", "set the logger level")
}
func addQueryFlags() {
queryCmd.PersistentFlags().StringVarP(&flagPath, "path", "", "/store", "path to prefix query with")
queryCmd.PersistentFlags().IntVarP(&flagHeight, "height", "", 0, "height to query the blockchain at")
queryCmd.PersistentFlags().BoolVarP(&flagProve, "prove", "", false, "whether or not to return a merkle proof of the query result")
queryCmd.PersistentFlags().BoolVarP(&flagProve,
"prove",
"",
false,
"whether or not to return a merkle proof of the query result")
}
func addCounterFlags() {
+1 -1
View File
@@ -111,7 +111,7 @@ func dialerFunc(ctx context.Context, addr string) (net.Conn, error) {
return cmn.Connect(addr)
}
func testGRPCSync(t *testing.T, app *types.GRPCApplication) {
func testGRPCSync(t *testing.T, app types.ABCIApplicationServer) {
numDeliverTxs := 2000
// Start the listener
+6 -1
View File
@@ -175,7 +175,12 @@ func TestValUpdates(t *testing.T) {
}
func makeApplyBlock(t *testing.T, kvstore types.Application, heightInt int, diff []types.ValidatorUpdate, txs ...[]byte) {
func makeApplyBlock(
t *testing.T,
kvstore types.Application,
heightInt int,
diff []types.ValidatorUpdate,
txs ...[]byte) {
// make and apply block
height := int64(heightInt)
hash := []byte("foo")
+2 -2
View File
@@ -144,7 +144,7 @@ func (s *SocketServer) waitForClose(closeConn chan error, connID int) {
}
// Read requests from conn and deal with them
func (s *SocketServer) handleRequests(closeConn chan error, conn net.Conn, responses chan<- *types.Response) {
func (s *SocketServer) handleRequests(closeConn chan error, conn io.Reader, responses chan<- *types.Response) {
var count int
var bufReader = bufio.NewReader(conn)
@@ -215,7 +215,7 @@ func (s *SocketServer) handleRequest(req *types.Request, responses chan<- *types
}
// Pull responses from 'responses' and write them to conn.
func (s *SocketServer) handleResponses(closeConn chan error, conn net.Conn, responses <-chan *types.Response) {
func (s *SocketServer) handleResponses(closeConn chan error, conn io.Writer, responses <-chan *types.Response) {
var count int
var bufWriter = bufio.NewWriter(conn)
for {
+2 -2
View File
@@ -3,8 +3,8 @@ package main
import (
"bufio"
"fmt"
"io"
"log"
"net"
"reflect"
"github.com/tendermint/tendermint/abci/types"
@@ -33,7 +33,7 @@ func main() {
}
}
func makeRequest(conn net.Conn, req *types.Request) (*types.Response, error) {
func makeRequest(conn io.ReadWriter, req *types.Request) (*types.Response, error) {
var bufWriter = bufio.NewWriter(conn)
// Write desired request
+2 -2
View File
@@ -36,7 +36,7 @@ func ensureABCIIsUp(typ string, n int) error {
}
for i := 0; i < n; i++ {
cmd := exec.Command("bash", "-c", cmdString) // nolint: gas
cmd := exec.Command("bash", "-c", cmdString)
_, err = cmd.CombinedOutput()
if err == nil {
break
@@ -53,7 +53,7 @@ func testCounter() {
}
fmt.Printf("Running %s test with abci=%s\n", abciApp, abciType)
cmd := exec.Command("bash", "-c", fmt.Sprintf("abci-cli %s", abciApp)) // nolint: gas
cmd := exec.Command("bash", "-c", fmt.Sprintf("abci-cli %s", abciApp)) //nolint:gosec
cmd.Stdout = os.Stdout
if err := cmd.Start(); err != nil {
log.Fatalf("starting %q err: %v", abciApp, err)
+1 -1
View File
@@ -18,7 +18,7 @@ type Application interface {
CheckTx(RequestCheckTx) ResponseCheckTx // Validate a tx for the mempool
// Consensus Connection
InitChain(RequestInitChain) ResponseInitChain // Initialize blockchain with validators and other info from TendermintCore
InitChain(RequestInitChain) ResponseInitChain // Initialize blockchain w validators/other info from TendermintCore
BeginBlock(RequestBeginBlock) ResponseBeginBlock // Signals the beginning of a block
DeliverTx(RequestDeliverTx) ResponseDeliverTx // Deliver a tx for full processing
EndBlock(RequestEndBlock) ResponseEndBlock // Signals the end of a block, returns changes to the validator set
+3 -1
View File
@@ -63,10 +63,12 @@ func NewMockReporter() *MockReporter {
}
// Report stores the PeerBehaviour produced by the peer identified by peerID.
func (mpbr *MockReporter) Report(behaviour PeerBehaviour) {
func (mpbr *MockReporter) Report(behaviour PeerBehaviour) error {
mpbr.mtx.Lock()
defer mpbr.mtx.Unlock()
mpbr.pb[behaviour.peerID] = append(mpbr.pb[behaviour.peerID], behaviour)
return nil
}
// GetBehaviours returns all behaviours reported on the peer identified by peerID.
+18 -3
View File
@@ -131,9 +131,24 @@ func TestMockPeerBehaviourReporterConcurrency(t *testing.T) {
}{
{"1", []bh.PeerBehaviour{bh.ConsensusVote("1", "")}},
{"2", []bh.PeerBehaviour{bh.ConsensusVote("2", ""), bh.ConsensusVote("2", ""), bh.ConsensusVote("2", "")}},
{"3", []bh.PeerBehaviour{bh.BlockPart("3", ""), bh.ConsensusVote("3", ""), bh.BlockPart("3", ""), bh.ConsensusVote("3", "")}},
{"4", []bh.PeerBehaviour{bh.ConsensusVote("4", ""), bh.ConsensusVote("4", ""), bh.ConsensusVote("4", ""), bh.ConsensusVote("4", "")}},
{"5", []bh.PeerBehaviour{bh.BlockPart("5", ""), bh.ConsensusVote("5", ""), bh.BlockPart("5", ""), bh.ConsensusVote("5", "")}},
{
"3",
[]bh.PeerBehaviour{bh.BlockPart("3", ""),
bh.ConsensusVote("3", ""),
bh.BlockPart("3", ""),
bh.ConsensusVote("3", "")}},
{
"4",
[]bh.PeerBehaviour{bh.ConsensusVote("4", ""),
bh.ConsensusVote("4", ""),
bh.ConsensusVote("4", ""),
bh.ConsensusVote("4", "")}},
{
"5",
[]bh.PeerBehaviour{bh.BlockPart("5", ""),
bh.ConsensusVote("5", ""),
bh.BlockPart("5", ""),
bh.ConsensusVote("5", "")}},
}
)
-29
View File
@@ -1,29 +0,0 @@
package benchmarks
import (
"sync/atomic"
"testing"
"unsafe"
)
func BenchmarkAtomicUintPtr(b *testing.B) {
b.StopTimer()
pointers := make([]uintptr, 1000)
b.Log(unsafe.Sizeof(pointers[0]))
b.StartTimer()
for j := 0; j < b.N; j++ {
atomic.StoreUintptr(&pointers[j%1000], uintptr(j))
}
}
func BenchmarkAtomicPointer(b *testing.B) {
b.StopTimer()
pointers := make([]unsafe.Pointer, 1000)
b.Log(unsafe.Sizeof(pointers[0]))
b.StartTimer()
for j := 0; j < b.N; j++ {
atomic.StorePointer(&pointers[j%1000], unsafe.Pointer(uintptr(j)))
}
}
-2
View File
@@ -1,2 +0,0 @@
data
-80
View File
@@ -1,80 +0,0 @@
#!/bin/bash
DATA=$GOPATH/src/github.com/tendermint/tendermint/benchmarks/blockchain/data
if [ ! -d $DATA ]; then
echo "no data found, generating a chain... (this only has to happen once)"
tendermint init --home $DATA
cp $DATA/config.toml $DATA/config2.toml
echo "
[consensus]
timeout_commit = 0
" >> $DATA/config.toml
echo "starting node"
tendermint node \
--home $DATA \
--proxy_app kvstore \
--p2p.laddr tcp://127.0.0.1:56656 \
--rpc.laddr tcp://127.0.0.1:56657 \
--log_level error &
echo "making blocks for 60s"
sleep 60
mv $DATA/config2.toml $DATA/config.toml
kill %1
echo "done generating chain."
fi
# validator node
HOME1=$TMPDIR$RANDOM$RANDOM
cp -R $DATA $HOME1
echo "starting validator node"
tendermint node \
--home $HOME1 \
--proxy_app kvstore \
--p2p.laddr tcp://127.0.0.1:56656 \
--rpc.laddr tcp://127.0.0.1:56657 \
--log_level error &
sleep 1
# downloader node
HOME2=$TMPDIR$RANDOM$RANDOM
tendermint init --home $HOME2
cp $HOME1/genesis.json $HOME2
printf "starting downloader node"
tendermint node \
--home $HOME2 \
--proxy_app kvstore \
--p2p.laddr tcp://127.0.0.1:56666 \
--rpc.laddr tcp://127.0.0.1:56667 \
--p2p.persistent_peers 127.0.0.1:56656 \
--log_level error &
# wait for node to start up so we only count time where we are actually syncing
sleep 0.5
while curl localhost:56667/status 2> /dev/null | grep "\"latest_block_height\": 0," > /dev/null
do
printf '.'
sleep 0.2
done
echo
echo "syncing blockchain for 10s"
for i in {1..10}
do
sleep 1
HEIGHT="$(curl localhost:56667/status 2> /dev/null \
| grep 'latest_block_height' \
| grep -o ' [0-9]*' \
| xargs)"
let 'RATE = HEIGHT / i'
echo "height: $HEIGHT, blocks/sec: $RATE"
done
kill %1
kill %2
rm -rf $HOME1 $HOME2
-19
View File
@@ -1,19 +0,0 @@
package benchmarks
import (
"testing"
)
func BenchmarkChanMakeClose(b *testing.B) {
b.StopTimer()
b.StartTimer()
for j := 0; j < b.N; j++ {
foo := make(chan struct{})
close(foo)
something, ok := <-foo
if ok {
b.Error(something, ok)
}
}
}
-123
View File
@@ -1,123 +0,0 @@
package benchmarks
import (
"testing"
"time"
amino "github.com/tendermint/go-amino"
proto "github.com/tendermint/tendermint/benchmarks/proto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/p2p"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
func testNodeInfo(id p2p.ID) p2p.DefaultNodeInfo {
return p2p.DefaultNodeInfo{
ProtocolVersion: p2p.ProtocolVersion{P2P: 1, Block: 2, App: 3},
ID_: id,
Moniker: "SOMENAME",
Network: "SOMENAME",
ListenAddr: "SOMEADDR",
Version: "SOMEVER",
Other: p2p.DefaultNodeInfoOther{
TxIndex: "on",
RPCAddress: "0.0.0.0:26657",
},
}
}
func BenchmarkEncodeStatusWire(b *testing.B) {
b.StopTimer()
cdc := amino.NewCodec()
ctypes.RegisterAmino(cdc)
nodeKey := p2p.NodeKey{PrivKey: ed25519.GenPrivKey()}
status := &ctypes.ResultStatus{
NodeInfo: testNodeInfo(nodeKey.ID()),
SyncInfo: ctypes.SyncInfo{
LatestBlockHash: []byte("SOMEBYTES"),
LatestBlockHeight: 123,
LatestBlockTime: time.Unix(0, 1234),
},
ValidatorInfo: ctypes.ValidatorInfo{
PubKey: nodeKey.PubKey(),
},
}
b.StartTimer()
counter := 0
for i := 0; i < b.N; i++ {
jsonBytes, err := cdc.MarshalJSON(status)
if err != nil {
panic(err)
}
counter += len(jsonBytes)
}
}
func BenchmarkEncodeNodeInfoWire(b *testing.B) {
b.StopTimer()
cdc := amino.NewCodec()
ctypes.RegisterAmino(cdc)
nodeKey := p2p.NodeKey{PrivKey: ed25519.GenPrivKey()}
nodeInfo := testNodeInfo(nodeKey.ID())
b.StartTimer()
counter := 0
for i := 0; i < b.N; i++ {
jsonBytes, err := cdc.MarshalJSON(nodeInfo)
if err != nil {
panic(err)
}
counter += len(jsonBytes)
}
}
func BenchmarkEncodeNodeInfoBinary(b *testing.B) {
b.StopTimer()
cdc := amino.NewCodec()
ctypes.RegisterAmino(cdc)
nodeKey := p2p.NodeKey{PrivKey: ed25519.GenPrivKey()}
nodeInfo := testNodeInfo(nodeKey.ID())
b.StartTimer()
counter := 0
for i := 0; i < b.N; i++ {
jsonBytes := cdc.MustMarshalBinaryBare(nodeInfo)
counter += len(jsonBytes)
}
}
func BenchmarkEncodeNodeInfoProto(b *testing.B) {
b.StopTimer()
nodeKey := p2p.NodeKey{PrivKey: ed25519.GenPrivKey()}
nodeID := string(nodeKey.ID())
someName := "SOMENAME"
someAddr := "SOMEADDR"
someVer := "SOMEVER"
someString := "SOMESTRING"
otherString := "OTHERSTRING"
nodeInfo := proto.NodeInfo{
Id: &proto.ID{Id: &nodeID},
Moniker: &someName,
Network: &someName,
ListenAddr: &someAddr,
Version: &someVer,
Other: []string{someString, otherString},
}
b.StartTimer()
counter := 0
for i := 0; i < b.N; i++ {
bytes, err := nodeInfo.Marshal()
if err != nil {
b.Fatal(err)
return
}
//jsonBytes := wire.JSONBytes(nodeInfo)
counter += len(bytes)
}
}
-1
View File
@@ -1 +0,0 @@
package benchmarks
-35
View File
@@ -1,35 +0,0 @@
package benchmarks
import (
"testing"
cmn "github.com/tendermint/tendermint/libs/common"
)
func BenchmarkSomething(b *testing.B) {
b.StopTimer()
numItems := 100000
numChecks := 100000
keys := make([]string, numItems)
for i := 0; i < numItems; i++ {
keys[i] = cmn.RandStr(100)
}
txs := make([]string, numChecks)
for i := 0; i < numChecks; i++ {
txs[i] = cmn.RandStr(100)
}
b.StartTimer()
counter := 0
for j := 0; j < b.N; j++ {
foo := make(map[string]string)
for _, key := range keys {
foo[key] = key
}
for _, tx := range txs {
if _, ok := foo[tx]; ok {
counter++
}
}
}
}
-33
View File
@@ -1,33 +0,0 @@
package benchmarks
import (
"os"
"testing"
cmn "github.com/tendermint/tendermint/libs/common"
)
func BenchmarkFileWrite(b *testing.B) {
b.StopTimer()
file, err := os.OpenFile("benchmark_file_write.out",
os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
if err != nil {
b.Error(err)
}
testString := cmn.RandStr(200) + "\n"
b.StartTimer()
for i := 0; i < b.N; i++ {
_, err := file.Write([]byte(testString))
if err != nil {
b.Error(err)
}
}
if err := file.Close(); err != nil {
b.Error(err)
}
if err := os.Remove("benchmark_file_write.out"); err != nil {
b.Error(err)
}
}
-2
View File
@@ -1,2 +0,0 @@
Doing some protobuf tests here.
Using gogoprotobuf.
File diff suppressed because it is too large Load Diff
-29
View File
@@ -1,29 +0,0 @@
message ResultStatus {
optional NodeInfo nodeInfo = 1;
required PubKey pubKey = 2;
required bytes latestBlockHash = 3;
required int64 latestBlockHeight = 4;
required int64 latestBlocktime = 5;
}
message NodeInfo {
required ID id = 1;
required string moniker = 2;
required string network = 3;
required string remoteAddr = 4;
required string listenAddr = 5;
required string version = 6;
repeated string other = 7;
}
message ID {
required string id = 1;
}
message PubKey {
optional PubKeyEd25519 ed25519 = 1;
}
message PubKeyEd25519 {
required bytes bytes = 1;
}
-47
View File
@@ -1,47 +0,0 @@
package main
import (
"context"
"encoding/binary"
"fmt"
"time"
cmn "github.com/tendermint/tendermint/libs/common"
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
)
func main() {
wsc := rpcclient.NewWSClient("127.0.0.1:26657", "/websocket")
err := wsc.Start()
if err != nil {
cmn.Exit(err.Error())
}
defer wsc.Stop()
// Read a bunch of responses
go func() {
for {
_, ok := <-wsc.ResponsesCh
if !ok {
break
}
//fmt.Println("Received response", string(wire.JSONBytes(res)))
}
}()
// Make a bunch of requests
buf := make([]byte, 32)
for i := 0; ; i++ {
binary.BigEndian.PutUint64(buf, uint64(i))
//txBytes := hex.EncodeToString(buf[:n])
fmt.Print(".")
err = wsc.Call(context.TODO(), "broadcast_tx", map[string]interface{}{"tx": buf[:8]})
if err != nil {
cmn.Exit(err.Error())
}
if i%1000 == 0 {
fmt.Println(i)
}
time.Sleep(time.Microsecond * 1000)
}
}
+12 -5
View File
@@ -247,7 +247,14 @@ func (pool *BlockPool) AddBlock(peerID p2p.ID, block *types.Block, blockSize int
requester := pool.requesters[block.Height]
if requester == nil {
pool.Logger.Info("peer sent us a block we didn't expect", "peer", peerID, "curHeight", pool.height, "blockHeight", block.Height)
pool.Logger.Info(
"peer sent us a block we didn't expect",
"peer",
peerID,
"curHeight",
pool.height,
"blockHeight",
block.Height)
diff := pool.height - block.Height
if diff < 0 {
diff *= -1
@@ -422,14 +429,14 @@ func (pool *BlockPool) debug() string {
//-------------------------------------
type bpPeer struct {
didTimeout bool
numPending int32
height int64
pool *BlockPool
id p2p.ID
recvMonitor *flow.Monitor
height int64
numPending int32
timeout *time.Timer
didTimeout bool
timeout *time.Timer
logger log.Logger
}
+2 -1
View File
@@ -42,7 +42,8 @@ func (p testPeer) runInputRoutine() {
func (p testPeer) simulateInput(input inputData) {
block := &types.Block{Header: types.Header{Height: input.request.Height}}
input.pool.AddBlock(input.request.PeerID, block, 123)
// TODO: uncommenting this creates a race which is detected by: https://github.com/golang/go/blob/2bd767b1022dd3254bcec469f0ee164024726486/src/testing/testing.go#L854-L856
// TODO: uncommenting this creates a race which is detected by:
// https://github.com/golang/go/blob/2bd767b1022dd3254bcec469f0ee164024726486/src/testing/testing.go#L854-L856
// see: https://github.com/tendermint/tendermint/issues/3390#issue-418379890
// input.t.Logf("Added block from peer %v (height: %v)", input.request.PeerID, input.request.Height)
}
+11 -2
View File
@@ -50,7 +50,11 @@ type BlockchainReactorPair struct {
app proxy.AppConns
}
func newBlockchainReactor(logger log.Logger, genDoc *types.GenesisDoc, privVals []types.PrivValidator, maxBlockHeight int64) BlockchainReactorPair {
func newBlockchainReactor(
logger log.Logger,
genDoc *types.GenesisDoc,
privVals []types.PrivValidator,
maxBlockHeight int64) BlockchainReactorPair {
if len(privVals) != 1 {
panic("only support one validator")
}
@@ -88,7 +92,12 @@ func newBlockchainReactor(logger log.Logger, genDoc *types.GenesisDoc, privVals
lastBlockMeta := blockStore.LoadBlockMeta(blockHeight - 1)
lastBlock := blockStore.LoadBlock(blockHeight - 1)
vote, err := types.MakeVote(lastBlock.Header.Height, lastBlockMeta.BlockID, state.Validators, privVals[0], lastBlock.Header.ChainID)
vote, err := types.MakeVote(
lastBlock.Header.Height,
lastBlockMeta.BlockID,
state.Validators,
privVals[0],
lastBlock.Header.ChainID)
if err != nil {
panic(err)
}
+18 -6
View File
@@ -198,14 +198,22 @@ func TestBlockPoolRemovePeer(t *testing.T) {
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
},
{
name: "delete the shortest of two peers without blocks",
pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 120}}, map[int64]tPBlocks{}),
name: "delete the shortest of two peers without blocks",
pool: makeBlockPool(
testBcR,
100,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 120}},
map[int64]tPBlocks{}),
args: args{"P1", nil},
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P2", Height: 120}}, map[int64]tPBlocks{}),
},
{
name: "delete the tallest of two peers without blocks",
pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 120}}, map[int64]tPBlocks{}),
name: "delete the tallest of two peers without blocks",
pool: makeBlockPool(
testBcR,
100,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 120}},
map[int64]tPBlocks{}),
args: args{"P2", nil},
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 100}}, map[int64]tPBlocks{}),
},
@@ -308,8 +316,12 @@ func TestBlockPoolSendRequestBatch(t *testing.T) {
expnumPendingBlockRequests: 2,
},
{
name: "n peers - send n*maxRequestsPerPeer block requests",
pool: makeBlockPool(testBcR, 10, []BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}}, map[int64]tPBlocks{}),
name: "n peers - send n*maxRequestsPerPeer block requests",
pool: makeBlockPool(
testBcR,
10,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
map[int64]tPBlocks{}),
maxRequestsPerPeer: 2,
expRequests: map[int64]bool{10: true, 11: true},
expPeerResults: []testPeerResult{
+6 -4
View File
@@ -162,10 +162,12 @@ var (
errNoTallerPeer = errors.New("fast sync timed out on waiting for a peer taller than this node")
// reported eventually to the switch
errPeerLowersItsHeight = errors.New("fast sync peer reports a height lower than previous") // handle return
errNoPeerResponseForCurrentHeights = errors.New("fast sync timed out on peer block response for current heights") // handle return
errNoPeerResponse = errors.New("fast sync timed out on peer block response") // xx
errBadDataFromPeer = errors.New("fast sync received block from wrong peer or block is bad") // xx
// handle return
errPeerLowersItsHeight = errors.New("fast sync peer reports a height lower than previous")
// handle return
errNoPeerResponseForCurrentHeights = errors.New("fast sync timed out on peer block response for current heights")
errNoPeerResponse = errors.New("fast sync timed out on peer block response") // xx
errBadDataFromPeer = errors.New("fast sync received block from wrong peer or block is bad") // xx
errDuplicateBlock = errors.New("fast sync received duplicate block from peer")
errBlockVerificationFailure = errors.New("fast sync block verification failure") // xx
errSlowPeer = errors.New("fast sync peer is not sending us data fast enough") // xx
+15 -3
View File
@@ -45,7 +45,11 @@ func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.G
}, privValidators
}
func makeVote(header *types.Header, blockID types.BlockID, valset *types.ValidatorSet, privVal types.PrivValidator) *types.Vote {
func makeVote(
header *types.Header,
blockID types.BlockID,
valset *types.ValidatorSet,
privVal types.PrivValidator) *types.Vote {
addr := privVal.GetPubKey().Address()
idx, _ := valset.GetByAddress(addr)
vote := &types.Vote{
@@ -68,7 +72,11 @@ type BlockchainReactorPair struct {
conR *consensusReactorTest
}
func newBlockchainReactor(logger log.Logger, genDoc *types.GenesisDoc, privVals []types.PrivValidator, maxBlockHeight int64) *BlockchainReactor {
func newBlockchainReactor(
logger log.Logger,
genDoc *types.GenesisDoc,
privVals []types.PrivValidator,
maxBlockHeight int64) *BlockchainReactor {
if len(privVals) != 1 {
panic("only support one validator")
}
@@ -129,7 +137,11 @@ func newBlockchainReactor(logger log.Logger, genDoc *types.GenesisDoc, privVals
return bcReactor
}
func newBlockchainReactorPair(logger log.Logger, genDoc *types.GenesisDoc, privVals []types.PrivValidator, maxBlockHeight int64) BlockchainReactorPair {
func newBlockchainReactorPair(
logger log.Logger,
genDoc *types.GenesisDoc,
privVals []types.PrivValidator,
maxBlockHeight int64) BlockchainReactorPair {
consensusReactor := &consensusReactorTest{}
consensusReactor.BaseReactor = *p2p.NewBaseReactor("Consensus reactor", consensusReactor)
+186
View File
@@ -0,0 +1,186 @@
package v2
import (
"fmt"
"github.com/tendermint/tendermint/p2p"
tdState "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
)
type peerError struct {
priorityHigh
peerID p2p.ID
}
type pcDuplicateBlock struct {
priorityNormal
}
type pcShortBlock struct {
priorityNormal
}
type bcBlockResponse struct {
priorityNormal
peerID p2p.ID
block *types.Block
height int64
}
type pcBlockVerificationFailure struct {
priorityNormal
peerID p2p.ID
height int64
}
type pcBlockProcessed struct {
priorityNormal
height int64
peerID p2p.ID
}
type pcProcessBlock struct {
priorityNormal
}
type pcStop struct {
priorityNormal
}
type pcFinished struct {
priorityNormal
height int64
blocksSynced int64
}
func (p pcFinished) Error() string {
return "finished"
}
type queueItem struct {
block *types.Block
peerID p2p.ID
}
type blockQueue map[int64]queueItem
type pcState struct {
height int64 // height of the last synced block
queue blockQueue // blocks waiting to be processed
chainID string
blocksSynced int64
draining bool
tdState tdState.State
context processorContext
}
func (state *pcState) String() string {
return fmt.Sprintf("height: %d queue length: %d draining: %v blocks synced: %d",
state.height, len(state.queue), state.draining, state.blocksSynced)
}
// newPcState returns a pcState initialized with the last verified block enqueued
func newPcState(initHeight int64, tdState tdState.State, chainID string, context processorContext) *pcState {
return &pcState{
height: initHeight,
queue: blockQueue{},
chainID: chainID,
draining: false,
blocksSynced: 0,
context: context,
tdState: tdState,
}
}
// nextTwo returns the next two unverified blocks
func (state *pcState) nextTwo() (queueItem, queueItem, error) {
if first, ok := state.queue[state.height+1]; ok {
if second, ok := state.queue[state.height+2]; ok {
return first, second, nil
}
}
return queueItem{}, queueItem{}, fmt.Errorf("not found")
}
// synced returns true when at most the last verified block remains in the queue
func (state *pcState) synced() bool {
return len(state.queue) <= 1
}
func (state *pcState) advance() {
state.height++
delete(state.queue, state.height)
state.blocksSynced++
}
func (state *pcState) enqueue(peerID p2p.ID, block *types.Block, height int64) error {
if _, ok := state.queue[height]; ok {
return fmt.Errorf("duplicate queue item")
}
state.queue[height] = queueItem{block: block, peerID: peerID}
return nil
}
// purgePeer moves all unprocessed blocks from the queue
func (state *pcState) purgePeer(peerID p2p.ID) {
// what if height is less than state.height?
for height, item := range state.queue {
if item.peerID == peerID {
delete(state.queue, height)
}
}
}
// handle processes FSM events
func (state *pcState) handle(event Event) (Event, error) {
switch event := event.(type) {
case *bcBlockResponse:
if event.height <= state.height {
return pcShortBlock{}, nil
}
err := state.enqueue(event.peerID, event.block, event.height)
if err != nil {
return pcDuplicateBlock{}, nil
}
case pcProcessBlock:
firstItem, secondItem, err := state.nextTwo()
if err != nil {
if state.draining {
return noOp, pcFinished{height: state.height}
}
return noOp, nil
}
first, second := firstItem.block, secondItem.block
firstParts := first.MakePartSet(types.BlockPartSizeBytes)
firstPartsHeader := firstParts.Header()
firstID := types.BlockID{Hash: first.Hash(), PartsHeader: firstPartsHeader}
err = state.context.verifyCommit(state.chainID, firstID, first.Height, second.LastCommit)
if err != nil {
return pcBlockVerificationFailure{peerID: firstItem.peerID, height: first.Height}, nil
}
state.context.saveBlock(first, firstParts, second.LastCommit)
state.tdState, err = state.context.applyBlock(state.tdState, firstID, first)
if err != nil {
panic(fmt.Sprintf("failed to process committed block (%d:%X): %v", first.Height, first.Hash(), err))
}
state.advance()
return pcBlockProcessed{height: first.Height, peerID: firstItem.peerID}, nil
case *peerError:
state.purgePeer(event.peerID)
case pcStop:
if state.synced() {
return noOp, pcFinished{height: state.height, blocksSynced: state.blocksSynced}
}
state.draining = true
}
return noOp, nil
}
+76
View File
@@ -0,0 +1,76 @@
package v2
import (
"fmt"
"github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/store"
"github.com/tendermint/tendermint/types"
)
type processorContext interface {
applyBlock(state state.State, blockID types.BlockID, block *types.Block) (state.State, error)
verifyCommit(chainID string, blockID types.BlockID, height int64, commit *types.Commit) error
saveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit)
}
// nolint:unused
type pContext struct {
store *store.BlockStore
executor *state.BlockExecutor
state *state.State
}
// nolint:unused,deadcode
func newProcessorContext(st *store.BlockStore, ex *state.BlockExecutor, s *state.State) *pContext {
return &pContext{
store: st,
executor: ex,
state: s,
}
}
func (pc *pContext) applyBlock(state state.State, blockID types.BlockID, block *types.Block) (state.State, error) {
return pc.executor.ApplyBlock(state, blockID, block)
}
func (pc *pContext) verifyCommit(chainID string, blockID types.BlockID, height int64, commit *types.Commit) error {
return pc.state.Validators.VerifyCommit(chainID, blockID, height, commit)
}
func (pc *pContext) saveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
pc.store.SaveBlock(block, blockParts, seenCommit)
}
type mockPContext struct {
applicationBL []int64
verificationBL []int64
}
func newMockProcessorContext(verificationBlackList []int64, applicationBlackList []int64) *mockPContext {
return &mockPContext{
applicationBL: applicationBlackList,
verificationBL: verificationBlackList,
}
}
func (mpc *mockPContext) applyBlock(state state.State, blockID types.BlockID, block *types.Block) (state.State, error) {
for _, h := range mpc.applicationBL {
if h == block.Height {
return state, fmt.Errorf("generic application error")
}
}
return state, nil
}
func (mpc *mockPContext) verifyCommit(chainID string, blockID types.BlockID, height int64, commit *types.Commit) error {
for _, h := range mpc.verificationBL {
if h == height {
return fmt.Errorf("generic verification error")
}
}
return nil
}
func (mpc *mockPContext) saveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
}
+336
View File
@@ -0,0 +1,336 @@
package v2
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tendermint/tendermint/p2p"
tdState "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
)
// pcBlock is a test helper structure with simple types. Its purpose is to help with test readability.
type pcBlock struct {
pid string
height int64
}
// params is a test structure used to create processor state.
type params struct {
height int64
items []pcBlock
blocksSynced int64
verBL []int64
appBL []int64
draining bool
}
// makePcBlock makes an empty block.
func makePcBlock(height int64) *types.Block {
return &types.Block{Header: types.Header{Height: height}}
}
// makeState takes test parameters and creates a specific processor state.
func makeState(p *params) *pcState {
var (
tdState = tdState.State{}
context = newMockProcessorContext(p.verBL, p.appBL)
)
state := newPcState(p.height, tdState, "test", context)
for _, item := range p.items {
_ = state.enqueue(p2p.ID(item.pid), makePcBlock(item.height), item.height)
}
state.blocksSynced = p.blocksSynced
state.draining = p.draining
return state
}
func mBlockResponse(peerID p2p.ID, height int64) *bcBlockResponse {
return &bcBlockResponse{
peerID: peerID,
block: makePcBlock(height),
height: height,
}
}
type pcFsmMakeStateValues struct {
currentState *params
event Event
wantState *params
wantNextEvent Event
wantErr error
wantPanic bool
}
type testFields struct {
name string
steps []pcFsmMakeStateValues
}
func executeProcessorTests(t *testing.T, tests []testFields) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
var state *pcState
for _, step := range tt.steps {
defer func() {
r := recover()
if (r != nil) != step.wantPanic {
t.Errorf("recover = %v, wantPanic = %v", r, step.wantPanic)
}
}()
// First step must always initialise the currentState as state.
if step.currentState != nil {
state = makeState(step.currentState)
}
if state == nil {
panic("Bad (initial?) step")
}
nextEvent, err := state.handle(step.event)
t.Log(state)
assert.Equal(t, step.wantErr, err)
assert.Equal(t, makeState(step.wantState), state)
assert.Equal(t, step.wantNextEvent, nextEvent)
// Next step may use the wantedState as their currentState.
state = makeState(step.wantState)
}
})
}
}
func TestPcBlockResponse(t *testing.T) {
tests := []testFields{
{
name: "add one block",
steps: []pcFsmMakeStateValues{
{
currentState: &params{}, event: mBlockResponse("P1", 1),
wantState: &params{items: []pcBlock{{"P1", 1}}}, wantNextEvent: noOp,
},
},
},
{
name: "add two blocks",
steps: []pcFsmMakeStateValues{
{
currentState: &params{}, event: mBlockResponse("P1", 3),
wantState: &params{items: []pcBlock{{"P1", 3}}}, wantNextEvent: noOp,
},
{ // use previous wantState as currentState,
event: mBlockResponse("P1", 4),
wantState: &params{items: []pcBlock{{"P1", 3}, {"P1", 4}}}, wantNextEvent: noOp,
},
},
},
{
name: "add duplicate block from same peer",
steps: []pcFsmMakeStateValues{
{
currentState: &params{}, event: mBlockResponse("P1", 3),
wantState: &params{items: []pcBlock{{"P1", 3}}}, wantNextEvent: noOp,
},
{ // use previous wantState as currentState,
event: mBlockResponse("P1", 3),
wantState: &params{items: []pcBlock{{"P1", 3}}}, wantNextEvent: pcDuplicateBlock{},
},
},
},
{
name: "add duplicate block from different peer",
steps: []pcFsmMakeStateValues{
{
currentState: &params{}, event: mBlockResponse("P1", 3),
wantState: &params{items: []pcBlock{{"P1", 3}}}, wantNextEvent: noOp,
},
{ // use previous wantState as currentState,
event: mBlockResponse("P2", 3),
wantState: &params{items: []pcBlock{{"P1", 3}}}, wantNextEvent: pcDuplicateBlock{},
},
},
},
{
name: "attempt to add block with height equal to state.height",
steps: []pcFsmMakeStateValues{
{
currentState: &params{height: 2, items: []pcBlock{{"P1", 3}}}, event: mBlockResponse("P1", 2),
wantState: &params{height: 2, items: []pcBlock{{"P1", 3}}}, wantNextEvent: pcShortBlock{},
},
},
},
{
name: "attempt to add block with height smaller than state.height",
steps: []pcFsmMakeStateValues{
{
currentState: &params{height: 2, items: []pcBlock{{"P1", 3}}}, event: mBlockResponse("P1", 1),
wantState: &params{height: 2, items: []pcBlock{{"P1", 3}}}, wantNextEvent: pcShortBlock{},
},
},
},
}
executeProcessorTests(t, tests)
}
func TestPcProcessBlockSuccess(t *testing.T) {
tests := []testFields{
{
name: "noop - no blocks over current height",
steps: []pcFsmMakeStateValues{
{
currentState: &params{}, event: pcProcessBlock{},
wantState: &params{}, wantNextEvent: noOp,
},
},
},
{
name: "noop - high new blocks",
steps: []pcFsmMakeStateValues{
{
currentState: &params{height: 5, items: []pcBlock{{"P1", 30}, {"P2", 31}}}, event: pcProcessBlock{},
wantState: &params{height: 5, items: []pcBlock{{"P1", 30}, {"P2", 31}}}, wantNextEvent: noOp,
},
},
},
{
name: "blocks H+1 and H+2 present",
steps: []pcFsmMakeStateValues{
{
currentState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}}}, event: pcProcessBlock{},
wantState: &params{height: 1, items: []pcBlock{{"P2", 2}}, blocksSynced: 1},
wantNextEvent: pcBlockProcessed{height: 1, peerID: "P1"},
},
},
},
{
name: "blocks H+1 and H+2 present after draining",
steps: []pcFsmMakeStateValues{
{ // some contiguous blocks - on stop check draining is set
currentState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}, {"P1", 4}}}, event: pcStop{},
wantState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}, {"P1", 4}}, draining: true},
wantNextEvent: noOp,
},
{
event: pcProcessBlock{},
wantState: &params{height: 1, items: []pcBlock{{"P2", 2}, {"P1", 4}}, blocksSynced: 1, draining: true},
wantNextEvent: pcBlockProcessed{height: 1, peerID: "P1"},
},
{ // finish when H+1 or/and H+2 are missing
event: pcProcessBlock{},
wantState: &params{height: 1, items: []pcBlock{{"P2", 2}, {"P1", 4}}, blocksSynced: 1, draining: true},
wantNextEvent: noOp,
wantErr: pcFinished{height: 1},
},
},
},
}
executeProcessorTests(t, tests)
}
func TestPcProcessBlockFailures(t *testing.T) {
tests := []testFields{
{
name: "blocks H+1 and H+2 present - H+1 verification fails ",
steps: []pcFsmMakeStateValues{
{
currentState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}}, verBL: []int64{1}}, event: pcProcessBlock{},
wantState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}}, verBL: []int64{1}},
wantNextEvent: pcBlockVerificationFailure{peerID: "P1", height: 1},
},
},
},
{
name: "blocks H+1 and H+2 present - H+1 applyBlock fails ",
steps: []pcFsmMakeStateValues{
{
currentState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}}, appBL: []int64{1}}, event: pcProcessBlock{},
wantState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}}, appBL: []int64{1}}, wantPanic: true,
},
},
},
}
executeProcessorTests(t, tests)
}
func TestPcPeerError(t *testing.T) {
tests := []testFields{
{
name: "peer not present",
steps: []pcFsmMakeStateValues{
{
currentState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}}}, event: &peerError{peerID: "P3"},
wantState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}}},
wantNextEvent: noOp,
},
},
},
{
name: "some blocks are from errored peer",
steps: []pcFsmMakeStateValues{
{
currentState: &params{items: []pcBlock{{"P1", 100}, {"P1", 99}, {"P2", 101}}}, event: &peerError{peerID: "P1"},
wantState: &params{items: []pcBlock{{"P2", 101}}},
wantNextEvent: noOp,
},
},
},
{
name: "all blocks are from errored peer",
steps: []pcFsmMakeStateValues{
{
currentState: &params{items: []pcBlock{{"P1", 100}, {"P1", 99}}}, event: &peerError{peerID: "P1"},
wantState: &params{},
wantNextEvent: noOp,
},
},
},
}
executeProcessorTests(t, tests)
}
func TestStop(t *testing.T) {
tests := []testFields{
{
name: "no blocks",
steps: []pcFsmMakeStateValues{
{
currentState: &params{height: 100, items: []pcBlock{}, blocksSynced: 100}, event: pcStop{},
wantState: &params{height: 100, items: []pcBlock{}, blocksSynced: 100},
wantNextEvent: noOp,
wantErr: pcFinished{height: 100, blocksSynced: 100},
},
},
},
{
name: "maxHeight+1 block present",
steps: []pcFsmMakeStateValues{
{
currentState: &params{height: 100, items: []pcBlock{{"P1", 101}}, blocksSynced: 100}, event: pcStop{},
wantState: &params{height: 100, items: []pcBlock{{"P1", 101}}, blocksSynced: 100},
wantNextEvent: noOp,
wantErr: pcFinished{height: 100, blocksSynced: 100},
},
},
},
{
name: "more blocks present",
steps: []pcFsmMakeStateValues{
{
currentState: &params{height: 100, items: []pcBlock{{"P1", 101}, {"P1", 102}}, blocksSynced: 100}, event: pcStop{},
wantState: &params{height: 100, items: []pcBlock{{"P1", 101}, {"P1", 102}}, blocksSynced: 100, draining: true},
wantNextEvent: noOp,
wantErr: nil,
},
},
},
}
executeProcessorTests(t, tests)
}
+1
View File
@@ -69,6 +69,7 @@ func (r *Reactor) Start() {
}()
}
// XXX: How to make this deterministic?
// XXX: Would it be possible here to provide some kind of type safety for the types
// of events that each routine can produce and consume?
func (r *Reactor) demux() {
+1
View File
@@ -164,6 +164,7 @@ func (sc *schedule) removePeer(peerID p2p.ID) error {
return nil
}
// TODO - keep track of highest height
func (sc *schedule) setPeerHeight(peerID p2p.ID, height int64) error {
peer, ok := sc.peers[peerID]
if !ok {
+5 -1
View File
@@ -40,7 +40,11 @@ func init() {
LiteCmd.Flags().StringVar(&nodeAddr, "node", "tcp://localhost:26657", "Connect to a Tendermint node at this address")
LiteCmd.Flags().StringVar(&chainID, "chain-id", "tendermint", "Specify the Tendermint chain ID")
LiteCmd.Flags().StringVar(&home, "home-dir", ".tendermint-lite", "Specify the home directory")
LiteCmd.Flags().IntVar(&maxOpenConnections, "max-open-connections", 900, "Maximum number of simultaneous connections (including WebSocket).")
LiteCmd.Flags().IntVar(
&maxOpenConnections,
"max-open-connections",
900,
"Maximum number of simultaneous connections (including WebSocket).")
LiteCmd.Flags().IntVar(&cacheSize, "cache-size", 10, "Specify the memory trust store cache size")
}
+23 -5
View File
@@ -16,22 +16,37 @@ func AddNodeFlags(cmd *cobra.Command) {
cmd.Flags().String("moniker", config.Moniker, "Node Name")
// priv val flags
cmd.Flags().String("priv_validator_laddr", config.PrivValidatorListenAddr, "Socket address to listen on for connections from external priv_validator process")
cmd.Flags().String(
"priv_validator_laddr",
config.PrivValidatorListenAddr,
"Socket address to listen on for connections from external priv_validator process")
// node flags
cmd.Flags().Bool("fast_sync", config.FastSyncMode, "Fast blockchain syncing")
// abci flags
cmd.Flags().String("proxy_app", config.ProxyApp, "Proxy app address, or one of: 'kvstore', 'persistent_kvstore', 'counter', 'counter_serial' or 'noop' for local testing.")
cmd.Flags().String(
"proxy_app",
config.ProxyApp,
"Proxy app address, or one of: 'kvstore',"+
" 'persistent_kvstore',"+
" 'counter',"+
" 'counter_serial' or 'noop' for local testing.")
cmd.Flags().String("abci", config.ABCI, "Specify abci transport (socket | grpc)")
// rpc flags
cmd.Flags().String("rpc.laddr", config.RPC.ListenAddress, "RPC listen address. Port required")
cmd.Flags().String("rpc.grpc_laddr", config.RPC.GRPCListenAddress, "GRPC listen address (BroadcastTx only). Port required")
cmd.Flags().String(
"rpc.grpc_laddr",
config.RPC.GRPCListenAddress,
"GRPC listen address (BroadcastTx only). Port required")
cmd.Flags().Bool("rpc.unsafe", config.RPC.Unsafe, "Enabled unsafe rpc methods")
// p2p flags
cmd.Flags().String("p2p.laddr", config.P2P.ListenAddress, "Node listen address. (0.0.0.0:0 means any interface, any port)")
cmd.Flags().String(
"p2p.laddr",
config.P2P.ListenAddress,
"Node listen address. (0.0.0.0:0 means any interface, any port)")
cmd.Flags().String("p2p.seeds", config.P2P.Seeds, "Comma-delimited ID@host:port seed nodes")
cmd.Flags().String("p2p.persistent_peers", config.P2P.PersistentPeers, "Comma-delimited ID@host:port persistent peers")
cmd.Flags().Bool("p2p.upnp", config.P2P.UPNP, "Enable/disable UPNP port forwarding")
@@ -40,7 +55,10 @@ func AddNodeFlags(cmd *cobra.Command) {
cmd.Flags().String("p2p.private_peer_ids", config.P2P.PrivatePeerIDs, "Comma-delimited private peer IDs")
// consensus flags
cmd.Flags().Bool("consensus.create_empty_blocks", config.Consensus.CreateEmptyBlocks, "Set this to false to only produce blocks when there are txs or when the AppHash changes")
cmd.Flags().Bool(
"consensus.create_empty_blocks",
config.Consensus.CreateEmptyBlocks,
"Set this to false to only produce blocks when there are txs or when the AppHash changes")
}
// NewRunNodeCmd returns the command that allows the CLI to start a node.
+9 -3
View File
@@ -51,13 +51,19 @@ func init() {
"Prefix the directory name for each node with (node results in node0, node1, ...)")
TestnetFilesCmd.Flags().BoolVar(&populatePersistentPeers, "populate-persistent-peers", true,
"Update config of each node with the list of persistent peers build using either hostname-prefix or starting-ip-address")
"Update config of each node with the list of persistent peers build using either"+
" hostname-prefix or"+
" starting-ip-address")
TestnetFilesCmd.Flags().StringVar(&hostnamePrefix, "hostname-prefix", "node",
"Hostname prefix (\"node\" results in persistent peers list ID0@node0:26656, ID1@node1:26656, ...)")
TestnetFilesCmd.Flags().StringVar(&hostnameSuffix, "hostname-suffix", "",
"Hostname suffix (\".xyz.com\" results in persistent peers list ID0@node0.xyz.com:26656, ID1@node1.xyz.com:26656, ...)")
"Hostname suffix ("+
"\".xyz.com\""+
" results in persistent peers list ID0@node0.xyz.com:26656, ID1@node1.xyz.com:26656, ...)")
TestnetFilesCmd.Flags().StringVar(&startingIPAddress, "starting-ip-address", "",
"Starting IP address (\"192.168.0.1\" results in persistent peers list ID0@192.168.0.1:26656, ID1@192.168.0.2:26656, ...)")
"Starting IP address ("+
"\"192.168.0.1\""+
" results in persistent peers list ID0@192.168.0.1:26656, ID1@192.168.0.2:26656, ...)")
TestnetFilesCmd.Flags().StringArrayVar(&hostnames, "hostname", []string{},
"Manually override all hostnames of validators and non-validators (use --hostname multiple times for multiple hosts)")
TestnetFilesCmd.Flags().IntVar(&p2pPort, "p2p-port", 26656,
+10 -6
View File
@@ -140,7 +140,7 @@ func (cfg *Config) ValidateBasic() error {
// BaseConfig
// BaseConfig defines the base configuration for a Tendermint node
type BaseConfig struct {
type BaseConfig struct { //nolint: maligned
// chainID is unexposed and immutable but here for convenience
chainID string
@@ -371,13 +371,15 @@ type RPCConfig struct {
// the certFile should be the concatenation of the server's certificate, any intermediates,
// and the CA's certificate.
//
// NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server. Otherwise, HTTP server is run.
// NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server.
// Otherwise, HTTP server is run.
TLSCertFile string `mapstructure:"tls_cert_file"`
// The path to a file containing matching private key that is used to create the HTTPS server.
// Migth be either absolute path or path related to tendermint's config directory.
//
// NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server. Otherwise, HTTP server is run.
// NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server.
// Otherwise, HTTP server is run.
TLSKeyFile string `mapstructure:"tls_key_file"`
}
@@ -471,7 +473,7 @@ func (cfg RPCConfig) IsTLSEnabled() bool {
// P2PConfig
// P2PConfig defines the configuration options for the Tendermint peer-to-peer networking layer
type P2PConfig struct {
type P2PConfig struct { //nolint: maligned
RootDir string `mapstructure:"home"`
// Address to listen for incoming connections
@@ -814,7 +816,8 @@ func (cfg *ConsensusConfig) Precommit(round int) time.Duration {
) * time.Nanosecond
}
// Commit returns the amount of time to wait for straggler votes after receiving +2/3 precommits for a single block (ie. a commit).
// Commit returns the amount of time to wait for straggler votes after receiving +2/3 precommits
// for a single block (ie. a commit).
func (cfg *ConsensusConfig) Commit(t time.Time) time.Time {
return t.Add(cfg.TimeoutCommit)
}
@@ -878,7 +881,8 @@ type TxIndexConfig struct {
//
// Options:
// 1) "null"
// 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend).
// 2) "kv" (default) - the simplest possible indexer,
// backed by key-value storage (defaults to levelDB; see DBBackend).
Indexer string `mapstructure:"indexer"`
// Comma-separated list of tags to index (by default the only tag is "tx.hash")
+9 -2
View File
@@ -67,6 +67,11 @@ func WriteConfigFile(configFilePath string, config *Config) {
const defaultConfigTemplate = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
# NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or
# relative to the home directory (e.g. "data"). The home directory is
# "$HOME/.tendermint" by default, but could be changed via $TMHOME env variable
# or --home cmd flag.
##### main base config options #####
# TCP or UNIX socket address of the ABCI application,
@@ -203,12 +208,14 @@ max_header_bytes = {{ .RPC.MaxHeaderBytes }}
# If the certificate is signed by a certificate authority,
# the certFile should be the concatenation of the server's certificate, any intermediates,
# and the CA's certificate.
# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server. Otherwise, HTTP server is run.
# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server.
# Otherwise, HTTP server is run.
tls_cert_file = "{{ .RPC.TLSCertFile }}"
# The path to a file containing matching private key that is used to create the HTTPS server.
# Migth be either absolute path or path related to tendermint's config directory.
# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server. Otherwise, HTTP server is run.
# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server.
# Otherwise, HTTP server is run.
tls_key_file = "{{ .RPC.TLSKeyFile }}"
##### peer to peer configuration options #####
+8 -1
View File
@@ -206,7 +206,14 @@ func byzantineDecideProposalFunc(t *testing.T, height int64, round int, cs *Cons
}
}
func sendProposalAndParts(height int64, round int, cs *ConsensusState, peer p2p.Peer, proposal *types.Proposal, blockHash []byte, parts *types.PartSet) {
func sendProposalAndParts(
height int64,
round int,
cs *ConsensusState,
peer p2p.Peer,
proposal *types.Proposal,
blockHash []byte,
parts *types.PartSet) {
// proposal
msg := &ProposalMessage{Proposal: proposal}
peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg))
+66 -12
View File
@@ -77,7 +77,10 @@ func NewValidatorStub(privValidator types.PrivValidator, valIndex int) *validato
}
}
func (vs *validatorStub) signVote(voteType types.SignedMsgType, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
func (vs *validatorStub) signVote(
voteType types.SignedMsgType,
hash []byte,
header types.PartSetHeader) (*types.Vote, error) {
addr := vs.PrivValidator.GetPubKey().Address()
vote := &types.Vote{
ValidatorIndex: vs.Index,
@@ -101,7 +104,11 @@ func signVote(vs *validatorStub, voteType types.SignedMsgType, hash []byte, head
return v
}
func signVotes(voteType types.SignedMsgType, hash []byte, header types.PartSetHeader, vss ...*validatorStub) []*types.Vote {
func signVotes(
voteType types.SignedMsgType,
hash []byte,
header types.PartSetHeader,
vss ...*validatorStub) []*types.Vote {
votes := make([]*types.Vote, len(vss))
for i, vs := range vss {
votes[i] = signVote(vs, voteType, hash, header)
@@ -148,7 +155,11 @@ func startTestRound(cs *ConsensusState, height int64, round int) {
}
// Create proposal block from cs1 but sign it with vs.
func decideProposal(cs1 *ConsensusState, vs *validatorStub, height int64, round int) (proposal *types.Proposal, block *types.Block) {
func decideProposal(
cs1 *ConsensusState,
vs *validatorStub,
height int64,
round int) (proposal *types.Proposal, block *types.Block) {
cs1.mtx.Lock()
block, blockParts := cs1.createProposalBlock()
validRound := cs1.ValidRound
@@ -173,7 +184,12 @@ func addVotes(to *ConsensusState, votes ...*types.Vote) {
}
}
func signAddVotes(to *ConsensusState, voteType types.SignedMsgType, hash []byte, header types.PartSetHeader, vss ...*validatorStub) {
func signAddVotes(
to *ConsensusState,
voteType types.SignedMsgType,
hash []byte,
header types.PartSetHeader,
vss ...*validatorStub) {
votes := signVotes(voteType, hash, header, vss...)
addVotes(to, votes...)
}
@@ -208,7 +224,14 @@ func validateLastPrecommit(t *testing.T, cs *ConsensusState, privVal *validatorS
}
}
func validatePrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *validatorStub, votedBlockHash, lockedBlockHash []byte) {
func validatePrecommit(
t *testing.T,
cs *ConsensusState,
thisRound,
lockRound int,
privVal *validatorStub,
votedBlockHash,
lockedBlockHash []byte) {
precommits := cs.Votes.Precommits(thisRound)
address := privVal.GetPubKey().Address()
var vote *types.Vote
@@ -228,17 +251,33 @@ func validatePrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound in
if lockedBlockHash == nil {
if cs.LockedRound != lockRound || cs.LockedBlock != nil {
panic(fmt.Sprintf("Expected to be locked on nil at round %d. Got locked at round %d with block %v", lockRound, cs.LockedRound, cs.LockedBlock))
panic(fmt.Sprintf(
"Expected to be locked on nil at round %d. Got locked at round %d with block %v",
lockRound,
cs.LockedRound,
cs.LockedBlock))
}
} else {
if cs.LockedRound != lockRound || !bytes.Equal(cs.LockedBlock.Hash(), lockedBlockHash) {
panic(fmt.Sprintf("Expected block to be locked on round %d, got %d. Got locked block %X, expected %X", lockRound, cs.LockedRound, cs.LockedBlock.Hash(), lockedBlockHash))
panic(fmt.Sprintf(
"Expected block to be locked on round %d, got %d. Got locked block %X, expected %X",
lockRound,
cs.LockedRound,
cs.LockedBlock.Hash(),
lockedBlockHash))
}
}
}
func validatePrevoteAndPrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *validatorStub, votedBlockHash, lockedBlockHash []byte) {
func validatePrevoteAndPrecommit(
t *testing.T,
cs *ConsensusState,
thisRound,
lockRound int,
privVal *validatorStub,
votedBlockHash,
lockedBlockHash []byte) {
// verify the prevote
validatePrevote(t, cs, thisRound, privVal, votedBlockHash)
// verify precommit
@@ -273,12 +312,21 @@ func newConsensusState(state sm.State, pv types.PrivValidator, app abci.Applicat
return newConsensusStateWithConfig(config, state, pv, app)
}
func newConsensusStateWithConfig(thisConfig *cfg.Config, state sm.State, pv types.PrivValidator, app abci.Application) *ConsensusState {
func newConsensusStateWithConfig(
thisConfig *cfg.Config,
state sm.State,
pv types.PrivValidator,
app abci.Application) *ConsensusState {
blockDB := dbm.NewMemDB()
return newConsensusStateWithConfigAndBlockStore(thisConfig, state, pv, app, blockDB)
}
func newConsensusStateWithConfigAndBlockStore(thisConfig *cfg.Config, state sm.State, pv types.PrivValidator, app abci.Application, blockDB dbm.DB) *ConsensusState {
func newConsensusStateWithConfigAndBlockStore(
thisConfig *cfg.Config,
state sm.State,
pv types.PrivValidator,
app abci.Application,
blockDB dbm.DB) *ConsensusState {
// Get BlockStore
blockStore := store.NewBlockStore(blockDB)
@@ -597,7 +645,12 @@ func randConsensusNet(nValidators int, testName string, tickerFunc func() Timeou
}
// nPeers = nValidators + nNotValidator
func randConsensusNetWithPeers(nValidators, nPeers int, testName string, tickerFunc func() TimeoutTicker, appFunc func(string) abci.Application) ([]*ConsensusState, *types.GenesisDoc, *cfg.Config, cleanupFunc) {
func randConsensusNetWithPeers(
nValidators,
nPeers int,
testName string,
tickerFunc func() TimeoutTicker,
appFunc func(string) abci.Application) ([]*ConsensusState, *types.GenesisDoc, *cfg.Config, cleanupFunc) {
genDoc, privVals := randGenesisDoc(nValidators, false, testMinPower)
css := make([]*ConsensusState, nPeers)
logger := consensusLogger()
@@ -631,7 +684,8 @@ func randConsensusNetWithPeers(nValidators, nPeers int, testName string, tickerF
app := appFunc(path.Join(config.DBDir(), fmt.Sprintf("%s_%d", testName, i)))
vals := types.TM2PB.ValidatorUpdates(state.Validators)
if _, ok := app.(*kvstore.PersistentKVStoreApplication); ok {
state.Version.Consensus.App = kvstore.ProtocolVersion //simulate handshake, receive app version. If don't do this, replay test will fail
// simulate handshake, receive app version. If don't do this, replay test will fail
state.Version.Consensus.App = kvstore.ProtocolVersion
}
app.InitChain(abci.RequestInitChain{Validators: vals})
//sm.SaveState(stateDB,state) //height 1's validatorsInfo already saved in LoadStateFromDBOrGenesisDoc above
+2 -2
View File
@@ -99,7 +99,7 @@ func deliverTxsRange(cs *ConsensusState, start, end int) {
for i := start; i < end; i++ {
txBytes := make([]byte, 8)
binary.BigEndian.PutUint64(txBytes, uint64(i))
err := assertMempool(cs.txNotifier).CheckTx(txBytes, nil)
err := assertMempool(cs.txNotifier).CheckTx(txBytes, nil, mempl.TxInfo{})
if err != nil {
panic(fmt.Sprintf("Error after CheckTx: %v", err))
}
@@ -159,7 +159,7 @@ func TestMempoolRmBadTx(t *testing.T) {
return
}
checkTxRespCh <- struct{}{}
})
}, mempl.TxInfo{})
if err != nil {
t.Errorf("Error after CheckTx: %v", err)
return
+20 -5
View File
@@ -137,8 +137,9 @@ func (conR *ConsensusReactor) GetChannels() []*p2p.ChannelDescriptor {
RecvMessageCapacity: maxMsgSize,
},
{
ID: DataChannel, // maybe split between gossiping current block and catchup stuff
Priority: 10, // once we gossip the whole block there's nothing left to send until next height or round
ID: DataChannel, // maybe split between gossiping current block and catchup stuff
// once we gossip the whole block there's nothing left to send until next height or round
Priority: 10,
SendQueueCapacity: 100,
RecvBufferCapacity: 50 * 4096,
RecvMessageCapacity: maxMsgSize,
@@ -670,7 +671,11 @@ OUTER_LOOP:
}
}
func (conR *ConsensusReactor) gossipVotesForHeight(logger log.Logger, rs *cstypes.RoundState, prs *cstypes.PeerRoundState, ps *PeerState) bool {
func (conR *ConsensusReactor) gossipVotesForHeight(
logger log.Logger,
rs *cstypes.RoundState,
prs *cstypes.PeerRoundState,
ps *PeerState) bool {
// If there are lastCommits to send...
if prs.Step == cstypes.RoundStepNewHeight {
@@ -1119,7 +1124,13 @@ func (ps *PeerState) ensureCatchupCommitRound(height int64, round int, numValida
NOTE: This is wrong, 'round' could change.
e.g. if orig round is not the same as block LastCommit round.
if ps.CatchupCommitRound != -1 && ps.CatchupCommitRound != round {
panic(fmt.Sprintf("Conflicting CatchupCommitRound. Height: %v, Orig: %v, New: %v", height, ps.CatchupCommitRound, round))
panic(fmt.Sprintf(
"Conflicting CatchupCommitRound. Height: %v,
Orig: %v,
New: %v",
height,
ps.CatchupCommitRound,
round))
}
*/
if ps.PRS.CatchupCommitRound == round {
@@ -1211,7 +1222,11 @@ func (ps *PeerState) SetHasVote(vote *types.Vote) {
}
func (ps *PeerState) setHasVote(height int64, round int, type_ types.SignedMsgType, index int) {
logger := ps.logger.With("peerH/R", fmt.Sprintf("%d/%d", ps.PRS.Height, ps.PRS.Round), "H/R", fmt.Sprintf("%d/%d", height, round))
logger := ps.logger.With(
"peerH/R",
fmt.Sprintf("%d/%d", ps.PRS.Height, ps.PRS.Round),
"H/R",
fmt.Sprintf("%d/%d", height, round))
logger.Debug("setHasVote", "type", type_, "index", index)
// NOTE: some may be nil BitArrays -> no side effects.
+70 -43
View File
@@ -237,7 +237,7 @@ func TestReactorCreatesBlockWhenEmptyBlocksFalse(t *testing.T) {
defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses)
// send a tx
if err := assertMempool(css[3].txNotifier).CheckTx([]byte{1, 2, 3}, nil); err != nil {
if err := assertMempool(css[3].txNotifier).CheckTx([]byte{1, 2, 3}, nil, mempl.TxInfo{}); err != nil {
t.Error(err)
}
@@ -318,7 +318,11 @@ func TestReactorRecordsVotesAndBlockParts(t *testing.T) {
func TestReactorVotingPowerChange(t *testing.T) {
nVals := 4
logger := log.TestingLogger()
css, cleanup := randConsensusNet(nVals, "consensus_voting_power_changes_test", newMockTickerFunc(true), newPersistentKVStore)
css, cleanup := randConsensusNet(
nVals,
"consensus_voting_power_changes_test",
newMockTickerFunc(true),
newPersistentKVStore)
defer cleanup()
reactors, blocksSubs, eventBuses := startConsensusNet(t, css, nVals)
defer stopConsensusNet(logger, reactors, eventBuses)
@@ -349,7 +353,10 @@ func TestReactorVotingPowerChange(t *testing.T) {
waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css)
if css[0].GetRoundState().LastValidators.TotalVotingPower() == previousTotalVotingPower {
t.Fatalf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[0].GetRoundState().LastValidators.TotalVotingPower())
t.Fatalf(
"expected voting power to change (before: %d, after: %d)",
previousTotalVotingPower,
css[0].GetRoundState().LastValidators.TotalVotingPower())
}
updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKeyABCI, 2)
@@ -361,7 +368,10 @@ func TestReactorVotingPowerChange(t *testing.T) {
waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css)
if css[0].GetRoundState().LastValidators.TotalVotingPower() == previousTotalVotingPower {
t.Fatalf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[0].GetRoundState().LastValidators.TotalVotingPower())
t.Fatalf(
"expected voting power to change (before: %d, after: %d)",
previousTotalVotingPower,
css[0].GetRoundState().LastValidators.TotalVotingPower())
}
updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKeyABCI, 26)
@@ -373,14 +383,22 @@ func TestReactorVotingPowerChange(t *testing.T) {
waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css)
if css[0].GetRoundState().LastValidators.TotalVotingPower() == previousTotalVotingPower {
t.Fatalf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[0].GetRoundState().LastValidators.TotalVotingPower())
t.Fatalf(
"expected voting power to change (before: %d, after: %d)",
previousTotalVotingPower,
css[0].GetRoundState().LastValidators.TotalVotingPower())
}
}
func TestReactorValidatorSetChanges(t *testing.T) {
nPeers := 7
nVals := 4
css, _, _, cleanup := randConsensusNetWithPeers(nVals, nPeers, "consensus_val_set_changes_test", newMockTickerFunc(true), newPersistentKVStoreWithPath)
css, _, _, cleanup := randConsensusNetWithPeers(
nVals,
nPeers,
"consensus_val_set_changes_test",
newMockTickerFunc(true),
newPersistentKVStoreWithPath)
defer cleanup()
logger := log.TestingLogger()
@@ -441,7 +459,10 @@ func TestReactorValidatorSetChanges(t *testing.T) {
waitForBlockWithUpdatedValsAndValidateIt(t, nPeers, activeVals, blocksSubs, css)
if css[nVals].GetRoundState().LastValidators.TotalVotingPower() == previousTotalVotingPower {
t.Errorf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[nVals].GetRoundState().LastValidators.TotalVotingPower())
t.Errorf(
"expected voting power to change (before: %d, after: %d)",
previousTotalVotingPower,
css[nVals].GetRoundState().LastValidators.TotalVotingPower())
}
//---------------------------------------------------------------------------
@@ -511,7 +532,7 @@ func waitForAndValidateBlock(
err := validateBlock(newBlock, activeVals)
assert.Nil(t, err)
for _, tx := range txs {
err := assertMempool(css[j].txNotifier).CheckTx(tx, nil)
err := assertMempool(css[j].txNotifier).CheckTx(tx, nil, mempl.TxInfo{})
assert.Nil(t, err)
}
}, css)
@@ -571,7 +592,10 @@ func waitForBlockWithUpdatedValsAndValidateIt(
css[j].Logger.Debug("waitForBlockWithUpdatedValsAndValidateIt: Got block", "height", newBlock.Height)
break LOOP
} else {
css[j].Logger.Debug("waitForBlockWithUpdatedValsAndValidateIt: Got block with no new validators. Skipping", "height", newBlock.Height)
css[j].Logger.Debug(
"waitForBlockWithUpdatedValsAndValidateIt: Got block with no new validators. Skipping",
"height",
newBlock.Height)
}
}
@@ -583,7 +607,10 @@ func waitForBlockWithUpdatedValsAndValidateIt(
// expects high synchrony!
func validateBlock(block *types.Block, activeVals map[string]struct{}) error {
if block.LastCommit.Size() != len(activeVals) {
return fmt.Errorf("Commit size doesn't match number of active validators. Got %d, expected %d", block.LastCommit.Size(), len(activeVals))
return fmt.Errorf(
"Commit size doesn't match number of active validators. Got %d, expected %d",
block.LastCommit.Size(),
len(activeVals))
}
for _, vote := range block.LastCommit.Precommits {
@@ -640,20 +667,20 @@ func capture() {
// Ensure basic validation of structs is functioning
func TestNewRoundStepMessageValidateBasic(t *testing.T) {
testCases := []struct {
testName string
messageHeight int64
messageRound int
messageStep cstypes.RoundStepType
messageLastCommitRound int
testCases := []struct { // nolint: maligned
expectErr bool
messageRound int
messageLastCommitRound int
messageHeight int64
testName string
messageStep cstypes.RoundStepType
}{
{"Valid Message", 0, 0, 0x01, 1, false},
{"Invalid Message", -1, 0, 0x01, 1, true},
{"Invalid Message", 0, -1, 0x01, 1, true},
{"Invalid Message", 0, 0, 0x00, 1, true},
{"Invalid Message", 0, 0, 0x00, 0, true},
{"Invalid Message", 1, 0, 0x01, 0, true},
{false, 0, 0, 0, "Valid Message", 0x01},
{true, -1, 0, 0, "Invalid Message", 0x01},
{true, 0, 0, -1, "Invalid Message", 0x01},
{true, 0, 0, 1, "Invalid Message", 0x00},
{true, 0, 0, 1, "Invalid Message", 0x00},
{true, 0, -2, 2, "Invalid Message", 0x01},
}
for _, tc := range testCases {
@@ -785,19 +812,19 @@ func TestHasVoteMessageValidateBasic(t *testing.T) {
invalidSignedMsgType types.SignedMsgType = 0x03
)
testCases := []struct {
testName string
messageHeight int64
messageRound int
messageType types.SignedMsgType
messageIndex int
testCases := []struct { // nolint: maligned
expectErr bool
messageRound int
messageIndex int
messageHeight int64
testName string
messageType types.SignedMsgType
}{
{"Valid Message", 0, 0, validSignedMsgType, 0, false},
{"Invalid Message", -1, 0, validSignedMsgType, 0, true},
{"Invalid Message", 0, -1, validSignedMsgType, 0, true},
{"Invalid Message", 0, 0, invalidSignedMsgType, 0, true},
{"Invalid Message", 0, 0, validSignedMsgType, -1, true},
{false, 0, 0, 0, "Valid Message", validSignedMsgType},
{true, -1, 0, 0, "Invalid Message", validSignedMsgType},
{true, 0, -1, 0, "Invalid Message", validSignedMsgType},
{true, 0, 0, 0, "Invalid Message", invalidSignedMsgType},
{true, 0, 0, -1, "Invalid Message", validSignedMsgType},
}
for _, tc := range testCases {
@@ -830,19 +857,19 @@ func TestVoteSetMaj23MessageValidateBasic(t *testing.T) {
},
}
testCases := []struct {
testName string
messageHeight int64
testCases := []struct { // nolint: maligned
expectErr bool
messageRound int
messageHeight int64
testName string
messageType types.SignedMsgType
messageBlockID types.BlockID
expectErr bool
}{
{"Valid Message", 0, 0, validSignedMsgType, validBlockID, false},
{"Invalid Message", -1, 0, validSignedMsgType, validBlockID, true},
{"Invalid Message", 0, -1, validSignedMsgType, validBlockID, true},
{"Invalid Message", 0, 0, invalidSignedMsgType, validBlockID, true},
{"Invalid Message", 0, 0, validSignedMsgType, invalidBlockID, true},
{false, 0, 0, "Valid Message", validSignedMsgType, validBlockID},
{true, -1, 0, "Invalid Message", validSignedMsgType, validBlockID},
{true, 0, -1, "Invalid Message", validSignedMsgType, validBlockID},
{true, 0, 0, "Invalid Message", invalidSignedMsgType, validBlockID},
{true, 0, 0, "Invalid Message", validSignedMsgType, invalidBlockID},
}
for _, tc := range testCases {
@@ -861,7 +888,7 @@ func TestVoteSetMaj23MessageValidateBasic(t *testing.T) {
}
func TestVoteSetBitsMessageValidateBasic(t *testing.T) {
testCases := []struct { // nolint: maligned
testCases := []struct {
malleateFn func(*VoteSetBitsMessage)
expErr string
}{
+14 -2
View File
@@ -290,7 +290,14 @@ func (h *Handshaker) ReplayBlocks(
) ([]byte, error) {
storeBlockHeight := h.store.Height()
stateBlockHeight := state.LastBlockHeight
h.logger.Info("ABCI Replay Blocks", "appHeight", appBlockHeight, "storeHeight", storeBlockHeight, "stateHeight", stateBlockHeight)
h.logger.Info(
"ABCI Replay Blocks",
"appHeight",
appBlockHeight,
"storeHeight",
storeBlockHeight,
"stateHeight",
stateBlockHeight)
// If appBlockHeight == 0 it means that we are at genesis and hence should send InitChain.
if appBlockHeight == 0 {
@@ -405,7 +412,12 @@ func (h *Handshaker) ReplayBlocks(
appBlockHeight, storeBlockHeight, stateBlockHeight))
}
func (h *Handshaker) replayBlocks(state sm.State, proxyApp proxy.AppConns, appBlockHeight, storeBlockHeight int64, mutateState bool) ([]byte, error) {
func (h *Handshaker) replayBlocks(
state sm.State,
proxyApp proxy.AppConns,
appBlockHeight,
storeBlockHeight int64,
mutateState bool) ([]byte, error) {
// App is further behind than it should be, so we need to replay blocks.
// We replay all blocks from appBlockHeight+1.
//
+57 -18
View File
@@ -23,6 +23,7 @@ import (
"github.com/tendermint/tendermint/crypto"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/libs/log"
mempl "github.com/tendermint/tendermint/mempool"
"github.com/tendermint/tendermint/mock"
"github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"
@@ -67,7 +68,12 @@ func startNewConsensusStateAndWaitForBlock(t *testing.T, consensusReplayConfig *
logger := log.TestingLogger()
state, _ := sm.LoadStateFromDBOrGenesisFile(stateDB, consensusReplayConfig.GenesisFile())
privValidator := loadPrivValidator(consensusReplayConfig)
cs := newConsensusStateWithConfigAndBlockStore(consensusReplayConfig, state, privValidator, kvstore.NewKVStoreApplication(), blockDB)
cs := newConsensusStateWithConfigAndBlockStore(
consensusReplayConfig,
state,
privValidator,
kvstore.NewKVStoreApplication(),
blockDB)
cs.SetLogger(logger)
bytes, _ := ioutil.ReadFile(cs.config.WalFile())
@@ -99,7 +105,7 @@ func sendTxs(ctx context.Context, cs *ConsensusState) {
return
default:
tx := []byte{byte(i)}
assertMempool(cs.txNotifier).CheckTx(tx, nil)
assertMempool(cs.txNotifier).CheckTx(tx, nil, mempl.TxInfo{})
i++
}
}
@@ -147,7 +153,12 @@ LOOP:
stateDB := blockDB
state, _ := sm.MakeGenesisStateFromFile(consensusReplayConfig.GenesisFile())
privValidator := loadPrivValidator(consensusReplayConfig)
cs := newConsensusStateWithConfigAndBlockStore(consensusReplayConfig, state, privValidator, kvstore.NewKVStoreApplication(), blockDB)
cs := newConsensusStateWithConfigAndBlockStore(
consensusReplayConfig,
state,
privValidator,
kvstore.NewKVStoreApplication(),
blockDB)
cs.SetLogger(logger)
// start sending transactions
@@ -257,7 +268,9 @@ func (w *crashingWAL) WriteSync(m WALMessage) error {
func (w *crashingWAL) FlushAndSync() error { return w.next.FlushAndSync() }
func (w *crashingWAL) SearchForEndHeight(height int64, options *WALSearchOptions) (rd io.ReadCloser, found bool, err error) {
func (w *crashingWAL) SearchForEndHeight(
height int64,
options *WALSearchOptions) (rd io.ReadCloser, found bool, err error) {
return w.next.SearchForEndHeight(height, options)
}
@@ -297,7 +310,12 @@ var modes = []uint{0, 1, 2}
func TestSimulateValidatorsChange(t *testing.T) {
nPeers := 7
nVals := 4
css, genDoc, config, cleanup := randConsensusNetWithPeers(nVals, nPeers, "replay_test", newMockTickerFunc(true), newPersistentKVStoreWithPath)
css, genDoc, config, cleanup := randConsensusNetWithPeers(
nVals,
nPeers,
"replay_test",
newMockTickerFunc(true),
newPersistentKVStoreWithPath)
sim.Config = config
sim.GenesisState, _ = sm.MakeGenesisState(genDoc)
sim.CleanupFunc = cleanup
@@ -327,7 +345,7 @@ func TestSimulateValidatorsChange(t *testing.T) {
newValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
valPubKey1ABCI := types.TM2PB.PubKey(newValidatorPubKey1)
newValidatorTx1 := kvstore.MakeValSetChangeTx(valPubKey1ABCI, testMinPower)
err := assertMempool(css[0].txNotifier).CheckTx(newValidatorTx1, nil)
err := assertMempool(css[0].txNotifier).CheckTx(newValidatorTx1, nil, mempl.TxInfo{})
assert.Nil(t, err)
propBlock, _ := css[0].createProposalBlock() //changeProposer(t, cs1, vs2)
propBlockParts := propBlock.MakePartSet(partSize)
@@ -352,7 +370,7 @@ func TestSimulateValidatorsChange(t *testing.T) {
updateValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
updatePubKey1ABCI := types.TM2PB.PubKey(updateValidatorPubKey1)
updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 25)
err = assertMempool(css[0].txNotifier).CheckTx(updateValidatorTx1, nil)
err = assertMempool(css[0].txNotifier).CheckTx(updateValidatorTx1, nil, mempl.TxInfo{})
assert.Nil(t, err)
propBlock, _ = css[0].createProposalBlock() //changeProposer(t, cs1, vs2)
propBlockParts = propBlock.MakePartSet(partSize)
@@ -377,12 +395,12 @@ func TestSimulateValidatorsChange(t *testing.T) {
newValidatorPubKey2 := css[nVals+1].privValidator.GetPubKey()
newVal2ABCI := types.TM2PB.PubKey(newValidatorPubKey2)
newValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, testMinPower)
err = assertMempool(css[0].txNotifier).CheckTx(newValidatorTx2, nil)
err = assertMempool(css[0].txNotifier).CheckTx(newValidatorTx2, nil, mempl.TxInfo{})
assert.Nil(t, err)
newValidatorPubKey3 := css[nVals+2].privValidator.GetPubKey()
newVal3ABCI := types.TM2PB.PubKey(newValidatorPubKey3)
newValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, testMinPower)
err = assertMempool(css[0].txNotifier).CheckTx(newValidatorTx3, nil)
err = assertMempool(css[0].txNotifier).CheckTx(newValidatorTx3, nil, mempl.TxInfo{})
assert.Nil(t, err)
propBlock, _ = css[0].createProposalBlock() //changeProposer(t, cs1, vs2)
propBlockParts = propBlock.MakePartSet(partSize)
@@ -410,7 +428,7 @@ func TestSimulateValidatorsChange(t *testing.T) {
ensureNewProposal(proposalCh, height, round)
removeValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, 0)
err = assertMempool(css[0].txNotifier).CheckTx(removeValidatorTx2, nil)
err = assertMempool(css[0].txNotifier).CheckTx(removeValidatorTx2, nil, mempl.TxInfo{})
assert.Nil(t, err)
rs = css[0].GetRoundState()
@@ -440,7 +458,7 @@ func TestSimulateValidatorsChange(t *testing.T) {
height++
incrementHeight(vss...)
removeValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, 0)
err = assertMempool(css[0].txNotifier).CheckTx(removeValidatorTx3, nil)
err = assertMempool(css[0].txNotifier).CheckTx(removeValidatorTx3, nil, mempl.TxInfo{})
assert.Nil(t, err)
propBlock, _ = css[0].createProposalBlock() //changeProposer(t, cs1, vs2)
propBlockParts = propBlock.MakePartSet(partSize)
@@ -586,7 +604,8 @@ func tempWALWithData(data []byte) string {
return walFile.Name()
}
// Make some blocks. Start a fresh app and apply nBlocks blocks. Then restart the app and sync it up with the remaining blocks
// Make some blocks. Start a fresh app and apply nBlocks blocks.
// Then restart the app and sync it up with the remaining blocks
func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uint, testValidatorsChange bool) {
var chain []*types.Block
var commits []*types.Commit
@@ -632,7 +651,8 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin
latestAppHash := state.AppHash
// make a new client creator
kvstoreApp := kvstore.NewPersistentKVStoreApplication(filepath.Join(config.DBDir(), fmt.Sprintf("replay_test_%d_%d_a", nBlocks, mode)))
kvstoreApp := kvstore.NewPersistentKVStoreApplication(
filepath.Join(config.DBDir(), fmt.Sprintf("replay_test_%d_%d_a", nBlocks, mode)))
clientCreator2 := proxy.NewLocalClientCreator(kvstoreApp)
if nBlocks > 0 {
@@ -664,7 +684,10 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin
// the app hash should be synced up
if !bytes.Equal(latestAppHash, res.LastBlockAppHash) {
t.Fatalf("Expected app hashes to match after handshake/replay. got %X, expected %X", res.LastBlockAppHash, latestAppHash)
t.Fatalf(
"Expected app hashes to match after handshake/replay. got %X, expected %X",
res.LastBlockAppHash,
latestAppHash)
}
expectedBlocksToSync := numBlocks - nBlocks
@@ -729,9 +752,17 @@ func buildAppStateFromChain(proxyApp proxy.AppConns, stateDB dbm.DB,
}
func buildTMStateFromChain(config *cfg.Config, stateDB dbm.DB, state sm.State, chain []*types.Block, nBlocks int, mode uint) sm.State {
func buildTMStateFromChain(
config *cfg.Config,
stateDB dbm.DB,
state sm.State,
chain []*types.Block,
nBlocks int,
mode uint) sm.State {
// run the whole chain against this client to build up the tendermint state
clientCreator := proxy.NewLocalClientCreator(kvstore.NewPersistentKVStoreApplication(filepath.Join(config.DBDir(), fmt.Sprintf("replay_test_%d_%d_t", nBlocks, mode))))
clientCreator := proxy.NewLocalClientCreator(
kvstore.NewPersistentKVStoreApplication(
filepath.Join(config.DBDir(), fmt.Sprintf("replay_test_%d_%d_t", nBlocks, mode))))
proxyApp := proxy.NewAppConns(clientCreator)
if err := proxyApp.Start(); err != nil {
panic(err)
@@ -854,7 +885,12 @@ func makeBlock(state sm.State, lastBlock *types.Block, lastBlockMeta *types.Bloc
lastCommit := types.NewCommit(types.BlockID{}, nil)
if height > 1 {
vote, _ := types.MakeVote(lastBlock.Header.Height, lastBlockMeta.BlockID, state.Validators, privVal, lastBlock.Header.ChainID)
vote, _ := types.MakeVote(
lastBlock.Header.Height,
lastBlockMeta.BlockID,
state.Validators,
privVal,
lastBlock.Header.ChainID)
voteCommitSig := vote.CommitSig()
lastCommit = types.NewCommit(lastBlockMeta.BlockID, []*types.CommitSig{voteCommitSig})
}
@@ -995,7 +1031,10 @@ func readPieceFromWAL(msg *TimedWALMessage) interface{} {
}
// fresh state and mock store
func stateAndStore(config *cfg.Config, pubKey crypto.PubKey, appVersion version.Protocol) (dbm.DB, sm.State, *mockBlockStore) {
func stateAndStore(
config *cfg.Config,
pubKey crypto.PubKey,
appVersion version.Protocol) (dbm.DB, sm.State, *mockBlockStore) {
stateDB := dbm.NewMemDB()
state, _ := sm.MakeGenesisStateFromFile(config.GenesisFile())
state.Version.Consensus.App = appVersion
+123 -25
View File
@@ -425,7 +425,11 @@ func (cs *ConsensusState) AddProposalBlockPart(height int64, round int, part *ty
}
// SetProposalAndBlock inputs the proposal and all block parts.
func (cs *ConsensusState) SetProposalAndBlock(proposal *types.Proposal, block *types.Block, parts *types.PartSet, peerID p2p.ID) error {
func (cs *ConsensusState) SetProposalAndBlock(
proposal *types.Proposal,
block *types.Block,
parts *types.PartSet,
peerID p2p.ID) error {
if err := cs.SetProposal(proposal, peerID); err != nil {
return err
}
@@ -511,7 +515,12 @@ func (cs *ConsensusState) updateToState(state sm.State) {
// signal the new round step, because other services (eg. txNotifier)
// depend on having an up-to-date peer state!
if !cs.state.IsEmpty() && (state.LastBlockHeight <= cs.state.LastBlockHeight) {
cs.Logger.Info("Ignoring updateToState()", "newHeight", state.LastBlockHeight+1, "oldHeight", cs.state.LastBlockHeight+1)
cs.Logger.Info(
"Ignoring updateToState()",
"newHeight",
state.LastBlockHeight+1,
"oldHeight",
cs.state.LastBlockHeight+1)
cs.newStep()
return
}
@@ -682,7 +691,14 @@ func (cs *ConsensusState) handleMsg(mi msgInfo) {
}
if err != nil && msg.Round != cs.Round {
cs.Logger.Debug("Received block part from wrong round", "height", cs.Height, "csRound", cs.Round, "blockRound", msg.Round)
cs.Logger.Debug(
"Received block part from wrong round",
"height",
cs.Height,
"csRound",
cs.Round,
"blockRound",
msg.Round)
err = nil
}
case *VoteMessage:
@@ -794,7 +810,13 @@ func (cs *ConsensusState) enterNewRound(height int64, round int) {
logger := cs.Logger.With("height", height, "round", round)
if cs.Height != height || round < cs.Round || (cs.Round == round && cs.Step != cstypes.RoundStepNewHeight) {
logger.Debug(fmt.Sprintf("enterNewRound(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
logger.Debug(fmt.Sprintf(
"enterNewRound(%v/%v): Invalid args. Current step: %v/%v/%v",
height,
round,
cs.Height,
cs.Round,
cs.Step))
return
}
@@ -858,13 +880,20 @@ func (cs *ConsensusState) needProofBlock(height int64) bool {
}
// Enter (CreateEmptyBlocks): from enterNewRound(height,round)
// Enter (CreateEmptyBlocks, CreateEmptyBlocksInterval > 0 ): after enterNewRound(height,round), after timeout of CreateEmptyBlocksInterval
// Enter (CreateEmptyBlocks, CreateEmptyBlocksInterval > 0 ):
// after enterNewRound(height,round), after timeout of CreateEmptyBlocksInterval
// Enter (!CreateEmptyBlocks) : after enterNewRound(height,round), once txs are in the mempool
func (cs *ConsensusState) enterPropose(height int64, round int) {
logger := cs.Logger.With("height", height, "round", round)
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPropose <= cs.Step) {
logger.Debug(fmt.Sprintf("enterPropose(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
logger.Debug(fmt.Sprintf(
"enterPropose(%v/%v): Invalid args. Current step: %v/%v/%v",
height,
round,
cs.Height,
cs.Round,
cs.Step))
return
}
logger.Info(fmt.Sprintf("enterPropose(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
@@ -900,10 +929,18 @@ func (cs *ConsensusState) enterPropose(height int64, round int) {
logger.Debug("This node is a validator")
if cs.isProposer(address) {
logger.Info("enterPropose: Our turn to propose", "proposer", cs.Validators.GetProposer().Address, "privValidator", cs.privValidator)
logger.Info("enterPropose: Our turn to propose",
"proposer",
cs.Validators.GetProposer().Address,
"privValidator",
cs.privValidator)
cs.decideProposal(height, round)
} else {
logger.Info("enterPropose: Not our turn to propose", "proposer", cs.Validators.GetProposer().Address, "privValidator", cs.privValidator)
logger.Info("enterPropose: Not our turn to propose",
"proposer",
cs.Validators.GetProposer().Address,
"privValidator",
cs.privValidator)
}
}
@@ -927,7 +964,8 @@ func (cs *ConsensusState) defaultDecideProposal(height int64, round int) {
}
}
// Flush the WAL. Otherwise, we may not recompute the same proposal to sign, and the privValidator will refuse to sign anything.
// Flush the WAL. Otherwise, we may not recompute the same proposal to sign,
// and the privValidator will refuse to sign anything.
cs.wal.FlushAndSync()
// Make proposal
@@ -995,7 +1033,13 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts
// Otherwise vote nil.
func (cs *ConsensusState) enterPrevote(height int64, round int) {
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrevote <= cs.Step) {
cs.Logger.Debug(fmt.Sprintf("enterPrevote(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
cs.Logger.Debug(fmt.Sprintf(
"enterPrevote(%v/%v): Invalid args. Current step: %v/%v/%v",
height,
round,
cs.Height,
cs.Round,
cs.Step))
return
}
@@ -1052,7 +1096,13 @@ func (cs *ConsensusState) enterPrevoteWait(height int64, round int) {
logger := cs.Logger.With("height", height, "round", round)
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrevoteWait <= cs.Step) {
logger.Debug(fmt.Sprintf("enterPrevoteWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
logger.Debug(fmt.Sprintf(
"enterPrevoteWait(%v/%v): Invalid args. Current step: %v/%v/%v",
height,
round,
cs.Height,
cs.Round,
cs.Step))
return
}
if !cs.Votes.Prevotes(round).HasTwoThirdsAny() {
@@ -1080,7 +1130,13 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
logger := cs.Logger.With("height", height, "round", round)
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrecommit <= cs.Step) {
logger.Debug(fmt.Sprintf("enterPrecommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
logger.Debug(fmt.Sprintf(
"enterPrecommit(%v/%v): Invalid args. Current step: %v/%v/%v",
height,
round,
cs.Height,
cs.Round,
cs.Step))
return
}
@@ -1204,7 +1260,13 @@ func (cs *ConsensusState) enterCommit(height int64, commitRound int) {
logger := cs.Logger.With("height", height, "commitRound", commitRound)
if cs.Height != height || cstypes.RoundStepCommit <= cs.Step {
logger.Debug(fmt.Sprintf("enterCommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, commitRound, cs.Height, cs.Round, cs.Step))
logger.Debug(fmt.Sprintf(
"enterCommit(%v/%v): Invalid args. Current step: %v/%v/%v",
height,
commitRound,
cs.Height,
cs.Round,
cs.Step))
return
}
logger.Info(fmt.Sprintf("enterCommit(%v/%v). Current: %v/%v/%v", height, commitRound, cs.Height, cs.Round, cs.Step))
@@ -1238,7 +1300,12 @@ func (cs *ConsensusState) enterCommit(height int64, commitRound int) {
// If we don't have the block being committed, set up to get it.
if !cs.ProposalBlock.HashesTo(blockID.Hash) {
if !cs.ProposalBlockParts.HasHeader(blockID.PartsHeader) {
logger.Info("Commit is for a block we don't know about. Set ProposalBlock=nil", "proposal", cs.ProposalBlock.Hash(), "commit", blockID.Hash)
logger.Info(
"Commit is for a block we don't know about. Set ProposalBlock=nil",
"proposal",
cs.ProposalBlock.Hash(),
"commit",
blockID.Hash)
// We're getting the wrong block.
// Set up ProposalBlockParts and keep waiting.
cs.ProposalBlock = nil
@@ -1268,7 +1335,12 @@ func (cs *ConsensusState) tryFinalizeCommit(height int64) {
if !cs.ProposalBlock.HashesTo(blockID.Hash) {
// TODO: this happens every time if we're not a validator (ugly logs)
// TODO: ^^ wait, why does it matter that we're a validator?
logger.Info("Attempt to finalize failed. We don't have the commit block.", "proposal-block", cs.ProposalBlock.Hash(), "commit-block", blockID.Hash)
logger.Info(
"Attempt to finalize failed. We don't have the commit block.",
"proposal-block",
cs.ProposalBlock.Hash(),
"commit-block",
blockID.Hash)
return
}
@@ -1279,7 +1351,12 @@ func (cs *ConsensusState) tryFinalizeCommit(height int64) {
// Increment height and goto cstypes.RoundStepNewHeight
func (cs *ConsensusState) finalizeCommit(height int64) {
if cs.Height != height || cs.Step != cstypes.RoundStepCommit {
cs.Logger.Debug(fmt.Sprintf("finalizeCommit(%v): Invalid args. Current step: %v/%v/%v", height, cs.Height, cs.Round, cs.Step))
cs.Logger.Debug(fmt.Sprintf(
"finalizeCommit(%v): Invalid args. Current step: %v/%v/%v",
height,
cs.Height,
cs.Round,
cs.Step))
return
}
@@ -1334,7 +1411,8 @@ func (cs *ConsensusState) finalizeCommit(height int64) {
// restart).
endMsg := EndHeightMessage{height}
if err := cs.wal.WriteSync(endMsg); err != nil { // NOTE: fsync
panic(fmt.Sprintf("Failed to write %v msg to consensus wal due to %v. Check your FS and restart the node", endMsg, err))
panic(fmt.Sprintf("Failed to write %v msg to consensus wal due to %v. Check your FS and restart the node",
endMsg, err))
}
fail.Fail() // XXX
@@ -1345,7 +1423,10 @@ func (cs *ConsensusState) finalizeCommit(height int64) {
// Execute and commit the block, update and save the state, and update the mempool.
// NOTE The block.AppHash wont reflect these txs until the next block.
var err error
stateCopy, err = cs.blockExec.ApplyBlock(stateCopy, types.BlockID{Hash: block.Hash(), PartsHeader: blockParts.Header()}, block)
stateCopy, err = cs.blockExec.ApplyBlock(
stateCopy,
types.BlockID{Hash: block.Hash(), PartsHeader: blockParts.Header()},
block)
if err != nil {
cs.Logger.Error("Error on ApplyBlock. Did the application crash? Please restart tendermint", "err", err)
err := cmn.Kill()
@@ -1452,7 +1533,8 @@ func (cs *ConsensusState) defaultSetProposal(proposal *types.Proposal) error {
}
// NOTE: block is not necessarily valid.
// Asynchronously triggers either enterPrevote (before we timeout of propose) or tryFinalizeCommit, once we have the full block.
// Asynchronously triggers either enterPrevote (before we timeout of propose) or tryFinalizeCommit,
// once we have the full block.
func (cs *ConsensusState) addProposalBlockPart(msg *BlockPartMessage, peerID p2p.ID) (added bool, err error) {
height, round, part := msg.Height, msg.Round, msg.Part
@@ -1534,7 +1616,11 @@ func (cs *ConsensusState) tryAddVote(vote *types.Vote, peerID p2p.ID) (bool, err
} else if voteErr, ok := err.(*types.ErrVoteConflictingVotes); ok {
addr := cs.privValidator.GetPubKey().Address()
if bytes.Equal(vote.ValidatorAddress, addr) {
cs.Logger.Error("Found conflicting vote from ourselves. Did you unsafe_reset a validator?", "height", vote.Height, "round", vote.Round, "type", vote.Type)
cs.Logger.Error(
"Found conflicting vote from ourselves. Did you unsafe_reset a validator?",
"height", vote.Height,
"round", vote.Round,
"type", vote.Type)
return added, err
}
cs.evpool.AddEvidence(voteErr.DuplicateVoteEvidence)
@@ -1543,7 +1629,8 @@ func (cs *ConsensusState) tryAddVote(vote *types.Vote, peerID p2p.ID) (bool, err
// Either
// 1) bad peer OR
// 2) not a bad peer? this can also err sometimes with "Unexpected step" OR
// 3) tmkms use with multiple validators connecting to a single tmkms instance (https://github.com/tendermint/tendermint/issues/3839).
// 3) tmkms use with multiple validators connecting to a single tmkms instance
// (https://github.com/tendermint/tendermint/issues/3839).
cs.Logger.Info("Error attempting to add vote", "err", err)
return added, ErrAddingVote
}
@@ -1553,8 +1640,15 @@ func (cs *ConsensusState) tryAddVote(vote *types.Vote, peerID p2p.ID) (bool, err
//-----------------------------------------------------------------------------
func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool, err error) {
cs.Logger.Debug("addVote", "voteHeight", vote.Height, "voteType", vote.Type, "valIndex", vote.ValidatorIndex, "csHeight", cs.Height)
func (cs *ConsensusState) addVote(
vote *types.Vote,
peerID p2p.ID) (added bool, err error) {
cs.Logger.Debug(
"addVote",
"voteHeight", vote.Height,
"voteType", vote.Type,
"valIndex", vote.ValidatorIndex,
"csHeight", cs.Height)
// A precommit for the previous height?
// These come in while we wait timeoutCommit
@@ -1700,8 +1794,12 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
return added, err
}
func (cs *ConsensusState) signVote(type_ types.SignedMsgType, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
// Flush the WAL. Otherwise, we may not recompute the same vote to sign, and the privValidator will refuse to sign anything.
func (cs *ConsensusState) signVote(
type_ types.SignedMsgType,
hash []byte,
header types.PartSetHeader) (*types.Vote, error) {
// Flush the WAL. Otherwise, we may not recompute the same vote to sign,
// and the privValidator will refuse to sign anything.
cs.wal.FlushAndSync()
addr := cs.privValidator.GetPubKey().Address()
+28 -6
View File
@@ -107,7 +107,10 @@ func TestStateProposerSelection2(t *testing.T) {
addr := vss[(i+round)%len(vss)].GetPubKey().Address()
correctProposer := addr
if !bytes.Equal(prop.Address, correctProposer) {
panic(fmt.Sprintf("expected RoundState.Validators.GetProposer() to be validator %d. Got %X", (i+2)%len(vss), prop.Address))
panic(fmt.Sprintf(
"expected RoundState.Validators.GetProposer() to be validator %d. Got %X",
(i+2)%len(vss),
prop.Address))
}
rs := cs1.GetRoundState()
@@ -432,7 +435,10 @@ func TestStateLockNoPOL(t *testing.T) {
// now we're on a new round and are the proposer
if !bytes.Equal(rs.ProposalBlock.Hash(), rs.LockedBlock.Hash()) {
panic(fmt.Sprintf("Expected proposal block to be locked block. Got %v, Expected %v", rs.ProposalBlock, rs.LockedBlock))
panic(fmt.Sprintf(
"Expected proposal block to be locked block. Got %v, Expected %v",
rs.ProposalBlock,
rs.LockedBlock))
}
ensurePrevote(voteCh, height, round) // prevote
@@ -446,7 +452,12 @@ func TestStateLockNoPOL(t *testing.T) {
validatePrecommit(t, cs1, round, 0, vss[0], nil, theBlockHash) // precommit nil but be locked on proposal
signAddVotes(cs1, types.PrecommitType, hash, rs.ProposalBlock.MakePartSet(partSize).Header(), vs2) // NOTE: conflicting precommits at same height
signAddVotes(
cs1,
types.PrecommitType,
hash,
rs.ProposalBlock.MakePartSet(partSize).Header(),
vs2) // NOTE: conflicting precommits at same height
ensurePrecommit(voteCh, height, round)
ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
@@ -486,7 +497,12 @@ func TestStateLockNoPOL(t *testing.T) {
ensurePrecommit(voteCh, height, round)
validatePrecommit(t, cs1, round, 0, vss[0], nil, theBlockHash) // precommit nil but locked on proposal
signAddVotes(cs1, types.PrecommitType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2) // NOTE: conflicting precommits at same height
signAddVotes(
cs1,
types.PrecommitType,
propBlock.Hash(),
propBlock.MakePartSet(partSize).Header(),
vs2) // NOTE: conflicting precommits at same height
ensurePrecommit(voteCh, height, round)
}
@@ -1330,7 +1346,10 @@ func TestStartNextHeightCorrectly(t *testing.T) {
ensureNewTimeout(timeoutProposeCh, height+1, round, cs1.config.Propose(round).Nanoseconds())
rs = cs1.GetRoundState()
assert.False(t, rs.TriggeredTimeoutPrecommit, "triggeredTimeoutPrecommit should be false at the beginning of each round")
assert.False(
t,
rs.TriggeredTimeoutPrecommit,
"triggeredTimeoutPrecommit should be false at the beginning of each round")
}
func TestResetTimeoutPrecommitUponNewHeight(t *testing.T) {
@@ -1382,7 +1401,10 @@ func TestResetTimeoutPrecommitUponNewHeight(t *testing.T) {
ensureNewProposal(proposalCh, height+1, 0)
rs = cs1.GetRoundState()
assert.False(t, rs.TriggeredTimeoutPrecommit, "triggeredTimeoutPrecommit should be false at the beginning of each height")
assert.False(
t,
rs.TriggeredTimeoutPrecommit,
"triggeredTimeoutPrecommit should be false at the beginning of each height")
}
//------------------------------------------------------------------------------------------
+7 -2
View File
@@ -16,7 +16,8 @@ type RoundVoteSet struct {
}
var (
GotVoteFromUnwantedRoundError = errors.New("Peer has sent a vote that does not match our round for more than one round")
GotVoteFromUnwantedRoundError = errors.New(
"Peer has sent a vote that does not match our round for more than one round")
)
/*
@@ -176,7 +177,11 @@ func (hvs *HeightVoteSet) getVoteSet(round int, type_ types.SignedMsgType) *type
// NOTE: if there are too many peers, or too much peer churn,
// this can cause memory issues.
// TODO: implement ability to remove peers too
func (hvs *HeightVoteSet) SetPeerMaj23(round int, type_ types.SignedMsgType, peerID p2p.ID, blockID types.BlockID) error {
func (hvs *HeightVoteSet) SetPeerMaj23(
round int,
type_ types.SignedMsgType,
peerID p2p.ID,
blockID types.BlockID) error {
hvs.mtx.Lock()
defer hvs.mtx.Unlock()
if !types.IsVoteTypeValid(type_) {
+22 -12
View File
@@ -13,21 +13,31 @@ import (
// PeerRoundState contains the known state of a peer.
// NOTE: Read-only when returned by PeerState.GetRoundState().
type PeerRoundState struct {
Height int64 `json:"height"` // Height peer is at
Round int `json:"round"` // Round peer is at, -1 if unknown.
Step RoundStepType `json:"step"` // Step peer is at
StartTime time.Time `json:"start_time"` // Estimated start of round 0 at this height
Proposal bool `json:"proposal"` // True if peer has proposal for this round
Height int64 `json:"height"` // Height peer is at
Round int `json:"round"` // Round peer is at, -1 if unknown.
Step RoundStepType `json:"step"` // Step peer is at
// Estimated start of round 0 at this height
StartTime time.Time `json:"start_time"`
// True if peer has proposal for this round
Proposal bool `json:"proposal"`
ProposalBlockPartsHeader types.PartSetHeader `json:"proposal_block_parts_header"` //
ProposalBlockParts *cmn.BitArray `json:"proposal_block_parts"` //
ProposalPOLRound int `json:"proposal_pol_round"` // Proposal's POL round. -1 if none.
ProposalPOL *cmn.BitArray `json:"proposal_pol"` // nil until ProposalPOLMessage received.
Prevotes *cmn.BitArray `json:"prevotes"` // All votes peer has for this round
Precommits *cmn.BitArray `json:"precommits"` // All precommits peer has for this round
LastCommitRound int `json:"last_commit_round"` // Round of commit for last height. -1 if none.
LastCommit *cmn.BitArray `json:"last_commit"` // All commit precommits of commit for last height.
CatchupCommitRound int `json:"catchup_commit_round"` // Round that we have commit for. Not necessarily unique. -1 if none.
CatchupCommit *cmn.BitArray `json:"catchup_commit"` // All commit precommits peer has for this height & CatchupCommitRound
// nil until ProposalPOLMessage received.
ProposalPOL *cmn.BitArray `json:"proposal_pol"`
Prevotes *cmn.BitArray `json:"prevotes"` // All votes peer has for this round
Precommits *cmn.BitArray `json:"precommits"` // All precommits peer has for this round
LastCommitRound int `json:"last_commit_round"` // Round of commit for last height. -1 if none.
LastCommit *cmn.BitArray `json:"last_commit"` // All commit precommits of commit for last height.
// Round that we have commit for. Not necessarily unique. -1 if none.
CatchupCommitRound int `json:"catchup_commit_round"`
// All commit precommits peer has for this height & CatchupCommitRound
CatchupCommit *cmn.BitArray `json:"catchup_commit"`
}
// String returns a string representation of the PeerRoundState
+21 -15
View File
@@ -65,21 +65,27 @@ func (rs RoundStepType) String() string {
// NOTE: Not thread safe. Should only be manipulated by functions downstream
// of the cs.receiveRoutine
type RoundState struct {
Height int64 `json:"height"` // Height we are working on
Round int `json:"round"`
Step RoundStepType `json:"step"`
StartTime time.Time `json:"start_time"`
CommitTime time.Time `json:"commit_time"` // Subjective time when +2/3 precommits for Block at Round were found
Validators *types.ValidatorSet `json:"validators"`
Proposal *types.Proposal `json:"proposal"`
ProposalBlock *types.Block `json:"proposal_block"`
ProposalBlockParts *types.PartSet `json:"proposal_block_parts"`
LockedRound int `json:"locked_round"`
LockedBlock *types.Block `json:"locked_block"`
LockedBlockParts *types.PartSet `json:"locked_block_parts"`
ValidRound int `json:"valid_round"` // Last known round with POL for non-nil valid block.
ValidBlock *types.Block `json:"valid_block"` // Last known block of POL mentioned above.
ValidBlockParts *types.PartSet `json:"valid_block_parts"` // Last known block parts of POL metnioned above.
Height int64 `json:"height"` // Height we are working on
Round int `json:"round"`
Step RoundStepType `json:"step"`
StartTime time.Time `json:"start_time"`
// Subjective time when +2/3 precommits for Block at Round were found
CommitTime time.Time `json:"commit_time"`
Validators *types.ValidatorSet `json:"validators"`
Proposal *types.Proposal `json:"proposal"`
ProposalBlock *types.Block `json:"proposal_block"`
ProposalBlockParts *types.PartSet `json:"proposal_block_parts"`
LockedRound int `json:"locked_round"`
LockedBlock *types.Block `json:"locked_block"`
LockedBlockParts *types.PartSet `json:"locked_block_parts"`
// Last known round with POL for non-nil valid block.
ValidRound int `json:"valid_round"`
ValidBlock *types.Block `json:"valid_block"` // Last known block of POL mentioned above.
// Last known block parts of POL metnioned above.
ValidBlockParts *types.PartSet `json:"valid_block_parts"`
Votes *HeightVoteSet `json:"votes"`
CommitRound int `json:"commit_round"` //
LastCommit *types.VoteSet `json:"last_commit"` // Last precommits at Height-1
+8 -2
View File
@@ -20,6 +20,7 @@ import (
const (
// amino overhead + time.Time + max consensus msg size
// TODO: Can we clarify better where 24 comes from precisely?
maxMsgSizeBytes = maxMsgSize + 24
// how often the WAL should be sync'd during period sync'ing
@@ -221,7 +222,9 @@ type WALSearchOptions struct {
// Group reader will be nil if found equals false.
//
// CONTRACT: caller must close group reader.
func (wal *baseWAL) SearchForEndHeight(height int64, options *WALSearchOptions) (rd io.ReadCloser, found bool, err error) {
func (wal *baseWAL) SearchForEndHeight(
height int64,
options *WALSearchOptions) (rd io.ReadCloser, found bool, err error) {
var (
msg *TimedWALMessage
gr *auto.GroupReader
@@ -365,7 +368,10 @@ func (dec *WALDecoder) Decode() (*TimedWALMessage, error) {
length := binary.BigEndian.Uint32(b)
if length > maxMsgSizeBytes {
return nil, DataCorruptionError{fmt.Errorf("length %d exceeded maximum possible value of %d bytes", length, maxMsgSizeBytes)}
return nil, DataCorruptionError{fmt.Errorf(
"length %d exceeded maximum possible value of %d bytes",
length,
maxMsgSizeBytes)}
}
data := make([]byte, length)
+5 -2
View File
@@ -27,7 +27,8 @@ import (
// WALGenerateNBlocks generates a consensus WAL. It does this by spinning up a
// stripped down version of node (proxy app, event bus, consensus state) with a
// persistent kvstore application and special consensus wal instance
// (byteBufferWAL) and waits until numBlocks are created. If the node fails to produce given numBlocks, it returns an error.
// (byteBufferWAL) and waits until numBlocks are created.
// If the node fails to produce given numBlocks, it returns an error.
func WALGenerateNBlocks(t *testing.T, wr io.Writer, numBlocks int) (err error) {
config := getConfig(t)
@@ -199,7 +200,9 @@ func (w *byteBufferWAL) WriteSync(m WALMessage) error {
func (w *byteBufferWAL) FlushAndSync() error { return nil }
func (w *byteBufferWAL) SearchForEndHeight(height int64, options *WALSearchOptions) (rd io.ReadCloser, found bool, err error) {
func (w *byteBufferWAL) SearchForEndHeight(
height int64,
options *WALSearchOptions) (rd io.ReadCloser, found bool, err error) {
return nil, false, nil
}
+1 -1
View File
@@ -14,7 +14,7 @@ If you want to decode bytes into one of the types, but don't care about the spec
## Binary encoding
For Binary encoding, please refer to the [Tendermint encoding spec](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md).
For Binary encoding, please refer to the [Tendermint encoding specification](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md).
## JSON Encoding
+8
View File
@@ -60,11 +60,19 @@ func RegisterAmino(cdc *amino.Codec) {
secp256k1.PrivKeyAminoName, nil)
}
// RegisterKeyType registers an external key type to allow decoding it from bytes
func RegisterKeyType(o interface{}, name string) {
cdc.RegisterConcrete(o, name, nil)
nameTable[reflect.TypeOf(o)] = name
}
// PrivKeyFromBytes unmarshals private key bytes and returns a PrivKey
func PrivKeyFromBytes(privKeyBytes []byte) (privKey crypto.PrivKey, err error) {
err = cdc.UnmarshalBinaryBare(privKeyBytes, &privKey)
return
}
// PubKeyFromBytes unmarshals public key bytes and returns a PubKey
func PubKeyFromBytes(pubKeyBytes []byte) (pubKey crypto.PubKey, err error) {
err = cdc.UnmarshalBinaryBare(pubKeyBytes, &pubKey)
return
+75
View File
@@ -2,10 +2,13 @@ package cryptoAmino
import (
"os"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
amino "github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/multisig"
@@ -147,3 +150,75 @@ func TestPubkeyAminoName(t *testing.T) {
}
}
}
var _ crypto.PrivKey = testPriv{}
var _ crypto.PubKey = testPub{}
var testCdc = amino.NewCodec()
type testPriv []byte
func (privkey testPriv) PubKey() crypto.PubKey { return testPub{} }
func (privkey testPriv) Bytes() []byte {
return testCdc.MustMarshalBinaryBare(privkey)
}
func (privkey testPriv) Sign(msg []byte) ([]byte, error) { return []byte{}, nil }
func (privkey testPriv) Equals(other crypto.PrivKey) bool { return true }
type testPub []byte
func (key testPub) Address() crypto.Address { return crypto.Address{} }
func (key testPub) Bytes() []byte {
return testCdc.MustMarshalBinaryBare(key)
}
func (key testPub) VerifyBytes(msg []byte, sig []byte) bool { return true }
func (key testPub) Equals(other crypto.PubKey) bool { return true }
var (
privAminoName = "registerTest/Priv"
pubAminoName = "registerTest/Pub"
)
func TestRegisterKeyType(t *testing.T) {
RegisterAmino(testCdc)
testCdc.RegisterConcrete(testPriv{}, privAminoName, nil)
testCdc.RegisterConcrete(testPub{}, pubAminoName, nil)
pub := testPub{0x1}
priv := testPriv{0x2}
// Check to make sure key cannot be decoded before registering
_, err := PrivKeyFromBytes(priv.Bytes())
require.Error(t, err)
_, err = PubKeyFromBytes(pub.Bytes())
require.Error(t, err)
// Check that name is not registered
_, found := PubkeyAminoName(testCdc, pub)
require.False(t, found)
// Register key types
RegisterKeyType(testPriv{}, privAminoName)
RegisterKeyType(testPub{}, pubAminoName)
// Name should exist after registering
name, found := PubkeyAminoName(testCdc, pub)
require.True(t, found)
require.Equal(t, name, pubAminoName)
// Decode keys using the encoded bytes from encoding with the other codec
decodedPriv, err := PrivKeyFromBytes(priv.Bytes())
require.NoError(t, err)
require.Equal(t, priv, decodedPriv)
decodedPub, err := PubKeyFromBytes(pub.Bytes())
require.NoError(t, err)
require.Equal(t, pub, decodedPub)
// Reset module codec after testing
cdc = amino.NewCodec()
nameTable = make(map[reflect.Type]string, 3)
RegisterAmino(cdc)
nameTable[reflect.TypeOf(ed25519.PubKeyEd25519{})] = ed25519.PubKeyAminoName
nameTable[reflect.TypeOf(secp256k1.PubKeySecp256k1{})] = secp256k1.PubKeyAminoName
nameTable[reflect.TypeOf(multisig.PubKeyMultisigThreshold{})] = multisig.PubKeyMultisigThresholdAminoRoute
}
+20 -4
View File
@@ -16,11 +16,27 @@ func TestSimpleMap(t *testing.T) {
{[]string{"key1"}, []string{"value1"}, "a44d3cc7daba1a4600b00a2434b30f8b970652169810d6dfa9fb1793a2189324"},
{[]string{"key1"}, []string{"value2"}, "0638e99b3445caec9d95c05e1a3fc1487b4ddec6a952ff337080360b0dcc078c"},
// swap order with 2 keys
{[]string{"key1", "key2"}, []string{"value1", "value2"}, "8fd19b19e7bb3f2b3ee0574027d8a5a4cec370464ea2db2fbfa5c7d35bb0cff3"},
{[]string{"key2", "key1"}, []string{"value2", "value1"}, "8fd19b19e7bb3f2b3ee0574027d8a5a4cec370464ea2db2fbfa5c7d35bb0cff3"},
{
[]string{"key1", "key2"},
[]string{"value1", "value2"},
"8fd19b19e7bb3f2b3ee0574027d8a5a4cec370464ea2db2fbfa5c7d35bb0cff3",
},
{
[]string{"key2", "key1"},
[]string{"value2", "value1"},
"8fd19b19e7bb3f2b3ee0574027d8a5a4cec370464ea2db2fbfa5c7d35bb0cff3",
},
// swap order with 3 keys
{[]string{"key1", "key2", "key3"}, []string{"value1", "value2", "value3"}, "1dd674ec6782a0d586a903c9c63326a41cbe56b3bba33ed6ff5b527af6efb3dc"},
{[]string{"key1", "key3", "key2"}, []string{"value1", "value3", "value2"}, "1dd674ec6782a0d586a903c9c63326a41cbe56b3bba33ed6ff5b527af6efb3dc"},
{
[]string{"key1", "key2", "key3"},
[]string{"value1", "value2", "value3"},
"1dd674ec6782a0d586a903c9c63326a41cbe56b3bba33ed6ff5b527af6efb3dc",
},
{
[]string{"key1", "key3", "key2"},
[]string{"value1", "value3", "value2"},
"1dd674ec6782a0d586a903c9c63326a41cbe56b3bba33ed6ff5b527af6efb3dc",
},
}
for i, tc := range tests {
db := newSimpleMap()
+8 -5
View File
@@ -9,7 +9,10 @@ import (
)
const (
maxAunts = 100
// MaxAunts is the maximum number of aunts that can be included in a SimpleProof.
// This corresponds to a tree of size 2^100, which should be sufficient for all conceivable purposes.
// This maximum helps prevent Denial-of-Service attacks by limitting the size of the proofs.
MaxAunts = 100
)
// SimpleProof represents a simple Merkle proof.
@@ -114,8 +117,8 @@ func (sp *SimpleProof) StringIndented(indent string) string {
}
// ValidateBasic performs basic validation.
// NOTE: - it expects LeafHash and Aunts of tmhash.Size size
// - it expects no more than 100 aunts
// NOTE: it expects the LeafHash and the elements of Aunts to be of size tmhash.Size,
// and it expects at most MaxAunts elements in Aunts.
func (sp *SimpleProof) ValidateBasic() error {
if sp.Total < 0 {
return errors.New("negative Total")
@@ -126,8 +129,8 @@ func (sp *SimpleProof) ValidateBasic() error {
if len(sp.LeafHash) != tmhash.Size {
return errors.Errorf("expected LeafHash size to be %d, got %d", tmhash.Size, len(sp.LeafHash))
}
if len(sp.Aunts) > maxAunts {
return errors.Errorf("expected no more than %d aunts, got %d", maxAunts, len(sp.Aunts))
if len(sp.Aunts) > MaxAunts {
return errors.Errorf("expected no more than %d aunts, got %d", MaxAunts, len(sp.Aunts))
}
for i, auntHash := range sp.Aunts {
if len(auntHash) != tmhash.Size {
+6 -3
View File
@@ -15,9 +15,12 @@ func TestSimpleProofValidateBasic(t *testing.T) {
{"Good", func(sp *SimpleProof) {}, ""},
{"Negative Total", func(sp *SimpleProof) { sp.Total = -1 }, "negative Total"},
{"Negative Index", func(sp *SimpleProof) { sp.Index = -1 }, "negative Index"},
{"Invalid LeafHash", func(sp *SimpleProof) { sp.LeafHash = make([]byte, 10) }, "expected LeafHash size to be 32, got 10"},
{"Too many Aunts", func(sp *SimpleProof) { sp.Aunts = make([][]byte, maxAunts+1) }, "expected no more than 100 aunts, got 101"},
{"Invalid Aunt", func(sp *SimpleProof) { sp.Aunts[0] = make([]byte, 10) }, "expected Aunts#0 size to be 32, got 10"},
{"Invalid LeafHash", func(sp *SimpleProof) { sp.LeafHash = make([]byte, 10) },
"expected LeafHash size to be 32, got 10"},
{"Too many Aunts", func(sp *SimpleProof) { sp.Aunts = make([][]byte, MaxAunts+1) },
"expected no more than 100 aunts, got 101"},
{"Invalid Aunt", func(sp *SimpleProof) { sp.Aunts[0] = make([]byte, 10) },
"expected Aunts#0 size to be 32, got 10"},
}
for _, tc := range testCases {
+5 -1
View File
@@ -67,7 +67,11 @@ func TestThresholdMultisigValidCases(t *testing.T) {
)
require.NoError(
t,
multisignature.AddSignatureFromPubKey(tc.signatures[tc.signingIndices[tc.k]], tc.pubkeys[tc.signingIndices[tc.k]], tc.pubkeys),
multisignature.AddSignatureFromPubKey(
tc.signatures[tc.signingIndices[tc.k]],
tc.pubkeys[tc.signingIndices[tc.k]],
tc.pubkeys,
),
)
require.True(
t,
+3 -1
View File
@@ -41,7 +41,9 @@ import (
/*
#include "libsecp256k1/include/secp256k1.h"
extern int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, const unsigned char *point, const unsigned char *scalar);
extern int secp256k1_ext_scalar_mul(const secp256k1_context* ctx,
const unsigned char *point,
const unsigned char *scalar);
*/
import "C"
+5 -1
View File
@@ -94,7 +94,11 @@ func TestGenPrivKeySecp256k1(t *testing.T) {
secret []byte
}{
{"empty secret", []byte{}},
{"some long secret", []byte("We live in a society exquisitely dependent on science and technology, in which hardly anyone knows anything about science and technology.")},
{
"some long secret",
[]byte("We live in a society exquisitely dependent on science and technology, " +
"in which hardly anyone knows anything about science and technology."),
},
{"another seed used in cosmos tests #1", []byte{0}},
{"another seed used in cosmos tests #2", []byte("mySecret")},
{"another seed used in cosmos tests #3", []byte("")},
+22 -3
View File
@@ -94,10 +94,29 @@ var vectors = []struct {
key, nonce, ad, plaintext, ciphertext []byte
}{
{
[]byte{0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f},
[]byte{
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
},
[]byte{0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b},
[]byte{0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7},
[]byte("Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it."),
[]byte{0x45, 0x3c, 0x06, 0x93, 0xa7, 0x40, 0x7f, 0x04, 0xff, 0x4c, 0x56, 0xae, 0xdb, 0x17, 0xa3, 0xc0, 0xa1, 0xaf, 0xff, 0x01, 0x17, 0x49, 0x30, 0xfc, 0x22, 0x28, 0x7c, 0x33, 0xdb, 0xcf, 0x0a, 0xc8, 0xb8, 0x9a, 0xd9, 0x29, 0x53, 0x0a, 0x1b, 0xb3, 0xab, 0x5e, 0x69, 0xf2, 0x4c, 0x7f, 0x60, 0x70, 0xc8, 0xf8, 0x40, 0xc9, 0xab, 0xb4, 0xf6, 0x9f, 0xbf, 0xc8, 0xa7, 0xff, 0x51, 0x26, 0xfa, 0xee, 0xbb, 0xb5, 0x58, 0x05, 0xee, 0x9c, 0x1c, 0xf2, 0xce, 0x5a, 0x57, 0x26, 0x32, 0x87, 0xae, 0xc5, 0x78, 0x0f, 0x04, 0xec, 0x32, 0x4c, 0x35, 0x14, 0x12, 0x2c, 0xfc, 0x32, 0x31, 0xfc, 0x1a, 0x8b, 0x71, 0x8a, 0x62, 0x86, 0x37, 0x30, 0xa2, 0x70, 0x2b, 0xb7, 0x63, 0x66, 0x11, 0x6b, 0xed, 0x09, 0xe0, 0xfd, 0x5c, 0x6d, 0x84, 0xb6, 0xb0, 0xc1, 0xab, 0xaf, 0x24, 0x9d, 0x5d, 0xd0, 0xf7, 0xf5, 0xa7, 0xea},
[]byte(
"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.",
),
[]byte{
0x45, 0x3c, 0x06, 0x93, 0xa7, 0x40, 0x7f, 0x04, 0xff, 0x4c, 0x56,
0xae, 0xdb, 0x17, 0xa3, 0xc0, 0xa1, 0xaf, 0xff, 0x01, 0x17, 0x49,
0x30, 0xfc, 0x22, 0x28, 0x7c, 0x33, 0xdb, 0xcf, 0x0a, 0xc8, 0xb8,
0x9a, 0xd9, 0x29, 0x53, 0x0a, 0x1b, 0xb3, 0xab, 0x5e, 0x69, 0xf2,
0x4c, 0x7f, 0x60, 0x70, 0xc8, 0xf8, 0x40, 0xc9, 0xab, 0xb4, 0xf6,
0x9f, 0xbf, 0xc8, 0xa7, 0xff, 0x51, 0x26, 0xfa, 0xee, 0xbb, 0xb5,
0x58, 0x05, 0xee, 0x9c, 0x1c, 0xf2, 0xce, 0x5a, 0x57, 0x26, 0x32,
0x87, 0xae, 0xc5, 0x78, 0x0f, 0x04, 0xec, 0x32, 0x4c, 0x35, 0x14,
0x12, 0x2c, 0xfc, 0x32, 0x31, 0xfc, 0x1a, 0x8b, 0x71, 0x8a, 0x62,
0x86, 0x37, 0x30, 0xa2, 0x70, 0x2b, 0xb7, 0x63, 0x66, 0x11, 0x6b,
0xed, 0x09, 0xe0, 0xfd, 0x5c, 0x6d, 0x84, 0xb6, 0xb0, 0xc1, 0xab,
0xaf, 0x24, 0x9d, 0x5d, 0xd0, 0xf7, 0xf5, 0xa7, 0xea,
},
},
}
+132 -128
View File
@@ -1,141 +1,145 @@
module.exports = {
title: "Tendermint Documentation",
description: "Documentation for Tendermint Core.",
ga: "UA-51029217-1",
dest: "./dist/docs",
base: "/docs/",
markdown: {
lineNumbers: true
},
theme: "cosmos",
// locales: {
// "/": {
// lang: "en-US"
// },
// "/ru/": {
// lang: "ru"
// }
// },
base: process.env.VUEPRESS_BASE,
themeConfig: {
repo: "tendermint/tendermint",
docsRepo: "tendermint/tendermint",
editLinks: true,
docsDir: "docs",
docsBranch: "develop",
editLinkText: 'Edit this page on Github',
lastUpdated: true,
algolia: {
apiKey: '59f0e2deb984aa9cdf2b3a5fd24ac501',
indexName: 'tendermint',
debug: false
logo: "/logo.svg",
label: "core",
gutter: {
title: "Help & Support",
editLink: true,
chat: {
title: "Riot Chat",
text: "Chat with Tendermint developers on Riot Chat.",
url: "https://riot.im/app/#/room/#tendermint:matrix.org",
bg: "#222"
},
forum: {
title: "Tendermint Forum",
text: "Join the Tendermint forum to learn more",
url: "https://forum.cosmos.network/c/tendermint",
bg: "#0B7E0B",
logo: "tendermint"
},
github: {
title: "Found an Issue?",
text: "Help us improve this page by suggesting edits on GitHub."
}
},
footer: {
logo: "/logo-bw.svg",
textLink: {
text: "tendermint.com",
url: "https://tendermint.com"
},
services: [
{
service: "medium",
url: "https://medium.com/@tendermint"
},
{
service: "twitter",
url: "https://twitter.com/tendermint_team"
},
{
service: "linkedin",
url: "https://www.linkedin.com/company/tendermint/"
},
{
service: "reddit",
url: "https://reddit.com/r/cosmosnetwork"
},
{
service: "telegram",
url: "https://t.me/cosmosproject"
},
{
service: "youtube",
url: "https://www.youtube.com/c/CosmosProject"
}
],
smallprint:
"The development of the Tendermint project is led primarily by Tendermint Inc., the for-profit entity which also maintains this website. Funding for this development comes primarily from the Interchain Foundation, a Swiss non-profit.",
links: [
{
title: "Documentation",
children: [
{
title: "Cosmos SDK",
url: "https://cosmos.network/docs"
},
{
title: "Cosmos Hub",
url: "https://hub.cosmos.network/"
}
]
},
{
title: "Community",
children: [
{
title: "Tendermint blog",
url: "https://medium.com/@tendermint"
},
{
title: "Forum",
url: "https://forum.cosmos.network/c/tendermint"
},
{
title: "Chat",
url: "https://riot.im/app/#/room/#tendermint:matrix.org"
}
]
},
{
title: "Contributing",
children: [
{
title: "Contributing to the docs",
url: "https://github.com/tendermint/tendermint"
},
{
title: "Source code on GitHub",
url: "https://github.com/tendermint/tendermint"
},
{
title: "Careers at Tendermint",
url: "https://tendermint.com/careers"
}
]
}
]
},
nav: [
{ text: "Back to Tendermint", link: "https://tendermint.com" },
{ text: "RPC", link: "https://tendermint.com/rpc/" }
],
sidebar: [
{
title: "Introduction",
collapsable: false,
title: "Resources",
children: [
"/introduction/",
"/introduction/quick-start",
"/introduction/install",
"/introduction/what-is-tendermint"
]
},
{
title: "Guides",
collapsable: false,
children: [
"/guides/go-built-in",
"/guides/go"
]
},
{
title: "Apps",
collapsable: false,
children: [
"/app-dev/getting-started",
"/app-dev/abci-cli",
"/app-dev/app-architecture",
"/app-dev/app-development",
"/app-dev/subscribing-to-events-via-websocket",
"/app-dev/indexing-transactions",
"/spec/abci/abci",
"/app-dev/ecosystem"
]
},
{
title: "Tendermint Core",
collapsable: false,
children: [
"/tendermint-core/",
"/tendermint-core/using-tendermint",
"/tendermint-core/configuration",
"/tendermint-core/rpc",
"/tendermint-core/running-in-production",
"/tendermint-core/fast-sync",
"/tendermint-core/how-to-read-logs",
"/tendermint-core/block-structure",
"/tendermint-core/light-client-protocol",
"/tendermint-core/metrics",
"/tendermint-core/secure-p2p",
"/tendermint-core/validators",
"/tendermint-core/mempool"
]
},
{
title: "Networks",
collapsable: false,
children: [
"/networks/",
"/networks/docker-compose",
"/networks/terraform-and-ansible",
]
},
{
title: "Tools",
collapsable: false,
children: [
"/tools/",
"/tools/benchmarking",
"/tools/monitoring",
"/tools/remote-signer-validation"
]
},
{
title: "Tendermint Spec",
collapsable: true,
children: [
"/spec/",
"/spec/blockchain/blockchain",
"/spec/blockchain/encoding",
"/spec/blockchain/state",
"/spec/software/abci",
"/spec/consensus/bft-time",
"/spec/consensus/consensus",
"/spec/consensus/light-client",
"/spec/software/wal",
"/spec/p2p/config",
"/spec/p2p/connection",
"/spec/p2p/node",
"/spec/p2p/peer",
"/spec/reactors/block_sync/reactor",
"/spec/reactors/block_sync/impl",
"/spec/reactors/consensus/consensus",
"/spec/reactors/consensus/consensus-reactor",
"/spec/reactors/consensus/proposer-selection",
"/spec/reactors/evidence/reactor",
"/spec/reactors/mempool/concurrency",
"/spec/reactors/mempool/config",
"/spec/reactors/mempool/functionality",
"/spec/reactors/mempool/messages",
"/spec/reactors/mempool/reactor",
"/spec/reactors/pex/pex",
"/spec/reactors/pex/reactor",
]
},
{
title: "ABCI Spec",
collapsable: false,
children: [
"/spec/abci/",
"/spec/abci/abci",
"/spec/abci/apps",
"/spec/abci/client-server"
{
title: "Developer Sessions",
path: "/DEV_SESSIONS.html"
},
{
title: "RPC",
path: "/rpc/",
static: true
}
]
}
]
},
markdown: {
anchor: {
permalinkSymbol: ""
}
}
};
-17
View File
@@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>VuePress</title>
<meta name="description" content="">
<link rel="preload" href="/assets/css/1.styles.c01b7ee3.css" as="style"><link rel="preload" href="/assets/js/app.48f1ff5f.js" as="script"><link rel="prefetch" href="/assets/js/0.7c2695bf.js">
<link rel="stylesheet" href="/assets/css/1.styles.c01b7ee3.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><div class="content"><h1>404</h1><blockquote>Looks like we've got some broken links.</blockquote><a href="/" class="router-link-active">Take me home.</a></div></div></div>
<script src="/assets/js/app.48f1ff5f.js" defer></script>
</body>
</html>
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="13"><g stroke-width="2" stroke="#aaa" fill="none"><path d="M11.29 11.71l-4-4"/><circle cx="5" cy="5" r="4"/></g></svg>

Before

Width:  |  Height:  |  Size: 216 B

-1
View File
@@ -1 +0,0 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[0],{136:function(e,t,s){"use strict";s.r(t);var n=s(0),r=Object(n.a)({},function(){this.$createElement;this._self._c;return this._m(0)},[function(){var e=this.$createElement,t=this._self._c||e;return t("div",{staticClass:"content"},[t("h1",{attrs:{id:"hello-vuepress"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#hello-vuepress","aria-hidden":"true"}},[this._v("#")]),this._v(" Hello VuePress")])])}],!1,null,null,null);t.default=r.exports}}]);
File diff suppressed because one or more lines are too long
-17
View File
@@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Hello VuePress</title>
<meta name="description" content="">
<link rel="preload" href="/assets/css/1.styles.c01b7ee3.css" as="style"><link rel="preload" href="/assets/js/app.48f1ff5f.js" as="script"><link rel="preload" href="/assets/js/0.7c2695bf.js" as="script">
<link rel="stylesheet" href="/assets/css/1.styles.c01b7ee3.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container no-sidebar"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><a href="/" class="home-link router-link-exact-active router-link-active"></a><div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""><!----></div><!----></div></header><div class="sidebar-mask"></div><div class="sidebar"><!----><!----></div><div class="page"><div class="content"><h1 id="hello-vuepress"><a href="#hello-vuepress" aria-hidden="true" class="header-anchor">#</a> Hello VuePress</h1></div><div class="page-edit"><!----><!----></div><!----></div></div></div>
<script src="/assets/js/0.7c2695bf.js" defer></script><script src="/assets/js/app.48f1ff5f.js" defer></script>
</body>
</html>
+7
View File
@@ -0,0 +1,7 @@
<svg width="142" height="20" viewBox="0 0 142 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M33.5369 19.2904H35.9969V7.57038H40.4569V5.29038H29.0769V7.57038H33.5369V19.2904ZM45.3214 19.5304C47.2614 19.5304 48.6414 18.7504 49.6414 17.5504L48.2214 16.2904C47.3814 17.1104 46.5414 17.5504 45.3614 17.5504C43.8014 17.5504 42.5814 16.5904 42.3214 14.8704H50.0814C50.1014 14.6304 50.1214 14.4104 50.1214 14.1904C50.1214 11.1504 48.4214 8.51038 45.0614 8.51038C42.0414 8.51038 39.9014 10.9904 39.9014 14.0104V14.0504C39.9014 17.3104 42.2614 19.5304 45.3214 19.5304ZM42.3014 13.2704C42.5214 11.6304 43.5614 10.4904 45.0414 10.4904C46.6414 10.4904 47.5614 11.7104 47.7214 13.2704H42.3014ZM52.5317 19.2904H54.9717V13.3304C54.9717 11.6904 55.9517 10.7104 57.3517 10.7104C58.7917 10.7104 59.6117 11.6504 59.6117 13.2904V19.2904H62.0317V12.5504C62.0317 10.1104 60.6517 8.51038 58.2717 8.51038C56.6317 8.51038 55.6517 9.37038 54.9717 10.3504V8.73038H52.5317V19.2904ZM69.3141 19.5104C71.0341 19.5104 72.1341 18.6304 72.9141 17.5304V19.2904H75.3341V4.69038H72.9141V10.3704C72.1541 9.37038 71.0541 8.51038 69.3141 8.51038C66.7941 8.51038 64.4141 10.4904 64.4141 13.9904V14.0304C64.4141 17.5304 66.8341 19.5104 69.3141 19.5104ZM69.8941 17.4104C68.2541 17.4104 66.8541 16.0704 66.8541 14.0304V13.9904C66.8541 11.9104 68.2341 10.6104 69.8941 10.6104C71.5141 10.6104 72.9541 11.9504 72.9541 13.9904V14.0304C72.9541 16.0504 71.5141 17.4104 69.8941 17.4104ZM83.212 19.5304C85.152 19.5304 86.532 18.7504 87.532 17.5504L86.112 16.2904C85.272 17.1104 84.432 17.5504 83.252 17.5504C81.692 17.5504 80.472 16.5904 80.212 14.8704H87.972C87.992 14.6304 88.012 14.4104 88.012 14.1904C88.012 11.1504 86.312 8.51038 82.952 8.51038C79.932 8.51038 77.792 10.9904 77.792 14.0104V14.0504C77.792 17.3104 80.152 19.5304 83.212 19.5304ZM80.192 13.2704C80.412 11.6304 81.452 10.4904 82.932 10.4904C84.532 10.4904 85.452 11.7104 85.612 13.2704H80.192ZM90.4223 19.2904H92.8623V15.2704C92.8623 12.4704 94.3423 11.0904 96.4623 11.0904H96.6023V8.53038C94.7423 8.45038 93.5223 9.53038 92.8623 11.1104V8.73038H90.4223V19.2904ZM98.6841 19.2904H101.124V13.3304C101.124 11.7104 102.044 10.7104 103.384 10.7104C104.724 10.7104 105.524 11.6304 105.524 13.2704V19.2904H107.944V13.3304C107.944 11.6304 108.884 10.7104 110.204 10.7104C111.564 10.7104 112.344 11.6104 112.344 13.2904V19.2904H114.764V12.5504C114.764 9.97038 113.364 8.51038 111.064 8.51038C109.464 8.51038 108.344 9.25038 107.504 10.3704C106.944 9.25038 105.864 8.51038 104.344 8.51038C102.724 8.51038 101.804 9.39038 101.124 10.3304V8.73038H98.6841V19.2904ZM117.728 7.11038H120.328V4.81038H117.728V7.11038ZM117.808 19.2904H120.248V8.73038H117.808V19.2904ZM123.391 19.2904H125.831V13.3304C125.831 11.6904 126.811 10.7104 128.211 10.7104C129.651 10.7104 130.471 11.6504 130.471 13.2904V19.2904H132.891V12.5504C132.891 10.1104 131.511 8.51038 129.131 8.51038C127.491 8.51038 126.511 9.37038 125.831 10.3504V8.73038H123.391V19.2904ZM139.353 19.4704C140.273 19.4704 140.933 19.2704 141.533 18.9304V16.9504C141.053 17.1904 140.573 17.3104 140.033 17.3104C139.213 17.3104 138.733 16.9304 138.733 15.9904V10.8104H141.573V8.73038H138.733V5.83038H136.313V8.73038H134.973V10.8104H136.313V16.3704C136.313 18.6904 137.573 19.4704 139.353 19.4704Z" fill="white" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.8359 8.62449C13.6297 8.17373 12.3308 7.93828 11.0189 7.93828C8.26156 7.93828 5.66799 8.96445 3.71603 10.8277C1.77253 12.6827 0.692757 15.1469 0.675382 17.7662L0.67308 18.1179L0.995493 18.2917C2.54939 19.1298 4.30666 19.5708 6.08735 19.5708C6.13631 19.5708 6.18567 19.5704 6.23475 19.5697C7.78697 19.5486 9.32263 19.1947 10.7148 18.5417C10.2758 18.3089 9.85515 18.0468 9.45524 17.7578C7.02864 18.664 4.27847 18.5523 1.95105 17.4173C2.17744 12.8209 6.16956 9.13899 11.0189 9.13899C12.3676 9.13899 13.6998 9.42181 14.903 9.95924C14.9185 9.51427 14.8962 9.06826 14.8359 8.62449" fill="white" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.3623 17.6846C21.3253 14.4281 19.6525 11.4569 16.864 9.64708C16.8661 10.1236 16.8325 10.5998 16.7635 11.0733C18.7449 12.6069 19.9528 14.8652 20.085 17.3394C15.8109 19.4271 10.4806 17.965 8.05257 13.9755C7.39676 12.8979 6.99466 11.693 6.87649 10.4619C6.46399 10.6752 6.07001 10.9205 5.69806 11.1956C5.89419 12.3803 6.32039 13.5309 6.95641 14.5759C8.33758 16.8453 10.5581 18.4723 13.2087 19.1571C14.108 19.3895 15.0224 19.5045 15.9317 19.5045C17.7034 19.5045 19.4562 19.068 21.0421 18.213L21.3662 18.0382L21.3623 17.6846Z" fill="white" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.3845 1.1535L11.0648 0.975742L10.745 1.15323C9.16521 2.02964 7.85272 3.28619 6.94934 4.78692C6.16925 6.08298 5.70784 7.5348 5.59962 9.01676C6.0321 8.77307 6.48263 8.55879 6.94848 8.37569C7.34977 5.93272 8.84843 3.72483 11.0642 2.37561C15.1338 4.85607 16.4721 9.999 14.0276 14.0154C13.3657 15.1031 12.4605 16.0436 11.3882 16.7656C11.7887 16.9971 12.2093 17.1981 12.6463 17.3662C13.6376 16.6043 14.4816 15.671 15.1238 14.6157C17.9778 9.92641 16.3003 3.88731 11.3845 1.1535" fill="white" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.0584 11.4001C10.4754 11.4001 10.0012 11.85 10.0012 12.4031C10.0012 12.9561 10.4754 13.4061 11.0584 13.4061C11.6415 13.4061 12.1158 12.9561 12.1158 12.4031C12.1158 11.85 11.6415 11.4001 11.0584 11.4001M11.0584 14.6068C9.77747 14.6068 8.73544 13.6183 8.73544 12.4031C8.73544 11.188 9.77747 10.1994 11.0584 10.1994C12.3394 10.1994 13.3815 11.188 13.3815 12.4031C13.3815 13.6183 12.3394 14.6068 11.0584 14.6068" fill="white" />
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

+3
View File
@@ -0,0 +1,3 @@
:root
--accent-color #00BB00
--background #222222
+32 -22
View File
@@ -1,3 +1,7 @@
---
order: 1
---
# Developer Sessions
The Tendermint Core developer call is comprised of both [Interchain
@@ -9,25 +13,31 @@ decision making process, technical information, update cycles etc.
## List
| Date | Topic | Link(s) |
| --------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| August 2019 | Part Three: Tendermint Lite Client | [YouTube](https://www.youtube.com/watch?v=whyL6UrKe7I&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=5) |
| August 2019 | Fork Accountability | [YouTube](https://www.youtube.com/watch?v=Jph-4PGtdPo&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=4) |
| July 2019 | Part Two: Tendermint Lite Client | [YouTube](https://www.youtube.com/watch?v=gTjG7jNNdKQ&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=6) |
| July 2019 | Part One: Tendermint Lite Client | [YouTube](https://www.youtube.com/watch?v=C6fH_sgPJzA&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=7) |
| June 2019 | Testnet Deployments | [YouTube](https://www.youtube.com/watch?v=gYA6no7tRlM&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=10) |
| June 2019 | Blockchain Reactor Refactor | [YouTube](https://www.youtube.com/watch?v=JLBGH8yxABk&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=11) |
| June 2019 | Tendermint Rust Libraries | [YouTube](https://www.youtube.com/watch?v=-WXKdyoGHwA&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=9) |
| May 2019 | Merkle Tree Deep Dive | [YouTube](https://www.youtube.com/watch?v=L3bt2Uw8ICg&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=8) |
| May 2019 | Remote Signer Refactor | [YouTube](https://www.youtube.com/watch?v=eUyXXEEuBzQ&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=12) |
| May 2019 | Introduction to Ansible | [YouTube](https://www.youtube.com/watch?v=72clQLjzPg4&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=14&t=0s) | | |
| April 2019 | Tendermint State Sync Design Discussion | [YouTube](https://www.youtube.com/watch?v=4k23j2QHwrM&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=11) |
| April 2019 | ADR-036 - Blockchain Reactor Refactor | [YouTube](https://www.youtube.com/watch?v=TW2xC1LwEkE&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=10) |
| April 2019 | Verifying Distributed Algorithms | [YouTube](https://www.youtube.com/watch?v=tMd4lgPVBxE&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=9) |
| April 2019 | Byzantine Model Checker Presentation | [YouTube](https://www.youtube.com/watch?v=rdXl4VCQyow&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=8) |
| January 2019 | Proposer Selection in Idris | [YouTube](https://www.youtube.com/watch?v=hWZdc9c1aH8&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=7) |
| January 2019 | Current Mempool Design | [YouTube](https://www.youtube.com/watch?v=--iGIYYiLu4&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=6) |
| December 2018 | ABCI Proxy App | [YouTube](https://www.youtube.com/watch?v=s6sQ2HOVHdo&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=5) |
| October 2018 | DB Performance | [YouTube](https://www.youtube.com/watch?v=jVSNHi4l0fQ&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=4) |
| October 2018 | Alternative Mempool Algorithms | [YouTube](https://www.youtube.com/watch?v=XxH5ZtM4vMM&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=2) |
| October 2018 | Tendermint Termination | [YouTube](https://www.youtube.com/watch?v=YBZjecfjeIk&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv) |
| Date | Topic | Link(s) |
| -------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| October 2019 | ABCI Overview (2/2) | [Youtube](https://www.youtube.com/watch?v=K3-E5wj2jA8) |
| October 2019 | ABCI Overview (1/2) | [YouTube](https://www.youtube.com/watch?v=I3OnA8yCHl4&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv) |
| September 2019 | IAVL+ Presentation | [YouTube](https://www.youtube.com/watch?v=e5wwBaCTc9Y&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=2) |
| September 2019 | Tendermint Dev Session - Blockchain Reactor in TLA+ | [YouTube](https://www.youtube.com/watch?v=q0e0pEQ5aiY&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=3) |
| September 2019 | Tendermint Code Review - SkipTimeoutCommit & Block Rollback | [YouTube](https://www.youtube.com/watch?v=MCo_oH7rys8&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=4) |
| September 2019 | Tendermint Evidence Handling | [YouTube](https://www.youtube.com/watch?v=-4H3_DVlYRk&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=5) |
| August 2019 | Part Three: Tendermint Lite Client | [YouTube](https://www.youtube.com/watch?v=whyL6UrKe7I&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=5) |
| August 2019 | Fork Accountability | [YouTube](https://www.youtube.com/watch?v=Jph-4PGtdPo&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=4) |
| July 2019 | Part Two: Tendermint Lite Client | [YouTube](https://www.youtube.com/watch?v=gTjG7jNNdKQ&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=6) |
| July 2019 | Part One: Tendermint Lite Client | [YouTube](https://www.youtube.com/watch?v=C6fH_sgPJzA&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=7) |
| June 2019 | Testnet Deployments | [YouTube](https://www.youtube.com/watch?v=gYA6no7tRlM&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=10) |
| June 2019 | Blockchain Reactor Refactor | [YouTube](https://www.youtube.com/watch?v=JLBGH8yxABk&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=11) |
| June 2019 | Tendermint Rust Libraries | [YouTube](https://www.youtube.com/watch?v=-WXKdyoGHwA&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=9) |
| May 2019 | Merkle Tree Deep Dive | [YouTube](https://www.youtube.com/watch?v=L3bt2Uw8ICg&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=8) |
| May 2019 | Remote Signer Refactor | [YouTube](https://www.youtube.com/watch?v=eUyXXEEuBzQ&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=12) |
| May 2019 | Introduction to Ansible | [YouTube](https://www.youtube.com/watch?v=72clQLjzPg4&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=14&t=0s) |
| April 2019 | Tendermint State Sync Design Discussion | [YouTube](https://www.youtube.com/watch?v=4k23j2QHwrM&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=11) |
| April 2019 | ADR-036 - Blockchain Reactor Refactor | [YouTube](https://www.youtube.com/watch?v=TW2xC1LwEkE&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=10) |
| April 2019 | Verifying Distributed Algorithms | [YouTube](https://www.youtube.com/watch?v=tMd4lgPVBxE&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=9) |
| April 2019 | Byzantine Model Checker Presentation | [YouTube](https://www.youtube.com/watch?v=rdXl4VCQyow&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=8) |
| January 2019 | Proposer Selection in Idris | [YouTube](https://www.youtube.com/watch?v=hWZdc9c1aH8&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=7) |
| January 2019 | Current Mempool Design | [YouTube](https://www.youtube.com/watch?v=--iGIYYiLu4&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=6) |
| December 2018 | ABCI Proxy App | [YouTube](https://www.youtube.com/watch?v=s6sQ2HOVHdo&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=5) |
| October 2018 | DB Performance | [YouTube](https://www.youtube.com/watch?v=jVSNHi4l0fQ&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=4) |
| October 2018 | Alternative Mempool Algorithms | [YouTube](https://www.youtube.com/watch?v=XxH5ZtM4vMM&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv&index=2) |
| October 2018 | Tendermint Termination | [YouTube](https://www.youtube.com/watch?v=YBZjecfjeIk&list=PLdQIb0qr3pnBbG5ZG-0gr3zM86_s8Rpqv) |
+11 -21
View File
@@ -60,37 +60,27 @@ to send users to the GitHub.
## Building Locally
To build and serve the documentation locally, run:
Make sure you are in the `docs` directory and run the following commands:
```
# from this directory
npm install -g vuepress
```sh
rm -rf node_modules
```
NOTE: the command may require `sudo`.
This command will remove old version of the visual theme and required packages. This step is optional.
then change the following line in the `.vuepress/config.js`:
```
base: "/docs/",
```sh
npm install
```
to:
Install the theme and all dependencies.
```
base: "/",
```sh
npm run serve
```
Finally, go up one directory to the root of the repo and run:
Run `pre` and `post` hooks and start a hot-reloading web-server. See output of this command for the URL (it is often https://localhost:8080).
```
# from root of repo
vuepress build docs
cd dist/docs
python -m SimpleHTTPServer 8080
```
then navigate to localhost:8080 in your browser.
To build documentation as a static website run `npm run build`. You will find the website in `.vuepress/dist` directory.
## Search
-4
View File
@@ -23,7 +23,3 @@ For more details on using Tendermint, see the respective documentation for
To contribute to the documentation, see [this file](https://github.com/tendermint/tendermint/blob/master/docs/DOCS_README.md) for details of the build process and
considerations when making changes.
## Version
This documentation is built from the following commit:
+4
View File
@@ -1,3 +1,7 @@
---
order: 2
---
# Using ABCI-CLI
To facilitate testing and debugging of ABCI servers and simple apps, we
-367
View File
@@ -1,367 +0,0 @@
# ABCI Specification
### XXX
DEPRECATED: Moved [here](../spec/abci/abci.md)
## Message Types
ABCI requests/responses are defined as simple Protobuf messages in [this
schema file](https://github.com/tendermint/tendermint/blob/master/abci/types/types.proto).
TendermintCore sends the requests, and the ABCI application sends the
responses. Here, we provide an overview of the messages types and how
they are used by Tendermint. Then we describe each request-response pair
as a function with arguments and return values, and add some notes on
usage.
Some messages (`Echo, Info, InitChain, BeginBlock, EndBlock, Commit`),
don't return errors because an error would indicate a critical failure
in the application and there's nothing Tendermint can do. The problem
should be addressed and both Tendermint and the application restarted.
All other messages (`SetOption, Query, CheckTx, DeliverTx`) return an
application-specific response `Code uint32`, where only `0` is reserved
for `OK`.
Some messages (`SetOption, Query, CheckTx, DeliverTx`) return
non-deterministic data in the form of `Info` and `Log`. The `Log` is
intended for the literal output from the application's logger, while the
`Info` is any additional info that should be returned.
The first time a new blockchain is started, Tendermint calls
`InitChain`. From then on, the Block Execution Sequence that causes the
committed state to be updated is as follows:
`BeginBlock, [DeliverTx], EndBlock, Commit`
where one `DeliverTx` is called for each transaction in the block.
Cryptographic commitments to the results of DeliverTx, EndBlock, and
Commit are included in the header of the next block.
Tendermint opens three connections to the application to handle the
different message types:
- `Consensus Connection - InitChain, BeginBlock, DeliverTx, EndBlock, Commit`
- `Mempool Connection - CheckTx`
- `Info Connection - Info, SetOption, Query`
The `Flush` message is used on every connection, and the `Echo` message
is only used for debugging.
Note that messages may be sent concurrently across all connections -a
typical application will thus maintain a distinct state for each
connection. They may be referred to as the `DeliverTx state`, the
`CheckTx state`, and the `Commit state` respectively.
See below for more details on the message types and how they are used.
## Request/Response Messages
### Echo
- **Request**:
- `Message (string)`: A string to echo back
- **Response**:
- `Message (string)`: The input string
- **Usage**:
- Echo a string to test an abci client/server implementation
### Flush
- **Usage**:
- Signals that messages queued on the client should be flushed to
the server. It is called periodically by the client
implementation to ensure asynchronous requests are actually
sent, and is called immediately to make a synchronous request,
which returns when the Flush response comes back.
### Info
- **Request**:
- `Version (string)`: The Tendermint version
- **Response**:
- `Data (string)`: Some arbitrary information
- `Version (Version)`: Version information
- `LastBlockHeight (int64)`: Latest block for which the app has
called Commit
- `LastBlockAppHash ([]byte)`: Latest result of Commit
- **Usage**:
- Return information about the application state.
- Used to sync Tendermint with the application during a handshake
that happens on startup.
- Tendermint expects `LastBlockAppHash` and `LastBlockHeight` to
be updated during `Commit`, ensuring that `Commit` is never
called twice for the same block height.
### SetOption
- **Request**:
- `Key (string)`: Key to set
- `Value (string)`: Value to set for key
- **Response**:
- `Code (uint32)`: Response code
- `Log (string)`: The output of the application's logger. May
be non-deterministic.
- `Info (string)`: Additional information. May
be non-deterministic.
- **Usage**:
- Set non-consensus critical application specific options.
- e.g. Key="min-fee", Value="100fermion" could set the minimum fee
required for CheckTx (but not DeliverTx - that would be
consensus critical).
### InitChain
- **Request**:
- `Time (google.protobuf.Timestamp)`: Genesis time.
- `ChainID (string)`: ID of the blockchain.
- `ConsensusParams (ConsensusParams)`: Initial consensus-critical parameters.
- `Validators ([]ValidatorUpdate)`: Initial genesis validators.
- `AppStateBytes ([]byte)`: Serialized initial application state. Amino-encoded JSON bytes.
- **Response**:
- `ConsensusParams (ConsensusParams)`: Initial
consensus-critical parameters.
- `Validators ([]ValidatorUpdate)`: Initial validator set (if non empty).
- **Usage**:
- Called once upon genesis.
- If ResponseInitChain.Validators is empty, the initial validator set will be the RequestInitChain.Validators
- If ResponseInitChain.Validators is not empty, the initial validator set will be the
ResponseInitChain.Validators (regardless of what is in RequestInitChain.Validators).
- This allows the app to decide if it wants to accept the initial validator
set proposed by tendermint (ie. in the genesis file), or if it wants to use
a different one (perhaps computed based on some application specific
information in the genesis file).
### Query
- **Request**:
- `Data ([]byte)`: Raw query bytes. Can be used with or in lieu
of Path.
- `Path (string)`: Path of request, like an HTTP GET path. Can be
used with or in liue of Data.
- Apps MUST interpret '/store' as a query by key on the
underlying store. The key SHOULD be specified in the Data field.
- Apps SHOULD allow queries over specific types like
'/accounts/...' or '/votes/...'
- `Height (int64)`: The block height for which you want the query
(default=0 returns data for the latest committed block). Note
that this is the height of the block containing the
application's Merkle root hash, which represents the state as it
was after committing the block at Height-1
- `Prove (bool)`: Return Merkle proof with response if possible
- **Response**:
- `Code (uint32)`: Response code.
- `Log (string)`: The output of the application's logger. May
be non-deterministic.
- `Info (string)`: Additional information. May
be non-deterministic.
- `Index (int64)`: The index of the key in the tree.
- `Key ([]byte)`: The key of the matching data.
- `Value ([]byte)`: The value of the matching data.
- `Proof ([]byte)`: Proof for the data, if requested.
- `Height (int64)`: The block height from which data was derived.
Note that this is the height of the block containing the
application's Merkle root hash, which represents the state as it
was after committing the block at Height-1
- **Usage**:
- Query for data from the application at current or past height.
- Optionally return Merkle proof.
### BeginBlock
- **Request**:
- `Hash ([]byte)`: The block's hash. This can be derived from the
block header.
- `Header (struct{})`: The block header.
- `LastCommitInfo (LastCommitInfo)`: Info about the last commit, including the
round, and the list of validators and which ones signed the last block.
- `ByzantineValidators ([]Evidence)`: List of evidence of
validators that acted maliciously.
- **Response**:
- `Tags ([]cmn.KVPair)`: Key-Value tags for filtering and indexing
- **Usage**:
- Signals the beginning of a new block. Called prior to
any DeliverTxs.
- The header contains the height, timestamp, and more - it exactly matches the
Tendermint block header. We may seek to generalize this in the future.
- The `LastCommitInfo` and `ByzantineValidators` can be used to determine
rewards and punishments for the validators. NOTE validators here do not
include pubkeys.
### CheckTx
- **Request**:
- `Tx ([]byte)`: The request transaction bytes
- **Response**:
- `Code (uint32)`: Response code
- `Data ([]byte)`: Result bytes, if any.
- `Log (string)`: The output of the application's logger. May
be non-deterministic.
- `Info (string)`: Additional information. May
be non-deterministic.
- `GasWanted (int64)`: Amount of gas request for transaction.
- `GasUsed (int64)`: Amount of gas consumed by transaction.
- `Tags ([]cmn.KVPair)`: Key-Value tags for filtering and indexing
transactions (eg. by account).
- **Usage**: Validate a mempool transaction, prior to broadcasting
or proposing. CheckTx should perform stateful but light-weight
checks of the validity of the transaction (like checking signatures
and account balances), but need not execute in full (like running a
smart contract).
Tendermint runs CheckTx and DeliverTx concurrently with eachother,
though on distinct ABCI connections - the mempool connection and the
consensus connection, respectively.
The application should maintain a separate state to support CheckTx.
This state can be reset to the latest committed state during
`Commit`. Before calling Commit, Tendermint will lock and flush the mempool,
ensuring that all existing CheckTx are responded to and no new ones can
begin. After `Commit`, the mempool will rerun
CheckTx for all remaining transactions, throwing out any that are no longer valid.
Then the mempool will unlock and start sending CheckTx again.
Keys and values in Tags must be UTF-8 encoded strings (e.g.
"account.owner": "Bob", "balance": "100.0", "date": "2018-01-02")
### DeliverTx
- **Request**:
- `Tx ([]byte)`: The request transaction bytes.
- **Response**:
- `Code (uint32)`: Response code.
- `Data ([]byte)`: Result bytes, if any.
- `Log (string)`: The output of the application's logger. May
be non-deterministic.
- `Info (string)`: Additional information. May
be non-deterministic.
- `GasWanted (int64)`: Amount of gas requested for transaction.
- `GasUsed (int64)`: Amount of gas consumed by transaction.
- `Tags ([]cmn.KVPair)`: Key-Value tags for filtering and indexing
transactions (eg. by account).
- **Usage**:
- Deliver a transaction to be executed in full by the application.
If the transaction is valid, returns CodeType.OK.
- Keys and values in Tags must be UTF-8 encoded strings (e.g.
"account.owner": "Bob", "balance": "100.0",
"time": "2018-01-02T12:30:00Z")
### EndBlock
- **Request**:
- `Height (int64)`: Height of the block just executed.
- **Response**:
- `ValidatorUpdates ([]ValidatorUpdate)`: Changes to validator set (set
voting power to 0 to remove).
- `ConsensusParamUpdates (ConsensusParams)`: Changes to
consensus-critical time, size, and other parameters.
- `Tags ([]cmn.KVPair)`: Key-Value tags for filtering and indexing
- **Usage**:
- Signals the end of a block.
- Called prior to each Commit, after all transactions.
- Validator updates returned for block H:
- apply to the NextValidatorsHash of block H+1
- apply to the ValidatorsHash (and thus the validator set) for block H+2
- apply to the RequestBeginBlock.LastCommitInfo (ie. the last validator set) for block H+3
- Consensus params returned for block H apply for block H+1
### Commit
- **Response**:
- `Data ([]byte)`: The Merkle root hash
- **Usage**:
- Persist the application state.
- Return a Merkle root hash of the application state.
- It's critical that all application instances return the
same hash. If not, they will not be able to agree on the next
block, because the hash is included in the next block!
## Data Messages
### Header
- **Fields**:
- `ChainID (string)`: ID of the blockchain
- `Height (int64)`: Height of the block in the chain
- `Time (google.protobuf.Timestamp)`: Time of the block. It is the proposer's
local time when block was created.
- `NumTxs (int32)`: Number of transactions in the block
- `TotalTxs (int64)`: Total number of transactions in the blockchain until
now
- `LastBlockID (BlockID)`: Hash of the previous (parent) block
- `LastCommitHash ([]byte)`: Hash of the previous block's commit
- `ValidatorsHash ([]byte)`: Hash of the validator set for this block
- `NextValidatorsHash ([]byte)`: Hash of the validator set for the next block
- `ConsensusHash ([]byte)`: Hash of the consensus parameters for this block
- `AppHash ([]byte)`: Data returned by the last call to `Commit` - typically the
Merkle root of the application state after executing the previous block's
transactions
- `LastResultsHash ([]byte)`: Hash of the ABCI results returned by the last block
- `EvidenceHash ([]byte)`: Hash of the evidence included in this block
- `ProposerAddress ([]byte)`: Original proposer for the block
- **Usage**:
- Provided in RequestBeginBlock
- Provides important context about the current state of the blockchain -
especially height and time.
- Provides the proposer of the current block, for use in proposer-based
reward mechanisms.
### Validator
- **Fields**:
- `Address ([]byte)`: Address of the validator (hash of the public key)
- `Power (int64)`: Voting power of the validator
- **Usage**:
- Validator identified by address
- Used in RequestBeginBlock as part of VoteInfo
- Does not include PubKey to avoid sending potentially large quantum pubkeys
over the ABCI
### ValidatorUpdate
- **Fields**:
- `PubKey (PubKey)`: Public key of the validator
- `Power (int64)`: Voting power of the validator
- **Usage**:
- Validator identified by PubKey
- Used to tell Tendermint to update the validator set
### VoteInfo
- **Fields**:
- `Validator (Validator)`: A validator
- `SignedLastBlock (bool)`: Indicates whether or not the validator signed
the last block
- **Usage**:
- Indicates whether a validator signed the last block, allowing for rewards
based on validator availability
### PubKey
- **Fields**:
- `Type (string)`: Type of the public key. A simple string like `"ed25519"`.
In the future, may indicate a serialization algorithm to parse the `Data`,
for instance `"amino"`.
- `Data ([]byte)`: Public key data. For a simple public key, it's just the
raw bytes. If the `Type` indicates an encoding algorithm, this is the
encoded public key.
- **Usage**:
- A generic and extensible typed public key
### Evidence
- **Fields**:
- `Type (string)`: Type of the evidence. A hierarchical path like
"duplicate/vote".
- `Validator (Validator`: The offending validator
- `Height (int64)`: Height when the offense was committed
- `Time (google.protobuf.Timestamp)`: Time of the block at height `Height`.
It is the proposer's local time when block was created.
- `TotalVotingPower (int64)`: Total voting power of the validator set at
height `Height`
### LastCommitInfo
- **Fields**:
- `Round (int32)`: Commit round.
- `Votes ([]VoteInfo)`: List of validators addresses in the last validator set
with their voting power and whether or not they signed a vote.
+5 -1
View File
@@ -1,3 +1,7 @@
---
order: 3
---
# Application Architecture Guide
Here we provide a brief guide on the recommended architecture of a
@@ -47,4 +51,4 @@ See the following for more extensive documentation:
- [Interchain Standard for the Light-Client REST API](https://github.com/cosmos/cosmos-sdk/pull/1028)
- [Tendermint RPC Docs](https://tendermint.com/rpc/)
- [Tendermint in Production](../tendermint-core/running-in-production.md)
- [ABCI spec](./abci-spec.md)
- [ABCI spec](https://github.com/tendermint/spec/tree/95cf253b6df623066ff7cd4074a94e7a3f147c7a/spec/abci)
+4
View File
@@ -1,3 +1,7 @@
---
order: 4
---
# Application Development Guide
## XXX
-200
View File
@@ -1,200 +0,0 @@
{
"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": "ParadigmCore",
"url": "https://github.com/ParadigmFoundation/ParadigmCore",
"language": "TypeScript",
"author": "Paradigm Labs",
"description": "Reference implementation of the Paradigm Protocol, and OrderStream network client."
},
{
"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": "go-abci",
"url": "https://github.com/tendermint/tendermint/tree/master/abci",
"language": "Go",
"author": "Tendermint"
},
{
"name": "js-abci",
"url": "https://github.com/tendermint/js-abci",
"language": "Javascript",
"author": "Tendermint"
},
{
"name": "rust-tsp",
"url": "https://github.com/tendermint/rust-tsp",
"language": "Rust",
"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": "tm-abci (fork of py-abci with async IO)",
"url": "https://github.com/SoftblocksCo/tm-abci",
"language": "Python",
"author": "Softblocks"
},
{
"name": "Spearmint",
"url": "https://github.com/dennismckinnon/spearmint",
"language": "Javascript",
"author": "Dennis McKinnon"
}
],
"aminoLibraries": [
{
"name": "JS-Amino",
"url": "https://github.com/TanNgocDo/Js-Amino",
"language": "Javascript",
"author": "TanNgocDo"
}
]
}
-9
View File
@@ -1,9 +0,0 @@
# Ecosystem
The growing list of applications built using various pieces of the
Tendermint stack can be found at the [ecosystem page](https://tendermint.com/ecosystem).
We thank the community for their contributions 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.
+15 -6
View File
@@ -1,3 +1,7 @@
---
order: 1
---
# Getting Started
## First Tendermint App
@@ -17,10 +21,13 @@ using Tendermint.
### Install
The first apps we will work with are written in Go. To install them, you
need to [install Go](https://golang.org/doc/install) and put
`$GOPATH/bin` in your `$PATH`; see
[here](https://github.com/tendermint/tendermint/wiki/Setting-GOPATH) for
more info.
need to [install Go](https://golang.org/doc/install), put
`$GOPATH/bin` in your `$PATH` and enable go modules with these instructions:
```bash
echo export GOPATH=\"\$HOME/go\" >> ~/.bash_profile
echo export PATH=\"\$PATH:\$GOPATH/bin\" >> ~/.bash_profile
echo export GO111MODULE=on >> ~/.bash_profile
```
Then run
@@ -51,8 +58,10 @@ Let's start a kvstore application.
abci-cli kvstore
```
In another terminal, we can start Tendermint. If you have never run
Tendermint before, use:
In another terminal, we can start Tendermint. You should already have the
Tendermint binary installed. If not, follow the steps from
[here](../introduction/install.md). If you have never run Tendermint
before, use:
```
tendermint init
+46 -29
View File
@@ -1,11 +1,24 @@
---
order: 6
---
# Indexing Transactions
Tendermint allows you to index transactions and later query or subscribe
to their results.
Events can be used to index transactions and blocks according to what happened
during their execution. Note that the set of events returned for a block from
`BeginBlock` and `EndBlock` are merged. In case both methods return the same
tag, only the value defined in `EndBlock` is used.
Each event contains a type and a list of attributes, which are key-value pairs
denoting something about what happened during the method's execution. For more
details on `Events`, see the [ABCI](../spec/abci/abci.md) documentation.
Let's take a look at the `[tx_index]` config section:
```
```toml
##### transactions indexer configuration options #####
[tx_index]
@@ -36,57 +49,61 @@ index_all_tags = false
By default, Tendermint will index all transactions by their respective
hashes using an embedded simple indexer. Note, we are planning to add
more options in the future (e.g., Postgresql indexer).
more options in the future (e.g., PostgreSQL indexer).
## Adding tags
## Adding Events
In your application's `DeliverTx` method, add the `Tags` field with the
pairs of UTF-8 encoded strings (e.g. "account.owner": "Bob", "balance":
"100.0", "date": "2018-01-02").
In your application's `DeliverTx` method, add the `Events` field with pairs of
UTF-8 encoded strings (e.g. "transfer.sender": "Bob", "transfer.recipient": "Alice",
"transfer.balance": "100").
Example:
```
```go
func (app *KVStoreApplication) DeliverTx(req types.RequestDeliverTx) types.Result {
...
tags := []cmn.KVPair{
{[]byte("account.name"), []byte("igor")},
{[]byte("account.address"), []byte("0xdeadbeef")},
{[]byte("tx.amount"), []byte("7")},
//...
events := []abci.Event{
{
Type: "transfer",
Attributes: cmn.KVPairs{
cmn.KVPair{Key: []byte("sender"), Value: []byte("Bob")},
cmn.KVPair{Key: []byte("recipient"), Value: []byte("Alice")},
cmn.KVPair{Key: []byte("balance"), Value: []byte("100")},
},
},
}
return types.ResponseDeliverTx{Code: code.CodeTypeOK, Tags: tags}
return types.ResponseDeliverTx{Code: code.CodeTypeOK, Events: events}
}
```
If you want Tendermint to only index transactions by "account.name" tag,
in the config set `tx_index.index_tags="account.name"`. If you to index
all tags, set `index_all_tags=true`
If you want Tendermint to only index transactions by "transfer.sender" event type,
in the config set `tx_index.index_tags="transfer.sender"`. If you to index all events,
set `index_all_tags=true`
Note, there are a few predefined tags:
Note, there are a few predefined event types:
- `tx.hash` (transaction's hash)
- `tx.height` (height of the block transaction was committed in)
Tendermint will throw a warning if you try to use any of the above keys.
## Querying transactions
## Querying Transactions
You can query the transaction results by calling `/tx_search` RPC
endpoint:
You can query the transaction results by calling `/tx_search` RPC endpoint:
```
```shell
curl "localhost:26657/tx_search?query=\"account.name='igor'\"&prove=true"
```
Check out [API docs](https://tendermint.com/rpc/#txsearch)
for more information on query syntax and other options.
Check out [API docs](https://tendermint.com/rpc/#txsearch) for more information
on query syntax and other options.
## Subscribing to transactions
## Subscribing to Transactions
Clients can subscribe to transactions with the given tags via Websocket
by providing a query to `/subscribe` RPC endpoint.
Clients can subscribe to transactions with the given tags via Websocket by providing
a query to `/subscribe` RPC endpoint.
```
```json
{
"jsonrpc": "2.0",
"method": "subscribe",
@@ -97,5 +114,5 @@ by providing a query to `/subscribe` RPC endpoint.
}
```
Check out [API docs](https://tendermint.com/rpc/#subscribe) for
more information on query syntax and other options.
Check out [API docs](https://tendermint.com/rpc/#subscribe) for more information
on query syntax and other options.
+7
View File
@@ -0,0 +1,7 @@
---
order: false
parent:
order: 3
---
# Apps

Some files were not shown because too many files have changed in this diff Show More