diff --git a/.circleci/config.yml b/.circleci/config.yml index 37f145c028ac..df222166ab16 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2.1 executors: golang: docker: - - image: circleci/golang:1.12.7 + - image: circleci/golang:1.13 docs: docker: - image: tendermintdev/docker-website-deployment diff --git a/CHANGELOG.md b/CHANGELOG.md index b3c3dc9b9115..4e8b39a1b109 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,27 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +## [v0.37.1] - TBD + +### Features + +* (cli) [\#4973](https://github.com/cosmos/cosmos-sdk/pull/4973) Enable application CPU profiling +via the `--cpu-profile` flag. +* [\#4979](https://github.com/cosmos/cosmos-sdk/issues/4979) Introduce a new `halt-time` config and +CLI option to the `start` command. When provided, an application will halt during `Commit` when the +block time is >= the `halt-time`. + +### Improvements + +* [\#4990](https://github.com/cosmos/cosmos-sdk/issues/4990) Add `Events` to the `ABCIMessageLog` to +provide context and grouping of events based on the messages they correspond to. The `Events` field +in `TxResponse` is deprecated and will be removed in the next major release. + +### Bug Fixes + +* [\#4979](https://github.com/cosmos/cosmos-sdk/issues/4979) Use `Signal(os.Interrupt)` over +`os.Exit(0)` during configured halting to allow any `defer` calls to be executed. + ## [v0.37.0] - 2019-08-21 ### Bug Fixes @@ -2535,6 +2556,7 @@ BUG FIXES: -[Unreleased]: https://github.com/cosmos/cosmos-sdk/compare/v0.37.0...HEAD +[Unreleased]: https://github.com/cosmos/cosmos-sdk/compare/v0.37.1...HEAD +[v0.37.1]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.1 [v0.37.0]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.37.0 [v0.36.0]: https://github.com/cosmos/cosmos-sdk/releases/tag/v0.36.0 diff --git a/Makefile b/Makefile index eea23bde2539..1a065755fcdc 100644 --- a/Makefile +++ b/Makefile @@ -98,24 +98,24 @@ test_sim_custom_genesis_fast: test_sim_import_export: runsim @echo "Running application import/export simulation. This may take several minutes..." - $(BINDIR)/runsim -j 4 $(SIMAPP) 50 5 TestAppImportExport + @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) 50 5 TestAppImportExport test_sim_after_import: runsim @echo "Running application simulation-after-import. This may take several minutes..." - $(BINDIR)/runsim -j 4 $(SIMAPP) 50 5 TestAppSimulationAfterImport + @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) 50 5 TestAppSimulationAfterImport test_sim_custom_genesis_multi_seed: runsim @echo "Running multi-seed custom genesis simulation..." @echo "By default, ${HOME}/.gaiad/config/genesis.json will be used." - $(BINDIR)/runsim -g ${HOME}/.gaiad/config/genesis.json $(SIMAPP) 400 5 TestFullAppSimulation + @$(BINDIR)/runsim -Genesis=${HOME}/.gaiad/config/genesis.json -SimAppPkg=$(SIMAPP) 400 5 TestFullAppSimulation test_sim_multi_seed_long: runsim @echo "Running multi-seed application simulation. This may take awhile!" - $(BINDIR)/runsim -j 4 $(SIMAPP) 500 50 TestFullAppSimulation + @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP)500 50 TestFullAppSimulation test_sim_multi_seed_short: runsim @echo "Running multi-seed application simulation. This may take awhile!" - $(BINDIR)/runsim -j 4 $(SIMAPP) 50 10 TestFullAppSimulation + @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) 50 10 TestFullAppSimulation test_sim_benchmark_invariants: @echo "Running simulation invariant benchmarks..." diff --git a/README.md b/README.md index 782cc949c644..9a0a0781a1d8 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ It is being used to build `Gaia`, the first implementation of the Cosmos Hub. **WARNING**: The SDK has mostly stabilized, but we are still making some breaking changes. -**Note**: Requires [Go 1.12+](https://golang.org/dl/) +**Note**: Requires [Go 1.13+](https://golang.org/dl/) ## Quick Start diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 496349e6fbba..14caccbf9743 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -8,6 +8,7 @@ import ( "runtime/debug" "sort" "strings" + "syscall" "errors" @@ -83,9 +84,12 @@ type BaseApp struct { // flag for sealing options and parameters to a BaseApp sealed bool - // height at which to halt the chain and gracefully shutdown + // block height at which to halt the chain and gracefully shutdown haltHeight uint64 + // minimum block time (in Unix seconds) at which to halt the chain and gracefully shutdown + haltTime uint64 + // application's version string appVersion string } @@ -264,8 +268,12 @@ func (app *BaseApp) setMinGasPrices(gasPrices sdk.DecCoins) { app.minGasPrices = gasPrices } -func (app *BaseApp) setHaltHeight(height uint64) { - app.haltHeight = height +func (app *BaseApp) setHaltHeight(haltHeight uint64) { + app.haltHeight = haltHeight +} + +func (app *BaseApp) setHaltTime(haltTime uint64) { + app.haltTime = haltTime } // Router returns the router of the BaseApp. @@ -753,7 +761,7 @@ func (app *BaseApp) getContextForTx(mode runTxMode, txBytes []byte) (ctx sdk.Con // runMsgs iterates through all the messages and executes them. // nolint: gocyclo func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (result sdk.Result) { - idxLogs := make([]sdk.ABCIMessageLog, 0, len(msgs)) // a list of JSON-encoded logs with msg index + msgLogs := make(sdk.ABCIMessageLogs, 0, len(msgs)) var ( data []byte @@ -764,12 +772,12 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re events := sdk.EmptyEvents() // NOTE: GasWanted is determined by ante handler and GasUsed by the GasMeter. - for msgIdx, msg := range msgs { + for i, msg := range msgs { // match message route msgRoute := msg.Route() handler := app.router.Route(msgRoute) if handler == nil { - return sdk.ErrUnknownRequest("Unrecognized Msg type: " + msgRoute).Result() + return sdk.ErrUnknownRequest("unrecognized Msg type: " + msgRoute).Result() } var msgResult sdk.Result @@ -787,28 +795,23 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re events = events.AppendEvent(sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyAction, msg.Type()))) events = events.AppendEvents(msgResult.Events) - idxLog := sdk.ABCIMessageLog{MsgIndex: uint16(msgIdx), Log: msgResult.Log} - // stop execution and return on first failed message if !msgResult.IsOK() { - idxLog.Success = false - idxLogs = append(idxLogs, idxLog) + msgLogs = append(msgLogs, sdk.NewABCIMessageLog(uint16(i), false, msgResult.Log, events)) code = msgResult.Code codespace = msgResult.Codespace break } - idxLog.Success = true - idxLogs = append(idxLogs, idxLog) + msgLogs = append(msgLogs, sdk.NewABCIMessageLog(uint16(i), true, msgResult.Log, events)) } - logJSON := codec.Cdc.MustMarshalJSON(idxLogs) result = sdk.Result{ Code: code, Codespace: codespace, Data: data, - Log: strings.TrimSpace(string(logJSON)), + Log: strings.TrimSpace(msgLogs.String()), GasUsed: ctx.GasMeter().GasConsumed(), Events: events, } @@ -988,7 +991,27 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc func (app *BaseApp) Commit() (res abci.ResponseCommit) { header := app.deliverState.ctx.BlockHeader() - // write the Deliver state and commit the MultiStore + var halt bool + + switch { + case app.haltHeight > 0 && uint64(header.Height) >= app.haltHeight: + halt = true + + case app.haltTime > 0 && header.Time.Unix() >= int64(app.haltTime): + halt = true + } + + if halt { + app.halt() + + // Note: State is not actually committed when halted. Logs from Tendermint + // can be ignored. + return abci.ResponseCommit{} + } + + // Write the DeliverTx state which is cache-wrapped and commit the MultiStore. + // The write to the DeliverTx state writes all state transitions to the root + // MultiStore (app.cms) so when Commit() is called is persists those values. app.deliverState.ms.Write() commitID := app.cms.Commit() app.logger.Debug("Commit synced", "commit", fmt.Sprintf("%X", commitID)) @@ -1002,18 +1025,33 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) { // empty/reset the deliver state app.deliverState = nil - defer func() { - if app.haltHeight > 0 && uint64(header.Height) == app.haltHeight { - app.logger.Info("halting node per configuration", "height", app.haltHeight) - os.Exit(0) - } - }() - return abci.ResponseCommit{ Data: commitID.Hash, } } +// halt attempts to gracefully shutdown the node via SIGINT and SIGTERM falling +// back on os.Exit if both fail. +func (app *BaseApp) halt() { + app.logger.Info("halting node per configuration", "height", app.haltHeight, "time", app.haltTime) + + p, err := os.FindProcess(os.Getpid()) + if err == nil { + // attempt cascading signals in case SIGINT fails (os dependent) + sigIntErr := p.Signal(syscall.SIGINT) + sigTermErr := p.Signal(syscall.SIGTERM) + + if sigIntErr == nil || sigTermErr == nil { + return + } + } + + // Resort to exiting immediately if the process could not be found or killed + // via SIGINT/SIGTERM signals. + app.logger.Info("failed to send SIGINT/SIGTERM; exiting...") + os.Exit(0) +} + // ---------------------------------------------------------------------------- // State diff --git a/baseapp/options.go b/baseapp/options.go index 18ee2fd42c84..9db6f83ee7c2 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -28,9 +28,14 @@ func SetMinGasPrices(gasPricesStr string) func(*BaseApp) { return func(bap *BaseApp) { bap.setMinGasPrices(gasPrices) } } -// SetHaltHeight returns a BaseApp option function that sets the halt height. -func SetHaltHeight(height uint64) func(*BaseApp) { - return func(bap *BaseApp) { bap.setHaltHeight(height) } +// SetHaltHeight returns a BaseApp option function that sets the halt block height. +func SetHaltHeight(blockHeight uint64) func(*BaseApp) { + return func(bap *BaseApp) { bap.setHaltHeight(blockHeight) } +} + +// SetHaltTime returns a BaseApp option function that sets the halt block time. +func SetHaltTime(haltTime uint64) func(*BaseApp) { + return func(bap *BaseApp) { bap.setHaltTime(haltTime) } } func (app *BaseApp) SetName(name string) { diff --git a/go.mod b/go.mod index 7182d2ce40b1..377013c80736 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,7 @@ module github.com/cosmos/cosmos-sdk +go 1.13 + require ( github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d github.com/bgentry/speakeasy v0.1.0 @@ -10,7 +12,7 @@ require ( github.com/gogo/protobuf v1.2.1 github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 github.com/gorilla/mux v1.7.0 - github.com/gorilla/websocket v1.4.0 // indirect + github.com/gorilla/websocket v1.4.1 // indirect github.com/mattn/go-isatty v0.0.6 github.com/pelletier/go-toml v1.2.0 github.com/pkg/errors v0.8.1 @@ -25,11 +27,12 @@ require ( github.com/spf13/pflag v1.0.3 github.com/spf13/viper v1.3.2 github.com/stretchr/testify v1.3.0 + github.com/stumble/gorocksdb v0.0.3 // indirect github.com/tendermint/btcd v0.1.1 github.com/tendermint/crypto v0.0.0-20180820045704-3764759f34a5 github.com/tendermint/go-amino v0.15.0 github.com/tendermint/iavl v0.12.4 - github.com/tendermint/tendermint v0.32.2 - github.com/tendermint/tm-db v0.1.1 + github.com/tendermint/tendermint v0.32.3 + github.com/tendermint/tm-db v0.2.0 gopkg.in/yaml.v2 v2.2.2 ) diff --git a/go.sum b/go.sum index 1a5d19f3f051..7d436990aa1f 100644 --- a/go.sum +++ b/go.sum @@ -41,6 +41,12 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/etcd-io/bbolt v1.3.2/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= +github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= +github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= +github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= +github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= @@ -62,7 +68,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 h1:tT8iWCYw4uOem71yYA3htfH+LNopJvcqZQshm56G5L4= github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -75,8 +80,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U= github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= @@ -140,6 +145,7 @@ github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M= github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= @@ -161,6 +167,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stumble/gorocksdb v0.0.3 h1:9UU+QA1pqFYJuf9+5p7z1IqdE5k0mma4UAeu2wmX8kA= +github.com/stumble/gorocksdb v0.0.3/go.mod h1:v6IHdFBXk5DJ1K4FZ0xi+eY737quiiBxYtSWXadLybY= github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965 h1:1oFLiOyVl+W7bnBzGhf7BbIv9loSFQcieWWYIjLqcAw= github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= @@ -173,10 +181,11 @@ github.com/tendermint/go-amino v0.15.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoM github.com/tendermint/iavl v0.12.4 h1:hd1woxUGISKkfUWBA4mmmTwOua6PQZTJM/F0FDrmMV8= github.com/tendermint/iavl v0.12.4/go.mod h1:8LHakzt8/0G3/I8FUU0ReNx98S/EP6eyPJkAUvEXT/o= github.com/tendermint/tendermint v0.32.1/go.mod h1:jmPDAKuNkev9793/ivn/fTBnfpA9mGBww8MPRNPNxnU= -github.com/tendermint/tendermint v0.32.2 h1:FvZWdksfDg/65vKKr5Lgo57keARFnmhrUEXHwyrV1QY= -github.com/tendermint/tendermint v0.32.2/go.mod h1:NwMyx58S8VJ7tEpFKqRVlVWKO9N9zjTHu+Dx96VsnOE= -github.com/tendermint/tm-db v0.1.1 h1:G3Xezy3sOk9+ekhjZ/kjArYIs1SmwV+1OUgNkj7RgV0= +github.com/tendermint/tendermint v0.32.3 h1:GEnWpGQ795h5oTFNbfBLsY0LW/CW2j6p6HtiYNfxsgg= +github.com/tendermint/tendermint v0.32.3/go.mod h1:ZK2c29jl1QRYznIRyRWRDsmm1yvtPzBRT00x4t1JToY= github.com/tendermint/tm-db v0.1.1/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw= +github.com/tendermint/tm-db v0.2.0 h1:rJxgdqn6fIiVJZy4zLpY1qVlyD0TU6vhkT4kEf71TQQ= +github.com/tendermint/tm-db v0.2.0/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= @@ -187,7 +196,6 @@ golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a h1:YX8ljsm6wXlHZO+aRz9Exqr0evNhKRNe5K/gi+zKh4U= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -195,7 +203,6 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -204,7 +211,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/server/config/config.go b/server/config/config.go index 1507999345fe..9b556b2124b5 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -18,9 +18,20 @@ type BaseConfig struct { // specified in this config (e.g. 0.25token1;0.0001token2). MinGasPrices string `mapstructure:"minimum-gas-prices"` - // HaltHeight contains a non-zero height at which a node will gracefully halt - // and shutdown that can be used to assist upgrades and testing. + // HaltHeight contains a non-zero block height at which a node will gracefully + // halt and shutdown that can be used to assist upgrades and testing. + // + // Note: State will not be committed on the corresponding height and any logs + // indicating such can be safely ignored. HaltHeight uint64 `mapstructure:"halt-height"` + + // HaltTime contains a non-zero minimum block time (in Unix seconds) at which + // a node will gracefully halt and shutdown that can be used to assist + // upgrades and testing. + // + // Note: State will not be committed on the corresponding height and any logs + // indicating such can be safely ignored. + HaltTime uint64 `mapstructure:"halt-time"` } // Config defines the server's top level configuration @@ -60,7 +71,6 @@ func DefaultConfig() *Config { return &Config{ BaseConfig{ MinGasPrices: defaultMinGasPrices, - HaltHeight: 0, }, } } diff --git a/server/config/toml.go b/server/config/toml.go index e381ee204a6f..fc9e9bdd814f 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -18,9 +18,20 @@ const defaultConfigTemplate = `# This is a TOML config file. # specified in this config (e.g. 0.25token1;0.0001token2). minimum-gas-prices = "{{ .BaseConfig.MinGasPrices }}" -# HaltHeight contains a non-zero height at which a node will gracefully halt -# and shutdown that can be used to assist upgrades and testing. +# HaltHeight contains a non-zero block height at which a node will gracefully +# halt and shutdown that can be used to assist upgrades and testing. +# +# Note: State will not be committed on the corresponding height and any logs +# indicating such can be safely ignored. halt-height = {{ .BaseConfig.HaltHeight }} + +# HaltTime contains a non-zero minimum block time (in Unix seconds) at which +# a node will gracefully halt and shutdown that can be used to assist upgrades +# and testing. +# +# Note: State will not be committed on the corresponding height and any logs +# indicating such can be safely ignored. +halt-time = {{ .BaseConfig.HaltTime }} ` var configTemplate *template.Template diff --git a/server/start.go b/server/start.go index a1e630d81852..696163300bdf 100644 --- a/server/start.go +++ b/server/start.go @@ -1,13 +1,15 @@ package server +// DONTCOVER + import ( "fmt" + "os" + "runtime/pprof" "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/tendermint/tendermint/abci/server" - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" cmn "github.com/tendermint/tendermint/libs/common" "github.com/tendermint/tendermint/node" @@ -22,8 +24,10 @@ const ( flagAddress = "address" flagTraceStore = "trace-store" flagPruning = "pruning" + flagCPUProfile = "cpu-profile" FlagMinGasPrices = "minimum-gas-prices" FlagHaltHeight = "halt-height" + FlagHaltTime = "halt-time" ) // StartCmd runs the service passed in, either stand-alone or in-process with @@ -32,13 +36,31 @@ func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command { cmd := &cobra.Command{ Use: "start", Short: "Run the full node", + Long: `Run the full node application with Tendermint in or out of process. By +default, the application will run with Tendermint in process. + +Pruning options can be provided via the '--pruning' flag. The options are as follows: + +syncable: only those states not needed for state syncing will be deleted (keeps last 100 + every 10000th) +nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) +everything: all saved states will be deleted, storing only the current state + +Node halting configurations exist in the form of two flags: '--halt-height' and '--halt-time'. During +the ABCI Commit phase, the node will check if the current block height is greater than or equal to +the halt-height or if the current block time is greater than or equal to the halt-time. If so, the +node will attempt to gracefully shutdown and the block will not be committed. In addition, the node +will not be able to commit subsequent blocks. + +For profiling and benchmarking purposes, CPU profiling can be enabled via the '--cpu-profile' flag +which accepts a path for the resulting pprof file. +`, RunE: func(cmd *cobra.Command, args []string) error { if !viper.GetBool(flagWithTendermint) { - ctx.Logger.Info("Starting ABCI without Tendermint") + ctx.Logger.Info("starting ABCI without Tendermint") return startStandAlone(ctx, appCreator) } - ctx.Logger.Info("Starting ABCI with Tendermint") + ctx.Logger.Info("starting ABCI with Tendermint") _, err := startInProcess(ctx, appCreator) return err @@ -55,6 +77,8 @@ func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command { "Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)", ) cmd.Flags().Uint64(FlagHaltHeight, 0, "Height at which to gracefully halt the chain and shutdown the node") + cmd.Flags().Uint64(FlagHaltTime, 0, "Minimum block time (in Unix seconds) at which to gracefully halt the chain and shutdown the node") + cmd.Flags().String(flagCPUProfile, "", "Enable CPU profiling and write to the provided file") // add support for all Tendermint-specific command line options tcmd.AddNodeFlags(cmd) @@ -99,8 +123,6 @@ func startStandAlone(ctx *Context, appCreator AppCreator) error { // run forever (the node will not be returned) select {} - - return nil } func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) { @@ -125,6 +147,7 @@ func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) { } UpgradeOldPrivValFile(cfg) + // create & start tendermint node tmNode, err := node.NewNode( cfg, @@ -140,19 +163,42 @@ func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) { return nil, err } - err = tmNode.Start() - if err != nil { + if err := tmNode.Start(); err != nil { return nil, err } + var cpuProfileCleanup func() + + if cpuProfile := viper.GetString(flagCPUProfile); cpuProfile != "" { + f, err := os.Create(cpuProfile) + if err != nil { + return nil, err + } + + ctx.Logger.Info("starting CPU profiler", "profile", cpuProfile) + if err := pprof.StartCPUProfile(f); err != nil { + return nil, err + } + + cpuProfileCleanup = func() { + ctx.Logger.Info("stopping CPU profiler", "profile", cpuProfile) + pprof.StopCPUProfile() + f.Close() + } + } + TrapSignal(func() { if tmNode.IsRunning() { _ = tmNode.Stop() } + + if cpuProfileCleanup != nil { + cpuProfileCleanup() + } + + ctx.Logger.Info("exiting...") }) // run forever (the node will not be returned) select {} } - -// DONTCOVER diff --git a/types/result.go b/types/result.go index 58ea83321ce4..41a31b84ba3c 100644 --- a/types/result.go +++ b/types/result.go @@ -7,6 +7,8 @@ import ( "math" "strings" + "github.com/cosmos/cosmos-sdk/codec" + ctypes "github.com/tendermint/tendermint/rpc/core/types" ) @@ -50,12 +52,25 @@ type ABCIMessageLog struct { MsgIndex uint16 `json:"msg_index"` Success bool `json:"success"` Log string `json:"log"` + + // Events contains a slice of Event objects that were emitted during some + // execution. + Events StringEvents `json:"events"` +} + +func NewABCIMessageLog(i uint16, success bool, log string, events Events) ABCIMessageLog { + return ABCIMessageLog{ + MsgIndex: i, + Success: success, + Log: log, + Events: StringifyEvents(events.ToABCIEvents()), + } } // String implements the fmt.Stringer interface for the ABCIMessageLogs type. func (logs ABCIMessageLogs) String() (str string) { if logs != nil { - raw, err := json.Marshal(logs) + raw, err := codec.Cdc.MarshalJSON(logs) if err == nil { str = string(raw) } @@ -76,10 +91,13 @@ type TxResponse struct { Info string `json:"info,omitempty"` GasWanted int64 `json:"gas_wanted,omitempty"` GasUsed int64 `json:"gas_used,omitempty"` - Events StringEvents `json:"events,omitempty"` Codespace string `json:"codespace,omitempty"` Tx Tx `json:"tx,omitempty"` Timestamp string `json:"timestamp,omitempty"` + + // DEPRECATED: Remove in the next next major release in favor of using the + // ABCIMessageLog.Events field. + Events StringEvents `json:"events,omitempty"` } // NewResponseResultTx returns a TxResponse given a ResultTx from tendermint diff --git a/types/result_test.go b/types/result_test.go index 6a020d47455b..c4fedc2992f3 100644 --- a/types/result_test.go +++ b/types/result_test.go @@ -3,6 +3,7 @@ package types import ( "testing" + "github.com/cosmos/cosmos-sdk/codec" "github.com/stretchr/testify/require" ) @@ -27,3 +28,13 @@ func TestParseABCILog(t *testing.T) { require.Equal(t, res[0].MsgIndex, uint16(1)) require.True(t, res[0].Success) } + +func TestABCIMessageLog(t *testing.T) { + events := Events{NewEvent("transfer", NewAttribute("sender", "foo"))} + msgLog := NewABCIMessageLog(0, true, "", events) + + msgLogs := ABCIMessageLogs{msgLog} + bz, err := codec.Cdc.MarshalJSON(msgLogs) + require.NoError(t, err) + require.Equal(t, string(bz), msgLogs.String()) +}