Browse Source

Merge pull request #37 from tendermint/valset

Valset
pull/1780/head
Ethan Buchman 8 years ago
committed by GitHub
parent
commit
f4e97a5db1
10 changed files with 453 additions and 96 deletions
  1. +3
    -12
      example/counter/counter.go
  2. +31
    -0
      example/dummy/README.md
  3. +10
    -6
      example/dummy/dummy.go
  4. +203
    -0
      example/dummy/dummy_test.go
  5. +109
    -6
      example/dummy/persistent_dummy.go
  6. +12
    -10
      glide.lock
  7. +2
    -2
      tests/test_cli/ex1.tmsp.out
  8. +57
    -58
      types/types.pb.go
  9. +2
    -2
      types/types.proto
  10. +24
    -0
      types/validators.go

+ 3
- 12
example/counter/counter.go View File

@ -2,7 +2,6 @@ package counter
import (
"encoding/binary"
"fmt"
. "github.com/tendermint/go-common"
"github.com/tendermint/tmsp/types"
@ -35,11 +34,7 @@ func (app *CounterApplication) AppendTx(tx []byte) types.Result {
copy(tx8[len(tx8)-len(tx):], tx)
txValue := binary.BigEndian.Uint64(tx8)
if txValue != uint64(app.txCount) {
return types.Result{
Code: types.CodeType_BadNonce,
Data: nil,
Log: fmt.Sprintf("Invalid nonce. Expected %v, got %v", app.txCount, txValue),
}
return types.ErrBadNonce.SetLog(Fmt("Invalid nonce. Expected %v, got %v", app.txCount, txValue))
}
}
app.txCount += 1
@ -52,11 +47,7 @@ func (app *CounterApplication) CheckTx(tx []byte) types.Result {
copy(tx8[len(tx8)-len(tx):], tx)
txValue := binary.BigEndian.Uint64(tx8)
if txValue < uint64(app.txCount) {
return types.Result{
Code: types.CodeType_BadNonce,
Data: nil,
Log: fmt.Sprintf("Invalid nonce. Expected >= %v, got %v", app.txCount, txValue),
}
return types.ErrBadNonce.SetLog(Fmt("Invalid nonce. Expected >= %v, got %v", app.txCount, txValue))
}
}
return types.OK
@ -75,5 +66,5 @@ func (app *CounterApplication) Commit() types.Result {
}
func (app *CounterApplication) Query(query []byte) types.Result {
return types.NewResultOK(nil, fmt.Sprintf("Query is not supported"))
return types.NewResultOK(nil, Fmt("Query is not supported"))
}

+ 31
- 0
example/dummy/README.md View File

@ -0,0 +1,31 @@
# Dummy
There are two app's here: the DummyApplication and the PersistentDummyApplication.
## DummyApplication
The DummyApplication is a simple merkle key-value store.
Transactions of the form `key=value` are stored as key-value pairs in the tree.
Transactions without an `=` sign set the value to the key.
The app has no replay protection (other than what the mempool provides).
## PersistentDummyApplication
The PersistentDummyApplication wraps the DummyApplication
and provides two additional features:
1) persistence of state across app restarts (using Tendermint's TMSP-Handshake mechanism)
2) validator set changes
The state is persisted in leveldb along with the last block committed,
and the Handshake allows any necessary blocks to be replayed.
Validator set changes are effected using the following transaction format:
```
val:pubkey1/power1,addr2/power2,addr3/power3"
```
where `power1` is the new voting power for the validator with `pubkey1` (possibly a new one).
There is no sybil protection against new validators joining.
Validators can be removed by setting their power to `0`.

+ 10
- 6
example/dummy/dummy.go View File

@ -5,6 +5,7 @@ import (
. "github.com/tendermint/go-common"
"github.com/tendermint/go-merkle"
"github.com/tendermint/go-wire"
"github.com/tendermint/tmsp/types"
)
@ -13,10 +14,7 @@ type DummyApplication struct {
}
func NewDummyApplication() *DummyApplication {
state := merkle.NewIAVLTree(
0,
nil,
)
state := merkle.NewIAVLTree(0, ".", nil)
return &DummyApplication{state: state}
}
@ -51,6 +49,12 @@ func (app *DummyApplication) Commit() types.Result {
func (app *DummyApplication) Query(query []byte) types.Result {
index, value, exists := app.state.Get(query)
resStr := Fmt("Index=%v value=%v exists=%v", index, string(value), exists)
return types.NewResultOK([]byte(resStr), "")
queryResult := QueryResult{index, string(value), exists}
return types.NewResultOK(wire.JSONBytes(queryResult), "")
}
type QueryResult struct {
Index int `json:"index"`
Value string `json:"value"`
Exists bool `json:"exists"`
}

+ 203
- 0
example/dummy/dummy_test.go View File

@ -0,0 +1,203 @@
package dummy
import (
"bytes"
"io/ioutil"
"sort"
"testing"
. "github.com/tendermint/go-common"
"github.com/tendermint/go-crypto"
"github.com/tendermint/go-wire"
"github.com/tendermint/tmsp/types"
)
func testDummy(t *testing.T, dummy types.Application, tx []byte, key, value string) {
if r := dummy.AppendTx(tx); r.IsErr() {
t.Fatal(r)
}
if r := dummy.AppendTx(tx); r.IsErr() {
t.Fatal(r)
}
r := dummy.Query([]byte(key))
if r.IsErr() {
t.Fatal(r)
}
q := new(QueryResult)
if err := wire.ReadJSONBytes(r.Data, q); err != nil {
t.Fatal(err)
}
if q.Value != value {
t.Fatalf("Got %s, expected %s", q.Value, value)
}
}
func TestDummyKV(t *testing.T) {
dummy := NewDummyApplication()
key := "abc"
value := key
tx := []byte(key)
testDummy(t, dummy, tx, key, value)
value = "def"
tx = []byte(key + "=" + value)
testDummy(t, dummy, tx, key, value)
}
func TestPersistentDummyKV(t *testing.T) {
dir, err := ioutil.TempDir("/tmp", "tmsp-dummy-test") // TODO
if err != nil {
t.Fatal(err)
}
dummy := NewPersistentDummyApplication(dir)
key := "abc"
value := key
tx := []byte(key)
testDummy(t, dummy, tx, key, value)
value = "def"
tx = []byte(key + "=" + value)
testDummy(t, dummy, tx, key, value)
}
func TestPersistentDummyInfo(t *testing.T) {
dir, err := ioutil.TempDir("/tmp", "tmsp-dummy-test") // TODO
if err != nil {
t.Fatal(err)
}
dummy := NewPersistentDummyApplication(dir)
height := uint64(0)
_, _, lastBlockInfo, _ := dummy.Info()
if lastBlockInfo.BlockHeight != height {
t.Fatalf("expected height of %d, got %d", height, lastBlockInfo.BlockHeight)
}
// make and apply block
height = uint64(1)
hash := []byte("foo")
header := &types.Header{
Height: uint64(height),
}
dummy.BeginBlock(hash, header)
dummy.EndBlock(height)
dummy.Commit()
_, _, lastBlockInfo, _ = dummy.Info()
if lastBlockInfo.BlockHeight != height {
t.Fatalf("expected height of %d, got %d", height, lastBlockInfo.BlockHeight)
}
}
// add a validator, remove a validator, update a validator
func TestValSetChanges(t *testing.T) {
dir, err := ioutil.TempDir("/tmp", "tmsp-dummy-test") // TODO
if err != nil {
t.Fatal(err)
}
dummy := NewPersistentDummyApplication(dir)
// init with some validators
total := 10
nInit := 5
vals := make([]*types.Validator, total)
for i := 0; i < total; i++ {
pubkey := crypto.GenPrivKeyEd25519FromSecret([]byte(Fmt("test%d", i))).PubKey().Bytes()
power := RandInt()
vals[i] = &types.Validator{pubkey, uint64(power)}
}
// iniitalize with the first nInit
dummy.InitChain(vals[:nInit])
vals1, vals2 := vals[:nInit], dummy.Validators()
valsEqual(t, vals1, vals2)
var v1, v2, v3 *types.Validator
// add some validators
v1, v2 = vals[nInit], vals[nInit+1]
diff := []*types.Validator{v1, v2}
tx1 := MakeValSetChangeTx(v1.PubKey, v1.Power)
tx2 := MakeValSetChangeTx(v2.PubKey, v2.Power)
makeApplyBlock(t, dummy, 1, diff, tx1, tx2)
vals1, vals2 = vals[:nInit+2], dummy.Validators()
valsEqual(t, vals1, vals2)
// remove some validators
v1, v2, v3 = vals[nInit-2], vals[nInit-1], vals[nInit]
v1.Power = 0
v2.Power = 0
v3.Power = 0
diff = []*types.Validator{v1, v2, v3}
tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power)
tx2 = MakeValSetChangeTx(v2.PubKey, v2.Power)
tx3 := MakeValSetChangeTx(v3.PubKey, v3.Power)
makeApplyBlock(t, dummy, 2, diff, tx1, tx2, tx3)
vals1 = append(vals[:nInit-2], vals[nInit+1])
vals2 = dummy.Validators()
valsEqual(t, vals1, vals2)
// update some validators
v1 = vals[0]
if v1.Power == 5 {
v1.Power = 6
} else {
v1.Power = 5
}
diff = []*types.Validator{v1}
tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power)
makeApplyBlock(t, dummy, 3, diff, tx1)
vals1 = append([]*types.Validator{v1}, vals1[1:len(vals1)]...)
vals2 = dummy.Validators()
valsEqual(t, vals1, vals2)
}
func makeApplyBlock(t *testing.T, dummy types.Application, heightInt int, diff []*types.Validator, txs ...[]byte) {
// make and apply block
height := uint64(heightInt)
hash := []byte("foo")
header := &types.Header{
Height: height,
}
dummyChain := dummy.(types.BlockchainAware) // hmm...
dummyChain.BeginBlock(hash, header)
for _, tx := range txs {
if r := dummy.AppendTx(tx); r.IsErr() {
t.Fatal(r)
}
}
diff2 := dummyChain.EndBlock(height)
dummy.Commit()
valsEqual(t, diff, diff2)
}
// order doesn't matter
func valsEqual(t *testing.T, vals1, vals2 []*types.Validator) {
if len(vals1) != len(vals2) {
t.Fatalf("vals dont match in len. got %d, expected %d", len(vals2), len(vals1))
}
sort.Sort(types.Validators(vals1))
sort.Sort(types.Validators(vals2))
for i, v1 := range vals1 {
v2 := vals2[i]
if !bytes.Equal(v1.PubKey, v2.PubKey) ||
v1.Power != v2.Power {
t.Fatalf("vals dont match at index %d. got %X/%d , expected %X/%d", i, v2.PubKey, v2.Power, v1.PubKey, v1.Power)
}
}
}

+ 109
- 6
example/dummy/persistent_dummy.go View File

@ -2,6 +2,9 @@ package dummy
import (
"bytes"
"encoding/hex"
"strconv"
"strings"
. "github.com/tendermint/go-common"
dbm "github.com/tendermint/go-db"
@ -10,6 +13,10 @@ import (
"github.com/tendermint/tmsp/types"
)
const (
ValidatorSetChangePrefix string = "val:"
)
//-----------------------------------------
type PersistentDummyApplication struct {
@ -17,18 +24,19 @@ type PersistentDummyApplication struct {
db dbm.DB
// latest received
// TODO: move to merkle tree?
blockHash []byte
blockHeader *types.Header
// validator set
changes []*types.Validator
}
func NewPersistentDummyApplication(dbDir string) *PersistentDummyApplication {
db := dbm.NewDB("dummy", "leveldb", dbDir)
lastBlock := LoadLastBlock(db)
stateTree := merkle.NewIAVLTree(
0,
db,
)
stateTree := merkle.NewIAVLTree(0, ".", db)
stateTree.Load(lastBlock.AppHash)
log.Notice("Loaded state", "block", lastBlock.BlockHeight, "root", stateTree.Hash())
@ -51,6 +59,15 @@ func (app *PersistentDummyApplication) SetOption(key string, value string) (log
// tx is either "key=value" or just arbitrary bytes
func (app *PersistentDummyApplication) AppendTx(tx []byte) types.Result {
// if it starts with "val:", update the validator set
// format is "val:pubkey/power"
if isValidatorTx(tx) {
// update validators in the merkle tree
// and in app.changes
return app.execValidatorTx(tx)
}
// otherwise, update the key-value store
return app.app.AppendTx(tx)
}
@ -76,17 +93,29 @@ func (app *PersistentDummyApplication) Query(query []byte) types.Result {
return app.app.Query(query)
}
// Save the validators in the merkle tree
func (app *PersistentDummyApplication) InitChain(validators []*types.Validator) {
return
for _, v := range validators {
r := app.updateValidator(v)
if r.IsErr() {
log.Error("Error updating validators", "r", r)
}
}
}
// Track the block hash and header information
func (app *PersistentDummyApplication) BeginBlock(hash []byte, header *types.Header) {
// update latest block info
app.blockHash = hash
app.blockHeader = header
// reset valset changes
app.changes = make([]*types.Validator, 0)
}
// Update the validator set
func (app *PersistentDummyApplication) EndBlock(height uint64) (diffs []*types.Validator) {
return nil
return app.changes
}
//-----------------------------------------
@ -120,3 +149,77 @@ func SaveLastBlock(db dbm.DB, lastBlock types.LastBlockInfo) {
}
db.Set(lastBlockKey, buf.Bytes())
}
//---------------------------------------------
// update validators
func (app *PersistentDummyApplication) Validators() (validators []*types.Validator) {
app.app.state.Iterate(func(key, value []byte) bool {
if isValidatorTx(key) {
validator := new(types.Validator)
err := types.ReadMessage(bytes.NewBuffer(value), validator)
if err != nil {
panic(err)
}
validators = append(validators, validator)
}
return false
})
return
}
func MakeValSetChangeTx(pubkey []byte, power uint64) []byte {
return []byte(Fmt("val:%X/%d", pubkey, power))
}
func isValidatorTx(tx []byte) bool {
if strings.HasPrefix(string(tx), ValidatorSetChangePrefix) {
return true
}
return false
}
// format is "val:pubkey1/power1,addr2/power2,addr3/power3"tx
func (app *PersistentDummyApplication) execValidatorTx(tx []byte) types.Result {
tx = tx[len(ValidatorSetChangePrefix):]
pubKeyAndPower := strings.Split(string(tx), "/")
if len(pubKeyAndPower) != 2 {
return types.ErrEncodingError.SetLog(Fmt("Expected 'pubkey/power'. Got %v", pubKeyAndPower))
}
pubkeyS, powerS := pubKeyAndPower[0], pubKeyAndPower[1]
pubkey, err := hex.DecodeString(pubkeyS)
if err != nil {
return types.ErrEncodingError.SetLog(Fmt("Pubkey (%s) is invalid hex", pubkeyS))
}
power, err := strconv.Atoi(powerS)
if err != nil {
return types.ErrEncodingError.SetLog(Fmt("Power (%s) is not an int", powerS))
}
// update
return app.updateValidator(&types.Validator{pubkey, uint64(power)})
}
// add, update, or remove a validator
func (app *PersistentDummyApplication) updateValidator(v *types.Validator) types.Result {
key := []byte("val:" + string(v.PubKey))
if v.Power == 0 {
// remove validator
if !app.app.state.Has(key) {
return types.ErrUnauthorized.SetLog(Fmt("Cannot remove non-existent validator %X", key))
}
app.app.state.Remove(key)
} else {
// add or update validator
value := bytes.NewBuffer(make([]byte, 0))
if err := types.WriteMessage(v, value); err != nil {
return types.ErrInternalError.SetLog(Fmt("Error encoding validator: %v", err))
}
app.app.state.Set(key, value.Bytes())
}
// we only update the changes array if we succesfully updated the tree
app.changes = append(app.changes, v)
return types.OK
}

+ 12
- 10
glide.lock View File

@ -1,8 +1,8 @@
hash: 603c43870dfc63a3113a3d13ae799038206bd77889e2e9596a860d3644b8fb67
updated: 2016-11-15T14:46:00.011667442-05:00
updated: 2016-11-22T20:57:55.984772241-05:00
imports:
- name: github.com/btcsuite/btcd
version: d9a674e1b7bc09d0830d6986c71cf5f535d753c3
version: afec1bd1245a4a19e6dfe1306974b733e7cbb9b8
subpackages:
- btcec
- name: github.com/btcsuite/fastsha256
@ -10,7 +10,7 @@ imports:
- name: github.com/go-stack/stack
version: 100eb0c0a9c5b306ca2fb4f165df21d80ada4b82
- name: github.com/golang/protobuf
version: da116c3771bf4a398a43f44e069195ef1c9688ef
version: 8ee79997227bf9b34611aee7946ae64735e6fd93
subpackages:
- proto
- name: github.com/golang/snappy
@ -39,8 +39,10 @@ imports:
subpackages:
- edwards25519
- extra25519
- name: github.com/tendermint/go-autofile
version: 63186e34b33d78ae47fb0d25e5717b307fdf3603
- name: github.com/tendermint/go-common
version: fa3daa7abc253264c916c12fecce3effa01a1287
version: 6b4160f2a57487f277c42bf06fd280195dfdb278
- name: github.com/tendermint/go-crypto
version: 4b11d62bdb324027ea01554e5767b71174680ba0
- name: github.com/tendermint/go-db
@ -48,7 +50,7 @@ imports:
- name: github.com/tendermint/go-logger
version: cefb3a45c0bf3c493a04e9bcd9b1540528be59f2
- name: github.com/tendermint/go-merkle
version: 05042c6ab9cad51d12e4cecf717ae68e3b1409a8
version: bfc4afe28c7a50045d4d1eb043e67460f8a51a4f
- name: github.com/tendermint/go-process
version: ba01cfbb58d446673beff17e72883cb49c835fb9
- name: github.com/tendermint/go-wire
@ -58,9 +60,9 @@ imports:
subpackages:
- term
- name: github.com/urfave/cli
version: b4f4786f378c0c1d3336b5bb798094b166edf5a9
version: 0bdeddeeb0f650497d603c4ad7b20cfe685682f6
- name: golang.org/x/crypto
version: 9477e0b78b9ac3d0b03822fd95422e2fe07627cd
version: ede567c8e044a5913dad1d1af3696d9da953104c
subpackages:
- nacl/secretbox
- openpgp/armor
@ -69,7 +71,7 @@ imports:
- ripemd160
- salsa20/salsa
- name: golang.org/x/net
version: cac22060de4e495155959e69adcb4b45763ccb10
version: 4971afdc2f162e82d185353533d3cf16188a9f4e
subpackages:
- context
- http2
@ -79,11 +81,11 @@ imports:
- lex/httplex
- trace
- name: golang.org/x/sys
version: b699b7032584f0953262cb2788a0ca19bb494703
version: 30237cf4eefd639b184d1f2cb77a581ea0be8947
subpackages:
- unix
- name: google.golang.org/grpc
version: 0d9891286aca15aeb2b0a73be9f5946c3cfefa85
version: 63bd55dfbf781b183216d2dd4433a659c947648a
subpackages:
- codes
- credentials


+ 2
- 2
tests/test_cli/ex1.tmsp.out View File

@ -17,7 +17,7 @@
> query abc
-> code: OK
-> data: {Index=0 value=abc exists=true}
-> data: {{"index":0,"value":"abc","exists":true}}
> append_tx def=xyz
-> code: OK
@ -27,5 +27,5 @@
> query def
-> code: OK
-> data: {Index=1 value=xyz exists=true}
-> data: {{"index":1,"value":"xyz","exists":true}}

+ 57
- 58
types/types.pb.go View File

@ -1502,7 +1502,7 @@ func (m *TMSPInfo) GetVersion() string {
}
type LastBlockInfo struct {
BlockHeight int32 `protobuf:"varint,1,opt,name=block_height,json=blockHeight" json:"block_height,omitempty"`
BlockHeight uint64 `protobuf:"varint,1,opt,name=block_height,json=blockHeight" json:"block_height,omitempty"`
BlockHash []byte `protobuf:"bytes,2,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"`
AppHash []byte `protobuf:"bytes,3,opt,name=app_hash,json=appHash,proto3" json:"app_hash,omitempty"`
}
@ -1512,7 +1512,7 @@ func (m *LastBlockInfo) String() string { return proto.CompactTextStr
func (*LastBlockInfo) ProtoMessage() {}
func (*LastBlockInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{26} }
func (m *LastBlockInfo) GetBlockHeight() int32 {
func (m *LastBlockInfo) GetBlockHeight() uint64 {
if m != nil {
return m.BlockHeight
}
@ -1551,7 +1551,7 @@ func (m *ConfigInfo) GetMaxBlockSize() uint64 {
type Header struct {
ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId" json:"chain_id,omitempty"`
Height int32 `protobuf:"varint,2,opt,name=height" json:"height,omitempty"`
Height uint64 `protobuf:"varint,2,opt,name=height" json:"height,omitempty"`
Time uint64 `protobuf:"varint,3,opt,name=time" json:"time,omitempty"`
NumTxs uint64 `protobuf:"varint,4,opt,name=num_txs,json=numTxs" json:"num_txs,omitempty"`
LastBlockId *BlockID `protobuf:"bytes,5,opt,name=last_block_id,json=lastBlockId" json:"last_block_id,omitempty"`
@ -1573,7 +1573,7 @@ func (m *Header) GetChainId() string {
return ""
}
func (m *Header) GetHeight() int32 {
func (m *Header) GetHeight() uint64 {
if m != nil {
return m.Height
}
@ -2143,7 +2143,7 @@ var _TMSPApplication_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("types/types.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 1746 bytes of a gzipped FileDescriptorProto
// 1743 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x58, 0x49, 0x73, 0xdb, 0xc8,
0x15, 0x16, 0x29, 0x6e, 0x78, 0xa4, 0xa8, 0xd6, 0xd3, 0x46, 0x33, 0x49, 0x95, 0x07, 0xf1, 0x64,
0x24, 0xc7, 0x65, 0xa7, 0xe4, 0x9a, 0x29, 0x3b, 0x93, 0x4a, 0x95, 0x65, 0x6b, 0x2c, 0xd5, 0xc4,
@ -2201,57 +2201,56 @@ var fileDescriptor0 = []byte{
0xbe, 0x9d, 0x27, 0x27, 0x6b, 0x2b, 0x73, 0x07, 0xf0, 0x66, 0xbf, 0xa8, 0x5b, 0xae, 0xd8, 0x09,
0xf8, 0x13, 0x68, 0x3a, 0xee, 0x64, 0x12, 0x0f, 0x1a, 0x2b, 0x2e, 0x0a, 0x25, 0x36, 0xef, 0x40,
0x27, 0xad, 0x3c, 0xaa, 0xf6, 0xb7, 0x3c, 0x8a, 0x53, 0x94, 0x36, 0xac, 0x94, 0x34, 0x3d, 0xd8,
0x28, 0x14, 0x1c, 0x7e, 0x02, 0x3d, 0x59, 0x95, 0xa3, 0x25, 0xf4, 0x6f, 0x5a, 0x5d, 0xc9, 0x3b,
0x95, 0x2c, 0xfc, 0x11, 0x80, 0x56, 0xb1, 0xf5, 0x60, 0xd7, 0xb3, 0x0c, 0xa5, 0x40, 0x77, 0xce,
0x2d, 0x20, 0xbc, 0x53, 0xc2, 0x75, 0x29, 0x6c, 0xdb, 0x61, 0x48, 0x22, 0xf3, 0x08, 0x20, 0xaf,
0x56, 0xbc, 0x03, 0xfd, 0xb9, 0xbd, 0x50, 0x4d, 0x30, 0x8a, 0xdd, 0xf7, 0x5c, 0x5f, 0x35, 0xbd,
0xb9, 0xbd, 0x90, 0x1b, 0x7a, 0xed, 0xbe, 0xe7, 0xe6, 0x1f, 0xeb, 0xd0, 0x52, 0xd7, 0x15, 0x79,
0x96, 0x20, 0x35, 0x72, 0x9d, 0xf4, 0x1c, 0x92, 0x3e, 0x73, 0x96, 0xae, 0xab, 0xba, 0xdc, 0xb0,
0xa6, 0x28, 0x25, 0xc2, 0x9d, 0x73, 0xb9, 0x91, 0x86, 0x25, 0xbf, 0x71, 0x1f, 0xda, 0x7e, 0x32,
0x1f, 0x89, 0x45, 0x2c, 0x3b, 0xa9, 0x61, 0xb5, 0xfc, 0x64, 0xfe, 0x66, 0x11, 0xe3, 0x11, 0x6c,
0xe4, 0x6d, 0x49, 0x8b, 0xa8, 0x3b, 0xa1, 0xaf, 0x43, 0xac, 0x82, 0xf4, 0xcc, 0xea, 0x66, 0x3d,
0x79, 0xe6, 0xe0, 0x01, 0x30, 0x69, 0xa3, 0xa0, 0x57, 0x9d, 0xba, 0x25, 0x4f, 0xdd, 0x27, 0xbe,
0xc6, 0x66, 0x8a, 0xcb, 0x0f, 0xc0, 0xa0, 0x8a, 0x50, 0x2a, 0x6d, 0xa9, 0xd2, 0x21, 0x86, 0x14,
0x7e, 0x06, 0x9b, 0xf9, 0xfd, 0xae, 0x54, 0x3a, 0xca, 0x4b, 0xce, 0xbe, 0x11, 0x5d, 0xa3, 0x18,
0xdd, 0x33, 0x68, 0xeb, 0x2d, 0x56, 0xce, 0x02, 0x77, 0xa1, 0x19, 0xda, 0x91, 0x88, 0x35, 0x3c,
0xa5, 0x78, 0x73, 0x6e, 0x47, 0x34, 0x43, 0xe9, 0x89, 0x40, 0xa9, 0x98, 0x8f, 0x61, 0xa3, 0xc0,
0x27, 0x54, 0x15, 0x81, 0xb0, 0x3d, 0x9d, 0x22, 0x45, 0x64, 0xcb, 0xd4, 0xf3, 0x65, 0xcc, 0xc7,
0x60, 0x64, 0xb5, 0x48, 0x69, 0x09, 0x93, 0x8b, 0xaf, 0x79, 0x3a, 0x16, 0x69, 0x8a, 0xdc, 0x85,
0xc1, 0xb7, 0x7a, 0x2c, 0x69, 0x58, 0x8a, 0xb8, 0xfb, 0x97, 0x1a, 0x74, 0x5f, 0x28, 0x18, 0xa6,
0xae, 0xc2, 0x4d, 0xe8, 0xbe, 0x4c, 0x3c, 0x4f, 0xb3, 0xd8, 0x1a, 0x76, 0xa0, 0x41, 0xe8, 0xcd,
0x6a, 0x68, 0x40, 0x53, 0xa2, 0x33, 0xab, 0x13, 0x93, 0xca, 0x89, 0xad, 0xe3, 0x06, 0x18, 0x19,
0xdc, 0xb1, 0x06, 0x91, 0xd9, 0xb5, 0xc0, 0x9a, 0xd8, 0x83, 0x4e, 0x8a, 0x72, 0x6c, 0x0b, 0xbb,
0xd0, 0xd6, 0xa0, 0xc4, 0x10, 0x01, 0x5a, 0x2a, 0x51, 0x6c, 0x9b, 0x3c, 0x4b, 0x3c, 0x61, 0x3b,
0xe4, 0x20, 0xeb, 0x50, 0xb6, 0x8b, 0x7d, 0x80, 0xbc, 0x37, 0xd9, 0x1e, 0x39, 0x4c, 0xbb, 0x92,
0xed, 0xdf, 0xfd, 0x73, 0x13, 0x3a, 0x29, 0x1e, 0x60, 0x0b, 0xea, 0xaf, 0xbe, 0x66, 0x6b, 0xb8,
0x05, 0x1b, 0x67, 0xbe, 0xe0, 0x91, 0x6f, 0x7b, 0x27, 0x74, 0x0f, 0xb1, 0x1a, 0xb1, 0x4e, 0xfc,
0x71, 0xe0, 0xb8, 0xfe, 0x54, 0xb1, 0xea, 0xe4, 0xe8, 0xd8, 0x76, 0x5e, 0x06, 0xfe, 0x98, 0xb3,
0x75, 0x64, 0xd0, 0xfb, 0xc6, 0xb7, 0x13, 0x31, 0x0b, 0x22, 0xf7, 0x3d, 0x77, 0x58, 0x03, 0x77,
0x61, 0xeb, 0xcc, 0x8f, 0x93, 0xc9, 0xc4, 0x1d, 0xbb, 0xdc, 0x17, 0x5f, 0x25, 0xbe, 0x13, 0xb3,
0x26, 0x22, 0xf4, 0xbf, 0xf1, 0x2f, 0xfd, 0xe0, 0x5b, 0x5f, 0x0f, 0x6f, 0xac, 0x85, 0x03, 0xd8,
0x39, 0xb6, 0x63, 0xfe, 0x2c, 0x09, 0x3d, 0x77, 0x6c, 0x0b, 0xfe, 0xc4, 0x71, 0x22, 0x1e, 0xc7,
0x8c, 0x93, 0x13, 0x92, 0x14, 0xd7, 0x9e, 0xa4, 0x06, 0x05, 0xff, 0x9c, 0xc7, 0x6c, 0x8a, 0xb7,
0x60, 0xf7, 0x86, 0x44, 0xae, 0x3c, 0xc3, 0x1f, 0xc2, 0xa0, 0x2c, 0x7a, 0x6e, 0xc7, 0xe7, 0x91,
0x3b, 0xe6, 0xcc, 0xc5, 0x1d, 0x60, 0x4a, 0x2a, 0x4b, 0xf7, 0xcc, 0x0f, 0x13, 0xc1, 0xfe, 0x90,
0xae, 0xaf, 0xb9, 0xaf, 0x12, 0x41, 0xec, 0xcb, 0x12, 0xfb, 0x5c, 0x96, 0x07, 0xf3, 0x70, 0x1f,
0xb6, 0x97, 0xd8, 0xaf, 0xe9, 0x7c, 0x14, 0x9d, 0x79, 0xbe, 0x5f, 0x25, 0x70, 0xa7, 0xbe, 0x2d,
0x92, 0x88, 0x33, 0x1f, 0xf7, 0x00, 0x49, 0xa2, 0x43, 0x92, 0x1e, 0x3c, 0x48, 0x57, 0xd0, 0x7c,
0xbd, 0x42, 0x58, 0x66, 0x7b, 0xc9, 0xd4, 0xf5, 0xd9, 0x3b, 0xdc, 0x05, 0xf6, 0x3c, 0xb8, 0xd2,
0xdc, 0x13, 0x5f, 0xb8, 0xe2, 0x9a, 0xfd, 0xad, 0x86, 0x3b, 0xb0, 0x99, 0xb3, 0x9f, 0x47, 0x41,
0x12, 0xb2, 0xbf, 0xd7, 0x70, 0x1f, 0x30, 0xe7, 0x9e, 0x47, 0x41, 0x18, 0xc4, 0xb6, 0xc7, 0xfe,
0x51, 0xc3, 0x3d, 0xd8, 0x7a, 0x1e, 0x5c, 0x65, 0x59, 0x50, 0x06, 0xff, 0x4c, 0x0d, 0x32, 0xfe,
0x0b, 0x3e, 0xbf, 0xe0, 0x11, 0xfb, 0x57, 0x0d, 0x6f, 0xc1, 0xce, 0xb2, 0x20, 0xf3, 0xf5, 0xef,
0x9a, 0xde, 0x51, 0x26, 0x7a, 0x1b, 0x08, 0xce, 0xfe, 0x93, 0xb2, 0x75, 0x1c, 0xb4, 0xa3, 0xff,
0xd6, 0x70, 0x1b, 0xfa, 0x39, 0x5b, 0xea, 0xfe, 0xaf, 0x86, 0x43, 0xd8, 0x2d, 0x30, 0x5d, 0x7f,
0x7a, 0x4e, 0x1d, 0xc7, 0xfe, 0x5f, 0x3b, 0xfa, 0xae, 0x09, 0x9b, 0x74, 0x51, 0x3c, 0x09, 0xd5,
0x02, 0x34, 0x2a, 0x3c, 0x50, 0x7d, 0x86, 0x15, 0x2f, 0xfb, 0x61, 0xd5, 0xac, 0x8e, 0x47, 0xba,
0x1d, 0xb1, 0xea, 0x81, 0x3f, 0xac, 0x1c, 0xd9, 0x69, 0x11, 0x35, 0x4e, 0xdd, 0x7c, 0xe7, 0x0f,
0xab, 0xe6, 0x76, 0xfc, 0xe5, 0x52, 0x7b, 0xe3, 0xaa, 0xd7, 0xfe, 0x70, 0xe5, 0x04, 0x8f, 0x5f,
0xe6, 0x00, 0x80, 0x2b, 0xde, 0xfc, 0xc3, 0x55, 0x53, 0x3c, 0x3e, 0xca, 0xf0, 0x02, 0xab, 0x5f,
0xfe, 0xc3, 0x15, 0x93, 0x3c, 0xc5, 0x46, 0x0d, 0x28, 0x55, 0x0f, 0xfa, 0x61, 0xe5, 0x70, 0x8e,
0x9f, 0xa7, 0x80, 0x84, 0x95, 0x7f, 0x1a, 0x0c, 0xab, 0x9f, 0x00, 0x14, 0xa1, 0xfc, 0x59, 0xb9,
0xea, 0xdf, 0x80, 0xe1, 0xca, 0xe1, 0x1e, 0x9f, 0x2c, 0x23, 0x1c, 0xae, 0xfc, 0x4f, 0x60, 0xb8,
0x7a, 0xc4, 0xa7, 0x20, 0xe7, 0x6f, 0xc8, 0xea, 0x7f, 0x06, 0x86, 0xab, 0xa6, 0xfc, 0x8b, 0x96,
0xfc, 0xc7, 0xe9, 0xe1, 0xf7, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa1, 0x0f, 0x72, 0x7a, 0x86, 0x12,
0x00, 0x00,
0x28, 0x14, 0x1c, 0x7e, 0x02, 0x3d, 0x59, 0x95, 0xa3, 0x02, 0xfa, 0x77, 0x25, 0xef, 0x54, 0xb2,
0xf0, 0x47, 0x00, 0x5a, 0xc5, 0xd6, 0x83, 0x5d, 0xcf, 0x32, 0x94, 0x02, 0xdd, 0x39, 0xb7, 0x80,
0xf0, 0x4e, 0x09, 0xd7, 0xa5, 0xb0, 0x6d, 0x87, 0x21, 0x89, 0xcc, 0x23, 0x80, 0xbc, 0x5a, 0xf1,
0x0e, 0xf4, 0xe7, 0xf6, 0x42, 0x35, 0xc1, 0x28, 0x76, 0xdf, 0x73, 0xbd, 0x58, 0x6f, 0x6e, 0x2f,
0xe4, 0x86, 0x5e, 0xbb, 0xef, 0xb9, 0xf9, 0xc7, 0x3a, 0xb4, 0xd4, 0x75, 0x45, 0x9e, 0x25, 0x48,
0x8d, 0x5c, 0x27, 0x3d, 0x87, 0xa4, 0xcf, 0x9c, 0xa5, 0xeb, 0xaa, 0xbe, 0x7c, 0x5d, 0x51, 0x4a,
0x84, 0x3b, 0xe7, 0x72, 0x23, 0x0d, 0x4b, 0x7e, 0xe3, 0x3e, 0xb4, 0xfd, 0x64, 0x3e, 0x12, 0x8b,
0x58, 0x76, 0x52, 0xc3, 0x6a, 0xf9, 0xc9, 0xfc, 0xcd, 0x22, 0xc6, 0x23, 0xd8, 0xc8, 0xdb, 0x92,
0x16, 0x51, 0x77, 0x42, 0x5f, 0x87, 0x58, 0x05, 0xe9, 0x99, 0xd5, 0xcd, 0x7a, 0xf2, 0xcc, 0xc1,
0x03, 0x60, 0xd2, 0x46, 0x41, 0xaf, 0x3a, 0x75, 0x4b, 0x9e, 0xba, 0x4f, 0x7c, 0x8d, 0xcd, 0x14,
0x97, 0x1f, 0x80, 0x41, 0x15, 0xa1, 0x54, 0xda, 0x52, 0xa5, 0x43, 0x0c, 0x29, 0xfc, 0x0c, 0x36,
0xf3, 0xfb, 0x5d, 0xa9, 0x74, 0x94, 0x97, 0x9c, 0x7d, 0x23, 0xba, 0x46, 0x31, 0xba, 0x67, 0xd0,
0xd6, 0x5b, 0xac, 0x9c, 0x05, 0xee, 0x42, 0x33, 0xb4, 0x23, 0x11, 0x6b, 0x78, 0x4a, 0xf1, 0xe6,
0xdc, 0x8e, 0x68, 0x86, 0xd2, 0x13, 0x81, 0x52, 0x31, 0x1f, 0xc3, 0x46, 0x81, 0x4f, 0xa8, 0x2a,
0x02, 0x61, 0x7b, 0x3a, 0x45, 0x8a, 0xc8, 0x96, 0xa9, 0xe7, 0xcb, 0x98, 0x8f, 0xc1, 0xc8, 0x6a,
0x91, 0xd2, 0x12, 0x26, 0x17, 0x5f, 0xf3, 0x74, 0x2c, 0xd2, 0x14, 0xb9, 0x0b, 0x83, 0x6f, 0xf5,
0x58, 0xd2, 0xb0, 0x14, 0x71, 0xf7, 0x2f, 0x35, 0xe8, 0xbe, 0x50, 0x30, 0x4c, 0x5d, 0x85, 0x9b,
0xd0, 0x7d, 0x99, 0x78, 0x9e, 0x66, 0xb1, 0x35, 0xec, 0x40, 0x83, 0xd0, 0x9b, 0xd5, 0xd0, 0x80,
0xa6, 0x44, 0x67, 0x56, 0x27, 0x26, 0x95, 0x13, 0x5b, 0xc7, 0x0d, 0x30, 0x32, 0xb8, 0x63, 0x0d,
0x22, 0xb3, 0x6b, 0x81, 0x35, 0xb1, 0x07, 0x9d, 0x14, 0xe5, 0xd8, 0x16, 0x76, 0xa1, 0xad, 0x41,
0x89, 0x21, 0x02, 0xb4, 0x54, 0xa2, 0xd8, 0x36, 0x79, 0x96, 0x78, 0xc2, 0x76, 0xc8, 0x41, 0xd6,
0xa1, 0x6c, 0x17, 0xfb, 0x00, 0x79, 0x6f, 0xb2, 0x3d, 0x72, 0x98, 0x76, 0x25, 0xdb, 0xbf, 0xfb,
0xe7, 0x26, 0x74, 0x52, 0x3c, 0xc0, 0x16, 0xd4, 0x5f, 0x7d, 0xcd, 0xd6, 0x70, 0x0b, 0x36, 0xce,
0x7c, 0xc1, 0x23, 0xdf, 0xf6, 0x4e, 0xe8, 0x1e, 0x62, 0x35, 0x62, 0x9d, 0xf8, 0xe3, 0xc0, 0x71,
0xfd, 0xa9, 0x62, 0xd5, 0xc9, 0xd1, 0xb1, 0xed, 0xbc, 0x0c, 0xfc, 0x31, 0x67, 0xeb, 0xc8, 0xa0,
0xf7, 0x8d, 0x6f, 0x27, 0x62, 0x16, 0x44, 0xee, 0x7b, 0xee, 0xb0, 0x06, 0xee, 0xc2, 0xd6, 0x99,
0x1f, 0x27, 0x93, 0x89, 0x3b, 0x76, 0xb9, 0x2f, 0xbe, 0x4a, 0x7c, 0x27, 0x66, 0x4d, 0x44, 0xe8,
0x7f, 0xe3, 0x5f, 0xfa, 0xc1, 0xb7, 0xbe, 0x1e, 0xde, 0x58, 0x0b, 0x07, 0xb0, 0x73, 0x6c, 0xc7,
0xfc, 0x59, 0x12, 0x7a, 0xee, 0xd8, 0x16, 0xfc, 0x89, 0xe3, 0x44, 0x3c, 0x8e, 0x19, 0x27, 0x27,
0x24, 0x29, 0xae, 0x3d, 0x49, 0x0d, 0x0a, 0xfe, 0x39, 0x8f, 0xd9, 0x14, 0x6f, 0xc1, 0xee, 0x0d,
0x89, 0x5c, 0x79, 0x86, 0x3f, 0x84, 0x41, 0x59, 0xf4, 0xdc, 0x8e, 0xcf, 0x23, 0x77, 0xcc, 0x99,
0x8b, 0x3b, 0xc0, 0x94, 0x54, 0x96, 0xee, 0x99, 0x1f, 0x26, 0x82, 0xfd, 0x21, 0x5d, 0x5f, 0x73,
0x5f, 0x25, 0x82, 0xd8, 0x97, 0x25, 0xf6, 0xb9, 0x2c, 0x0f, 0xe6, 0xe1, 0x3e, 0x6c, 0x2f, 0xb1,
0x5f, 0xd3, 0xf9, 0x28, 0x3a, 0xf3, 0x7c, 0xbf, 0x4a, 0xe0, 0x4e, 0x7d, 0x5b, 0x24, 0x11, 0x67,
0x3e, 0xee, 0x01, 0x92, 0x44, 0x87, 0x24, 0x3d, 0x78, 0x90, 0xae, 0xa0, 0xf9, 0x7a, 0x85, 0xb0,
0xcc, 0xf6, 0x92, 0xa9, 0xeb, 0xb3, 0x77, 0xb8, 0x0b, 0xec, 0x79, 0x70, 0xa5, 0xb9, 0x27, 0xbe,
0x70, 0xc5, 0x35, 0xfb, 0x5b, 0x0d, 0x77, 0x60, 0x33, 0x67, 0x3f, 0x8f, 0x82, 0x24, 0x64, 0x7f,
0xaf, 0xe1, 0x3e, 0x60, 0xce, 0x3d, 0x8f, 0x82, 0x30, 0x88, 0x6d, 0x8f, 0xfd, 0xa3, 0x86, 0x7b,
0xb0, 0xf5, 0x3c, 0xb8, 0xca, 0xb2, 0xa0, 0x0c, 0xfe, 0x99, 0x1a, 0x64, 0xfc, 0x17, 0x7c, 0x7e,
0xc1, 0x23, 0xf6, 0xaf, 0x1a, 0xde, 0x82, 0x9d, 0x65, 0x41, 0xe6, 0xeb, 0xdf, 0x35, 0xbd, 0xa3,
0x4c, 0xf4, 0x36, 0x10, 0x9c, 0xfd, 0x27, 0x65, 0xeb, 0x38, 0x68, 0x47, 0xff, 0xad, 0xe1, 0x36,
0xf4, 0x73, 0xb6, 0xd4, 0xfd, 0x5f, 0x0d, 0x87, 0xb0, 0x5b, 0x60, 0xba, 0xfe, 0xf4, 0x9c, 0x3a,
0x8e, 0xfd, 0xbf, 0x76, 0xf4, 0x5d, 0x13, 0x36, 0xe9, 0xa2, 0x78, 0x12, 0xaa, 0x05, 0x68, 0x54,
0x78, 0xa0, 0xfa, 0x0c, 0x2b, 0x5e, 0xf6, 0xc3, 0xaa, 0x59, 0x1d, 0x8f, 0x74, 0x3b, 0x62, 0xd5,
0x03, 0x7f, 0x58, 0x39, 0xb2, 0xd3, 0x22, 0x6a, 0x9c, 0xba, 0xf9, 0xce, 0x1f, 0x56, 0xcd, 0xed,
0xf8, 0xcb, 0xa5, 0xf6, 0xc6, 0x55, 0xaf, 0xfd, 0xe1, 0xca, 0x09, 0x1e, 0xbf, 0xcc, 0x01, 0x00,
0x57, 0xbc, 0xf9, 0x87, 0xab, 0xa6, 0x78, 0x7c, 0x94, 0xe1, 0x05, 0x56, 0xbf, 0xfc, 0x87, 0x2b,
0x26, 0x79, 0x8a, 0x8d, 0x1a, 0x50, 0xaa, 0x1e, 0xf4, 0xc3, 0xca, 0xe1, 0x1c, 0x3f, 0x4f, 0x01,
0x09, 0x2b, 0xff, 0x34, 0x18, 0x56, 0x3f, 0x01, 0x28, 0x42, 0xf9, 0xb3, 0x72, 0xd5, 0xbf, 0x01,
0xc3, 0x95, 0xc3, 0x3d, 0x3e, 0x59, 0x46, 0x38, 0x5c, 0xf9, 0x9f, 0xc0, 0x70, 0xf5, 0x88, 0x4f,
0x41, 0xce, 0xdf, 0x90, 0xd5, 0xff, 0x0c, 0x0c, 0x57, 0x4d, 0xf9, 0x17, 0x2d, 0xf9, 0x8f, 0xd3,
0xc3, 0xef, 0x03, 0x00, 0x00, 0xff, 0xff, 0xa2, 0x81, 0xd5, 0x01, 0x86, 0x12, 0x00, 0x00,
}

+ 2
- 2
types/types.proto View File

@ -219,7 +219,7 @@ message TMSPInfo {
}
message LastBlockInfo {
int32 block_height = 1;
uint64 block_height = 1;
bytes block_hash = 2;
bytes app_hash = 3;
}
@ -233,7 +233,7 @@ message ConfigInfo {
message Header {
string chain_id = 1;
int32 height = 2;
uint64 height = 2;
uint64 time = 3;
uint64 num_txs = 4;
BlockID last_block_id = 5;


+ 24
- 0
types/validators.go View File

@ -0,0 +1,24 @@
package types
import (
"bytes"
)
// validators implements sort
type Validators []*Validator
func (v Validators) Len() int {
return len(v)
}
// XXX: doesn't distinguish same validator with different power
func (v Validators) Less(i, j int) bool {
return bytes.Compare(v[i].PubKey, v[j].PubKey) <= 0
}
func (v Validators) Swap(i, j int) {
v1 := v[i]
v[i] = v[j]
v[j] = v1
}

Loading…
Cancel
Save