mirror of
https://github.com/tendermint/tendermint.git
synced 2026-07-29 19:42:51 +00:00
ci: add markdown linter (#146)
This commit is contained in:
+106
-106
@@ -36,29 +36,29 @@ the data in the current block, the previous block, and the results returned by t
|
||||
|
||||
```go
|
||||
type Header struct {
|
||||
// basic block info
|
||||
Version Version
|
||||
ChainID string
|
||||
Height int64
|
||||
Time Time
|
||||
// basic block info
|
||||
Version Version
|
||||
ChainID string
|
||||
Height int64
|
||||
Time Time
|
||||
|
||||
// prev block info
|
||||
LastBlockID BlockID
|
||||
// prev block info
|
||||
LastBlockID BlockID
|
||||
|
||||
// hashes of block data
|
||||
LastCommitHash []byte // commit from validators from the last block
|
||||
DataHash []byte // MerkleRoot of transaction hashes
|
||||
// hashes of block data
|
||||
LastCommitHash []byte // commit from validators from the last block
|
||||
DataHash []byte // MerkleRoot of transaction hashes
|
||||
|
||||
// hashes from the app output from the prev block
|
||||
ValidatorsHash []byte // validators for the current block
|
||||
NextValidatorsHash []byte // validators for the next block
|
||||
ConsensusHash []byte // consensus params for current block
|
||||
AppHash []byte // state after txs from the previous block
|
||||
LastResultsHash []byte // root hash of all results from the txs from the previous block
|
||||
// hashes from the app output from the prev block
|
||||
ValidatorsHash []byte // validators for the current block
|
||||
NextValidatorsHash []byte // validators for the next block
|
||||
ConsensusHash []byte // consensus params for current block
|
||||
AppHash []byte // state after txs from the previous block
|
||||
LastResultsHash []byte // root hash of all results from the txs from the previous block
|
||||
|
||||
// consensus info
|
||||
EvidenceHash []byte // evidence included in the block
|
||||
ProposerAddress []byte // original proposer of the block
|
||||
// consensus info
|
||||
EvidenceHash []byte // evidence included in the block
|
||||
ProposerAddress []byte // original proposer of the block
|
||||
```
|
||||
|
||||
Further details on each of these fields is described below.
|
||||
@@ -67,8 +67,8 @@ Further details on each of these fields is described below.
|
||||
|
||||
```go
|
||||
type Version struct {
|
||||
Block uint64
|
||||
App uint64
|
||||
Block uint64
|
||||
App uint64
|
||||
}
|
||||
```
|
||||
|
||||
@@ -111,7 +111,7 @@ format, which uses two integers, one for Seconds and for Nanoseconds.
|
||||
Data is just a wrapper for a list of transactions, where transactions are
|
||||
arbitrary byte arrays:
|
||||
|
||||
```
|
||||
```go
|
||||
type Data struct {
|
||||
Txs [][]byte
|
||||
}
|
||||
@@ -124,10 +124,10 @@ validator. It also contains the relevant BlockID, height and round:
|
||||
|
||||
```go
|
||||
type Commit struct {
|
||||
Height int64
|
||||
Round int
|
||||
BlockID BlockID
|
||||
Signatures []CommitSig
|
||||
Height int64
|
||||
Round int
|
||||
BlockID BlockID
|
||||
Signatures []CommitSig
|
||||
}
|
||||
```
|
||||
|
||||
@@ -141,19 +141,19 @@ to reconstruct the vote set given the validator set.
|
||||
type BlockIDFlag byte
|
||||
|
||||
const (
|
||||
// BlockIDFlagAbsent - no vote was received from a validator.
|
||||
BlockIDFlagAbsent BlockIDFlag = 0x01
|
||||
// BlockIDFlagCommit - voted for the Commit.BlockID.
|
||||
BlockIDFlagCommit = 0x02
|
||||
// BlockIDFlagNil - voted for nil.
|
||||
BlockIDFlagNil = 0x03
|
||||
// BlockIDFlagAbsent - no vote was received from a validator.
|
||||
BlockIDFlagAbsent BlockIDFlag = 0x01
|
||||
// BlockIDFlagCommit - voted for the Commit.BlockID.
|
||||
BlockIDFlagCommit = 0x02
|
||||
// BlockIDFlagNil - voted for nil.
|
||||
BlockIDFlagNil = 0x03
|
||||
)
|
||||
|
||||
type CommitSig struct {
|
||||
BlockIDFlag BlockIDFlag
|
||||
ValidatorAddress Address
|
||||
Timestamp time.Time
|
||||
Signature []byte
|
||||
BlockIDFlag BlockIDFlag
|
||||
ValidatorAddress Address
|
||||
Timestamp time.Time
|
||||
Signature []byte
|
||||
}
|
||||
```
|
||||
|
||||
@@ -168,14 +168,14 @@ The vote includes information about the validator signing it.
|
||||
|
||||
```go
|
||||
type Vote struct {
|
||||
Type byte
|
||||
Height int64
|
||||
Round int
|
||||
BlockID BlockID
|
||||
Timestamp Time
|
||||
ValidatorAddress []byte
|
||||
ValidatorIndex int
|
||||
Signature []byte
|
||||
Type byte
|
||||
Height int64
|
||||
Round int
|
||||
BlockID BlockID
|
||||
Timestamp Time
|
||||
ValidatorAddress []byte
|
||||
ValidatorIndex int
|
||||
Signature []byte
|
||||
}
|
||||
```
|
||||
|
||||
@@ -193,7 +193,7 @@ See the [signature spec](./encoding.md#key-types) for more.
|
||||
|
||||
EvidenceData is a simple wrapper for a list of evidence:
|
||||
|
||||
```
|
||||
```go
|
||||
type EvidenceData struct {
|
||||
Evidence []Evidence
|
||||
}
|
||||
@@ -201,40 +201,40 @@ type EvidenceData struct {
|
||||
|
||||
## Evidence
|
||||
|
||||
Evidence in Tendermint is used to indicate breaches in the consensus by a validator.
|
||||
Evidence in Tendermint is used to indicate breaches in the consensus by a validator.
|
||||
It is implemented as the following interface.
|
||||
|
||||
```go
|
||||
type Evidence interface {
|
||||
Height() int64 // height of the equivocation
|
||||
Time() time.Time // time of the equivocation
|
||||
Address() []byte // address of the equivocating validator
|
||||
Bytes() []byte // bytes which comprise the evidence
|
||||
Hash() []byte // hash of the evidence
|
||||
Verify(chainID string, pubKey crypto.PubKey) error // verify the evidence
|
||||
Equal(Evidence) bool // check equality of evidence
|
||||
Height() int64 // height of the equivocation
|
||||
Time() time.Time // time of the equivocation
|
||||
Address() []byte // address of the equivocating validator
|
||||
Bytes() []byte // bytes which comprise the evidence
|
||||
Hash() []byte // hash of the evidence
|
||||
Verify(chainID string, pubKey crypto.PubKey) error // verify the evidence
|
||||
Equal(Evidence) bool // check equality of evidence
|
||||
|
||||
ValidateBasic() error
|
||||
String() string
|
||||
ValidateBasic() error
|
||||
String() string
|
||||
}
|
||||
```
|
||||
|
||||
All evidence can be encoded and decoded to and from Protobuf with the `EvidenceToProto()`
|
||||
and `EvidenceFromProto()` functions. The [Fork Accountability](../consensus/light-client/accountability.md)
|
||||
All evidence can be encoded and decoded to and from Protobuf with the `EvidenceToProto()`
|
||||
and `EvidenceFromProto()` functions. The [Fork Accountability](../consensus/light-client/accountability.md)
|
||||
document provides a good overview for the types of evidence and how they occur. For evidence to be committed onchain, it must adhere to the validation rules of each evidence and must not be expired. The expiration age, measured in both block height and time is set in `EvidenceParams`. Each evidence uses
|
||||
the timestamp of the block that the evidence occured at to indicate the age of the evidence.
|
||||
the timestamp of the block that the evidence occured at to indicate the age of the evidence.
|
||||
|
||||
### DuplicateVoteEvidence
|
||||
### DuplicateVoteEvidence
|
||||
|
||||
`DuplicateVoteEvidence` represents a validator that has voted for two different blocks
|
||||
`DuplicateVoteEvidence` represents a validator that has voted for two different blocks
|
||||
in the same round of the same height. Votes are lexicographically sorted on `BlockID`.
|
||||
|
||||
```go
|
||||
type DuplicateVoteEvidence struct {
|
||||
VoteA *Vote
|
||||
VoteB *Vote
|
||||
|
||||
Timestamp time.Time
|
||||
VoteA *Vote
|
||||
VoteB *Vote
|
||||
|
||||
Timestamp time.Time
|
||||
}
|
||||
```
|
||||
|
||||
@@ -252,15 +252,15 @@ Valid Duplicate Vote Evidence must adhere to the following rules:
|
||||
|
||||
### AmensiaEvidence
|
||||
|
||||
`AmnesiaEvidence` represents a validator that has incorrectly voted for another block in a
|
||||
`AmnesiaEvidence` represents a validator that has incorrectly voted for another block in a
|
||||
different round to the the block that the validator was previously locked on. This form
|
||||
of evidence is generated differently from the rest. See this
|
||||
of evidence is generated differently from the rest. See this
|
||||
[ADR](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-056-proving-amnesia-attacks.md) for more information.
|
||||
|
||||
```go
|
||||
type AmnesiaEvidence struct {
|
||||
*PotentialAmnesiaEvidence
|
||||
Polc *ProofOfLockChange
|
||||
*PotentialAmnesiaEvidence
|
||||
Polc *ProofOfLockChange
|
||||
}
|
||||
```
|
||||
|
||||
@@ -280,16 +280,16 @@ Valid Amnesia Evidence must adhere to the following rules:
|
||||
|
||||
### LunaticValidatorEvidence
|
||||
|
||||
`LunaticValidatorEvidence` represents a validator that has signed for an arbitrary application state.
|
||||
`LunaticValidatorEvidence` represents a validator that has signed for an arbitrary application state.
|
||||
This attack only applies to Light clients.
|
||||
|
||||
```go
|
||||
type LunaticValidatorEvidence struct {
|
||||
Header *Header
|
||||
Vote *Vote
|
||||
InvalidHeaderField string
|
||||
|
||||
Timestamp time.Time
|
||||
Header *Header
|
||||
Vote *Vote
|
||||
InvalidHeaderField string
|
||||
|
||||
Timestamp time.Time
|
||||
}
|
||||
```
|
||||
|
||||
@@ -330,7 +330,7 @@ A Header is valid if its corresponding fields are valid.
|
||||
|
||||
### Version
|
||||
|
||||
```
|
||||
```go
|
||||
block.Version.Block == state.Version.Consensus.Block
|
||||
block.Version.App == state.Version.Consensus.App
|
||||
```
|
||||
@@ -339,7 +339,7 @@ The block version must match consensus version from the state.
|
||||
|
||||
### ChainID
|
||||
|
||||
```
|
||||
```go
|
||||
len(block.ChainID) < 50
|
||||
```
|
||||
|
||||
@@ -357,7 +357,7 @@ The height is an incrementing integer. The first block has `block.Header.Height
|
||||
|
||||
### Time
|
||||
|
||||
```
|
||||
```go
|
||||
block.Header.Timestamp >= prevBlock.Header.Timestamp + state.consensusParams.Block.TimeIotaMs
|
||||
block.Header.Timestamp == MedianTime(block.LastCommit, state.LastValidators)
|
||||
```
|
||||
@@ -371,7 +371,7 @@ block being voted on.
|
||||
The timestamp of the first block must be equal to the genesis time (since
|
||||
there's no votes to compute the median).
|
||||
|
||||
```
|
||||
```go
|
||||
if block.Header.Height == state.InitialHeight {
|
||||
block.Header.Timestamp == genesisTime
|
||||
}
|
||||
@@ -543,21 +543,21 @@ using the given ChainID:
|
||||
|
||||
```go
|
||||
func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error {
|
||||
if !bytes.Equal(pubKey.Address(), vote.ValidatorAddress) {
|
||||
return ErrVoteInvalidValidatorAddress
|
||||
}
|
||||
if !bytes.Equal(pubKey.Address(), vote.ValidatorAddress) {
|
||||
return ErrVoteInvalidValidatorAddress
|
||||
}
|
||||
|
||||
if !pubKey.VerifyBytes(vote.SignBytes(chainID), vote.Signature) {
|
||||
return ErrVoteInvalidSignature
|
||||
}
|
||||
return nil
|
||||
if !pubKey.VerifyBytes(vote.SignBytes(chainID), vote.Signature) {
|
||||
return ErrVoteInvalidSignature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
where `pubKey.Verify` performs the appropriate digital signature verification of the `pubKey`
|
||||
against the given signature and message bytes.
|
||||
|
||||
# Execution
|
||||
## Execution
|
||||
|
||||
Once a block is validated, it can be executed against the state.
|
||||
|
||||
@@ -574,26 +574,26 @@ set (TODO). Execute is defined as:
|
||||
|
||||
```go
|
||||
func Execute(s State, app ABCIApp, block Block) State {
|
||||
// Fuction ApplyBlock executes block of transactions against the app and returns the new root hash of the app state,
|
||||
// modifications to the validator set and the changes of the consensus parameters.
|
||||
AppHash, ValidatorChanges, ConsensusParamChanges := app.ApplyBlock(block)
|
||||
// Fuction ApplyBlock executes block of transactions against the app and returns the new root hash of the app state,
|
||||
// modifications to the validator set and the changes of the consensus parameters.
|
||||
AppHash, ValidatorChanges, ConsensusParamChanges := app.ApplyBlock(block)
|
||||
|
||||
nextConsensusParams := UpdateConsensusParams(state.ConsensusParams, ConsensusParamChanges)
|
||||
return State{
|
||||
ChainID: state.ChainID,
|
||||
InitialHeight: state.InitialHeight,
|
||||
LastResults: abciResponses.DeliverTxResults,
|
||||
AppHash: AppHash,
|
||||
InitialHeight: state.InitialHeight,
|
||||
LastValidators: state.Validators,
|
||||
Validators: state.NextValidators,
|
||||
NextValidators: UpdateValidators(state.NextValidators, ValidatorChanges),
|
||||
ConsensusParams: nextConsensusParams,
|
||||
Version: {
|
||||
Consensus: {
|
||||
AppVersion: nextConsensusParams.Version.AppVersion,
|
||||
},
|
||||
},
|
||||
}
|
||||
nextConsensusParams := UpdateConsensusParams(state.ConsensusParams, ConsensusParamChanges)
|
||||
return State{
|
||||
ChainID: state.ChainID,
|
||||
InitialHeight: state.InitialHeight,
|
||||
LastResults: abciResponses.DeliverTxResults,
|
||||
AppHash: AppHash,
|
||||
InitialHeight: state.InitialHeight,
|
||||
LastValidators: state.Validators,
|
||||
Validators: state.NextValidators,
|
||||
NextValidators: UpdateValidators(state.NextValidators, ValidatorChanges),
|
||||
ConsensusParams: nextConsensusParams,
|
||||
Version: {
|
||||
Consensus: {
|
||||
AppVersion: nextConsensusParams.Version.AppVersion,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
+43
-43
@@ -86,7 +86,7 @@ TODO: pubkey
|
||||
|
||||
The address is the first 20-bytes of the SHA256 hash of the raw 32-byte public key:
|
||||
|
||||
```
|
||||
```go
|
||||
address = SHA256(pubkey)[:20]
|
||||
```
|
||||
|
||||
@@ -98,7 +98,7 @@ TODO: pubkey
|
||||
|
||||
The address is the first 20-bytes of the SHA256 hash of the raw 32-byte public key:
|
||||
|
||||
```
|
||||
```go
|
||||
address = SHA256(pubkey)[:20]
|
||||
```
|
||||
|
||||
@@ -110,7 +110,7 @@ TODO: pubkey
|
||||
|
||||
The address is the RIPEMD160 hash of the SHA256 hash of the OpenSSL compressed public key:
|
||||
|
||||
```
|
||||
```go
|
||||
address = RIPEMD160(SHA256(pubkey))
|
||||
```
|
||||
|
||||
@@ -194,7 +194,7 @@ The differences between RFC 6962 and the simplest form a merkle tree are that:
|
||||
(The largest power of two less than the number of items) This allows new leaves to be added with less
|
||||
recomputation. For example:
|
||||
|
||||
```
|
||||
```md
|
||||
Simple Tree with 6 items Simple Tree with 7 items
|
||||
|
||||
* *
|
||||
@@ -223,29 +223,29 @@ func emptyHash() []byte {
|
||||
|
||||
// SHA256(0x00 || leaf)
|
||||
func leafHash(leaf []byte) []byte {
|
||||
return tmhash.Sum(append(0x00, leaf...))
|
||||
return tmhash.Sum(append(0x00, leaf...))
|
||||
}
|
||||
|
||||
// SHA256(0x01 || left || right)
|
||||
func innerHash(left []byte, right []byte) []byte {
|
||||
return tmhash.Sum(append(0x01, append(left, right...)...))
|
||||
return tmhash.Sum(append(0x01, append(left, right...)...))
|
||||
}
|
||||
|
||||
// largest power of 2 less than k
|
||||
func getSplitPoint(k int) { ... }
|
||||
|
||||
func MerkleRoot(items [][]byte) []byte{
|
||||
switch len(items) {
|
||||
case 0:
|
||||
return empthHash()
|
||||
case 1:
|
||||
return leafHash(items[0])
|
||||
default:
|
||||
k := getSplitPoint(len(items))
|
||||
left := MerkleRoot(items[:k])
|
||||
right := MerkleRoot(items[k:])
|
||||
return innerHash(left, right)
|
||||
}
|
||||
switch len(items) {
|
||||
case 0:
|
||||
return empthHash()
|
||||
case 1:
|
||||
return leafHash(items[0])
|
||||
default:
|
||||
k := getSplitPoint(len(items))
|
||||
left := MerkleRoot(items[:k])
|
||||
right := MerkleRoot(items[k:])
|
||||
return innerHash(left, right)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -253,7 +253,7 @@ Note: `MerkleRoot` operates on items which are arbitrary byte arrays, not
|
||||
necessarily hashes. For items which need to be hashed first, we introduce the
|
||||
`Hashes` function:
|
||||
|
||||
```
|
||||
```go
|
||||
func Hashes(items [][]byte) [][]byte {
|
||||
return SHA256 of each item
|
||||
}
|
||||
@@ -281,31 +281,31 @@ Which is verified as follows:
|
||||
|
||||
```golang
|
||||
func (proof SimpleProof) Verify(rootHash []byte, leaf []byte) bool {
|
||||
assert(proof.LeafHash, leafHash(leaf)
|
||||
assert(proof.LeafHash, leafHash(leaf)
|
||||
|
||||
computedHash := computeHashFromAunts(proof.Index, proof.Total, proof.LeafHash, proof.Aunts)
|
||||
computedHash := computeHashFromAunts(proof.Index, proof.Total, proof.LeafHash, proof.Aunts)
|
||||
return computedHash == rootHash
|
||||
}
|
||||
|
||||
func computeHashFromAunts(index, total int, leafHash []byte, innerHashes [][]byte) []byte{
|
||||
assert(index < total && index >= 0 && total > 0)
|
||||
assert(index < total && index >= 0 && total > 0)
|
||||
|
||||
if total == 1{
|
||||
assert(len(proof.Aunts) == 0)
|
||||
return leafHash
|
||||
}
|
||||
if total == 1{
|
||||
assert(len(proof.Aunts) == 0)
|
||||
return leafHash
|
||||
}
|
||||
|
||||
assert(len(innerHashes) > 0)
|
||||
assert(len(innerHashes) > 0)
|
||||
|
||||
numLeft := getSplitPoint(total) // largest power of 2 less than total
|
||||
if index < numLeft {
|
||||
leftHash := computeHashFromAunts(index, numLeft, leafHash, innerHashes[:len(innerHashes)-1])
|
||||
assert(leftHash != nil)
|
||||
return innerHash(leftHash, innerHashes[len(innerHashes)-1])
|
||||
}
|
||||
rightHash := computeHashFromAunts(index-numLeft, total-numLeft, leafHash, innerHashes[:len(innerHashes)-1])
|
||||
assert(rightHash != nil)
|
||||
return innerHash(innerHashes[len(innerHashes)-1], rightHash)
|
||||
numLeft := getSplitPoint(total) // largest power of 2 less than total
|
||||
if index < numLeft {
|
||||
leftHash := computeHashFromAunts(index, numLeft, leafHash, innerHashes[:len(innerHashes)-1])
|
||||
assert(leftHash != nil)
|
||||
return innerHash(leftHash, innerHashes[len(innerHashes)-1])
|
||||
}
|
||||
rightHash := computeHashFromAunts(index-numLeft, total-numLeft, leafHash, innerHashes[:len(innerHashes)-1])
|
||||
assert(rightHash != nil)
|
||||
return innerHash(innerHashes[len(innerHashes)-1], rightHash)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -323,7 +323,7 @@ Because Tendermint only uses a Simple Merkle Tree, application developers are ex
|
||||
|
||||
Amino also supports JSON encoding - registered types are simply encoded as:
|
||||
|
||||
```
|
||||
```json
|
||||
{
|
||||
"type": "<amino type name>",
|
||||
"value": <JSON>
|
||||
@@ -332,7 +332,7 @@ Amino also supports JSON encoding - registered types are simply encoded as:
|
||||
|
||||
For instance, an ED25519 PubKey would look like:
|
||||
|
||||
```
|
||||
```json
|
||||
{
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "uZ4h63OFWuQ36ZZ4Bd6NF+/w9fWUwrOncrQsackrsTk="
|
||||
@@ -353,12 +353,12 @@ We call this encoding the SignBytes. For instance, SignBytes for a vote is the A
|
||||
|
||||
```go
|
||||
type CanonicalVote struct {
|
||||
Type byte
|
||||
Height int64 `binary:"fixed64"`
|
||||
Round int64 `binary:"fixed64"`
|
||||
BlockID CanonicalBlockID
|
||||
Timestamp time.Time
|
||||
ChainID string
|
||||
Type byte
|
||||
Height int64 `binary:"fixed64"`
|
||||
Round int64 `binary:"fixed64"`
|
||||
BlockID CanonicalBlockID
|
||||
Timestamp time.Time
|
||||
ChainID string
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
+22
-22
@@ -50,8 +50,8 @@ application as two `uint64` values:
|
||||
|
||||
```go
|
||||
type Consensus struct {
|
||||
Block uint64
|
||||
App uint64
|
||||
Block uint64
|
||||
App uint64
|
||||
}
|
||||
```
|
||||
|
||||
@@ -112,43 +112,43 @@ evolve without breaking the header.
|
||||
|
||||
```go
|
||||
type ConsensusParams struct {
|
||||
Block
|
||||
Evidence
|
||||
Validator
|
||||
Version
|
||||
Block
|
||||
Evidence
|
||||
Validator
|
||||
Version
|
||||
}
|
||||
|
||||
type hashedParams struct {
|
||||
BlockMaxBytes int64
|
||||
BlockMaxGas int64
|
||||
BlockMaxBytes int64
|
||||
BlockMaxGas int64
|
||||
}
|
||||
|
||||
func (params ConsensusParams) Hash() []byte {
|
||||
SHA256(hashedParams{
|
||||
BlockMaxBytes: params.Block.MaxBytes,
|
||||
BlockMaxGas: params.Block.MaxGas,
|
||||
})
|
||||
SHA256(hashedParams{
|
||||
BlockMaxBytes: params.Block.MaxBytes,
|
||||
BlockMaxGas: params.Block.MaxGas,
|
||||
})
|
||||
}
|
||||
|
||||
type BlockParams struct {
|
||||
MaxBytes int64
|
||||
MaxGas int64
|
||||
TimeIotaMs int64
|
||||
MaxBytes int64
|
||||
MaxGas int64
|
||||
TimeIotaMs int64
|
||||
}
|
||||
|
||||
type EvidenceParams struct {
|
||||
MaxAgeNumBlocks int64
|
||||
MaxAgeDuration time.Duration
|
||||
MaxNum uint32
|
||||
ProofTrialPeriod int64
|
||||
MaxAgeNumBlocks int64
|
||||
MaxAgeDuration time.Duration
|
||||
MaxNum uint32
|
||||
ProofTrialPeriod int64
|
||||
}
|
||||
|
||||
type ValidatorParams struct {
|
||||
PubKeyTypes []string
|
||||
PubKeyTypes []string
|
||||
}
|
||||
|
||||
type VersionParams struct {
|
||||
AppVersion uint64
|
||||
AppVersion uint64
|
||||
}
|
||||
```
|
||||
|
||||
@@ -170,7 +170,7 @@ For evidence in a block to be valid, it must satisfy:
|
||||
|
||||
```go
|
||||
block.Header.Time-evidence.Time < ConsensusParams.Evidence.MaxAgeDuration &&
|
||||
block.Header.Height-evidence.Height < ConsensusParams.Evidence.MaxAgeNumBlocks
|
||||
block.Header.Height-evidence.Height < ConsensusParams.Evidence.MaxAgeNumBlocks
|
||||
```
|
||||
|
||||
#### Validator
|
||||
|
||||
Reference in New Issue
Block a user