diff --git a/.circleci/config.yml b/.circleci/config.yml index fd22668a..ab773382 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -46,7 +46,7 @@ jobs: paths: - /go/src/github.com/tendermint/abci - test_integration: + test_apps: <<: *defaults steps: - attach_workspace: @@ -56,10 +56,27 @@ jobs: - restore_cache: key: v1-tree-{{ .Environment.CIRCLE_SHA1 }} - run: - name: Run integration tests + name: Run apps tests command: | - find . -path ./vendor -prune -o -name "*.sock" -exec rm {} \; - bash tests/test.sh + export PATH="$GOBIN:$PATH" + bash tests/test_app/test.sh + +# XXX: if this test fails, fix it and update the docs at: +# https://github.com/tendermint/tendermint/blob/develop/docs/abci-cli.rst + test_cli: + <<: *defaults + steps: + - attach_workspace: + at: /tmp/workspace + - restore_cache: + key: v1-pkg-cache + - restore_cache: + key: v1-tree-{{ .Environment.CIRCLE_SHA1 }} + - run: + name: Run cli tests + command: | + export PATH="$GOBIN:$PATH" + bash tests/test_cli/test.sh test_cover: <<: *defaults @@ -111,11 +128,12 @@ workflows: - test_cover: requires: - setup_dependencies - - test_integration: - requires: + - test_apps: + requires: + - setup_dependencies + - test_cli: + requires: - setup_dependencies - upload_coverage: requires: - - test_integrations - - + - test_cover diff --git a/.gitignore b/.gitignore index 8c2b367c..421292fa 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ types/types.pb.go *.sw[op] abci-cli coverage.txt +profile.out \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d15c4e15..2584353d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## 0.11.0 + +*TBD* + +BREAKING CHANGES: + +- [example/dummy] Remove. See example/kvstore +- [types] Upgrade many messages: + - RequestInitChain takes all fields from a Genesis file + - RequestBeginBlock provides a list of all validators and whether or not + they signed + - Header: remove some fields, add proposer + - BlockID, PartSetHeader: remove + - Validator: includes address + - PubKey: new message with `type` and `data` + - Evidence: add type and more fields + +FEATURES: + +- [types] Add some fields + - ResponseInitChain includes ConsensusParams and Validators + - ResponseBeginBlock includes tags + - ResponseEndBlock includes tags + ## 0.10.3 (April 9, 2018) IMPROVEMENTS: diff --git a/Makefile b/Makefile index 64a989a8..7d1c4b2e 100644 --- a/Makefile +++ b/Makefile @@ -82,9 +82,21 @@ test_race: @echo "==> Running go test --race" @go test -v -race $(PACKAGES) -test_integrations: - @bash test.sh +### three tests tested by Jenkins +test_cover: + @ bash tests/test_cover.sh +test_apps: + # test the counter using a go test script + @ bash tests/test_app/test.sh + +test_cli: + # test the cli against the examples in the tutorial at: + # http://tendermint.readthedocs.io/projects/tools/en/master/abci-cli.html + # + # XXX: if this test fails, fix it and update the docs at: + # https://github.com/tendermint/tendermint/blob/develop/docs/abci-cli.rst + @ bash tests/test_cli/test.sh ######################################## ### Formatting, linting, and vetting @@ -159,4 +171,4 @@ devdoc_clean: # To avoid unintended conflicts with file names, always add to .PHONY # unless there is a reason not to. # https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html -.PHONY: check protoc build dist install check_tools get_tools get_protoc update_tools get_vendor_deps test test_race test_integrations fmt metalinter metalinter_all docker_build docker_run docker_run_rm devdoc_init devdoc devdoc_save devdoc_clean +.PHONY: check protoc build dist install check_tools get_tools get_protoc update_tools get_vendor_deps test test_race fmt metalinter metalinter_all docker_build docker_run docker_run_rm devdoc_init devdoc devdoc_save devdoc_clean diff --git a/README.md b/README.md index e6051cc3..6de9f706 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,8 @@ Blockchains are systems for multi-master state machine replication. **ABCI** is an interface that defines the boundary between the replication engine (the blockchain), and the state machine (the application). -By using a socket protocol, we enable a consensus engine running in one process -to manage an application state running in another. - -For background information on ABCI, motivations, and tendermint, please visit [the documentation](http://tendermint.readthedocs.io/en/master/). -The two guides to focus on are the `Application Development Guide` and `Using ABCI-CLI`. +Using a socket protocol, a consensus engine running in one process +can manage an application state running in another. Previously, the ABCI was referred to as TMSP. @@ -17,8 +14,19 @@ The community has provided a number of addtional implementations, see the [Tende ## Specification -The [primary specification](https://github.com/tendermint/abci/blob/master/types/types.proto) -is made using Protocol Buffers. To build it, run +A detailed description of the ABCI methods and message types is contained in: + +- [A prose specification](specification.md) +- [A protobuf file](https://github.com/tendermint/abci/blob/master/types/types.proto) +- [A Go interface](https://github.com/tendermint/abci/blob/master/types/application.go). + +For more background information on ABCI, motivations, and tendermint, please visit [the documentation](http://tendermint.readthedocs.io/en/master/). +The two guides to focus on are the `Application Development Guide` and `Using ABCI-CLI`. + + +## Protocl Buffers + +To compile the protobuf file, run: ``` make protoc @@ -28,12 +36,10 @@ See `protoc --help` and [the Protocol Buffers site](https://developers.google.co for details on compiling for other languages. Note we also include a [GRPC](http://www.grpc.io/docs) service definition. -For the specification as an interface in Go, see the -[types/application.go file](https://github.com/tendermint/abci/blob/master/types/application.go). +## Install ABCI-CLI -See the [spec file](specification.rst) for a detailed description of the message types. - -## Install +The `abci-cli` is a simple tool for debugging ABCI servers and running some +example apps. To install it: ``` go get github.com/tendermint/abci diff --git a/cmd/abci-cli/abci-cli.go b/cmd/abci-cli/abci-cli.go index 4dc5e96e..2743fa2b 100644 --- a/cmd/abci-cli/abci-cli.go +++ b/cmd/abci-cli/abci-cli.go @@ -44,11 +44,9 @@ var ( flagProve bool // counter - flagAddrC string flagSerial bool // kvstore - flagAddrD string flagPersist string ) @@ -125,17 +123,14 @@ func addQueryFlags() { } func addCounterFlags() { - counterCmd.PersistentFlags().StringVarP(&flagAddrC, "addr", "", "tcp://0.0.0.0:46658", "listen address") counterCmd.PersistentFlags().BoolVarP(&flagSerial, "serial", "", false, "enforce incrementing (serial) transactions") } func addDummyFlags() { - dummyCmd.PersistentFlags().StringVarP(&flagAddrD, "addr", "", "tcp://0.0.0.0:46658", "listen address") dummyCmd.PersistentFlags().StringVarP(&flagPersist, "persist", "", "", "directory to use for a database") } func addKVStoreFlags() { - kvstoreCmd.PersistentFlags().StringVarP(&flagAddrD, "addr", "", "tcp://0.0.0.0:46658", "listen address") kvstoreCmd.PersistentFlags().StringVarP(&flagPersist, "persist", "", "", "directory to use for a database") } @@ -659,7 +654,7 @@ func cmdCounter(cmd *cobra.Command, args []string) error { logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) // Start the listener - srv, err := server.NewServer(flagAddrC, flagAbci, app) + srv, err := server.NewServer(flagAddress, flagAbci, app) if err != nil { return err } @@ -689,7 +684,7 @@ func cmdKVStore(cmd *cobra.Command, args []string) error { } // Start the listener - srv, err := server.NewServer(flagAddrD, flagAbci, app) + srv, err := server.NewServer(flagAddress, flagAbci, app) if err != nil { return err } diff --git a/example/dummy/README.md b/example/dummy/README.md deleted file mode 100644 index fe9d1c2d..00000000 --- a/example/dummy/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Dummy - -DEPRECATED. See KVStore - diff --git a/example/dummy/helpers.go b/example/dummy/helpers.go deleted file mode 100644 index 92731986..00000000 --- a/example/dummy/helpers.go +++ /dev/null @@ -1,36 +0,0 @@ -package dummy - -import ( - "github.com/tendermint/abci/types" - cmn "github.com/tendermint/tmlibs/common" -) - -// RandVal creates one random validator, with a key derived -// from the input value -func RandVal(i int) types.Validator { - pubkey := cmn.RandBytes(33) - power := cmn.RandUint16() + 1 - return types.Validator{pubkey, int64(power)} -} - -// RandVals returns a list of cnt validators for initializing -// the application. Note that the keys are deterministically -// derived from the index in the array, while the power is -// random (Change this if not desired) -func RandVals(cnt int) []types.Validator { - res := make([]types.Validator, cnt) - for i := 0; i < cnt; i++ { - res[i] = RandVal(i) - } - return res -} - -// InitDummy initializes the dummy app with some data, -// which allows tests to pass and is fine as long as you -// don't make any tx that modify the validator state -func InitDummy(app *PersistentDummyApplication) { - app.InitChain(types.RequestInitChain{ - Validators: RandVals(1), - AppStateBytes: []byte("[]"), - }) -} diff --git a/example/dummy/kvstore.go b/example/dummy/kvstore.go deleted file mode 100644 index 79aa4397..00000000 --- a/example/dummy/kvstore.go +++ /dev/null @@ -1,126 +0,0 @@ -package dummy - -import ( - "bytes" - "encoding/binary" - "encoding/json" - "fmt" - - "github.com/tendermint/abci/example/code" - "github.com/tendermint/abci/types" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" -) - -var ( - stateKey = []byte("stateKey") - kvPairPrefixKey = []byte("kvPairKey:") -) - -type State struct { - db dbm.DB - Size int64 `json:"size"` - Height int64 `json:"height"` - AppHash []byte `json:"app_hash"` -} - -func loadState(db dbm.DB) State { - stateBytes := db.Get(stateKey) - var state State - if len(stateBytes) != 0 { - err := json.Unmarshal(stateBytes, &state) - if err != nil { - panic(err) - } - } - state.db = db - return state -} - -func saveState(state State) { - stateBytes, err := json.Marshal(state) - if err != nil { - panic(err) - } - state.db.Set(stateKey, stateBytes) -} - -func prefixKey(key []byte) []byte { - return append(kvPairPrefixKey, key...) -} - -//--------------------------------------------------- - -var _ types.Application = (*DummyApplication)(nil) - -type DummyApplication struct { - types.BaseApplication - - state State -} - -func NewDummyApplication() *DummyApplication { - state := loadState(dbm.NewMemDB()) - return &DummyApplication{state: state} -} - -func (app *DummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { - return types.ResponseInfo{Data: fmt.Sprintf("{\"size\":%v}", app.state.Size)} -} - -// tx is either "key=value" or just arbitrary bytes -func (app *DummyApplication) DeliverTx(tx []byte) types.ResponseDeliverTx { - var key, value []byte - parts := bytes.Split(tx, []byte("=")) - if len(parts) == 2 { - key, value = parts[0], parts[1] - } else { - key, value = tx, tx - } - app.state.db.Set(prefixKey(key), value) - app.state.Size += 1 - - tags := []cmn.KVPair{ - {[]byte("app.creator"), []byte("jae")}, - {[]byte("app.key"), key}, - } - return types.ResponseDeliverTx{Code: code.CodeTypeOK, Tags: tags} -} - -func (app *DummyApplication) CheckTx(tx []byte) types.ResponseCheckTx { - return types.ResponseCheckTx{Code: code.CodeTypeOK} -} - -func (app *DummyApplication) Commit() types.ResponseCommit { - // Using a memdb - just return the big endian size of the db - appHash := make([]byte, 8) - binary.PutVarint(appHash, app.state.Size) - app.state.AppHash = appHash - app.state.Height += 1 - saveState(app.state) - return types.ResponseCommit{Data: appHash} -} - -func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) { - if reqQuery.Prove { - value := app.state.db.Get(prefixKey(reqQuery.Data)) - resQuery.Index = -1 // TODO make Proof return index - resQuery.Key = reqQuery.Data - resQuery.Value = value - if value != nil { - resQuery.Log = "exists" - } else { - resQuery.Log = "does not exist" - } - return - } else { - value := app.state.db.Get(prefixKey(reqQuery.Data)) - resQuery.Value = value - if value != nil { - resQuery.Log = "exists" - } else { - resQuery.Log = "does not exist" - } - return - } -} diff --git a/example/dummy/kvstore_test.go b/example/dummy/kvstore_test.go deleted file mode 100644 index 548fe742..00000000 --- a/example/dummy/kvstore_test.go +++ /dev/null @@ -1,310 +0,0 @@ -package dummy - -import ( - "bytes" - "io/ioutil" - "sort" - "testing" - - "github.com/stretchr/testify/require" - - cmn "github.com/tendermint/tmlibs/common" - "github.com/tendermint/tmlibs/log" - - abcicli "github.com/tendermint/abci/client" - "github.com/tendermint/abci/example/code" - abciserver "github.com/tendermint/abci/server" - "github.com/tendermint/abci/types" -) - -func testDummy(t *testing.T, app types.Application, tx []byte, key, value string) { - ar := app.DeliverTx(tx) - require.False(t, ar.IsErr(), ar) - // repeating tx doesn't raise error - ar = app.DeliverTx(tx) - require.False(t, ar.IsErr(), ar) - - // make sure query is fine - resQuery := app.Query(types.RequestQuery{ - Path: "/store", - Data: []byte(key), - }) - require.Equal(t, code.CodeTypeOK, resQuery.Code) - require.Equal(t, value, string(resQuery.Value)) - - // make sure proof is fine - resQuery = app.Query(types.RequestQuery{ - Path: "/store", - Data: []byte(key), - Prove: true, - }) - require.EqualValues(t, code.CodeTypeOK, resQuery.Code) - require.Equal(t, value, string(resQuery.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", "abci-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", "abci-dummy-test") // TODO - if err != nil { - t.Fatal(err) - } - dummy := NewPersistentDummyApplication(dir) - InitDummy(dummy) - height := int64(0) - - resInfo := dummy.Info(types.RequestInfo{}) - if resInfo.LastBlockHeight != height { - t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight) - } - - // make and apply block - height = int64(1) - hash := []byte("foo") - header := types.Header{ - Height: int64(height), - } - dummy.BeginBlock(types.RequestBeginBlock{hash, header, nil, nil}) - dummy.EndBlock(types.RequestEndBlock{header.Height}) - dummy.Commit() - - resInfo = dummy.Info(types.RequestInfo{}) - if resInfo.LastBlockHeight != height { - t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight) - } - -} - -// add a validator, remove a validator, update a validator -func TestValUpdates(t *testing.T) { - dir, err := ioutil.TempDir("/tmp", "abci-dummy-test") // TODO - if err != nil { - t.Fatal(err) - } - dummy := NewPersistentDummyApplication(dir) - - // init with some validators - total := 10 - nInit := 5 - vals := RandVals(total) - // iniitalize with the first nInit - dummy.InitChain(types.RequestInitChain{ - Validators: 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:]...) - 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 := int64(heightInt) - hash := []byte("foo") - header := types.Header{ - Height: height, - } - - dummy.BeginBlock(types.RequestBeginBlock{hash, header, nil, nil}) - for _, tx := range txs { - if r := dummy.DeliverTx(tx); r.IsErr() { - t.Fatal(r) - } - } - resEndBlock := dummy.EndBlock(types.RequestEndBlock{header.Height}) - dummy.Commit() - - valsEqual(t, diff, resEndBlock.ValidatorUpdates) - -} - -// 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) - } - } -} - -func makeSocketClientServer(app types.Application, name string) (abcicli.Client, cmn.Service, error) { - // Start the listener - socket := cmn.Fmt("unix://%s.sock", name) - logger := log.TestingLogger() - - server := abciserver.NewSocketServer(socket, app) - server.SetLogger(logger.With("module", "abci-server")) - if err := server.Start(); err != nil { - return nil, nil, err - } - - // Connect to the socket - client := abcicli.NewSocketClient(socket, false) - client.SetLogger(logger.With("module", "abci-client")) - if err := client.Start(); err != nil { - server.Stop() - return nil, nil, err - } - - return client, server, nil -} - -func makeGRPCClientServer(app types.Application, name string) (abcicli.Client, cmn.Service, error) { - // Start the listener - socket := cmn.Fmt("unix://%s.sock", name) - logger := log.TestingLogger() - - gapp := types.NewGRPCApplication(app) - server := abciserver.NewGRPCServer(socket, gapp) - server.SetLogger(logger.With("module", "abci-server")) - if err := server.Start(); err != nil { - return nil, nil, err - } - - client := abcicli.NewGRPCClient(socket, true) - client.SetLogger(logger.With("module", "abci-client")) - if err := client.Start(); err != nil { - server.Stop() - return nil, nil, err - } - return client, server, nil -} - -func TestClientServer(t *testing.T) { - // set up socket app - dummy := NewDummyApplication() - client, server, err := makeSocketClientServer(dummy, "dummy-socket") - require.Nil(t, err) - defer server.Stop() - defer client.Stop() - - runClientTests(t, client) - - // set up grpc app - dummy = NewDummyApplication() - gclient, gserver, err := makeGRPCClientServer(dummy, "dummy-grpc") - require.Nil(t, err) - defer gserver.Stop() - defer gclient.Stop() - - runClientTests(t, gclient) -} - -func runClientTests(t *testing.T, client abcicli.Client) { - // run some tests.... - key := "abc" - value := key - tx := []byte(key) - testClient(t, client, tx, key, value) - - value = "def" - tx = []byte(key + "=" + value) - testClient(t, client, tx, key, value) -} - -func testClient(t *testing.T, app abcicli.Client, tx []byte, key, value string) { - ar, err := app.DeliverTxSync(tx) - require.NoError(t, err) - require.False(t, ar.IsErr(), ar) - // repeating tx doesn't raise error - ar, err = app.DeliverTxSync(tx) - require.NoError(t, err) - require.False(t, ar.IsErr(), ar) - - // make sure query is fine - resQuery, err := app.QuerySync(types.RequestQuery{ - Path: "/store", - Data: []byte(key), - }) - require.Nil(t, err) - require.Equal(t, code.CodeTypeOK, resQuery.Code) - require.Equal(t, value, string(resQuery.Value)) - - // make sure proof is fine - resQuery, err = app.QuerySync(types.RequestQuery{ - Path: "/store", - Data: []byte(key), - Prove: true, - }) - require.Nil(t, err) - require.Equal(t, code.CodeTypeOK, resQuery.Code) - require.Equal(t, value, string(resQuery.Value)) -} diff --git a/example/dummy/persistent_kvstore.go b/example/dummy/persistent_kvstore.go deleted file mode 100644 index 30885bc1..00000000 --- a/example/dummy/persistent_kvstore.go +++ /dev/null @@ -1,205 +0,0 @@ -package dummy - -import ( - "bytes" - "encoding/hex" - "fmt" - "strconv" - "strings" - - "github.com/tendermint/abci/example/code" - "github.com/tendermint/abci/types" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" -) - -const ( - ValidatorSetChangePrefix string = "val:" -) - -//----------------------------------------- - -var _ types.Application = (*PersistentDummyApplication)(nil) - -type PersistentDummyApplication struct { - app *DummyApplication - - // validator set - ValUpdates []types.Validator - - logger log.Logger -} - -func NewPersistentDummyApplication(dbDir string) *PersistentDummyApplication { - name := "dummy" - db, err := dbm.NewGoLevelDB(name, dbDir) - if err != nil { - panic(err) - } - - state := loadState(db) - - return &PersistentDummyApplication{ - app: &DummyApplication{state: state}, - logger: log.NewNopLogger(), - } -} - -func (app *PersistentDummyApplication) SetLogger(l log.Logger) { - app.logger = l -} - -func (app *PersistentDummyApplication) Info(req types.RequestInfo) types.ResponseInfo { - res := app.app.Info(req) - res.LastBlockHeight = app.app.state.Height - res.LastBlockAppHash = app.app.state.AppHash - return res -} - -func (app *PersistentDummyApplication) SetOption(req types.RequestSetOption) types.ResponseSetOption { - return app.app.SetOption(req) -} - -// tx is either "val:pubkey/power" or "key=value" or just arbitrary bytes -func (app *PersistentDummyApplication) DeliverTx(tx []byte) types.ResponseDeliverTx { - // 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.ValUpdates - return app.execValidatorTx(tx) - } - - // otherwise, update the key-value store - return app.app.DeliverTx(tx) -} - -func (app *PersistentDummyApplication) CheckTx(tx []byte) types.ResponseCheckTx { - return app.app.CheckTx(tx) -} - -// Commit will panic if InitChain was not called -func (app *PersistentDummyApplication) Commit() types.ResponseCommit { - return app.app.Commit() -} - -func (app *PersistentDummyApplication) Query(reqQuery types.RequestQuery) types.ResponseQuery { - return app.app.Query(reqQuery) -} - -// Save the validators in the merkle tree -func (app *PersistentDummyApplication) InitChain(req types.RequestInitChain) types.ResponseInitChain { - for _, v := range req.Validators { - r := app.updateValidator(v) - if r.IsErr() { - app.logger.Error("Error updating validators", "r", r) - } - } - return types.ResponseInitChain{} -} - -// Track the block hash and header information -func (app *PersistentDummyApplication) BeginBlock(req types.RequestBeginBlock) types.ResponseBeginBlock { - // reset valset changes - app.ValUpdates = make([]types.Validator, 0) - return types.ResponseBeginBlock{} -} - -// Update the validator set -func (app *PersistentDummyApplication) EndBlock(req types.RequestEndBlock) types.ResponseEndBlock { - return types.ResponseEndBlock{ValidatorUpdates: app.ValUpdates} -} - -//--------------------------------------------- -// update validators - -func (app *PersistentDummyApplication) Validators() (validators []types.Validator) { - itr := app.app.state.db.Iterator(nil, nil) - for ; itr.Valid(); itr.Next() { - if isValidatorTx(itr.Key()) { - validator := new(types.Validator) - err := types.ReadMessage(bytes.NewBuffer(itr.Value()), validator) - if err != nil { - panic(err) - } - validators = append(validators, *validator) - } - } - return -} - -func MakeValSetChangeTx(pubkey []byte, power int64) []byte { - return []byte(cmn.Fmt("val:%X/%d", pubkey, power)) -} - -func isValidatorTx(tx []byte) bool { - return strings.HasPrefix(string(tx), ValidatorSetChangePrefix) -} - -// format is "val:pubkey1/power1,addr2/power2,addr3/power3"tx -func (app *PersistentDummyApplication) execValidatorTx(tx []byte) types.ResponseDeliverTx { - tx = tx[len(ValidatorSetChangePrefix):] - - //get the pubkey and power - pubKeyAndPower := strings.Split(string(tx), "/") - if len(pubKeyAndPower) != 2 { - return types.ResponseDeliverTx{ - Code: code.CodeTypeEncodingError, - Log: fmt.Sprintf("Expected 'pubkey/power'. Got %v", pubKeyAndPower)} - } - pubkeyS, powerS := pubKeyAndPower[0], pubKeyAndPower[1] - - // decode the pubkey, ensuring its go-crypto encoded - pubkey, err := hex.DecodeString(pubkeyS) - if err != nil { - return types.ResponseDeliverTx{ - Code: code.CodeTypeEncodingError, - Log: fmt.Sprintf("Pubkey (%s) is invalid hex", pubkeyS)} - } - /*_, err = crypto.PubKeyFromBytes(pubkey) - if err != nil { - return types.ResponseDeliverTx{ - Code: code.CodeTypeEncodingError, - Log: fmt.Sprintf("Pubkey (%X) is invalid go-crypto encoded", pubkey)} - }*/ - - // decode the power - power, err := strconv.ParseInt(powerS, 10, 64) - if err != nil { - return types.ResponseDeliverTx{ - Code: code.CodeTypeEncodingError, - Log: fmt.Sprintf("Power (%s) is not an int", powerS)} - } - - // update - return app.updateValidator(types.Validator{pubkey, power}) -} - -// add, update, or remove a validator -func (app *PersistentDummyApplication) updateValidator(v types.Validator) types.ResponseDeliverTx { - key := []byte("val:" + string(v.PubKey)) - if v.Power == 0 { - // remove validator - if !app.app.state.db.Has(key) { - return types.ResponseDeliverTx{ - Code: code.CodeTypeUnauthorized, - Log: fmt.Sprintf("Cannot remove non-existent validator %X", key)} - } - app.app.state.db.Delete(key) - } else { - // add or update validator - value := bytes.NewBuffer(make([]byte, 0)) - if err := types.WriteMessage(&v, value); err != nil { - return types.ResponseDeliverTx{ - Code: code.CodeTypeEncodingError, - Log: fmt.Sprintf("Error encoding validator: %v", err)} - } - app.app.state.db.Set(key, value.Bytes()) - } - - // we only update the changes array if we successfully updated the tree - app.ValUpdates = append(app.ValUpdates, v) - - return types.ResponseDeliverTx{Code: code.CodeTypeOK} -} diff --git a/example/kvstore/helpers.go b/example/kvstore/helpers.go index c71e371a..63bc31a6 100644 --- a/example/kvstore/helpers.go +++ b/example/kvstore/helpers.go @@ -8,9 +8,12 @@ import ( // RandVal creates one random validator, with a key derived // from the input value func RandVal(i int) types.Validator { - pubkey := cmn.RandBytes(33) + addr := cmn.RandBytes(20) + pubkey := cmn.RandBytes(32) power := cmn.RandUint16() + 1 - return types.Validator{pubkey, int64(power)} + v := types.Ed25519Validator(pubkey, int64(power)) + v.Address = addr + return v } // RandVals returns a list of cnt validators for initializing @@ -30,7 +33,6 @@ func RandVals(cnt int) []types.Validator { // don't make any tx that modify the validator state func InitKVStore(app *PersistentKVStoreApplication) { app.InitChain(types.RequestInitChain{ - Validators: RandVals(1), - AppStateBytes: []byte("[]"), + Validators: RandVals(1), }) } diff --git a/example/kvstore/kvstore_test.go b/example/kvstore/kvstore_test.go index b3d29ffb..ff3e4920 100644 --- a/example/kvstore/kvstore_test.go +++ b/example/kvstore/kvstore_test.go @@ -198,7 +198,7 @@ func valsEqual(t *testing.T, vals1, vals2 []types.Validator) { sort.Sort(types.Validators(vals2)) for i, v1 := range vals1 { v2 := vals2[i] - if !bytes.Equal(v1.PubKey, v2.PubKey) || + if !bytes.Equal(v1.PubKey.Data, v2.PubKey.Data) || 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/kvstore/persistent_kvstore.go b/example/kvstore/persistent_kvstore.go index 888258ff..02f7ce74 100644 --- a/example/kvstore/persistent_kvstore.go +++ b/example/kvstore/persistent_kvstore.go @@ -129,15 +129,16 @@ func (app *PersistentKVStoreApplication) Validators() (validators []types.Valida return } -func MakeValSetChangeTx(pubkey []byte, power int64) []byte { - return []byte(cmn.Fmt("val:%X/%d", pubkey, power)) +func MakeValSetChangeTx(pubkey types.PubKey, power int64) []byte { + return []byte(cmn.Fmt("val:%X/%d", pubkey.Data, power)) } func isValidatorTx(tx []byte) bool { return strings.HasPrefix(string(tx), ValidatorSetChangePrefix) } -// format is "val:pubkey1/power1,addr2/power2,addr3/power3"tx +// format is "val:pubkey/power" +// pubkey is raw 32-byte ed25519 key func (app *PersistentKVStoreApplication) execValidatorTx(tx []byte) types.ResponseDeliverTx { tx = tx[len(ValidatorSetChangePrefix):] @@ -150,19 +151,13 @@ func (app *PersistentKVStoreApplication) execValidatorTx(tx []byte) types.Respon } pubkeyS, powerS := pubKeyAndPower[0], pubKeyAndPower[1] - // decode the pubkey, ensuring its go-crypto encoded + // decode the pubkey pubkey, err := hex.DecodeString(pubkeyS) if err != nil { return types.ResponseDeliverTx{ Code: code.CodeTypeEncodingError, Log: fmt.Sprintf("Pubkey (%s) is invalid hex", pubkeyS)} } - /*_, err = crypto.PubKeyFromBytes(pubkey) - if err != nil { - return types.ResponseDeliverTx{ - Code: code.CodeTypeEncodingError, - Log: fmt.Sprintf("Pubkey (%X) is invalid go-crypto encoded", pubkey)} - }*/ // decode the power power, err := strconv.ParseInt(powerS, 10, 64) @@ -173,12 +168,12 @@ func (app *PersistentKVStoreApplication) execValidatorTx(tx []byte) types.Respon } // update - return app.updateValidator(types.Validator{pubkey, power}) + return app.updateValidator(types.Ed25519Validator(pubkey, int64(power))) } // add, update, or remove a validator func (app *PersistentKVStoreApplication) updateValidator(v types.Validator) types.ResponseDeliverTx { - key := []byte("val:" + string(v.PubKey)) + key := []byte("val:" + string(v.PubKey.Data)) if v.Power == 0 { // remove validator if !app.app.state.db.Has(key) { diff --git a/specification.md b/specification.md new file mode 100644 index 00000000..25b9d7d0 --- /dev/null +++ b/specification.md @@ -0,0 +1,324 @@ +# ABCI Specification + +## Message Types + +ABCI requests/responses are defined as simple Protobuf messages in [this +schema file](https://github.com/tendermint/abci/blob/master/types/types.proto). +TendermintCore sends the requests, and the ABCI application sends the +responses. Here, we provide an overview of the messages types and how +they are used by Tendermint. Then we describe each request-response pair +as a function with arguments and return values, and add some notes on +usage. + +Some messages (`Echo, Info, InitChain, BeginBlock, EndBlock, Commit`), +don't return errors because an error would indicate a critical failure +in the application and there's nothing Tendermint can do. The problem +should be addressed and both Tendermint and the application restarted. +All other messages (`SetOption, Query, CheckTx, DeliverTx`) return an +application-specific response `Code uint32`, where only `0` is reserved +for `OK`. + +Some messages (`SetOption, Query, CheckTx, DeliverTx`) return +non-deterministic data in the form of `Info` and `Log`. The `Log` is +intended for the literal output from the application's logger, while the +`Info` is any additional info that should be returned. + +The first time a new blockchain is started, Tendermint calls +`InitChain`. From then on, the Block Execution Sequence that causes the +committed state to be updated is as follows: + +`BeginBlock, [DeliverTx], EndBlock, Commit` + +where one `DeliverTx` is called for each transaction in the block. +Cryptographic commitments to the results of DeliverTx, EndBlock, and +Commit are included in the header of the next block. + +Tendermint opens three connections to the application to handle the +different message types: + +- `Consensus Connection - InitChain, BeginBlock, DeliverTx, EndBlock, Commit` +- `Mempool Connection - CheckTx` +- `Info Connection - Info, SetOption, Query` + +The `Flush` message is used on every connection, and the `Echo` message +is only used for debugging. + +Note that messages may be sent concurrently across all connections -a +typical application will thus maintain a distinct state for each +connection. They may be referred to as the `DeliverTx state`, the +`CheckTx state`, and the `Commit state` respectively. + +See below for more details on the message types and how they are used. + +## Request/Response Messages + +### Echo + +- **Request**: + - `Message (string)`: A string to echo back +- **Response**: + - `Message (string)`: The input string +- **Usage**: + - Echo a string to test an abci client/server implementation + +### Flush + +- **Usage**: + - Signals that messages queued on the client should be flushed to + the server. It is called periodically by the client + implementation to ensure asynchronous requests are actually + sent, and is called immediately to make a synchronous request, + which returns when the Flush response comes back. + +### Info + +- **Request**: + - `Version (string)`: The Tendermint version +- **Response**: + - `Data (string)`: Some arbitrary information + - `Version (Version)`: Version information + - `LastBlockHeight (int64)`: Latest block for which the app has + called Commit + - `LastBlockAppHash ([]byte)`: Latest result of Commit +- **Usage**: + - Return information about the application state. + - Used to sync Tendermint with the application during a handshake + that happens on startup. + - Tendermint expects `LastBlockAppHash` and `LastBlockHeight` to + be updated during `Commit`, ensuring that `Commit` is never + called twice for the same block height. + +### SetOption + +- **Request**: + - `Key (string)`: Key to set + - `Value (string)`: Value to set for key +- **Response**: + - `Code (uint32)`: Response code + - `Log (string)`: The output of the application's logger. May + be non-deterministic. + - `Info (string)`: Additional information. May + be non-deterministic. +- **Usage**: + - Set non-consensus critical application specific options. + - e.g. Key="min-fee", Value="100fermion" could set the minimum fee + required for CheckTx (but not DeliverTx - that would be + consensus critical). + +### InitChain + +- **Request**: + - `Validators ([]Validator)`: Initial genesis validators + - `AppStateBytes ([]byte)`: Serialized initial application state +- **Response**: + - `ConsensusParams (ConsensusParams)`: Initial + consensus-critical parameters. + - `Validators ([]Validator)`: Initial validator set. +- **Usage**: + - Called once upon genesis. + +### Query + +- **Request**: + - `Data ([]byte)`: Raw query bytes. Can be used with or in lieu + of Path. + - `Path (string)`: Path of request, like an HTTP GET path. Can be + used with or in liue of Data. + - Apps MUST interpret '/store' as a query by key on the + underlying store. The key SHOULD be specified in the Data field. + - Apps SHOULD allow queries over specific types like + '/accounts/...' or '/votes/...' + - `Height (int64)`: The block height for which you want the query + (default=0 returns data for the latest committed block). Note + that this is the height of the block containing the + application's Merkle root hash, which represents the state as it + was after committing the block at Height-1 + - `Prove (bool)`: Return Merkle proof with response if possible +- **Response**: + - `Code (uint32)`: Response code. + - `Log (string)`: The output of the application's logger. May + be non-deterministic. + - `Info (string)`: Additional information. May + be non-deterministic. + - `Index (int64)`: The index of the key in the tree. + - `Key ([]byte)`: The key of the matching data. + - `Value ([]byte)`: The value of the matching data. + - `Proof ([]byte)`: Proof for the data, if requested. + - `Height (int64)`: The block height from which data was derived. + Note that this is the height of the block containing the + application's Merkle root hash, which represents the state as it + was after committing the block at Height-1 +- **Usage**: + - Query for data from the application at current or past height. + - Optionally return Merkle proof. + +### BeginBlock + +- **Request**: + - `Hash ([]byte)`: The block's hash. This can be derived from the + block header. + - `Header (struct{})`: The block header + - `Validators ([]SigningValidator)`: List of validators in the current validator + set and whether or not they signed a vote in the LastCommit + - `ByzantineValidators ([]Evidence)`: List of evidence of + validators that acted maliciously +- **Response**: + - `Tags ([]cmn.KVPair)`: Key-Value tags for filtering and indexing +- **Usage**: + - Signals the beginning of a new block. Called prior to + any DeliverTxs. + - The header is expected to at least contain the Height. + - The `Validators` and `ByzantineValidators` can be used to + determine rewards and punishments for the validators. + +### CheckTx + +- **Request**: + - `Tx ([]byte)`: The request transaction bytes +- **Response**: + - `Code (uint32)`: Response code + - `Data ([]byte)`: Result bytes, if any. + - `Log (string)`: The output of the application's logger. May + be non-deterministic. + - `Info (string)`: Additional information. May + be non-deterministic. + - `GasWanted (int64)`: Amount of gas request for transaction. + - `GasUsed (int64)`: Amount of gas consumed by transaction. + - `Tags ([]cmn.KVPair)`: Key-Value tags for filtering and indexing + transactions (eg. by account). + - `Fee (cmn.KI64Pair)`: Fee paid for the transaction. +- **Usage**: Validate a mempool transaction, prior to broadcasting + or proposing. CheckTx should perform stateful but light-weight + checks of the validity of the transaction (like checking signatures + and account balances), but need not execute in full (like running a + smart contract). + + Tendermint runs CheckTx and DeliverTx concurrently with eachother, + though on distinct ABCI connections - the mempool connection and the + consensus connection, respectively. + + The application should maintain a separate state to support CheckTx. + This state can be reset to the latest committed state during + `Commit`, where Tendermint ensures the mempool is locked and not + sending new `CheckTx`. After `Commit`, the mempool will rerun + CheckTx on all remaining transactions, throwing out any that are no + longer valid. + + Keys and values in Tags must be UTF-8 encoded strings (e.g. + "account.owner": "Bob", "balance": "100.0", "date": "2018-01-02") + +### DeliverTx + +- **Request**: + - `Tx ([]byte)`: The request transaction bytes. +- **Response**: + - `Code (uint32)`: Response code. + - `Data ([]byte)`: Result bytes, if any. + - `Log (string)`: The output of the application's logger. May + be non-deterministic. + - `Info (string)`: Additional information. May + be non-deterministic. + - `GasWanted (int64)`: Amount of gas requested for transaction. + - `GasUsed (int64)`: Amount of gas consumed by transaction. + - `Tags ([]cmn.KVPair)`: Key-Value tags for filtering and indexing + transactions (eg. by account). + - `Fee (cmn.KI64Pair)`: Fee paid for the transaction. +- **Usage**: + - Deliver a transaction to be executed in full by the application. + If the transaction is valid, returns CodeType.OK. + - Keys and values in Tags must be UTF-8 encoded strings (e.g. + "account.owner": "Bob", "balance": "100.0", + "time": "2018-01-02T12:30:00Z") + +### EndBlock + +- **Request**: + - `Height (int64)`: Height of the block just executed. +- **Response**: + - `ValidatorUpdates ([]Validator)`: Changes to validator set (set + voting power to 0 to remove). + - `ConsensusParamUpdates (ConsensusParams)`: Changes to + consensus-critical time, size, and other parameters. + - `Tags ([]cmn.KVPair)`: Key-Value tags for filtering and indexing +- **Usage**: + - Signals the end of a block. + - Called prior to each Commit, after all transactions. + - Validator set and consensus params are updated with the result. + - Validator pubkeys are expected to be go-wire encoded. + +### Commit + +- **Response**: + - `Data ([]byte)`: The Merkle root hash +- **Usage**: + - Persist the application state. + - Return a Merkle root hash of the application state. + - It's critical that all application instances return the + same hash. If not, they will not be able to agree on the next + block, because the hash is included in the next block! + +## Data Messages + +### Header + +- **Fields**: + - `ChainID (string)`: ID of the blockchain + - `Height (int64)`: Height of the block in the chain + - `Time (int64)`: Unix time of the block + - `NumTxs (int32)`: Number of transactions in the block + - `TotalTxs (int64)`: Total number of transactions in the blockchain until + now + - `LastBlockHash ([]byte)`: Hash of the previous (parent) block + - `ValidatorsHash ([]byte)`: Hash of the validator set for this block + - `AppHash ([]byte)`: Data returned by the last call to `Commit` - typically the + Merkle root of the application state after executing the previous block's + transactions + - `Proposer (Validator)`: Original proposer for the block +- **Usage**: + - Provided in RequestBeginBlock + - Provides important context about the current state of the blockchain - + especially height and time. + - Provides the proposer of the current block, for use in proposer-based + reward mechanisms. + +### Validator + +- **Fields**: + - `Address ([]byte)`: Address of the validator (hash of the public key) + - `PubKey (PubKey)`: Public key of the validator + - `Power (int64)`: Voting power of the validator +- **Usage**: + - Provides all identifying information about the validator + +### SigningValidator + +- **Fields**: + - `Validator (Validator)`: A validator + - `SignedLastBlock (bool)`: Indicated whether or not the validator signed + the last block +- **Usage**: + - Indicates whether a validator signed the last block, allowing for rewards + based on validator availability + +### PubKey + +- **Fields**: + - `Type (string)`: Type of the public key. A simple string like `"ed25519"`. + In the future, may indicate a serialization algorithm to parse the `Data`, + for instance `"amino"`. + - `Data ([]byte)`: Public key data. For a simple public key, it's just the + raw bytes. If the `Type` indicates an encoding algorithm, this is the + encoded public key. +- **Usage**: + - A generic and extensible typed public key + +### Evidence + +- **Fields**: + - `Type (string)`: Type of the evidence. A hierarchical path like + "duplicate/vote". + - `Validator (Validator`: The offending validator + - `Height (int64)`: Height when the offense was committed + - `Time (int64)`: Unix time of the block at height `Height` + - `TotalVotingPower (int64)`: Total voting power of the validator set at + height `Height` diff --git a/specification.rst b/specification.rst index 8ebe8892..8d8530de 100644 --- a/specification.rst +++ b/specification.rst @@ -1,6 +1,8 @@ ABCI Specification ================== +NOTE: this file has moved to `specification.md <./specification.md>`__. It is left to prevent link breakages for the forseable future. It can safely be deleted in a few months. + Message Types ~~~~~~~~~~~~~ diff --git a/tests/server/client.go b/tests/server/client.go index e7bcbc93..5ef978c7 100644 --- a/tests/server/client.go +++ b/tests/server/client.go @@ -16,11 +16,10 @@ func InitChain(client abcicli.Client) error { for i := 0; i < total; i++ { pubkey := cmn.RandBytes(33) power := cmn.RandInt() - vals[i] = types.Validator{pubkey, int64(power)} + vals[i] = types.Ed25519Validator(pubkey, int64(power)) } _, err := client.InitChainSync(types.RequestInitChain{ - Validators: vals, - AppStateBytes: []byte("{}"), + Validators: vals, }) if err != nil { fmt.Printf("Failed test: InitChain - %v\n", err) diff --git a/tests/test.sh b/tests/test.sh deleted file mode 100755 index 416145fc..00000000 --- a/tests/test.sh +++ /dev/null @@ -1,11 +0,0 @@ -#! /bin/bash -set -e - -# test the counter using a go test script -bash tests/test_app/test.sh - -# test the cli against the examples in the tutorial at tendermint.com -# TODO: make these less fragile -# bash tests/test_cli/test.sh - - diff --git a/tests/test_cli/ex1.abci.out b/tests/test_cli/ex1.abci.out index 6e344071..5d4c196d 100644 --- a/tests/test_cli/ex1.abci.out +++ b/tests/test_cli/ex1.abci.out @@ -10,6 +10,7 @@ > commit -> code: OK +-> data.hex: 0x0000000000000000 > deliver_tx "abc" -> code: OK @@ -21,7 +22,7 @@ > commit -> code: OK --> data.hex: 0x49DFD15CCDACDEAE9728CB01FBB5E8688CA58B91 +-> data.hex: 0x0200000000000000 > query "abc" -> code: OK @@ -35,7 +36,7 @@ > commit -> code: OK --> data.hex: 0x70102DB32280373FBF3F9F89DA2A20CE2CD62B0B +-> data.hex: 0x0400000000000000 > query "def" -> code: OK diff --git a/tests/test_cli/ex2.abci.out b/tests/test_cli/ex2.abci.out index 741dd7b7..5bceb85d 100644 --- a/tests/test_cli/ex2.abci.out +++ b/tests/test_cli/ex2.abci.out @@ -1,5 +1,6 @@ > set_option serial on -> code: OK +-> log: OK (SetOption doesn't return anything.) > check_tx 0x00 -> code: OK diff --git a/test.sh b/tests/test_cover.sh similarity index 57% rename from test.sh rename to tests/test_cover.sh index 978b26e1..abbbbe56 100755 --- a/test.sh +++ b/tests/test_cover.sh @@ -11,9 +11,3 @@ for d in $(go list ./... | grep -v vendor); do rm profile.out fi done - -echo "==> Running integration tests (./tests)" -find . -path ./vendor -prune -o -name "*.sock" -exec rm {} \; -# tests/test.sh requires that we run the installed cmds, must not be out of date -make install -bash tests/test.sh diff --git a/types/pubkey.go b/types/pubkey.go new file mode 100644 index 00000000..e5cd5fbf --- /dev/null +++ b/types/pubkey.go @@ -0,0 +1,16 @@ +package types + +const ( + PubKeyEd25519 = "ed25519" +) + +func Ed25519Validator(pubkey []byte, power int64) Validator { + return Validator{ + // Address: + PubKey: PubKey{ + Type: PubKeyEd25519, + Data: pubkey, + }, + Power: power, + } +} diff --git a/types/types.pb.go b/types/types.pb.go index 92cbe7d8..a6b806fe 100644 --- a/types/types.pb.go +++ b/types/types.pb.go @@ -38,9 +38,9 @@ It has these top-level messages: TxSize BlockGossip Header - BlockID - PartSetHeader Validator + SigningValidator + PubKey Evidence */ //nolint: gas @@ -532,8 +532,11 @@ func (m *RequestSetOption) GetValue() string { } type RequestInitChain struct { - Validators []Validator `protobuf:"bytes,1,rep,name=validators" json:"validators"` - AppStateBytes []byte `protobuf:"bytes,2,opt,name=app_state_bytes,json=appStateBytes,proto3" json:"app_state_bytes,omitempty"` + Time int64 `protobuf:"varint,1,opt,name=time,proto3" json:"time,omitempty"` + ChainId string `protobuf:"bytes,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + ConsensusParams *ConsensusParams `protobuf:"bytes,3,opt,name=consensus_params,json=consensusParams" json:"consensus_params,omitempty"` + Validators []Validator `protobuf:"bytes,4,rep,name=validators" json:"validators"` + AppStateBytes []byte `protobuf:"bytes,5,opt,name=app_state_bytes,json=appStateBytes,proto3" json:"app_state_bytes,omitempty"` } func (m *RequestInitChain) Reset() { *m = RequestInitChain{} } @@ -541,6 +544,27 @@ func (m *RequestInitChain) String() string { return proto.CompactText func (*RequestInitChain) ProtoMessage() {} func (*RequestInitChain) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{5} } +func (m *RequestInitChain) GetTime() int64 { + if m != nil { + return m.Time + } + return 0 +} + +func (m *RequestInitChain) GetChainId() string { + if m != nil { + return m.ChainId + } + return "" +} + +func (m *RequestInitChain) GetConsensusParams() *ConsensusParams { + if m != nil { + return m.ConsensusParams + } + return nil +} + func (m *RequestInitChain) GetValidators() []Validator { if m != nil { return m.Validators @@ -596,10 +620,10 @@ func (m *RequestQuery) GetProve() bool { } type RequestBeginBlock struct { - Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` - Header Header `protobuf:"bytes,2,opt,name=header" json:"header"` - AbsentValidators []int32 `protobuf:"varint,3,rep,packed,name=absent_validators,json=absentValidators" json:"absent_validators,omitempty"` - ByzantineValidators []Evidence `protobuf:"bytes,4,rep,name=byzantine_validators,json=byzantineValidators" json:"byzantine_validators"` + Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + Header Header `protobuf:"bytes,2,opt,name=header" json:"header"` + Validators []SigningValidator `protobuf:"bytes,3,rep,name=validators" json:"validators"` + ByzantineValidators []Evidence `protobuf:"bytes,4,rep,name=byzantine_validators,json=byzantineValidators" json:"byzantine_validators"` } func (m *RequestBeginBlock) Reset() { *m = RequestBeginBlock{} } @@ -621,9 +645,9 @@ func (m *RequestBeginBlock) GetHeader() Header { return Header{} } -func (m *RequestBeginBlock) GetAbsentValidators() []int32 { +func (m *RequestBeginBlock) GetValidators() []SigningValidator { if m != nil { - return m.AbsentValidators + return m.Validators } return nil } @@ -1238,6 +1262,8 @@ func (m *ResponseSetOption) GetInfo() string { } type ResponseInitChain struct { + ConsensusParams *ConsensusParams `protobuf:"bytes,1,opt,name=consensus_params,json=consensusParams" json:"consensus_params,omitempty"` + Validators []Validator `protobuf:"bytes,2,rep,name=validators" json:"validators"` } func (m *ResponseInitChain) Reset() { *m = ResponseInitChain{} } @@ -1245,6 +1271,20 @@ func (m *ResponseInitChain) String() string { return proto.CompactTex func (*ResponseInitChain) ProtoMessage() {} func (*ResponseInitChain) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{18} } +func (m *ResponseInitChain) GetConsensusParams() *ConsensusParams { + if m != nil { + return m.ConsensusParams + } + return nil +} + +func (m *ResponseInitChain) GetValidators() []Validator { + if m != nil { + return m.Validators + } + return nil +} + type ResponseQuery struct { Code uint32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` // bytes data = 2; // use "value" instead. @@ -1319,6 +1359,7 @@ func (m *ResponseQuery) GetHeight() int64 { } type ResponseBeginBlock struct { + Tags []common.KVPair `protobuf:"bytes,1,rep,name=tags" json:"tags,omitempty"` } func (m *ResponseBeginBlock) Reset() { *m = ResponseBeginBlock{} } @@ -1326,6 +1367,13 @@ func (m *ResponseBeginBlock) String() string { return proto.CompactTe func (*ResponseBeginBlock) ProtoMessage() {} func (*ResponseBeginBlock) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{20} } +func (m *ResponseBeginBlock) GetTags() []common.KVPair { + if m != nil { + return m.Tags + } + return nil +} + type ResponseCheckTx struct { Code uint32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` @@ -1473,6 +1521,7 @@ func (m *ResponseDeliverTx) GetFee() common.KI64Pair { type ResponseEndBlock struct { ValidatorUpdates []Validator `protobuf:"bytes,1,rep,name=validator_updates,json=validatorUpdates" json:"validator_updates"` ConsensusParamUpdates *ConsensusParams `protobuf:"bytes,2,opt,name=consensus_param_updates,json=consensusParamUpdates" json:"consensus_param_updates,omitempty"` + Tags []common.KVPair `protobuf:"bytes,3,rep,name=tags" json:"tags,omitempty"` } func (m *ResponseEndBlock) Reset() { *m = ResponseEndBlock{} } @@ -1494,6 +1543,13 @@ func (m *ResponseEndBlock) GetConsensusParamUpdates() *ConsensusParams { return nil } +func (m *ResponseEndBlock) GetTags() []common.KVPair { + if m != nil { + return m.Tags + } + return nil +} + type ResponseCommit struct { // reserve 1 Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` @@ -1622,16 +1678,21 @@ func (m *BlockGossip) GetBlockPartSizeBytes() int32 { return 0 } +// just the minimum the app might need type Header struct { - ChainID string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` - Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` - Time int64 `protobuf:"varint,3,opt,name=time,proto3" json:"time,omitempty"` - NumTxs int32 `protobuf:"varint,4,opt,name=num_txs,json=numTxs,proto3" json:"num_txs,omitempty"` - LastBlockID BlockID `protobuf:"bytes,5,opt,name=last_block_id,json=lastBlockId" json:"last_block_id"` - LastCommitHash []byte `protobuf:"bytes,6,opt,name=last_commit_hash,json=lastCommitHash,proto3" json:"last_commit_hash,omitempty"` - DataHash []byte `protobuf:"bytes,7,opt,name=data_hash,json=dataHash,proto3" json:"data_hash,omitempty"` - ValidatorsHash []byte `protobuf:"bytes,8,opt,name=validators_hash,json=validatorsHash,proto3" json:"validators_hash,omitempty"` - AppHash []byte `protobuf:"bytes,9,opt,name=app_hash,json=appHash,proto3" json:"app_hash,omitempty"` + // basics + ChainID string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` + Time int64 `protobuf:"varint,3,opt,name=time,proto3" json:"time,omitempty"` + // txs + NumTxs int32 `protobuf:"varint,4,opt,name=num_txs,json=numTxs,proto3" json:"num_txs,omitempty"` + TotalTxs int64 `protobuf:"varint,5,opt,name=total_txs,json=totalTxs,proto3" json:"total_txs,omitempty"` + // hashes + LastBlockHash []byte `protobuf:"bytes,6,opt,name=last_block_hash,json=lastBlockHash,proto3" json:"last_block_hash,omitempty"` + ValidatorsHash []byte `protobuf:"bytes,7,opt,name=validators_hash,json=validatorsHash,proto3" json:"validators_hash,omitempty"` + AppHash []byte `protobuf:"bytes,8,opt,name=app_hash,json=appHash,proto3" json:"app_hash,omitempty"` + // consensus + Proposer Validator `protobuf:"bytes,9,opt,name=proposer" json:"proposer"` } func (m *Header) Reset() { *m = Header{} } @@ -1667,23 +1728,16 @@ func (m *Header) GetNumTxs() int32 { return 0 } -func (m *Header) GetLastBlockID() BlockID { +func (m *Header) GetTotalTxs() int64 { if m != nil { - return m.LastBlockID + return m.TotalTxs } - return BlockID{} + return 0 } -func (m *Header) GetLastCommitHash() []byte { +func (m *Header) GetLastBlockHash() []byte { if m != nil { - return m.LastCommitHash - } - return nil -} - -func (m *Header) GetDataHash() []byte { - if m != nil { - return m.DataHash + return m.LastBlockHash } return nil } @@ -1702,69 +1756,37 @@ func (m *Header) GetAppHash() []byte { return nil } -type BlockID struct { - Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` - Parts PartSetHeader `protobuf:"bytes,2,opt,name=parts" json:"parts"` -} - -func (m *BlockID) Reset() { *m = BlockID{} } -func (m *BlockID) String() string { return proto.CompactTextString(m) } -func (*BlockID) ProtoMessage() {} -func (*BlockID) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{30} } - -func (m *BlockID) GetHash() []byte { +func (m *Header) GetProposer() Validator { if m != nil { - return m.Hash + return m.Proposer } - return nil -} - -func (m *BlockID) GetParts() PartSetHeader { - if m != nil { - return m.Parts - } - return PartSetHeader{} -} - -type PartSetHeader struct { - Total int32 `protobuf:"varint,1,opt,name=total,proto3" json:"total,omitempty"` - Hash []byte `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"` -} - -func (m *PartSetHeader) Reset() { *m = PartSetHeader{} } -func (m *PartSetHeader) String() string { return proto.CompactTextString(m) } -func (*PartSetHeader) ProtoMessage() {} -func (*PartSetHeader) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{31} } - -func (m *PartSetHeader) GetTotal() int32 { - if m != nil { - return m.Total - } - return 0 -} - -func (m *PartSetHeader) GetHash() []byte { - if m != nil { - return m.Hash - } - return nil + return Validator{} } +// Validator type Validator struct { - PubKey []byte `protobuf:"bytes,1,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty"` - Power int64 `protobuf:"varint,2,opt,name=power,proto3" json:"power,omitempty"` + Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + PubKey PubKey `protobuf:"bytes,2,opt,name=pub_key,json=pubKey" json:"pub_key"` + Power int64 `protobuf:"varint,3,opt,name=power,proto3" json:"power,omitempty"` } func (m *Validator) Reset() { *m = Validator{} } func (m *Validator) String() string { return proto.CompactTextString(m) } func (*Validator) ProtoMessage() {} -func (*Validator) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{32} } +func (*Validator) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{30} } -func (m *Validator) GetPubKey() []byte { +func (m *Validator) GetAddress() []byte { + if m != nil { + return m.Address + } + return nil +} + +func (m *Validator) GetPubKey() PubKey { if m != nil { return m.PubKey } - return nil + return PubKey{} } func (m *Validator) GetPower() int64 { @@ -1774,9 +1796,61 @@ func (m *Validator) GetPower() int64 { return 0 } +// Validator with an extra bool +type SigningValidator struct { + Validator Validator `protobuf:"bytes,1,opt,name=validator" json:"validator"` + SignedLastBlock bool `protobuf:"varint,2,opt,name=signed_last_block,json=signedLastBlock,proto3" json:"signed_last_block,omitempty"` +} + +func (m *SigningValidator) Reset() { *m = SigningValidator{} } +func (m *SigningValidator) String() string { return proto.CompactTextString(m) } +func (*SigningValidator) ProtoMessage() {} +func (*SigningValidator) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{31} } + +func (m *SigningValidator) GetValidator() Validator { + if m != nil { + return m.Validator + } + return Validator{} +} + +func (m *SigningValidator) GetSignedLastBlock() bool { + if m != nil { + return m.SignedLastBlock + } + return false +} + +type PubKey struct { + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *PubKey) Reset() { *m = PubKey{} } +func (m *PubKey) String() string { return proto.CompactTextString(m) } +func (*PubKey) ProtoMessage() {} +func (*PubKey) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{32} } + +func (m *PubKey) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *PubKey) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + type Evidence struct { - PubKey []byte `protobuf:"bytes,1,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty"` - Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + Validator Validator `protobuf:"bytes,2,opt,name=validator" json:"validator"` + Height int64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"` + Time int64 `protobuf:"varint,4,opt,name=time,proto3" json:"time,omitempty"` + TotalVotingPower int64 `protobuf:"varint,5,opt,name=total_voting_power,json=totalVotingPower,proto3" json:"total_voting_power,omitempty"` } func (m *Evidence) Reset() { *m = Evidence{} } @@ -1784,11 +1858,18 @@ func (m *Evidence) String() string { return proto.CompactTextString(m func (*Evidence) ProtoMessage() {} func (*Evidence) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{33} } -func (m *Evidence) GetPubKey() []byte { +func (m *Evidence) GetType() string { if m != nil { - return m.PubKey + return m.Type } - return nil + return "" +} + +func (m *Evidence) GetValidator() Validator { + if m != nil { + return m.Validator + } + return Validator{} } func (m *Evidence) GetHeight() int64 { @@ -1798,6 +1879,20 @@ func (m *Evidence) GetHeight() int64 { return 0 } +func (m *Evidence) GetTime() int64 { + if m != nil { + return m.Time + } + return 0 +} + +func (m *Evidence) GetTotalVotingPower() int64 { + if m != nil { + return m.TotalVotingPower + } + return 0 +} + func init() { proto.RegisterType((*Request)(nil), "types.Request") proto.RegisterType((*RequestEcho)(nil), "types.RequestEcho") @@ -1829,9 +1924,9 @@ func init() { proto.RegisterType((*TxSize)(nil), "types.TxSize") proto.RegisterType((*BlockGossip)(nil), "types.BlockGossip") proto.RegisterType((*Header)(nil), "types.Header") - proto.RegisterType((*BlockID)(nil), "types.BlockID") - proto.RegisterType((*PartSetHeader)(nil), "types.PartSetHeader") proto.RegisterType((*Validator)(nil), "types.Validator") + proto.RegisterType((*SigningValidator)(nil), "types.SigningValidator") + proto.RegisterType((*PubKey)(nil), "types.PubKey") proto.RegisterType((*Evidence)(nil), "types.Evidence") } @@ -2240,115 +2335,121 @@ var _ABCIApplication_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("types/types.proto", fileDescriptorTypes) } var fileDescriptorTypes = []byte{ - // 1757 bytes of a gzipped FileDescriptorProto + // 1846 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x58, 0xcd, 0x6e, 0x1b, 0xc9, - 0x11, 0x16, 0xff, 0x39, 0x45, 0x89, 0x94, 0x5a, 0xb2, 0x4d, 0x73, 0x11, 0x58, 0x18, 0x04, 0x5e, - 0x3a, 0xf6, 0x8a, 0x89, 0x36, 0x36, 0x6c, 0x6f, 0xb0, 0x88, 0x29, 0x39, 0x26, 0xb1, 0x49, 0xd6, - 0x19, 0x7b, 0x1d, 0x20, 0x17, 0xa2, 0xc9, 0x69, 0x91, 0x03, 0x73, 0x7e, 0x76, 0xba, 0xa9, 0xa5, - 0x7c, 0xcb, 0x7d, 0xef, 0x39, 0xe7, 0x94, 0x27, 0xc8, 0x2b, 0x04, 0x09, 0xf2, 0x0e, 0x3a, 0xec, - 0x31, 0x2f, 0x91, 0xa0, 0xba, 0x7b, 0x7e, 0x35, 0xb3, 0x58, 0xe4, 0xba, 0x17, 0xb2, 0xab, 0xeb, - 0xab, 0xee, 0xae, 0xee, 0xea, 0xaf, 0x6a, 0x1a, 0x0e, 0xc4, 0x55, 0xc0, 0xf8, 0x48, 0xfe, 0x9e, - 0x04, 0xa1, 0x2f, 0x7c, 0xd2, 0x90, 0xc2, 0xe0, 0x93, 0xa5, 0x23, 0x56, 0x9b, 0xf9, 0xc9, 0xc2, - 0x77, 0x47, 0x4b, 0x7f, 0xe9, 0x8f, 0xa4, 0x76, 0xbe, 0xb9, 0x90, 0x92, 0x14, 0x64, 0x4b, 0x59, - 0x0d, 0x46, 0x29, 0xb8, 0x60, 0x9e, 0xcd, 0x42, 0xd7, 0xf1, 0xc4, 0x48, 0xb8, 0x6b, 0x67, 0xce, - 0x47, 0x0b, 0xdf, 0x75, 0x7d, 0x2f, 0x3d, 0x8d, 0xf9, 0x8f, 0x3a, 0xb4, 0x2c, 0xf6, 0xf5, 0x86, - 0x71, 0x41, 0x86, 0x50, 0x67, 0x8b, 0x95, 0xdf, 0xaf, 0x1e, 0x57, 0x86, 0x9d, 0x53, 0x72, 0xa2, - 0x70, 0x5a, 0xfb, 0x72, 0xb1, 0xf2, 0x27, 0x3b, 0x96, 0x44, 0x90, 0x87, 0xd0, 0xb8, 0x58, 0x6f, - 0xf8, 0xaa, 0x5f, 0x93, 0xd0, 0xc3, 0x2c, 0xf4, 0x37, 0xa8, 0x9a, 0xec, 0x58, 0x0a, 0x83, 0xc3, - 0x3a, 0xde, 0x85, 0xdf, 0xaf, 0x17, 0x0d, 0x3b, 0xf5, 0x2e, 0xe4, 0xb0, 0x88, 0x20, 0x4f, 0x01, - 0x38, 0x13, 0x33, 0x3f, 0x10, 0x8e, 0xef, 0xf5, 0x1b, 0x12, 0x7f, 0x27, 0x8b, 0x7f, 0xc3, 0xc4, - 0x97, 0x52, 0x3d, 0xd9, 0xb1, 0x0c, 0x1e, 0x09, 0x68, 0xe9, 0x78, 0x8e, 0x98, 0x2d, 0x56, 0xd4, - 0xf1, 0xfa, 0xcd, 0x22, 0xcb, 0xa9, 0xe7, 0x88, 0x33, 0x54, 0xa3, 0xa5, 0x13, 0x09, 0xe8, 0xca, - 0xd7, 0x1b, 0x16, 0x5e, 0xf5, 0x5b, 0x45, 0xae, 0xfc, 0x01, 0x55, 0xe8, 0x8a, 0xc4, 0x90, 0xcf, - 0xa0, 0x33, 0x67, 0x4b, 0xc7, 0x9b, 0xcd, 0xd7, 0xfe, 0xe2, 0x7d, 0xbf, 0x2d, 0x4d, 0xfa, 0x59, - 0x93, 0x31, 0x02, 0xc6, 0xa8, 0x9f, 0xec, 0x58, 0x30, 0x8f, 0x25, 0x72, 0x0a, 0xed, 0xc5, 0x8a, - 0x2d, 0xde, 0xcf, 0xc4, 0xb6, 0x6f, 0x48, 0xcb, 0x5b, 0x59, 0xcb, 0x33, 0xd4, 0xbe, 0xdd, 0x4e, - 0x76, 0xac, 0xd6, 0x42, 0x35, 0xd1, 0x2f, 0x9b, 0xad, 0x9d, 0x4b, 0x16, 0xa2, 0xd5, 0x61, 0x91, - 0x5f, 0xe7, 0x4a, 0x2f, 0xed, 0x0c, 0x3b, 0x12, 0xc8, 0x63, 0x30, 0x98, 0x67, 0xeb, 0x85, 0x76, - 0xa4, 0xe1, 0xed, 0xdc, 0x89, 0x7a, 0x76, 0xb4, 0xcc, 0x36, 0xd3, 0x6d, 0x72, 0x02, 0x4d, 0x8c, - 0x12, 0x47, 0xf4, 0x77, 0xa5, 0xcd, 0x51, 0x6e, 0x89, 0x52, 0x37, 0xd9, 0xb1, 0x34, 0x6a, 0xdc, - 0x82, 0xc6, 0x25, 0x5d, 0x6f, 0x98, 0xf9, 0x31, 0x74, 0x52, 0x91, 0x42, 0xfa, 0xd0, 0x72, 0x19, - 0xe7, 0x74, 0xc9, 0xfa, 0x95, 0xe3, 0xca, 0xd0, 0xb0, 0x22, 0xd1, 0xec, 0xc2, 0x6e, 0x3a, 0x4e, - 0x52, 0x86, 0x18, 0x0b, 0x68, 0x78, 0xc9, 0x42, 0x8e, 0x01, 0xa0, 0x0d, 0xb5, 0x68, 0x3e, 0x87, - 0xfd, 0x7c, 0x10, 0x90, 0x7d, 0xa8, 0xbd, 0x67, 0x57, 0x1a, 0x89, 0x4d, 0x72, 0xa4, 0x17, 0x24, - 0xa3, 0xd8, 0xb0, 0xf4, 0xea, 0xc2, 0xd8, 0x36, 0x0e, 0x03, 0xf2, 0x04, 0xe0, 0x92, 0xae, 0x1d, - 0x9b, 0x0a, 0x3f, 0xe4, 0xfd, 0xca, 0x71, 0x6d, 0xd8, 0x39, 0xdd, 0xd7, 0xee, 0xbe, 0x8b, 0x14, - 0xe3, 0xfa, 0x3f, 0xaf, 0xef, 0xed, 0x58, 0x29, 0x24, 0xb9, 0x0f, 0x3d, 0x1a, 0x04, 0x33, 0x2e, - 0xa8, 0x60, 0xb3, 0xf9, 0x95, 0x60, 0x5c, 0xce, 0xb5, 0x6b, 0xed, 0xd1, 0x20, 0x78, 0x83, 0xbd, - 0x63, 0xec, 0x34, 0xed, 0xd8, 0x51, 0x19, 0x45, 0x84, 0x40, 0xdd, 0xa6, 0x82, 0xca, 0xc5, 0xee, - 0x5a, 0xb2, 0x8d, 0x7d, 0x01, 0x15, 0x2b, 0xbd, 0x58, 0xd9, 0x26, 0xb7, 0xa1, 0xb9, 0x62, 0xce, - 0x72, 0x25, 0xe4, 0xed, 0xaa, 0x59, 0x5a, 0x42, 0xcf, 0x82, 0xd0, 0xbf, 0x64, 0xf2, 0x22, 0xb5, - 0x2d, 0x25, 0x98, 0xff, 0xae, 0xc0, 0xc1, 0x8d, 0xc8, 0xc3, 0x71, 0x57, 0x94, 0xaf, 0xa2, 0xb9, - 0xb0, 0x4d, 0x1e, 0xe2, 0xb8, 0xd4, 0x66, 0xa1, 0xbe, 0xe0, 0x7b, 0xda, 0xd7, 0x89, 0xec, 0xd4, - 0x8e, 0x6a, 0x08, 0x79, 0x08, 0x07, 0x74, 0xce, 0x99, 0x27, 0x66, 0xa9, 0x3d, 0xaa, 0x1d, 0xd7, - 0x86, 0x0d, 0x6b, 0x5f, 0x29, 0xde, 0x25, 0x3b, 0x32, 0x81, 0xa3, 0xf9, 0xd5, 0x07, 0xea, 0x09, - 0xc7, 0x63, 0x69, 0x7c, 0x5d, 0xee, 0x69, 0x4f, 0xcf, 0xf3, 0xf2, 0xd2, 0xb1, 0x99, 0xb7, 0x60, - 0x7a, 0xa6, 0xc3, 0xd8, 0x24, 0x19, 0xc9, 0x3c, 0x86, 0x6e, 0xf6, 0x32, 0x90, 0x2e, 0x54, 0xc5, - 0x56, 0xfb, 0x51, 0x15, 0x5b, 0xd3, 0x8c, 0x4f, 0x32, 0x0e, 0xfc, 0x1b, 0x98, 0x07, 0xd0, 0xcb, - 0xc5, 0x78, 0x6a, 0x53, 0x2b, 0xe9, 0x4d, 0x35, 0x7b, 0xb0, 0x97, 0x09, 0x6d, 0xf3, 0xdb, 0x06, - 0xb4, 0x2d, 0xc6, 0x03, 0xdf, 0xe3, 0x8c, 0x3c, 0x05, 0x83, 0x6d, 0x17, 0x4c, 0xf1, 0x51, 0x25, - 0x77, 0xdb, 0x15, 0xe6, 0x65, 0xa4, 0xc7, 0xeb, 0x17, 0x83, 0xc9, 0x83, 0x0c, 0x97, 0x1e, 0xe6, - 0x8d, 0xd2, 0x64, 0xfa, 0x28, 0x4b, 0xa6, 0x47, 0x39, 0x6c, 0x8e, 0x4d, 0x1f, 0x64, 0xd8, 0x34, - 0x3f, 0x70, 0x86, 0x4e, 0x9f, 0x15, 0xd0, 0x69, 0x7e, 0xf9, 0x25, 0x7c, 0xfa, 0xac, 0x80, 0x4f, - 0xfb, 0x37, 0xe6, 0x2a, 0x24, 0xd4, 0x47, 0x59, 0x42, 0xcd, 0xbb, 0x93, 0x63, 0xd4, 0x5f, 0x15, - 0x31, 0xea, 0xdd, 0x9c, 0x4d, 0x29, 0xa5, 0x7e, 0x7a, 0x83, 0x52, 0x6f, 0xe7, 0x4c, 0x0b, 0x38, - 0xf5, 0x59, 0x86, 0x53, 0xa1, 0xd0, 0xb7, 0x12, 0x52, 0x7d, 0x72, 0x93, 0x54, 0xef, 0xe4, 0x8f, - 0xb6, 0x88, 0x55, 0x47, 0x39, 0x56, 0xbd, 0x95, 0x5f, 0x65, 0x29, 0xad, 0x3e, 0xc0, 0xdb, 0x9d, - 0x8b, 0x34, 0x64, 0x02, 0x16, 0x86, 0x7e, 0xa8, 0x79, 0x4f, 0x09, 0xe6, 0x10, 0xf9, 0x26, 0x89, - 0xaf, 0xef, 0xa1, 0x60, 0x19, 0xf4, 0xa9, 0xe8, 0x32, 0xff, 0x52, 0x49, 0x6c, 0x25, 0x0b, 0xa7, - 0xb9, 0xca, 0xd0, 0x5c, 0x95, 0x62, 0xe6, 0x6a, 0x86, 0x99, 0xc9, 0xcf, 0xe0, 0x60, 0x4d, 0xb9, - 0x50, 0xfb, 0x32, 0xcb, 0x90, 0x57, 0x0f, 0x15, 0x6a, 0x43, 0x14, 0x8b, 0x7d, 0x02, 0x87, 0x29, - 0x2c, 0x12, 0xa9, 0x24, 0xaa, 0xba, 0xbc, 0xbc, 0xfb, 0x31, 0xfa, 0x45, 0x10, 0x4c, 0x28, 0x5f, - 0x99, 0xbf, 0x4b, 0xfc, 0x4f, 0x58, 0x9f, 0x40, 0x7d, 0xe1, 0xdb, 0xca, 0xad, 0x3d, 0x4b, 0xb6, - 0x31, 0x13, 0xac, 0xfd, 0xa5, 0x9c, 0xd5, 0xb0, 0xb0, 0x89, 0xa8, 0xf8, 0xa6, 0x18, 0xea, 0x4a, - 0x98, 0x87, 0xc9, 0x70, 0x71, 0xf8, 0x9a, 0x7f, 0xaf, 0x24, 0xfb, 0x11, 0x53, 0xf5, 0xff, 0x37, - 0x01, 0x1e, 0x8d, 0xe3, 0xd9, 0x6c, 0x2b, 0xaf, 0x5b, 0xcd, 0x52, 0x42, 0x94, 0xa6, 0x9a, 0xd2, - 0xc9, 0x6c, 0x9a, 0x6a, 0xc9, 0x3e, 0x25, 0x68, 0x8a, 0xf7, 0x2f, 0xe4, 0x3d, 0xd8, 0xb5, 0x94, - 0x90, 0xe2, 0x2e, 0x23, 0xc3, 0x5d, 0x47, 0x40, 0x6e, 0xde, 0x10, 0xf3, 0xbf, 0x15, 0x64, 0xbf, - 0x4c, 0xf4, 0x17, 0xfa, 0x13, 0x1d, 0x71, 0x35, 0x95, 0x8e, 0x7e, 0x98, 0x8f, 0x3f, 0x01, 0x58, - 0x52, 0x3e, 0xfb, 0x86, 0x7a, 0x82, 0xd9, 0xda, 0x51, 0x63, 0x49, 0xf9, 0x1f, 0x65, 0x07, 0xb9, - 0x0b, 0x6d, 0x54, 0x6f, 0x38, 0xb3, 0xa5, 0xc7, 0x35, 0xab, 0xb5, 0xa4, 0xfc, 0x2b, 0xce, 0x6c, - 0xf2, 0x1c, 0xea, 0x82, 0x2e, 0x79, 0xbf, 0x25, 0x13, 0x43, 0xf7, 0x44, 0x15, 0xa4, 0x27, 0x5f, - 0xbc, 0x7b, 0x4d, 0x9d, 0x70, 0x7c, 0x1b, 0xf3, 0xc2, 0x7f, 0xae, 0xef, 0x75, 0x11, 0xf3, 0xc8, - 0x77, 0x1d, 0xc1, 0xdc, 0x40, 0x5c, 0x59, 0xd2, 0x86, 0x0c, 0xa1, 0x76, 0xc1, 0x98, 0x66, 0x88, - 0xfd, 0xd8, 0x74, 0xfa, 0xe4, 0x97, 0xd2, 0x58, 0x25, 0x15, 0x84, 0x98, 0x7f, 0xae, 0x26, 0xa7, - 0x9c, 0x24, 0x89, 0x1f, 0xd7, 0x1e, 0xfc, 0xad, 0x82, 0x79, 0x32, 0x4b, 0x49, 0xe4, 0x0c, 0x0e, - 0xe2, 0xec, 0x3c, 0xdb, 0x04, 0x36, 0xc5, 0xda, 0xe5, 0xfb, 0x0b, 0x9f, 0xfd, 0xd8, 0xe0, 0x2b, - 0x85, 0x27, 0xbf, 0x87, 0x3b, 0x0b, 0x1c, 0xd5, 0xe3, 0x1b, 0x3e, 0x0b, 0x68, 0x48, 0xdd, 0x78, - 0xa8, 0x6a, 0x86, 0x82, 0xcf, 0x22, 0xd4, 0x6b, 0x04, 0x71, 0xeb, 0xd6, 0x22, 0xd3, 0xa1, 0xc7, - 0x33, 0x7f, 0x8a, 0x29, 0x3f, 0x4d, 0x83, 0x45, 0xa7, 0x62, 0xfe, 0xb5, 0x02, 0xbd, 0xdc, 0x80, - 0x64, 0x04, 0xa0, 0x58, 0x84, 0x3b, 0x1f, 0x98, 0x4e, 0xcf, 0x91, 0x1f, 0xd2, 0xe1, 0x37, 0xce, - 0x07, 0x66, 0x19, 0xf3, 0xa8, 0x49, 0xee, 0x43, 0x4b, 0x6c, 0x15, 0x3a, 0x5b, 0x02, 0xbd, 0xdd, - 0x4a, 0x68, 0x53, 0xc8, 0x7f, 0xf2, 0x18, 0x76, 0xd5, 0xc0, 0x4b, 0x9f, 0x73, 0x27, 0xd0, 0x89, - 0x99, 0xa4, 0x87, 0x7e, 0x25, 0x35, 0x56, 0x67, 0x9e, 0x08, 0xe6, 0x9f, 0xc0, 0x88, 0xa7, 0x25, - 0x1f, 0x81, 0xe1, 0xd2, 0xad, 0xae, 0x0f, 0x71, 0x6d, 0x0d, 0xab, 0xed, 0xd2, 0xad, 0x2c, 0x0d, - 0xc9, 0x1d, 0x68, 0xa1, 0x52, 0x6c, 0xd5, 0x9e, 0x35, 0xac, 0xa6, 0x4b, 0xb7, 0x6f, 0xb7, 0xb1, - 0x62, 0x49, 0x79, 0x54, 0xfc, 0xb9, 0x74, 0xfb, 0x8a, 0x72, 0xf3, 0x73, 0x68, 0xaa, 0x45, 0xfe, - 0xa0, 0x81, 0xd1, 0xbe, 0x9a, 0xb1, 0xff, 0x35, 0x74, 0x52, 0xeb, 0x26, 0xbf, 0x80, 0x5b, 0xca, - 0xc3, 0x80, 0x86, 0x42, 0xee, 0x48, 0x66, 0x40, 0x22, 0x95, 0xaf, 0x69, 0x28, 0x70, 0x4a, 0x55, - 0xce, 0xfe, 0xab, 0x0a, 0x4d, 0x55, 0x2a, 0x92, 0xfb, 0x98, 0x76, 0xa9, 0xe3, 0xcd, 0x1c, 0x5b, - 0x65, 0x88, 0x71, 0xe7, 0xbb, 0xeb, 0x7b, 0x2d, 0xc9, 0xa6, 0xd3, 0x73, 0xcc, 0xb4, 0xd8, 0xb0, - 0x53, 0xc4, 0x55, 0xcd, 0x54, 0xb2, 0x04, 0xea, 0xc2, 0x71, 0x99, 0x76, 0x51, 0xb6, 0x71, 0xe5, - 0xde, 0xc6, 0x95, 0x5b, 0x52, 0x57, 0x5b, 0xe2, 0x6d, 0x5c, 0xdc, 0x92, 0x57, 0xb0, 0x97, 0x4a, - 0x18, 0x8e, 0xad, 0x0b, 0x99, 0x6e, 0xfa, 0x34, 0xa6, 0xe7, 0xe3, 0x43, 0x0c, 0xd7, 0xef, 0xae, - 0xef, 0x75, 0x7e, 0x1b, 0xa5, 0x90, 0xe9, 0xb9, 0xd5, 0x89, 0xf3, 0xc9, 0xd4, 0x26, 0x43, 0x90, - 0xe9, 0x65, 0xa6, 0x52, 0xac, 0x4a, 0x3b, 0x8a, 0x91, 0xbb, 0xd8, 0xaf, 0x73, 0x30, 0x56, 0xca, - 0x1f, 0x81, 0x81, 0x41, 0xa7, 0x20, 0x8a, 0xa0, 0xdb, 0xd8, 0x21, 0x95, 0x1f, 0x43, 0x2f, 0x29, - 0x71, 0x15, 0x44, 0xb1, 0x75, 0x37, 0xe9, 0x96, 0xc0, 0xbb, 0xd0, 0x8e, 0xd3, 0x9b, 0x21, 0x11, - 0x2d, 0xaa, 0xb3, 0xda, 0x97, 0xd0, 0xd2, 0x4b, 0x2c, 0xac, 0xd4, 0x7f, 0x0e, 0x0d, 0x3c, 0x97, - 0xe8, 0x42, 0x45, 0x25, 0x94, 0x3c, 0x0f, 0x26, 0x32, 0xf5, 0xba, 0x02, 0x9a, 0xcf, 0x60, 0x2f, - 0xa3, 0xc5, 0x4c, 0x22, 0x7c, 0x41, 0xd7, 0xfa, 0x40, 0x95, 0x10, 0x4f, 0x56, 0x4d, 0x26, 0x33, - 0x9f, 0x83, 0x11, 0x5f, 0x7a, 0x3c, 0x85, 0x60, 0x33, 0x9f, 0x45, 0xdf, 0x54, 0xbb, 0x56, 0x33, - 0xd8, 0xcc, 0xbf, 0x50, 0xf9, 0x2a, 0xf0, 0xbf, 0xd1, 0xdf, 0x0e, 0x35, 0x4b, 0x09, 0xe6, 0x67, - 0xd0, 0x8e, 0xaa, 0xfa, 0x72, 0xd3, 0x92, 0x28, 0x38, 0xfd, 0xb6, 0x01, 0xbd, 0x17, 0xe3, 0xb3, - 0xe9, 0x8b, 0x20, 0x58, 0x3b, 0x0b, 0x2a, 0x33, 0xfb, 0x08, 0xea, 0xb2, 0x76, 0x29, 0x78, 0x7c, - 0x18, 0x14, 0x15, 0xd1, 0xe4, 0x14, 0x1a, 0xb2, 0x84, 0x21, 0x45, 0x6f, 0x10, 0x83, 0xc2, 0x5a, - 0x1a, 0x27, 0x51, 0x45, 0xce, 0xcd, 0xa7, 0x88, 0x41, 0x51, 0x41, 0x4d, 0x3e, 0x07, 0x23, 0x29, - 0x3e, 0xca, 0x1e, 0x24, 0x06, 0xa5, 0xa5, 0x35, 0xda, 0x27, 0x79, 0xa8, 0xec, 0xf3, 0x7d, 0x50, - 0x5a, 0x83, 0x92, 0xa7, 0xd0, 0x8a, 0x32, 0x79, 0xf1, 0x93, 0xc1, 0xa0, 0xa4, 0xec, 0xc5, 0xed, - 0x51, 0x15, 0x4d, 0xd1, 0xbb, 0xc6, 0xa0, 0xb0, 0x36, 0x27, 0x8f, 0xa1, 0xa9, 0x89, 0xb8, 0xf0, - 0xe3, 0x7f, 0x50, 0x5c, 0xbc, 0xa2, 0x93, 0xc9, 0xb7, 0x75, 0xd9, 0xdb, 0xcb, 0xa0, 0xf4, 0x23, - 0x82, 0xbc, 0x00, 0x48, 0x7d, 0xc0, 0x96, 0x3e, 0xaa, 0x0c, 0xca, 0x3f, 0x0e, 0x08, 0x86, 0x63, - 0xfc, 0xc1, 0x57, 0xfc, 0xd8, 0x31, 0x28, 0xab, 0xd7, 0xe7, 0x4d, 0xf9, 0x20, 0xf6, 0xe9, 0xff, - 0x02, 0x00, 0x00, 0xff, 0xff, 0x46, 0xbe, 0x48, 0x9c, 0x8c, 0x13, 0x00, 0x00, + 0x11, 0x16, 0xff, 0x39, 0xa5, 0x1f, 0xd2, 0x2d, 0xdb, 0xa2, 0xb9, 0x08, 0x6c, 0x0c, 0x02, 0xaf, + 0x9c, 0xd5, 0x8a, 0x89, 0x76, 0x6d, 0xd8, 0xbb, 0xc9, 0x22, 0x92, 0xd6, 0x59, 0x0a, 0x9b, 0x1f, + 0x65, 0xec, 0x75, 0x80, 0x5c, 0x88, 0x26, 0xa7, 0x45, 0x0e, 0x4c, 0xce, 0xcc, 0x4e, 0x37, 0xb5, + 0x94, 0x6f, 0xb9, 0x2f, 0x72, 0xcd, 0x39, 0x2f, 0x90, 0x43, 0x80, 0xbc, 0x42, 0x90, 0x97, 0x88, + 0x0f, 0x49, 0x4e, 0x79, 0x89, 0x04, 0x55, 0xdd, 0xf3, 0xab, 0xa1, 0xe1, 0x38, 0xc7, 0xbd, 0x48, + 0x5d, 0x5d, 0x55, 0x3d, 0x5d, 0xc5, 0xaa, 0xaf, 0xaa, 0x1a, 0x6e, 0xa8, 0xab, 0x50, 0xc8, 0x01, + 0xfd, 0x3d, 0x0c, 0xa3, 0x40, 0x05, 0xac, 0x41, 0x44, 0xff, 0xc3, 0xa9, 0xa7, 0x66, 0xcb, 0xf1, + 0xe1, 0x24, 0x58, 0x0c, 0xa6, 0xc1, 0x34, 0x18, 0x10, 0x77, 0xbc, 0xbc, 0x20, 0x8a, 0x08, 0x5a, + 0x69, 0xad, 0xfe, 0x20, 0x23, 0xae, 0x84, 0xef, 0x8a, 0x68, 0xe1, 0xf9, 0x6a, 0xa0, 0x16, 0x73, + 0x6f, 0x2c, 0x07, 0x93, 0x60, 0xb1, 0x08, 0xfc, 0xec, 0x67, 0xec, 0xbf, 0xd6, 0xa1, 0xe5, 0x88, + 0xaf, 0x97, 0x42, 0x2a, 0xb6, 0x0f, 0x75, 0x31, 0x99, 0x05, 0xbd, 0xea, 0xbd, 0xca, 0xfe, 0xe6, + 0x11, 0x3b, 0xd4, 0x72, 0x86, 0xfb, 0x74, 0x32, 0x0b, 0x86, 0x1b, 0x0e, 0x49, 0xb0, 0x0f, 0xa0, + 0x71, 0x31, 0x5f, 0xca, 0x59, 0xaf, 0x46, 0xa2, 0xbb, 0x79, 0xd1, 0x9f, 0x21, 0x6b, 0xb8, 0xe1, + 0x68, 0x19, 0x3c, 0xd6, 0xf3, 0x2f, 0x82, 0x5e, 0xbd, 0xec, 0xd8, 0x33, 0xff, 0x82, 0x8e, 0x45, + 0x09, 0xf6, 0x18, 0x40, 0x0a, 0x35, 0x0a, 0x42, 0xe5, 0x05, 0x7e, 0xaf, 0x41, 0xf2, 0x7b, 0x79, + 0xf9, 0x67, 0x42, 0xfd, 0x8a, 0xd8, 0xc3, 0x0d, 0xc7, 0x92, 0x31, 0x81, 0x9a, 0x9e, 0xef, 0xa9, + 0xd1, 0x64, 0xc6, 0x3d, 0xbf, 0xd7, 0x2c, 0xd3, 0x3c, 0xf3, 0x3d, 0x75, 0x8a, 0x6c, 0xd4, 0xf4, + 0x62, 0x02, 0x4d, 0xf9, 0x7a, 0x29, 0xa2, 0xab, 0x5e, 0xab, 0xcc, 0x94, 0x5f, 0x23, 0x0b, 0x4d, + 0x21, 0x19, 0xf6, 0x29, 0x6c, 0x8e, 0xc5, 0xd4, 0xf3, 0x47, 0xe3, 0x79, 0x30, 0x79, 0xd9, 0x6b, + 0x93, 0x4a, 0x2f, 0xaf, 0x72, 0x82, 0x02, 0x27, 0xc8, 0x1f, 0x6e, 0x38, 0x30, 0x4e, 0x28, 0x76, + 0x04, 0xed, 0xc9, 0x4c, 0x4c, 0x5e, 0x8e, 0xd4, 0xaa, 0x67, 0x91, 0xe6, 0xad, 0xbc, 0xe6, 0x29, + 0x72, 0x9f, 0xaf, 0x86, 0x1b, 0x4e, 0x6b, 0xa2, 0x97, 0x68, 0x97, 0x2b, 0xe6, 0xde, 0xa5, 0x88, + 0x50, 0x6b, 0xb7, 0xcc, 0xae, 0xcf, 0x35, 0x9f, 0xf4, 0x2c, 0x37, 0x26, 0xd8, 0x43, 0xb0, 0x84, + 0xef, 0x9a, 0x8b, 0x6e, 0x92, 0xe2, 0xed, 0xc2, 0x2f, 0xea, 0xbb, 0xf1, 0x35, 0xdb, 0xc2, 0xac, + 0xd9, 0x21, 0x34, 0x31, 0x4a, 0x3c, 0xd5, 0xdb, 0x22, 0x9d, 0x9b, 0x85, 0x2b, 0x12, 0x6f, 0xb8, + 0xe1, 0x18, 0xa9, 0x93, 0x16, 0x34, 0x2e, 0xf9, 0x7c, 0x29, 0xec, 0xf7, 0x61, 0x33, 0x13, 0x29, + 0xac, 0x07, 0xad, 0x85, 0x90, 0x92, 0x4f, 0x45, 0xaf, 0x72, 0xaf, 0xb2, 0x6f, 0x39, 0x31, 0x69, + 0xef, 0xc0, 0x56, 0x36, 0x4e, 0x32, 0x8a, 0x18, 0x0b, 0xa8, 0x78, 0x29, 0x22, 0x89, 0x01, 0x60, + 0x14, 0x0d, 0x69, 0x7f, 0x02, 0xdd, 0x62, 0x10, 0xb0, 0x2e, 0xd4, 0x5e, 0x8a, 0x2b, 0x23, 0x89, + 0x4b, 0x76, 0xd3, 0x5c, 0x88, 0xa2, 0xd8, 0x72, 0xcc, 0xed, 0xfe, 0x55, 0x49, 0x94, 0x93, 0x38, + 0x60, 0x0c, 0xea, 0xca, 0x5b, 0xe8, 0x0b, 0xd6, 0x1c, 0x5a, 0xb3, 0x3b, 0xf8, 0x23, 0x71, 0xcf, + 0x1f, 0x79, 0xae, 0x39, 0xa1, 0x45, 0xf4, 0x99, 0xcb, 0x8e, 0xa1, 0x3b, 0x09, 0x7c, 0x29, 0x7c, + 0xb9, 0x94, 0xa3, 0x90, 0x47, 0x7c, 0x21, 0x4d, 0xfc, 0xc7, 0x8e, 0x3d, 0x8d, 0xd9, 0xe7, 0xc4, + 0x75, 0x3a, 0x93, 0xfc, 0x06, 0x7b, 0x04, 0x70, 0xc9, 0xe7, 0x9e, 0xcb, 0x55, 0x10, 0xc9, 0x5e, + 0xfd, 0x5e, 0x6d, 0x7f, 0xf3, 0xa8, 0x6b, 0x94, 0x5f, 0xc4, 0x8c, 0x93, 0xfa, 0xdf, 0x5e, 0xdf, + 0xdd, 0x70, 0x32, 0x92, 0xec, 0x3e, 0x74, 0x78, 0x18, 0x8e, 0xa4, 0xe2, 0x4a, 0x8c, 0xc6, 0x57, + 0x4a, 0x48, 0xca, 0x8e, 0x2d, 0x67, 0x9b, 0x87, 0xe1, 0x33, 0xdc, 0x3d, 0xc1, 0x4d, 0xdb, 0x4d, + 0x7c, 0x4b, 0x81, 0x8b, 0x16, 0xba, 0x5c, 0x71, 0xb2, 0x70, 0xcb, 0xa1, 0x35, 0xee, 0x85, 0x5c, + 0xcd, 0x8c, 0x75, 0xb4, 0x66, 0xb7, 0xa1, 0x39, 0x13, 0xde, 0x74, 0xa6, 0xc8, 0xa0, 0x9a, 0x63, + 0x28, 0x74, 0x66, 0x18, 0x05, 0x97, 0x82, 0x72, 0xb7, 0xed, 0x68, 0xc2, 0xfe, 0x7b, 0x05, 0x6e, + 0x5c, 0x0b, 0x76, 0x3c, 0x77, 0xc6, 0xe5, 0x2c, 0xfe, 0x16, 0xae, 0xd9, 0x07, 0x78, 0x2e, 0x77, + 0x45, 0x64, 0x30, 0x65, 0xdb, 0xd8, 0x3a, 0xa4, 0x4d, 0x63, 0xa8, 0x11, 0x61, 0x3f, 0xc9, 0x39, + 0xa7, 0x46, 0xce, 0x89, 0x63, 0xfd, 0x99, 0x37, 0xf5, 0x3d, 0x7f, 0xfa, 0x26, 0x1f, 0x0d, 0xe1, + 0xe6, 0xf8, 0xea, 0x15, 0xf7, 0x95, 0xe7, 0x8b, 0xd1, 0x35, 0x2f, 0x77, 0xcc, 0x41, 0x4f, 0x2f, + 0x3d, 0x57, 0xf8, 0x13, 0x61, 0x0e, 0xd8, 0x4d, 0x54, 0x92, 0xa3, 0xa5, 0x7d, 0x0f, 0x76, 0xf2, + 0x19, 0xc9, 0x76, 0xa0, 0xaa, 0x56, 0xc6, 0xb2, 0xaa, 0x5a, 0xd9, 0x76, 0x12, 0x4d, 0x49, 0xf6, + 0x5d, 0x93, 0x79, 0x00, 0x9d, 0x42, 0xa2, 0x65, 0xdc, 0x5c, 0xc9, 0xba, 0xd9, 0xee, 0xc0, 0x76, + 0x2e, 0xbf, 0xec, 0x6f, 0x1b, 0xd0, 0x76, 0x84, 0x0c, 0x31, 0x7c, 0xd8, 0x63, 0xb0, 0xc4, 0x6a, + 0x22, 0x34, 0x28, 0x56, 0x0a, 0x90, 0xa3, 0x65, 0x9e, 0xc6, 0x7c, 0xc4, 0x80, 0x44, 0x98, 0x3d, + 0xc8, 0x01, 0xfa, 0x6e, 0x51, 0x29, 0x8b, 0xe8, 0x07, 0x79, 0x44, 0xbf, 0x59, 0x90, 0x2d, 0x40, + 0xfa, 0x83, 0x1c, 0xa4, 0x17, 0x0f, 0xce, 0x61, 0xfa, 0x93, 0x12, 0x4c, 0x2f, 0x5e, 0x7f, 0x0d, + 0xa8, 0x3f, 0x29, 0x01, 0xf5, 0xde, 0xb5, 0x6f, 0x95, 0xa2, 0xfa, 0x41, 0x1e, 0xd5, 0x8b, 0xe6, + 0x14, 0x60, 0xfd, 0xc7, 0x65, 0xb0, 0x7e, 0xa7, 0xa0, 0xb3, 0x16, 0xd7, 0x3f, 0xba, 0x86, 0xeb, + 0xb7, 0x0b, 0xaa, 0x25, 0xc0, 0xfe, 0x24, 0x07, 0xec, 0x50, 0x6a, 0xdb, 0x1a, 0x64, 0x7f, 0x74, + 0x1d, 0xd9, 0xf7, 0x8a, 0x3f, 0x6d, 0x19, 0xb4, 0x0f, 0x0a, 0xd0, 0x7e, 0xab, 0x78, 0xcb, 0xb5, + 0xd8, 0xfe, 0x00, 0xf3, 0xbd, 0x10, 0x69, 0x88, 0x0d, 0x22, 0x8a, 0x82, 0xc8, 0x80, 0xaf, 0x26, + 0xec, 0x7d, 0x44, 0xa0, 0x34, 0xbe, 0xde, 0x50, 0x07, 0x28, 0xe8, 0x33, 0xd1, 0x65, 0xff, 0xa1, + 0x92, 0xea, 0x52, 0x29, 0xc8, 0xa2, 0x97, 0x65, 0xd0, 0x2b, 0x53, 0x1e, 0xaa, 0xb9, 0xf2, 0xc0, + 0x7e, 0x00, 0x37, 0xe6, 0x5c, 0x2a, 0xed, 0x97, 0x51, 0x0e, 0xce, 0x3a, 0xc8, 0xd0, 0x0e, 0xd1, + 0xb8, 0xf6, 0x21, 0xec, 0x66, 0x64, 0x11, 0x5a, 0x09, 0xba, 0xea, 0x94, 0xbc, 0xdd, 0x44, 0xfa, + 0x38, 0x0c, 0x87, 0x5c, 0xce, 0xec, 0x5f, 0xa4, 0xf6, 0xa7, 0xa5, 0x87, 0x41, 0x7d, 0x12, 0xb8, + 0xda, 0xac, 0x6d, 0x87, 0xd6, 0x58, 0x8e, 0xe6, 0xc1, 0x94, 0xbe, 0x6a, 0x39, 0xb8, 0x44, 0xa9, + 0x24, 0x53, 0x2c, 0x9d, 0x12, 0xf6, 0xef, 0x2b, 0xe9, 0x79, 0x69, 0x35, 0x2a, 0x2b, 0x2f, 0x95, + 0xff, 0xa7, 0xbc, 0x54, 0xdf, 0xb6, 0xbc, 0xd8, 0x7f, 0xa9, 0xa4, 0xbf, 0x45, 0x52, 0x38, 0xde, + 0xcd, 0x38, 0x0c, 0x0b, 0xcf, 0x77, 0xc5, 0x8a, 0x52, 0xbd, 0xe6, 0x68, 0x22, 0xae, 0xd3, 0x4d, + 0x72, 0x70, 0xbe, 0x4e, 0xb7, 0x68, 0x4f, 0x13, 0xa6, 0xe0, 0x04, 0x17, 0x94, 0x83, 0x5b, 0x8e, + 0x26, 0x32, 0xb8, 0x69, 0xe5, 0x70, 0xf3, 0x1c, 0xd8, 0xf5, 0xec, 0x64, 0x9f, 0x40, 0x5d, 0xf1, + 0x29, 0x3a, 0x0f, 0xed, 0xdf, 0x39, 0xd4, 0x5d, 0xef, 0xe1, 0x97, 0x2f, 0xce, 0xb9, 0x17, 0x9d, + 0xdc, 0x46, 0xeb, 0xff, 0xfd, 0xfa, 0xee, 0x0e, 0xca, 0x1c, 0x04, 0x0b, 0x4f, 0x89, 0x45, 0xa8, + 0xae, 0x1c, 0xd2, 0xb1, 0xff, 0x53, 0x41, 0xd4, 0xce, 0x65, 0x6d, 0xa9, 0x2f, 0xe2, 0xd0, 0xac, + 0x66, 0x0a, 0xeb, 0xdb, 0xf9, 0xe7, 0x7b, 0x00, 0x53, 0x2e, 0x47, 0xdf, 0x70, 0x5f, 0x09, 0xd7, + 0x38, 0xc9, 0x9a, 0x72, 0xf9, 0x1b, 0xda, 0xc0, 0xfe, 0x03, 0xd9, 0x4b, 0x29, 0x5c, 0xf2, 0x56, + 0xcd, 0x69, 0x4d, 0xb9, 0xfc, 0x4a, 0x0a, 0x37, 0xb1, 0xab, 0xf5, 0xbf, 0xdb, 0xc5, 0xf6, 0xa1, + 0x76, 0x21, 0x84, 0x41, 0xb6, 0x6e, 0xa2, 0x7a, 0xf6, 0xe8, 0x63, 0x52, 0xd6, 0x21, 0x81, 0x22, + 0xf6, 0xef, 0xaa, 0x69, 0x70, 0xa6, 0xc5, 0xed, 0xbb, 0xe5, 0x83, 0x7f, 0x52, 0xb7, 0x98, 0x87, + 0x52, 0x76, 0x0a, 0x37, 0x92, 0x94, 0x19, 0x2d, 0x43, 0x97, 0x63, 0x17, 0x56, 0x79, 0x63, 0x8e, + 0x75, 0x13, 0x85, 0xaf, 0xb4, 0x3c, 0xfb, 0x25, 0xec, 0x15, 0x92, 0x3c, 0x39, 0xaa, 0xfa, 0xc6, + 0x5c, 0xbf, 0x95, 0xcf, 0xf5, 0xf8, 0xbc, 0xd8, 0x1f, 0xb5, 0x77, 0x88, 0xf5, 0xef, 0x63, 0x9b, + 0x93, 0x85, 0xfe, 0xb2, 0x5f, 0xd4, 0xfe, 0x63, 0x05, 0x3a, 0x85, 0xcb, 0xb0, 0x01, 0x80, 0x46, + 0x4e, 0xe9, 0xbd, 0x12, 0x06, 0xa4, 0x62, 0x1f, 0x90, 0xb3, 0x9e, 0x79, 0xaf, 0x84, 0x63, 0x8d, + 0xe3, 0x25, 0xbb, 0x0f, 0x2d, 0xb5, 0xd2, 0xd2, 0xf9, 0x46, 0xf0, 0xf9, 0x8a, 0x44, 0x9b, 0x8a, + 0xfe, 0xb3, 0x87, 0xb0, 0xa5, 0x0f, 0x9e, 0x06, 0x52, 0x7a, 0xa1, 0x69, 0x46, 0x58, 0xf6, 0xe8, + 0x2f, 0x88, 0xe3, 0x6c, 0x8e, 0x53, 0xc2, 0xfe, 0x2d, 0x58, 0xc9, 0x67, 0xd9, 0x7b, 0x60, 0x2d, + 0xf8, 0xca, 0x74, 0xc9, 0x78, 0xb7, 0x86, 0xd3, 0x5e, 0xf0, 0x15, 0x35, 0xc8, 0x6c, 0x0f, 0x5a, + 0xc8, 0x54, 0x2b, 0xed, 0xef, 0x86, 0xd3, 0x5c, 0xf0, 0xd5, 0xf3, 0x55, 0xc2, 0x98, 0x72, 0x19, + 0xb7, 0xc0, 0x0b, 0xbe, 0xfa, 0x82, 0x4b, 0xfb, 0x33, 0x68, 0xea, 0x4b, 0xbe, 0xd5, 0xc1, 0xa8, + 0x5f, 0xcd, 0xe9, 0xff, 0x14, 0x36, 0x33, 0xf7, 0x66, 0x3f, 0x82, 0x5b, 0xda, 0xc2, 0x90, 0x47, + 0x8a, 0x3c, 0x92, 0x3b, 0x90, 0x11, 0xf3, 0x9c, 0x47, 0x0a, 0x3f, 0xa9, 0x9b, 0xfa, 0x3f, 0x57, + 0xa1, 0xa9, 0x1b, 0x66, 0x76, 0x3f, 0x33, 0x9d, 0x50, 0x55, 0x3c, 0xd9, 0xfc, 0xc7, 0xeb, 0xbb, + 0x2d, 0x2a, 0x20, 0x67, 0x9f, 0xa7, 0xa3, 0x4a, 0x0a, 0x98, 0xd5, 0x5c, 0x3f, 0x1f, 0x4f, 0x3c, + 0xb5, 0xcc, 0xc4, 0xb3, 0x07, 0x2d, 0x7f, 0xb9, 0x20, 0x97, 0xd4, 0xb5, 0x4b, 0xfc, 0xe5, 0x02, + 0x5d, 0xf2, 0x1e, 0x58, 0x2a, 0x50, 0x7c, 0x4e, 0x2c, 0x9d, 0xa4, 0x6d, 0xda, 0x40, 0xe6, 0x7d, + 0xe8, 0x64, 0xab, 0x2d, 0x56, 0x4f, 0x0d, 0xee, 0xdb, 0x69, 0xad, 0xc5, 0x09, 0xe0, 0x7d, 0xe8, + 0xa4, 0x85, 0x46, 0xcb, 0x69, 0xc0, 0xdf, 0x49, 0xb7, 0x49, 0xf0, 0x0e, 0xb4, 0x93, 0x3a, 0xac, + 0xc1, 0xbf, 0xc5, 0x75, 0xf9, 0xc5, 0xc1, 0x39, 0x8c, 0x82, 0x30, 0x90, 0x22, 0x32, 0x0d, 0xd6, + 0xba, 0x84, 0x4b, 0xe4, 0x6c, 0x0f, 0xac, 0x84, 0x89, 0x4d, 0x03, 0x77, 0xdd, 0x48, 0x48, 0x69, + 0xfa, 0xf3, 0x98, 0x64, 0x07, 0xd0, 0x0a, 0x97, 0xe3, 0x11, 0xd6, 0xa6, 0x7c, 0x60, 0x9e, 0x2f, + 0xc7, 0x5f, 0x8a, 0xab, 0x78, 0x42, 0x09, 0x89, 0xa2, 0xea, 0x14, 0x7c, 0x23, 0x22, 0xe3, 0x3f, + 0x4d, 0xd8, 0x0a, 0xba, 0xc5, 0xf1, 0x84, 0x7d, 0x0c, 0x56, 0x62, 0x5f, 0x21, 0x41, 0x8a, 0x77, + 0x4e, 0x05, 0xb1, 0x85, 0x91, 0xde, 0xd4, 0x17, 0xee, 0x28, 0xf5, 0x2d, 0xdd, 0xab, 0xed, 0x74, + 0x34, 0xe3, 0xe7, 0xb1, 0x73, 0xed, 0x1f, 0x42, 0x53, 0xdf, 0x91, 0x7e, 0xd4, 0xab, 0x30, 0xee, + 0xaf, 0x68, 0x5d, 0x9a, 0xc9, 0x7f, 0xaa, 0x40, 0x3b, 0x1e, 0x7f, 0x4a, 0x95, 0x72, 0x97, 0xae, + 0xbe, 0xed, 0xa5, 0xd7, 0xcd, 0x8e, 0x71, 0xac, 0xd5, 0x33, 0xb1, 0x76, 0x00, 0x4c, 0x87, 0xd4, + 0x65, 0xa0, 0x3c, 0x7f, 0x3a, 0xd2, 0xde, 0xd4, 0xb1, 0xd5, 0x25, 0xce, 0x0b, 0x62, 0x9c, 0xe3, + 0xfe, 0xd1, 0xb7, 0x0d, 0xe8, 0x1c, 0x9f, 0x9c, 0x9e, 0x1d, 0x87, 0xe1, 0xdc, 0x9b, 0x70, 0xea, + 0xba, 0x06, 0x50, 0xa7, 0xbe, 0xb2, 0xe4, 0x75, 0xaa, 0x5f, 0x36, 0xe0, 0xb0, 0x23, 0x68, 0x50, + 0x7b, 0xc9, 0xca, 0x1e, 0xa9, 0xfa, 0xa5, 0x73, 0x0e, 0x7e, 0x44, 0x37, 0xa0, 0xd7, 0xdf, 0xaa, + 0xfa, 0x65, 0xc3, 0x0e, 0xfb, 0x0c, 0xac, 0xb4, 0x31, 0x5c, 0xf7, 0x62, 0xd5, 0x5f, 0x3b, 0xf6, + 0xa0, 0x7e, 0x5a, 0x6b, 0xd7, 0xbd, 0xef, 0xf4, 0xd7, 0xce, 0x07, 0xec, 0x31, 0xb4, 0xe2, 0x6e, + 0xa5, 0xfc, 0x4d, 0xa9, 0xbf, 0x66, 0x24, 0x41, 0xf7, 0xe8, 0x8e, 0xaf, 0xec, 0xe1, 0xab, 0x5f, + 0x3a, 0x37, 0xb1, 0x87, 0xd0, 0x34, 0x05, 0xa3, 0xf4, 0x75, 0xa8, 0x5f, 0x3e, 0x58, 0xa0, 0x91, + 0x69, 0xb7, 0xbb, 0xee, 0x71, 0xae, 0xbf, 0x76, 0xc0, 0x63, 0xc7, 0x00, 0x99, 0x2e, 0x6f, 0xed, + 0xab, 0x5b, 0x7f, 0xfd, 0xe0, 0xc6, 0x3e, 0x85, 0x76, 0x3a, 0x8c, 0x97, 0xbf, 0x86, 0xf5, 0xd7, + 0xcd, 0x52, 0xe3, 0x26, 0xbd, 0x98, 0x7e, 0xf4, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe5, 0xf3, + 0xb2, 0x34, 0xad, 0x15, 0x00, 0x00, } diff --git a/types/types.proto b/types/types.proto index 363ceabb..b4f4b2aa 100644 --- a/types/types.proto +++ b/types/types.proto @@ -47,8 +47,11 @@ message RequestSetOption { } message RequestInitChain { - repeated Validator validators = 1 [(gogoproto.nullable)=false]; - bytes app_state_bytes = 2; + int64 time = 1; + string chain_id = 2; + ConsensusParams consensus_params = 3; + repeated Validator validators = 4 [(gogoproto.nullable)=false]; + bytes app_state_bytes = 5; } message RequestQuery { @@ -61,7 +64,7 @@ message RequestQuery { message RequestBeginBlock { bytes hash = 1; Header header = 2 [(gogoproto.nullable)=false]; - repeated int32 absent_validators = 3; + repeated SigningValidator validators = 3 [(gogoproto.nullable)=false]; repeated Evidence byzantine_validators = 4 [(gogoproto.nullable)=false]; } @@ -128,6 +131,8 @@ message ResponseSetOption { } message ResponseInitChain { + ConsensusParams consensus_params = 1; + repeated Validator validators = 2 [(gogoproto.nullable)=false]; } message ResponseQuery { @@ -143,6 +148,7 @@ message ResponseQuery { } message ResponseBeginBlock { + repeated common.KVPair tags = 1 [(gogoproto.nullable)=false, (gogoproto.jsontag)="tags,omitempty"]; } message ResponseCheckTx { @@ -170,6 +176,7 @@ message ResponseDeliverTx { message ResponseEndBlock { repeated Validator validator_updates = 1 [(gogoproto.nullable)=false]; ConsensusParams consensus_param_updates = 2; + repeated common.KVPair tags = 3 [(gogoproto.nullable)=false, (gogoproto.jsontag)="tags,omitempty"]; } message ResponseCommit { @@ -211,36 +218,50 @@ message BlockGossip { //---------------------------------------- // Blockchain Types +// just the minimum the app might need message Header { + // basics string chain_id = 1 [(gogoproto.customname)="ChainID"]; int64 height = 2; int64 time = 3; + + // txs int32 num_txs = 4; - BlockID last_block_id = 5 [(gogoproto.customname)="LastBlockID", (gogoproto.nullable)=false]; - bytes last_commit_hash = 6; - bytes data_hash = 7; - bytes validators_hash = 8; - bytes app_hash = 9; -} - -message BlockID { - bytes hash = 1; - PartSetHeader parts = 2 [(gogoproto.nullable)=false]; -} - -message PartSetHeader { - int32 total = 1; - bytes hash = 2; + int64 total_txs = 5; + + // hashes + bytes last_block_hash = 6; + bytes validators_hash = 7; + bytes app_hash = 8; + + // consensus + Validator proposer = 9 [(gogoproto.nullable)=false]; } +// Validator message Validator { - bytes pub_key = 1; - int64 power = 2; + bytes address = 1; + PubKey pub_key = 2 [(gogoproto.nullable)=false]; + int64 power = 3; +} + +// Validator with an extra bool +message SigningValidator { + Validator validator = 1 [(gogoproto.nullable)=false]; + bool signed_last_block = 2; +} + +message PubKey { + string type = 1; + bytes data = 2; } message Evidence { - bytes pub_key = 1; - int64 height = 2; + string type = 1; + Validator validator = 2 [(gogoproto.nullable)=false]; + int64 height = 3; + int64 time = 4; + int64 total_voting_power = 5; } //---------------------------------------- diff --git a/types/util.go b/types/util.go index 39a24e02..0924ab5f 100644 --- a/types/util.go +++ b/types/util.go @@ -3,6 +3,9 @@ package types import ( "bytes" "encoding/json" + "sort" + + cmn "github.com/tendermint/tmlibs/common" ) //------------------------------------------------------------------------------ @@ -10,13 +13,21 @@ import ( // Validators is a list of validators that implements the Sort interface type Validators []Validator +var _ sort.Interface = (Validators)(nil) + +// All these methods for Validators: +// Len, Less and Swap +// are for Validators to implement sort.Interface +// which will be used by the sort package. +// See Issue https://github.com/tendermint/abci/issues/212 + 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 + return bytes.Compare(v[i].PubKey.Data, v[j].PubKey.Data) <= 0 } func (v Validators) Swap(i, j int) { @@ -28,7 +39,11 @@ func (v Validators) Swap(i, j int) { func ValidatorsString(vs Validators) string { s := make([]validatorPretty, len(vs)) for i, v := range vs { - s[i] = validatorPretty(v) + s[i] = validatorPretty{ + Address: v.Address, + PubKey: v.PubKey.Data, + Power: v.Power, + } } b, err := json.Marshal(s) if err != nil { @@ -38,6 +53,7 @@ func ValidatorsString(vs Validators) string { } type validatorPretty struct { - PubKey []byte `json:"pub_key"` - Power int64 `json:"power"` + Address cmn.HexBytes `json:"address"` + PubKey []byte `json:"pub_key"` + Power int64 `json:"power"` } diff --git a/version/version.go b/version/version.go index e1077c98..e813a01c 100644 --- a/version/version.go +++ b/version/version.go @@ -3,7 +3,7 @@ package version // NOTE: we should probably be versioning the ABCI and the abci-cli separately const Maj = "0" -const Min = "10" -const Fix = "3" +const Min = "11" +const Fix = "0" -const Version = "0.10.3" +const Version = "0.11.0"