diff --git a/example/counter/counter.go b/example/counter/counter.go index 2596eb107..230556e18 100644 --- a/example/counter/counter.go +++ b/example/counter/counter.go @@ -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")) } diff --git a/example/dummy/README.md b/example/dummy/README.md new file mode 100644 index 000000000..19f82fda6 --- /dev/null +++ b/example/dummy/README.md @@ -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`. + diff --git a/example/dummy/dummy.go b/example/dummy/dummy.go index 0c6a90893..80c1ad9d0 100644 --- a/example/dummy/dummy.go +++ b/example/dummy/dummy.go @@ -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"` } diff --git a/example/dummy/dummy_test.go b/example/dummy/dummy_test.go new file mode 100644 index 000000000..e284f1258 --- /dev/null +++ b/example/dummy/dummy_test.go @@ -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) + } + } +} diff --git a/example/dummy/persistent_dummy.go b/example/dummy/persistent_dummy.go index cb2171f55..230e537a8 100644 --- a/example/dummy/persistent_dummy.go +++ b/example/dummy/persistent_dummy.go @@ -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 +} diff --git a/glide.lock b/glide.lock index 9171ff8d7..e82a60d46 100644 --- a/glide.lock +++ b/glide.lock @@ -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 diff --git a/tests/test_cli/ex1.tmsp.out b/tests/test_cli/ex1.tmsp.out index 89bd61c2f..836df8aeb 100644 --- a/tests/test_cli/ex1.tmsp.out +++ b/tests/test_cli/ex1.tmsp.out @@ -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}} diff --git a/types/types.pb.go b/types/types.pb.go index 0b3248a35..7204767eb 100644 --- a/types/types.pb.go +++ b/types/types.pb.go @@ -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, } diff --git a/types/types.proto b/types/types.proto index db25fbba3..3e9ebfe59 100644 --- a/types/types.proto +++ b/types/types.proto @@ -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; diff --git a/types/validators.go b/types/validators.go new file mode 100644 index 000000000..6494394ee --- /dev/null +++ b/types/validators.go @@ -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 +}