mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-14 13:51:21 +00:00
lint markdown docs using a stop-words and write-good linters (#2195)
* lint docs with write-good, stop-words * remove package-lock.json * update changelog * fix wrong paragraph formatting * fix some docs formatting * fix docs format * fix abci spec format
This commit is contained in:
committed by
Anton Kaliaev
parent
8a84593c02
commit
20e35654c6
@ -23,6 +23,7 @@ FEATURES:
|
|||||||
- [types] allow genesis file to have 0 validators ([#2015](https://github.com/tendermint/tendermint/issues/2015))
|
- [types] allow genesis file to have 0 validators ([#2015](https://github.com/tendermint/tendermint/issues/2015))
|
||||||
|
|
||||||
IMPROVEMENTS:
|
IMPROVEMENTS:
|
||||||
|
- [docs] Lint documentation with `write-good` and `stop-words`.
|
||||||
- [scripts] Added json2wal tool, which is supposed to help our users restore
|
- [scripts] Added json2wal tool, which is supposed to help our users restore
|
||||||
corrupted WAL files and compose test WAL files (@bradyjoestar)
|
corrupted WAL files and compose test WAL files (@bradyjoestar)
|
||||||
|
|
||||||
|
9
docs/.textlintrc.json
Normal file
9
docs/.textlintrc.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"stop-words": {
|
||||||
|
"severity": "warning",
|
||||||
|
"defaultWords": false,
|
||||||
|
"words": "stop-words.txt"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,24 +5,21 @@
|
|||||||
"url": "https://github.com/cosmos/cosmos-sdk",
|
"url": "https://github.com/cosmos/cosmos-sdk",
|
||||||
"language": "Go",
|
"language": "Go",
|
||||||
"author": "Cosmos",
|
"author": "Cosmos",
|
||||||
"description":
|
"description": "A prototypical account based crypto currency state machine supporting plugins"
|
||||||
"A prototypical account based crypto currency state machine supporting plugins"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "cb-ledger",
|
"name": "cb-ledger",
|
||||||
"url": "https://github.com/block-finance/cpp-abci",
|
"url": "https://github.com/block-finance/cpp-abci",
|
||||||
"language": "C++",
|
"language": "C++",
|
||||||
"author": "Block Finance",
|
"author": "Block Finance",
|
||||||
"description":
|
"description": "Custodian Bank Ledger, integrating central banking with the blockchains of tomorrow"
|
||||||
"Custodian Bank Ledger, integrating central banking with the blockchains of tomorrow"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Clearchain",
|
"name": "Clearchain",
|
||||||
"url": "https://github.com/tendermint/clearchain",
|
"url": "https://github.com/tendermint/clearchain",
|
||||||
"language": "Go",
|
"language": "Go",
|
||||||
"author": "FXCLR",
|
"author": "FXCLR",
|
||||||
"description":
|
"description": "Application to manage a distributed ledger for money transfers that support multi-currency accounts"
|
||||||
"Application to manage a distributed ledger for money transfers that support multi-currency accounts"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Ethermint",
|
"name": "Ethermint",
|
||||||
@ -43,8 +40,7 @@
|
|||||||
"url": "https://github.com/hyperledger/burrow",
|
"url": "https://github.com/hyperledger/burrow",
|
||||||
"language": "Go",
|
"language": "Go",
|
||||||
"author": "Monax Industries",
|
"author": "Monax Industries",
|
||||||
"description":
|
"description": "Ethereum Virtual Machine augmented with native permissioning scheme and global key-value store"
|
||||||
"Ethereum Virtual Machine augmented with native permissioning scheme and global key-value store"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Merkle AVL Tree",
|
"name": "Merkle AVL Tree",
|
||||||
@ -72,8 +68,7 @@
|
|||||||
"url": "https://github.com/trusch/passchain",
|
"url": "https://github.com/trusch/passchain",
|
||||||
"language": "Go",
|
"language": "Go",
|
||||||
"author": "trusch",
|
"author": "trusch",
|
||||||
"description":
|
"description": "Tool to securely store and share passwords, tokens and other short secrets"
|
||||||
"Tool to securely store and share passwords, tokens and other short secrets"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Passwerk",
|
"name": "Passwerk",
|
||||||
@ -87,8 +82,7 @@
|
|||||||
"url": "https://github.com/davebryson/py-tendermint",
|
"url": "https://github.com/davebryson/py-tendermint",
|
||||||
"language": "Python",
|
"language": "Python",
|
||||||
"author": "Dave Bryson",
|
"author": "Dave Bryson",
|
||||||
"description":
|
"description": "A Python microframework for building blockchain applications with Tendermint"
|
||||||
"A Python microframework for building blockchain applications with Tendermint"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Stratumn SDK",
|
"name": "Stratumn SDK",
|
||||||
@ -102,16 +96,14 @@
|
|||||||
"url": "https://github.com/keppel/lotion",
|
"url": "https://github.com/keppel/lotion",
|
||||||
"language": "Javascript",
|
"language": "Javascript",
|
||||||
"author": "Judd Keppel",
|
"author": "Judd Keppel",
|
||||||
"description":
|
"description": "A Javascript microframework for building blockchain applications with Tendermint"
|
||||||
"A Javascript microframework for building blockchain applications with Tendermint"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Tendermint Blockchain Chat App",
|
"name": "Tendermint Blockchain Chat App",
|
||||||
"url": "https://github.com/SaifRehman/tendermint-chat-app/",
|
"url": "https://github.com/SaifRehman/tendermint-chat-app/",
|
||||||
"language": "Javascript",
|
"language": "Javascript",
|
||||||
"author": "Saif Rehman",
|
"author": "Saif Rehman",
|
||||||
"description":
|
"description": "This is a minimal chat application based on Tendermint using Lotion.js in 30 lines of code!. It also includes web/mobile application built using Ionic 3."
|
||||||
"This is a minimal chat application based on Tendermint using Lotion.js in 30 lines of code!. It also includes web/mobile application built using Ionic 3."
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "BigchainDB",
|
"name": "BigchainDB",
|
||||||
@ -184,16 +176,14 @@
|
|||||||
"url": "https://github.com/tendermint/tools",
|
"url": "https://github.com/tendermint/tools",
|
||||||
"technology": "Docker and Kubernetes",
|
"technology": "Docker and Kubernetes",
|
||||||
"author": "Tendermint",
|
"author": "Tendermint",
|
||||||
"description":
|
"description": "Deploy a Tendermint test network using Google's kubernetes"
|
||||||
"Deploy a Tendermint test network using Google's kubernetes"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "terraforce",
|
"name": "terraforce",
|
||||||
"url": "https://github.com/tendermint/tools",
|
"url": "https://github.com/tendermint/tools",
|
||||||
"technology": "Terraform",
|
"technology": "Terraform",
|
||||||
"author": "Tendermint",
|
"author": "Tendermint",
|
||||||
"description":
|
"description": "Terraform + our custom terraforce tool; deploy a production Tendermint network with load balancing over multiple AWS availability zones"
|
||||||
"Terraform + our custom terraforce tool; deploy a production Tendermint network with load balancing over multiple AWS availability zones"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ansible-tendermint",
|
"name": "ansible-tendermint",
|
||||||
|
@ -7,8 +7,7 @@ a subset of transactions** (rather than all of them) using `/subscribe?event=X`.
|
|||||||
example, I want to subscribe for all transactions associated with a particular
|
example, I want to subscribe for all transactions associated with a particular
|
||||||
account. Same for fetching. The user may want to **fetch transactions based on
|
account. Same for fetching. The user may want to **fetch transactions based on
|
||||||
some filter** (rather than fetching all the blocks). For example, I want to get
|
some filter** (rather than fetching all the blocks). For example, I want to get
|
||||||
all transactions for a particular account in the last two weeks (`tx's block
|
all transactions for a particular account in the last two weeks (`tx's block time >= '2017-06-05'`).
|
||||||
time >= '2017-06-05'`).
|
|
||||||
|
|
||||||
Now you can't even subscribe to "all txs" in Tendermint.
|
Now you can't even subscribe to "all txs" in Tendermint.
|
||||||
|
|
||||||
|
@ -83,4 +83,3 @@ Proposed.
|
|||||||
### Neutral
|
### Neutral
|
||||||
|
|
||||||
- The TxSize, which checks validity, may be in conflict with the config's `max_block_size_tx`, which determines proposal sizes
|
- The TxSize, which checks validity, may be in conflict with the config's `max_block_size_tx`, which determines proposal sizes
|
||||||
|
|
||||||
|
@ -8,13 +8,13 @@ The proposed trust metric will allow Tendermint to maintain local trust rankings
|
|||||||
|
|
||||||
The Tendermint Core project developers would like to improve Tendermint security and reliability by keeping track of the level of trustworthiness peers have demonstrated within the peer-to-peer network. This way, undesirable outcomes from peers will not immediately result in them being dropped from the network (potentially causing drastic changes to take place). Instead, peers behavior can be monitored with appropriate metrics and be removed from the network once Tendermint Core is certain the peer is a threat. For example, when the PEXReactor makes a request for peers network addresses from a already known peer, and the returned network addresses are unreachable, this untrustworthy behavior should be tracked. Returning a few bad network addresses probably shouldn’t cause a peer to be dropped, while excessive amounts of this behavior does qualify the peer being dropped.
|
The Tendermint Core project developers would like to improve Tendermint security and reliability by keeping track of the level of trustworthiness peers have demonstrated within the peer-to-peer network. This way, undesirable outcomes from peers will not immediately result in them being dropped from the network (potentially causing drastic changes to take place). Instead, peers behavior can be monitored with appropriate metrics and be removed from the network once Tendermint Core is certain the peer is a threat. For example, when the PEXReactor makes a request for peers network addresses from a already known peer, and the returned network addresses are unreachable, this untrustworthy behavior should be tracked. Returning a few bad network addresses probably shouldn’t cause a peer to be dropped, while excessive amounts of this behavior does qualify the peer being dropped.
|
||||||
|
|
||||||
Trust metrics can be circumvented by malicious nodes through the use of strategic oscillation techniques, which adapts the malicious node’s behavior pattern in order to maximize its goals. For instance, if the malicious node learns that the time interval of the Tendermint trust metric is *X* hours, then it could wait *X* hours in-between malicious activities. We could try to combat this issue by increasing the interval length, yet this will make the system less adaptive to recent events.
|
Trust metrics can be circumvented by malicious nodes through the use of strategic oscillation techniques, which adapts the malicious node’s behavior pattern in order to maximize its goals. For instance, if the malicious node learns that the time interval of the Tendermint trust metric is _X_ hours, then it could wait _X_ hours in-between malicious activities. We could try to combat this issue by increasing the interval length, yet this will make the system less adaptive to recent events.
|
||||||
|
|
||||||
Instead, having shorter intervals, but keeping a history of interval values, will give our metric the flexibility needed in order to keep the network stable, while also making it resilient against a strategic malicious node in the Tendermint peer-to-peer network. Also, the metric can access trust data over a rather long period of time while not greatly increasing its history size by aggregating older history values over a larger number of intervals, and at the same time, maintain great precision for the recent intervals. This approach is referred to as fading memories, and closely resembles the way human beings remember their experiences. The trade-off to using history data is that the interval values should be preserved in-between executions of the node.
|
Instead, having shorter intervals, but keeping a history of interval values, will give our metric the flexibility needed in order to keep the network stable, while also making it resilient against a strategic malicious node in the Tendermint peer-to-peer network. Also, the metric can access trust data over a rather long period of time while not greatly increasing its history size by aggregating older history values over a larger number of intervals, and at the same time, maintain great precision for the recent intervals. This approach is referred to as fading memories, and closely resembles the way human beings remember their experiences. The trade-off to using history data is that the interval values should be preserved in-between executions of the node.
|
||||||
|
|
||||||
### References
|
### References
|
||||||
|
|
||||||
S. Mudhakar, L. Xiong, and L. Liu, “TrustGuard: Countering Vulnerabilities in Reputation Management for Decentralized Overlay Networks,” in *Proceedings of the 14th international conference on World Wide Web, pp. 422-431*, May 2005.
|
S. Mudhakar, L. Xiong, and L. Liu, “TrustGuard: Countering Vulnerabilities in Reputation Management for Decentralized Overlay Networks,” in _Proceedings of the 14th international conference on World Wide Web, pp. 422-431_, May 2005.
|
||||||
|
|
||||||
## Decision
|
## Decision
|
||||||
|
|
||||||
@ -26,25 +26,23 @@ The three subsections below will cover the process being considered for calculat
|
|||||||
|
|
||||||
The proposed trust metric will count good and bad events relevant to the object, and calculate the percent of counters that are good over an interval with a predefined duration. This is the procedure that will continue for the life of the trust metric. When the trust metric is queried for the current **trust value**, a resilient equation will be utilized to perform the calculation.
|
The proposed trust metric will count good and bad events relevant to the object, and calculate the percent of counters that are good over an interval with a predefined duration. This is the procedure that will continue for the life of the trust metric. When the trust metric is queried for the current **trust value**, a resilient equation will be utilized to perform the calculation.
|
||||||
|
|
||||||
The equation being proposed resembles a Proportional-Integral-Derivative (PID) controller used in control systems. The proportional component allows us to be sensitive to the value of the most recent interval, while the integral component allows us to incorporate trust values stored in the history data, and the derivative component allows us to give weight to sudden changes in the behavior of a peer. We compute the trust value of a peer in interval i based on its current trust ranking, its trust rating history prior to interval *i* (over the past *maxH* number of intervals) and its trust ranking fluctuation. We will break up the equation into the three components.
|
The equation being proposed resembles a Proportional-Integral-Derivative (PID) controller used in control systems. The proportional component allows us to be sensitive to the value of the most recent interval, while the integral component allows us to incorporate trust values stored in the history data, and the derivative component allows us to give weight to sudden changes in the behavior of a peer. We compute the trust value of a peer in interval i based on its current trust ranking, its trust rating history prior to interval _i_ (over the past _maxH_ number of intervals) and its trust ranking fluctuation. We will break up the equation into the three components.
|
||||||
|
|
||||||
```math
|
```math
|
||||||
(1) Proportional Value = a * R[i]
|
(1) Proportional Value = a * R[i]
|
||||||
```
|
```
|
||||||
|
|
||||||
where *R*[*i*] denotes the raw trust value at time interval *i* (where *i* == 0 being current time) and *a* is the weight applied to the contribution of the current reports. The next component of our equation uses a weighted sum over the last *maxH* intervals to calculate the history value for time *i*:
|
where _R_[*i*] denotes the raw trust value at time interval _i_ (where _i_ == 0 being current time) and _a_ is the weight applied to the contribution of the current reports. The next component of our equation uses a weighted sum over the last _maxH_ intervals to calculate the history value for time _i_:
|
||||||
|
|
||||||
|
|
||||||
`H[i] =` 
|
`H[i] =` 
|
||||||
|
|
||||||
|
The weights can be chosen either optimistically or pessimistically. An optimistic weight creates larger weights for newer history data values, while the the pessimistic weight creates larger weights for time intervals with lower scores. The default weights used during the calculation of the history value are optimistic and calculated as _Wk_ = 0.8^_k_, for time interval _k_. With the history value available, we can now finish calculating the integral value:
|
||||||
The weights can be chosen either optimistically or pessimistically. An optimistic weight creates larger weights for newer history data values, while the the pessimistic weight creates larger weights for time intervals with lower scores. The default weights used during the calculation of the history value are optimistic and calculated as *Wk* = 0.8^*k*, for time interval *k*. With the history value available, we can now finish calculating the integral value:
|
|
||||||
|
|
||||||
```math
|
```math
|
||||||
(2) Integral Value = b * H[i]
|
(2) Integral Value = b * H[i]
|
||||||
```
|
```
|
||||||
|
|
||||||
Where *H*[*i*] denotes the history value at time interval *i* and *b* is the weight applied to the contribution of past performance for the object being measured. The derivative component will be calculated as follows:
|
Where _H_[*i*] denotes the history value at time interval _i_ and _b_ is the weight applied to the contribution of past performance for the object being measured. The derivative component will be calculated as follows:
|
||||||
|
|
||||||
```math
|
```math
|
||||||
D[i] = R[i] – H[i]
|
D[i] = R[i] – H[i]
|
||||||
@ -52,19 +50,19 @@ D[i] = R[i] – H[i]
|
|||||||
(3) Derivative Value = c(D[i]) * D[i]
|
(3) Derivative Value = c(D[i]) * D[i]
|
||||||
```
|
```
|
||||||
|
|
||||||
Where the value of *c* is selected based on the *D*[*i*] value relative to zero. The default selection process makes *c* equal to 0 unless *D*[*i*] is a negative value, in which case c is equal to 1. The result is that the maximum penalty is applied when current behavior is lower than previously experienced behavior. If the current behavior is better than the previously experienced behavior, then the Derivative Value has no impact on the trust value. With the three components brought together, our trust value equation is calculated as follows:
|
Where the value of _c_ is selected based on the _D_[*i*] value relative to zero. The default selection process makes _c_ equal to 0 unless _D_[*i*] is a negative value, in which case c is equal to 1. The result is that the maximum penalty is applied when current behavior is lower than previously experienced behavior. If the current behavior is better than the previously experienced behavior, then the Derivative Value has no impact on the trust value. With the three components brought together, our trust value equation is calculated as follows:
|
||||||
|
|
||||||
```math
|
```math
|
||||||
TrustValue[i] = a * R[i] + b * H[i] + c(D[i]) * D[i]
|
TrustValue[i] = a * R[i] + b * H[i] + c(D[i]) * D[i]
|
||||||
```
|
```
|
||||||
|
|
||||||
As a performance optimization that will keep the amount of raw interval data being saved to a reasonable size of *m*, while allowing us to represent 2^*m* - 1 history intervals, we can employ the fading memories technique that will trade space and time complexity for the precision of the history data values by summarizing larger quantities of less recent values. While our equation above attempts to access up to *maxH* (which can be 2^*m* - 1), we will map those requests down to *m* values using equation 4 below:
|
As a performance optimization that will keep the amount of raw interval data being saved to a reasonable size of _m_, while allowing us to represent 2^_m_ - 1 history intervals, we can employ the fading memories technique that will trade space and time complexity for the precision of the history data values by summarizing larger quantities of less recent values. While our equation above attempts to access up to _maxH_ (which can be 2^_m_ - 1), we will map those requests down to _m_ values using equation 4 below:
|
||||||
|
|
||||||
```math
|
```math
|
||||||
(4) j = index, where index > 0
|
(4) j = index, where index > 0
|
||||||
```
|
```
|
||||||
|
|
||||||
Where *j* is one of *(0, 1, 2, … , m – 1)* indices used to access history interval data. Now we can access the raw intervals using the following calculations:
|
Where _j_ is one of _(0, 1, 2, … , m – 1)_ indices used to access history interval data. Now we can access the raw intervals using the following calculations:
|
||||||
|
|
||||||
```math
|
```math
|
||||||
R[0] = raw data for current time interval
|
R[0] = raw data for current time interval
|
||||||
@ -84,9 +82,7 @@ When the node is shutting down, the trust metric store will save history data fo
|
|||||||
|
|
||||||
Each trust metric allows for the recording of positive/negative events, querying the current trust value/score, and the stopping/pausing of tracking over time intervals. This can be seen below:
|
Each trust metric allows for the recording of positive/negative events, querying the current trust value/score, and the stopping/pausing of tracking over time intervals. This can be seen below:
|
||||||
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
|
||||||
// TrustMetric - keeps track of peer reliability
|
// TrustMetric - keeps track of peer reliability
|
||||||
type TrustMetric struct {
|
type TrustMetric struct {
|
||||||
// Private elements.
|
// Private elements.
|
||||||
@ -123,13 +119,11 @@ tm.BadEvents(1)
|
|||||||
score := tm.TrustScore()
|
score := tm.TrustScore()
|
||||||
|
|
||||||
tm.Stop()
|
tm.Stop()
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Some of the trust metric parameters can be configured. The weight values should probably be left alone in more cases, yet the time durations for the tracking window and individual time interval should be considered.
|
Some of the trust metric parameters can be configured. The weight values should probably be left alone in more cases, yet the time durations for the tracking window and individual time interval should be considered.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
|
||||||
// TrustMetricConfig - Configures the weight functions and time intervals for the metric
|
// TrustMetricConfig - Configures the weight functions and time intervals for the metric
|
||||||
type TrustMetricConfig struct {
|
type TrustMetricConfig struct {
|
||||||
// Determines the percentage given to current behavior
|
// Determines the percentage given to current behavior
|
||||||
@ -167,7 +161,6 @@ tm := NewMetricWithConfig(config)
|
|||||||
tm.BadEvents(10)
|
tm.BadEvents(10)
|
||||||
tm.Pause()
|
tm.Pause()
|
||||||
tm.GoodEvents(1) // becomes active again
|
tm.GoodEvents(1) // becomes active again
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
A trust metric store should be created with a DB that has persistent storage so it can save history data across node executions. All trust metrics instantiated by the store will be created with the provided TrustMetricConfig configuration.
|
A trust metric store should be created with a DB that has persistent storage so it can save history data across node executions. All trust metrics instantiated by the store will be created with the provided TrustMetricConfig configuration.
|
||||||
@ -177,7 +170,6 @@ When you attempt to fetch the trust metric for a peer, and an entry does not exi
|
|||||||
In additional to the fetching method, GetPeerTrustMetric, the trust metric store provides a method to call when a peer has disconnected from the node. This is so the metric can be paused (history data will not be saved) for periods of time when the node is not having direct experiences with the peer.
|
In additional to the fetching method, GetPeerTrustMetric, the trust metric store provides a method to call when a peer has disconnected from the node. This is so the metric can be paused (history data will not be saved) for periods of time when the node is not having direct experiences with the peer.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
|
||||||
// TrustMetricStore - Manages all trust metrics for peers
|
// TrustMetricStore - Manages all trust metrics for peers
|
||||||
type TrustMetricStore struct {
|
type TrustMetricStore struct {
|
||||||
cmn.BaseService
|
cmn.BaseService
|
||||||
@ -214,7 +206,6 @@ tm := tms.GetPeerTrustMetric(key)
|
|||||||
tm.BadEvents(1)
|
tm.BadEvents(1)
|
||||||
|
|
||||||
tms.PeerDisconnected(key)
|
tms.PeerDisconnected(key)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
@ -17,11 +17,13 @@ For example, when the PEXReactor makes a request for peers network addresses fro
|
|||||||
The trust metric implementation allows a developer to obtain a peer's trust metric from a trust metric store, and track good and bad events relevant to a peer's behavior, and at any time, the peer's metric can be queried for a current trust value. The current trust value is calculated with a formula that utilizes current behavior, previous behavior, and change between the two. Current behavior is calculated as the percentage of good behavior within a time interval. The time interval is short; probably set between 30 seconds and 5 minutes. On the other hand, the historic data can estimate a peer's behavior over days worth of tracking. At the end of a time interval, the current behavior becomes part of the historic data, and a new time interval begins with the good and bad counters reset to zero.
|
The trust metric implementation allows a developer to obtain a peer's trust metric from a trust metric store, and track good and bad events relevant to a peer's behavior, and at any time, the peer's metric can be queried for a current trust value. The current trust value is calculated with a formula that utilizes current behavior, previous behavior, and change between the two. Current behavior is calculated as the percentage of good behavior within a time interval. The time interval is short; probably set between 30 seconds and 5 minutes. On the other hand, the historic data can estimate a peer's behavior over days worth of tracking. At the end of a time interval, the current behavior becomes part of the historic data, and a new time interval begins with the good and bad counters reset to zero.
|
||||||
|
|
||||||
These are some important things to keep in mind regarding how the trust metrics handle time intervals and scoring:
|
These are some important things to keep in mind regarding how the trust metrics handle time intervals and scoring:
|
||||||
|
|
||||||
- Each new time interval begins with a perfect score
|
- Each new time interval begins with a perfect score
|
||||||
- Bad events quickly bring the score down and good events cause the score to slowly rise
|
- Bad events quickly bring the score down and good events cause the score to slowly rise
|
||||||
- When the time interval is over, the percentage of good events becomes historic data.
|
- When the time interval is over, the percentage of good events becomes historic data.
|
||||||
|
|
||||||
Some useful information about the inner workings of the trust metric:
|
Some useful information about the inner workings of the trust metric:
|
||||||
|
|
||||||
- When a trust metric is first instantiated, a timer (ticker) periodically fires in order to handle transitions between trust metric time intervals
|
- When a trust metric is first instantiated, a timer (ticker) periodically fires in order to handle transitions between trust metric time intervals
|
||||||
- If a peer is disconnected from a node, the timer should be paused, since the node is no longer connected to that peer
|
- If a peer is disconnected from a node, the timer should be paused, since the node is no longer connected to that peer
|
||||||
- The ability to pause the metric is supported with the store **PeerDisconnected** method and the metric **Pause** method
|
- The ability to pause the metric is supported with the store **PeerDisconnected** method and the metric **Pause** method
|
||||||
@ -76,6 +78,7 @@ Peer quality is tracked in the connection and across the reactors by storing the
|
|||||||
thread safe Data store.
|
thread safe Data store.
|
||||||
|
|
||||||
Peer behaviour is then defined as one of the following:
|
Peer behaviour is then defined as one of the following:
|
||||||
|
|
||||||
- Fatal - something outright malicious that causes us to disconnect the peer and ban it from the address book for some amount of time
|
- Fatal - something outright malicious that causes us to disconnect the peer and ban it from the address book for some amount of time
|
||||||
- Bad - Any kind of timeout, messages that don't unmarshal, fail other validity checks, or messages we didn't ask for or aren't expecting (usually worth one bad event)
|
- Bad - Any kind of timeout, messages that don't unmarshal, fail other validity checks, or messages we didn't ask for or aren't expecting (usually worth one bad event)
|
||||||
- Neutral - Unknown channels/message types/version upgrades (no good or bad events recorded)
|
- Neutral - Unknown channels/message types/version upgrades (no good or bad events recorded)
|
||||||
|
@ -66,7 +66,7 @@ possible.
|
|||||||
### Validators
|
### Validators
|
||||||
|
|
||||||
To change the validator set, applications can return a list of validator updates
|
To change the validator set, applications can return a list of validator updates
|
||||||
with ResponseEndBlock. In these updates, the public key *must* be included,
|
with ResponseEndBlock. In these updates, the public key _must_ be included,
|
||||||
because Tendermint requires the public key to verify validator signatures. This
|
because Tendermint requires the public key to verify validator signatures. This
|
||||||
means ABCI developers have to work with PubKeys. That said, it would also be
|
means ABCI developers have to work with PubKeys. That said, it would also be
|
||||||
convenient to work with address information, and for it to be simple to do so.
|
convenient to work with address information, and for it to be simple to do so.
|
||||||
@ -120,7 +120,6 @@ v1 will:
|
|||||||
That said, an Amino v2 will be worked on to improve the performance of the
|
That said, an Amino v2 will be worked on to improve the performance of the
|
||||||
format and its useability in cryptographic applications.
|
format and its useability in cryptographic applications.
|
||||||
|
|
||||||
|
|
||||||
### PubKey
|
### PubKey
|
||||||
|
|
||||||
Encoding schemes infect software. As a generic middleware, ABCI aims to have
|
Encoding schemes infect software. As a generic middleware, ABCI aims to have
|
||||||
@ -143,7 +142,6 @@ where `type` can be:
|
|||||||
- "ed225519", with `data = <raw 32-byte pubkey>`
|
- "ed225519", with `data = <raw 32-byte pubkey>`
|
||||||
- "secp256k1", with `data = <33-byte OpenSSL compressed pubkey>`
|
- "secp256k1", with `data = <33-byte OpenSSL compressed pubkey>`
|
||||||
|
|
||||||
|
|
||||||
As we want to retain flexibility here, and since ideally, PubKey would be an
|
As we want to retain flexibility here, and since ideally, PubKey would be an
|
||||||
interface type, we do not use `enum` or `oneof`.
|
interface type, we do not use `enum` or `oneof`.
|
||||||
|
|
||||||
|
@ -66,13 +66,10 @@ Make the following changes:
|
|||||||
|
|
||||||
- More modern and standard cryptographic functions with wider adoption and hardware acceleration
|
- More modern and standard cryptographic functions with wider adoption and hardware acceleration
|
||||||
|
|
||||||
|
|
||||||
### Negative
|
### Negative
|
||||||
|
|
||||||
- Exact authenticated encryption construction isn't already provided in a well-used library
|
- Exact authenticated encryption construction isn't already provided in a well-used library
|
||||||
|
|
||||||
|
|
||||||
### Neutral
|
### Neutral
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ A few solutions were considered:
|
|||||||
b) [go-kit metrics package](https://github.com/go-kit/kit/tree/master/metrics) as an interface plus Prometheus
|
b) [go-kit metrics package](https://github.com/go-kit/kit/tree/master/metrics) as an interface plus Prometheus
|
||||||
c) [telegraf](https://github.com/influxdata/telegraf)
|
c) [telegraf](https://github.com/influxdata/telegraf)
|
||||||
d) new service, which will listen to events emitted by pubsub and report metrics
|
d) new service, which will listen to events emitted by pubsub and report metrics
|
||||||
5. [OpenCensus](https://opencensus.io/go/index.html)
|
2. [OpenCensus](https://opencensus.io/go/index.html)
|
||||||
|
|
||||||
### 1. Prometheus
|
### 1. Prometheus
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ will need to write interfaces ourselves.
|
|||||||
### List of metrics
|
### List of metrics
|
||||||
|
|
||||||
| | Name | Type | Description |
|
| | Name | Type | Description |
|
||||||
| - | --------------------------------------- | ------- | ----------------------------------------------------------------------------- |
|
| --- | ------------------------------------ | ------ | ----------------------------------------------------------------------------- |
|
||||||
| A | consensus_height | Gauge | |
|
| A | consensus_height | Gauge | |
|
||||||
| A | consensus_validators | Gauge | Number of validators who signed |
|
| A | consensus_validators | Gauge | Number of validators who signed |
|
||||||
| A | consensus_validators_power | Gauge | Total voting power of all validators |
|
| A | consensus_validators_power | Gauge | Total voting power of all validators |
|
||||||
|
@ -9,8 +9,9 @@ handling. An artifact is the dependency of the Switch on
|
|||||||
`[config.P2PConfig`](https://github.com/tendermint/tendermint/blob/05a76fb517f50da27b4bfcdc7b4cf185fc61eff6/config/config.go#L272-L339).
|
`[config.P2PConfig`](https://github.com/tendermint/tendermint/blob/05a76fb517f50da27b4bfcdc7b4cf185fc61eff6/config/config.go#L272-L339).
|
||||||
|
|
||||||
Addresses:
|
Addresses:
|
||||||
* [#2046](https://github.com/tendermint/tendermint/issues/2046)
|
|
||||||
* [#2047](https://github.com/tendermint/tendermint/issues/2047)
|
- [#2046](https://github.com/tendermint/tendermint/issues/2046)
|
||||||
|
- [#2047](https://github.com/tendermint/tendermint/issues/2047)
|
||||||
|
|
||||||
First iteraton in [#2067](https://github.com/tendermint/tendermint/issues/2067)
|
First iteraton in [#2067](https://github.com/tendermint/tendermint/issues/2067)
|
||||||
|
|
||||||
@ -29,13 +30,12 @@ transport implementation is responsible to filter establishing peers specific
|
|||||||
to its domain, for the default multiplexed implementation the following will
|
to its domain, for the default multiplexed implementation the following will
|
||||||
apply:
|
apply:
|
||||||
|
|
||||||
* connections from our own node
|
- connections from our own node
|
||||||
* handshake fails
|
- handshake fails
|
||||||
* upgrade to secret connection fails
|
- upgrade to secret connection fails
|
||||||
* prevent duplicate ip
|
- prevent duplicate ip
|
||||||
* prevent duplicate id
|
- prevent duplicate id
|
||||||
* nodeinfo incompatibility
|
- nodeinfo incompatibility
|
||||||
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// PeerTransport proxies incoming and outgoing peer connections.
|
// PeerTransport proxies incoming and outgoing peer connections.
|
||||||
@ -96,17 +96,17 @@ In Review.
|
|||||||
|
|
||||||
### Positive
|
### Positive
|
||||||
|
|
||||||
* free Switch from transport concerns - simpler implementation
|
- free Switch from transport concerns - simpler implementation
|
||||||
* pluggable transport implementation - simpler test setup
|
- pluggable transport implementation - simpler test setup
|
||||||
* remove Switch dependency on P2PConfig - easier to test
|
- remove Switch dependency on P2PConfig - easier to test
|
||||||
|
|
||||||
### Negative
|
### Negative
|
||||||
|
|
||||||
* more setup for tests which depend on Switches
|
- more setup for tests which depend on Switches
|
||||||
|
|
||||||
### Neutral
|
### Neutral
|
||||||
|
|
||||||
* multiplexed will be the default implementation
|
- multiplexed will be the default implementation
|
||||||
|
|
||||||
[0] These guards could be potentially extended to be pluggable much like
|
[0] These guards could be potentially extended to be pluggable much like
|
||||||
middlewares to express different concerns required by differentally configured
|
middlewares to express different concerns required by differentally configured
|
||||||
|
@ -30,6 +30,7 @@ Consequently decryption with multiple algoritms is sub-optimal.
|
|||||||
## Decision
|
## Decision
|
||||||
|
|
||||||
We should create the following two methods in a new `crypto/encoding/symmetric` package:
|
We should create the following two methods in a new `crypto/encoding/symmetric` package:
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
func Encrypt(aead cipher.AEAD, plaintext []byte) (ciphertext []byte, err error)
|
func Encrypt(aead cipher.AEAD, plaintext []byte) (ciphertext []byte, err error)
|
||||||
func Decrypt(key []byte, ciphertext []byte) (plaintext []byte, err error)
|
func Decrypt(key []byte, ciphertext []byte) (plaintext []byte, err error)
|
||||||
@ -49,6 +50,7 @@ This will be binary data, but thats not a problem considering the nonce and ciph
|
|||||||
|
|
||||||
This solution requires a mapping from aead type to name.
|
This solution requires a mapping from aead type to name.
|
||||||
We can achieve this via reflection.
|
We can achieve this via reflection.
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
func getType(myvar interface{}) string {
|
func getType(myvar interface{}) string {
|
||||||
if t := reflect.TypeOf(myvar); t.Kind() == reflect.Ptr {
|
if t := reflect.TypeOf(myvar); t.Kind() == reflect.Ptr {
|
||||||
@ -58,6 +60,7 @@ func getType(myvar interface{}) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Then we maintain a map from the name returned from `getType(aead)` to `algo_name`.
|
Then we maintain a map from the name returned from `getType(aead)` to `algo_name`.
|
||||||
|
|
||||||
In decryption, we read the `algo_name`, and then instantiate a new AEAD with the key.
|
In decryption, we read the `algo_name`, and then instantiate a new AEAD with the key.
|
||||||
@ -81,13 +84,16 @@ Proposed.
|
|||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
### Positive
|
### Positive
|
||||||
* Allows us to support new AEAD's, in a way that makes decryption easier
|
|
||||||
* Allows downstream users to add their own AEAD
|
- Allows us to support new AEAD's, in a way that makes decryption easier
|
||||||
|
- Allows downstream users to add their own AEAD
|
||||||
|
|
||||||
### Negative
|
### Negative
|
||||||
* We will have to break all private keys stored on disk.
|
|
||||||
|
- We will have to break all private keys stored on disk.
|
||||||
They can be recovered using seed words, and upgrade scripts are simple.
|
They can be recovered using seed words, and upgrade scripts are simple.
|
||||||
|
|
||||||
### Neutral
|
### Neutral
|
||||||
* Caller has to instantiate the AEAD with the private key.
|
|
||||||
|
- Caller has to instantiate the AEAD with the private key.
|
||||||
However it forces them to be aware of what signing algorithm they are using, which is a positive.
|
However it forces them to be aware of what signing algorithm they are using, which is a positive.
|
@ -52,10 +52,12 @@ Proposed.
|
|||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
### Positive
|
### Positive
|
||||||
* Lets us maintain the ability to expect a tx hash to appear in the blockchain.
|
|
||||||
|
- Lets us maintain the ability to expect a tx hash to appear in the blockchain.
|
||||||
|
|
||||||
### Negative
|
### Negative
|
||||||
* More work in all future implementations (Though this is a very simple check)
|
|
||||||
* Requires us to maintain another fork
|
- More work in all future implementations (Though this is a very simple check)
|
||||||
|
- Requires us to maintain another fork
|
||||||
|
|
||||||
### Neutral
|
### Neutral
|
||||||
|
@ -54,9 +54,11 @@ When placed in state, signatures will still be amino encoded, but it will be the
|
|||||||
primitive type `[]byte` getting encoded.
|
primitive type `[]byte` getting encoded.
|
||||||
|
|
||||||
#### Ed25519
|
#### Ed25519
|
||||||
|
|
||||||
Use the canonical representation for signatures.
|
Use the canonical representation for signatures.
|
||||||
|
|
||||||
#### Secp256k1
|
#### Secp256k1
|
||||||
|
|
||||||
There isn't a clear canonical representation here.
|
There isn't a clear canonical representation here.
|
||||||
Signatures have two elements `r,s`.
|
Signatures have two elements `r,s`.
|
||||||
These bytes are encoded as `r || s`, where `r` and `s` are both exactly
|
These bytes are encoded as `r || s`, where `r` and `s` are both exactly
|
||||||
@ -71,10 +73,13 @@ Needs decision on Enum types.
|
|||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
### Positive
|
### Positive
|
||||||
* More space efficient signatures
|
|
||||||
|
- More space efficient signatures
|
||||||
|
|
||||||
### Negative
|
### Negative
|
||||||
* We have an amino dependency for cryptography.
|
|
||||||
|
- We have an amino dependency for cryptography.
|
||||||
|
|
||||||
### Neutral
|
### Neutral
|
||||||
* No change to public keys
|
|
||||||
|
- No change to public keys
|
||||||
|
@ -59,8 +59,7 @@ to connect to peers with older version.
|
|||||||
### BlockVersion
|
### BlockVersion
|
||||||
|
|
||||||
- All tendermint hashed data-structures (headers, votes, txs, responses, etc.).
|
- All tendermint hashed data-structures (headers, votes, txs, responses, etc.).
|
||||||
- Note the semantic meaning of a transaction may change according to the AppVersion,
|
- Note the semantic meaning of a transaction may change according to the AppVersion, but the way txs are merklized into the header is part of the BlockVersion
|
||||||
but the way txs are merklized into the header is part of the BlockVersion
|
|
||||||
- It should be the least frequent/likely to change.
|
- It should be the least frequent/likely to change.
|
||||||
- Tendermint should be stabilizing - it's just Atomic Broadcast.
|
- Tendermint should be stabilizing - it's just Atomic Broadcast.
|
||||||
- We can start considering for Tendermint v2.0 in a year
|
- We can start considering for Tendermint v2.0 in a year
|
||||||
@ -69,8 +68,7 @@ to connect to peers with older version.
|
|||||||
### P2PVersion
|
### P2PVersion
|
||||||
|
|
||||||
- All p2p and reactor messaging (messages, detectable behaviour)
|
- All p2p and reactor messaging (messages, detectable behaviour)
|
||||||
- Will change gradually as reactors evolve to improve performance and support new features
|
- Will change gradually as reactors evolve to improve performance and support new features - eg proposed new message types BatchTx in the mempool and HasBlockPart in the consensus
|
||||||
- eg proposed new message types BatchTx in the mempool and HasBlockPart in the consensus
|
|
||||||
- It's easy to determine the version of a peer from its first serialized message/s
|
- It's easy to determine the version of a peer from its first serialized message/s
|
||||||
- New versions must be compatible with at least one old version to allow gradual upgrades
|
- New versions must be compatible with at least one old version to allow gradual upgrades
|
||||||
|
|
||||||
@ -79,7 +77,7 @@ to connect to peers with older version.
|
|||||||
- The ABCI state machine (txs, begin/endblock behaviour, commit hashing)
|
- The ABCI state machine (txs, begin/endblock behaviour, commit hashing)
|
||||||
- Behaviour and message types will change abruptly in the course of the life of a chain
|
- Behaviour and message types will change abruptly in the course of the life of a chain
|
||||||
- Need to minimize complexity of the code for supporting different AppVersions at different heights
|
- Need to minimize complexity of the code for supporting different AppVersions at different heights
|
||||||
- Ideally, each version of the software supports only a *single* AppVersion at one time
|
- Ideally, each version of the software supports only a _single_ AppVersion at one time
|
||||||
- this means we checkout different versions of the software at different heights instead of littering the code
|
- this means we checkout different versions of the software at different heights instead of littering the code
|
||||||
with conditionals
|
with conditionals
|
||||||
- minimize the number of data migrations required across AppVersion (ie. most AppVersion should be able to read the same state from disk as previous AppVersion).
|
- minimize the number of data migrations required across AppVersion (ie. most AppVersion should be able to read the same state from disk as previous AppVersion).
|
||||||
@ -125,7 +123,6 @@ serve as a complete description of the consensus-critical protocol.
|
|||||||
Using the `NextVersion` field, proposer's can signal their readiness to upgrade
|
Using the `NextVersion` field, proposer's can signal their readiness to upgrade
|
||||||
to a new Block and/or App version.
|
to a new Block and/or App version.
|
||||||
|
|
||||||
|
|
||||||
### NodeInfo
|
### NodeInfo
|
||||||
|
|
||||||
NodeInfo should include a Version struct as its first field like:
|
NodeInfo should include a Version struct as its first field like:
|
||||||
@ -150,7 +147,6 @@ it's SemVer version - this is for convenience only. Eg.
|
|||||||
|
|
||||||
The other versions and ChainID will determine peer compatibility (described below).
|
The other versions and ChainID will determine peer compatibility (described below).
|
||||||
|
|
||||||
|
|
||||||
### ABCI
|
### ABCI
|
||||||
|
|
||||||
Since the ABCI is responsible for keeping Tendermint and the App in sync, we
|
Since the ABCI is responsible for keeping Tendermint and the App in sync, we
|
||||||
@ -280,7 +276,6 @@ checking out and installing new software versions and restarting the process. It
|
|||||||
would subscribe to the relevant upgrade event (needs to be implemented) and call `/unsafe_stop` at
|
would subscribe to the relevant upgrade event (needs to be implemented) and call `/unsafe_stop` at
|
||||||
the correct height (of course only after getting approval from its user!)
|
the correct height (of course only after getting approval from its user!)
|
||||||
|
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
### Positive
|
### Positive
|
||||||
|
@ -54,7 +54,6 @@ they will each require a new identifier, and the old chain identifier will be re
|
|||||||
|
|
||||||
We need a consistent way to describe forks.
|
We need a consistent way to describe forks.
|
||||||
|
|
||||||
|
|
||||||
## Proposal
|
## Proposal
|
||||||
|
|
||||||
### ChainDescription
|
### ChainDescription
|
||||||
@ -92,9 +91,9 @@ ChainDescription = <ChainID>/x/<Height>/<ForkDescription>
|
|||||||
```
|
```
|
||||||
|
|
||||||
Where
|
Where
|
||||||
|
|
||||||
- ChainID is the ChainID from the previous ChainDescription (ie. its hash)
|
- ChainID is the ChainID from the previous ChainDescription (ie. its hash)
|
||||||
- `x` denotes that a change occured
|
- `x` denotes that a change occured
|
||||||
- `Height` is the height the change occured
|
- `Height` is the height the change occured
|
||||||
- ForkDescription has the same form as ChainDescription but for the fork
|
- ForkDescription has the same form as ChainDescription but for the fork
|
||||||
- this allows forks to specify new versions for tendermint or the app, as well as arbitrary changes to the state or validator set
|
- this allows forks to specify new versions for tendermint or the app, as well as arbitrary changes to the state or validator set
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ type ThresholdMultiSignaturePubKey struct { // K of N threshold multisig
|
|||||||
Pubkeys []crypto.Pubkey `json:"pubkeys"`
|
Pubkeys []crypto.Pubkey `json:"pubkeys"`
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
We will derive N from the length of pubkeys. (For spatial efficiency in encoding)
|
We will derive N from the length of pubkeys. (For spatial efficiency in encoding)
|
||||||
|
|
||||||
`Verify` will expect an `[]byte` encoded version of the Multisignature.
|
`Verify` will expect an `[]byte` encoded version of the Multisignature.
|
||||||
@ -70,6 +71,7 @@ type WeightedThresholdMultiSignaturePubKey struct {
|
|||||||
Pubkeys []crypto.Pubkey `json:"pubkeys"`
|
Pubkeys []crypto.Pubkey `json:"pubkeys"`
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Weights and Pubkeys must be of the same length.
|
Weights and Pubkeys must be of the same length.
|
||||||
Everything else proceeds identically to the K of N multisig,
|
Everything else proceeds identically to the K of N multisig,
|
||||||
except the multisig fails if the sum of the weights is less than the threshold.
|
except the multisig fails if the sum of the weights is less than the threshold.
|
||||||
@ -77,6 +79,7 @@ except the multisig fails if the sum of the weights is less than the threshold.
|
|||||||
#### Multisignature
|
#### Multisignature
|
||||||
|
|
||||||
The inter-mediate phase of the signatures (as it accrues more signatures) will be the following struct:
|
The inter-mediate phase of the signatures (as it accrues more signatures) will be the following struct:
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
type Multisignature struct {
|
type Multisignature struct {
|
||||||
BitArray CryptoBitArray // Documented later
|
BitArray CryptoBitArray // Documented later
|
||||||
@ -88,21 +91,26 @@ So no signing algorithm ever outputs the multisignature.
|
|||||||
The UI will take a signature, cast into a multisignature, and then keep adding
|
The UI will take a signature, cast into a multisignature, and then keep adding
|
||||||
new signatures into it, and when done marshal into `[]byte`.
|
new signatures into it, and when done marshal into `[]byte`.
|
||||||
This will require the following helper methods:
|
This will require the following helper methods:
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
func SigToMultisig(sig []byte, n int)
|
func SigToMultisig(sig []byte, n int)
|
||||||
func GetIndex(pk crypto.Pubkey, []crypto.Pubkey)
|
func GetIndex(pk crypto.Pubkey, []crypto.Pubkey)
|
||||||
func AddSignature(sig Signature, index int, multiSig *Multisignature)
|
func AddSignature(sig Signature, index int, multiSig *Multisignature)
|
||||||
```
|
```
|
||||||
|
|
||||||
The multisignature will be converted to an `[]byte` using amino.MarshalBinaryBare. \*
|
The multisignature will be converted to an `[]byte` using amino.MarshalBinaryBare. \*
|
||||||
|
|
||||||
#### Bit Array
|
#### Bit Array
|
||||||
|
|
||||||
We would be using a new implementation of a bitarray. The struct it would be encoded/decoded from is
|
We would be using a new implementation of a bitarray. The struct it would be encoded/decoded from is
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
type CryptoBitArray struct {
|
type CryptoBitArray struct {
|
||||||
ExtraBitsStored byte `json:"extra_bits"` // The number of extra bits in elems.
|
ExtraBitsStored byte `json:"extra_bits"` // The number of extra bits in elems.
|
||||||
Elems []byte `json:"elems"`
|
Elems []byte `json:"elems"`
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The reason for not using the BitArray currently implemented in `libs/common/bit_array.go`
|
The reason for not using the BitArray currently implemented in `libs/common/bit_array.go`
|
||||||
is that it is less space efficient, due to a space / time trade-off.
|
is that it is less space efficient, due to a space / time trade-off.
|
||||||
Evidence for this is outlined in [this issue](https://github.com/tendermint/tendermint/issues/2077).
|
Evidence for this is outlined in [this issue](https://github.com/tendermint/tendermint/issues/2077).
|
||||||
@ -138,13 +146,15 @@ Proposed.
|
|||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
### Positive
|
### Positive
|
||||||
* Supports multisignatures, in a way that won't require any special cases in our downstream verification code.
|
|
||||||
* Easy to serialize / deserialize
|
- Supports multisignatures, in a way that won't require any special cases in our downstream verification code.
|
||||||
* Unbounded number of signers
|
- Easy to serialize / deserialize
|
||||||
|
- Unbounded number of signers
|
||||||
|
|
||||||
### Negative
|
### Negative
|
||||||
* Larger codebase, however this should reside in a subfolder of tendermint/crypto, as it provides no new interfaces. (Ref #https://github.com/tendermint/go-crypto/issues/136)
|
|
||||||
* Space inefficient due to utilization of amino encoding
|
- Larger codebase, however this should reside in a subfolder of tendermint/crypto, as it provides no new interfaces. (Ref #https://github.com/tendermint/go-crypto/issues/136)
|
||||||
* Suggested implementation requires a new struct for every ASM.
|
- Space inefficient due to utilization of amino encoding
|
||||||
|
- Suggested implementation requires a new struct for every ASM.
|
||||||
|
|
||||||
### Neutral
|
### Neutral
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
### Positive
|
### Positive
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
"prettier": "^1.13.7",
|
"prettier": "^1.13.7",
|
||||||
"remark-cli": "^5.0.0",
|
"remark-cli": "^5.0.0",
|
||||||
"remark-lint-no-dead-urls": "^0.3.0",
|
"remark-lint-no-dead-urls": "^0.3.0",
|
||||||
"textlint": "^10.2.1"
|
"remark-lint-write-good": "^1.0.3",
|
||||||
|
"textlint": "^10.2.1",
|
||||||
|
"textlint-rule-stop-words": "^1.0.3"
|
||||||
},
|
},
|
||||||
"name": "tendermint",
|
"name": "tendermint",
|
||||||
"description": "Tendermint Core Documentation",
|
"description": "Tendermint Core Documentation",
|
||||||
@ -31,7 +33,8 @@
|
|||||||
"homepage": "https://tendermint.com/docs/",
|
"homepage": "https://tendermint.com/docs/",
|
||||||
"remarkConfig": {
|
"remarkConfig": {
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"remark-lint-no-dead-urls"
|
"remark-lint-no-dead-urls",
|
||||||
|
"remark-lint-write-good"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ is malicious or faulty.
|
|||||||
A commit in Tendermint is a set of signed messages from more than 2/3 of
|
A commit in Tendermint is a set of signed messages from more than 2/3 of
|
||||||
the total weight of the current Validator set. Validators take turns proposing
|
the total weight of the current Validator set. Validators take turns proposing
|
||||||
blocks and voting on them. Once enough votes are received, the block is considered
|
blocks and voting on them. Once enough votes are received, the block is considered
|
||||||
committed. These votes are included in the *next* block as proof that the previous block
|
committed. These votes are included in the _next_ block as proof that the previous block
|
||||||
was committed - they cannot be included in the current block, as that block has already been
|
was committed - they cannot be included in the current block, as that block has already been
|
||||||
created.
|
created.
|
||||||
|
|
||||||
@ -71,8 +71,8 @@ of the latest state of the blockchain. To achieve this, it embeds
|
|||||||
cryptographic commitments to certain information in the block "header".
|
cryptographic commitments to certain information in the block "header".
|
||||||
This information includes the contents of the block (eg. the transactions),
|
This information includes the contents of the block (eg. the transactions),
|
||||||
the validator set committing the block, as well as the various results returned by the application.
|
the validator set committing the block, as well as the various results returned by the application.
|
||||||
Note, however, that block execution only occurs *after* a block is committed.
|
Note, however, that block execution only occurs _after_ a block is committed.
|
||||||
Thus, application results can only be included in the *next* block.
|
Thus, application results can only be included in the _next_ block.
|
||||||
|
|
||||||
Also note that information like the transaction results and the validator set are never
|
Also note that information like the transaction results and the validator set are never
|
||||||
directly included in the block - only their cryptographic digests (Merkle roots) are.
|
directly included in the block - only their cryptographic digests (Merkle roots) are.
|
||||||
|
@ -104,8 +104,8 @@ type Vote struct {
|
|||||||
```
|
```
|
||||||
|
|
||||||
There are two types of votes:
|
There are two types of votes:
|
||||||
a *prevote* has `vote.Type == 1` and
|
a _prevote_ has `vote.Type == 1` and
|
||||||
a *precommit* has `vote.Type == 2`.
|
a _precommit_ has `vote.Type == 2`.
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
@ -288,6 +288,7 @@ This can be used to validate the `LastCommit` included in the next block.
|
|||||||
```go
|
```go
|
||||||
block.NextValidatorsHash == SimpleMerkleRoot(state.NextValidators)
|
block.NextValidatorsHash == SimpleMerkleRoot(state.NextValidators)
|
||||||
```
|
```
|
||||||
|
|
||||||
Simple Merkle root of the next validator set that will be the validator set that commits the next block.
|
Simple Merkle root of the next validator set that will be the validator set that commits the next block.
|
||||||
Modifications to the validator set are defined by the application.
|
Modifications to the validator set are defined by the application.
|
||||||
|
|
||||||
@ -431,7 +432,4 @@ Execute(s State, app ABCIApp, block Block) State {
|
|||||||
ConsensusParams: UpdateConsensusParams(state.ConsensusParams, ConsensusParamChanges),
|
ConsensusParams: UpdateConsensusParams(state.ConsensusParams, ConsensusParamChanges),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,20 +48,20 @@ spec](https://github.com/tendermint/go-amino#computing-the-prefix-and-disambigua
|
|||||||
|
|
||||||
In what follows, we provide the type names and prefix bytes directly.
|
In what follows, we provide the type names and prefix bytes directly.
|
||||||
Notice that when encoding byte-arrays, the length of the byte-array is appended
|
Notice that when encoding byte-arrays, the length of the byte-array is appended
|
||||||
to the PrefixBytes. Thus the encoding of a byte array becomes `<PrefixBytes>
|
to the PrefixBytes. Thus the encoding of a byte array becomes `<PrefixBytes> <Length> <ByteArray>`. In other words, to encode any type listed below you do not need to be
|
||||||
<Length> <ByteArray>`. In other words, to encode any type listed below you do not need to be
|
|
||||||
familiar with amino encoding.
|
familiar with amino encoding.
|
||||||
You can simply use below table and concatenate Prefix || Length (of raw bytes) || raw bytes
|
You can simply use below table and concatenate Prefix || Length (of raw bytes) || raw bytes
|
||||||
( while || stands for byte concatenation here).
|
( while || stands for byte concatenation here).
|
||||||
|
|
||||||
| Type | Name | Prefix | Length | Notes |
|
| Type | Name | Prefix | Length | Notes |
|
||||||
| ---- | ---- | ------ | ----- | ------ |
|
| ------------------ | ----------------------------- | ---------- | -------- | ----- |
|
||||||
| PubKeyEd25519 | tendermint/PubKeyEd25519 | 0x1624DE64 | 0x20 | |
|
| PubKeyEd25519 | tendermint/PubKeyEd25519 | 0x1624DE64 | 0x20 | |
|
||||||
| PubKeySecp256k1 | tendermint/PubKeySecp256k1 | 0xEB5AE987 | 0x21 | |
|
| PubKeySecp256k1 | tendermint/PubKeySecp256k1 | 0xEB5AE987 | 0x21 | |
|
||||||
| PrivKeyEd25519 | tendermint/PrivKeyEd25519 | 0xA3288910 | 0x40 | |
|
| PrivKeyEd25519 | tendermint/PrivKeyEd25519 | 0xA3288910 | 0x40 | |
|
||||||
| PrivKeySecp256k1 | tendermint/PrivKeySecp256k1 | 0xE1B0F79B | 0x20 | |
|
| PrivKeySecp256k1 | tendermint/PrivKeySecp256k1 | 0xE1B0F79B | 0x20 | |
|
||||||
| SignatureEd25519 | tendermint/SignatureEd25519 | 0x2031EA53 | 0x40 | |
|
| SignatureEd25519 | tendermint/SignatureEd25519 | 0x2031EA53 | 0x40 | |
|
||||||
| SignatureSecp256k1 | tendermint/SignatureSecp256k1 | 0x7FC4A495 | variable |
|
| SignatureSecp256k1 | tendermint/SignatureSecp256k1 | 0x7FC4A495 | variable |
|
||||||
|
|
||||||
|
|
|
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
@ -152,7 +152,6 @@ func MakeParts(obj interface{}, partSize int) []Part
|
|||||||
For an overview of Merkle trees, see
|
For an overview of Merkle trees, see
|
||||||
[wikipedia](https://en.wikipedia.org/wiki/Merkle_tree)
|
[wikipedia](https://en.wikipedia.org/wiki/Merkle_tree)
|
||||||
|
|
||||||
|
|
||||||
A Simple Tree is a simple compact binary tree for a static list of items. Simple Merkle trees are used in numerous places in Tendermint to compute a cryptographic digest of a data structure. In a Simple Tree, the transactions and validation signatures of a block are hashed using this simple merkle tree logic.
|
A Simple Tree is a simple compact binary tree for a static list of items. Simple Merkle trees are used in numerous places in Tendermint to compute a cryptographic digest of a data structure. In a 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
|
If the number of items is not a power of two, the tree will not be full
|
||||||
@ -224,7 +223,6 @@ For `[]struct` arguments, we compute a `[][]byte` by hashing the individual `str
|
|||||||
|
|
||||||
Proof that a leaf is in a Merkle tree consists of a simple structure:
|
Proof that a leaf is in a Merkle tree consists of a simple structure:
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
type SimpleProof struct {
|
type SimpleProof struct {
|
||||||
Aunts [][]byte
|
Aunts [][]byte
|
||||||
@ -265,8 +263,8 @@ func computeHashFromAunts(index, total int, leafHash []byte, innerHashes [][]byt
|
|||||||
|
|
||||||
The Simple Tree is used to merkelize a list of items, so to merkelize a
|
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
|
(short) dictionary of key-value pairs, encode the dictionary as an
|
||||||
ordered list of ``KVPair`` structs. The block hash is such a hash
|
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
|
derived from all the fields of the block `Header`. The state hash is
|
||||||
similarly derived.
|
similarly derived.
|
||||||
|
|
||||||
### IAVL+ Tree
|
### IAVL+ Tree
|
||||||
@ -300,7 +298,6 @@ For instance, an ED25519 PubKey would look like:
|
|||||||
Where the `"value"` is the base64 encoding of the raw pubkey bytes, and the
|
Where the `"value"` is the base64 encoding of the raw pubkey bytes, and the
|
||||||
`"type"` is the full disfix bytes for Ed25519 pubkeys.
|
`"type"` is the full disfix bytes for Ed25519 pubkeys.
|
||||||
|
|
||||||
|
|
||||||
### Signed Messages
|
### Signed Messages
|
||||||
|
|
||||||
Signed messages (eg. votes, proposals) in the consensus are encoded using Amino-JSON, rather than in the standard binary format.
|
Signed messages (eg. votes, proposals) in the consensus are encoded using Amino-JSON, rather than in the standard binary format.
|
||||||
|
@ -75,7 +75,6 @@ func TotalVotingPower(vals []Validators) int64{
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### ConsensusParams
|
### ConsensusParams
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
@ -22,11 +22,11 @@ the voting power is not uniform (one process one vote), a vote message is actual
|
|||||||
number is equal to the voting power of the process that has casted the corresponding votes message.
|
number is equal to the voting power of the process that has casted the corresponding votes message.
|
||||||
|
|
||||||
Let's consider the following example:
|
Let's consider the following example:
|
||||||
|
|
||||||
- we have four processes p1, p2, p3 and p4, with the following voting power distribution (p1, 23), (p2, 27), (p3, 10)
|
- we have four processes p1, p2, p3 and p4, with the following voting power distribution (p1, 23), (p2, 27), (p3, 10)
|
||||||
and (p4, 10). The total voting power is 70 (`N = 3f+1`, where `N` is the total voting power, and `f` is the maximum voting
|
and (p4, 10). The total voting power is 70 (`N = 3f+1`, where `N` is the total voting power, and `f` is the maximum voting
|
||||||
power of the faulty processes), so we assume that the faulty processes have at most 23 of voting power.
|
power of the faulty processes), so we assume that the faulty processes have at most 23 of voting power.
|
||||||
Furthermore, we have the following vote messages in some LastCommit field (we ignore all fields except Time field):
|
Furthermore, we have the following vote messages in some LastCommit field (we ignore all fields except Time field): - (p1, 100), (p2, 98), (p3, 1000), (p4, 500). We assume that p3 and p4 are faulty processes. Let's assume that the
|
||||||
- (p1, 100), (p2, 98), (p3, 1000), (p4, 500). We assume that p3 and p4 are faulty processes. Let's assume that the
|
|
||||||
`block.LastCommit` message contains votes of processes p2, p3 and p4. Median is then chosen the following way:
|
`block.LastCommit` message contains votes of processes p2, p3 and p4. Median is then chosen the following way:
|
||||||
the value 98 is counted 27 times, the value 1000 is counted 10 times and the value 500 is counted also 10 times.
|
the value 98 is counted 27 times, the value 1000 is counted 10 times and the value 500 is counted also 10 times.
|
||||||
So the median value will be the value 98. No matter what set of messages with at least `2f+1` voting power we
|
So the median value will be the value 98. No matter what set of messages with at least `2f+1` voting power we
|
||||||
@ -35,8 +35,7 @@ Furthermore, we have the following vote messages in some LastCommit field (we ig
|
|||||||
We ensure Time Monotonicity and Time Validity properties by the following rules:
|
We ensure Time Monotonicity and Time Validity properties by the following rules:
|
||||||
|
|
||||||
- let rs denotes `RoundState` (consensus internal state) of some process. Then
|
- let rs denotes `RoundState` (consensus internal state) of some process. Then
|
||||||
`rs.ProposalBlock.Header.Time == median(rs.LastCommit) &&
|
`rs.ProposalBlock.Header.Time == median(rs.LastCommit) && rs.Proposal.Timestamp == rs.ProposalBlock.Header.Time`.
|
||||||
rs.Proposal.Timestamp == rs.ProposalBlock.Header.Time`.
|
|
||||||
|
|
||||||
- Furthermore, when creating the `vote` message, the following rules for determining `vote.Time` field should hold:
|
- Furthermore, when creating the `vote` message, the following rules for determining `vote.Time` field should hold:
|
||||||
|
|
||||||
@ -52,5 +51,3 @@ rs.Proposal.Timestamp == rs.ProposalBlock.Header.Time`.
|
|||||||
where `getVotes` function returns the votes for particular `Height`, `Round` and `Type`.
|
where `getVotes` function returns the votes for particular `Height`, `Round` and `Type`.
|
||||||
The second rule is relevant for the case when a process jumps to a higher round upon receiving +2/3 votes for a higher
|
The second rule is relevant for the case when a process jumps to a higher round upon receiving +2/3 votes for a higher
|
||||||
round, but the corresponding `Proposal` message for the higher round hasn't been received yet.
|
round, but the corresponding `Proposal` message for the higher round hasn't been received yet.
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,31 +2,31 @@
|
|||||||
|
|
||||||
## Terms
|
## Terms
|
||||||
|
|
||||||
- The network is composed of optionally connected *nodes*. Nodes
|
- The network is composed of optionally connected _nodes_. Nodes
|
||||||
directly connected to a particular node are called *peers*.
|
directly connected to a particular node are called _peers_.
|
||||||
- The consensus process in deciding the next block (at some *height*
|
- The consensus process in deciding the next block (at some _height_
|
||||||
`H`) is composed of one or many *rounds*.
|
`H`) is composed of one or many _rounds_.
|
||||||
- `NewHeight`, `Propose`, `Prevote`, `Precommit`, and `Commit`
|
- `NewHeight`, `Propose`, `Prevote`, `Precommit`, and `Commit`
|
||||||
represent state machine states of a round. (aka `RoundStep` or
|
represent state machine states of a round. (aka `RoundStep` or
|
||||||
just "step").
|
just "step").
|
||||||
- A node is said to be *at* a given height, round, and step, or at
|
- 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.
|
`(H,R,S)`, or at `(H,R)` in short to omit the step.
|
||||||
- To *prevote* or *precommit* something means to broadcast a [prevote
|
- To _prevote_ or _precommit_ something means to broadcast a [prevote
|
||||||
vote](https://godoc.org/github.com/tendermint/tendermint/types#Vote)
|
vote](https://godoc.org/github.com/tendermint/tendermint/types#Vote)
|
||||||
or [first precommit
|
or [first precommit
|
||||||
vote](https://godoc.org/github.com/tendermint/tendermint/types#FirstPrecommit)
|
vote](https://godoc.org/github.com/tendermint/tendermint/types#FirstPrecommit)
|
||||||
for something.
|
for something.
|
||||||
- A vote *at* `(H,R)` is a vote signed with the bytes for `H` and `R`
|
- A vote _at_ `(H,R)` is a vote signed with the bytes for `H` and `R`
|
||||||
included in its [sign-bytes](block-structure.html#vote-sign-bytes).
|
included in its [sign-bytes](block-structure.html#vote-sign-bytes).
|
||||||
- *+2/3* is short for "more than 2/3"
|
- _+2/3_ is short for "more than 2/3"
|
||||||
- *1/3+* is short for "1/3 or more"
|
- _1/3+_ is short for "1/3 or more"
|
||||||
- A set of +2/3 of prevotes for a particular block or `<nil>` at
|
- 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.
|
`(H,R)` is called a _proof-of-lock-change_ or _PoLC_ for short.
|
||||||
|
|
||||||
## State Machine Overview
|
## State Machine Overview
|
||||||
|
|
||||||
At each height of the blockchain a round-based protocol is run to
|
At each height of the blockchain a round-based protocol is run to
|
||||||
determine the next block. Each round is composed of three *steps*
|
determine the next block. Each round is composed of three _steps_
|
||||||
(`Propose`, `Prevote`, and `Precommit`), along with two special steps
|
(`Propose`, `Prevote`, and `Precommit`), along with two special steps
|
||||||
`Commit` and `NewHeight`.
|
`Commit` and `NewHeight`.
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ In the optimal scenario, the order of steps is:
|
|||||||
NewHeight -> (Propose -> Prevote -> Precommit)+ -> Commit -> NewHeight ->...
|
NewHeight -> (Propose -> Prevote -> Precommit)+ -> Commit -> NewHeight ->...
|
||||||
```
|
```
|
||||||
|
|
||||||
The sequence `(Propose -> Prevote -> Precommit)` is called a *round*.
|
The sequence `(Propose -> Prevote -> Precommit)` is called a _round_.
|
||||||
There may be more than one round required to commit a block at a given
|
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:
|
height. Examples for why more rounds may be required include:
|
||||||
|
|
||||||
@ -80,14 +80,13 @@ parameters over each successive round.
|
|||||||
+--------------------------------------------------------------------+
|
+--------------------------------------------------------------------+
|
||||||
```
|
```
|
||||||
|
|
||||||
Background Gossip
|
# Background Gossip
|
||||||
=================
|
|
||||||
|
|
||||||
A node may not have a corresponding validator private key, but it
|
A node may not have a corresponding validator private key, but it
|
||||||
nevertheless plays an active role in the consensus process by relaying
|
nevertheless plays an active role in the consensus process by relaying
|
||||||
relevant meta-data, proposals, blocks, and votes to its peers. A node
|
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
|
that has the private keys of an active validator and is engaged in
|
||||||
signing votes is called a *validator-node*. All nodes (not just
|
signing votes is called a _validator-node_. All nodes (not just
|
||||||
validator-nodes) have an associated state (the current height, round,
|
validator-nodes) have an associated state (the current height, round,
|
||||||
and step) and work to make progress.
|
and step) and work to make progress.
|
||||||
|
|
||||||
@ -161,6 +160,7 @@ receiving any +2/3 prevotes. --> goto `Precommit(H,R)` - After
|
|||||||
### Precommit Step (height:H,round:R)
|
### Precommit Step (height:H,round:R)
|
||||||
|
|
||||||
Upon entering `Precommit`, each validator broadcasts its precommit vote.
|
Upon entering `Precommit`, each validator broadcasts its precommit vote.
|
||||||
|
|
||||||
- If the validator has a PoLC at `(H,R)` for a particular block `B`, it
|
- 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
|
(re)locks (or changes lock to) and precommits `B` and sets
|
||||||
`LastLockRound = R`. - Else, if the validator has a PoLC at `(H,R)` for
|
`LastLockRound = R`. - Else, if the validator has a PoLC at `(H,R)` for
|
||||||
@ -236,7 +236,7 @@ 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
|
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
|
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
|
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
|
_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
|
commit-set) are each justified in the JSet with no duplicitous vote
|
||||||
signatures (by the committers).
|
signatures (by the committers).
|
||||||
|
|
||||||
|
@ -46,7 +46,6 @@ names are slightly different); we shortened (and modified) it for the purpose of
|
|||||||
clear and simple. Furthermore, note that in case of the third function, the returned header has `ValSetNumber` equals to
|
clear and simple. Furthermore, note that in case of the third function, the returned header has `ValSetNumber` equals to
|
||||||
`valSetNumber+1`.
|
`valSetNumber+1`.
|
||||||
|
|
||||||
|
|
||||||
Locally, light client manages the following state:
|
Locally, light client manages the following state:
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
|
|
||||||
`MConnection` is a multiplex connection that supports multiple independent streams
|
`MConnection` is a multiplex connection that supports multiple independent streams
|
||||||
with distinct quality of service guarantees atop a single TCP connection.
|
with distinct quality of service guarantees atop a single TCP connection.
|
||||||
Each stream is known as a `Channel` and each `Channel` has a globally unique *byte id*.
|
Each stream is known as a `Channel` and each `Channel` has a globally unique _byte id_.
|
||||||
Each `Channel` also has a relative priority that determines the quality of service
|
Each `Channel` also has a relative priority that determines the quality of service
|
||||||
of the `Channel` compared to other `Channel`s.
|
of the `Channel` compared to other `Channel`s.
|
||||||
The *byte id* and the relative priorities of each `Channel` are configured upon
|
The _byte id_ and the relative priorities of each `Channel` are configured upon
|
||||||
initialization of the connection.
|
initialization of the connection.
|
||||||
|
|
||||||
The `MConnection` supports three packet types:
|
The `MConnection` supports three packet types:
|
||||||
@ -53,6 +53,7 @@ Messages are chosen for a batch one at a time from the channel with the lowest r
|
|||||||
## Sending Messages
|
## Sending Messages
|
||||||
|
|
||||||
There are two methods for sending messages:
|
There are two methods for sending messages:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (m MConnection) Send(chID byte, msg interface{}) bool {}
|
func (m MConnection) Send(chID byte, msg interface{}) bool {}
|
||||||
func (m MConnection) TrySend(chID byte, msg interface{}) bool {}
|
func (m MConnection) TrySend(chID byte, msg interface{}) bool {}
|
||||||
|
@ -17,6 +17,7 @@ See [the peer-exchange docs](https://github.com/tendermint/tendermint/blob/maste
|
|||||||
## New Full Node
|
## New Full Node
|
||||||
|
|
||||||
A new node needs a few things to connect to the network:
|
A new node needs a few things to connect to the network:
|
||||||
|
|
||||||
- a list of seeds, which can be provided to Tendermint via config file or flags,
|
- a list of seeds, which can be provided to Tendermint via config file or flags,
|
||||||
or hardcoded into the software by in-process apps
|
or hardcoded into the software by in-process apps
|
||||||
- a `ChainID`, also called `Network` at the p2p layer
|
- a `ChainID`, also called `Network` at the p2p layer
|
||||||
|
@ -29,6 +29,7 @@ Both handshakes have configurable timeouts (they should complete quickly).
|
|||||||
Tendermint implements the Station-to-Station protocol
|
Tendermint implements the Station-to-Station protocol
|
||||||
using X25519 keys for Diffie-Helman key-exchange and chacha20poly1305 for encryption.
|
using X25519 keys for Diffie-Helman key-exchange and chacha20poly1305 for encryption.
|
||||||
It goes as follows:
|
It goes as follows:
|
||||||
|
|
||||||
- generate an ephemeral X25519 keypair
|
- generate an ephemeral X25519 keypair
|
||||||
- send the ephemeral public key to the peer
|
- send the ephemeral public key to the peer
|
||||||
- wait to receive the peer's ephemeral public key
|
- wait to receive the peer's ephemeral public key
|
||||||
@ -48,7 +49,6 @@ using the respective secret and nonce. Each nonce is incremented by one after ea
|
|||||||
- wait to receive the persistent public key and signature from the peer
|
- wait to receive the persistent public key and signature from the peer
|
||||||
- verify the signature on the challenge using the peer's persistent public key
|
- verify the signature on the challenge using the peer's persistent public key
|
||||||
|
|
||||||
|
|
||||||
If this is an outgoing connection (we dialed the peer) and we used a peer ID,
|
If this is an outgoing connection (we dialed the peer) and we used a peer ID,
|
||||||
then finally verify that the peer's persistent public key corresponds to the peer ID we dialed,
|
then finally verify that the peer's persistent public key corresponds to the peer ID we dialed,
|
||||||
ie. `peer.PubKey.Address() == <ID>`.
|
ie. `peer.PubKey.Address() == <ID>`.
|
||||||
@ -69,7 +69,6 @@ an optional whitelist which can be managed through the ABCI app -
|
|||||||
if the whitelist is enabled and the peer does not qualify, the connection is
|
if the whitelist is enabled and the peer does not qualify, the connection is
|
||||||
terminated.
|
terminated.
|
||||||
|
|
||||||
|
|
||||||
### Tendermint Version Handshake
|
### Tendermint Version Handshake
|
||||||
|
|
||||||
The Tendermint Version Handshake allows the peers to exchange their NodeInfo:
|
The Tendermint Version Handshake allows the peers to exchange their NodeInfo:
|
||||||
@ -89,6 +88,7 @@ type NodeInfo struct {
|
|||||||
```
|
```
|
||||||
|
|
||||||
The connection is disconnected if:
|
The connection is disconnected if:
|
||||||
|
|
||||||
- `peer.NodeInfo.ID` is not equal `peerConn.ID`
|
- `peer.NodeInfo.ID` is not equal `peerConn.ID`
|
||||||
- `peer.NodeInfo.Version` is not formatted as `X.X.X` where X are integers known as Major, Minor, and Revision
|
- `peer.NodeInfo.Version` is not formatted as `X.X.X` where X are integers known as Major, Minor, and Revision
|
||||||
- `peer.NodeInfo.Version` Major is not the same as ours
|
- `peer.NodeInfo.Version` Major is not the same as ours
|
||||||
@ -97,7 +97,6 @@ The connection is disconnected if:
|
|||||||
- `peer.NodeInfo.ListenAddr` is malformed or is a DNS host that cannot be
|
- `peer.NodeInfo.ListenAddr` is malformed or is a DNS host that cannot be
|
||||||
resolved
|
resolved
|
||||||
|
|
||||||
|
|
||||||
At this point, if we have not disconnected, the peer is valid.
|
At this point, if we have not disconnected, the peer is valid.
|
||||||
It is added to the switch and hence all reactors via the `AddPeer` method.
|
It is added to the switch and hence all reactors via the `AddPeer` method.
|
||||||
Note that each reactor may handle multiple channels.
|
Note that each reactor may handle multiple channels.
|
||||||
|
@ -1,46 +1,46 @@
|
|||||||
## Blockchain Reactor
|
## Blockchain Reactor
|
||||||
|
|
||||||
* coordinates the pool for syncing
|
- coordinates the pool for syncing
|
||||||
* coordinates the store for persistence
|
- coordinates the store for persistence
|
||||||
* coordinates the playing of blocks towards the app using a sm.BlockExecutor
|
- coordinates the playing of blocks towards the app using a sm.BlockExecutor
|
||||||
* handles switching between fastsync and consensus
|
- handles switching between fastsync and consensus
|
||||||
* it is a p2p.BaseReactor
|
- it is a p2p.BaseReactor
|
||||||
* starts the pool.Start() and its poolRoutine()
|
- starts the pool.Start() and its poolRoutine()
|
||||||
* registers all the concrete types and interfaces for serialisation
|
- registers all the concrete types and interfaces for serialisation
|
||||||
|
|
||||||
### poolRoutine
|
### poolRoutine
|
||||||
|
|
||||||
* listens to these channels:
|
- listens to these channels:
|
||||||
* pool requests blocks from a specific peer by posting to requestsCh, block reactor then sends
|
- pool requests blocks from a specific peer by posting to requestsCh, block reactor then sends
|
||||||
a &bcBlockRequestMessage for a specific height
|
a &bcBlockRequestMessage for a specific height
|
||||||
* pool signals timeout of a specific peer by posting to timeoutsCh
|
- pool signals timeout of a specific peer by posting to timeoutsCh
|
||||||
* switchToConsensusTicker to periodically try and switch to consensus
|
- switchToConsensusTicker to periodically try and switch to consensus
|
||||||
* trySyncTicker to periodically check if we have fallen behind and then catch-up sync
|
- trySyncTicker to periodically check if we have fallen behind and then catch-up sync
|
||||||
* if there aren't any new blocks available on the pool it skips syncing
|
- if there aren't any new blocks available on the pool it skips syncing
|
||||||
* tries to sync the app by taking downloaded blocks from the pool, gives them to the app and stores
|
- tries to sync the app by taking downloaded blocks from the pool, gives them to the app and stores
|
||||||
them on disk
|
them on disk
|
||||||
* implements Receive which is called by the switch/peer
|
- implements Receive which is called by the switch/peer
|
||||||
* calls AddBlock on the pool when it receives a new block from a peer
|
- calls AddBlock on the pool when it receives a new block from a peer
|
||||||
|
|
||||||
## Block Pool
|
## Block Pool
|
||||||
|
|
||||||
* responsible for downloading blocks from peers
|
- responsible for downloading blocks from peers
|
||||||
* makeRequestersRoutine()
|
- makeRequestersRoutine()
|
||||||
* removes timeout peers
|
- removes timeout peers
|
||||||
* starts new requesters by calling makeNextRequester()
|
- starts new requesters by calling makeNextRequester()
|
||||||
* requestRoutine():
|
- requestRoutine():
|
||||||
* picks a peer and sends the request, then blocks until:
|
- picks a peer and sends the request, then blocks until:
|
||||||
* pool is stopped by listening to pool.Quit
|
- pool is stopped by listening to pool.Quit
|
||||||
* requester is stopped by listening to Quit
|
- requester is stopped by listening to Quit
|
||||||
* request is redone
|
- request is redone
|
||||||
* we receive a block
|
- we receive a block
|
||||||
* gotBlockCh is strange
|
- gotBlockCh is strange
|
||||||
|
|
||||||
## Block Store
|
## Block Store
|
||||||
|
|
||||||
* persists blocks to disk
|
- persists blocks to disk
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
* How does the switch from bcR to conR happen? Does conR persist blocks to disk too?
|
- How does the switch from bcR to conR happen? Does conR persist blocks to disk too?
|
||||||
* What is the interaction between the consensus and blockchain reactors?
|
- What is the interaction between the consensus and blockchain reactors?
|
||||||
|
@ -47,10 +47,10 @@ type bcStatusResponseMessage struct {
|
|||||||
## Architecture and algorithm
|
## Architecture and algorithm
|
||||||
|
|
||||||
The Blockchain reactor is organised as a set of concurrent tasks:
|
The Blockchain reactor is organised as a set of concurrent tasks:
|
||||||
|
|
||||||
- Receive routine of Blockchain Reactor
|
- Receive routine of Blockchain Reactor
|
||||||
- Task for creating Requesters
|
- Task for creating Requesters
|
||||||
- Set of Requesters tasks and
|
- Set of Requesters tasks and - Controller task.
|
||||||
- Controller task.
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@ -58,8 +58,7 @@ The Blockchain reactor is organised as a set of concurrent tasks:
|
|||||||
|
|
||||||
These are the core data structures necessarily to provide the Blockchain Reactor logic.
|
These are the core data structures necessarily to provide the Blockchain Reactor logic.
|
||||||
|
|
||||||
Requester data structure is used to track assignment of request for `block` at position `height` to a
|
Requester data structure is used to track assignment of request for `block` at position `height` to a peer with id equals to `peerID`.
|
||||||
peer with id equals to `peerID`.
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type Requester {
|
type Requester {
|
||||||
@ -70,25 +69,24 @@ type Requester {
|
|||||||
redoChannel chan struct{}
|
redoChannel chan struct{}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Pool is core data structure that stores last executed block (`height`), assignment of requests to peers (`requesters`),
|
|
||||||
current height for each peer and number of pending requests for each peer (`peers`), maximum peer height, etc.
|
Pool is core data structure that stores last executed block (`height`), assignment of requests to peers (`requesters`), current height for each peer and number of pending requests for each peer (`peers`), maximum peer height, etc.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type Pool {
|
type Pool {
|
||||||
mtx Mutex
|
mtx Mutex
|
||||||
requesters map[int64]*Requester
|
requesters map[int64]*Requester
|
||||||
height int64
|
height int64
|
||||||
peers map[p2p.ID]*Peer
|
peers map[p2p.ID]*Peer
|
||||||
maxPeerHeight int64
|
maxPeerHeight int64
|
||||||
numPending int32
|
numPending int32
|
||||||
store BlockStore
|
store BlockStore
|
||||||
requestsChannel chan<- BlockRequest
|
requestsChannel chan<- BlockRequest
|
||||||
errorsChannel chan<- peerError
|
errorsChannel chan<- peerError
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Peer data structure stores for each peer current `height` and number of pending requests sent to
|
Peer data structure stores for each peer current `height` and number of pending requests sent to the peer (`numPending`), etc.
|
||||||
the peer (`numPending`), etc.
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type Peer struct {
|
type Peer struct {
|
||||||
@ -100,8 +98,7 @@ type Peer struct {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
BlockRequest is internal data structure used to denote current mapping of request for a block at some `height` to
|
BlockRequest is internal data structure used to denote current mapping of request for a block at some `height` to a peer (`PeerID`).
|
||||||
a peer (`PeerID`).
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type BlockRequest {
|
type BlockRequest {
|
||||||
@ -112,9 +109,7 @@ type BlockRequest {
|
|||||||
|
|
||||||
### Receive routine of Blockchain Reactor
|
### Receive routine of Blockchain Reactor
|
||||||
|
|
||||||
It is executed upon message reception on the BlockchainChannel inside p2p receive routine. There is a separate p2p
|
It is executed upon message reception on the BlockchainChannel inside p2p receive routine. There is a separate p2p receive routine (and therefore receive routine of the Blockchain Reactor) executed for each peer. Note that try to send will not block (returns immediately) if outgoing buffer is full.
|
||||||
receive routine (and therefore receive routine of the Blockchain Reactor) executed for each peer. Note that
|
|
||||||
try to send will not block (returns immediately) if outgoing buffer is full.
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
handleMsg(pool, m):
|
handleMsg(pool, m):
|
||||||
@ -209,10 +204,13 @@ pickAvailablePeer(height):
|
|||||||
|
|
||||||
return selectedPeer
|
return selectedPeer
|
||||||
```
|
```
|
||||||
|
|
||||||
sleep for requestIntervalMS
|
sleep for requestIntervalMS
|
||||||
|
|
||||||
### Task for creating Requesters
|
### Task for creating Requesters
|
||||||
|
|
||||||
This task is responsible for continuously creating and starting Requester tasks.
|
This task is responsible for continuously creating and starting Requester tasks.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
createRequesters(pool):
|
createRequesters(pool):
|
||||||
while true do
|
while true do
|
||||||
@ -240,8 +238,8 @@ createRequesters(pool):
|
|||||||
pool.mtx.Unlock()
|
pool.mtx.Unlock()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Main blockchain reactor controller task
|
### Main blockchain reactor controller task
|
||||||
|
|
||||||
```go
|
```go
|
||||||
main(pool):
|
main(pool):
|
||||||
create trySyncTicker with interval trySyncIntervalMS
|
create trySyncTicker with interval trySyncIntervalMS
|
||||||
|
@ -22,7 +22,6 @@ Inside Consensus State we have the following units of execution: Timeout Ticker
|
|||||||
Timeout Ticker is a timer that schedules timeouts conditional on the height/round/step that are processed
|
Timeout Ticker is a timer that schedules timeouts conditional on the height/round/step that are processed
|
||||||
by the Receive Routine.
|
by the Receive Routine.
|
||||||
|
|
||||||
|
|
||||||
### Receive Routine of the ConsensusState service
|
### Receive Routine of the ConsensusState service
|
||||||
|
|
||||||
Receive Routine of the ConsensusState handles messages which may cause internal consensus state transitions.
|
Receive Routine of the ConsensusState handles messages which may cause internal consensus state transitions.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Look at the concurrency model this uses...
|
Look at the concurrency model this uses...
|
||||||
|
|
||||||
* Receiving CheckTx
|
- Receiving CheckTx
|
||||||
* Broadcasting new tx
|
- Broadcasting new tx
|
||||||
* Interfaces with consensus engine, reap/update while checking
|
- Interfaces with consensus engine, reap/update while checking
|
||||||
* Calling the ABCI app (ordering. callbacks. how proxy works alongside the blockchain proxy which actually writes blocks)
|
- Calling the ABCI app (ordering. callbacks. how proxy works alongside the blockchain proxy which actually writes blocks)
|
||||||
|
@ -11,12 +11,12 @@ Flag: `--mempool.recheck_empty=false`
|
|||||||
Environment: `TM_MEMPOOL_RECHECK_EMPTY=false`
|
Environment: `TM_MEMPOOL_RECHECK_EMPTY=false`
|
||||||
|
|
||||||
Config:
|
Config:
|
||||||
|
|
||||||
```
|
```
|
||||||
[mempool]
|
[mempool]
|
||||||
recheck_empty = false
|
recheck_empty = false
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Recheck
|
## Recheck
|
||||||
|
|
||||||
`--mempool.recheck=false` (default: true)
|
`--mempool.recheck=false` (default: true)
|
||||||
|
@ -6,26 +6,25 @@ consensus reactor when it is selected as the block proposer.
|
|||||||
|
|
||||||
There are two sides to the mempool state:
|
There are two sides to the mempool state:
|
||||||
|
|
||||||
* External: get, check, and broadcast new transactions
|
- External: get, check, and broadcast new transactions
|
||||||
* Internal: return valid transaction, update list after block commit
|
- Internal: return valid transaction, update list after block commit
|
||||||
|
|
||||||
|
|
||||||
## External functionality
|
## External functionality
|
||||||
|
|
||||||
External functionality is exposed via network interfaces
|
External functionality is exposed via network interfaces
|
||||||
to potentially untrusted actors.
|
to potentially untrusted actors.
|
||||||
|
|
||||||
* CheckTx - triggered via RPC or P2P
|
- CheckTx - triggered via RPC or P2P
|
||||||
* Broadcast - gossip messages after a successful check
|
- Broadcast - gossip messages after a successful check
|
||||||
|
|
||||||
## Internal functionality
|
## Internal functionality
|
||||||
|
|
||||||
Internal functionality is exposed via method calls to other
|
Internal functionality is exposed via method calls to other
|
||||||
code compiled into the tendermint binary.
|
code compiled into the tendermint binary.
|
||||||
|
|
||||||
* Reap - get tx to propose in next block
|
- Reap - get tx to propose in next block
|
||||||
* Update - remove tx that were included in last block
|
- Update - remove tx that were included in last block
|
||||||
* ABCI.CheckTx - call ABCI app to validate the tx
|
- ABCI.CheckTx - call ABCI app to validate the tx
|
||||||
|
|
||||||
What does it provide the consensus reactor?
|
What does it provide the consensus reactor?
|
||||||
What guarantees does it need from the ABCI app?
|
What guarantees does it need from the ABCI app?
|
||||||
|
@ -95,6 +95,7 @@ remove from address book completely.
|
|||||||
## Select Peers to Exchange
|
## Select Peers to Exchange
|
||||||
|
|
||||||
When we’re asked for peers, we select them as follows:
|
When we’re asked for peers, we select them as follows:
|
||||||
|
|
||||||
- select at most `maxGetSelection` peers
|
- select at most `maxGetSelection` peers
|
||||||
- try to select at least `minGetSelection` peers - if we have less than that, select them all.
|
- try to select at least `minGetSelection` peers - if we have less than that, select them all.
|
||||||
- select a random, unbiased `getSelectionPercent` of the peers
|
- select a random, unbiased `getSelectionPercent` of the peers
|
||||||
@ -126,4 +127,3 @@ to use it in the PEX.
|
|||||||
See the [trustmetric](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-006-trust-metric.md)
|
See the [trustmetric](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-006-trust-metric.md)
|
||||||
and [trustmetric useage](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-007-trust-metric-usage.md)
|
and [trustmetric useage](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-007-trust-metric-usage.md)
|
||||||
architecture docs for more details.
|
architecture docs for more details.
|
||||||
|
|
||||||
|
@ -44,7 +44,6 @@ Thus, during Commit, it is safe to reset the QueryState and the CheckTxState to
|
|||||||
Note, however, that it is not possible to send transactions to Tendermint during Commit - if your app
|
Note, however, that it is not possible to send transactions to Tendermint during Commit - if your app
|
||||||
tries to send a `/broadcast_tx` to Tendermint during Commit, it will deadlock.
|
tries to send a `/broadcast_tx` to Tendermint during Commit, it will deadlock.
|
||||||
|
|
||||||
|
|
||||||
## EndBlock Validator Updates
|
## EndBlock Validator Updates
|
||||||
|
|
||||||
Updates to the Tendermint validator set can be made by returning `Validator`
|
Updates to the Tendermint validator set can be made by returning `Validator`
|
||||||
@ -60,10 +59,10 @@ message PubKey {
|
|||||||
string type
|
string type
|
||||||
bytes data
|
bytes data
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The `pub_key` currently supports two types:
|
The `pub_key` currently supports two types:
|
||||||
|
|
||||||
- `type = "ed25519" and`data = <raw 32-byte public key>`
|
- `type = "ed25519" and`data = <raw 32-byte public key>`
|
||||||
- `type = "secp256k1" and `data = <33-byte OpenSSL compressed public key>`
|
- `type = "secp256k1" and `data = <33-byte OpenSSL compressed public key>`
|
||||||
|
|
||||||
@ -128,11 +127,9 @@ On startup, Tendermint calls Info on the Query connection to get the latest
|
|||||||
committed state of the app. The app MUST return information consistent with the
|
committed state of the app. The app MUST return information consistent with the
|
||||||
last block it succesfully completed Commit for.
|
last block it succesfully completed Commit for.
|
||||||
|
|
||||||
If the app succesfully committed block H but not H+1, then `last_block_height =
|
If the app succesfully committed block H but not H+1, then `last_block_height = H` and `last_block_app_hash = <hash returned by Commit for block H>`. If the app
|
||||||
H` and `last_block_app_hash = <hash returned by Commit for block H>`. If the app
|
|
||||||
failed during the Commit of block H, then `last_block_height = H-1` and
|
failed during the Commit of block H, then `last_block_height = H-1` and
|
||||||
`last_block_app_hash = <hash returned by Commit for block H-1, which is the hash
|
`last_block_app_hash = <hash returned by Commit for block H-1, which is the hash in the header of block H>`.
|
||||||
in the header of block H>`.
|
|
||||||
|
|
||||||
We now distinguish three heights, and describe how Tendermint syncs itself with
|
We now distinguish three heights, and describe how Tendermint syncs itself with
|
||||||
the app.
|
the app.
|
||||||
|
6
docs/stop-words.txt
Normal file
6
docs/stop-words.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
investor
|
||||||
|
invest
|
||||||
|
investing
|
||||||
|
token distribution
|
||||||
|
atom distribution
|
||||||
|
distribution of atoms
|
@ -66,7 +66,7 @@ effects of running that transaction will be first visible in the
|
|||||||
`AppHash` from the block header at height `H+1`.
|
`AppHash` from the block header at height `H+1`.
|
||||||
|
|
||||||
Like the `LastCommit` issue, this is a requirement of the immutability
|
Like the `LastCommit` issue, this is a requirement of the immutability
|
||||||
of the block chain, as the application only applies transactions *after*
|
of the block chain, as the application only applies transactions _after_
|
||||||
they are commited to the chain.
|
they are commited to the chain.
|
||||||
|
|
||||||
## Commit
|
## Commit
|
||||||
@ -90,7 +90,7 @@ you look at the code, you will notice that we need to provide the
|
|||||||
`chainID` of the blockchain in order to properly calculate the votes.
|
`chainID` of the blockchain in order to properly calculate the votes.
|
||||||
This is to protect anyone from swapping votes between chains to fake (or
|
This is to protect anyone from swapping votes between chains to fake (or
|
||||||
frame) a validator. Also note that this `chainID` is in the
|
frame) a validator. Also note that this `chainID` is in the
|
||||||
`genesis.json` from *Tendermint*, not the `genesis.json` from the
|
`genesis.json` from _Tendermint_, not the `genesis.json` from the
|
||||||
basecoin app ([that is a different
|
basecoin app ([that is a different
|
||||||
chainID...](https://github.com/cosmos/cosmos-sdk/issues/32)).
|
chainID...](https://github.com/cosmos/cosmos-sdk/issues/32)).
|
||||||
|
|
||||||
|
@ -135,10 +135,10 @@ Tendermint, replay will fail with panic.
|
|||||||
|
|
||||||
Recovering from data corruption can be hard and time-consuming. Here are two approaches you can take:
|
Recovering from data corruption can be hard and time-consuming. Here are two approaches you can take:
|
||||||
|
|
||||||
1) Delete the WAL file and restart Tendermint. It will attempt to sync with other peers.
|
1. Delete the WAL file and restart Tendermint. It will attempt to sync with other peers.
|
||||||
2) Try to repair the WAL file manually:
|
2. Try to repair the WAL file manually:
|
||||||
|
|
||||||
1. Create a backup of the corrupted WAL file:
|
1) Create a backup of the corrupted WAL file:
|
||||||
|
|
||||||
```
|
```
|
||||||
cp "$TMHOME/data/cs.wal/wal" > /tmp/corrupted_wal_backup
|
cp "$TMHOME/data/cs.wal/wal" > /tmp/corrupted_wal_backup
|
||||||
@ -161,6 +161,7 @@ cp "$TMHOME/data/cs.wal/wal" > /tmp/corrupted_wal_backup
|
|||||||
```
|
```
|
||||||
$EDITOR /tmp/corrupted_wal
|
$EDITOR /tmp/corrupted_wal
|
||||||
```
|
```
|
||||||
|
|
||||||
5. After editing, convert this file back into binary form by running:
|
5. After editing, convert this file back into binary form by running:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Validators are responsible for committing new blocks in the blockchain.
|
Validators are responsible for committing new blocks in the blockchain.
|
||||||
These validators participate in the consensus protocol by broadcasting
|
These validators participate in the consensus protocol by broadcasting
|
||||||
*votes* which contain cryptographic signatures signed by each
|
_votes_ which contain cryptographic signatures signed by each
|
||||||
validator's private key.
|
validator's private key.
|
||||||
|
|
||||||
Some Proof-of-Stake consensus algorithms aim to create a "completely"
|
Some Proof-of-Stake consensus algorithms aim to create a "completely"
|
||||||
@ -28,12 +28,12 @@ There are two ways to become validator.
|
|||||||
|
|
||||||
## Committing a Block
|
## Committing a Block
|
||||||
|
|
||||||
*+2/3 is short for "more than 2/3"*
|
_+2/3 is short for "more than 2/3"_
|
||||||
|
|
||||||
A block is committed when +2/3 of the validator set sign [precommit
|
A block is committed when +2/3 of the validator set sign [precommit
|
||||||
votes](../spec/blockchain/blockchain.md#vote) for that block at the same `round`.
|
votes](../spec/blockchain/blockchain.md#vote) for that block at the same `round`.
|
||||||
The +2/3 set of precommit votes is called a
|
The +2/3 set of precommit votes is called a
|
||||||
[*commit*](../spec/blockchain/blockchain.md#commit). While any +2/3 set of
|
[_commit_](../spec/blockchain/blockchain.md#commit). While any +2/3 set of
|
||||||
precommits for the same block at the same height&round can serve as
|
precommits for the same block at the same height&round can serve as
|
||||||
validation, the canonical commit is included in the next block (see
|
validation, the canonical commit is included in the next block (see
|
||||||
[LastCommit](../spec/blockchain/blockchain.md#last-commit)).
|
[LastCommit](../spec/blockchain/blockchain.md#last-commit)).
|
||||||
|
@ -26,6 +26,7 @@ use `kvstore`:
|
|||||||
docker run -it --rm -v "/tmp:/tendermint" tendermint/tendermint init
|
docker run -it --rm -v "/tmp:/tendermint" tendermint/tendermint init
|
||||||
docker run -it --rm -v "/tmp:/tendermint" -p "26657:26657" --name=tm tendermint/tendermint node --proxy_app=kvstore
|
docker run -it --rm -v "/tmp:/tendermint" -p "26657:26657" --name=tm tendermint/tendermint node --proxy_app=kvstore
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
docker run -it --rm -p "26670:26670" --link=tm tendermint/monitor tm:26657
|
docker run -it --rm -p "26670:26670" --link=tm tendermint/monitor tm:26657
|
||||||
```
|
```
|
||||||
|
2611
docs/yarn.lock
Normal file
2611
docs/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user