mirror of
https://github.com/fluencelabs/tendermint
synced 2025-08-01 04:31:57 +00:00
Merge branch 'master' into ancaz/blockchain_reactor_reorg
This commit is contained in:
@@ -44,7 +44,7 @@ module.exports = {
|
||||
"/app-dev/app-development",
|
||||
"/app-dev/subscribing-to-events-via-websocket",
|
||||
"/app-dev/indexing-transactions",
|
||||
"/app-dev/abci-spec",
|
||||
"/spec/abci/abci",
|
||||
"/app-dev/ecosystem"
|
||||
]
|
||||
},
|
||||
|
@@ -326,10 +326,18 @@ application easily in any language.
|
||||
We have implemented the counter in a number of languages [see the
|
||||
example directory](https://github.com/tendermint/tendermint/tree/develop/abci/example).
|
||||
|
||||
To run the Node JS version, `cd` to `example/js` and run
|
||||
To run the Node.js version, fist download & install [the Javascript ABCI server](https://github.com/tendermint/js-abci):
|
||||
|
||||
```
|
||||
node app.js
|
||||
git clone https://github.com/tendermint/js-abci.git
|
||||
cd js-abci
|
||||
npm install abci
|
||||
```
|
||||
|
||||
Now you can start the app:
|
||||
|
||||
```bash
|
||||
node example/counter.js
|
||||
```
|
||||
|
||||
(you'll have to kill the other counter application process). In another
|
||||
|
@@ -101,8 +101,8 @@ mempool state (this behaviour can be turned off with
|
||||
In go:
|
||||
|
||||
```
|
||||
func (app *KVStoreApplication) CheckTx(tx []byte) types.Result {
|
||||
return types.OK
|
||||
func (app *KVStoreApplication) CheckTx(req types.RequestCheckTx) types.ResponseCheckTx {
|
||||
return types.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -133,8 +133,8 @@ the mempool. If Tendermint is just started or the clients sent more than
|
||||
100k transactions, old transactions may be sent to the application. So
|
||||
it is important CheckTx implements some logic to handle them.
|
||||
|
||||
There are cases where a transaction will (or may) become valid in some
|
||||
future state, in which case you probably want to disable Tendermint's
|
||||
If there are cases in your application where a transaction may become invalid in some
|
||||
future state, you probably want to disable Tendermint's
|
||||
cache. You can do that by setting `[mempool] cache_size = 0` in the
|
||||
config.
|
||||
|
||||
@@ -168,14 +168,29 @@ In go:
|
||||
|
||||
```
|
||||
// tx is either "key=value" or just arbitrary bytes
|
||||
func (app *KVStoreApplication) DeliverTx(tx []byte) types.Result {
|
||||
parts := strings.Split(string(tx), "=")
|
||||
if len(parts) == 2 {
|
||||
app.state.Set([]byte(parts[0]), []byte(parts[1]))
|
||||
} else {
|
||||
app.state.Set(tx, tx)
|
||||
}
|
||||
return types.OK
|
||||
func (app *KVStoreApplication) DeliverTx(req types.RequestDeliverTx) types.ResponseDeliverTx {
|
||||
var key, value []byte
|
||||
parts := bytes.Split(req.Tx, []byte("="))
|
||||
if len(parts) == 2 {
|
||||
key, value = parts[0], parts[1]
|
||||
} else {
|
||||
key, value = req.Tx, req.Tx
|
||||
}
|
||||
|
||||
app.state.db.Set(prefixKey(key), value)
|
||||
app.state.Size += 1
|
||||
|
||||
events := []types.Event{
|
||||
{
|
||||
Type: "app",
|
||||
Attributes: []cmn.KVPair{
|
||||
{Key: []byte("creator"), Value: []byte("Cosmoshi Netowoko")},
|
||||
{Key: []byte("key"), Value: key},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return types.ResponseDeliverTx{Code: code.CodeTypeOK, Events: events}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -205,7 +220,7 @@ 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
|
||||
safely updated during Commit. This means the app _MUST NOT_ do any
|
||||
blocking communication with the mempool (ie. broadcast_tx) during
|
||||
Commit, or there will be deadlock. Note also that all remaining
|
||||
transactions in the mempool are replayed on the mempool connection
|
||||
@@ -223,9 +238,14 @@ job of the [Handshake](#handshake).
|
||||
In go:
|
||||
|
||||
```
|
||||
func (app *KVStoreApplication) Commit() types.Result {
|
||||
hash := app.state.Hash()
|
||||
return types.NewResultOK(hash, "")
|
||||
func (app *KVStoreApplication) Commit() types.ResponseCommit {
|
||||
// Using a memdb - just return the big endian size of the db
|
||||
appHash := make([]byte, 8)
|
||||
binary.PutVarint(appHash, app.state.Size)
|
||||
app.state.AppHash = appHash
|
||||
app.state.Height += 1
|
||||
saveState(app.state)
|
||||
return types.ResponseCommit{Data: appHash}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -256,12 +276,10 @@ In go:
|
||||
|
||||
```
|
||||
// Track the block hash and header information
|
||||
func (app *PersistentKVStoreApplication) BeginBlock(params types.RequestBeginBlock) {
|
||||
// update latest block info
|
||||
app.blockHeader = params.Header
|
||||
|
||||
// reset valset changes
|
||||
app.changes = make([]*types.Validator, 0)
|
||||
func (app *PersistentKVStoreApplication) BeginBlock(req types.RequestBeginBlock) types.ResponseBeginBlock {
|
||||
// reset valset changes
|
||||
app.ValUpdates = make([]types.ValidatorUpdate, 0)
|
||||
return types.ResponseBeginBlock{}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -303,7 +321,7 @@ In go:
|
||||
```
|
||||
// Update the validator set
|
||||
func (app *PersistentKVStoreApplication) EndBlock(req types.RequestEndBlock) types.ResponseEndBlock {
|
||||
return types.ResponseEndBlock{ValidatorUpdates: app.ValUpdates}
|
||||
return types.ResponseEndBlock{ValidatorUpdates: app.ValUpdates}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -347,43 +365,29 @@ Note: these query formats are subject to change!
|
||||
In go:
|
||||
|
||||
```
|
||||
func (app *KVStoreApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
|
||||
if reqQuery.Prove {
|
||||
value, proof, exists := app.state.GetWithProof(reqQuery.Data)
|
||||
resQuery.Index = -1 // TODO make Proof return index
|
||||
resQuery.Key = reqQuery.Data
|
||||
resQuery.Value = value
|
||||
resQuery.Proof = proof
|
||||
if exists {
|
||||
resQuery.Log = "exists"
|
||||
} else {
|
||||
resQuery.Log = "does not exist"
|
||||
}
|
||||
return
|
||||
} else {
|
||||
index, value, exists := app.state.Get(reqQuery.Data)
|
||||
resQuery.Index = int64(index)
|
||||
resQuery.Value = value
|
||||
if exists {
|
||||
resQuery.Log = "exists"
|
||||
} else {
|
||||
resQuery.Log = "does not exist"
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
} else {
|
||||
index, value, exists := app.state.Get(reqQuery.Data)
|
||||
resQuery.Index = int64(index)
|
||||
resQuery.Value = value
|
||||
if exists {
|
||||
resQuery.Log = "exists"
|
||||
} else {
|
||||
resQuery.Log = "does not exist"
|
||||
}
|
||||
return
|
||||
}
|
||||
func (app *KVStoreApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
|
||||
if reqQuery.Prove {
|
||||
value := app.state.db.Get(prefixKey(reqQuery.Data))
|
||||
resQuery.Index = -1 // TODO make Proof return index
|
||||
resQuery.Key = reqQuery.Data
|
||||
resQuery.Value = value
|
||||
if value != nil {
|
||||
resQuery.Log = "exists"
|
||||
} else {
|
||||
resQuery.Log = "does not exist"
|
||||
}
|
||||
return
|
||||
} else {
|
||||
resQuery.Key = reqQuery.Data
|
||||
value := app.state.db.Get(prefixKey(reqQuery.Data))
|
||||
resQuery.Value = value
|
||||
if value != nil {
|
||||
resQuery.Log = "exists"
|
||||
} else {
|
||||
resQuery.Log = "does not exist"
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -439,7 +443,11 @@ In go:
|
||||
|
||||
```
|
||||
func (app *KVStoreApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
|
||||
return types.ResponseInfo{Data: fmt.Sprintf("{\"size\":%v}", app.state.Size())}
|
||||
return types.ResponseInfo{
|
||||
Data: fmt.Sprintf("{\"size\":%v}", app.state.Size),
|
||||
Version: version.ABCIVersion,
|
||||
AppVersion: ProtocolVersion.Uint64(),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -463,13 +471,14 @@ In go:
|
||||
|
||||
```
|
||||
// Save the validators in the merkle tree
|
||||
func (app *PersistentKVStoreApplication) InitChain(params types.RequestInitChain) {
|
||||
for _, v := range params.Validators {
|
||||
r := app.updateValidator(v)
|
||||
if r.IsErr() {
|
||||
app.logger.Error("Error updating validators", "r", r)
|
||||
}
|
||||
}
|
||||
func (app *PersistentKVStoreApplication) InitChain(req types.RequestInitChain) types.ResponseInitChain {
|
||||
for _, v := range req.Validators {
|
||||
r := app.updateValidator(v)
|
||||
if r.IsErr() {
|
||||
app.logger.Error("Error updating validators", "r", r)
|
||||
}
|
||||
}
|
||||
return types.ResponseInitChain{}
|
||||
}
|
||||
```
|
||||
|
||||
|
@@ -47,7 +47,7 @@ pairs of UTF-8 encoded strings (e.g. "account.owner": "Bob", "balance":
|
||||
Example:
|
||||
|
||||
```
|
||||
func (app *KVStoreApplication) DeliverTx(tx []byte) types.Result {
|
||||
func (app *KVStoreApplication) DeliverTx(req types.RequestDeliverTx) types.Result {
|
||||
...
|
||||
tags := []cmn.KVPair{
|
||||
{[]byte("account.name"), []byte("igor")},
|
||||
|
@@ -45,6 +45,8 @@ make build
|
||||
|
||||
to put the binary in `./build`.
|
||||
|
||||
_DISCLAIMER_ The binary of tendermint is build/installed without the DWARF symbol table. If you would like to build/install tendermint with the DWARF symbol and debug information, remove `-s -w` from `BUILD_FLAGS` in the make file.
|
||||
|
||||
The latest `tendermint version` is now installed.
|
||||
|
||||
## Run
|
||||
|
@@ -141,7 +141,7 @@ on them. All other fields in the `Response*` must be strictly deterministic.
|
||||
## Block Execution
|
||||
|
||||
The first time a new blockchain is started, Tendermint calls
|
||||
`InitChain`. From then on, the follow sequence of methods is executed for each
|
||||
`InitChain`. From then on, the following sequence of methods is executed for each
|
||||
block:
|
||||
|
||||
`BeginBlock, [DeliverTx], EndBlock, Commit`
|
||||
@@ -296,6 +296,12 @@ Commit are included in the header of the next block.
|
||||
|
||||
- **Request**:
|
||||
- `Tx ([]byte)`: The request transaction bytes
|
||||
- `Type (CheckTxType)`: What type of `CheckTx` request is this? At present,
|
||||
there are two possible values: `CheckTx_Unchecked` (the default, which says
|
||||
that a full check is required), and `CheckTx_Checked` (when the mempool is
|
||||
initiating a normal recheck of a transaction).
|
||||
- `AdditionalData ([]byte)`: Reserved for future use. See
|
||||
[here](https://github.com/tendermint/tendermint/issues/2127#issuecomment-456661420).
|
||||
- **Response**:
|
||||
- `Code (uint32)`: Response code
|
||||
- `Data ([]byte)`: Result bytes, if any.
|
||||
|
@@ -218,7 +218,7 @@ func MerkleRoot(items [][]byte) []byte{
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return leafHash(leafs[0])
|
||||
return leafHash(items[0])
|
||||
default:
|
||||
k := getSplitPoint(len(items))
|
||||
left := MerkleRoot(items[:k])
|
||||
|
@@ -59,7 +59,7 @@ type Validator struct {
|
||||
When hashing the Validator struct, the address is not included,
|
||||
because it is redundant with the pubkey.
|
||||
|
||||
The `state.Validators`, `state.LastValidators`, and `state.NextValidators`, must always by sorted by validator address,
|
||||
The `state.Validators`, `state.LastValidators`, and `state.NextValidators`, must always be sorted by validator address,
|
||||
so that there is a canonical order for computing the MerkleRoot.
|
||||
|
||||
We also define a `TotalVotingPower` function, to return the total voting power:
|
||||
|
BIN
docs/tendermint-core-image.jpg
Executable file
BIN
docs/tendermint-core-image.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 123 KiB |
@@ -138,14 +138,16 @@ max_subscriptions_per_client = 5
|
||||
# See https://github.com/tendermint/tendermint/issues/3435
|
||||
timeout_broadcast_tx_commit = "10s"
|
||||
|
||||
# The name of a file containing certificate that is used to create the HTTPS server.
|
||||
# The path to a file containing certificate that is used to create the HTTPS server.
|
||||
# Migth be either absolute path or path related to tendermint's config directory.
|
||||
# If the certificate is signed by a certificate authority,
|
||||
# the certFile should be the concatenation of the server's certificate, any intermediates,
|
||||
# and the CA's certificate.
|
||||
# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server. Otherwise, HTTP server is run.
|
||||
tls_cert_file = ""
|
||||
|
||||
# The name of a file containing matching private key that is used to create the HTTPS server.
|
||||
# The path to a file containing matching private key that is used to create the HTTPS server.
|
||||
# Migth be either absolute path or path related to tendermint's config directory.
|
||||
# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server. Otherwise, HTTP server is run.
|
||||
tls_key_file = ""
|
||||
|
||||
|
@@ -202,8 +202,10 @@ Note that raw hex cannot be used in `POST` transactions.
|
||||
|
||||
## Reset
|
||||
|
||||
**WARNING: UNSAFE** Only do this in development and only if you can
|
||||
::: warning
|
||||
**UNSAFE** Only do this in development and only if you can
|
||||
afford to lose all blockchain data!
|
||||
:::
|
||||
|
||||
To reset a blockchain, stop the node and run:
|
||||
|
||||
|
Reference in New Issue
Block a user