Browse Source

Cleanup build and structure

pull/1051/head
Adrian Brink 7 years ago
committed by Ethan Buchman
parent
commit
6366eb9d99
6 changed files with 191 additions and 170 deletions
  1. +1
    -0
      docs/.python-version
  2. +3
    -0
      docs/Makefile
  3. +26
    -27
      docs/specification/new-spec/blockchain.md
  4. +113
    -100
      docs/specification/new-spec/consensus.md
  5. +38
    -33
      docs/specification/new-spec/encoding.md
  6. +10
    -10
      docs/specification/new-spec/state.md

+ 1
- 0
docs/.python-version View File

@ -0,0 +1 @@
2.7.14

+ 3
- 0
docs/Makefile View File

@ -12,6 +12,9 @@ BUILDDIR = _build
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
install:
@pip install -r requirements.txt
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new


+ 26
- 27
docs/specification/new-spec/blockchain.md View File

@ -2,7 +2,7 @@
Here we describe the data structures in the Tendermint blockchain and the rules for validating them.
# Data Structures
## Data Structures
The Tendermint blockchains consists of a short list of basic data types:
`Block`, `Header`, `Vote`, `BlockID`, `Signature`, and `Evidence`.
@ -12,7 +12,7 @@ The Tendermint blockchains consists of a short list of basic data types:
A block consists of a header, a list of transactions, a list of votes (the commit),
and a list of evidence if malfeasance (ie. signing conflicting votes).
```
```go
type Block struct {
Header Header
Txs [][]byte
@ -26,7 +26,7 @@ type Block struct {
A block header contains metadata about the block and about the consensus, as well as commitments to
the data in the current block, the previous block, and the results returned by the application:
```
```go
type Header struct {
// block metadata
Version string // Version string
@ -66,7 +66,7 @@ the block during consensus, is the Merkle root of the complete serialized block
cut into parts. The `BlockID` includes these two hashes, as well as the number of
parts.
```
```go
type BlockID struct {
Hash []byte
Parts PartsHeader
@ -83,7 +83,7 @@ type PartsHeader struct {
A vote is a signed message from a validator for a particular block.
The vote includes information about the validator signing it.
```
```go
type Vote struct {
Timestamp int64
Address []byte
@ -96,7 +96,6 @@ type Vote struct {
}
```
There are two types of votes:
a prevote has `vote.Type == 1` and
a precommit has `vote.Type == 2`.
@ -111,7 +110,7 @@ Currently, Tendermint supports Ed25519 and Secp256k1.
An ED25519 signature has `Type == 0x1`. It looks like:
```
```go
// Implements Signature
type Ed25519Signature struct {
Type int8 = 0x1
@ -125,7 +124,7 @@ where `Signature` is the 64 byte signature.
A `Secp256k1` signature has `Type == 0x2`. It looks like:
```
```go
// Implements Signature
type Secp256k1Signature struct {
Type int8 = 0x2
@ -135,7 +134,7 @@ type Secp256k1Signature struct {
where `Signature` is the DER encoded signature, ie:
```
```hex
0x30 <length of whole message> <0x02> <length of R> <R> 0x2 <length of S> <S>.
```
@ -143,7 +142,7 @@ where `Signature` is the DER encoded signature, ie:
TODO
# Validation
## Validation
Here we describe the validation rules for every element in a block.
Blocks which do not satisfy these rules are considered invalid.
@ -159,7 +158,7 @@ and other results from the application.
Elements of an object are accessed as expected,
ie. `block.Header`. See [here](state.md) for the definition of `state`.
## Header
### Header
A Header is valid if its corresponding fields are valid.
@ -173,7 +172,7 @@ Arbitrary constant string.
### Height
```
```go
block.Header.Height > 0
block.Header.Height == prevBlock.Header.Height + 1
```
@ -190,7 +189,7 @@ block being voted on.
### NumTxs
```
```go
block.Header.NumTxs == len(block.Txs)
```
@ -198,7 +197,7 @@ Number of transactions included in the block.
### TxHash
```
```go
block.Header.TxHash == SimpleMerkleRoot(block.Txs)
```
@ -206,7 +205,7 @@ Simple Merkle root of the transactions in the block.
### LastCommitHash
```
```go
block.Header.LastCommitHash == SimpleMerkleRoot(block.LastCommit)
```
@ -217,7 +216,7 @@ The first block has `block.Header.LastCommitHash == []byte{}`
### TotalTxs
```
```go
block.Header.TotalTxs == prevBlock.Header.TotalTxs + block.Header.NumTxs
```
@ -227,7 +226,7 @@ The first block has `block.Header.TotalTxs = block.Header.NumberTxs`.
### LastBlockID
```
```go
prevBlockParts := MakeParts(prevBlock, state.LastConsensusParams.BlockGossip.BlockPartSize)
block.Header.LastBlockID == BlockID {
Hash: SimpleMerkleRoot(prevBlock.Header),
@ -245,7 +244,7 @@ The first block has `block.Header.LastBlockID == BlockID{}`.
### ResultsHash
```
```go
block.ResultsHash == SimpleMerkleRoot(state.LastResults)
```
@ -255,7 +254,7 @@ The first block has `block.Header.ResultsHash == []byte{}`.
### AppHash
```
```go
block.AppHash == state.AppHash
```
@ -265,7 +264,7 @@ The first block has `block.Header.AppHash == []byte{}`.
### ValidatorsHash
```
```go
block.ValidatorsHash == SimpleMerkleRoot(state.Validators)
```
@ -275,7 +274,7 @@ May be updated by the application.
### ConsensusParamsHash
```
```go
block.ConsensusParamsHash == SimpleMerkleRoot(state.ConsensusParams)
```
@ -284,7 +283,7 @@ May be updated by the application.
### Proposer
```
```go
block.Header.Proposer in state.Validators
```
@ -296,7 +295,7 @@ and we do not track the initial round the block was proposed.
### EvidenceHash
```
```go
block.EvidenceHash == SimpleMerkleRoot(block.Evidence)
```
@ -310,7 +309,7 @@ Arbitrary length array of arbitrary length byte-arrays.
The first height is an exception - it requires the LastCommit to be empty:
```
```go
if block.Header.Height == 1 {
len(b.LastCommit) == 0
}
@ -318,7 +317,7 @@ if block.Header.Height == 1 {
Otherwise, we require:
```
```go
len(block.LastCommit) == len(state.LastValidators)
talliedVotingPower := 0
for i, vote := range block.LastCommit{
@ -356,7 +355,7 @@ For signing, votes are encoded in JSON, and the ChainID is included, in the form
We define a method `Verify` that returns `true` if the signature verifies against the pubkey for the CanonicalSignBytes
using the given ChainID:
```
```go
func (v Vote) Verify(chainID string, pubKey PubKey) bool {
return pubKey.Verify(v.Signature, CanonicalSignBytes(chainID, v))
}
@ -384,7 +383,7 @@ Once a block is validated, it can be executed against the state.
The state follows the recursive equation:
```
```go
app = NewABCIApp
state(1) = InitialState
state(h+1) <- Execute(state(h), app, block(h))


+ 113
- 100
docs/specification/new-spec/consensus.md View File

@ -1,197 +1,210 @@
# Tendermint Consensus
# Tendermint Consensus Reactor
Tendermint consensus is a distributed protocol executed by validator processes to agree on
the next block to be added to the Tendermint blockchain. The protocol proceeds in rounds, where
each round is a try to reach agreement on the next block. A round starts by having a dedicated
process (called proposer) suggesting to other processes what should be the next block with
Tendermint Consensus is a distributed protocol executed by validator processes to agree on
the next block to be added to the Tendermint blockchain. The protocol proceeds in rounds, where
each round is a try to reach agreement on the next block. A round starts by having a dedicated
process (called proposer) suggesting to other processes what should be the next block with
the `ProposalMessage`.
The processes respond by voting for a block with `VoteMessage` (there are two kinds of vote messages, prevote
and precommit votes). Note that a proposal message is just a suggestion what the next block should be; a
validator might vote with a `VoteMessage` for a different block. If in some round, enough number
of processes vote for the same block, then this block is committed and later added to the blockchain.
The processes respond by voting for a block with `VoteMessage` (there are two kinds of vote messages, prevote
and precommit votes). Note that a proposal message is just a suggestion what the next block should be; a
validator might vote with a `VoteMessage` for a different block. If in some round, enough number
of processes vote for the same block, then this block is committed and later added to the blockchain.
`ProposalMessage` and `VoteMessage` are signed by the private key of the validator.
The internals of the protocol and how it ensures safety and liveness properties are
The internals of the protocol and how it ensures safety and liveness properties are
explained [here](https://github.com/tendermint/spec).
For efficiency reasons, validators in Tendermint consensus protocol do not agree directly on the block
as the block size is big, i.e., they don't embed the block inside `Proposal` and `VoteMessage`. Instead, they
reach agreement on the `BlockID` (see `BlockID` definition in [Blockchain](blockchain.md) section)
as the block size is big, i.e., they don't embed the block inside `Proposal` and `VoteMessage`. Instead, they
reach agreement on the `BlockID` (see `BlockID` definition in [Blockchain](blockchain.md) section)
that uniquely identifies each block. The block itself is disseminated to validator processes using
peer-to-peer gossiping protocol. It starts by having a proposer first splitting a block into a
number of block parts, that are then gossiped between processes using `BlockPartMessage`.
peer-to-peer gossiping protocol. It starts by having a proposer first splitting a block into a
number of block parts, that are then gossiped between processes using `BlockPartMessage`.
Validators in Tendermint communicate by peer-to-peer gossiping protocol. Each validator is connected
only to a subset of processes called peers. By the gossiping protocol, a validator send to its peers
all needed information (`ProposalMessage`, `VoteMessage` and `BlockPartMessage`) so they can
Validators in Tendermint communicate by peer-to-peer gossiping protocol. Each validator is connected
only to a subset of processes called peers. By the gossiping protocol, a validator send to its peers
all needed information (`ProposalMessage`, `VoteMessage` and `BlockPartMessage`) so they can
reach agreement on some block, and also obtain the content of the chosen block (block parts). As part of
the gossiping protocol, processes also send auxiliary messages that inform peers about the
executed steps of the core consensus algorithm (`NewRoundStepMessage` and `CommitStepMessage`), and
the gossiping protocol, processes also send auxiliary messages that inform peers about the
executed steps of the core consensus algorithm (`NewRoundStepMessage` and `CommitStepMessage`), and
also messages that inform peers what votes the process has seen (`HasVoteMessage`,
`VoteSetMaj23Message` and `VoteSetBitsMessage`). These messages are then used in the gossiping protocol
to determine what messages a process should send to its peers.
to determine what messages a process should send to its peers.
We now describe the content of each message exchanged during Tendermint consensus protocol.
## ProposalMessage
ProposalMessage is sent when a new block is proposed. It is a suggestion of what the
ProposalMessage is sent when a new block is proposed. It is a suggestion of what the
next block in the blockchain should be.
```
```go
type ProposalMessage struct {
Proposal Proposal
Proposal Proposal
}
```
### Proposal
Proposal contains height and round for which this proposal is made, BlockID as a unique identifier of proposed
block, timestamp, and two fields (POLRound and POLBlockID) that are needed for termination of the consensus.
The message is signed by the validator private key.
The message is signed by the validator private key.
```
```go
type Proposal struct {
Height int64
Round int
Timestamp Time
BlockID BlockID
POLRound int
POLBlockID BlockID
Signature Signature
Height int64
Round int
Timestamp Time
BlockID BlockID
POLRound int
POLBlockID BlockID
Signature Signature
}
```
NOTE: In the current version of the Tendermint, the consensus value in proposal is represented with
PartSetHeader, and with BlockID in vote message. It should be aligned as suggested in this spec as
BlockID contains PartSetHeader.
PartSetHeader, and with BlockID in vote message. It should be aligned as suggested in this spec as
BlockID contains PartSetHeader.
## VoteMessage
VoteMessage is sent to vote for some block (or to inform others that a process does not vote in the current round).
Vote is defined in [Blockchain](blockchain.md) section and contains validator's information (validator address
and index), height and round for which the vote is sent, vote type, blockID if process vote for some
Vote is defined in [Blockchain](blockchain.md) section and contains validator's information (validator address
and index), height and round for which the vote is sent, vote type, blockID if process vote for some
block (`nil` otherwise) and a timestamp when the vote is sent. The message is signed by the validator private key.
```
```go
type VoteMessage struct {
Vote Vote
Vote Vote
}
```
## BlockPartMessage
BlockPartMessage is sent when gossipping a piece of the proposed block. It contains height, round
and the block part.
```
BlockPartMessage is sent when gossipping a piece of the proposed block. It contains height, round
and the block part.
```go
type BlockPartMessage struct {
Height int64
Round int
Part Part
Height int64
Round int
Part Part
}
```
## ProposalHeartbeatMessage
ProposalHeartbeatMessage is sent to signal that a node is alive and waiting for transactions
## ProposalHeartbeatMessage
ProposalHeartbeatMessage is sent to signal that a node is alive and waiting for transactions
to be able to create a next block proposal.
```
```go
type ProposalHeartbeatMessage struct {
Heartbeat Heartbeat
}
```
### Heartbeat
Heartbeat contains validator information (address and index),
height, round and sequence number. It is signed by the private key of the validator.
height, round and sequence number. It is signed by the private key of the validator.
```
```go
type Heartbeat struct {
ValidatorAddress []byte
ValidatorIndex int
Height int64
Round int
Sequence int
Signature Signature
ValidatorAddress []byte
ValidatorIndex int
Height int64
Round int
Sequence int
Signature Signature
}
```
## NewRoundStepMessage
NewRoundStepMessage is sent for every step transition during the core consensus algorithm execution. It is
used in the gossip part of the Tendermint protocol to inform peers about a current height/round/step
NewRoundStepMessage is sent for every step transition during the core consensus algorithm execution. It is
used in the gossip part of the Tendermint protocol to inform peers about a current height/round/step
a process is in.
```
```go
type NewRoundStepMessage struct {
Height int64
Round int
Step RoundStepType
SecondsSinceStartTime int
LastCommitRound int
Height int64
Round int
Step RoundStepType
SecondsSinceStartTime int
LastCommitRound int
}
```
## CommitStepMessage
CommitStepMessage is sent when an agreement on some block is reached. It contains height for which agreement
is reached, block parts header that describes the decided block and is used to obtain all block parts,
and a bit array of the block parts a process currently has, so its peers can know what parts
it is missing so they can send them.
and a bit array of the block parts a process currently has, so its peers can know what parts
it is missing so they can send them.
```
```go
type CommitStepMessage struct {
Height int64
BlockID BlockID
BlockParts BitArray
Height int64
BlockID BlockID
BlockParts BitArray
}
```
TODO: We use BlockID instead of BlockPartsHeader (in current implementation) for symmetry.
TODO: We use BlockID instead of BlockPartsHeader (in current implementation) for symmetry.
## ProposalPOLMessage
ProposalPOLMessage is sent when a previous block is re-proposed.
It is used to inform peers in what round the process learned for this block (ProposalPOLRound),
and what prevotes for the re-proposed block the process has.
```
and what prevotes for the re-proposed block the process has.
```go
type ProposalPOLMessage struct {
Height int64
ProposalPOLRound int
ProposalPOL BitArray
Height int64
ProposalPOLRound int
ProposalPOL BitArray
}
```
## HasVoteMessage
HasVoteMessage is sent to indicate that a particular vote has been received. It contains height,
round, vote type and the index of the validator that is the originator of the corresponding vote.
```
HasVoteMessage is sent to indicate that a particular vote has been received. It contains height,
round, vote type and the index of the validator that is the originator of the corresponding vote.
```go
type HasVoteMessage struct {
Height int64
Round int
Type byte
Index int
Height int64
Round int
Type byte
Index int
}
```
## VoteSetMaj23Message
VoteSetMaj23Message is sent to indicate that a process has seen +2/3 votes for some BlockID.
It contains height, round, vote type and the BlockID.
It contains height, round, vote type and the BlockID.
```
```go
type VoteSetMaj23Message struct {
Height int64
Round int
Type byte
BlockID BlockID
Height int64
Round int
Type byte
BlockID BlockID
}
```
## VoteSetBitsMessage
VoteSetBitsMessage is sent to communicate the bit-array of votes a process has seen for a given
BlockID. It contains height, round, vote type, BlockID and a bit array of
VoteSetBitsMessage is sent to communicate the bit-array of votes a process has seen for a given
BlockID. It contains height, round, vote type, BlockID and a bit array of
the votes a process has.
```
```go
type VoteSetBitsMessage struct {
Height int64
Round int
Type byte
BlockID BlockID
Votes BitArray
Height int64
Round int
Type byte
BlockID BlockID
Votes BitArray
}
```

+ 38
- 33
docs/specification/new-spec/encoding.md View File

@ -2,9 +2,11 @@
## Binary Serialization (TMBIN)
Tendermint aims to encode data structures in a manner similar to how the corresponding Go structs are laid out in memory.
Tendermint aims to encode data structures in a manner similar to how the corresponding Go structs
are laid out in memory.
Variable length items are length-prefixed.
While the encoding was inspired by Go, it is easily implemented in other languages as well given its intuitive design.
While the encoding was inspired by Go, it is easily implemented in other languages as well given its
intuitive design.
XXX: This is changing to use real varints and 4-byte-prefixes.
See https://github.com/tendermint/go-wire/tree/sdk2.
@ -19,7 +21,7 @@ Negative integers are encoded via twos-complement.
Examples:
```
```go
encode(uint8(6)) == [0x06]
encode(uint32(6)) == [0x00, 0x00, 0x00, 0x06]
@ -36,10 +38,9 @@ Negative integers are encoded by flipping the leading bit of the length-prefix t
Zero is encoded as `0x00`. It is not length-prefixed.
Examples:
```
```go
encode(uint(6)) == [0x01, 0x06]
encode(uint(70000)) == [0x03, 0x01, 0x11, 0x70]
@ -58,7 +59,7 @@ The empty string is encoded as `0x00`. It is not length-prefixed.
Examples:
```
```go
encode("") == [0x00]
encode("a") == [0x01, 0x01, 0x61]
encode("hello") == [0x01, 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F]
@ -72,7 +73,7 @@ There is no length-prefix.
Examples:
```
```go
encode([4]int8{1, 2, 3, 4}) == [0x01, 0x02, 0x03, 0x04]
encode([4]int16{1, 2, 3, 4}) == [0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04]
encode([4]int{1, 2, 3, 4}) == [0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04]
@ -81,14 +82,15 @@ encode([2]string{"abc", "efg"}) == [0x01, 0x03, 0x61, 0x62, 0x63, 0x01, 0x03, 0x
### Slices (variable length)
An encoded variable-length array is a length prefix followed by the concatenation of the encoding of its elements.
An encoded variable-length array is a length prefix followed by the concatenation of the encoding of
its elements.
The length-prefix is itself encoded as an `int`.
An empty slice is encoded as `0x00`. It is not length-prefixed.
Examples:
```
```go
encode([]int8{}) == [0x00]
encode([]int8{1, 2, 3, 4}) == [0x01, 0x04, 0x01, 0x02, 0x03, 0x04]
encode([]int16{1, 2, 3, 4}) == [0x01, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04]
@ -97,10 +99,11 @@ encode([]string{"abc", "efg"}) == [0x01, 0x02, 0x01, 0x03, 0x61, 0x62, 0x63, 0x
```
### BitArray
BitArray is encoded as an `int` of the number of bits, and with an array of `uint64` to encode
value of each array element.
```
```go
type BitArray struct {
Bits int
Elems []uint64
@ -116,7 +119,7 @@ Times before then are invalid.
Examples:
```
```go
encode(time.Time("Jan 1 00:00:00 UTC 1970")) == [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
encode(time.Time("Jan 1 00:00:01 UTC 1970")) == [0x00, 0x00, 0x00, 0x00, 0x3B, 0x9A, 0xCA, 0x00] // 1,000,000,000 ns
encode(time.Time("Mon Jan 2 15:04:05 -0700 MST 2006")) == [0x0F, 0xC4, 0xBB, 0xC1, 0x53, 0x03, 0x12, 0x00]
@ -129,7 +132,7 @@ There is no length-prefix.
Examples:
```
```go
type MyStruct struct{
A int
B string
@ -139,7 +142,6 @@ encode(MyStruct{4, "hello", time.Time("Mon Jan 2 15:04:05 -0700 MST 2006")}) ==
[0x01, 0x04, 0x01, 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0F, 0xC4, 0xBB, 0xC1, 0x53, 0x03, 0x12, 0x00]
```
## Merkle Trees
Simple Merkle trees are used in numerous places in Tendermint to compute a cryptographic digest of a data structure.
@ -148,23 +150,24 @@ RIPEMD160 is always used as the hashing function.
The function `SimpleMerkleRoot` is a simple recursive function defined as follows:
```
```go
func SimpleMerkleRoot(hashes [][]byte) []byte{
switch len(hashes) {
case 0:
return nil
case 1:
return hashes[0]
default:
left := SimpleMerkleRoot(hashes[:(len(hashes)+1)/2])
right := SimpleMerkleRoot(hashes[(len(hashes)+1)/2:])
return RIPEMD160(append(left, right))
}
switch len(hashes) {
case 0:
return nil
case 1:
return hashes[0]
default:
left := SimpleMerkleRoot(hashes[:(len(hashes)+1)/2])
right := SimpleMerkleRoot(hashes[(len(hashes)+1)/2:])
return RIPEMD160(append(left, right))
}
}
```
Note we abuse notion and call `SimpleMerkleRoot` with arguments of type `struct` or type `[]struct`.
For `struct` arguments, we compute a `[][]byte` by sorting elements of the `struct` according to field name and then hashing them.
For `struct` arguments, we compute a `[][]byte` by sorting elements of the `struct` according to
field name and then hashing them.
For `[]struct` arguments, we compute a `[][]byte` by hashing the individual `struct` elements.
## JSON (TMJSON)
@ -172,10 +175,12 @@ For `[]struct` arguments, we compute a `[][]byte` by hashing the individual `str
Signed messages (eg. votes, proposals) in the consensus are encoded in TMJSON, rather than TMBIN.
TMJSON is JSON where `[]byte` are encoded as uppercase hex, rather than base64.
When signing, the elements of a message are sorted by key and the sorted message is embedded in an outer JSON that includes a `chain_id` field.
We call this encoding the CanonicalSignBytes. For instance, CanonicalSignBytes for a vote would look like:
When signing, the elements of a message are sorted by key and the sorted message is embedded in an
outer JSON that includes a `chain_id` field.
We call this encoding the CanonicalSignBytes. For instance, CanonicalSignBytes for a vote would look
like:
```
```json
{"chain_id":"my-chain-id","vote":{"block_id":{"hash":DEADBEEF,"parts":{"hash":BEEFDEAD,"total":3}},"height":3,"round":2,"timestamp":1234567890, "type":2}
```
@ -187,16 +192,16 @@ Note how the fields within each level are sorted.
TMBIN encode an object and slice it into parts.
```
```go
MakeParts(object, partSize)
```
### Part
```
```go
type Part struct {
Index int
Bytes byte[]
Proof byte[]
Index int
Bytes byte[]
Proof byte[]
}
```

+ 10
- 10
docs/specification/new-spec/state.md View File

@ -2,13 +2,13 @@
## State
The state contains information whose cryptographic digest is included in block headers,
and thus is necessary for validating new blocks.
For instance, the Merkle root of the results from executing the previous block, or the Merkle root of the current validators.
While neither the results of transactions now the validators are ever included in the blockchain itself,
the Merkle roots are, and hence we need a separate data structure to track them.
The state contains information whose cryptographic digest is included in block headers, and thus is
necessary for validating new blocks. For instance, the Merkle root of the results from executing the
previous block, or the Merkle root of the current validators. While neither the results of
transactions now the validators are ever included in the blockchain itself, the Merkle roots are,
and hence we need a separate data structure to track them.
```
```go
type State struct {
LastResults []Result
AppHash []byte
@ -22,7 +22,7 @@ type State struct {
### Result
```
```go
type Result struct {
Code uint32
Data []byte
@ -46,7 +46,7 @@ represented in the tags.
A validator is an active participant in the consensus with a public key and a voting power.
Validator's also contain an address which is derived from the PubKey:
```
```go
type Validator struct {
Address []byte
PubKey PubKey
@ -59,7 +59,7 @@ so that there is a canonical order for computing the SimpleMerkleRoot.
We also define a `TotalVotingPower` function, to return the total voting power:
```
```go
func TotalVotingPower(vals []Validators) int64{
sum := 0
for v := range vals{
@ -82,7 +82,7 @@ TODO:
We define an `Execute` function that takes a state and a block,
executes the block against the application, and returns an updated state.
```
```go
Execute(s State, app ABCIApp, block Block) State {
abciResponses := app.ApplyBlock(block)


Loading…
Cancel
Save