Browse Source

Merge pull request #1701 from tendermint/bucky/abci-fixes

Bucky/abci fixes
pull/1694/head
Ethan Buchman 6 years ago
committed by GitHub
parent
commit
46fb179605
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 192 additions and 46 deletions
  1. +16
    -2
      CHANGELOG.md
  2. +4
    -4
      Gopkg.lock
  3. +1
    -1
      Gopkg.toml
  4. +16
    -2
      consensus/replay.go
  5. +51
    -0
      consensus/replay_test.go
  6. +31
    -6
      docs/spec/blockchain/encoding.md
  7. +20
    -7
      docs/spec/consensus/abci.md
  8. +1
    -1
      node/node.go
  9. +11
    -0
      state/execution.go
  10. +38
    -20
      types/protobuf.go
  11. +3
    -3
      version/version.go

+ 16
- 2
CHANGELOG.md View File

@ -1,8 +1,22 @@
# Changelog
## 0.19.10
## 0.20.0
*June 6th, 2018*
BREAKING CHANGES
- [abci] Upgrade to
[v0.11.0](https://github.com/tendermint/abci/blob/master/CHANGELOG.md#0110)
- [abci] Query path for filtering peers by node ID changed from
`p2p/filter/pubkey/<id>` to `p2p/filter/id/<id>`
NOTE: this release does not break any blockchain data structures or
protocols other than the ABCI messages between Tendermint and the application.
Applications that upgrade for ABCI v0.11.0 should be able to continue running Tendermint
v0.20.0 on blockchains created with v0.19.X
*TBD*
## 0.19.9


+ 4
- 4
Gopkg.lock View File

@ -238,8 +238,8 @@
"server",
"types"
]
revision = "7cf66f570e2f47b286985e2d688b0a400c028e4c"
version = "v0.11.0-rc6"
revision = "ebee2fe114020aa49c70bbbae50b7079fc7e7b90"
version = "v0.11.0"
[[projects]]
branch = "master"
@ -313,7 +313,7 @@
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "c11f84a56e43e20a78cee75a7c034031ecf57d1f"
revision = "9527bec2660bd847c050fda93a0f0c6dee0800bb"
[[projects]]
name = "golang.org/x/text"
@ -374,6 +374,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "132980da98fc92b6c0dd988df07316a340f5fc91ee77593cf984ade4e3e5fd62"
inputs-digest = "ae6792578b0664708339f4c05e020687d6b799ad6f8282394b919de69e403d1f"
solver-name = "gps-cdcl"
solver-version = 1

+ 1
- 1
Gopkg.toml View File

@ -71,7 +71,7 @@
[[constraint]]
name = "github.com/tendermint/abci"
version = "~0.11.0-rc6"
version = "~0.11.0"
[[constraint]]
name = "github.com/tendermint/go-crypto"


+ 16
- 2
consensus/replay.go View File

@ -267,17 +267,31 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight
// If appBlockHeight == 0 it means that we are at genesis and hence should send InitChain
if appBlockHeight == 0 {
validators := types.TM2PB.Validators(state.Validators)
csParams := types.TM2PB.ConsensusParams(h.genDoc.ConsensusParams)
req := abci.RequestInitChain{
Time: h.genDoc.GenesisTime.Unix(), // TODO
ChainId: h.genDoc.ChainID,
ConsensusParams: types.TM2PB.ConsensusParams(h.genDoc.ConsensusParams),
ConsensusParams: csParams,
Validators: validators,
AppStateBytes: h.genDoc.AppStateJSON,
}
_, err := proxyApp.Consensus().InitChainSync(req)
res, err := proxyApp.Consensus().InitChainSync(req)
if err != nil {
return nil, err
}
// update the state
if len(res.Validators) > 0 {
vals, err := types.PB2TM.Validators(res.Validators)
if err != nil {
return nil, err
}
state.Validators = types.NewValidatorSet(vals)
}
if res.ConsensusParams != nil {
// TODO
}
sm.SaveState(h.stateDB, state)
}
// First handle edge cases and constraints on the storeBlockHeight


+ 51
- 0
consensus/replay_test.go View File

@ -13,6 +13,7 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/abci/example/kvstore"
@ -634,3 +635,53 @@ func (bs *mockBlockStore) LoadBlockCommit(height int64) *types.Commit {
func (bs *mockBlockStore) LoadSeenCommit(height int64) *types.Commit {
return bs.commits[height-1]
}
//----------------------------------------
func TestInitChainUpdateValidators(t *testing.T) {
val, _ := types.RandValidator(true, 10)
vals := types.NewValidatorSet([]*types.Validator{val})
app := &initChainApp{vals: types.TM2PB.Validators(vals)}
clientCreator := proxy.NewLocalClientCreator(app)
config := ResetConfig("proxy_test_")
privVal := privval.LoadFilePV(config.PrivValidatorFile())
stateDB, state, store := stateAndStore(config, privVal.GetPubKey())
oldValAddr := state.Validators.Validators[0].Address
// now start the app using the handshake - it should sync
genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile())
handshaker := NewHandshaker(stateDB, state, store, genDoc)
proxyApp := proxy.NewAppConns(clientCreator, handshaker)
if err := proxyApp.Start(); err != nil {
t.Fatalf("Error starting proxy app connections: %v", err)
}
defer proxyApp.Stop()
// reload the state, check the validator set was updated
state = sm.LoadState(stateDB)
newValAddr := state.Validators.Validators[0].Address
expectValAddr := val.Address
assert.NotEqual(t, oldValAddr, newValAddr)
assert.Equal(t, newValAddr, expectValAddr)
}
func newInitChainApp(vals []abci.Validator) *initChainApp {
return &initChainApp{
vals: vals,
}
}
// returns the vals on InitChain
type initChainApp struct {
abci.BaseApplication
vals []abci.Validator
}
func (ica *initChainApp) InitChain(req abci.RequestInitChain) abci.ResponseInitChain {
return abci.ResponseInitChain{
Validators: ica.vals,
}
}

+ 31
- 6
docs/spec/blockchain/encoding.md View File

@ -49,14 +49,14 @@ spec](https://github.com/tendermint/go-amino#computing-the-prefix-and-disambigua
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
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
familiar with amino encoding.
You can simply use below table and concatenate Prefix || Length (of raw bytes) || raw bytes
<Length> <ByteArray>`. In other words, to encode any type listed below you do not need to be
familiar with amino encoding.
You can simply use below table and concatenate Prefix || Length (of raw bytes) || raw bytes
( while || stands for byte concatenation here).
| Type | Name | Prefix | Length |
| ---- | ---- | ------ | ----- |
| PubKeyEd25519 | tendermint/PubKeyEd25519 | 0x1624DE62 | 0x20 |
| ---- | ---- | ------ | ----- |
| PubKeyEd25519 | tendermint/PubKeyEd25519 | 0x1624DE62 | 0x20 |
| PubKeyLedgerEd25519 | tendermint/PubKeyLedgerEd25519 | 0x5C3453B2 | 0x20 |
| PubKeySecp256k1 | tendermint/PubKeySecp256k1 | 0xEB5AE982 | 0x21 |
| PrivKeyEd25519 | tendermint/PrivKeyEd25519 | 0xA3288912 | 0x40 |
@ -69,7 +69,7 @@ You can simply use below table and concatenate Prefix || Length (of raw bytes) |
### Examples
1. For example, the 33-byte (or 0x21-byte in hex) Secp256k1 pubkey
`020BD40F225A57ED383B440CF073BC5539D0341F5767D2BF2D78406D00475A2EE9`
`020BD40F225A57ED383B440CF073BC5539D0341F5767D2BF2D78406D00475A2EE9`
would be encoded as
`EB5AE98221020BD40F225A57ED383B440CF073BC5539D0341F5767D2BF2D78406D00475A2EE9`
@ -78,6 +78,31 @@ would be encoded as
would be encoded as
`16E1FEEA46304402201CD4B8C764D2FD8AF23ECFE6666CA8A53886D47754D951295D2D311E1FEA33BF02201E0F906BB1CF2C30EAACFFB032A7129358AFF96B9F79B06ACFFB18AC90C2ADD7`
### Addresses
Addresses for each public key types are computed as follows:
#### Ed25519
RIPEMD160 hash of the Amino encoded public key:
```
address = RIPEMD160(AMINO(pubkey))
```
NOTE: this will soon change to the truncated 20-bytes of the SHA256 of the raw
public key
#### Secp256k1
RIPEMD160 hash of the SHA256 hash of the OpenSSL compressed public key:
```
address = RIPEMD160(SHA256(pubkey))
```
This is the same as Bitcoin.
## Other Common Types
### BitArray


+ 20
- 7
docs/spec/consensus/abci.md View File

@ -52,20 +52,33 @@ objects in the `ResponseBeginBlock`:
```
message Validator {
bytes pub_key = 1;
int64 power = 2;
bytes address = 1;
PubKey pub_key = 2;
int64 power = 3;
}
message PubKey {
string type = 1;
bytes data = 2;
}
```
The `pub_key` is the Amino encoded public key for the validator. For details on
Amino encoded public keys, see the [section of the encoding spec](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md#public-key-cryptography).
The `pub_key` currently supports two types:
- `type = "ed25519" and `data = <raw 32-byte public key>`
- `type = "secp256k1" and `data = <33-byte OpenSSL compressed public key>`
If the address is provided, it must match the address of the pubkey, as
specified [here](/docs/spec/blockchain/encoding.md#Addresses)
(Note: In the v0.19 series, the `pub_key` is the [Amino encoded public
key](/docs/spec/blockchain/encoding.md#public-key-cryptography).
For Ed25519 pubkeys, the Amino prefix is always "1624DE6220". For example, the 32-byte Ed25519 pubkey
`76852933A4686A721442E931A8415F62F5F1AEDF4910F1F252FB393F74C40C85` would be
Amino encoded as
`1624DE622076852933A4686A721442E931A8415F62F5F1AEDF4910F1F252FB393F74C40C85`
`1624DE622076852933A4686A721442E931A8415F62F5F1AEDF4910F1F252FB393F74C40C85`)
(Note: in old versions of Tendermint (pre-v0.19.0), the pubkey is just prefixed with a
(Note: In old versions of Tendermint (pre-v0.19.0), the pubkey is just prefixed with a
single type byte, so for ED25519 we'd have `pub_key = 0x1 | pub`)
The `power` is the new voting power for the validator, with the
@ -94,7 +107,7 @@ using the following paths, with no additional data:
- `/p2p/filter/addr/<IP:PORT>`, where `<IP:PORT>` denote the IP address and
the port of the connection
- `p2p/filter/pubkey/<ID>`, where `<ID>` is the peer node ID (ie. the
- `p2p/filter/id/<ID>`, where `<ID>` is the peer node ID (ie. the
pubkey.Address() for the peer's PubKey)
If either of these queries return a non-zero ABCI code, Tendermint will refuse


+ 1
- 1
node/node.go View File

@ -302,7 +302,7 @@ func NewNode(config *cfg.Config,
return nil
})
sw.SetIDFilter(func(id p2p.ID) error {
resQuery, err := proxyApp.Query().QuerySync(abci.RequestQuery{Path: cmn.Fmt("/p2p/filter/pubkey/%s", id)})
resQuery, err := proxyApp.Query().QuerySync(abci.RequestQuery{Path: cmn.Fmt("/p2p/filter/id/%s", id)})
if err != nil {
return err
}


+ 11
- 0
state/execution.go View File

@ -1,6 +1,7 @@
package state
import (
"bytes"
"fmt"
fail "github.com/ebuchman/fail-test"
@ -278,6 +279,16 @@ func updateValidators(currentSet *types.ValidatorSet, updates []abci.Validator)
}
address := pubkey.Address()
// If the app provided an address too, it must match.
// This is just a sanity check.
if len(v.Address) > 0 {
if !bytes.Equal(address, v.Address) {
return fmt.Errorf("Validator.Address (%X) does not match PubKey.Address (%X)",
v.Address, address)
}
}
power := int64(v.Power)
// mind the overflow from int64
if power < 0 {


+ 38
- 20
types/protobuf.go View File

@ -32,20 +32,26 @@ type tm2pb struct{}
func (tm2pb) Header(header *Header) abci.Header {
return abci.Header{
ChainID: header.ChainID,
Height: header.Height,
Time: header.Time.Unix(),
NumTxs: int32(header.NumTxs), // XXX: overflow
ChainID: header.ChainID,
Height: header.Height,
Time: header.Time.Unix(),
NumTxs: int32(header.NumTxs), // XXX: overflow
TotalTxs: header.NumTxs,
LastBlockHash: header.LastBlockID.Hash,
ValidatorsHash: header.ValidatorsHash,
AppHash: header.AppHash,
// Proposer: TODO
}
}
func (tm2pb) Validator(val *Validator) abci.Validator {
return abci.Validator{
PubKey: TM2PB.PubKey(val.PubKey),
Power: val.VotingPower,
Address: val.PubKey.Address(),
PubKey: TM2PB.PubKey(val.PubKey),
Power: val.VotingPower,
}
}
@ -101,28 +107,24 @@ func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci.
panic(val)
}
abciEvidence := abci.Evidence{
Validator: abci.Validator{
Address: ev.Address(),
PubKey: TM2PB.PubKey(val.PubKey),
Power: val.VotingPower,
},
Height: ev.Height(),
Time: evTime.Unix(),
TotalVotingPower: valSet.TotalVotingPower(),
}
// set type
var evType string
switch ev.(type) {
case *DuplicateVoteEvidence:
abciEvidence.Type = ABCIEvidenceTypeDuplicateVote
evType = ABCIEvidenceTypeDuplicateVote
case *MockGoodEvidence, MockGoodEvidence:
abciEvidence.Type = ABCIEvidenceTypeMockGood
evType = ABCIEvidenceTypeMockGood
default:
panic(fmt.Sprintf("Unknown evidence type: %v %v", ev, reflect.TypeOf(ev)))
}
return abciEvidence
return abci.Evidence{
Type: evType,
Validator: TM2PB.Validator(val),
Height: ev.Height(),
Time: evTime.Unix(),
TotalVotingPower: valSet.TotalVotingPower(),
}
}
func (tm2pb) ValidatorFromPubKeyAndPower(pubkey crypto.PubKey, power int64) abci.Validator {
@ -165,3 +167,19 @@ func (pb2tm) PubKey(pubKey abci.PubKey) (crypto.PubKey, error) {
return nil, fmt.Errorf("Unknown pubkey type %v", pubKey.Type)
}
}
func (pb2tm) Validators(vals []abci.Validator) ([]*Validator, error) {
tmVals := make([]*Validator, len(vals))
for i, v := range vals {
pub, err := PB2TM.PubKey(v.PubKey)
if err != nil {
return nil, err
}
tmVals[i] = &Validator{
Address: v.Address,
PubKey: pub,
VotingPower: v.Power,
}
}
return tmVals, nil
}

+ 3
- 3
version/version.go View File

@ -3,14 +3,14 @@ package version
// Version components
const (
Maj = "0"
Min = "19"
Fix = "10"
Min = "20"
Fix = "0"
)
var (
// Version is the current version of Tendermint
// Must be a string because scripts like dist.sh read this file.
Version = "0.19.10-dev"
Version = "0.20.0-dev"
// GitCommit is the current HEAD set using ldflags.
GitCommit string


Loading…
Cancel
Save