mirror of
https://github.com/tendermint/tendermint.git
synced 2025-12-23 14:25:19 +00:00
docs: cleanup (#5252)
This commit is contained in:
@@ -15,8 +15,6 @@ Make sure you [have Go installed](https://golang.org/doc/install).
|
||||
Next, install the `abci-cli` tool and example applications:
|
||||
|
||||
```sh
|
||||
mkdir -p $GOPATH/src/github.com/tendermint
|
||||
cd $GOPATH/src/github.com/tendermint
|
||||
git clone https://github.com/tendermint/tendermint.git
|
||||
cd tendermint
|
||||
make tools
|
||||
@@ -226,7 +224,7 @@ Like the kvstore app, its code can be found
|
||||
[here](https://github.com/tendermint/tendermint/blob/master/abci/cmd/abci-cli/abci-cli.go)
|
||||
and looks like:
|
||||
|
||||
```sh
|
||||
```go
|
||||
func cmdCounter(cmd *cobra.Command, args []string) error {
|
||||
|
||||
app := counter.NewCounterApplication(flagSerial)
|
||||
@@ -340,7 +338,7 @@ npm install abci
|
||||
|
||||
Now you can start the app:
|
||||
|
||||
```bash
|
||||
```sh
|
||||
node example/counter.js
|
||||
```
|
||||
|
||||
|
||||
@@ -18,10 +18,9 @@ ABCI application, which is the logic that actually runs on the blockchain.
|
||||
Transactions sent by an end-user application are ultimately processed by the ABCI
|
||||
application after being committed by the Tendermint consensus.
|
||||
|
||||
The end-user application in this diagram is the Cosmos Voyager, at the bottom
|
||||
left. Voyager communicates with a REST API exposed by a local Light-Client
|
||||
Daemon. The Light-Client Daemon is an application specific program that
|
||||
communicates with Tendermint nodes and verifies Tendermint light-client proofs
|
||||
The end-user application in this diagram is the [Lunie](https://lunie.io/) app, located at the bottom
|
||||
left. Lunie communicates with a REST API exposed by the application.
|
||||
The application with Tendermint nodes and verifies Tendermint light-client proofs
|
||||
through the Tendermint Core RPC. The Tendermint Core process communicates with
|
||||
a local ABCI application, where the user query or transaction is actually
|
||||
processed.
|
||||
|
||||
@@ -1,507 +0,0 @@
|
||||
---
|
||||
order: 4
|
||||
---
|
||||
|
||||
# Application Development Guide
|
||||
|
||||
## XXX
|
||||
|
||||
This page is undergoing deprecation. All content is being moved to the new [home
|
||||
of the ABCI specification](https://github.com/tendermint/spec/tree/master/spec/abci).
|
||||
|
||||
## ABCI Design
|
||||
|
||||
The purpose of ABCI is to provide a clean interface between state
|
||||
transition machines on one computer and the mechanics of their
|
||||
replication across multiple computers. The former we call 'application
|
||||
logic' and the latter the 'consensus engine'. Application logic
|
||||
validates transactions and optionally executes transactions against some
|
||||
persistent state. A consensus engine ensures all transactions are
|
||||
replicated in the same order on every machine. We call each machine in a
|
||||
consensus engine a 'validator', and each validator runs the same
|
||||
transactions through the same application logic. In particular, we are
|
||||
interested in blockchain-style consensus engines, where transactions are
|
||||
committed in hash-linked blocks.
|
||||
|
||||
The ABCI design has a few distinct components:
|
||||
|
||||
- message protocol
|
||||
- pairs of request and response messages
|
||||
- consensus makes requests, application responds
|
||||
- defined using protobuf
|
||||
- server/client
|
||||
- consensus engine runs the client
|
||||
- application runs the server
|
||||
- two implementations:
|
||||
- async raw bytes
|
||||
- grpc
|
||||
- blockchain protocol
|
||||
- abci is connection oriented
|
||||
- Tendermint Core maintains three connections:
|
||||
- [mempool connection](#mempool-connection): for checking if
|
||||
transactions should be relayed before they are committed;
|
||||
only uses `CheckTx`
|
||||
- [consensus connection](#consensus-connection): for executing
|
||||
transactions that have been committed. Message sequence is
|
||||
-for every block -`BeginBlock, [DeliverTx, ...], EndBlock, Commit`
|
||||
- [query connection](#query-connection): for querying the
|
||||
application state; only uses Query and Info
|
||||
|
||||
The mempool and consensus logic act as clients, and each maintains an
|
||||
open ABCI connection with the application, which hosts an ABCI server.
|
||||
Shown are the request and response types sent on each connection.
|
||||
|
||||
Most of the examples below are from [kvstore
|
||||
application](https://github.com/tendermint/tendermint/blob/master/abci/example/kvstore/kvstore.go),
|
||||
which is a part of the abci repo. [persistent_kvstore
|
||||
application](https://github.com/tendermint/tendermint/blob/master/abci/example/kvstore/persistent_kvstore.go)
|
||||
is used to show `BeginBlock`, `EndBlock` and `InitChain` example
|
||||
implementations.
|
||||
|
||||
## Blockchain Protocol
|
||||
|
||||
In ABCI, a transaction is simply an arbitrary length byte-array. It is
|
||||
the application's responsibility to define the transaction codec as they
|
||||
please, and to use it for both CheckTx and DeliverTx.
|
||||
|
||||
Note that there are two distinct means for running transactions,
|
||||
corresponding to stages of 'awareness' of the transaction in the
|
||||
network. The first stage is when a transaction is received by a
|
||||
validator from a client into the so-called mempool or transaction pool
|
||||
-this is where we use CheckTx. The second is when the transaction is
|
||||
successfully committed on more than 2/3 of validators - where we use
|
||||
DeliverTx. In the former case, it may not be necessary to run all the
|
||||
state transitions associated with the transaction, as the transaction
|
||||
may not ultimately be committed until some much later time, when the
|
||||
result of its execution will be different. For instance, an Ethereum
|
||||
ABCI app would check signatures and amounts in CheckTx, but would not
|
||||
actually execute any contract code until the DeliverTx, so as to avoid
|
||||
executing state transitions that have not been finalized.
|
||||
|
||||
To formalize the distinction further, two explicit ABCI connections are
|
||||
made between Tendermint Core and the application: the mempool connection
|
||||
and the consensus connection. We also make a third connection, the query
|
||||
connection, to query the local state of the app.
|
||||
|
||||
### Mempool Connection
|
||||
|
||||
The mempool connection is used _only_ for CheckTx requests. Transactions
|
||||
are run using CheckTx in the same order they were received by the
|
||||
validator. If the CheckTx returns `OK`, the transaction is kept in
|
||||
memory and relayed to other peers in the same order it was received.
|
||||
Otherwise, it is discarded.
|
||||
|
||||
CheckTx requests run concurrently with block processing; so they should
|
||||
run against a copy of the main application state which is reset after
|
||||
every block. This copy is necessary to track transitions made by a
|
||||
sequence of CheckTx requests before they are included in a block. When a
|
||||
block is committed, the application must ensure to reset the mempool
|
||||
state to the latest committed state. Tendermint Core will then filter
|
||||
through all transactions in the mempool, removing any that were included
|
||||
in the block, and re-run the rest using CheckTx against the post-Commit
|
||||
mempool state (this behaviour can be turned off with
|
||||
`[mempool] recheck = false`).
|
||||
|
||||
In go:
|
||||
|
||||
```go
|
||||
func (app *KVStoreApplication) CheckTx(req types.RequestCheckTx) types.ResponseCheckTx {
|
||||
return types.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1}
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```java
|
||||
ResponseCheckTx requestCheckTx(RequestCheckTx req) {
|
||||
byte[] transaction = req.getTx().toByteArray();
|
||||
|
||||
// validate transaction
|
||||
|
||||
if (notValid) {
|
||||
return ResponseCheckTx.newBuilder().setCode(CodeType.BadNonce).setLog("invalid tx").build();
|
||||
} else {
|
||||
return ResponseCheckTx.newBuilder().setCode(CodeType.OK).build();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Replay Protection
|
||||
|
||||
To prevent old transactions from being replayed, CheckTx must implement
|
||||
replay protection.
|
||||
|
||||
Tendermint provides the first defence layer by keeping a lightweight
|
||||
in-memory cache of 100k (`[mempool] cache_size`) last transactions in
|
||||
the mempool. If Tendermint is just started or the clients sent more than
|
||||
100k transactions, old transactions may be sent to the application. So
|
||||
it is important CheckTx implements some logic to handle them.
|
||||
|
||||
If there are cases in your application where a transaction may become invalid in some
|
||||
future state, you probably want to disable Tendermint's
|
||||
cache. You can do that by setting `[mempool] cache_size = 0` in the
|
||||
config.
|
||||
|
||||
### Consensus Connection
|
||||
|
||||
The consensus connection is used only when a new block is committed, and
|
||||
communicates all information from the block in a series of requests:
|
||||
`BeginBlock, [DeliverTx, ...], EndBlock, Commit`. That is, when a block
|
||||
is committed in the consensus, we send a list of DeliverTx requests (one
|
||||
for each transaction) sandwiched by BeginBlock and EndBlock requests,
|
||||
and followed by a Commit.
|
||||
|
||||
### DeliverTx
|
||||
|
||||
DeliverTx is the workhorse of the blockchain. Tendermint sends the
|
||||
DeliverTx requests asynchronously but in order, and relies on the
|
||||
underlying socket protocol (ie. TCP) to ensure they are received by the
|
||||
app in order. They have already been ordered in the global consensus by
|
||||
the Tendermint protocol.
|
||||
|
||||
DeliverTx returns a abci.Result, which includes a Code, Data, and Log.
|
||||
The code may be non-zero (non-OK), meaning the corresponding transaction
|
||||
should have been rejected by the mempool, but may have been included in
|
||||
a block by a Byzantine proposer.
|
||||
|
||||
The block header will be updated (TODO) to include some commitment to
|
||||
the results of DeliverTx, be it a bitarray of non-OK transactions, or a
|
||||
merkle root of the data returned by the DeliverTx requests, or both.
|
||||
|
||||
In go:
|
||||
|
||||
```go
|
||||
// tx is either "key=value" or just arbitrary bytes
|
||||
func (app *KVStoreApplication) DeliverTx(req types.RequestDeliverTx) types.ResponseDeliverTx {
|
||||
var key, value []byte
|
||||
parts := bytes.Split(req.Tx, []byte("="))
|
||||
if len(parts) == 2 {
|
||||
key, value = parts[0], parts[1]
|
||||
} else {
|
||||
key, value = req.Tx, req.Tx
|
||||
}
|
||||
|
||||
app.state.db.Set(prefixKey(key), value)
|
||||
app.state.Size += 1
|
||||
|
||||
events := []types.Event{
|
||||
{
|
||||
Type: "app",
|
||||
Attributes: []kv.Pair{
|
||||
{Key: []byte("creator"), Value: []byte("Cosmoshi Netowoko")},
|
||||
{Key: []byte("key"), Value: key},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return types.ResponseDeliverTx{Code: code.CodeTypeOK, Events: events}
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```java
|
||||
/**
|
||||
* Using Protobuf types from the protoc compiler, we always start with a byte[]
|
||||
*/
|
||||
ResponseDeliverTx deliverTx(RequestDeliverTx request) {
|
||||
byte[] transaction = request.getTx().toByteArray();
|
||||
|
||||
// validate your transaction
|
||||
|
||||
if (notValid) {
|
||||
return ResponseDeliverTx.newBuilder().setCode(CodeType.BadNonce).setLog("transaction was invalid").build();
|
||||
} else {
|
||||
ResponseDeliverTx.newBuilder().setCode(CodeType.OK).build();
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Commit
|
||||
|
||||
Once all processing of the block is complete, Tendermint sends the
|
||||
Commit request and blocks waiting for a response. While the mempool may
|
||||
run concurrently with block processing (the BeginBlock, DeliverTxs, and
|
||||
EndBlock), it is locked for the Commit request so that its state can be
|
||||
safely updated during Commit. This means the app _MUST NOT_ do any
|
||||
blocking communication with the mempool (ie. broadcast_tx) during
|
||||
Commit, or there will be deadlock. Note also that all remaining
|
||||
transactions in the mempool are replayed on the mempool connection
|
||||
(CheckTx) following a commit.
|
||||
|
||||
The app should respond to the Commit request with a byte array, which is
|
||||
the deterministic state root of the application. It is included in the
|
||||
header of the next block. It can be used to provide easily verified
|
||||
Merkle-proofs of the state of the application.
|
||||
|
||||
It is expected that the app will persist state to disk on Commit. The
|
||||
option to have all transactions replayed from some previous block is the
|
||||
job of the [Handshake](#handshake).
|
||||
|
||||
In go:
|
||||
|
||||
```go
|
||||
func (app *KVStoreApplication) Commit() types.ResponseCommit {
|
||||
// Using a memdb - just return the big endian size of the db
|
||||
appHash := make([]byte, 8)
|
||||
binary.PutVarint(appHash, app.state.Size)
|
||||
app.state.AppHash = appHash
|
||||
app.state.Height += 1
|
||||
saveState(app.state)
|
||||
return types.ResponseCommit{Data: appHash}
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```java
|
||||
ResponseCommit requestCommit(RequestCommit requestCommit) {
|
||||
|
||||
// update the internal app-state
|
||||
byte[] newAppState = calculateAppState();
|
||||
|
||||
// and return it to the node
|
||||
return ResponseCommit.newBuilder().setCode(CodeType.OK).setData(ByteString.copyFrom(newAppState)).build();
|
||||
}
|
||||
```
|
||||
|
||||
### BeginBlock
|
||||
|
||||
The BeginBlock request can be used to run some code at the beginning of
|
||||
every block. It also allows Tendermint to send the current block hash
|
||||
and header to the application, before it sends any of the transactions.
|
||||
|
||||
The app should remember the latest height and header (ie. from which it
|
||||
has run a successful Commit) so that it can tell Tendermint where to
|
||||
pick up from when it restarts. See information on the Handshake, below.
|
||||
|
||||
In go:
|
||||
|
||||
```go
|
||||
// Track the block hash and header information
|
||||
func (app *PersistentKVStoreApplication) BeginBlock(req types.RequestBeginBlock) types.ResponseBeginBlock {
|
||||
// reset valset changes
|
||||
app.ValUpdates = make([]types.ValidatorUpdate, 0)
|
||||
return types.ResponseBeginBlock{}
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```java
|
||||
/*
|
||||
* all types come from protobuf definition
|
||||
*/
|
||||
ResponseBeginBlock requestBeginBlock(RequestBeginBlock req) {
|
||||
|
||||
Header header = req.getHeader();
|
||||
byte[] prevAppHash = header.getAppHash().toByteArray();
|
||||
long prevHeight = header.getHeight();
|
||||
|
||||
// run your pre-block logic. Maybe prepare a state snapshot, message components, etc
|
||||
|
||||
return ResponseBeginBlock.newBuilder().build();
|
||||
}
|
||||
```
|
||||
|
||||
### EndBlock
|
||||
|
||||
The EndBlock request can be used to run some code at the end of every block.
|
||||
Additionally, the response may contain a list of validators, which can be used
|
||||
to update the validator set. To add a new validator or update an existing one,
|
||||
simply include them in the list returned in the EndBlock response. To remove
|
||||
one, include it in the list with a `power` equal to `0`. Validator's `address`
|
||||
field can be left empty. Tendermint core will take care of updating the
|
||||
validator set. Note the change in voting power must be strictly less than 1/3
|
||||
per block if you want a light client to be able to prove the transition
|
||||
externally. See the [light client
|
||||
docs](https://godoc.org/github.com/tendermint/tendermint/light#hdr-How_We_Track_Validators)
|
||||
for details on how it tracks validators.
|
||||
|
||||
In go:
|
||||
|
||||
```go
|
||||
// Update the validator set
|
||||
func (app *PersistentKVStoreApplication) EndBlock(req types.RequestEndBlock) types.ResponseEndBlock {
|
||||
return types.ResponseEndBlock{ValidatorUpdates: app.ValUpdates}
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```java
|
||||
/*
|
||||
* Assume that one validator changes. The new validator has a power of 10
|
||||
*/
|
||||
ResponseEndBlock requestEndBlock(RequestEndBlock req) {
|
||||
final long currentHeight = req.getHeight();
|
||||
final byte[] validatorPubKey = getValPubKey();
|
||||
|
||||
ResponseEndBlock.Builder builder = ResponseEndBlock.newBuilder();
|
||||
builder.addDiffs(1, Types.Validator.newBuilder().setPower(10L).setPubKey(ByteString.copyFrom(validatorPubKey)).build());
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
```
|
||||
|
||||
### Query Connection
|
||||
|
||||
This connection is used to query the application without engaging
|
||||
consensus. It's exposed over the tendermint core rpc, so clients can
|
||||
query the app without exposing a server on the app itself, but they must
|
||||
serialize each query as a single byte array. Additionally, certain
|
||||
"standardized" queries may be used to inform local decisions, for
|
||||
instance about which peers to connect to.
|
||||
|
||||
Tendermint Core currently uses the Query connection to filter peers upon
|
||||
connecting, according to IP address or node ID. For instance,
|
||||
returning non-OK ABCI response to either of the following queries will
|
||||
cause Tendermint to not connect to the corresponding peer:
|
||||
|
||||
- `p2p/filter/addr/<ip addr>`, where `<ip addr>` is an IP address.
|
||||
- `p2p/filter/id/<id>`, where `<is>` is the hex-encoded node ID (the hash of
|
||||
the node's p2p pubkey).
|
||||
|
||||
Note: these query formats are subject to change!
|
||||
|
||||
In go:
|
||||
|
||||
```go
|
||||
func (app *KVStoreApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
|
||||
if reqQuery.Prove {
|
||||
value := app.state.db.Get(prefixKey(reqQuery.Data))
|
||||
resQuery.Index = -1 // TODO make Proof return index
|
||||
resQuery.Key = reqQuery.Data
|
||||
resQuery.Value = value
|
||||
if value != nil {
|
||||
resQuery.Log = "exists"
|
||||
} else {
|
||||
resQuery.Log = "does not exist"
|
||||
}
|
||||
return
|
||||
} else {
|
||||
resQuery.Key = reqQuery.Data
|
||||
value := app.state.db.Get(prefixKey(reqQuery.Data))
|
||||
resQuery.Value = value
|
||||
if value != nil {
|
||||
resQuery.Log = "exists"
|
||||
} else {
|
||||
resQuery.Log = "does not exist"
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```java
|
||||
ResponseQuery requestQuery(RequestQuery req) {
|
||||
final boolean isProveQuery = req.getProve();
|
||||
final ResponseQuery.Builder responseBuilder = ResponseQuery.newBuilder();
|
||||
byte[] queryData = req.getData().toByteArray();
|
||||
|
||||
if (isProveQuery) {
|
||||
com.app.example.QueryResultWithProof result = generateQueryResultWithProof(queryData);
|
||||
responseBuilder.setIndex(result.getLeftIndex());
|
||||
responseBuilder.setKey(req.getData());
|
||||
responseBuilder.setValue(result.getValueOrNull(0));
|
||||
responseBuilder.setHeight(result.getHeight());
|
||||
responseBuilder.setProof(result.getProof());
|
||||
responseBuilder.setLog(result.getLogValue());
|
||||
} else {
|
||||
com.app.example.QueryResult result = generateQueryResult(queryData);
|
||||
responseBuilder.setIndex(result.getIndex());
|
||||
responseBuilder.setValue(result.getValue());
|
||||
responseBuilder.setLog(result.getLogValue());
|
||||
}
|
||||
|
||||
responseBuilder.setIndex(result.getIndex());
|
||||
responseBuilder.setValue(ByteString.copyFrom(result.getValue()));
|
||||
responseBuilder.setLog(result.getLogValue());
|
||||
}
|
||||
|
||||
return responseBuilder.build();
|
||||
}
|
||||
```
|
||||
|
||||
### Handshake
|
||||
|
||||
When the app or tendermint restarts, they need to sync to a common
|
||||
height. When an ABCI connection is first established, Tendermint will
|
||||
call `Info` on the Query connection. The response should contain the
|
||||
LastBlockHeight and LastBlockAppHash - the former is the last block for
|
||||
which the app ran Commit successfully, the latter is the response from
|
||||
that Commit.
|
||||
|
||||
Using this information, Tendermint will determine what needs to be
|
||||
replayed, if anything, against the app, to ensure both Tendermint and
|
||||
the app are synced to the latest block height.
|
||||
|
||||
If the app returns a LastBlockHeight of 0, Tendermint will just replay
|
||||
all blocks.
|
||||
|
||||
In go:
|
||||
|
||||
```go
|
||||
func (app *KVStoreApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
|
||||
return types.ResponseInfo{
|
||||
Data: fmt.Sprintf("{\"size\":%v}", app.state.Size),
|
||||
Version: version.ABCIVersion,
|
||||
AppVersion: ProtocolVersion.Uint64(),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```java
|
||||
ResponseInfo requestInfo(RequestInfo req) {
|
||||
final byte[] lastAppHash = getLastAppHash();
|
||||
final long lastHeight = getLastHeight();
|
||||
return ResponseInfo.newBuilder().setLastBlockAppHash(ByteString.copyFrom(lastAppHash)).setLastBlockHeight(lastHeight).build();
|
||||
}
|
||||
```
|
||||
|
||||
### Genesis
|
||||
|
||||
`InitChain` will be called once upon the genesis. `params` includes the
|
||||
initial validator set. Later on, it may be extended to take parts of the
|
||||
consensus params.
|
||||
|
||||
In go:
|
||||
|
||||
```go
|
||||
// Save the validators in the merkle tree
|
||||
func (app *PersistentKVStoreApplication) InitChain(req types.RequestInitChain) types.ResponseInitChain {
|
||||
for _, v := range req.Validators {
|
||||
r := app.updateValidator(v)
|
||||
if r.IsErr() {
|
||||
app.logger.Error("Error updating validators", "r", r)
|
||||
}
|
||||
}
|
||||
return types.ResponseInitChain{}
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```java
|
||||
/*
|
||||
* all types come from protobuf definition
|
||||
*/
|
||||
ResponseInitChain requestInitChain(RequestInitChain req) {
|
||||
final int validatorsCount = req.getValidatorsCount();
|
||||
final List<Types.Validator> validatorsList = req.getValidatorsList();
|
||||
|
||||
validatorsList.forEach((validator) -> {
|
||||
long power = validator.getPower();
|
||||
byte[] validatorPubKey = validator.getPubKey().toByteArray();
|
||||
|
||||
// do somehing for validator setup in app
|
||||
});
|
||||
|
||||
return ResponseInitChain.newBuilder().build();
|
||||
}
|
||||
```
|
||||
@@ -27,7 +27,6 @@ need to [install Go](https://golang.org/doc/install), put
|
||||
```bash
|
||||
echo export GOPATH=\"\$HOME/go\" >> ~/.bash_profile
|
||||
echo export PATH=\"\$PATH:\$GOPATH/bin\" >> ~/.bash_profile
|
||||
echo export GO111MODULE=on >> ~/.bash_profile
|
||||
```
|
||||
|
||||
Then run
|
||||
|
||||
@@ -46,8 +46,7 @@ indexer = "kv"
|
||||
```
|
||||
|
||||
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).
|
||||
hashes and height using an embedded simple indexer.
|
||||
|
||||
You can turn off indexing completely by setting `tx_index` to `null`.
|
||||
|
||||
@@ -81,7 +80,7 @@ func (app *KVStoreApplication) DeliverTx(req types.RequestDeliverTx) types.Resul
|
||||
|
||||
The transaction will be indexed (if the indexer is not `null`) with a certain
|
||||
attribute if the attribute's `Index` field is set to `true`. In the above
|
||||
example, all attributes will be used.
|
||||
example, all attributes will be indexed.
|
||||
|
||||
## Querying Transactions
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Tendermint Architectural Overview
|
||||
|
||||
|
||||
> **November 2019**
|
||||
|
||||
Over the next few weeks, @brapse, @marbar3778 and I (@tessr) are having a series of meetings to go over the architecture of Tendermint Core. These are my notes from these meetings, which will either serve as an artifact for onboarding future engineers; or will provide the basis for such a document.
|
||||
@@ -10,7 +11,8 @@ There are three forms of communication (e.g., requests, responses, connections)
|
||||
|
||||
- Internode communication: Happens between a node and other peers. This kind of communication happens over TCP or HTTP. More on this below.
|
||||
- Intranode communication: Happens within the node itself (i.e., between reactors or other components). These are typically function or method calls, or occasionally happen through an event bus.
|
||||
- Client communiation: Happens between a client (like a wallet or a browser) and a node on the network.
|
||||
|
||||
- Client communication: Happens between a client (like a wallet or a browser) and a node on the network.
|
||||
|
||||
### Internode Communication
|
||||
|
||||
@@ -22,7 +24,7 @@ Internode communication can happen in two ways:
|
||||
2. RPC over HTTP
|
||||
- Reserved for short-lived, one-off requests
|
||||
- Example: reactor-specific state, like height
|
||||
- Also possible: websocks connected to channels for notifications (like new transactions)
|
||||
- Also possible: web-sockets connected to channels for notifications (like new transactions)
|
||||
|
||||
### P2P Business (the Switch, the PEX, and the Address Book)
|
||||
|
||||
@@ -83,6 +85,7 @@ node.go is the entrypoint for running a node. It sets up reactors, sets up the s
|
||||
|
||||
## Types of Nodes
|
||||
|
||||
|
||||
1. Validator Node:
|
||||
2. Full Node:
|
||||
3. Seed Node:
|
||||
@@ -120,6 +123,7 @@ The following is an exhaustive (?) list of reactors:
|
||||
|
||||
Each of these will be discussed in more detail later.
|
||||
|
||||
|
||||
### Blockchain Reactor
|
||||
|
||||
The blockchain reactor has two responsibilities:
|
||||
|
||||
@@ -13,10 +13,9 @@ To download pre-built binaries, see the [releases page](https://github.com/tende
|
||||
You'll need `go` [installed](https://golang.org/doc/install) and the required
|
||||
environment variables set, which can be done with the following commands:
|
||||
|
||||
```bash
|
||||
```sh
|
||||
echo export GOPATH=\"\$HOME/go\" >> ~/.bash_profile
|
||||
echo export PATH=\"\$PATH:\$GOPATH/bin\" >> ~/.bash_profile
|
||||
echo export GO111MODULE=on >> ~/.bash_profile
|
||||
```
|
||||
|
||||
### Get Source Code
|
||||
|
||||
@@ -16,7 +16,7 @@ works and want to get started right away, continue.
|
||||
To quickly get Tendermint installed on a fresh
|
||||
Ubuntu 16.04 machine, use [this script](https://git.io/fFfOR).
|
||||
|
||||
WARNING: do not run this on your local machine.
|
||||
> :warning: Do not copy scripts to run on your machine without knowing what they do.
|
||||
|
||||
```sh
|
||||
curl -L https://git.io/fFfOR | bash
|
||||
@@ -62,6 +62,8 @@ Start tendermint with a simple in-process application:
|
||||
tendermint node --proxy_app=kvstore
|
||||
```
|
||||
|
||||
> Note: `kvstore` is a non persistent app, if you would like to run an application with persistence run `--proxy_app=persistent_kvstore`
|
||||
|
||||
and blocks will start to stream in:
|
||||
|
||||
```sh
|
||||
|
||||
698
docs/package-lock.json
generated
698
docs/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
# README in russian
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
parent:
|
||||
order: false
|
||||
---
|
||||
@@ -7,4 +7,16 @@ parent:
|
||||
|
||||
# Overview
|
||||
|
||||
See the side-bar for details on the various features of Tendermint Core.
|
||||
This section dives into the internals of Tendermint the implementation.
|
||||
|
||||
- [Using Tendermint](./using-tendermint.md)
|
||||
- [Configuration](./configuration.md)
|
||||
- [Running in Production](./running-in-production.md)
|
||||
- [Metrics](./metrics.md)
|
||||
- [Validators](./validators.md)
|
||||
- [Block Structure](./block-structure.md)
|
||||
- [RPC](./rpc.md)
|
||||
- [Fast Sync](./fast-sync.md)
|
||||
- [Mempool](./mempool.md)
|
||||
- [Light Client](./light-client.md)
|
||||
- [Secure P2P](./secure-p2p.md)
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
---
|
||||
order: 8
|
||||
order: 7
|
||||
---
|
||||
|
||||
# Block Structure
|
||||
|
||||
The tendermint consensus engine records all agreements by a
|
||||
The Tendermint consensus engine records all agreements by a
|
||||
supermajority of nodes into a blockchain, which is replicated among all
|
||||
nodes. This blockchain is accessible via various rpc endpoints, mainly
|
||||
nodes. This blockchain is accessible via various RPC endpoints, mainly
|
||||
`/block?height=` to get the full block, as well as
|
||||
`/blockchain?minHeight=_&maxHeight=_` to get a list of headers. But what
|
||||
exactly is stored in these blocks?
|
||||
|
||||
The [specification](https://github.com/tendermint/spec/blob/953523c3cb99fdb8c8f7a2d21e3a99094279e9de/spec/blockchain/blockchain.md) contains a detailed description of each component - that's the best place to get started.
|
||||
The [specification](https://github.com/tendermint/spec/blob/8dd2ed4c6fe12459edeb9b783bdaaaeb590ec15c/spec/core/data_structures.md) contains a detailed description of each component - that's the best place to get started.
|
||||
|
||||
To dig deeper, check out the [types package documentation](https://godoc.org/github.com/tendermint/tendermint/types).
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
order: 6
|
||||
order: 9
|
||||
---
|
||||
|
||||
# Fast Sync
|
||||
@@ -16,11 +16,11 @@ consensus gossip protocol.
|
||||
|
||||
## Using Fast Sync
|
||||
|
||||
To support faster syncing, tendermint offers a `fast-sync` mode, which
|
||||
To support faster syncing, Tendermint offers a `fast-sync` mode, which
|
||||
is enabled by default, and can be toggled in the `config.toml` or via
|
||||
`--fast_sync=false`.
|
||||
|
||||
In this mode, the tendermint daemon will sync hundreds of times faster
|
||||
In this mode, the Tendermint daemon will sync hundreds of times faster
|
||||
than if it used the real-time consensus process. Once caught up, the
|
||||
daemon will switch out of fast sync and into the normal consensus mode.
|
||||
After running for some time, the node is considered `caught up` if it
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
order: 9
|
||||
order: 11
|
||||
---
|
||||
|
||||
# Light Client
|
||||
@@ -33,7 +33,7 @@ proofs](https://github.com/tendermint/spec/blob/953523c3cb99fdb8c8f7a2d21e3a9909
|
||||
|
||||
## Where to obtain trusted height & hash
|
||||
|
||||
<https://pkg.go.dev/github.com/tendermint/tendermint/light?tab=doc#TrustOptions>
|
||||
[Trust Options](https://pkg.go.dev/github.com/tendermint/tendermint/light?tab=doc#TrustOptions)
|
||||
|
||||
One way to obtain semi-trusted hash & height is to query multiple full nodes
|
||||
and compare their hashes:
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
order: 11
|
||||
order: 5
|
||||
---
|
||||
|
||||
# Metrics
|
||||
@@ -18,37 +18,37 @@ Listen address can be changed in the config file (see
|
||||
|
||||
The following metrics are available:
|
||||
|
||||
| **Name** | **Type** | **Since** | **Tags** | **Description** |
|
||||
| -------------------------------------- | --------- | --------- | ------------- | ---------------------------------------------------------------------- |
|
||||
| consensus_height | Gauge | 0.21.0 | | Height of the chain |
|
||||
| consensus_validators | Gauge | 0.21.0 | | Number of validators |
|
||||
| consensus_validators_power | Gauge | 0.21.0 | | Total voting power of all validators |
|
||||
| consensus_validator_power | Gauge | 0.33.0 | | Voting power of the node if in the validator set |
|
||||
| consensus_validator_last_signed_height | Gauge | 0.33.0 | | Last height the node signed a block, if the node is a validator |
|
||||
| consensus_validator_missed_blocks | Gauge | 0.33.0 | | Total amount of blocks missed for the node, if the node is a validator |
|
||||
| consensus_missing_validators | Gauge | 0.21.0 | | Number of validators who did not sign |
|
||||
| consensus_missing_validators_power | Gauge | 0.21.0 | | Total voting power of the missing validators |
|
||||
| consensus_byzantine_validators | Gauge | 0.21.0 | | Number of validators who tried to double sign |
|
||||
| consensus_byzantine_validators_power | Gauge | 0.21.0 | | Total voting power of the byzantine validators |
|
||||
| consensus_block_interval_seconds | Histogram | 0.21.0 | | Time between this and last block (Block.Header.Time) in seconds |
|
||||
| consensus_rounds | Gauge | 0.21.0 | | Number of rounds |
|
||||
| consensus_num_txs | Gauge | 0.21.0 | | Number of transactions |
|
||||
| consensus_total_txs | Gauge | 0.21.0 | | Total number of transactions committed |
|
||||
| consensus_block_parts | counter | 0.25.0 | peer_id | number of blockparts transmitted by peer |
|
||||
| consensus_latest_block_height | gauge | 0.25.0 | | /status sync_info number |
|
||||
| consensus_fast_syncing | gauge | 0.25.0 | | either 0 (not fast syncing) or 1 (syncing) |
|
||||
| consensus_block_size_bytes | Gauge | 0.21.0 | | Block size in bytes |
|
||||
| p2p_peers | Gauge | 0.21.0 | | Number of peers node's connected to |
|
||||
| p2p_peer_receive_bytes_total | counter | 0.25.0 | peer_id, chID | number of bytes per channel received from a given peer |
|
||||
| p2p_peer_send_bytes_total | counter | 0.25.0 | peer_id, chID | number of bytes per channel sent to a given peer |
|
||||
| p2p_peer_pending_send_bytes | gauge | 0.25.0 | peer_id | number of pending bytes to be sent to a given peer |
|
||||
| p2p_num_txs | gauge | 0.25.0 | peer_id | number of transactions submitted by each peer_id |
|
||||
| p2p_pending_send_bytes | gauge | 0.25.0 | peer_id | amount of data pending to be sent to peer |
|
||||
| mempool_size | Gauge | 0.21.0 | | Number of uncommitted transactions |
|
||||
| mempool_tx_size_bytes | histogram | 0.25.0 | | transaction sizes in bytes |
|
||||
| mempool_failed_txs | counter | 0.25.0 | | number of failed transactions |
|
||||
| mempool_recheck_times | counter | 0.25.0 | | number of transactions rechecked in the mempool |
|
||||
| state_block_processing_time | histogram | 0.25.0 | | time between BeginBlock and EndBlock in ms |
|
||||
| **Name** | **Type** | **Tags** | **Description** |
|
||||
| -------------------------------------- | --------- | ------------- | ---------------------------------------------------------------------- |
|
||||
| consensus_height | Gauge | | Height of the chain |
|
||||
| consensus_validators | Gauge | | Number of validators |
|
||||
| consensus_validators_power | Gauge | | Total voting power of all validators |
|
||||
| consensus_validator_power | Gauge | | Voting power of the node if in the validator set |
|
||||
| consensus_validator_last_signed_height | Gauge | | Last height the node signed a block, if the node is a validator |
|
||||
| consensus_validator_missed_blocks | Gauge | | Total amount of blocks missed for the node, if the node is a validator |
|
||||
| consensus_missing_validators | Gauge | | Number of validators who did not sign |
|
||||
| consensus_missing_validators_power | Gauge | | Total voting power of the missing validators |
|
||||
| consensus_byzantine_validators | Gauge | | Number of validators who tried to double sign |
|
||||
| consensus_byzantine_validators_power | Gauge | | Total voting power of the byzantine validators |
|
||||
| consensus_block_interval_seconds | Histogram | | Time between this and last block (Block.Header.Time) in seconds |
|
||||
| consensus_rounds | Gauge | | Number of rounds |
|
||||
| consensus_num_txs | Gauge | | Number of transactions |
|
||||
| consensus_total_txs | Gauge | | Total number of transactions committed |
|
||||
| consensus_block_parts | counter | peer_id | number of blockparts transmitted by peer |
|
||||
| consensus_latest_block_height | gauge | | /status sync_info number |
|
||||
| consensus_fast_syncing | gauge | | either 0 (not fast syncing) or 1 (syncing) |
|
||||
| consensus_block_size_bytes | Gauge | | Block size in bytes |
|
||||
| p2p_peers | Gauge | | Number of peers node's connected to |
|
||||
| p2p_peer_receive_bytes_total | counter | peer_id, chID | number of bytes per channel received from a given peer |
|
||||
| p2p_peer_send_bytes_total | counter | peer_id, chID | number of bytes per channel sent to a given peer |
|
||||
| p2p_peer_pending_send_bytes | gauge | peer_id | number of pending bytes to be sent to a given peer |
|
||||
| p2p_num_txs | gauge | peer_id | number of transactions submitted by each peer_id |
|
||||
| p2p_pending_send_bytes | gauge | peer_id | amount of data pending to be sent to peer |
|
||||
| mempool_size | Gauge | | Number of uncommitted transactions |
|
||||
| mempool_tx_size_bytes | histogram | | transaction sizes in bytes |
|
||||
| mempool_failed_txs | counter | | number of failed transactions |
|
||||
| mempool_recheck_times | counter | | number of transactions rechecked in the mempool |
|
||||
| state_block_processing_time | histogram | | time between BeginBlock and EndBlock in ms |
|
||||
|
||||
## Useful queries
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
order: 4
|
||||
order: 8
|
||||
---
|
||||
|
||||
# RPC
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
order: 5
|
||||
order: 4
|
||||
---
|
||||
|
||||
# Running in production
|
||||
@@ -23,7 +23,7 @@ Tendermint keeps multiple distinct databases in the `$TMROOT/data`:
|
||||
used to temporarily store intermediate results during block processing.
|
||||
- `tx_index.db`: Indexes txs (and their results) by tx hash and by DeliverTx result events.
|
||||
|
||||
By default, Tendermint will only index txs by their hash, not by their DeliverTx
|
||||
By default, Tendermint will only index txs by their hash and height, not by their DeliverTx
|
||||
result events. See [indexing transactions](../app-dev/indexing-transactions.md) for
|
||||
details.
|
||||
|
||||
@@ -85,7 +85,7 @@ For the above reasons, the `mempool.wal` is disabled by default. To enable, set
|
||||
## DOS Exposure and Mitigation
|
||||
|
||||
Validators are supposed to setup [Sentry Node
|
||||
Architecture](https://blog.cosmos.network/tendermint-explained-bringing-bft-based-pos-to-the-public-blockchain-domain-f22e274a0fdb)
|
||||
Architecture](./validators.md)
|
||||
to prevent Denial-of-service attacks. You can read more about it
|
||||
[here](../interviews/tendermint-bft.md).
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ curl http://localhost:26657/status | json_pp | grep latest_app_hash
|
||||
|
||||
<!-- markdown-link-check-disable -->
|
||||
|
||||
Visit <http://localhost:26657> in your browser to see the list of other
|
||||
Visit `http://localhost:26657` in your browser to see the list of other
|
||||
endpoints. Some take no arguments (like `/status`), while others specify
|
||||
the argument name and use `_` as a placeholder.
|
||||
|
||||
@@ -196,7 +196,7 @@ taken into account:
|
||||
|
||||
With `GET`:
|
||||
|
||||
To send a UTF8 string byte array, quote the value of the tx pramater:
|
||||
To send a UTF8 string byte array, quote the value of the tx parameter:
|
||||
|
||||
```sh
|
||||
curl 'http://localhost:26657/broadcast_tx_commit?tx="hello"'
|
||||
@@ -204,7 +204,7 @@ curl 'http://localhost:26657/broadcast_tx_commit?tx="hello"'
|
||||
|
||||
which sends a 5 byte transaction: "h e l l o" \[68 65 6c 6c 6f\].
|
||||
|
||||
Note the URL must be wrapped with single quoes, else bash will ignore
|
||||
Note the URL must be wrapped with single quotes, else bash will ignore
|
||||
the double quotes. To avoid the single quotes, escape the double quotes:
|
||||
|
||||
```sh
|
||||
@@ -267,7 +267,7 @@ Some fields from the config file can be overwritten with flags.
|
||||
|
||||
## No Empty Blocks
|
||||
|
||||
While the default behaviour of `tendermint` is still to create blocks
|
||||
While the default behavior of `tendermint` is still to create blocks
|
||||
approximately once per second, it is possible to disable empty blocks or
|
||||
set a block creation interval. In the former case, blocks will be
|
||||
created when there are new transactions or when the AppHash changes.
|
||||
@@ -437,7 +437,7 @@ another address from the address book. On restarts you will always try to
|
||||
connect to these peers regardless of the size of your address book.
|
||||
|
||||
All peers relay peers they know of by default. This is called the peer exchange
|
||||
protocol (PeX). With PeX, peers will be gossipping about known peers and forming
|
||||
protocol (PeX). With PeX, peers will be gossiping about known peers and forming
|
||||
a network, storing peer addresses in the addrbook. Because of this, you don't
|
||||
have to use a seed node if you have a live persistent peer.
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
order: 6
|
||||
---
|
||||
|
||||
# Validators
|
||||
|
||||
Validators are responsible for committing new blocks in the blockchain.
|
||||
|
||||
@@ -204,7 +204,7 @@ paths:
|
||||
summary: Checks the transaction without executing it.
|
||||
tags:
|
||||
- Tx
|
||||
operationId: broadcast_tx_commit
|
||||
operationId: check_tx
|
||||
description: |
|
||||
The transaction won't be added to the mempool.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user