Merge branch 'master' into anton/lc-adr-2

This commit is contained in:
Anton Kaliaev
2019-08-28 13:13:44 +04:00
8 changed files with 490 additions and 258 deletions

View File

@ -216,11 +216,11 @@ jobs:
name: Trigger website build name: Trigger website build
command: | command: |
curl --silent \ curl --silent \
--show-error \ --show-error \
-X POST \ -X POST \
--header "Content-Type: application/json" \ --header "Content-Type: application/json" \
-d "{\"branch\": \"$CIRCLE_BRANCH\"}" \ -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 "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` RESULT=`jq -r '.status' response.json`
MESSAGE=`jq -r '.message' response.json` MESSAGE=`jq -r '.message' response.json`
@ -373,12 +373,12 @@ jobs:
steps: steps:
- checkout - checkout
- run: - run:
name: Test RPC endpoints agsainst swagger documentation name: Test RPC endpoints against swagger documentation
command: | command: |
set -x set -x
export PATH=~/.local/bin:$PATH export PATH=~/.local/bin:$PATH
# install node 11.15 and dredd # install node and dredd
./scripts/get_nodejs.sh ./scripts/get_nodejs.sh
# build the binaries with a proper version of Go # build the binaries with a proper version of Go

View File

@ -1,5 +1,32 @@
# Changelog # Changelog
## v0.32.3
*August 28, 2019*
@climber73 wrote the [Writing a Tendermint Core application in Java
(gRPC)](https://github.com/tendermint/tendermint/blob/master/docs/guides/java.md)
guide.
Special thanks to external contributors on this release:
@gchaincl, @bluele, @climber73
Friendly reminder, we have a [bug bounty
program](https://hackerone.com/tendermint).
### IMPROVEMENTS:
- [consensus] [\#3839](https://github.com/tendermint/tendermint/issues/3839) Reduce "Error attempting to add vote" message severity (Error -> Info)
- [mempool] [\#3877](https://github.com/tendermint/tendermint/pull/3877) Make `max_tx_bytes` configurable instead of `max_msg_bytes` (@bluele)
- [privval] [\#3370](https://github.com/tendermint/tendermint/issues/3370) Refactor and simplify validator/kms connection handling. Please refer to [this comment](https://github.com/tendermint/tendermint/pull/3370#issue-257360971) for details
- [rpc] [\#3880](https://github.com/tendermint/tendermint/issues/3880) Document endpoints with `swagger`, introduce contract tests of implementation against documentation
### BUG FIXES:
- [config] [\#3868](https://github.com/tendermint/tendermint/issues/3868) Move misplaced `max_msg_bytes` into mempool section (@bluele)
- [rpc] [\#3910](https://github.com/tendermint/tendermint/pull/3910) Fix DATA RACE in HTTP client (@gchaincl)
- [store] [\#3893](https://github.com/tendermint/tendermint/issues/3893) Fix "Unregistered interface types.Evidence" panic
## v0.32.2 ## v0.32.2
*July 31, 2019* *July 31, 2019*

View File

@ -1,4 +1,4 @@
## v0.32.3 ## v0.32.4
\*\* \*\*
@ -19,13 +19,4 @@ program](https://hackerone.com/tendermint).
### IMPROVEMENTS: ### IMPROVEMENTS:
- [privval] \#3370 Refactors and simplifies validator/kms connection handling. Please refer to thttps://github.com/tendermint/tendermint/pull/3370#issue-257360971
- [consensus] \#3839 Reduce "Error attempting to add vote" message severity (Error -> Info)
- [mempool] \#3877 Make `max_tx_bytes` configurable instead of `max_msg_bytes`
- [rpc] \#3880 Document endpoints with `swagger`, introduce contract tests of implementation against documentation
### BUG FIXES: ### BUG FIXES:
- [config] \#3868 move misplaced `max_msg_bytes` into mempool section
- [store] \#3893 register block amino, not just crypto
- [rpc] [\#3910](https://github.com/tendermint/tendermint/pull/3910) protect subscription access from race conditions (@gchaincl)

View File

@ -2,7 +2,7 @@
Thank you for considering making contributions to Tendermint and related repositories! Start by taking a look at the [coding repo](https://github.com/tendermint/coding) for overall information on repository workflow and standards. Thank you for considering making contributions to Tendermint and related repositories! Start by taking a look at the [coding repo](https://github.com/tendermint/coding) for overall information on repository workflow and standards.
Please follow standard github best practices: fork the repo, branch from the tip of `master`, make some commits, and submit a pull request to `master`. Please follow standard github best practices: fork the repo, branch from the tip of `master`, make some commits, and submit a pull request to `master`.
See the [open issues](https://github.com/tendermint/tendermint/issues) for things we need help with! See the [open issues](https://github.com/tendermint/tendermint/issues) for things we need help with!
Before making a pull request, please open an issue describing the Before making a pull request, please open an issue describing the
@ -21,16 +21,16 @@ Please make sure to use `gofmt` before every commit - the easiest way to do this
Please note that Go requires code to live under absolute paths, which complicates forking. Please note that Go requires code to live under absolute paths, which complicates forking.
While my fork lives at `https://github.com/ebuchman/tendermint`, While my fork lives at `https://github.com/ebuchman/tendermint`,
the code should never exist at `$GOPATH/src/github.com/ebuchman/tendermint`. the code should never exist at `$GOPATH/src/github.com/ebuchman/tendermint`.
Instead, we use `git remote` to add the fork as a new remote for the original repo, Instead, we use `git remote` to add the fork as a new remote for the original repo,
`$GOPATH/src/github.com/tendermint/tendermint `, and do all the work there. `$GOPATH/src/github.com/tendermint/tendermint`, and do all the work there.
For instance, to create a fork and work on a branch of it, I would: For instance, to create a fork and work on a branch of it, I would:
* Create the fork on github, using the fork button. - Create the fork on github, using the fork button.
* Go to the original repo checked out locally (i.e. `$GOPATH/src/github.com/tendermint/tendermint`) - Go to the original repo checked out locally (i.e. `$GOPATH/src/github.com/tendermint/tendermint`)
* `git remote rename origin upstream` - `git remote rename origin upstream`
* `git remote add origin git@github.com:ebuchman/basecoin.git` - `git remote add origin git@github.com:ebuchman/basecoin.git`
Now `origin` refers to my fork and `upstream` refers to the tendermint version. Now `origin` refers to my fork and `upstream` refers to the tendermint version.
So I can `git push -u origin master` to update my fork, and make pull requests to tendermint from there. So I can `git push -u origin master` to update my fork, and make pull requests to tendermint from there.
@ -38,8 +38,8 @@ Of course, replace `ebuchman` with your git handle.
To pull in updates from the origin repo, run To pull in updates from the origin repo, run
* `git fetch upstream` - `git fetch upstream`
* `git rebase upstream/master` (or whatever branch you want) - `git rebase upstream/master` (or whatever branch you want)
## Dependencies ## Dependencies
@ -113,7 +113,7 @@ removed from the header in rpc responses as well.
## Branching Model and Release ## Branching Model and Release
The main development branch is master. The main development branch is master.
Every release is maintained in a release branch named `vX.Y.Z`. Every release is maintained in a release branch named `vX.Y.Z`.
@ -140,36 +140,35 @@ easy to reference the pull request where a change was introduced.
#### Major Release #### Major Release
1. start on `master` 1. start on `master`
2. run integration tests (see `test_integrations` in Makefile) 2. run integration tests (see `test_integrations` in Makefile)
3. prepare release in a pull request against `master` (to be squash merged): 3. prepare release in a pull request against `master` (to be squash merged):
- copy `CHANGELOG_PENDING.md` to top of `CHANGELOG.md` - copy `CHANGELOG_PENDING.md` to top of `CHANGELOG.md`
- run `python ./scripts/linkify_changelog.py CHANGELOG.md` to add links for - run `python ./scripts/linkify_changelog.py CHANGELOG.md` to add links for
all issues all issues
- run `bash ./scripts/authors.sh` to get a list of authors since the latest - run `bash ./scripts/authors.sh` to get a list of authors since the latest
release, and add the github aliases of external contributors to the top of release, and add the github aliases of external contributors to the top of
the changelog. To lookup an alias from an email, try `bash the changelog. To lookup an alias from an email, try `bash ./scripts/authors.sh <email>`
./scripts/authors.sh <email>` - reset the `CHANGELOG_PENDING.md`
- reset the `CHANGELOG_PENDING.md` - bump versions
- bump versions
4. push your changes with prepared release details to `vX.X` (this will trigger the release `vX.X.0`) 4. push your changes with prepared release details to `vX.X` (this will trigger the release `vX.X.0`)
5. merge back to master (don't squash merge!) 5. merge back to master (don't squash merge!)
#### Minor Release #### Minor Release
If there were no breaking changes and you need to create a release nonetheless, If there were no breaking changes and you need to create a release nonetheless,
the procedure is almost exactly like with a new release above. the procedure is almost exactly like with a new release above.
The only difference is that in the end you create a pull request against the existing `X.X` branch. The only difference is that in the end you create a pull request against the existing `X.X` branch.
The branch name should match the release number you want to create. The branch name should match the release number you want to create.
Merging this PR will trigger the next release. Merging this PR will trigger the next release.
For example, if the PR is against an existing 0.34 branch which already contains a v0.34.0 release/tag, For example, if the PR is against an existing 0.34 branch which already contains a v0.34.0 release/tag,
the patch version will be incremented and the created release will be v0.34.1. the patch version will be incremented and the created release will be v0.34.1.
#### Backport Release #### Backport Release
1. start from the existing release branch you want to backport changes to (e.g. v0.30) 1. start from the existing release branch you want to backport changes to (e.g. v0.30)
Branch to a release/vX.X.X branch locally (e.g. release/v0.30.7) Branch to a release/vX.X.X branch locally (e.g. release/v0.30.7)
2. cherry pick the commit(s) that contain the changes you want to backport (usually these commits are from squash-merged PRs which were already reviewed) 2. cherry pick the commit(s) that contain the changes you want to backport (usually these commits are from squash-merged PRs which were already reviewed)
3. steps 2 and 3 from [Major Release](#major-release) 3. steps 2 and 3 from [Major Release](#major-release)
4. push changes to release/vX.X.X branch 4. push changes to release/vX.X.X branch
@ -187,12 +186,12 @@ includes its continuous integration status using a badge in the `README.md`.
### RPC Testing ### 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](./docs/spec/rpc/swagger.yaml)
To test your changes you should install `nodejs` version `v11.15.*` and run: To test your changes you should install `nodejs` and run:
```bash ```bash
npm i -g dredd npm i -g dredd
make build-linux build-contract-tests-hooks make build-linux build-contract-tests-hooks
make contract-tests make contract-tests
``` ```
This command will popup a network and check every endpoint against what has been documented This command will popup a network and check every endpoint against what has been documented

View File

@ -1,113 +1,329 @@
# Light Client # Lite client
A light client is a process that connects to the Tendermint Full Node(s) and then tries to verify the Merkle proofs A lite client is a process that connects to Tendermint full nodes and then tries to verify application data using the Merkle proofs.
about the blockchain application. In this document we describe mechanisms that ensures that the Tendermint light client
has the same level of security as Full Node processes (without being itself a Full Node).
To be able to validate a Merkle proof, a light client needs to validate the blockchain header that contains the root app hash. ## Context of this document
Validating a blockchain header in Tendermint consists in verifying that the header is committed (signed) by >2/3 of the
voting power of the corresponding validator set. As the validator set is a dynamic set (it is changing), one of the
core functionality of the light client is updating the current validator set, that is then used to verify the
blockchain header, and further the corresponding Merkle proofs.
For the purpose of this light client specification, we assume that the Tendermint Full Node exposes the following functions over In order to make sure that full nodes have the incentive to follow the protocol, we have to address the following three Issues
Tendermint RPC:
```golang 1) The lite client needs a method to verify headers it obtains from full nodes according to trust assumptions -- this document.
Header(height int64) (SignedHeader, error) // returns signed header for the given height
Validators(height int64) (ResultValidators, error) // returns validator set for the given height
LastHeader(valSetNumber int64) (SignedHeader, error) // returns last header signed by the validator set with the given validator set number
type SignedHeader struct { 2) The lite client must be able to connect to one correct full node to detect and report on failures in the trust assumptions (i.e., conflicting headers) -- a future document.
Header Header
Commit Commit
ValSetNumber int64
}
type ResultValidators struct { 3) In the event the trust assumption fails (i.e., a lite client is fooled by a conflicting header), the Tendermint fork accountability protocol must account for the evidence -- see #3840
BlockHeight int64
Validators []Validator ## Problem statement
// time the current validator set is initialised, i.e, time of the last validator change before header BlockHeight
ValSetTime int64
} We assume that the lite client knows a (base) header *inithead* it trusts (by social consensus or because the lite client has decided to trust the header before). The goal is to check whether another header *newhead* can be trusted based on the data in *inithead*.
The correctness of the protocol is based on the assumption that *inithead* was generated by an instance of Tendermint consensus. The term "trusting" above indicates that the correctness on the protocol depends on this assumption. It is in the responsibility of the user that runs the lite client to make sure that the risk of trusting a corrupted/forged *inithead* is negligible.
## Definitions
### Data structures
In the following, only the details of the data structures needed for this specification are given.
* header fields
- *height*
- *bfttime*: the chain time when the header (block) was generated
- *V*: validator set containing validators for this block.
- *NextV*: validator set for next block.
- *commit*: evidence that block with height *height* - 1 was committed by a set of validators (canonical commit). We will use ```signers(commit)``` to refer to the set of validators that committed the block.
* signed header fields: contains a header and a *commit* for the current header; a "seen commit". In the Tendermint consensus the "canonical commit" is stored in header *height* + 1.
* For each header *h* it has locally stored, the lite client stores whether
it trusts *h*. We write *trust(h) = true*, if this is the case.
* Validator fields. We will write a validator as a tuple *(v,p)* such that
+ *v* is the identifier (we assume identifiers are unique in each validator set)
+ *p* is its voting power
### Functions
For the purpose of this lite client specification, we assume that the Tendermint Full Node exposes the following function over Tendermint RPC:
```go
func Commit(height int64) (SignedHeader, error)
// returns signed header: header (with the fields from
// above) with Commit that include signatures of
// validators that signed the header
type SignedHeader struct {
Header Header
Commit Commit
}
``` ```
We assume that Tendermint keeps track of the validator set changes and that each time a validator set is changed it is ### Definitions
being assigned the next sequence number. We can call this number the validator set sequence number. Tendermint also remembers
the Time from the header when the next validator set is initialised (starts to be in power), and we refer to this time
as validator set init time.
Furthermore, we assume that each validator set change is signed (committed) by the current validator set. More precisely,
given a block `H` that contains transactions that are modifying the current validator set, the Merkle root hash of the next
validator set (modified based on transactions from block H) will be in block `H+1` (and signed by the current validator
set), and then starting from the block `H+2`, it will be signed by the next validator set.
Note that the real Tendermint RPC API is slightly different (for example, response messages contain more data and function * *tp*: trusting period
names are slightly different); we shortened (and modified) it for the purpose of this document to make the spec more * for realtime *t*, the predicate *correct(v,t)* is true if the validator *v*
clear and simple. Furthermore, note that in case of the third function, the returned header has `ValSetNumber` equals to follows the protocol until time *t* (we will see about recovery later).
`valSetNumber+1`.
Locally, light client manages the following state:
```golang
valSet []Validator // current validator set (last known and verified validator set)
valSetNumber int64 // sequence number of the current validator set ### Tendermint Failure Model
valSetHash []byte // hash of the current validator set
valSetTime int64 // time when the current validator set is initialised If a block *h* is generated at time *bfttime* (and this time is stored in the block), then a set of validators that hold more than 2/3 of the voting power in h.Header.NextV is correct until time h.Header.bfttime + tp.
Formally,
\[
\sum_{(v,p) \in h.Header.NextV \wedge correct(v,h.Header.bfttime + tp)} p >
2/3 \sum_{(v,p) \in h.Header.NextV} p
\]
*Assumption*: "correct" is defined w.r.t. realtime (some Newtonian global notion of time, i.e., wall time), while *bfttime* corresponds to the reading of the local clock of a validator (how this time is computed may change when the Tendermint consensus is modified). In this note, we assume that all clocks are synchronized to realtime. We can make this more precise eventually (incorporating clock drift, accuracy, precision, etc.). Right now, we consider this assumption sufficient, as clock synchronization (under NTP) is in the order of milliseconds and *tp* is in the order of weeks.
*Remark*: This failure model might change to a hybrid version that takes heights into account in the future.
The specification in this document considers an implementation of the lite client under this assumption. Issues like *counter-factual signing* and *fork accountability* and *evidence submission* are mechanisms that justify this assumption by incentivizing validators to follow the protocol.
If they don't, and we have more that 1/3 faults, safety may be violated. Our approach then is to *detect* these cases (after the fact), and take suitable repair actions (automatic and social). This is discussed in an upcoming document on "Fork accountability". (These safety violations include the lite client wrongly trusting a header, a fork in the blockchain, etc.)
## Lite Client Trusting Spec
The lite client communicates with a full node and learns new headers. The goal is to locally decide whether to trust a header. Our implementation needs to ensure the following two properties:
- Lite Client Completeness: If header *h* was correctly generated by an instance of Tendermint consensus (and its age is less than the trusting period), then the lite client should eventually set *trust(h)* to true.
- Lite Client Accuracy: If header *h* was *not generated* by an instance of Tendermint consensus, then the lite client should never set *trust(h)* to true.
*Remark*: If in the course of the computation, the lite client obtains certainty that some headers were forged by adversaries (that is were not generated by an instance of Tendermint consensus), it may submit (a subset of) the headers it has seen as evidence of misbehavior.
*Remark*: In Completeness we use "eventually", while in practice *trust(h)* should be set to true before *h.Header.bfttime + tp*. If not, the block cannot be trusted because it is too old.
*Remark*: If a header *h* is marked with *trust(h)*, but it is too old (its bfttime is more than *tp* ago), then the lite client should set *trust(h)* to false again.
*Assumption*: Initially, the lite client has a header *inithead* that it trusts correctly, that is, *inithead* was correctly generated by the Tendermint consensus.
To reason about the correctness, we may prove the following invariant.
*Verification Condition: Lite Client Invariant.*
For each lite client *l* and each header *h*:
if *l* has set *trust(h) = true*,
then validators that are correct until time *h.Header.bfttime + tp* have more than two thirds of the voting power in *h.Header.NextV*.
Formally,
\[
\sum_{(v,p) \in h.Header.NextV \wedge correct(v,h.Header.bfttime + tp)} p >
2/3 \sum_{(v,p) \in h.Header.NextV} p
\]
*Remark.* To prove the invariant, we will have to prove that the lite client only trusts headers that were correctly generated by Tendermint consensus, then the formula above follows from the Tendermint failure model.
## High Level Solution
Upon initialization, the lite client is given a header *inithead* it trusts (by
social consensus). It is assumed that *inithead* satisfies the lite client invariant. (If *inithead* has been correctly generated by Tendermint consensus, the invariant follows from the Tendermint Failure Model.)
When a lite clients sees a signed new header *snh*, it has to decide whether to trust the new
header. Trust can be obtained by (possibly) the combination of three methods.
1. **Uninterrupted sequence of proof.** If a block is appended to the chain, where the last block
is trusted (and properly committed by the old validator set in the next block),
and the new block contains a new validator set, the new block is trusted if the lite client knows all headers in the prefix.
Intuitively, a trusted validator set is assumed to only chose a new validator set that will obey the Tendermint Failure Model.
2. **Trusting period.** Based on a trusted block *h*, and the lite client
invariant, which ensures the fault assumption during the trusting period, we can check whether at least one validator, that has been continuously correct from *h.Header.bfttime* until now, has signed *snh*.
If this is the case, similarly to above, the chosen validator set in *snh* does not violate the Tendermint Failure Model.
3. **Bisection.** If a check according to the trusting period fails, the lite client can try to obtain a header *hp* whose height lies between *h* and *snh* in order to check whether *h* can be used to get trust for *hp*, and *hp* can be used to get trust for *snh*. If this is the case we can trust *snh*; if not, we may continue recursively.
## How to use it
We consider the following use case:
the lite client wants to verify a header for some given height *k*. Thus:
- it requests the signed header for height *k* from a full node
- it tries to verify this header with the methods described here.
This can be used in several settings:
- someone tells the lite client that application data that is relevant for it can be read in the block of height *k*.
- the lite clients wants the latest state. It asks a full nude for the current height, and uses the response for *k*.
## Details
*Assumptions*
1. *tp < unbonding period*.
2. *snh.Header.bfttime < now*
3. *snh.Header.bfttime < h.Header.bfttime+tp*
4. *trust(h)=true*
**Observation 1.** If *h.Header.bfttime + tp > now*, we trust the old
validator set *h.Header.NextV*.
When we say we trust *h.Header.NextV* we do *not* trust that each individual validator in *h.Header.NextV* is correct, but we only trust the fact that at most 1/3 of them are faulty (more precisely, the faulty ones have at most 1/3 of the total voting power).
### Functions
The function *Bisection* checks whether to trust header *h2* based on the trusted header *h1*. It does so by calling
the function *CheckSupport* in the process of
bisection/recursion. *CheckSupport* implements the trusted period method and, for two adjacent headers (in term of heights), it checks uninterrupted sequence of proof.
*Assumption*: In the following, we assume that *h2.Header.height > h1.Header.height*. We will quickly discuss the other case in the next section.
We consider the following set-up:
- the lite client communicates with one full node
- the lite client locally stores all the signed headers it obtained (trusted or not). In the pseudo code below we write *Store(header)* for this.
- If *Bisection* returns *false*, then the lite client has seen a forged header.
* However, it does not know which header(s) is/are the problematic one(s).
* In this case, the lite client can submit (some of) the headers it has seen as evidence. As the lite client communicates with one full node only when executing Bisection, there are two cases
- the full node is faulty
- the full node is correct and there was a fork in Tendermint consensus. Header *h1* is from a different branch than the one taken by the full node. This case is not focus of this document, but will be treated in the document on fork accountability.
- the lite client must retry to retrieve correct headers from another full node
* it picks a new full node
* it restarts *Bisection*
* there might be optimizations; a lite client may not need to call *Commit(k)*, for a height *k* for which it already has a signed header it trusts.
* how to make sure that a lite client can communicate with a correct full node will be the focus of a separate document (recall Issue 3 from "Context of this document").
**Auxiliary Functions.** We will use the function ```votingpower_in(V1,V2)``` to compute the voting power the validators in set V1 have according to their voting power in set V2;
we will write ```totalVotingPower(V)``` for ```votingpower_in(V,V)```, which returns the total voting power in V.
We further use the function ```signers(Commit)``` that returns the set of validators that signed the Commit.
**CheckSupport.** The following function checks whether we can trust the header h2 based on header h1 following the trusting period method.
```go
func CheckSupport(h1,h2,trustlevel) bool {
if h1.Header.bfttime + tp < now { // Observation 1
return false // old header was once trusted but it is expired
}
vp_all := totalVotingPower(h1.Header.NextV)
// total sum of voting power of validators in h2
if h2.Header.height == h1.Header.height + 1 {
// specific check for adjacent headers; everything must be
// properly signed.
// also check that h2.Header.V == h1.Header.NextV
// Plus the following check that 2/3 of the voting power
// in h1 signed h2
return (votingpower_in(signers(h2.Commit),h1.Header.NextV) >
2/3 * vp_all)
// signing validators are more than two third in h1.
}
return (votingpower_in(signers(h2.Commit),h1.Header.NextV) >
max(1/3,trustlevel) * vp_all)
// get validators in h1 that signed h2
// sum of voting powers in h1 of
// validators that signed h2
// is more than a third in h1
}
``` ```
The light client is initialised with the trusted validator set, for example based on the known validator set hash, *Remark*: Basic header verification must be done for *h2*. Similar checks are done in:
validator set sequence number and the validator set init time. https://github.com/tendermint/tendermint/blob/master/types/validator_set.go#L591-L633
The core of the light client logic is captured by the VerifyAndUpdate function that is used to 1) verify if the given header is valid,
and 2) update the validator set (when the given header is valid and it is more recent than the seen headers).
```golang *Remark*: There are some sanity checks which are not in the code:
VerifyAndUpdate(signedHeader SignedHeader): *h2.Header.height > h1.Header.height* and *h2.Header.bfttime > h1.Header.bfttime* and *h2.Header.bfttime < now*.
assertThat signedHeader.valSetNumber >= valSetNumber
if isValid(signedHeader) and signedHeader.Header.Time <= valSetTime + UNBONDING_PERIOD then *Remark*: ```return (votingpower_in(signers(h2.Commit),h1.Header.NextV) > max(1/3,trustlevel) * vp_all)``` may return false even if *h2* was properly generated by Tendermint consensus in the case of big changes in the validator sets. However, the check ```return (votingpower_in(signers(h2.Commit),h1.Header.NextV) >
setValidatorSet(signedHeader) 2/3 * vp_all)``` must return true if *h1* and *h2* were generated by Tendermint consensus.
*Remark*: The 1/3 check differs from a previously proposed method that was based on intersecting validator sets and checking that the new validator set contains "enough" correct validators. We found that the old check is not suited for realistic changes in the validator sets. The new method is not only based on cardinalities, but also exploits that we can trust what is signed by a correct validator (i.e., signed by more than 1/3 of the voting power).
*Correctness arguments*
Towards Lite Client Accuracy:
- Assume by contradiction that *h2* was not generated correctly and the lite client sets trust to true because *CheckSupport* returns true.
- h1 is trusted and sufficiently new
- by Tendermint Fault Model, less than 1/3 of voting power held by faulty validators => at least one correct validator *v* has signed *h2*.
- as *v* is correct up to now, it followed the Tendermint consensus protocol at least up to signing *h2* => *h2* was correctly generated, we arrive at the required contradiction.
Towards Lite Client Completeness:
- The check is successful if sufficiently many validators of *h1* are still validators in *h2* and signed *h2*.
- If *h2.Header.height = h1.Header.height + 1*, and both headers were generated correctly, the test passes
*Verification Condition:* We may need a Tendermint invariant stating that if *h2.Header.height = h1.Header.height + 1* then *signers(h2.Commit) \subseteq h1.Header.NextV*.
*Remark*: The variable *trustlevel* can be used if the user believes that relying on one correct validator is not sufficient. However, in case of (frequent) changes in the validator set, the higher the *trustlevel* is chosen, the more unlikely it becomes that CheckSupport returns true for non-adjacent headers.
**Bisection.** The following function uses CheckSupport in a recursion to find intermediate headers that allow to establish a sequence of trust.
```go
func Bisection(h1,h2,trustlevel) bool{
if CheckSupport(h1,h2,trustlevel) {
return true return true
else }
updateValidatorSet(signedHeader.ValSetNumber) if h2.Header.height == h1.Header.height + 1 {
return VerifyAndUpdate(signedHeader) // we have adjacent headers that are not matching (failed
// the CheckSupport)
isValid(signedHeader SignedHeader): // we could submit evidence here
valSetOfTheHeader = Validators(signedHeader.Header.Height)
assertThat Hash(valSetOfTheHeader) == signedHeader.Header.ValSetHash
assertThat signedHeader is passing basic validation
if votingPower(signedHeader.Commit) > 2/3 * votingPower(valSetOfTheHeader) then return true
else
return false return false
}
pivot := (h1.Header.height + h2.Header.height) / 2
hp := Commit(pivot)
// ask a full node for header of height pivot
Store(hp)
// store header hp locally
if Bisection(h1,hp,trustlevel) {
// only check right branch if hp is trusted
// (otherwise a lot of unnecessary computation may be done)
return Bisection(hp,h2,trustlevel)
}
else {
return false
}
}
```
setValidatorSet(signedHeader SignedHeader):
nextValSet = Validators(signedHeader.Header.Height)
assertThat Hash(nextValSet) == signedHeader.Header.ValidatorsHash
valSet = nextValSet.Validators
valSetHash = signedHeader.Header.ValidatorsHash
valSetNumber = signedHeader.ValSetNumber
valSetTime = nextValSet.ValSetTime
votingPower(commit Commit):
votingPower = 0
for each precommit in commit.Precommits do:
if precommit.ValidatorAddress is in valSet and signature of the precommit verifies then
votingPower += valSet[precommit.ValidatorAddress].VotingPower
return votingPower
votingPower(validatorSet []Validator):
for each validator in validatorSet do:
votingPower += validator.VotingPower
return votingPower
updateValidatorSet(valSetNumberOfTheHeader): *Correctness arguments (sketch)*
while valSetNumber != valSetNumberOfTheHeader do
signedHeader = LastHeader(valSetNumber) Lite Client Accuracy:
if isValid(signedHeader) then - Assume by contradiction that *h2* was not generated correctly and the lite client sets trust to true because Bisection returns true.
setValidatorSet(signedHeader) - Bisection returns true only if all calls to CheckSupport in the recursion return true.
else return error - Thus we have a sequence of headers that all satisfied the CheckSupport
return - again a contradiction
Lite Client Completeness:
This is only ensured if upon *Commit(pivot)* the lite client is always provided with a correctly generated header.
*Stalling*
With Bisection, a faulty full node could stall a lite client by creating a long sequence of headers that are queried one-by-one by the lite client and look OK, before the lite client eventually detects a problem. There are several ways to address this:
* Each call to ```Commit``` could be issued to a different full node
* Instead of querying header by header, the lite client tells a full node which header it trusts, and the height of the header it needs. The full node responds with the header along with a proof consisting of intermediate headers that the light client can use to verify. Roughly, Bisection would then be executed at the full node.
* We may set a timeout how long bisection may take.
### The case *h2.Header.height < h1.Header.height*
In the use case where someone tells the lite client that application data that is relevant for it can be read in the block of height *k* and the lite client trusts a more recent header, we can use the hashes to verify headers "down the chain." That is, we iterate down the heights and check the hashes in each step.
*Remark.* For the case were the lite client trusts two headers *i* and *j* with *i < k < j*, we should discuss/experiment whether the forward or the backward method is more effective.
```go
func Backwards(h1,h2) bool {
assert (h2.Header.height < h1.Header.height)
old := h1
for i := h1.Header.height - 1; i > h2.Header.height; i-- {
new := Commit(i)
Store(new)
if (hash(new) != old.Header.hash) {
return false
}
old := new
}
return (hash(h2) == old.Header.hash)
}
``` ```
Note that in the logic above we assume that the light client will always go upward with respect to header verifications,
i.e., that it will always be used to verify more recent headers. In case a light client needs to be used to verify older
headers (go backward) the same mechanisms and similar logic can be used. In case a call to the FullNode or subsequent
checks fail, a light client need to implement some recovery strategy, for example connecting to other FullNode.

View File

@ -1,6 +1,6 @@
swagger: "2.0" swagger: "2.0"
info: info:
version: "0.32.1" version: "Master"
title: RPC client for Tendermint title: RPC client for Tendermint
description: A REST interface for state queries, transaction generation and broadcasting. description: A REST interface for state queries, transaction generation and broadcasting.
license: license:
@ -37,12 +37,12 @@ paths:
If you haven't received anything after a couple of blocks, resend it. If the If you haven't received anything after a couple of blocks, resend it. If the
same happens again, send it to some other node. A few reasons why it could same happens again, send it to some other node. A few reasons why it could
happen: happen:
1. malicious node can drop or pretend it had committed your tx 1. malicious node can drop or pretend it had committed your tx
2. malicious proposer (not necessary the one you're communicating with) can 2. malicious proposer (not necessary the one you're communicating with) can
drop transactions, which might become valid in the future drop transactions, which might become valid in the future
(https://github.com/tendermint/tendermint/issues/3322) (https://github.com/tendermint/tendermint/issues/3322)
Please refer to Please refer to
https://tendermint.com/docs/tendermint-core/using-tendermint.html#formatting https://tendermint.com/docs/tendermint-core/using-tendermint.html#formatting
@ -60,11 +60,11 @@ paths:
200: 200:
description: empty answer description: empty answer
schema: schema:
$ref: '#/definitions/BroadcastTxResponse' $ref: "#/definitions/BroadcastTxResponse"
500: 500:
description: empty error description: empty error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/broadcast_tx_async: /broadcast_tx_async:
get: get:
summary: Returns right away, with no response. Does not wait for CheckTx nor DeliverTx results. summary: Returns right away, with no response. Does not wait for CheckTx nor DeliverTx results.
@ -101,11 +101,11 @@ paths:
200: 200:
description: empty answer description: empty answer
schema: schema:
$ref: '#/definitions/BroadcastTxResponse' $ref: "#/definitions/BroadcastTxResponse"
500: 500:
description: empty error description: empty error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/broadcast_tx_commit: /broadcast_tx_commit:
get: get:
summary: Returns with the responses from CheckTx and DeliverTx. summary: Returns with the responses from CheckTx and DeliverTx.
@ -140,11 +140,11 @@ paths:
200: 200:
description: empty answer description: empty answer
schema: schema:
$ref: '#/definitions/BroadcastTxCommitResponse' $ref: "#/definitions/BroadcastTxCommitResponse"
500: 500:
description: empty error description: empty error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/subscribe: /subscribe:
get: get:
summary: Subscribe for events via WebSocket. summary: Subscribe for events via WebSocket.
@ -285,11 +285,11 @@ paths:
200: 200:
description: empty answer description: empty answer
schema: schema:
$ref: '#/definitions/EmptyResponse' $ref: "#/definitions/EmptyResponse"
500: 500:
description: empty error description: empty error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/unsubscribe: /unsubscribe:
get: get:
summary: Unsubscribe from event on Websocket summary: Unsubscribe from event on Websocket
@ -297,19 +297,19 @@ paths:
- Websocket - Websocket
operationId: unsubscribe operationId: unsubscribe
description: | description: |
```go ```go
client := client.NewHTTP("tcp:0.0.0.0:26657", "/websocket") client := client.NewHTTP("tcp:0.0.0.0:26657", "/websocket")
err := client.Start() err := client.Start()
if err != nil { if err != nil {
handle error handle error
} }
defer client.Stop() defer client.Stop()
query := "tm.event = 'Tx' AND tx.height = 3" query := "tm.event = 'Tx' AND tx.height = 3"
err = client.Unsubscribe(context.Background(), "test-client", query) err = client.Unsubscribe(context.Background(), "test-client", query)
if err != nil { if err != nil {
handle error handle error
} }
``` ```
parameters: parameters:
- in: query - in: query
name: query name: query
@ -328,11 +328,11 @@ paths:
200: 200:
description: empty answer description: empty answer
schema: schema:
$ref: '#/definitions/EmptyResponse' $ref: "#/definitions/EmptyResponse"
500: 500:
description: empty error description: empty error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/unsubscribe_all: /unsubscribe_all:
get: get:
summary: Unsubscribe from all events via WebSocket summary: Unsubscribe from all events via WebSocket
@ -347,11 +347,11 @@ paths:
200: 200:
description: empty answer description: empty answer
schema: schema:
$ref: '#/definitions/EmptyResponse' $ref: "#/definitions/EmptyResponse"
500: 500:
description: empty error description: empty error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/health: /health:
get: get:
summary: Node heartbeat summary: Node heartbeat
@ -366,11 +366,11 @@ paths:
200: 200:
description: empty answer description: empty answer
schema: schema:
$ref: '#/definitions/EmptyResponse' $ref: "#/definitions/EmptyResponse"
500: 500:
description: empty error description: empty error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/status: /status:
get: get:
summary: Node Status summary: Node Status
@ -385,11 +385,11 @@ paths:
200: 200:
description: Status of the node description: Status of the node
schema: schema:
$ref: '#/definitions/StatusResponse' $ref: "#/definitions/StatusResponse"
500: 500:
description: empty error description: empty error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/net_info: /net_info:
get: get:
summary: Network informations summary: Network informations
@ -404,11 +404,11 @@ paths:
200: 200:
description: empty answer description: empty answer
schema: schema:
$ref: '#/definitions/NetInfoResponse' $ref: "#/definitions/NetInfoResponse"
500: 500:
description: empty error description: empty error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/blockchain: /blockchain:
get: get:
summary: Get block headers for minHeight <= height <= maxHeight. summary: Get block headers for minHeight <= height <= maxHeight.
@ -434,11 +434,11 @@ paths:
200: 200:
description: Block headers, returned in descending order (highest first). description: Block headers, returned in descending order (highest first).
schema: schema:
$ref: '#/definitions/BlockchainResponse' $ref: "#/definitions/BlockchainResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/block: /block:
get: get:
summary: Get block at a specified height summary: Get block at a specified height
@ -460,11 +460,11 @@ paths:
200: 200:
description: Block informations. description: Block informations.
schema: schema:
$ref: '#/definitions/BlockResponse' $ref: "#/definitions/BlockResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/block_results: /block_results:
get: get:
summary: Get block results at a specified height summary: Get block results at a specified height
@ -486,11 +486,11 @@ paths:
200: 200:
description: Block results. description: Block results.
schema: schema:
$ref: '#/definitions/BlockResultsResponse' $ref: "#/definitions/BlockResultsResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/commit: /commit:
get: get:
summary: Get commit results at a specified height summary: Get commit results at a specified height
@ -512,11 +512,11 @@ paths:
200: 200:
description: Commit results. description: Commit results.
schema: schema:
$ref: '#/definitions/CommitResponse' $ref: "#/definitions/CommitResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/validators: /validators:
get: get:
summary: Get validator set at a specified height summary: Get validator set at a specified height
@ -538,11 +538,11 @@ paths:
200: 200:
description: Commit results. description: Commit results.
schema: schema:
$ref: '#/definitions/ValidatorsResponse' $ref: "#/definitions/ValidatorsResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/genesis: /genesis:
get: get:
summary: Get Genesis summary: Get Genesis
@ -557,11 +557,11 @@ paths:
200: 200:
description: Genesis results. description: Genesis results.
schema: schema:
$ref: '#/definitions/GenesisResponse' $ref: "#/definitions/GenesisResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/dump_consensus_state: /dump_consensus_state:
get: get:
summary: Get consensus state summary: Get consensus state
@ -576,11 +576,11 @@ paths:
200: 200:
description: consensus state results. description: consensus state results.
schema: schema:
$ref: '#/definitions/DumpConsensusResponse' $ref: "#/definitions/DumpConsensusResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/consensus_state: /consensus_state:
get: get:
summary: Get consensus state summary: Get consensus state
@ -595,11 +595,11 @@ paths:
200: 200:
description: consensus state results. description: consensus state results.
schema: schema:
$ref: '#/definitions/ConsensusStateResponse' $ref: "#/definitions/ConsensusStateResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/consensus_params: /consensus_params:
get: get:
summary: Get consensus parameters summary: Get consensus parameters
@ -621,11 +621,11 @@ paths:
200: 200:
description: consensus parameters results. description: consensus parameters results.
schema: schema:
$ref: '#/definitions/ConsensusParamsResponse' $ref: "#/definitions/ConsensusParamsResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/unconfirmed_txs: /unconfirmed_txs:
get: get:
summary: Get the list of unconfirmed transactions summary: Get the list of unconfirmed transactions
@ -646,11 +646,11 @@ paths:
200: 200:
description: List of unconfirmed transactions description: List of unconfirmed transactions
schema: schema:
$ref: '#/definitions/UnconfirmedTransactionsResponse' $ref: "#/definitions/UnconfirmedTransactionsResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/num_unconfirmed_txs: /num_unconfirmed_txs:
get: get:
summary: Get data about unconfirmed transactions summary: Get data about unconfirmed transactions
@ -665,11 +665,11 @@ paths:
200: 200:
description: status about unconfirmed transactions description: status about unconfirmed transactions
schema: schema:
$ref: '#/definitions/NumUnconfirmedTransactionsResponse' $ref: "#/definitions/NumUnconfirmedTransactionsResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/tx_search: /tx_search:
get: get:
summary: Search for transactions summary: Search for transactions
@ -712,11 +712,11 @@ paths:
200: 200:
description: List of unconfirmed transactions description: List of unconfirmed transactions
schema: schema:
$ref: '#/definitions/TxSearchResponse' $ref: "#/definitions/TxSearchResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/tx: /tx:
get: get:
summary: Get transactions by hash summary: Get transactions by hash
@ -745,11 +745,11 @@ paths:
200: 200:
description: Get a transaction description: Get a transaction
schema: schema:
$ref: '#/definitions/TxResponse' $ref: "#/definitions/TxResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/abci_info: /abci_info:
get: get:
summary: Get some info about the application. summary: Get some info about the application.
@ -764,11 +764,11 @@ paths:
200: 200:
description: Get some info about the application. description: Get some info about the application.
schema: schema:
$ref: '#/definitions/ABCIInfoResponse' $ref: "#/definitions/ABCIInfoResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/abci_query: /abci_query:
get: get:
summary: Query the application for some information. summary: Query the application for some information.
@ -810,11 +810,11 @@ paths:
200: 200:
description: Response of the submitted query description: Response of the submitted query
schema: schema:
$ref: '#/definitions/ABCIQueryResponse' $ref: "#/definitions/ABCIQueryResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
/broadcast_evidence: /broadcast_evidence:
get: get:
@ -837,12 +837,11 @@ paths:
200: 200:
description: Broadcast evidence of the misbehavior. description: Broadcast evidence of the misbehavior.
schema: schema:
$ref: '#/definitions/BroadcastEvidenceResponse' $ref: "#/definitions/BroadcastEvidenceResponse"
500: 500:
description: Error description: Error
schema: schema:
$ref: '#/definitions/ErrorResponse' $ref: "#/definitions/ErrorResponse"
definitions: definitions:
JSONRPC: JSONRPC:
@ -857,7 +856,7 @@ definitions:
EmptyResponse: EmptyResponse:
description: Empty Response description: Empty Response
allOf: allOf:
- $ref: '#/definitions/JSONRPC' - $ref: "#/definitions/JSONRPC"
- type: object - type: object
properties: properties:
result: result:
@ -866,7 +865,7 @@ definitions:
ErrorResponse: ErrorResponse:
description: Error Response description: Error Response
allOf: allOf:
- $ref: '#/definitions/JSONRPC' - $ref: "#/definitions/JSONRPC"
- type: object - type: object
properties: properties:
error: error:
@ -897,7 +896,7 @@ definitions:
type: object type: object
properties: properties:
protocol_version: protocol_version:
$ref: '#/definitions/ProtocolVersion' $ref: "#/definitions/ProtocolVersion"
id: id:
type: string type: string
x-example: "5576458aef205977e18fd50b274e9b5d9014525a" x-example: "5576458aef205977e18fd50b274e9b5d9014525a"
@ -951,7 +950,7 @@ definitions:
type: string type: string
x-example: "5D6A51A8E9899C44079C6AF90618BA0369070E6E" x-example: "5D6A51A8E9899C44079C6AF90618BA0369070E6E"
pub_key: pub_key:
$ref: '#/definitions/PubKey' $ref: "#/definitions/PubKey"
voting_power: voting_power:
type: string type: string
x-example: "0" x-example: "0"
@ -960,19 +959,19 @@ definitions:
type: object type: object
properties: properties:
node_info: node_info:
$ref: '#/definitions/NodeInfo' $ref: "#/definitions/NodeInfo"
sync_info: sync_info:
$ref: '#/definitions/SyncInfo' $ref: "#/definitions/SyncInfo"
validator_info: validator_info:
$ref: '#/definitions/ValidatorInfo' $ref: "#/definitions/ValidatorInfo"
StatusResponse: StatusResponse:
description: Status Response description: Status Response
allOf: allOf:
- $ref: '#/definitions/JSONRPC' - $ref: "#/definitions/JSONRPC"
- type: object - type: object
properties: properties:
result: result:
$ref: '#/definitions/Status' $ref: "#/definitions/Status"
Monitor: Monitor:
type: object type: object
properties: properties:
@ -1040,23 +1039,23 @@ definitions:
type: string type: string
x-example: "168901057956119" x-example: "168901057956119"
SendMonitor: SendMonitor:
$ref: '#/definitions/Monitor' $ref: "#/definitions/Monitor"
RecvMonitor: RecvMonitor:
$ref: '#/definitions/Monitor' $ref: "#/definitions/Monitor"
Channels: Channels:
type: array type: array
items: items:
$ref: '#/definitions/Channel' $ref: "#/definitions/Channel"
Peer: Peer:
type: object type: object
properties: properties:
node_info: node_info:
$ref: '#/definitions/NodeInfo' $ref: "#/definitions/NodeInfo"
is_outbound: is_outbound:
type: boolean type: boolean
x-example: true x-example: true
connection_status: connection_status:
$ref: '#/definitions/ConnectionStatus' $ref: "#/definitions/ConnectionStatus"
remote_ip: remote_ip:
type: string type: string
x-example: "95.179.155.35" x-example: "95.179.155.35"
@ -1077,15 +1076,15 @@ definitions:
peers: peers:
type: array type: array
items: items:
$ref: '#/definitions/Peer' $ref: "#/definitions/Peer"
NetInfoResponse: NetInfoResponse:
description: NetInfo Response description: NetInfo Response
allOf: allOf:
- $ref: '#/definitions/JSONRPC' - $ref: "#/definitions/JSONRPC"
- type: object - type: object
properties: properties:
result: result:
$ref: '#/definitions/NetInfo' $ref: "#/definitions/NetInfo"
BlockID: BlockID:
required: required:
- "hash" - "hash"
@ -1154,7 +1153,7 @@ definitions:
type: string type: string
x-example: "3" x-example: "3"
last_block_id: last_block_id:
$ref: '#/definitions/BlockID' $ref: "#/definitions/BlockID"
last_commit_hash: last_commit_hash:
type: string type: string
x-example: "21B9BC845AD2CB2C4193CDD17BFC506F1EBE5A7402E84AD96E64171287A34812" x-example: "21B9BC845AD2CB2C4193CDD17BFC506F1EBE5A7402E84AD96E64171287A34812"
@ -1208,9 +1207,9 @@ definitions:
type: object type: object
properties: properties:
block_id: block_id:
$ref: '#/definitions/BlockMetaId' $ref: "#/definitions/BlockMetaId"
header: header:
$ref: '#/definitions/BlockMetaHeader' $ref: "#/definitions/BlockMetaHeader"
Blockchain: Blockchain:
type: object type: object
required: required:
@ -1223,15 +1222,15 @@ definitions:
block_metas: block_metas:
type: "array" type: "array"
items: items:
$ref: '#/definitions/BlockMeta' $ref: "#/definitions/BlockMeta"
BlockchainResponse: BlockchainResponse:
description: Blockchain info description: Blockchain info
allOf: allOf:
- $ref: '#/definitions/JSONRPC' - $ref: "#/definitions/JSONRPC"
- type: object - type: object
properties: properties:
result: result:
$ref: '#/definitions/Blockchain' $ref: "#/definitions/Blockchain"
Commit: Commit:
required: required:
- "type" - "type"
@ -1253,7 +1252,7 @@ definitions:
type: string type: string
x-example: "0" x-example: "0"
block_id: block_id:
$ref: '#/definitions/BlockID' $ref: "#/definitions/BlockID"
timestamp: timestamp:
type: string type: string
x-example: "2019-08-01T11:39:38.867269833Z" x-example: "2019-08-01T11:39:38.867269833Z"
@ -1270,30 +1269,30 @@ definitions:
type: object type: object
properties: properties:
header: header:
$ref: '#/definitions/BlockMetaHeader' $ref: "#/definitions/BlockMetaHeader"
data: data:
type: array type: array
items: items:
type: string type: string
x-example: 'yQHwYl3uCkKoo2GaChRnd+THLQ2RM87nEZrE19910Z28ABIUWW/t8AtIMwcyU0sT32RcMDI9GF0aEAoFdWF0b20SBzEwMDAwMDASEwoNCgV1YXRvbRIEMzEwMRCd8gEaagom61rphyEDoJPxlcjRoNDtZ9xMdvs+lRzFaHe2dl2P5R2yVCWrsHISQKkqX5H1zXAIJuC57yw0Yb03Fwy75VRip0ZBtLiYsUqkOsPUoQZAhDNP+6LY+RUwz/nVzedkF0S29NZ32QXdGv0=' x-example: "yQHwYl3uCkKoo2GaChRnd+THLQ2RM87nEZrE19910Z28ABIUWW/t8AtIMwcyU0sT32RcMDI9GF0aEAoFdWF0b20SBzEwMDAwMDASEwoNCgV1YXRvbRIEMzEwMRCd8gEaagom61rphyEDoJPxlcjRoNDtZ9xMdvs+lRzFaHe2dl2P5R2yVCWrsHISQKkqX5H1zXAIJuC57yw0Yb03Fwy75VRip0ZBtLiYsUqkOsPUoQZAhDNP+6LY+RUwz/nVzedkF0S29NZ32QXdGv0="
evidence: evidence:
type: array type: array
items: items:
$ref: '#/definitions/Evidence' $ref: "#/definitions/Evidence"
last_commit: last_commit:
type: object type: object
properties: properties:
block_id: block_id:
$ref: '#/definitions/BlockID' $ref: "#/definitions/BlockID"
precommits: precommits:
type: array type: array
items: items:
$ref: '#/definitions/Commit' $ref: "#/definitions/Commit"
Validator: Validator:
type: object type: object
properties: properties:
pub_key: pub_key:
$ref: '#/definitions/PubKey' $ref: "#/definitions/PubKey"
voting_power: voting_power:
type: number type: number
address: address:
@ -1310,31 +1309,31 @@ definitions:
total_voting_power: total_voting_power:
type: number type: number
validator: validator:
$ref: '#/definitions/Validator' $ref: "#/definitions/Validator"
BlockComplete: BlockComplete:
type: object type: object
properties: properties:
block_meta: block_meta:
$ref: '#/definitions/BlockMeta' $ref: "#/definitions/BlockMeta"
block: block:
$ref: '#/definitions/Block' $ref: "#/definitions/Block"
BlockResponse: BlockResponse:
description: Blockc info description: Blockc info
allOf: allOf:
- $ref: '#/definitions/JSONRPC' - $ref: "#/definitions/JSONRPC"
- type: object - type: object
properties: properties:
result: result:
$ref: '#/definitions/BlockComplete' $ref: "#/definitions/BlockComplete"
Tag: Tag:
type: object type: object
properties: properties:
key: key:
type: string type: string
example: 'YWN0aW9u' example: "YWN0aW9u"
value: value:
type: string type: string
example: 'c2VuZA==' example: "c2VuZA=="
################## FROM NOW ON NEEDS REFACTOR ################## ################## FROM NOW ON NEEDS REFACTOR ##################
BlockResultsResponse: BlockResultsResponse:
type: "object" type: "object"
@ -1371,7 +1370,7 @@ definitions:
properties: properties:
log: log:
type: "string" type: "string"
example: "[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]" example: '[{"msg_index":"0","success":true,"log":""}]'
gasWanted: gasWanted:
type: "string" type: "string"
example: "25629" example: "25629"
@ -2249,7 +2248,7 @@ definitions:
- "n_txs" - "n_txs"
- "total" - "total"
- "total_bytes" - "total_bytes"
# - "txs" # - "txs"
properties: properties:
n_txs: n_txs:
type: "string" type: "string"
@ -2260,14 +2259,14 @@ definitions:
total_bytes: total_bytes:
type: "string" type: "string"
example: "19974" example: "19974"
# txs: # txs:
# type: "array" # type: "array"
# x-nullable: true # x-nullable: true
# items: # items:
# type: "string" # type: "string"
# x-nullable: true # x-nullable: true
# example: # example:
# - "gAPwYl3uCjCMTXENChSMnIkb5ZpYHBKIZqecFEV2tuZr7xIUA75/FmYq9WymsOBJ0XSJ8yV8zmQKMIxNcQ0KFIyciRvlmlgcEohmp5wURXa25mvvEhQbrvwbvlNiT+Yjr86G+YQNx7kRVgowjE1xDQoUjJyJG+WaWBwSiGannBRFdrbma+8SFK2m+1oxgILuQLO55n8mWfnbIzyPCjCMTXENChSMnIkb5ZpYHBKIZqecFEV2tuZr7xIUQNGfkmhTNMis4j+dyMDIWXdIPiYKMIxNcQ0KFIyciRvlmlgcEohmp5wURXa25mvvEhS8sL0D0wwgGCItQwVowak5YB38KRIUCg4KBXVhdG9tEgUxMDA1NBDoxRgaagom61rphyECn8x7emhhKdRCB2io7aS/6Cpuq5NbVqbODmqOT3jWw6kSQKUresk+d+Gw0BhjiggTsu8+1voW+VlDCQ1GRYnMaFOHXhyFv7BCLhFWxLxHSAYT8a5XqoMayosZf9mANKdXArA=" # - "gAPwYl3uCjCMTXENChSMnIkb5ZpYHBKIZqecFEV2tuZr7xIUA75/FmYq9WymsOBJ0XSJ8yV8zmQKMIxNcQ0KFIyciRvlmlgcEohmp5wURXa25mvvEhQbrvwbvlNiT+Yjr86G+YQNx7kRVgowjE1xDQoUjJyJG+WaWBwSiGannBRFdrbma+8SFK2m+1oxgILuQLO55n8mWfnbIzyPCjCMTXENChSMnIkb5ZpYHBKIZqecFEV2tuZr7xIUQNGfkmhTNMis4j+dyMDIWXdIPiYKMIxNcQ0KFIyciRvlmlgcEohmp5wURXa25mvvEhS8sL0D0wwgGCItQwVowak5YB38KRIUCg4KBXVhdG9tEgUxMDA1NBDoxRgaagom61rphyECn8x7emhhKdRCB2io7aS/6Cpuq5NbVqbODmqOT3jWw6kSQKUresk+d+Gw0BhjiggTsu8+1voW+VlDCQ1GRYnMaFOHXhyFv7BCLhFWxLxHSAYT8a5XqoMayosZf9mANKdXArA="
type: "object" type: "object"
NumUnconfirmedTransactionsResponse: NumUnconfirmedTransactionsResponse:
type: object type: object
@ -2349,7 +2348,7 @@ definitions:
properties: properties:
log: log:
type: "string" type: "string"
example: "[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]" example: '[{"msg_index":"0","success":true,"log":""}]'
gasWanted: gasWanted:
type: "string" type: "string"
example: "200000" example: "200000"
@ -2450,7 +2449,7 @@ definitions:
properties: properties:
log: log:
type: "string" type: "string"
example: "[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]" example: '[{"msg_index":"0","success":true,"log":""}]'
gasWanted: gasWanted:
type: "string" type: "string"
example: "200000" example: "200000"
@ -2497,7 +2496,7 @@ definitions:
properties: properties:
data: data:
type: "string" type: "string"
example: "{\"size\":0}" example: '{"size":0}'
version: version:
type: string type: string
example: "0.16.1" example: "0.16.1"

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
VERSION=v11.15.0 VERSION=v12.9.0
NODE_FULL=node-${VERSION}-linux-x64 NODE_FULL=node-${VERSION}-linux-x64
mkdir -p ~/.local/bin mkdir -p ~/.local/bin
@ -10,5 +10,5 @@ tar -xzf ~/.local/node/${NODE_FULL}.tar.gz -C ~/.local/node/
ln -s ~/.local/node/${NODE_FULL}/bin/node ~/.local/bin/node ln -s ~/.local/node/${NODE_FULL}/bin/node ~/.local/bin/node
ln -s ~/.local/node/${NODE_FULL}/bin/npm ~/.local/bin/npm ln -s ~/.local/node/${NODE_FULL}/bin/npm ~/.local/bin/npm
export PATH=~/.local/bin:$PATH export PATH=~/.local/bin:$PATH
npm i -g dredd@11.0.1 npm i -g dredd
ln -s ~/.local/node/${NODE_FULL}/bin/dredd ~/.local/bin/dredd ln -s ~/.local/node/${NODE_FULL}/bin/dredd ~/.local/bin/dredd

View File

@ -20,7 +20,7 @@ const (
// Must be a string because scripts like dist.sh read this file. // Must be a string because scripts like dist.sh read this file.
// XXX: Don't change the name of this variable or you will break // XXX: Don't change the name of this variable or you will break
// automation :) // automation :)
TMCoreSemVer = "0.32.2" TMCoreSemVer = "0.32.3"
// ABCISemVer is the semantic version of the ABCI library // ABCISemVer is the semantic version of the ABCI library
ABCISemVer = "0.16.1" ABCISemVer = "0.16.1"