mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-24 22:32:15 +00:00
add wiki
This commit is contained in:
parent
886a83dfb8
commit
f1ce6ff4d0
67
docs/archived.wiki/Application-Architecture.md
Normal file
67
docs/archived.wiki/Application-Architecture.md
Normal file
@ -0,0 +1,67 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
# Overview
|
||||
|
||||
This page is for developers looking to build a complete system with Tendermint. It is assumed that you have read the wiki and understand the basic principles. In particular, that you have read [[Application Developers]] on the ABCI <-> Validator Node connection and hopefully, also [played with a simple app connected to a tendermint](http://tendermint.com/guide/run-your-first-tmsp-application/).
|
||||
|
||||
However, a blockchain application is more than the consensus engine and the transaction logic (eg. smart contracts, business logic) as implemented in the ABCI app. There are also (mobile, web, desktop) clients that will need to connect and make use of the app. We will assume for now that you have a well designed transactions and database model, but maybe this will be the topic of another article. This article is more interested in various ways of setting up the "plumbing" and connecting these pieces, and demonstrating some evolving best practices.
|
||||
|
||||
# Security
|
||||
|
||||
A very important aspect when constructing a blockchain is security. The consensus model can be DoSed (no consensus possible) by corrupting 1/3 of the validators and exploited (writing arbitrary blocks) by corrupting 2/3 of the validators. So, while the security is not that of the "weakest link", you should take care that the "average link" is sufficiently hardened.
|
||||
|
||||
One big attack surface on the validators is the communication between the ABCI app and Tendermint. This should be highly protected. Ideally, the app and the core are running on the same machine, so no external agent can target the communication channel. You can use unix sockets (with permissions preventing access from other users), or even compile the two apps into one binary if the ABCI app is also writen in go (@ebuchman says this is possible). If you are unable to do that due to language support, then the ABCI app should bind a TCP connection to localhost (127.0.0.1), which is less efficient and secure, but still not reachable from outside. If you must run the ABCI app and Tendermint on separate machines, make sure you have a secure communication channel (ssh tunnel?).
|
||||
|
||||
Now assuming, you have linked together your app and the core securely, you must also make sure no one can get on the machine it is hosted on. At this point it is basic network security. Run on a secure operating system (SELinux?). Limit who has access to the machine (user accounts, but also where the physical machine is hosted). Turn off all services except for ssh, which should only be accessible by some well-guarded public/private key pairs (no password). And maybe even firewall off access to the ports used by the validators, so only known validators can connect.
|
||||
|
||||
There was also a suggestion on slack from @jhon about compiling everything together with a unikernel for more security, such as [Mirage](https://mirage.io) or [UNIK](https://github.com/emc-advanced-dev/unik).
|
||||
|
||||
# Connecting your client to the blockchain
|
||||
|
||||
## Tendermint Core RPC
|
||||
|
||||
I believe this was the original design from @ebuchman. The concept is that the ABCI app is completely hidden from the outside world and only communicated through a tested and secured [interface exposed by the tendermint core](../RPC). This interface exposes a lot of data on the block header and consensus process, which is quite useful for externally verifying the system. It also includes 3(!) methods to broadcast a transaction (propose it for the blockchain, and possibly await a response). And one method to query app-specific data from the ABCI application.
|
||||
|
||||
Pros:
|
||||
* Server code already written
|
||||
* Access to block headers to validate merkle proofs (nice for light clients)
|
||||
* Basic read/write functionality is supported
|
||||
|
||||
Cons:
|
||||
* Limited interface to app. All queries must be serialized into []byte (less expressive than JSON over HTTP) and there is no way to push data from ABCI app to the client (eg. notify me if account X receives a transaction).
|
||||
|
||||
## Custom ABCI server
|
||||
|
||||
This was proposed by @wolfposd on slack and demonstrated by [TMChat](https://github.com/wolfposd/TMChat), a sample app. The concept is to write a custom server for your app (with typical REST API/websockets/etc for easy use by a mobile app). This custom server is in the same binary as the ABCI app and data store, so can easily react to complex events there that involve understanding the data format (send a message if my balance drops below 500). All "writes" sent to this server are proxied via websocket/JSON-RPC to tendermint core. When they come back as append_tx over ABCI, they will be written to the data store. For "reads", we can do any queries we wish that are supported by our architecture, using any web technology that is useful. The general architecture is shown in the following diagram:
|
||||
|
||||
[[https://github.com/wolfposd/tutorials/blob/master/images/tendermint/TMApplicationExample.png|alt=applicationarchitecture]]
|
||||
|
||||
Pros:
|
||||
* Separates application logic from blockchain logic
|
||||
* Allows much richer, more flexible client-facing API
|
||||
* Allows pub-sub, watching certain fields, etc.
|
||||
* Hides the tendermint-rpc from unregulated access (only the ABCI-app can call rpc functions)
|
||||
|
||||
Cons:
|
||||
* You must write your own API (but maybe that's a pro...)
|
||||
* You must relay Tendermint messages to connected clients (allows more context for messages)
|
||||
|
||||
## Hybrid solutions
|
||||
|
||||
Likely the least secure but most versatile. The client can access both the Tendermint node for all blockchain info, as well as a custom app server, for complex queries and pub-sub on the ABCI app.
|
||||
|
||||
Pros:
|
||||
* All from both above solutions
|
||||
|
||||
Cons:
|
||||
* Even more complexity
|
||||
* Even more attack vectors (less security)
|
||||
|
||||
# Scalability
|
||||
|
||||
Read replica using non-validating nodes? They could forward transactions to the validators (fewer connections, more security), and locally allow all queries in any of the above configurations. Thus, while transaction-processing speed is limited by the speed of the ABCI app and the number of validators, one should be able to scale our read performance to quite an extent (until the replication process drains too many resources from the validator nodes).
|
||||
|
||||
# Example Code
|
||||
|
||||
* [TMChat](https://github.com/wolfposd/TMChat)
|
||||
* see https://tendermint.com/ecosystem
|
149
docs/archived.wiki/Application-Developers.md
Normal file
149
docs/archived.wiki/Application-Developers.md
Normal file
@ -0,0 +1,149 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
# Background
|
||||
|
||||
For a lighter introduction, see [the ABCI blog post](https://tendermint.com/blog/abci-the-application-blockchain-interface) and the [guide to run your first ABCI application](https://tendermint.com/intro/getting-started/first-abci). Here we'll provide more details about writing ABCI applications and implementing ABCI servers to support new programming languages.
|
||||
|
||||
# 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
|
||||
|
||||
<img src="http://tendermint.readthedocs.io/en/master/_images/abci.png" width="600">
|
||||
|
||||
The mempool and consensus logic act as clients, and each maintains an open TMSP connection with the application, which hosts a TMSP server. Shown are the request and response types sent on each connection.
|
||||
|
||||
# Message Protocol
|
||||
|
||||
The message protocol consists of pairs of requests and responses. Some messages have no fields, while others may include byte-arrays, strings, or integers. See the `message Request` and `message Response` definitions in [the protobuf definition file](https://github.com/tendermint/tmsp/blob/master/types/types.proto), and the [protobuf documentation](https://developers.google.com/protocol-buffers/docs/overview) for more details.
|
||||
|
||||
For each request, a server should respond with the corresponding response, where order of requests is preserved in the order of responses.
|
||||
|
||||
# Server
|
||||
|
||||
To use ABCI in your programming language of choice, there must be a ABCI server in that language.
|
||||
Tendermint supports two kinds of implementation of the server:
|
||||
|
||||
- Asynchronous, raw socket server
|
||||
- GRPC
|
||||
|
||||
Both can be tested using the `abci-cli` by setting the `--abci` flag appropriately (ie. to `socket` or `grpc`).
|
||||
|
||||
See examples, in various stages of maintenance, in [go](https://github.com/tendermint/tmsp/tree/master/server), [javascript](https://github.com/tendermint/js-tmsp), [python](https://github.com/tendermint/tmsp/tree/master/example/python3/tmsp), [c++](https://github.com/mdyring/cpp-tmsp), and [java](https://github.com/jTMSP/jTMSP).
|
||||
|
||||
## GRPC
|
||||
|
||||
If GRPC is available in your language, this is the easiest approach,
|
||||
though it will have significant performance overhead.
|
||||
|
||||
To get started with GRPC, copy in the [protobuf file](https://github.com/tendermint/tmsp/blob/master/types/types.proto) and compile it using the GRPC plugin for your language.
|
||||
For instance, for golang, the command is `protoc --go_out=plugins=grpc:. types.proto`. See the [grpc documentation for more details](http://www.grpc.io/docs/). `protoc` will autogenerate all the necessary code for TMSP client and server in your language, including whatever interface your application must satisfy to be used by the TMSP server for handling requests.
|
||||
|
||||
## Async Raw
|
||||
|
||||
If GRPC is not available in your language, or you require higher performance, or otherwise enjoy programming, you may implement your own ABCI server.
|
||||
The first step is still to auto-generate the relevant data types and codec in your language using `protoc`.
|
||||
Messages coming over the socket are Protobuf3 encoded, but additionally length-prefixed to facilitate use as a streaming protocol. Protobuf3 doesn't have an official length-prefix standard, so we use our own. The first byte in the prefix represents the length of the Big Endian encoded length. The remaining bytes in the prefix are the Big Endian encoded length.
|
||||
|
||||
For example, if the Protobuf3 encoded TMSP message is 0xDEADBEEF (4 bytes), the length-prefixed message is 0x0104DEADBEEF. If the Protobuf3 encoded TMSP message is 65535 bytes long, the length-prefixed message would be like 0x02FFFF....
|
||||
|
||||
Note this prefixing does not apply for grpc.
|
||||
|
||||
An ABCI server must also be able to support multiple connections, as Tendermint uses three connections.
|
||||
|
||||
# Client
|
||||
|
||||
There are currently two use-cases for a ABCI client.
|
||||
One is a testing tool, as in the `abci-cli`, which allows ABCI requests to be sent via command line.
|
||||
The other is a consensus engine, such as Tendermint Core, which makes requests to the application every time a new transaction is received or a block is committed.
|
||||
|
||||
It is unlikely that you will need to implement a client. For details of our client, see [here](https://github.com/tendermint/abci/tree/master/client).
|
||||
|
||||
# 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 TMSP 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.
|
||||
|
||||
## 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.
|
||||
|
||||
### 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 reset 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 Commit response includes 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).
|
||||
|
||||
### 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 [Handshake](#handshake).
|
||||
|
||||
### 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`. Tendermint core will take care of updating the validator set (TODO).
|
||||
|
||||
## 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 public key. For instance, returning non-OK TMSP response to either of the following queries will cause Tendermint to not connect to the corresponding peer:
|
||||
|
||||
- `p2p/filter/addr/<addr>`, where `<addr>` is an IP address.
|
||||
- `p2p/filter/pubkey/<pubkey>`, where `<pubkey>` is the hex-encoded ED25519 key of the node (not it's validator key)
|
||||
|
||||
Note: these query formats are subject to change!
|
||||
|
||||
## Handshake
|
||||
|
||||
The ABCI handshake and related improvements are [upcoming in v0.8.0](https://github.com/tendermint/tendermint/issues/300)
|
18
docs/archived.wiki/Benchmarks.md
Normal file
18
docs/archived.wiki/Benchmarks.md
Normal file
@ -0,0 +1,18 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
For benchmarking tooling, see the `tm-bench` tools at https://github.com/tendermint/tools
|
||||
|
||||
**Q: How many txs/sec can Tendermint process?**
|
||||
|
||||
This depends on what kind of data structure holds the account data, what the persistence strategy is, how many accounts there are, and how many transactions there are in a block, and other factors.
|
||||
|
||||
Keeping 1M accounts *in memory* with the existing IAVLTree implementation (self-balancing key-value tree) with no Merkle hashing yields about 42000 get/set ops per second.
|
||||
|
||||
```bash
|
||||
$ go test -bench=. merkle/*.go
|
||||
100000 23564 ns/op
|
||||
```
|
||||
|
||||
If you're sending funds from one account to another, you'll need 4 ops, so maybe that's 10500 txs/s. This does not take into account the overhead needed to process signatures or run EVM bytecode. Merkle hashing would be performed in batch between blocks, in this case. Storage could run in the background.
|
||||
|
||||
We still need to benchmark the mempool. The mempool is "safe" but it's slow. We'll look into overlaying a faster mempool network later when we know that it's the bottleneck.
|
105
docs/archived.wiki/Block-Structure.md
Normal file
105
docs/archived.wiki/Block-Structure.md
Normal file
@ -0,0 +1,105 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
### Block
|
||||
A `Block` is composed of:
|
||||
- [`Header`](#header): basic information about the chain and last state
|
||||
- [`Data`](#data): transactions and other data
|
||||
- [`LastCommit`](#commit): +2/3 precommit signatures for the previous block
|
||||
|
||||
### Header
|
||||
The block `Header` is composed of:
|
||||
- `ChainId (string)`: name of the blockchain, e.g. "tendermint"
|
||||
- `Height (int)`: sequential block number starting with 1
|
||||
- `Time (time)`: local time of the proposer who proposed this block
|
||||
- `LastBlockHash ([]byte)`: [`block hash`](#block-hash) of the previous block at height `Height-1`
|
||||
- `LastBlockParts (PartSetHeader)`: [`partset header`](#partset-header) of the previous block
|
||||
- `StateHash ([]byte)`: [`state hash`](#state-hash) of the state after processing this block
|
||||
|
||||
### Data
|
||||
The block `Data` is composed of:
|
||||
- `Txs ([]Tx)`: a list of [`transactions`](#transaction)
|
||||
|
||||
### Commit
|
||||
The block `Commit` is composed of:
|
||||
- `Precommits ([]Vote)`: a list of [`precommit votes`](#vote)
|
||||
|
||||
### Vote
|
||||
A `Vote` is composed of:
|
||||
- `Height (int)`: The block height being decided on
|
||||
- `Round (int)`: The consensus round number, starting with 0
|
||||
- `Type (byte)`: The type of vote, either a `prevote` or a `precommit`
|
||||
- `BlockHash ([]byte)`: The [`block hash`](#block-hash) of a valid block, or `nil`
|
||||
- `BlockParts (PartSetHeader)`: The corresponding [`partset header`](#partset-header), or `x0000` if the `block hash` is `nil`
|
||||
- `Signature (Signature)`: The signature of this `Vote`'s [`sign-bytes`](#vote-sign-bytes)
|
||||
|
||||
#### Vote Sign Bytes
|
||||
The `sign-bytes` of a transaction is produced by taking a [`stable-json`](https://github.com/substack/json-stable-stringify)-like deterministic JSON [`wire`](Wire-Protocol) encoding of the vote (excluding the `Signature` field), and wrapping it with `{"chain_id":"tendermint","vote":...}`.
|
||||
|
||||
For example, a precommit vote might have the following `sign-bytes`:
|
||||
|
||||
```json
|
||||
{"chain_id":"tendermint","vote":{"block_hash":"611801F57B4CE378DF1A3FFF1216656E89209A99","block_parts_header":{"hash":"B46697379DBE0774CC2C3B656083F07CA7E0F9CE","total":123},"height":1234,"round":1,"type":2}}
|
||||
```
|
||||
|
||||
### Block Hash
|
||||
|
||||
The block hash is the [Simple Tree hash](Merkle-Trees#simple-tree-with-dictionaries) of the fields of the block `Header` encoded as a list of `KVPair`s.
|
||||
|
||||
### State Hash
|
||||
|
||||
The state hash is the [Simple Tree hash](Merkle-Trees#simple-tree-with-dictionaries) of the state's fields (e.g. `BondedValidators`, `UnbondingValidators`, `Accounts`, `ValidatorInfos`, and `NameRegistry`) encoded as a list of `KVPair`s. This state hash is recursively included in the block `Header` and thus the [block hash](#block-hash) indirectly.
|
||||
|
||||
### Transaction
|
||||
|
||||
A transaction is any sequence of bytes. It is up to your [TMSP](https://github.com/tendermint/tmsp) application to accept or reject transactions.
|
||||
|
||||
### PartSet
|
||||
|
||||
PartSet is used to split a byteslice of data into parts (pieces) for transmission.
|
||||
By splitting data into smaller parts and computing a Merkle root hash on the list,
|
||||
you can verify that a part is legitimately part of the complete data, and the
|
||||
part can be forwarded to other peers before all the parts are known. In short,
|
||||
it's a fast way to propagate a large file over a gossip network.
|
||||
|
||||
PartSet was inspired by the LibSwift project.
|
||||
|
||||
Usage:
|
||||
|
||||
```Go
|
||||
data := RandBytes(2 << 20) // Something large
|
||||
|
||||
partSet := NewPartSetFromData(data)
|
||||
partSet.Total() // Total number of 4KB parts
|
||||
partSet.Count() // Equal to the Total, since we already have all the parts
|
||||
partSet.Hash() // The Merkle root hash
|
||||
partSet.BitArray() // A BitArray of partSet.Total() 1's
|
||||
|
||||
header := partSet.Header() // Send this to the peer
|
||||
header.Total // Total number of parts
|
||||
header.Hash // The merkle root hash
|
||||
|
||||
// Now we'll reconstruct the data from the parts
|
||||
partSet2 := NewPartSetFromHeader(header)
|
||||
partSet2.Total() // Same total as partSet.Total()
|
||||
partSet2.Count() // Zero, since this PartSet doesn't have any parts yet.
|
||||
partSet2.Hash() // Same hash as in partSet.Hash()
|
||||
partSet2.BitArray() // A BitArray of partSet.Total() 0's
|
||||
|
||||
// In a gossip network the parts would arrive in arbitrary order, perhaps
|
||||
// in response to explicit requests for parts, or optimistically in response
|
||||
// to the receiving peer's partSet.BitArray().
|
||||
for !partSet2.IsComplete() {
|
||||
part := receivePartFromGossipNetwork()
|
||||
added, err := partSet2.AddPart(part)
|
||||
if err != nil {
|
||||
// A wrong part,
|
||||
// the merkle trail does not hash to partSet2.Hash()
|
||||
} else if !added {
|
||||
// A duplicate part already received
|
||||
}
|
||||
}
|
||||
|
||||
data2, _ := ioutil.ReadAll(partSet2.GetReader())
|
||||
bytes.Equal(data, data2) // true
|
||||
```
|
||||
|
195
docs/archived.wiki/Byzantine-Consensus-Algorithm.md
Normal file
195
docs/archived.wiki/Byzantine-Consensus-Algorithm.md
Normal file
@ -0,0 +1,195 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](https://tendermint.com/docs/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
For the latest description of the consensus algorithm, see [our paper](https://arxiv.org/abs/1807.04938) and the [source repository](https://github.com/tendermint/spec)
|
||||
|
||||
## Terms
|
||||
- The network is composed of optionally connected _nodes_. Nodes directly connected to a particular node are called _peers_.
|
||||
- The consensus process in deciding the next block (at some _height_ `H`) is composed of one or many _rounds_.
|
||||
- `NewHeight`, `Propose`, `Prevote`, `Precommit`, and `Commit` represent state machine states of a round. (aka `RoundStep` or just "step").
|
||||
- A node is said to be _at_ a given height, round, and step, or at `(H,R,S)`, or at `(H,R)` in short to omit the step.
|
||||
- To _prevote_ or _precommit_ something means to broadcast a [prevote vote](Block-Structure#vote) or [precommit vote](Block-Structure#vote) for something.
|
||||
- A vote _at_ `(H,R)` is a vote signed with the bytes for `H` and `R` included in its [`sign-bytes`](Block-Structure#vote).
|
||||
- _+2/3_ is short for "more than 2/3"
|
||||
- _1/3+_ is short for "1/3 or more"
|
||||
- A set of +2/3 of prevotes for a particular block or `<nil>` at `(H,R)` is called a _proof-of-lock-change_ or _PoLC_ for short.
|
||||
|
||||
## State Machine Overview
|
||||
|
||||
At each height of the blockchain a round-based protocol is run to determine
|
||||
the next block. Each round is composed of three _steps_ (`Propose`, `Prevote`, and
|
||||
`Precommit`), along with two special steps `Commit` and `NewHeight`.
|
||||
|
||||
In the optimal scenario, the order of steps is:
|
||||
```
|
||||
NewHeight -> (Propose -> Prevote -> Precommit)+ -> Commit -> NewHeight ->...
|
||||
```
|
||||
|
||||
The sequence `(Propose -> Prevote -> Precommit)` is called a _round_. There may be more than one round required to commit a block at a given height. Examples for why more rounds may be required include:
|
||||
|
||||
- The designated proposer was not online.
|
||||
- The block proposed by the designated proposer was not valid.
|
||||
- The block proposed by the designated proposer did not propagate in time.
|
||||
- The block proposed was valid, but +2/3 of prevotes for the proposed block were not received in time for enough validator nodes by the time they reached the `Precommit` step. Even though +2/3 of prevotes are necessary to progress to the next step, at least one validator may have voted `<nil>` or maliciously voted for something else.
|
||||
- The block proposed was valid, and +2/3 of prevotes were received for enough nodes, but +2/3 of precommits for the proposed block were not received for enough validator nodes.
|
||||
|
||||
Some of these problems are resolved by moving onto the next round & proposer. Others are resolved by increasing certain round timeout parameters over each successive round.
|
||||
|
||||
## State Machine Diagram
|
||||
```
|
||||
+-------------------------------------+
|
||||
v |(Wait til `CommmitTime+timeoutCommit`)
|
||||
+-----------+ +-----+-----+
|
||||
+----------> | Propose +--------------+ | NewHeight |
|
||||
| +-----------+ | +-----------+
|
||||
| | ^
|
||||
|(Else, after timeoutPrecommit) v |
|
||||
+-----+-----+ +-----------+ |
|
||||
| Precommit | <------------------------+ Prevote | |
|
||||
+-----+-----+ +-----------+ |
|
||||
|(When +2/3 Precommits for block found) |
|
||||
v |
|
||||
+--------------------------------------------------------------------+
|
||||
| Commit |
|
||||
| |
|
||||
| * Set CommitTime = now; |
|
||||
| * Wait for block, then stage/save/commit block; |
|
||||
+--------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
## Background Gossip
|
||||
|
||||
A node may not have a corresponding validator private key, but it nevertheless plays an active role in the consensus process by relaying relevant meta-data, proposals, blocks, and votes to its peers. A node that has the private keys of an active validator and is engaged in signing votes is called a _validator-node_. All nodes (not just validator-nodes) have an associated state (the current height, round, and step) and work to make progress.
|
||||
|
||||
Between two nodes there exists a `Connection`, and multiplexed on top of this connection are fairly throttled `Channel`s of information. An epidemic gossip protocol is implemented among some of these channels to bring peers up to speed on the most recent state of consensus. For example,
|
||||
|
||||
- Nodes gossip `PartSet` parts of the current round's proposer's proposed block. A LibSwift inspired algorithm is used to quickly broadcast blocks across the gossip network.
|
||||
- Nodes gossip prevote/precommit votes. A node NODE_A that is ahead of NODE_B can send NODE_B prevotes or precommits for NODE_B's current (or future) round to enable it to progress forward.
|
||||
- Nodes gossip prevotes for the proposed PoLC (proof-of-lock-change) round if one is proposed.
|
||||
- Nodes gossip to nodes lagging in blockchain height with block [commits](Block-Structure#commit) for older blocks.
|
||||
- Nodes opportunistically gossip `HasVote` messages to hint peers what votes it already has.
|
||||
- Nodes broadcast their current state to all neighboring peers. (but is not gossiped further)
|
||||
|
||||
There's more, but let's not get ahead of ourselves here.
|
||||
|
||||
## Proposals
|
||||
|
||||
A proposal is signed and published by the designated proposer at each round. The proposer is chosen by a deterministic and non-choking round robin selection algorithm that selects proposers in proportion to their voting power. (see [details](https://github.com/tendermint/tendermint/blob/master/docs/spec/reactors/consensus/proposer-selection.md))
|
||||
|
||||
A proposal at `(H,R)` is composed of a block and an optional latest `PoLC-Round < R` which is included iff the proposer knows of one. This hints the network to allow nodes to unlock (when safe) to ensure the liveness property.
|
||||
|
||||
## State Machine Spec
|
||||
|
||||
### Propose Step (height:H,round:R)
|
||||
Upon entering `Propose`:
|
||||
- The designated proposer proposes a block at `(H,R)`.
|
||||
|
||||
The `Propose` step ends:
|
||||
- After `timeoutProposeR` after entering `Propose`. --> goto `Prevote(H,R)`
|
||||
- After receiving proposal block and all prevotes at `PoLC-Round`. --> goto `Prevote(H,R)`
|
||||
- After [common exit conditions](#common-exit-conditions)
|
||||
|
||||
### Prevote Step (height:H,round:R)
|
||||
Upon entering `Prevote`, each validator broadcasts its prevote vote.
|
||||
|
||||
- First, if the validator is locked on a block since `LastLockRound` but now has a PoLC for something else at round `PoLC-Round` where `LastLockRound < PoLC-Round < R`, then it unlocks.
|
||||
- If the validator is still locked on a block, it prevotes that.
|
||||
- Else, if the proposed block from `Propose(H,R)` is good, it prevotes that.
|
||||
- Else, if the proposal is invalid or wasn't received on time, it prevotes `<nil>`.
|
||||
|
||||
The `Prevote` step ends:
|
||||
- After +2/3 prevotes for a particular block or `<nil>`. --> goto `Precommit(H,R)`
|
||||
- After `timeoutPrevote` after receiving any +2/3 prevotes. --> goto `Precommit(H,R)`
|
||||
- After [common exit conditions](#common-exit-conditions)
|
||||
|
||||
### Precommit Step (height:H,round:R)
|
||||
Upon entering `Precommit`, each validator broadcasts its precommit vote.
|
||||
- If the validator has a PoLC at `(H,R)` for a particular block `B`, it (re)locks (or changes lock to) and precommits `B` and sets `LastLockRound = R`.
|
||||
- Else, if the validator has a PoLC at `(H,R)` for `<nil>`, it unlocks and precommits `<nil>`.
|
||||
- Else, it keeps the lock unchanged and precommits `<nil>`.
|
||||
|
||||
A precommit for `<nil>` means "I didn’t see a PoLC for this round, but I did get +2/3 prevotes and waited a bit".
|
||||
|
||||
The Precommit step ends:
|
||||
- After +2/3 precommits for `<nil>`. --> goto `Propose(H,R+1)`
|
||||
- After `timeoutPrecommit` after receiving any +2/3 precommits. --> goto `Propose(H,R+1)`
|
||||
- After [common exit conditions](#common-exit-conditions)
|
||||
|
||||
#### common exit conditions
|
||||
- After +2/3 precommits for a particular block. --> goto `Commit(H)`
|
||||
- After any +2/3 prevotes received at `(H,R+x)`. --> goto `Prevote(H,R+x)`
|
||||
- After any +2/3 precommits received at `(H,R+x)`. --> goto `Precommit(H,R+x)`
|
||||
|
||||
### Commit Step (height:H)
|
||||
- Set `CommitTime = now()`
|
||||
- Wait until block is received. --> goto `NewHeight(H+1)`
|
||||
|
||||
### NewHeight Step (height:H)
|
||||
- Move `Precommits` to `LastCommit` and increment height.
|
||||
- Set `StartTime = CommitTime+timeoutCommit`
|
||||
- Wait until `StartTime` to receive straggler commits. --> goto `Propose(H,0)`
|
||||
|
||||
## Proofs
|
||||
|
||||
### Proof of Safety
|
||||
Assume that at most -1/3 of the voting power of validators is byzantine. If a validator commits block `B` at round `R`, it's because it saw +2/3 of precommits at round `R`. This implies that 1/3+ of honest nodes are still locked at round `R' > R`. These locked validators will remain locked until they see a PoLC at `R' > R`, but this won't happen because 1/3+ are locked and honest, so at most -2/3 are available to vote for anything other than `B`.
|
||||
|
||||
### Proof of Liveness
|
||||
If 1/3+ honest validators are locked on two different blocks from different rounds, a proposers' `PoLC-Round` will eventually cause nodes locked from the earlier round to unlock. Eventually, the designated proposer will be one that is aware of a PoLC at the later round. Also, `timeoutProposalR` increments with round `R`, while the size of a proposal are capped, so eventually the network is able to "fully gossip" the whole proposal (e.g. the block & PoLC).
|
||||
|
||||
### Proof of Fork Accountability
|
||||
Define the JSet (justification-vote-set) at height `H` of a validator `V1` to be all the votes signed by the validator at `H` along with justification PoLC prevotes for each lock change. For example, if `V1` signed the following precommits: `Precommit(B1 @ round 0)`, `Precommit(<nil> @ round 1)`, `Precommit(B2 @ round 4)` (note that no precommits were signed for rounds 2 and 3, and that's ok), `Precommit(B1 @ round 0)` must be justified by a PoLC at round 0, and `Precommit(B2 @ round 4)` must be justified by a PoLC at round 4; but the precommit for `<nil>` at round 1 is not a lock-change by definition so the JSet for `V1` need not include any prevotes at round 1, 2, or 3 (unless `V1` happened to have prevoted for those rounds).
|
||||
|
||||
Further, define the JSet at height `H` of a set of validators `VSet` to be the union of the JSets for each validator in `VSet`. For a given commit by honest validators at round `R` for block `B` we can construct a JSet to justify the commit for `B` at `R`.
|
||||
We say that a JSet _justifies_ a commit at `(H,R)` if all the committers (validators in the commit-set) are each justified in the JSet with no duplicitous vote signatures (by the committers).
|
||||
|
||||
- **Lemma**: When a fork is detected by the existence of two conflicting [commits](Validators#Committing-a-Block), the union of the JSets for both commits (if they can be compiled) must include double-signing by at least 1/3+ of the validator set. **Proof**: The commit cannot be at the same round, because that would immediately imply double-signing by 1/3+. Take the union of the JSets of both commits. If there is no double-signing by at least 1/3+ of the validator set in the union, then no honest validator could have precommitted any different block after the first commit. Yet, +2/3 did. Reductio ad absurdum.
|
||||
|
||||
As a corollary, when there is a fork, an external process can determine the blame by requiring each validator to justify all of its round votes. Either we will find 1/3+ who cannot justify at least one of their votes, and/or, we will find 1/3+ who had double-signed.
|
||||
|
||||
### Alternative algorithm
|
||||
|
||||
Alternatively, we can take the JSet of a commit to be the "full commit". That is, if light clients and validators do not consider a block to be committed unless the JSet of the commit is also known, then we get the desirable property that if there ever is a fork (e.g. there are two conflicting "full commits"), then 1/3+ of the validators are immediately punishable for double-signing.
|
||||
|
||||
There are many ways to ensure that the gossip network efficiently share the JSet of a commit. One solution is to add a new message type that tells peers that this node has (or does not have) a +2/3 majority for B (or <nil>) at (H,R), and a bitarray of which votes contributed towards that majority. Peers can react by responding with appropriate votes.
|
||||
|
||||
We will implement such an algorithm for the next iteration of the Tendermint consensus protocol.
|
||||
|
||||
Other potential improvements include adding more data in votes such as the last known PoLC round that caused a lock change, and the last voted round/step (or, we may require that validators not skip any votes). This may make JSet verification/gossip logic easier to implement.
|
||||
|
||||
### Censorship Attacks
|
||||
|
||||
Due to the definition of a block [commit](Validators#committing-a-block), any 1/3+ coalition of validators can halt the blockchain by not broadcasting their votes. Such a coalition can also censor particular transactions by rejecting blocks that include these transactions, though this would result in a significant proportion of block proposals to be rejected, which would slow down the rate of block commits of the blockchain, reducing its utility and value. The malicious coalition might also broadcast votes in a trickle so as to grind blockchain block commits to a near halt, or engage in any combination of these attacks.
|
||||
|
||||
If a global active adversary were also involved, it can partition the network in such a way that it may appear that the wrong subset of validators were responsible for the slowdown. This is not just a limitation of Tendermint, but rather a limitation of all consensus protocols whose network is potentially controlled by an active adversary.
|
||||
|
||||
### Overcoming Forks and Censorship Attacks
|
||||
|
||||
For these types of attacks, a subset of the validators through external means
|
||||
should coordinate to sign a reorg-proposal that chooses a fork (and any evidence
|
||||
thereof) and the initial subset of validators with their signatures. Validators
|
||||
who sign such a reorg-proposal forego its collateral on all other forks.
|
||||
Clients should verify the signatures on the reorg-proposal, verify any evidence,
|
||||
and make a judgement or prompt the end-user for a decision. For example, a
|
||||
phone wallet app may prompt the user with a security warning, while a
|
||||
refrigerator may accept any reorg-proposal signed by +½ of the original
|
||||
validators.
|
||||
|
||||
No non-synchronous Byzantine fault-tolerant algorithm can come to consensus when
|
||||
⅓+ of validators are dishonest, yet a fork assumes that ⅓+ of validators have
|
||||
already been dishonest by double-signing or lock-changing without justification.
|
||||
So, signing the reorg-proposal is a coordination problem that cannot be solved
|
||||
by any non-synchronous protocol (i.e. automatically, and without making
|
||||
assumptions about the reliability of the underlying network). It must be
|
||||
provided by means external to the weakly-synchronous Tendermint consensus
|
||||
algorithm. For now, we leave the problem of reorg-proposal coordination to
|
||||
human coordination via internet media. Validators must take care to ensure that
|
||||
there are no significant network partitions, to avoid situations where two
|
||||
conflicting reorg-proposals are signed.
|
||||
|
||||
Assuming that the external coordination medium and protocol is robust, it follows that forks are less of a concern than [censorship attacks](#censorship-attacks).
|
||||
|
||||
### Revisions
|
||||
|
||||
#### 0.6 -> 0.7 (current)
|
||||
1. Reduced the minimum number of signature steps from 3 to 2 by removing the "commit" vote and step.
|
||||
2. The protocol is more asynchronous: instead of each round taking a predetermined duration of time, each step of a round progresses after +2/3 of the step's votes are found and a timeout is reached, or immediately after +2/3 of matching votes (e.g. a PoLC for prevotes, or a commit for precommits).
|
36
docs/archived.wiki/CLI.md
Normal file
36
docs/archived.wiki/CLI.md
Normal file
@ -0,0 +1,36 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
# Tendermint CLI
|
||||
|
||||
Some notes on using the command line `tendermint` tool. See [[Installation]] to get it set up.
|
||||
|
||||
The help menu is available at `tendermint --help` and the version number at `tendermint version`.
|
||||
|
||||
## Directory Root
|
||||
|
||||
The default directory for blockchain data is `~/.tendermint`. Override this with the `TMHOME` environment variable or `--home` flag.
|
||||
|
||||
## Initialize
|
||||
|
||||
`tendermint init` will initialize the `~/.tendermint` (or `$TMHOME`) directory with a new private key (`priv_validator.json`), and a `genesis.json` containing the associated public key.
|
||||
This is all that's necessary to run a local testnet with one validator.
|
||||
|
||||
## Run a node
|
||||
|
||||
To run a tendermint node, use `tendermint node`.
|
||||
|
||||
Note by default it will try to connect to a tmsp app running on `0.0.0.0:46658`.
|
||||
Alternatively, specify an in-process tmsp app (eg. `tendermint node --proxy_app=dummy` to run the dummy app) or an different socket address (eg. `tendermint node --proxy_app=/var/run/tmsp.sock`).
|
||||
To use grpc instead of the raw tmsp socket protocol, set `--tmsp=grpc`.
|
||||
|
||||
[Fast-sync](Fast-sync) mode is enabled by default. It can be disabled with `--fast_sync=false`, and will turn off automatically once the node is synced up.
|
||||
|
||||
Specify seeds to connect to with a comma separated list, eg. `--seeds=seed1.mynodes.io:46656,seed2.mynodes.io:46656`
|
||||
|
||||
The logging level defaults to `notice`, but can be set to `error`, `warn`, `notice`, `info`, `debug` using `--log_level=<level>`.
|
||||
|
||||
## Reset
|
||||
|
||||
WARNING: UNSAFE. Only do this in development and only if you can afford to lose all blockchain data!
|
||||
|
||||
To reset a blockchain, remove the `~/.tendermint/data` directory and run `tendermint unsafe_reset_priv_validator`. This will reset the `priv_validator.json`, allowing you to sign blocks for heights you've already signed (doing this on a live network is considered a Byzantine fault!)
|
31
docs/archived.wiki/Configuration.md
Normal file
31
docs/archived.wiki/Configuration.md
Normal file
@ -0,0 +1,31 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
Tendermint can be configured via a TOML file in `$TMHOME/config/config.toml`. Some of these parameters can be overridden by command-line flags.
|
||||
|
||||
### Config parameters
|
||||
|
||||
The main config parameters are defined [here](https://github.com/tendermint/tendermint/blob/master/config/tendermint/config.go).
|
||||
|
||||
* `genesis_file`: The location of the genesis file. _Default_: `"$TMROOT/genesis.json"`
|
||||
* `proxy_app`: The TMSP app endpoint. _Default_: `"tcp://127.0.0.1:46658"`
|
||||
* `moniker`: Name of this node. _Default_: `"anonymous"`
|
||||
* `node_laddr`: TendermintCore listen address. _Default_: `"0.0.0.0:46656"`
|
||||
* `fast_sync`: Whether to sync faster from the block pool. _Default_: `true`
|
||||
* `seeds`: Initial peers to connect to. e.g. `"addr1:46656,addr2:46656"` _Default_: `""`
|
||||
* `skip_upnp`: Skip UPNP detection. _Default_: `false`
|
||||
* `addrbook_file`: Peer address book. _Default_: `"$TMROOT/addrbook.json"`. **NOT USED**
|
||||
* `priv_validator_file`: Validator private key file. _Default_: `"$TMROOT/priv_validator.json"`
|
||||
* `db_backend`: Database backend for the blockchain and TendermintCore state. `leveldb` or `memdb`. _Default_: `"leveldb"`
|
||||
* `db_dir`: Database dir. _Default_: `"$TMROOT/data"`
|
||||
* `log_level`: _Default_: `"info"`
|
||||
* `rpc_laddr`: RPC listen address. _Default_: `"0.0.0.0:46657"`
|
||||
* `prof_laddr`: Profile listen address. _Default_: `""`
|
||||
* `revision_file`: **TODO**
|
||||
* `cswal`: Consensus state WAL. _Default_: `"$TMROOT/data/cswal"`
|
||||
* `cswal_light`: Whether to use light-mode for Consensus state WAL. _Default_: `false`
|
||||
* `block_size`: Maximum number of block txs. _Default_: `10000`
|
||||
* `disable_data_hash`: Disable Merkle-izing block txs. _Default_: `false`
|
||||
* `timeout_*`: Various consensus timeout parameters **TODO**
|
||||
* `mempool_*`: Various mempool parameters **TODO**
|
||||
|
||||
**TODO** Document command-line flag parameters from [here](https://github.com/tendermint/tendermint/blob/master/cmd/tendermint/flags.go)
|
71
docs/archived.wiki/Contributing.md
Normal file
71
docs/archived.wiki/Contributing.md
Normal file
@ -0,0 +1,71 @@
|
||||
Thanks for considering making contributions to Tendermint!
|
||||
|
||||
Please follow standard github best practices: fork the repo, branch from the tip of develop, make some commits, and submit a pull request to develop. See the [open issues](https://github.com/tendermint/tendermint/issues) for things we need help with!
|
||||
|
||||
Please make sure to use `gofmt` before every commit - the easiest way to do this is have your editor run it for you upon saving a file.
|
||||
|
||||
# Forking
|
||||
|
||||
Please note that Go requires absolute paths. So to work on a fork of tendermint, you have to still work in `$GOPATH/src/github.com/tendermint/tendermint`. But you can check out a branch from your fork in that directory. For instance, to work on a branch from my fork, I would:
|
||||
|
||||
```
|
||||
cd $GOPATH/src/github.com/tendermint/tendermint
|
||||
git remote add ebuchman https://github.com/ebuchman/tendermint
|
||||
git fetch -a ebuchman
|
||||
git checkout -b mybranch ebuchman/mybranch
|
||||
```
|
||||
|
||||
Now I will have the branch `mybranch` from my fork at `github.com/ebuchman/tendermint` checked out, but locally it's in `$GOPATH/src/github.com/tendermint/tendermint`, rather than `$GOPATH/src/github.com/ebuchman/tendermint`, which should actually never exist.
|
||||
|
||||
Now I can make changes, commit, and push to my fork:
|
||||
|
||||
```
|
||||
< make some changes >
|
||||
git add -u
|
||||
git commit -m "... changes ..."
|
||||
git push ebuchman mybranch
|
||||
```
|
||||
|
||||
# Dependencies
|
||||
|
||||
We use [glide](https://github.com/masterminds/glide) to manage dependencies.
|
||||
That said, the master branch of every Tendermint repository should just build with `go get`, which means they should be kept up-to-date with their dependencies so we can get away with telling people they can just `go get` our software.
|
||||
Since some dependencies are not under our control, a third party may break our build, in which case we can fall back on `glide install`. Even for dependencies under our control, glide helps us keeps multiple repos in sync as they evolve. Anything with an executable, such as apps, tools, and the core, should use glide.
|
||||
|
||||
Run `bash scripts/glide/status.sh` to get a list of vendored dependencies that may not be up-to-date.
|
||||
|
||||
# Testing
|
||||
|
||||
All repos should be hooked up to circle.
|
||||
If they have `.go` files in the root directory, they will be automatically tested by circle using `go test -v -race ./...`. If not, they will need a `circle.yml`. Ideally, every repo has a `Makefile` that defines `make test` and includes its continuous integration status using a badge in the README.md.
|
||||
|
||||
# Branching Model and Release
|
||||
|
||||
User-facing repos should adhere to the branching model: http://nvie.com/posts/a-successful-git-branching-model/.
|
||||
That is, these repos should be well versioned, and any merge to master requires a version bump and tagged release.
|
||||
|
||||
Libraries need not follow the model strictly, but would be wise to,
|
||||
especially `go-p2p` and `go-rpc`, as their versions are referenced in tendermint core.
|
||||
|
||||
Release Checklist:
|
||||
|
||||
- development accumulates on `develop`
|
||||
- use `--no-ff` for all merges
|
||||
- prepare changelog/release issue
|
||||
- create `release-x.x.x` branch; ensure version is correct
|
||||
- push release branch, integration tests run (see `test_integrations` in Makefile).
|
||||
- make PR to master; link changelog
|
||||
- when tests pass, MERGE to master
|
||||
- tag the release and push to github or open the tag/release directly on github
|
||||
- bump version on develop
|
||||
- remove release branch
|
||||
|
||||
Automation TODOs
|
||||
- Push builds: docker, AMIs
|
||||
- Update github.com/tendermint/tendermint-stable with latest master and vendored deps for debian releases
|
||||
|
||||
TODO: sign releases
|
||||
|
||||
# Docker
|
||||
|
||||
We have loose dependencies on docker. The mintnet tool uses the `tendermint/tmbase` docker image, which is really just a fluffy Go image. The mintnet tooling runs an `init.sh` script in the container which clones the repo from github and installs it at run time, rather than building it into the image, for faster dev cycles.
|
71
docs/archived.wiki/Eris-Permissions.md
Normal file
71
docs/archived.wiki/Eris-Permissions.md
Normal file
@ -0,0 +1,71 @@
|
||||
Design goals:
|
||||
- permissions for all basic chain actions
|
||||
- native implementations for efficiency
|
||||
- permissions over a set of administrative native contracts
|
||||
- GlobalPermissions defaults for accounts with "unset" permission values
|
||||
- customizable set of "roles" for defining capabilities
|
||||
|
||||
Every account on a chain has a set of BasePermissions:
|
||||
|
||||
```
|
||||
type PermFlag uint64
|
||||
Root PermFlag = 1 << iota # Do anything (!)
|
||||
Send # SendTx, CALL to non-contract account
|
||||
Call # CallTx, CALL to a contract
|
||||
CreateContract # CallTx to empty address, CREATE
|
||||
CreateAccount # SendTx to non-existing account, CALL to non-existing account, (... ?)
|
||||
Bond # BondTx, participate in the consensus
|
||||
Name # NameTx, register in the name registry
|
||||
|
||||
HasBase # check if an account has permission
|
||||
SetBase # set a permission for an account
|
||||
UnsetBase # unset a permission for an account
|
||||
SetGlobal # set a global permission
|
||||
HasRole # check if an account has a role
|
||||
AddRole # add a role to an account
|
||||
RmRole # rm a role from an account
|
||||
```
|
||||
|
||||
Root gives you every permission - it should only be used for development and for initializing a production chain.
|
||||
|
||||
The HasBase and HasRole permissions allow us to isolate contracts. Maybe they're unnecessary.
|
||||
|
||||
The `genesis.json` specifies some initial accounts, along with their permissions. It also specifies the "global permissions", which are stored in account with address 0x00000000000000000000, and which are given by default to new accounts.
|
||||
|
||||
Each account exposes a permission struct:
|
||||
|
||||
```
|
||||
type Account struct{
|
||||
...
|
||||
Permissions *AccountPermissions
|
||||
}
|
||||
```
|
||||
|
||||
Account Permissions consists of Base permissions (which cover basic interaction with the chain and the secure native contracts) and a set of Roles.
|
||||
|
||||
```
|
||||
// Permissions for every account determining basic interaction with chain
|
||||
type BasePermissions struct{
|
||||
Flags uint64
|
||||
SetBit uint64 // unset bits default to global values
|
||||
}
|
||||
|
||||
BasePermissions by itself has no roles.
|
||||
|
||||
// Permissions for administrative personnel with the same set of BasePermissions
|
||||
// and arbitrary additional permissions on top.
|
||||
type AccountPermissions struct{
|
||||
Base BasePermissions
|
||||
Roles []string
|
||||
}
|
||||
```
|
||||
|
||||
Subtleties:
|
||||
|
||||
- since all permission updates are done through transactions in the consensus, bonded validators have a final say in everything (even root)
|
||||
- new accounts are created either by SendTx or CALL (opcode) to an unknown address. For SendTx, all inputs must have both Send permission and CreateAccount permission. For CALL, the contract must have both Call permission and CreateAccount permission
|
||||
- tokens are still a thing, there is gas, value transfers, etc. this is probably not terrible and can be used as general purpose tracking of activity on the network, where periodic refills via some native contract may be necessary.
|
||||
|
||||
|
||||
|
||||
|
13
docs/archived.wiki/Fast-Sync.md
Normal file
13
docs/archived.wiki/Fast-Sync.md
Normal file
@ -0,0 +1,13 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
# Background
|
||||
|
||||
In a proof of work blockchain, syncing with the chain is the same process as staying up-to-date with the consensus: download blocks, and look for the one with the most total work. In proof-of-stake, the consensus process is more complex, as it involves rounds of communication between the nodes to determine what block should be committed next. Using this process to sync up with the blockchain from scratch can take a very long time. It's much faster to just download blocks and check the merkle tree of validators than to run the real-time consensus gossip protocol.
|
||||
|
||||
# Fast Sync
|
||||
|
||||
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 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 has at least one peer and it's height is at least as high as the max reported peer height. See [the IsCaughtUp method](https://github.com/tendermint/tendermint/blob/381fe19335ba8825e04d1d0fefa5cac709bb7178/blockchain/pool.go#L143).
|
||||
|
||||
If we're lagging sufficiently, we should go back to fast syncing, but this is an open issue: https://github.com/tendermint/tendermint/issues/129
|
61
docs/archived.wiki/Genesis.md
Normal file
61
docs/archived.wiki/Genesis.md
Normal file
@ -0,0 +1,61 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
The `genesis.json` file in `$TMHOME/config` defines the initial Tendermint state upon genesis of the blockchain ([see definition](https://github.com/tendermint/tendermint/blob/master/types/genesis.go)).
|
||||
|
||||
NOTE: This does not (yet) specify the application state (e.g. initial distribution of tokens). Currently we leave it up to the application to load the initial application genesis state. In the future, we may include genesis SetOption messages that get passed from Tendermint to the app upon genesis.
|
||||
|
||||
### Fields
|
||||
|
||||
* `genesis_time`: Official time of blockchain start.
|
||||
* `chain_id`: ID of the blockchain. This must be unique for every blockchain. If your testnet blockchains do not have unique chain IDs, you will have a bad time.
|
||||
* `validators`:
|
||||
* `pub_key`: The first element specifies the pub_key type. 1 == Ed25519. The second element are the pubkey bytes.
|
||||
* `amount`: The validator's voting power.
|
||||
* `name`: Name of the validator (optional).
|
||||
* `app_hash`: The expected application hash (as returned by the `Commit` TMSP message) upon genesis. If the app's hash does not match, a warning message is printed.
|
||||
|
||||
### Sample genesis.json
|
||||
|
||||
This example is from the Basecoin mintnet example ([link to file](https://github.com/tendermint/mintnet/blob/master/examples/basecoin/mach1/core/genesis.json)).
|
||||
```json
|
||||
{
|
||||
"genesis_time": "2016-02-05T06:02:31.526Z",
|
||||
"chain_id": "chain-tTH4mi",
|
||||
"validators": [
|
||||
{
|
||||
"pub_key": [
|
||||
1,
|
||||
"9BC5112CB9614D91CE423FA8744885126CD9D08D9FC9D1F42E552D662BAA411E"
|
||||
],
|
||||
"amount": 1,
|
||||
"name": "mach1"
|
||||
},
|
||||
{
|
||||
"pub_key": [
|
||||
1,
|
||||
"F46A5543D51F31660D9F59653B4F96061A740FF7433E0DC1ECBC30BE8494DE06"
|
||||
],
|
||||
"amount": 1,
|
||||
"name": "mach2"
|
||||
},
|
||||
{
|
||||
"pub_key": [
|
||||
1,
|
||||
"0E7B423C1635FD07C0FC3603B736D5D27953C1C6CA865BB9392CD79DE1A682BB"
|
||||
],
|
||||
"amount": 1,
|
||||
"name": "mach3"
|
||||
},
|
||||
{
|
||||
"pub_key": [
|
||||
1,
|
||||
"4F49237B9A32EB50682EDD83C48CE9CDB1D02A7CFDADCFF6EC8C1FAADB358879"
|
||||
],
|
||||
"amount": 1,
|
||||
"name": "mach4"
|
||||
}
|
||||
],
|
||||
"app_hash": "15005165891224E721CB664D15CB972240F5703F"
|
||||
}
|
||||
```
|
||||
|
25
docs/archived.wiki/Home.md
Normal file
25
docs/archived.wiki/Home.md
Normal file
@ -0,0 +1,25 @@
|
||||
Please note we have moved the wiki content to our documentation website at https://tendermint.readthedocs.io/en/master/. This wiki is considered mostly deprecated but is left for historical purposes. The content for the documentation website is located in the [docs](https://github.com/tendermint/tendermint/tree/master/docs) directory and edits made there will update Read The Docs. That docs directory also contains the formal Tendermint specification.
|
||||
|
||||
### Tendermint Core
|
||||
|
||||
- [[Introduction]]
|
||||
- [[Validators]]
|
||||
- [[Byzantine Consensus Algorithm]]
|
||||
- [[Block Structure]]
|
||||
- [[RPC]]
|
||||
- [[Genesis]]
|
||||
- [[Configuration]]
|
||||
- [[Light Client Protocol]]
|
||||
- [[Roadmap for V2]]
|
||||
- [[Installation]]
|
||||
- [[CLI]]
|
||||
- [[Contributing]]
|
||||
- [[Application Developers]]
|
||||
- [[Application Architecture]]
|
||||
|
||||
### Sub-projects
|
||||
|
||||
* [ABCI](http://github.com/tendermint/abci)
|
||||
* [Go-Crypto](http://github.com/tendermint/go-crypto)
|
||||
* [Go-Wire](http://github.com/tendermint/go-wire)
|
||||
* [TmLibs](http://github.com/tendermint/tmlibs)
|
52
docs/archived.wiki/Installation.md
Normal file
52
docs/archived.wiki/Installation.md
Normal file
@ -0,0 +1,52 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
# Install Go
|
||||
|
||||
Make sure you have installed Go and [set the GOPATH](https://github.com/tendermint/tendermint/wiki/Setting-GOPATH).
|
||||
|
||||
# Install Tendermint
|
||||
|
||||
You should be able to install the latest with a simple `go get -u github.com/tendermint/tendermint/cmd/tendermint`.
|
||||
The `-u` makes sure all dependencies are updated as well.
|
||||
|
||||
See `tendermint version` and `tendermint --help` for more.
|
||||
|
||||
## Vendored dependencies
|
||||
|
||||
If updated dependencies break builds, install the vendored commits using `glide`.
|
||||
|
||||
First, install `glide`:
|
||||
|
||||
```
|
||||
go get github.com/Masterminds/glide
|
||||
```
|
||||
|
||||
Now, fetch the dependencies and install them with `glide` and `go`:
|
||||
|
||||
```
|
||||
cd $GOPATH/src/github.com/tendermint/tendermint
|
||||
glide install
|
||||
go install ./cmd/tendermint
|
||||
```
|
||||
|
||||
The latest Tendermint Core version is now installed. Check by running `tendermint version`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If `go get` failing bothers you, fetch the code using `git`:
|
||||
|
||||
```
|
||||
mkdir -p $GOPATH/src/github.com/tendermint
|
||||
git clone https://github.com/tendermint/tendermint $GOPATH/src/github.com/tendermint/tendermint
|
||||
```
|
||||
|
||||
# Run
|
||||
|
||||
To start a one-node blockchain with a simple in-process application:
|
||||
|
||||
```
|
||||
tendermint init
|
||||
tendermint node --proxy_app=dummy
|
||||
```
|
||||
|
||||
See the [application developers guide](https://github.com/tendermint/tendermint/wiki/Application-Developers) for more details on building and running applications.
|
11
docs/archived.wiki/Introduction.md
Normal file
11
docs/archived.wiki/Introduction.md
Normal file
@ -0,0 +1,11 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
Tendermint is a high-performance blockchain consensus engine that enables you to run Byzantine fault tolerant applications, written in any programming language, on many machines spread across the globe, with strong security guarantees. Unlike most blockchains, which require you to use an opinionated scripting language or environment, Tendermint makes no assumptions about the application, giving developers the utmost freedom to express their business logic using the tools right for them. This makes it possible to use any programming language, and even to integrate with existing codebases like Bitcoind, go-ethereum, or otherwise.
|
||||
|
||||
To achieve this flexibility, Tendermint and the application it powers run in separate UNIX processes, and speak to each other via a simple messaging protocol called [ABCI](https://github.com/tendermint/abci). See the [application developers guide](https://github.com/tendermint/tendermint/wiki/Application-Developers) for more on ABCI.
|
||||
|
||||
In addition to flexibility for application developers, the main benefits of using Tendermint (as opposed to using Proof-of-Work systems or other BFT consensus engines), are those guaranteed by the [Tendermint consensus algorithm](Byzantine-Consensus-Algorithm):
|
||||
|
||||
* __speed__: Tendermint blocks can commit to finality in the order of 1 second. Tendermint can handle transaction volume at the rate of 10,000 transactions per second for 250byte transactions. The bottleneck is in the application.
|
||||
* __security__: Tendermint consensus is not just fault tolerant, it's optimally Byzantine fault-tolerant, with accountability. When the blockchain forks, there is a way to determine liability.
|
||||
* __scalability__: Unlike PoW, running parallel blockchains does not diminish the speed or security of each chain, so sharding is trivial. The algorithm can scale to hundreds or thousands of validators (depending on desired block times), and will only get better over time with advances in bandwidth and cpu capacity.
|
17
docs/archived.wiki/Light-Client-Protocol.md
Normal file
17
docs/archived.wiki/Light-Client-Protocol.md
Normal file
@ -0,0 +1,17 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
Light clients are an important part of the complete blockchain system for most applications. Tendermint provides unique speed and security properties for light client applications.
|
||||
|
||||
## Overview
|
||||
|
||||
The objective of the light client protocol is to get a [commit](Validators#committing-a-block) for a recent [block hash](Block-Structure#block-hash) where the commit includes a majority of signatures from the last known validator set. From there, all the application state is verifiable with [merkle proofs](Merkle-Trees#iavl-tree).
|
||||
|
||||
### Syncing the Validator Set
|
||||
|
||||
[[https://github.com/tendermint/tendermint/wiki/Light-client-syncing-of-validator-changes]]
|
||||
|
||||
## Properties
|
||||
|
||||
- You get the full collateralized security benefits of Tendermint; No need to wait for confirmations.
|
||||
- You get the full speed benefits of Tendermint; Transactions commit instantly.
|
||||
- You can get the most recent version of the application state non-interactively (without committing anything to the blockchain). For example, this means that you can get the most recent value of a name from the name-registry without worrying about fork censorship attacks, without posting a commit and waiting for confirmations. It's fast, secure, and free!
|
@ -0,0 +1,57 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
Light-client syncing of validator-changes
|
||||
=========================================
|
||||
|
||||
Let's take a look at the current Block Header structure.
|
||||
|
||||
```golang
|
||||
type Header struct {
|
||||
ChainID string `json:"chain_id"`
|
||||
Height int `json:"height"`
|
||||
Time time.Time `json:"time"`
|
||||
NumTxs int `json:"num_txs"` // XXX: Can we get rid of this?
|
||||
LastBlockID BlockID `json:"last_block_id"`
|
||||
LastCommitHash []byte `json:"last_commit_hash"` // commit from validators from the last block
|
||||
DataHash []byte `json:"data_hash"` // transactions
|
||||
ValidatorsHash []byte `json:"validators_hash"` // validators for the current block
|
||||
AppHash []byte `json:"app_hash"` // state after txs from the previous block
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Gradual changes
|
||||
---------------
|
||||
|
||||
This is assuming that there are many validators, and that the total amount of voting power that changes per block is small (e.g. << 1/3 of the voting power) and that the change is gradual.
|
||||
|
||||
Lets say we have the validator set V(H) for block H. That is, +2/3 of V(H) have signed block H's blockhash. Lets say the light client trusts block H. As long as the validator-set changes are gradual, for many subsequent blocks, even though the validator set is not exactly V(H), we will be able to find a sufficinet number of signatures for block H+x (x > 0) where the signatures come from the set V(H). What is a sufficient number of signatures? Well, it only needs to be 1/3+ because these validators are signing blocks at H+x whose Header includes the ValidatorsHash hash. While 1/3+ signatures isn't enough to make a commit, e.g. they may move on to subsequent rounds and actually commit another block, all valid proposals for block H+x should include the same identical ValidatorsHash because it was determined by the previous transactions that were committed at block H+x-1 and prior.
|
||||
|
||||
So, we can find the largest x (where x < unbonding period) such that the light client is convinced of the new validator set. And in this way the light-client can fast-forward, and as long as the validator-set changes are very gradual, the light client need only sync the validator set a few times, and still get the 1/3+ economic guarantee. This is assuming that validators are slashed for signing a block that includes an invalid header.ValidatorsHash. (If we don't assume this we can do something else, but more on that later)
|
||||
|
||||
|
||||
Sudden changes
|
||||
--------------
|
||||
|
||||
This is about when the validator-set can change dramatically from 1 block to another.
|
||||
|
||||
Header.ValidatorsHash represents the validator set that is responsible for signing that block.
|
||||
|
||||
Lets say we have the Commit for a block. Now, the transactions (Merkleized into DataHash) of this block haven't been executed yet, so we haven't gotten the result of EndBlock which determines who the next validators will be. But after the execution of this block, EndBlock will return validator diffs, and the next block will need to be signed by the updated validator set. (according to the current implementation of Tendermint)
|
||||
|
||||
This is unfortunate, because what we really want is something like this:
|
||||
|
||||
```golang
|
||||
type Header struct {
|
||||
...
|
||||
ValidatorsHash []byte `json:"validators_hash"` // validators for the current block
|
||||
NextValidatorsHash []byte `json:"validators_hash"` // validators for the next block
|
||||
AppHash []byte `json:"app_hash"` // state after txs from the previous block
|
||||
}
|
||||
```
|
||||
|
||||
Then we can look at the Commit for the block.Header, which would be signed by +2/3 of the validators represented by ValidatorsHash, and a light client can know how the validator-set is to evolve for the next block.
|
||||
|
||||
Maybe we can delay the effect of EndBlock>validator diffs for 1 block, and thereby allow us to include this NextValidatorsHash. Are there other good solutions?
|
||||
|
||||
Note to self: I think we want to make this change anyways in order to allow for lightweight validator signing devices that can always update its locally cached validator-set, and ensure that it never signs a block with an invalid header.ValidatorsHash, to enforce slashing for signing a block with the wrong header.ValidatorsHash.
|
47
docs/archived.wiki/Merkle-Trees.md
Normal file
47
docs/archived.wiki/Merkle-Trees.md
Normal file
@ -0,0 +1,47 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
For an overview of Merkle trees, see [wikipedia](https://en.wikipedia.org/wiki/Merkle_tree).
|
||||
|
||||
There are two types of Merkle trees used in Tendermint.
|
||||
|
||||
- [`IAVL+ Tree`](#iavl-tree): An immutable self-balancing binary tree for persistent application state
|
||||
- [`Simple Tree`](#simple-tree): A simple compact binary tree for a static list of items
|
||||
|
||||
## IAVL+ Tree
|
||||
|
||||
- see https://github.com/tendermint/iavl
|
||||
|
||||
The purpose of this data structure is to provide persistent storage for key-value pairs (e.g. account state, name-registrar data, and per-contract data) such that a deterministic merkle root hash can be computed. The tree is balanced using a variant of the [AVL algorithm](http://en.wikipedia.org/wiki/AVL_tree) so all operations are O(log(n)).
|
||||
|
||||
Nodes of this tree are immutable and indexed by its hash. Thus any node serves as an immutable snapshot which lets us stage uncommitted transactions from the mempool cheaply, and we can instantly roll back to the last committed state to process transactions of a newly committed block (which may not be the same set of transactions as those from the mempool).
|
||||
|
||||
In an AVL tree, the heights of the two child subtrees of any node differ by at most one. Whenever this condition is violated upon an update, the tree is rebalanced by creating O(log(n)) new nodes that point to unmodified nodes of the old tree. In the original AVL algorithm, inner nodes can also hold key-value pairs. The AVL+ algorithm (note the plus) modifies the AVL algorithm to keep all values on leaf nodes, while only using branch-nodes to store keys. This simplifies the algorithm while minimizing the size of merkle proofs
|
||||
|
||||
In Ethereum, the analog is the [Patricia trie](http://en.wikipedia.org/wiki/Radix_tree). There are tradeoffs. Keys do not need to be hashed prior to insertion in IAVL+ trees, so this provides faster iteration in the key space which may benefit some applications. The logic is simpler to implement, requiring only two types of nodes -- inner nodes and leaf nodes. The IAVL+ tree is a binary tree, so merkle proofs are much shorter than the base 16 Patricia trie. On the other hand, while IAVL+ trees provide a deterministic merkle root hash, it depends on the order of updates. In practice this shouldn't be a problem, since you can efficiently encode the tree structure when serializing the tree contents.
|
||||
|
||||
## Simple Tree
|
||||
|
||||
For merkelizing smaller static lists, use the Simple Tree. The transactions and validation signatures of a block are hashed using this simple merkle tree logic.
|
||||
|
||||
If the number of items is not a power of two, the tree will not be full and some leaf nodes will be at different levels. Simple Tree tries to keep both sides of the tree the same size, but the left side may be one greater.
|
||||
|
||||
```
|
||||
Simple Tree with 6 items Simple Tree with 7 items
|
||||
|
||||
* *
|
||||
/ \ / \
|
||||
/ \ / \
|
||||
/ \ / \
|
||||
/ \ / \
|
||||
* * * *
|
||||
/ \ / \ / \ / \
|
||||
/ \ / \ / \ / \
|
||||
/ \ / \ / \ / \
|
||||
* h2 * h5 * * * h6
|
||||
/ \ / \ / \ / \ / \
|
||||
h0 h1 h3 h4 h0 h1 h2 h3 h4 h5
|
||||
```
|
||||
|
||||
### Simple Tree with Dictionaries
|
||||
|
||||
The Simple Tree is used to merkelize a list of items, so to merkelize a (short) dictionary of key-value pairs, encode the dictionary as an ordered list of `KVPair` structs. The block hash is such a hash derived from all the fields of the block `Header`. The state hash is similarly derived.
|
32
docs/archived.wiki/P2P-Authenticated-Encryption.md
Normal file
32
docs/archived.wiki/P2P-Authenticated-Encryption.md
Normal file
@ -0,0 +1,32 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
The Tendermint p2p protocol uses an authenticated encryption scheme based on the [Station-to-Station Protocol](https://en.wikipedia.org/wiki/Station-to-Station_protocol). The implementation uses [golang's](https://godoc.org/golang.org/x/crypto/nacl/box) [nacl box](http://nacl.cr.yp.to/box.html) for the actual authenticated encryption algorithm.
|
||||
|
||||
Each peer generates an ED25519 key-pair to use as a persistent (long-term) id.
|
||||
|
||||
When two peers establish a TCP connection, they first each generate an ephemeral ED25519 key-pair to use for this session, and send each other their respective ephemeral public keys. This happens in the clear.
|
||||
|
||||
They then each compute the shared secret. The shared secret is the multiplication of the peer's ephemeral private key by the other peer's ephemeral public key. The result is the same for both peers by the magic of [elliptic curves](https://en.wikipedia.org/wiki/Elliptic_curve_cryptography). The shared secret is used as the symmetric key for the encryption algorithm.
|
||||
|
||||
The two ephemeral public keys are sorted to establish a canonical order. Then a 24-byte nonce is generated by concatenating the public keys and hashing them with Ripemd160. Note Ripemd160 produces 20byte hashes, so the nonce ends with four 0s.
|
||||
|
||||
The nonce is used to seed the encryption - it is critical that the same nonce never be used twice with the same private key. For convenience, the last bit of the nonce is flipped, giving us two nonces: one for encrypting our own messages, one for decrypting our peer's. Which ever peer has the higher public key uses the "bit-flipped" nonce for encryption.
|
||||
|
||||
Now, a challenge is generated by concatenating the ephemeral public keys and taking the SHA256 hash.
|
||||
|
||||
Each peer signs the challenge with their persistent private key, and sends the other peer an AuthSigMsg, containing their persistent public key and the signature. On receiving an AuthSigMsg, the peer verifies the signature.
|
||||
|
||||
The peers are now authenticated.
|
||||
|
||||
All future communications can now be encrypted using the shared secret and the generated nonces, where each nonce is incremented by one each time it is used. The communications maintain Perfect Forward Secrecy, as the persistent key pair was not used for generating secrets - only for authenticating.
|
||||
|
||||
Caveat
|
||||
------
|
||||
This system is still vulnerable to a Man-In-The-Middle attack if the persistent public key of the remote node is not known in advance. The only way to mitigate this is with a public key authentication system, such as the Web-of-Trust or Certificate Authorities. In our case, we can use the blockchain itself as a certificate authority to ensure that we are connected to at least one validator [TODO](Future-Work).
|
||||
|
||||
Links
|
||||
------
|
||||
|
||||
- [Implementation](https://github.com/tendermint/tendermint/blob/develop/p2p/secret_connection.go#L49 for implementation)
|
||||
- [Original STS paper by Whitfield Diffie, Paul C. van Oorschot and Michael J. Wiener](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.216.6107&rep=rep1&type=pdf)
|
||||
- [Further work on secret handshakes](https://dominictarr.github.io/secret-handshake-paper/shs.pdf)
|
25
docs/archived.wiki/Potential-ABCI-apps.md
Normal file
25
docs/archived.wiki/Potential-ABCI-apps.md
Normal file
@ -0,0 +1,25 @@
|
||||
# List of ideas for ABCI apps
|
||||
Let's collect as many ideas for ABCI apps as possible with varying complexity so that interested people have a starting point to build something. Later on this could lead to the community writing tutorials and guides around building these first apps and what to watch out for in terms of building deterministic and fast ABCI apps. Overall it will help us to onboard new developers which should increase adoption and expand the ecosystem.
|
||||
|
||||
**ABCI Apps:**
|
||||
* Traceability app
|
||||
* ICO-specific app. With possibility to make several funding rounds with reasonable caps and milestone.
|
||||
* Blockchain bridges
|
||||
* The best e-cash ever
|
||||
* App that tracks shares and ownership of companies and pays dividends
|
||||
* Stock exchange
|
||||
* Invoicing app
|
||||
* Voting/governance systems
|
||||
* IPFS - enabling file sharing
|
||||
* E-voting for board rooms
|
||||
* Trading one type of coin for another with greater liquidity
|
||||
* Digitising physical assets such as silver
|
||||
* Magic the gathering - creating creative and tradable tokens that link back to real-life objects
|
||||
* [Bravenewcoin](https://bravenewcoin.com/assets/Whitepapers/A-Note-on-Cryptocurrency-Stabilisation-Seigniorage-Shares.pdf)
|
||||
* [Permissioned Blocks](https://github.com/autocontracts/permissioned-blocks/blob/master/whitepaper.md)
|
||||
* I was that guy that won one of the Consensus Hackathon prizes for a mircro-insurance solution to help farmers in Africa. I combined both Ethermint and IPFS in the solution, and discussed during my presentation about the benefits of using the Tendermint consensus engine over the vanilla Ethereum POW engine in this design. Higher throughput and lower gas fees.
|
||||
I've spent the past 6 months in my spare time developing what I've called "Permissioned Blocks" and have written the following technical white paper about the design:
|
||||
https://github.com/autocontracts/permissioned-blocks/blob/master/whitepaper.md
|
||||
It's basically p2p file sharing with permissions but also has the ability to make smart contract state information private. A colleague has further developed on my ideas with this paper:
|
||||
https://gist.github.com/shmookey/e1df57beeea0a2b8e6014bce6c69c0a4
|
||||
* High Frequency Energy Trading
|
78
docs/archived.wiki/RPC.md
Normal file
78
docs/archived.wiki/RPC.md
Normal file
@ -0,0 +1,78 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
Tendermint supports the following RPC protocols:
|
||||
* URI over HTTP
|
||||
* JSONRPC over HTTP
|
||||
* JSONRPC over websockets
|
||||
|
||||
### Configuration
|
||||
|
||||
Set the `rpc_laddr` config parameter in the `$TMHOME/config/config.toml` file or the `--rpc-laddr` command-line flag to the desired listener:port setting. Default: `0.0.0.0:46657`.
|
||||
|
||||
### URI/HTTP
|
||||
|
||||
Example request:
|
||||
```bash
|
||||
TXBYTES="<HEXBYTES>"
|
||||
curl "http://localhost:46657/broadcast_tx_sync?tx=%22$TXBYTES%22" | jq
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{"jsonrpc":"2.0","id":"","result":[96,{"code":0,"data":"","log":""}],"error":""}
|
||||
|
||||
```
|
||||
The first entry in the result-array (96) is the method this response correlates with. 96 refers to "ResultTypeBroadcastTx", see [responses.go](https://github.com/tendermint/tendermint/blob/master/rpc/core/types/responses.go) for a complete overview.
|
||||
|
||||
|
||||
### JSONRPC/HTTP
|
||||
|
||||
JSONRPC requests can be POST'd to the root RPC endpoint via HTTP (e.g. `http://localhost:46657/`).
|
||||
|
||||
Example request:
|
||||
```json
|
||||
{
|
||||
"method": "broadcast_tx_sync",
|
||||
"jsonrpc": "2.0",
|
||||
"params": [ "<HEXBYTES>" ],
|
||||
"id": "dontcare"
|
||||
}
|
||||
```
|
||||
|
||||
### JSONRPC/websockets
|
||||
|
||||
JSONRPC requests can be made via websocket. The websocket endpoint is at `/websocket`, e.g. `http://localhost:46657/websocket`. Asynchronous RPC functions like event `subscribe` and `unsubscribe` are only available via websockets.
|
||||
|
||||
NOTE: see [this issue](https://github.com/tendermint/tendermint/issues/536#issuecomment-312788905) for additional information on transaction formats.
|
||||
|
||||
### Endpoints
|
||||
|
||||
An HTTP Get request to the root RPC endpoint (e.g. `http://localhost:46657`) shows a list of available endpoints.
|
||||
|
||||
```
|
||||
Available endpoints:
|
||||
http://localhost:46657/dump_consensus_state
|
||||
http://localhost:46657/genesis
|
||||
http://localhost:46657/net_info
|
||||
http://localhost:46657/num_unconfirmed_txs
|
||||
http://localhost:46657/status
|
||||
http://localhost:46657/unconfirmed_txs
|
||||
http://localhost:46657/unsafe_stop_cpu_profiler
|
||||
http://localhost:46657/validators
|
||||
|
||||
Endpoints that require arguments:
|
||||
http://localhost:46657/block?height=_
|
||||
http://localhost:46657/blockchain?minHeight=_&maxHeight=_
|
||||
http://localhost:46657/broadcast_tx_async?tx=_
|
||||
http://localhost:46657/broadcast_tx_sync?tx=_
|
||||
http://localhost:46657/dial_seeds?seeds=_
|
||||
http://localhost:46657/subscribe?event=_
|
||||
http://localhost:46657/unsafe_set_config?type=_&key=_&value=_
|
||||
http://localhost:46657/unsafe_start_cpu_profiler?filename=_
|
||||
http://localhost:46657/unsafe_write_heap_profile?filename=_
|
||||
http://localhost:46657/unsubscribe?event=_
|
||||
```
|
||||
|
||||
### More Examples
|
||||
|
||||
See the various bash tests using curl in `test/`, and examples using the `Go` API in `rpc/test/`. Tendermint uses the [go-rpc](https://github.com/tendermint/go-rpc) library, with docs at https://godoc.org/github.com/tendermint/go-rpc/client.
|
4
docs/archived.wiki/Roadmap-for-V2.asciidoc
Normal file
4
docs/archived.wiki/Roadmap-for-V2.asciidoc
Normal file
@ -0,0 +1,4 @@
|
||||
* Allow applications (through ABCI) to update the ValidatorSet.
|
||||
* Use the chain as its own CA for its nodes and validators.
|
||||
* Graceful handling/recovery for apps that have non-determinism or fail to halt
|
||||
* Consensus version 0.8: Update so `Commit` is not just +2/3 precommits for a block, but the entire `JSet`. While the commit size may grow unbounded in size, it makes a fork immediately slash a +1/3 Byzantine subset of validators.
|
11
docs/archived.wiki/Sample-Applications.md
Normal file
11
docs/archived.wiki/Sample-Applications.md
Normal file
@ -0,0 +1,11 @@
|
||||
## Name Resolution
|
||||
|
||||
One of the best ways to understand how to build applications on Tendermint is to dive into the implementation of `NameTx` (See [1](https://github.com/tendermint/tendermint/blob/develop/types/tx.go#L205), [2](https://github.com/tendermint/tendermint/blob/develop/state/execution.go#L514), and also [DNS](https://github.com/eris-ltd/mindy)).
|
||||
|
||||
The most interesting thing about name-resolution applications on Tendermint is the speed and security offered by Tendermint's [[Light Client Protocol]].
|
||||
|
||||
## Etc
|
||||
- [DNS](https://github.com/eris-ltd/mindy)
|
||||
- [[Payment Channels]]
|
||||
- [[Actually Secure Certificate Authority]]
|
||||
- [[Mesh Networks]]
|
54
docs/archived.wiki/Secure-Native-Contracts.md
Normal file
54
docs/archived.wiki/Secure-Native-Contracts.md
Normal file
@ -0,0 +1,54 @@
|
||||
_UPDATE: This page is outdated. Secure Native contracts have been implemented, though not "DestroyStake()". That's not a bad idea._
|
||||
|
||||
Chain modification and control is accessed through secure native contracts (SNC here for short).
|
||||
|
||||
Each SNC should have an associated permission stored with the account which controls access to that contract. The format of the Native contract permission should be identical to the base chain permissions described in [the Permissions Wiki page](https://github.com/tendermint/tendermint/wiki/Permissions).
|
||||
|
||||
In order to access each SNC and perform its action the caller must have either the correct SNC perm or the Root base permission.
|
||||
|
||||
|
||||
## Secure Native Contracts we need (names subject to bettering):
|
||||
|
||||
**getPermValue(permname, account)**
|
||||
Returns: the permission value for the provided account, permname pair
|
||||
Default global SNC perm value (GPV): True (Everyone should be able to access this perm by default as it is informational only)
|
||||
|
||||
**setPermValue(permname, account, value)** - Sets permission value for account for permission permname.
|
||||
Returns: 0 - Failure (lack of permissions, perm doesn't exist etc) 1 - permission successfully set
|
||||
Default GPV: False
|
||||
|
||||
**unsetPerm(permname, account)** - Set the "set/unset" bit to "unset" - restoring the global value to the account
|
||||
Returns: 0 - Failure, 1 - permission successfully set
|
||||
Default GPV: False
|
||||
|
||||
**setPermGlobalValue(permname, value)** - Sets global value for permission permname
|
||||
Returns: 0 - Failure to complete, 1 - Successfully set
|
||||
Default GPV: False
|
||||
|
||||
**clearPerm(permname)** - Resets all accounts to "unset" for permission permname
|
||||
Returns: 0 - Failure to complete, 1 - Successful
|
||||
Default GPV: False
|
||||
|
||||
---------
|
||||
If general "dynamic" perm creation allowed the above should work for those as well as the following
|
||||
|
||||
**addPerm(permname)** - Creates new "dynamic" perm
|
||||
Returns: 0 - Failure, 1 - Success
|
||||
Default GPV: False
|
||||
|
||||
**rmPerm(permname)** - Removes a "dynamic" perm (Optional)
|
||||
Returns: 0 - Failure, 1 - Success
|
||||
Default GPV: False
|
||||
|
||||
----------
|
||||
Others
|
||||
|
||||
If we are building this lovely framework for secure access to chain properties we might as well expose some other core abilities right?
|
||||
|
||||
for example:
|
||||
|
||||
**deleteStake(account)** - Remove all stake (balance? not sure about the proper term) owned by account (adjust total stake accordingly)
|
||||
|
||||
**setStake(account)** - allows setting to an arbitrary value.
|
||||
|
||||
etc. Not sure there are that many more. But anything that someone might want to control the in course of administrating their chain should be considered for addition to this list. also any informational aspects not normally accessible through vm opcodes.
|
18
docs/archived.wiki/Setting-GOPATH.md
Normal file
18
docs/archived.wiki/Setting-GOPATH.md
Normal file
@ -0,0 +1,18 @@
|
||||
This page helps you set your GOPATH environment variable after [installing go](https://golang.org/doc/install).
|
||||
|
||||
<hr/>
|
||||
|
||||
The GOPATH environment variable is a directory where all Go projects live.
|
||||
|
||||
First, make your GOPATH directory
|
||||
|
||||
```bash
|
||||
> mkdir ~/go
|
||||
```
|
||||
|
||||
Then, set environment variables in your shell startup script. On OS X, this is `~/.bash_profile`. For different operating systems or shells, the path may be different. For Ubuntu, it may be `~/.profile` or `~/.bashrc`.
|
||||
|
||||
```bash
|
||||
echo export GOPATH=\"\$HOME/go\" >> ~/.bash_profile
|
||||
echo export PATH=\"\$PATH:\$GOPATH/bin\" >> ~/.bash_profile
|
||||
```
|
3
docs/archived.wiki/Users.md
Normal file
3
docs/archived.wiki/Users.md
Normal file
@ -0,0 +1,3 @@
|
||||
The tendermint ecosystem is growing!
|
||||
|
||||
See https://tendermint.com/ecosytem for more information.
|
21
docs/archived.wiki/Validators.md
Normal file
21
docs/archived.wiki/Validators.md
Normal file
@ -0,0 +1,21 @@
|
||||
NOTE: this wiki is mostly deprecated and left for archival purposes. Please see the [documentation website](http://tendermint.readthedocs.io/en/master/) which is built from the [docs directory](https://github.com/tendermint/tendermint/tree/master/docs). Additional information about the specification can also be found in that directory.
|
||||
|
||||
Validators are responsible for committing new blocks in the blockchain.
|
||||
These validators participate in the consensus protocol by broadcasting _votes_ which contain cryptographic signatures signed by each validator's public key.
|
||||
|
||||
Some Proof-of-Stake consensus algorithms aim to create a "completely" decentralized system where all stakeholders (even those who are not always available online) participate in the committing of blocks. Tendermint has a different approach to block creation. Validators are expected to be online, and the set of validators is permissioned/curated by some external process. Proof-of-stake is not required, but can be implemented on top of Tendermint consensus. That is, validators may be required to post collateral on-chain, off-chain, or may not be required to post any collateral at all.
|
||||
|
||||
Validators have a cryptographic key-pair and an associated amount of "voting power". Voting power need not be the same.
|
||||
|
||||
## Becoming a Validator
|
||||
|
||||
There are two ways to become validator.
|
||||
|
||||
1. They can be pre-established in the [genesis state](Genesis-State)
|
||||
2. The [ABCI app responds to the EndBlock message](https://github.com/tendermint/abci) with changes to the existing validator set.
|
||||
|
||||
## Committing a Block
|
||||
|
||||
_+2/3 is short for "more than 2/3"_
|
||||
|
||||
A block is committed when +2/3 of the validator set sign [precommit votes](Block-Structure#vote) for that block at the same [round](Byzantine-Consensus-Algorithm). The +2/3 set of precommit votes is called a [_commit_](Block-Structure#commit). While any +2/3 set of precommits for the same block at the same height&round can serve as validation, the canonical commit is included in the next block (see [LastCommit](Block-Structure)).
|
117
docs/archived.wiki/Wire-Protocol.md
Normal file
117
docs/archived.wiki/Wire-Protocol.md
Normal file
@ -0,0 +1,117 @@
|
||||
The [Tendermint wire protocol](https://github.com/tendermint/tendermint/go-wire) encodes data in [c-style binary](#binary) and [JSON](#json) form.
|
||||
|
||||
## Supported types
|
||||
|
||||
- Primitive types
|
||||
- `uint8` (aka `byte`), `uint16`, `uint32`, `uint64`
|
||||
- `int8`, `int16`, `int32`, `int64`
|
||||
- `uint`, `int`: variable length (un)signed integers
|
||||
- `string`, `[]byte`
|
||||
- `time`
|
||||
- Derived types
|
||||
- structs
|
||||
- var-length arrays of a particular type
|
||||
- fixed-length arrays of a particular type
|
||||
- interfaces: registered union types preceded by a `type byte`
|
||||
- pointers
|
||||
|
||||
## Binary
|
||||
|
||||
**Fixed-length primitive types** are encoded with 1,2,3, or 4 big-endian bytes.
|
||||
- `uint8` (aka `byte`), `uint16`, `uint32`, `uint64`: takes 1,2,3, and 4 bytes respectively
|
||||
- `int8`, `int16`, `int32`, `int64`: takes 1,2,3, and 4 bytes respectively
|
||||
- `time`: `int64` representation of nanoseconds since epoch
|
||||
|
||||
**Variable-length integers** are encoded with a single leading byte representing the length of the following big-endian bytes. For signed negative integers, the most significant bit of the leading byte is a 1.
|
||||
|
||||
- `uint`: 1-byte length prefixed variable-size (0 ~ 255 bytes) unsigned integers
|
||||
- `int`: 1-byte length prefixed variable-size (0 ~ 127 bytes) signed integers
|
||||
|
||||
NOTE: While the number 0 (zero) is encoded with a single byte `x00`, the number 1 (one) takes two bytes to represent: `x0101`. This isn't the most efficient representation, but the rules are easier to remember.
|
||||
|
||||
| number | binary `uint` | binary `int` |
|
||||
| ------------ | ------------- | ------------- |
|
||||
| 0 | `x00` | `x00` |
|
||||
| 1 | `x0101` | `x0101` |
|
||||
| 2 | `x0102` | `x0102` |
|
||||
| 256 | `x020100` | `x020100` |
|
||||
| 2^(127*8)-1 | `x7FFFFF...` | `x7FFFFF...` |
|
||||
| 2^(127*8) | `x800100...` | overflow |
|
||||
| 2^(255*8)-1 | `xFFFFFF...` | overflow |
|
||||
| -1 | n/a | `x8101` |
|
||||
| -2 | n/a | `x8102` |
|
||||
| -256 | n/a | `x820100` |
|
||||
|
||||
**Structures** are encoded by encoding the field values in order of declaration.
|
||||
|
||||
```go
|
||||
type Foo struct {
|
||||
MyString string
|
||||
MyUint32 uint32
|
||||
}
|
||||
var foo = Foo{"626172", math.MaxUint32}
|
||||
|
||||
/* The binary representation of foo:
|
||||
0103626172FFFFFFFF
|
||||
0103: `int` encoded length of string, here 3
|
||||
626172: 3 bytes of string "bar"
|
||||
FFFFFFFF: 4 bytes of uint32 MaxUint32
|
||||
*/
|
||||
```
|
||||
|
||||
**Variable-length arrays** are encoded with a leading `int` denoting the length of the array followed by the binary representation of the items. **Fixed-length arrays** are similar but aren't preceded by the leading `int`.
|
||||
|
||||
```go
|
||||
foos := []Foo{foo, foo}
|
||||
|
||||
/* The binary representation of foos:
|
||||
01020103626172FFFFFFFF0103626172FFFFFFFF
|
||||
0102: `int` encoded length of array, here 2
|
||||
0103626172FFFFFFFF: the first `foo`
|
||||
0103626172FFFFFFFF: the second `foo`
|
||||
*/
|
||||
|
||||
foos := [2]Foo{foo, foo} // fixed-length array
|
||||
|
||||
/* The binary representation of foos:
|
||||
0103626172FFFFFFFF0103626172FFFFFFFF
|
||||
0103626172FFFFFFFF: the first `foo`
|
||||
0103626172FFFFFFFF: the second `foo`
|
||||
*/
|
||||
```
|
||||
|
||||
**Interfaces** can represent one of any number of concrete types. The concrete types of an interface must first be declared with their corresponding `type byte`. An interface is then encoded with the leading `type byte`, then the binary encoding of the underlying concrete type.
|
||||
|
||||
NOTE: The byte `x00` is reserved for the `nil` interface value and `nil` pointer values.
|
||||
|
||||
```go
|
||||
type Animal interface{}
|
||||
type Dog uint32
|
||||
type Cat string
|
||||
|
||||
RegisterInterface(
|
||||
struct{ Animal }{}, // Convenience for referencing the 'Animal' interface
|
||||
ConcreteType{Dog(0), 0x01}, // Register the byte 0x01 to denote a Dog
|
||||
ConcreteType{Cat(""), 0x02}, // Register the byte 0x02 to denote a Cat
|
||||
)
|
||||
|
||||
var animal Animal = Dog(02)
|
||||
|
||||
/* The binary representation of animal:
|
||||
010102
|
||||
01: the type byte for a `Dog`
|
||||
0102: the bytes of Dog(02)
|
||||
*/
|
||||
```
|
||||
|
||||
**Pointers** are encoded with a single leading byte `x00` for `nil` pointers, otherwise encoded with a leading byte `x01` followed by the binary encoding of the value pointed to.
|
||||
|
||||
NOTE: It's easy to convert pointer types into interface types, since the `type byte` `x00` is always `nil`.
|
||||
|
||||
## JSON
|
||||
|
||||
The JSON codec is compatible with the [`binary`](#binary) codec, and is fairly intuitive if you're already familiar with golang's JSON encoding. Some quirks are noted below:
|
||||
|
||||
- variable-length and fixed-length bytes are encoded as uppercase hexadecimal strings
|
||||
- interface values are encoded as an array of two items: `[type_byte, concrete_value]`
|
||||
- times are encoded as rfc2822 strings
|
10
docs/archived.wiki/_Sidebar.md
Normal file
10
docs/archived.wiki/_Sidebar.md
Normal file
@ -0,0 +1,10 @@
|
||||
### Tendermint Core
|
||||
|
||||
- [[Introduction]]
|
||||
- [[Validators]]
|
||||
- [[Byzantine Consensus Algorithm]]
|
||||
- [[Block Structure]]
|
||||
- [[RPC]]
|
||||
- [[Genesis]]
|
||||
- [[Configuration]]
|
||||
- [[Light Client Protocol]]
|
Loading…
x
Reference in New Issue
Block a user