diff --git a/Gopkg.lock b/Gopkg.lock index b166713ee..f8d29e590 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -35,11 +35,11 @@ [[projects]] branch = "master" - digest = "1:c0decf632843204d2b8781de7b26e7038584e2dcccc7e2f401e88ae85b1df2b7" + digest = "1:093bf93a65962e8191e3e8cd8fc6c363f83d43caca9739c906531ba7210a9904" name = "github.com/btcsuite/btcd" packages = ["btcec"] pruneopts = "UT" - revision = "67e573d211ace594f1366b4ce9d39726c4b19bd0" + revision = "3dcf298fed2d5fd65918dc560b3942b2aa0629e8" [[projects]] digest = "1:386de157f7d19259a7f9c81f26ce011223ce0f090353c1152ffdf730d7d10ac2" @@ -88,12 +88,12 @@ version = "v0.6.0" [[projects]] - digest = "1:31a18dae27a29aa074515e43a443abfd2ba6deb6d69309d8d7ce789c45f34659" + digest = "1:4062bc6de62d73e2be342243cf138cf499b34d558876db8d9430e2149388a4d8" name = "github.com/go-logfmt/logfmt" packages = ["."] pruneopts = "UT" - revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5" - version = "v0.3.0" + revision = "07c9b44f60d7ffdfb7d8efe1ad539965737836dc" + version = "v0.4.0" [[projects]] digest = "1:586ea76dbd0374d6fb649a91d70d652b7fe0ccffb8910a77468e7702e7901f3d" @@ -157,20 +157,21 @@ version = "v1.6.2" [[projects]] - digest = "1:43dd08a10854b2056e615d1b1d22ac94559d822e1f8b6fcc92c1a1057e85188e" + digest = "1:7b5c6e2eeaa9ae5907c391a91c132abfd5c9e8a784a341b5625e750c67e6825d" name = "github.com/gorilla/websocket" packages = ["."] pruneopts = "UT" - revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b" - version = "v1.2.0" + revision = "66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d" + version = "v1.4.0" [[projects]] - digest = "1:ea40c24cdbacd054a6ae9de03e62c5f252479b96c716375aace5c120d68647c8" + digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10" name = "github.com/hashicorp/hcl" packages = [ ".", "hcl/ast", "hcl/parser", + "hcl/printer", "hcl/scanner", "hcl/strconv", "hcl/token", @@ -271,14 +272,16 @@ version = "v1.0.0" [[projects]] - digest = "1:c1a04665f9613e082e1209cf288bf64f4068dcd6c87a64bf1c4ff006ad422ba0" + digest = "1:26663fafdea73a38075b07e8e9d82fc0056379d2be8bb4e13899e8fda7c7dd23" name = "github.com/prometheus/client_golang" packages = [ "prometheus", + "prometheus/internal", "prometheus/promhttp", ] pruneopts = "UT" - revision = "ae27198cdd90bf12cd134ad79d1366a6cf49f632" + revision = "abad2d1bd44235a26707c172eab6bca5bf2dbad3" + version = "v0.9.1" [[projects]] branch = "master" @@ -298,7 +301,7 @@ "model", ] pruneopts = "UT" - revision = "0b1957f9d949dfa3084171a6ec5642b38055276a" + revision = "4724e9255275ce38f7179b2478abeae4e28c904f" [[projects]] branch = "master" @@ -328,6 +331,14 @@ pruneopts = "UT" revision = "e2704e165165ec55d062f5919b4b29494e9fa790" +[[projects]] + digest = "1:b0c25f00bad20d783d259af2af8666969e2fc343fa0dc9efe52936bbd67fb758" + name = "github.com/rs/cors" + packages = ["."] + pruneopts = "UT" + revision = "9a47f48565a795472d43519dd49aac781f3034fb" + version = "v1.6.0" + [[projects]] digest = "1:6a4a11ba764a56d2758899ec6f3848d24698d48442ebce85ee7a3f63284526cd" name = "github.com/spf13/afero" @@ -348,12 +359,12 @@ version = "v1.3.0" [[projects]] - digest = "1:7ffc0983035bc7e297da3688d9fe19d60a420e9c38bef23f845c53788ed6a05e" + digest = "1:645cabccbb4fa8aab25a956cbcbdf6a6845ca736b2c64e197ca7cbb9d210b939" name = "github.com/spf13/cobra" packages = ["."] pruneopts = "UT" - revision = "7b2c5ac9fc04fc5efafb60700713d4fa609b777b" - version = "v0.0.1" + revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385" + version = "v0.0.3" [[projects]] digest = "1:68ea4e23713989dc20b1bded5d9da2c5f9be14ff9885beef481848edd18c26cb" @@ -372,12 +383,12 @@ version = "v1.0.3" [[projects]] - digest = "1:f8e1a678a2571e265f4bf91a3e5e32aa6b1474a55cb0ea849750cc177b664d96" + digest = "1:ba07ec7953d565ac57a11b123a3bf0c8e848f2c7f637fccb0f9ce4f9e489d69a" name = "github.com/spf13/viper" packages = ["."] pruneopts = "UT" - revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7" - version = "v1.0.0" + revision = "a1b837276271029e31f796ae5d03ba9ffb017244" + version = "v1.0.3" [[projects]] digest = "1:7e8d267900c7fa7f35129a2a37596e38ed0f11ca746d6d9ba727980ee138f9f6" @@ -426,15 +437,16 @@ version = "v0.14.1" [[projects]] - digest = "1:9f8c4c93658315a795ffd3e0c943d39f78067dd8382b8d7bcfaf6686b92f3978" + branch = "jae/reverseiterator" + digest = "1:c42b83333367f9c701d2373c2ce11177382c41bfce3b105aa632eaf0e5654ccb" name = "github.com/tendermint/iavl" packages = ["."] pruneopts = "UT" - revision = "fa74114f764f9827c4ad5573f990ed25bf8c4bac" - version = "v0.11.1" + revision = "d8d0eef715649bcc21682990ac635566119f070c" [[projects]] - digest = "1:ba2ba7d6a0853472bdb7a64c4f9c1d5f9cba0eb7aac0b024654104387bf5eb57" + branch = "jae/reverseiterator" + digest = "1:db22ebc8142359cc3f8b6fc3954177be59358699af699794302cf60168dcf343" name = "github.com/tendermint/tendermint" packages = [ "abci/client", @@ -465,7 +477,6 @@ "libs/clist", "libs/common", "libs/db", - "libs/errors", "libs/events", "libs/fail", "libs/flowrate", @@ -500,8 +511,7 @@ "version", ] pruneopts = "UT" - revision = "80d0a362500fea2dd089258319075a54e5d40a2d" - version = "v0.26.1" + revision = "70a7cae58c8f880aede3b19101e54fb9a7b08c0b" [[projects]] digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666" @@ -594,7 +604,7 @@ revision = "383e8b2c3b9e36c4076b235b32537292176bae20" [[projects]] - digest = "1:2dab32a43451e320e49608ff4542fdfc653c95dcc35d0065ec9c6c3dd540ed74" + digest = "1:c3ad9841823db6da420a5625b367913b4ff54bbe60e8e3c98bd20e243e62e2d2" name = "google.golang.org/grpc" packages = [ ".", @@ -610,7 +620,9 @@ "internal", "internal/backoff", "internal/channelz", + "internal/envconfig", "internal/grpcrand", + "internal/transport", "keepalive", "metadata", "naming", @@ -621,11 +633,10 @@ "stats", "status", "tap", - "transport", ] pruneopts = "UT" - revision = "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" - version = "v1.13.0" + revision = "2e463a05d100327ca47ac218281906921038fd95" + version = "v1.16.0" [[projects]] digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202" diff --git a/Gopkg.toml b/Gopkg.toml index f8ffcca05..a43d7ff40 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -32,11 +32,11 @@ [[override]] name = "github.com/tendermint/iavl" - version = "=v0.11.1" + revision = "d8d0eef715649bcc21682990ac635566119f070c" [[override]] name = "github.com/tendermint/tendermint" - version = "v0.26.1" + revision = "70a7cae58c8f880aede3b19101e54fb9a7b08c0b" ## deps without releases: diff --git a/Makefile b/Makefile index 8ed722775..4fdb5a30f 100644 --- a/Makefile +++ b/Makefile @@ -174,7 +174,7 @@ test_sim_gaia_nondeterminism: test_sim_gaia_fast: @echo "Running quick Gaia simulation. This may take several minutes..." - @go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=500 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=10 -v -timeout 24h + @go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=500 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=99 -v -timeout 24h test_sim_gaia_import_export: @echo "Running Gaia import/export simulation. This may take several minutes..." diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index a83713d42..c3479a59b 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -56,6 +56,7 @@ type BaseApp struct { endBlocker sdk.EndBlocker // logic to run after all txs, and to determine valset changes addrPeerFilter sdk.PeerFilter // filter peers by address and port pubkeyPeerFilter sdk.PeerFilter // filter peers by public key + fauxMerkleMode bool // if true, IAVL MountStores uses MountStoresDB for simulation speed. //-------------------- // Volatile @@ -86,13 +87,14 @@ var _ abci.Application = (*BaseApp)(nil) // Accepts variable number of option functions, which act on the BaseApp to set configuration choices func NewBaseApp(name string, logger log.Logger, db dbm.DB, txDecoder sdk.TxDecoder, options ...func(*BaseApp)) *BaseApp { app := &BaseApp{ - Logger: logger, - name: name, - db: db, - cms: store.NewCommitMultiStore(db), - router: NewRouter(), - queryRouter: NewQueryRouter(), - txDecoder: txDecoder, + Logger: logger, + name: name, + db: db, + cms: store.NewCommitMultiStore(db), + router: NewRouter(), + queryRouter: NewQueryRouter(), + txDecoder: txDecoder, + fauxMerkleMode: false, } for _, option := range options { option(app) @@ -111,10 +113,16 @@ func (app *BaseApp) SetCommitMultiStoreTracer(w io.Writer) { app.cms.WithTracer(w) } -// Mount IAVL stores to the provided keys in the BaseApp multistore -func (app *BaseApp) MountStoresIAVL(keys ...*sdk.KVStoreKey) { +// Mount IAVL or DB stores to the provided keys in the BaseApp multistore +func (app *BaseApp) MountStores(keys ...*sdk.KVStoreKey) { for _, key := range keys { - app.MountStore(key, sdk.StoreTypeIAVL) + if !app.fauxMerkleMode { + app.MountStore(key, sdk.StoreTypeIAVL) + } else { + // StoreTypeDB doesn't do anything upon commit, and it doesn't + // retain history, but it's useful for faster simulation. + app.MountStore(key, sdk.StoreTypeDB) + } } } diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index c09f050ed..4678655d0 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -60,7 +60,7 @@ func setupBaseApp(t *testing.T, options ...func(*BaseApp)) *BaseApp { app.LoadLatestVersion(capKey1) }) - app.MountStoresIAVL(capKey1, capKey2) + app.MountStores(capKey1, capKey2) // stores are mounted err := app.LoadLatestVersion(capKey1) @@ -91,7 +91,7 @@ func TestLoadVersion(t *testing.T) { // make a cap key and mount the store capKey := sdk.NewKVStoreKey("main") - app.MountStoresIAVL(capKey) + app.MountStores(capKey) err := app.LoadLatestVersion(capKey) // needed to make stores non-nil require.Nil(t, err) @@ -117,7 +117,7 @@ func TestLoadVersion(t *testing.T) { // reload with LoadLatestVersion app = NewBaseApp(name, logger, db, nil) - app.MountStoresIAVL(capKey) + app.MountStores(capKey) err = app.LoadLatestVersion(capKey) require.Nil(t, err) testLoadVersionHelper(t, app, int64(2), commitID2) @@ -125,7 +125,7 @@ func TestLoadVersion(t *testing.T) { // reload with LoadVersion, see if you can commit the same block and get // the same result app = NewBaseApp(name, logger, db, nil) - app.MountStoresIAVL(capKey) + app.MountStores(capKey) err = app.LoadVersion(1, capKey) require.Nil(t, err) testLoadVersionHelper(t, app, int64(1), commitID1) @@ -161,7 +161,7 @@ func testChangeNameHelper(name string) func(*BaseApp) { // make a cap key and mount the store capKey := sdk.NewKVStoreKey("main") - app.MountStoresIAVL(capKey) + app.MountStores(capKey) err := app.LoadLatestVersion(capKey) // needed to make stores non-nil require.Nil(t, err) @@ -219,7 +219,7 @@ func TestInitChainer(t *testing.T) { app := NewBaseApp(name, logger, db, nil) capKey := sdk.NewKVStoreKey("main") capKey2 := sdk.NewKVStoreKey("key2") - app.MountStoresIAVL(capKey, capKey2) + app.MountStores(capKey, capKey2) // set a value in the store on init chain key, value := []byte("hello"), []byte("goodbye") @@ -262,7 +262,7 @@ func TestInitChainer(t *testing.T) { // reload app app = NewBaseApp(name, logger, db, nil) app.SetInitChainer(initChainer) - app.MountStoresIAVL(capKey, capKey2) + app.MountStores(capKey, capKey2) err = app.LoadLatestVersion(capKey) // needed to make stores non-nil require.Nil(t, err) diff --git a/baseapp/options.go b/baseapp/options.go index a6460248d..8d86933a0 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -102,6 +102,16 @@ func (app *BaseApp) SetPubKeyPeerFilter(pf sdk.PeerFilter) { app.pubkeyPeerFilter = pf } +func (app *BaseApp) SetFauxMerkleMode() { + if app.sealed { + panic("SetFauxMerkleMode() on sealed BaseApp") + } + app.fauxMerkleMode = true +} + +//---------------------------------------- +// TODO: move these out of this file? + func (app *BaseApp) Router() Router { if app.sealed { panic("Router() on sealed BaseApp") diff --git a/client/lcd/root.go b/client/lcd/root.go index 7081b76c0..ffe5d061f 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -18,7 +18,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/tendermint/tendermint/libs/log" - tmserver "github.com/tendermint/tendermint/rpc/lib/server" + rpcserver "github.com/tendermint/tendermint/rpc/lib/server" // Import statik for light client stuff _ "github.com/cosmos/cosmos-sdk/client/lcd/statik" @@ -87,9 +87,9 @@ func (rs *RestServer) Start(listenAddr string, sslHosts string, "Insecure mode is temporarily disabled, please locally generate an " + "SSL certificate to test. Support will be re-enabled soon!", ) - // listener, err = tmserver.StartHTTPServer( + // listener, err = rpcserver.StartHTTPServer( // listenAddr, handler, logger, - // tmserver.Config{MaxOpenConnections: maxOpen}, + // rpcserver.Config{MaxOpenConnections: maxOpen}, // ) // if err != nil { // return @@ -120,16 +120,19 @@ func (rs *RestServer) Start(listenAddr string, sslHosts string, }() } - rs.listener, err = tmserver.StartHTTPAndTLSServer( - listenAddr, rs.Mux, - certFile, keyFile, - rs.log, - tmserver.Config{MaxOpenConnections: maxOpen}, + rs.listener, err = rpcserver.Listen( + listenAddr, + rpcserver.Config{MaxOpenConnections: maxOpen}, ) if err != nil { return } - + go rpcserver.StartHTTPAndTLSServer( + rs.listener, + rs.Mux, + certFile, keyFile, + rs.log, + ) rs.log.Info(rs.fingerprint) rs.log.Info("REST server started") } diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 4fbacf3d5..921dc96dd 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -360,13 +360,16 @@ func startTM( } // startLCD starts the LCD. -// -// NOTE: This causes the thread to block. func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec, t *testing.T) (net.Listener, error) { rs := NewRestServer(cdc) rs.setKeybase(GetTestKeyBase(t)) registerRoutes(rs) - return tmrpc.StartHTTPServer(listenAddr, rs.Mux, logger, tmrpc.Config{}) + listener, err := tmrpc.Listen(listenAddr, tmrpc.Config{}) + if err != nil { + return nil, err + } + go tmrpc.StartHTTPServer(listener, rs.Mux, logger) + return listener, nil } // NOTE: If making updates here also update cmd/gaia/cmd/gaiacli/main.go diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 10248b426..aaed04632 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -156,7 +156,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio AddRoute("stake", stake.NewQuerier(app.stakeKeeper, app.cdc)) // initialize BaseApp - app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyStake, app.keyMint, app.keyDistr, + app.MountStores(app.keyMain, app.keyAccount, app.keyStake, app.keyMint, app.keyDistr, app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams) app.SetInitChainer(app.initChainer) app.SetBeginBlocker(app.BeginBlocker) @@ -188,7 +188,6 @@ func MakeCodec() *codec.Codec { // application updates every end block func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { - tags := slashing.BeginBlocker(ctx, req, app.slashingKeeper) // distribute rewards from previous block distr.BeginBlocker(ctx, req, app.distrKeeper) @@ -196,6 +195,13 @@ func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) ab // mint new tokens for this new block mint.BeginBlocker(ctx, app.mintKeeper) + // slash anyone who double signed. + // NOTE: This should happen after distr.BeginBlocker so that + // there is nothing left over in the validator fee pool, + // so as to keep the CanWithdrawInvariant invariant. + // TODO: This should really happen at EndBlocker. + tags := slashing.BeginBlocker(ctx, req, app.slashingKeeper) + return abci.ResponseBeginBlock{ Tags: tags.ToKVPairs(), } diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index 66868f13b..97ea568fd 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -16,6 +16,7 @@ import ( dbm "github.com/tendermint/tendermint/libs/db" "github.com/tendermint/tendermint/libs/log" + "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" authsim "github.com/cosmos/cosmos-sdk/x/auth/simulation" banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation" @@ -193,6 +194,11 @@ func invariants(app *GaiaApp) []simulation.Invariant { } } +// Pass this in as an option to use a dbStoreAdapter instead of an IAVLStore for simulation speed. +func fauxMerkleModeOpt(bapp *baseapp.BaseApp) { + bapp.SetFauxMerkleMode() +} + // Profile with: // /usr/local/go/bin/go test -benchmem -run=^$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$ -SimulationCommit=true -cpuprofile cpu.out func BenchmarkFullGaiaSimulation(b *testing.B) { @@ -249,7 +255,7 @@ func TestFullGaiaSimulation(t *testing.T) { db.Close() os.RemoveAll(dir) }() - app := NewGaiaApp(logger, db, nil) + app := NewGaiaApp(logger, db, nil, fauxMerkleModeOpt) require.Equal(t, "GaiaApp", app.Name()) // Run randomized simulation @@ -291,7 +297,7 @@ func TestGaiaImportExport(t *testing.T) { db.Close() os.RemoveAll(dir) }() - app := NewGaiaApp(logger, db, nil) + app := NewGaiaApp(logger, db, nil, fauxMerkleModeOpt) require.Equal(t, "GaiaApp", app.Name()) // Run randomized simulation @@ -328,7 +334,7 @@ func TestGaiaImportExport(t *testing.T) { newDB.Close() os.RemoveAll(newDir) }() - newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil) + newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil, fauxMerkleModeOpt) require.Equal(t, "GaiaApp", newApp.Name()) var genesisState GenesisState err = app.cdc.UnmarshalJSON(appState, &genesisState) @@ -388,7 +394,7 @@ func TestGaiaSimulationAfterImport(t *testing.T) { db.Close() os.RemoveAll(dir) }() - app := NewGaiaApp(logger, db, nil) + app := NewGaiaApp(logger, db, nil, fauxMerkleModeOpt) require.Equal(t, "GaiaApp", app.Name()) // Run randomized simulation @@ -431,7 +437,7 @@ func TestGaiaSimulationAfterImport(t *testing.T) { newDB.Close() os.RemoveAll(newDir) }() - newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil) + newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil, fauxMerkleModeOpt) require.Equal(t, "GaiaApp", newApp.Name()) newApp.InitChain(abci.RequestInitChain{ AppStateBytes: appState, diff --git a/cmd/gaia/cmd/gaiadebug/hack.go b/cmd/gaia/cmd/gaiadebug/hack.go index e9f3b5658..1fb7b447d 100644 --- a/cmd/gaia/cmd/gaiadebug/hack.go +++ b/cmd/gaia/cmd/gaiadebug/hack.go @@ -188,7 +188,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp app.SetBeginBlocker(app.BeginBlocker) app.SetEndBlocker(app.EndBlocker) app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper)) - app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyStake, app.keySlashing, app.keyParams) + app.MountStores(app.keyMain, app.keyAccount, app.keyStake, app.keySlashing, app.keyParams) app.MountStore(app.tkeyParams, sdk.StoreTypeTransient) err := app.LoadLatestVersion(app.keyMain) if err != nil { diff --git a/docs/examples/basecoin/app/app.go b/docs/examples/basecoin/app/app.go index 3e58e71f9..f534c9128 100644 --- a/docs/examples/basecoin/app/app.go +++ b/docs/examples/basecoin/app/app.go @@ -89,7 +89,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.Ba app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper)) // mount the multistore and load the latest state - app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC) + app.MountStores(app.keyMain, app.keyAccount, app.keyIBC) err := app.LoadLatestVersion(app.keyMain) if err != nil { cmn.Exit(err.Error()) diff --git a/docs/examples/democoin/app/app.go b/docs/examples/democoin/app/app.go index ec9db1ae8..99c1e3ed9 100644 --- a/docs/examples/democoin/app/app.go +++ b/docs/examples/democoin/app/app.go @@ -97,7 +97,7 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp { // Initialize BaseApp. app.SetInitChainer(app.initChainerFn(app.coolKeeper, app.powKeeper)) - app.MountStoresIAVL(app.capKeyMainStore, app.capKeyAccountStore, app.capKeyPowStore, app.capKeyIBCStore, app.capKeyStakingStore) + app.MountStores(app.capKeyMainStore, app.capKeyAccountStore, app.capKeyPowStore, app.capKeyIBCStore, app.capKeyStakingStore) app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper)) err := app.LoadLatestVersion(app.capKeyMainStore) if err != nil { diff --git a/docs/examples/kvstore/main.go b/docs/examples/kvstore/main.go index 125c7cd47..d7aa80834 100644 --- a/docs/examples/kvstore/main.go +++ b/docs/examples/kvstore/main.go @@ -35,7 +35,7 @@ func main() { var baseApp = bam.NewBaseApp("kvstore", logger, db, decodeTx) // Set mounts for BaseApp's MultiStore. - baseApp.MountStoresIAVL(capKeyMainStore) + baseApp.MountStores(capKeyMainStore) // Set a handler Route. baseApp.Router().AddRoute("kvstore", Handler(capKeyMainStore)) diff --git a/server/mock/app.go b/server/mock/app.go index dd8f3f5ab..9e5af4498 100644 --- a/server/mock/app.go +++ b/server/mock/app.go @@ -31,7 +31,7 @@ func NewApp(rootDir string, logger log.Logger) (abci.Application, error) { baseApp := bam.NewBaseApp("kvstore", logger, db, decodeTx) // Set mounts for BaseApp's MultiStore. - baseApp.MountStoresIAVL(capKeyMainStore) + baseApp.MountStores(capKeyMainStore) baseApp.SetInitChainer(InitChainer(capKeyMainStore)) diff --git a/store/cachekvstore.go b/store/cachekvstore.go index 4a2940f4d..4860566c4 100644 --- a/store/cachekvstore.go +++ b/store/cachekvstore.go @@ -7,6 +7,7 @@ import ( "sync" cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" ) // If value is nil but deleted is false, it means the parent doesn't have the @@ -159,29 +160,29 @@ func (ci *cacheKVStore) iterator(start, end []byte, ascending bool) Iterator { parent = ci.parent.ReverseIterator(start, end) } - items := ci.dirtyItems(ascending) + items := ci.dirtyItems(start, end, ascending) cache = newMemIterator(start, end, items) return newCacheMergeIterator(parent, cache, ascending) } // Constructs a slice of dirty items, to use w/ memIterator. -func (ci *cacheKVStore) dirtyItems(ascending bool) []cmn.KVPair { - items := make([]cmn.KVPair, 0, len(ci.cache)) +func (ci *cacheKVStore) dirtyItems(start, end []byte, ascending bool) []cmn.KVPair { + items := make([]cmn.KVPair, 0) for key, cacheValue := range ci.cache { if !cacheValue.dirty { continue } - - items = append(items, cmn.KVPair{Key: []byte(key), Value: cacheValue.value}) + if dbm.IsKeyInDomain([]byte(key), start, end) { + items = append(items, cmn.KVPair{Key: []byte(key), Value: cacheValue.value}) + } } sort.Slice(items, func(i, j int) bool { if ascending { return bytes.Compare(items[i].Key, items[j].Key) < 0 } - return bytes.Compare(items[i].Key, items[j].Key) > 0 }) diff --git a/store/dbstoreadapter.go b/store/dbstoreadapter.go index 739e30596..8f4a1583c 100644 --- a/store/dbstoreadapter.go +++ b/store/dbstoreadapter.go @@ -39,3 +39,28 @@ func (dsa dbStoreAdapter) Gas(meter GasMeter, config GasConfig) KVStore { // dbm.DB implements KVStore so we can CacheKVStore it. var _ KVStore = dbStoreAdapter{} + +//---------------------------------------- +// commitDBStoreWrapper should only be used for simulation/debugging, +// as it doesn't compute any commit hash, and it cannot load older state. + +// Wrapper type for dbm.Db with implementation of KVStore +type commitDBStoreAdapter struct { + dbStoreAdapter +} + +func (cdsa commitDBStoreAdapter) Commit() CommitID { + return CommitID{ + Version: -1, + Hash: []byte("FAKE_HASH"), + } +} + +func (cdsa commitDBStoreAdapter) LastCommitID() CommitID { + return CommitID{ + Version: -1, + Hash: []byte("FAKE_HASH"), + } +} + +func (cdsa commitDBStoreAdapter) SetPruning(_ PruningStrategy) {} diff --git a/store/gaskvstore_test.go b/store/gaskvstore_test.go index 69f4ae204..f059df7f8 100644 --- a/store/gaskvstore_test.go +++ b/store/gaskvstore_test.go @@ -3,6 +3,7 @@ package store import ( "testing" + "github.com/tendermint/iavl" dbm "github.com/tendermint/tendermint/libs/db" sdk "github.com/cosmos/cosmos-sdk/types" @@ -86,7 +87,7 @@ func testGasKVStoreWrap(t *testing.T, store KVStore) { func TestGasKVStoreWrap(t *testing.T) { db := dbm.NewMemDB() - tree, _ := newTree(t, db) + tree := iavl.NewMutableTree(db, cacheSize) iavl := newIAVLStore(tree, numRecent, storeEvery) testGasKVStoreWrap(t, iavl) diff --git a/store/iavlstore_test.go b/store/iavlstore_test.go index d26cee055..4d8605e4e 100644 --- a/store/iavlstore_test.go +++ b/store/iavlstore_test.go @@ -28,8 +28,8 @@ var ( nMoreData = 0 ) -// make a tree and save it -func newTree(t *testing.T, db dbm.DB) (*iavl.MutableTree, CommitID) { +// make a tree with data from above and save it +func newAlohaTree(t *testing.T, db dbm.DB) (*iavl.MutableTree, CommitID) { tree := iavl.NewMutableTree(db, cacheSize) for k, v := range treeData { tree.Set([]byte(k), []byte(v)) @@ -46,7 +46,7 @@ func newTree(t *testing.T, db dbm.DB) (*iavl.MutableTree, CommitID) { func TestIAVLStoreGetSetHasDelete(t *testing.T) { db := dbm.NewMemDB() - tree, _ := newTree(t, db) + tree, _ := newAlohaTree(t, db) iavlStore := newIAVLStore(tree, numRecent, storeEvery) key := "hello" @@ -71,7 +71,7 @@ func TestIAVLStoreGetSetHasDelete(t *testing.T) { func TestIAVLIterator(t *testing.T) { db := dbm.NewMemDB() - tree, _ := newTree(t, db) + tree, _ := newAlohaTree(t, db) iavlStore := newIAVLStore(tree, numRecent, storeEvery) iter := iavlStore.Iterator([]byte("aloha"), []byte("hellz")) expected := []string{"aloha", "hello"} @@ -142,9 +142,40 @@ func TestIAVLIterator(t *testing.T) { require.Equal(t, len(expected), i) } -func TestIAVLSubspaceIterator(t *testing.T) { +func TestIAVLReverseIterator(t *testing.T) { db := dbm.NewMemDB() - tree, _ := newTree(t, db) + tree := iavl.NewMutableTree(db, cacheSize) + iavlStore := newIAVLStore(tree, numRecent, storeEvery) + + iavlStore.Set([]byte{0x00}, []byte("0")) + iavlStore.Set([]byte{0x00, 0x00}, []byte("0 0")) + iavlStore.Set([]byte{0x00, 0x01}, []byte("0 1")) + iavlStore.Set([]byte{0x00, 0x02}, []byte("0 2")) + iavlStore.Set([]byte{0x01}, []byte("1")) + + var testReverseIterator = func(t *testing.T, start []byte, end []byte, expected []string) { + iter := iavlStore.ReverseIterator(start, end) + var i int + for i = 0; iter.Valid(); iter.Next() { + expectedValue := expected[i] + value := iter.Value() + require.EqualValues(t, string(value), expectedValue) + i++ + } + require.Equal(t, len(expected), i) + } + + testReverseIterator(t, nil, nil, []string{"1", "0 2", "0 1", "0 0", "0"}) + testReverseIterator(t, []byte{0x00}, nil, []string{"1", "0 2", "0 1", "0 0", "0"}) + testReverseIterator(t, []byte{0x00}, []byte{0x00, 0x01}, []string{"0 0", "0"}) + testReverseIterator(t, []byte{0x00}, []byte{0x01}, []string{"0 2", "0 1", "0 0", "0"}) + testReverseIterator(t, []byte{0x00, 0x01}, []byte{0x01}, []string{"0 2", "0 1"}) + testReverseIterator(t, nil, []byte{0x01}, []string{"0 2", "0 1", "0 0", "0"}) +} + +func TestIAVLPrefixIterator(t *testing.T) { + db := dbm.NewMemDB() + tree := iavl.NewMutableTree(db, cacheSize) iavlStore := newIAVLStore(tree, numRecent, storeEvery) iavlStore.Set([]byte("test1"), []byte("test1")) @@ -204,9 +235,9 @@ func TestIAVLSubspaceIterator(t *testing.T) { require.Equal(t, len(expected), i) } -func TestIAVLReverseSubspaceIterator(t *testing.T) { +func TestIAVLReversePrefixIterator(t *testing.T) { db := dbm.NewMemDB() - tree, _ := newTree(t, db) + tree := iavl.NewMutableTree(db, cacheSize) iavlStore := newIAVLStore(tree, numRecent, storeEvery) iavlStore.Set([]byte("test1"), []byte("test1")) diff --git a/store/memiterator.go b/store/memiterator.go index a72418db6..c9a026cb5 100644 --- a/store/memiterator.go +++ b/store/memiterator.go @@ -18,8 +18,7 @@ type memIterator struct { func newMemIterator(start, end []byte, items []cmn.KVPair) *memIterator { itemsInDomain := make([]cmn.KVPair, 0) for _, item := range items { - ascending := keyCompare(start, end) < 0 - if dbm.IsKeyInDomain(item.Key, start, end, !ascending) { + if dbm.IsKeyInDomain(item.Key, start, end) { itemsInDomain = append(itemsInDomain, item) } } diff --git a/store/prefixstore.go b/store/prefixstore.go index 3abea4653..1f52a99fe 100644 --- a/store/prefixstore.go +++ b/store/prefixstore.go @@ -99,24 +99,16 @@ func (s prefixStore) Iterator(start, end []byte) Iterator { // Implements KVStore // Check https://github.com/tendermint/tendermint/blob/master/libs/db/prefix_db.go#L129 func (s prefixStore) ReverseIterator(start, end []byte) Iterator { - var newstart []byte - if start == nil { - newstart = cpIncr(s.prefix) - } else { - newstart = cloneAppend(s.prefix, start) - } + newstart := cloneAppend(s.prefix, start) var newend []byte if end == nil { - newend = cpDecr(s.prefix) + newend = cpIncr(s.prefix) } else { newend = cloneAppend(s.prefix, end) } iter := s.parent.ReverseIterator(newstart, newend) - if start == nil { - skipOne(iter, cpIncr(s.prefix)) - } return newPrefixIterator(s.prefix, start, end, iter) } diff --git a/store/prefixstore_test.go b/store/prefixstore_test.go index 4e555292c..48e6cd17f 100644 --- a/store/prefixstore_test.go +++ b/store/prefixstore_test.go @@ -388,13 +388,15 @@ func TestPrefixDBReverseIterator2(t *testing.T) { store := mockStoreWithStuff() pstore := store.Prefix(bz("key")) - itr := pstore.ReverseIterator(nil, bz("")) - checkDomain(t, itr, nil, bz("")) + itr := pstore.ReverseIterator(bz(""), nil) + checkDomain(t, itr, bz(""), nil) checkItem(t, itr, bz("3"), bz("value3")) checkNext(t, itr, true) checkItem(t, itr, bz("2"), bz("value2")) checkNext(t, itr, true) checkItem(t, itr, bz("1"), bz("value1")) + checkNext(t, itr, true) + checkItem(t, itr, bz(""), bz("value")) checkNext(t, itr, false) checkInvalid(t, itr) itr.Close() @@ -404,10 +406,8 @@ func TestPrefixDBReverseIterator3(t *testing.T) { store := mockStoreWithStuff() pstore := store.Prefix(bz("key")) - itr := pstore.ReverseIterator(bz(""), nil) - checkDomain(t, itr, bz(""), nil) - checkItem(t, itr, bz(""), bz("value")) - checkNext(t, itr, false) + itr := pstore.ReverseIterator(nil, bz("")) + checkDomain(t, itr, nil, bz("")) checkInvalid(t, itr) itr.Close() } diff --git a/store/rootmultistore.go b/store/rootmultistore.go index 3faf67a5e..c309f9e9b 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -358,7 +358,8 @@ func (rs *rootMultiStore) loadCommitStoreFromParams(key sdk.StoreKey, id CommitI store, err = LoadIAVLStore(db, id, rs.pruning) return case sdk.StoreTypeDB: - panic("dbm.DB is not a CommitStore") + store = commitDBStoreAdapter{dbStoreAdapter{db}} + return case sdk.StoreTypeTransient: _, ok := key.(*sdk.TransientStoreKey) if !ok { diff --git a/types/store.go b/types/store.go index c2e57a342..671a881c2 100644 --- a/types/store.go +++ b/types/store.go @@ -143,7 +143,7 @@ type KVStore interface { Iterator(start, end []byte) Iterator // Iterator over a domain of keys in descending order. End is exclusive. - // Start must be greater than end, or the Iterator is invalid. + // Start must be less than end, or the Iterator is invalid. // Iterator must be closed by caller. // CONTRACT: No writes may happen within a domain while an iterator exists over it. ReverseIterator(start, end []byte) Iterator diff --git a/x/distribution/alias.go b/x/distribution/alias.go index f293857ab..ad76596a4 100644 --- a/x/distribution/alias.go +++ b/x/distribution/alias.go @@ -16,6 +16,8 @@ type ( ValidatorDistInfo = types.ValidatorDistInfo TotalAccum = types.TotalAccum FeePool = types.FeePool + DecCoin = types.DecCoin + DecCoins = types.DecCoins MsgSetWithdrawAddress = types.MsgSetWithdrawAddress MsgWithdrawDelegatorRewardsAll = types.MsgWithdrawDelegatorRewardsAll @@ -56,6 +58,8 @@ var ( NewMsgWithdrawDelegatorRewardsAll = types.NewMsgWithdrawDelegatorRewardsAll NewMsgWithdrawDelegatorReward = types.NewMsgWithdrawDelegatorReward NewMsgWithdrawValidatorRewardsAll = types.NewMsgWithdrawValidatorRewardsAll + + NewDecCoins = types.NewDecCoins ) const ( diff --git a/x/distribution/keeper/allocation.go b/x/distribution/keeper/allocation.go index abe6b32df..97b1e4b37 100644 --- a/x/distribution/keeper/allocation.go +++ b/x/distribution/keeper/allocation.go @@ -18,6 +18,16 @@ func (k Keeper) AllocateTokens(ctx sdk.Context, percentVotes sdk.Dec, proposer s feesCollected := k.feeCollectionKeeper.GetCollectedFees(ctx) feesCollectedDec := types.NewDecCoins(feesCollected) + feePool := k.GetFeePool(ctx) + // Temporary workaround to keep CanWithdrawInvariant happy. + // General discussions here: https://github.com/cosmos/cosmos-sdk/issues/2906#issuecomment-441867634 + if k.stakeKeeper.GetLastTotalPower(ctx).IsZero() { + feePool.CommunityPool = feePool.CommunityPool.Plus(feesCollectedDec) + k.SetFeePool(ctx, feePool) + k.feeCollectionKeeper.ClearCollectedFees(ctx) + return + } + // allocated rewards to proposer baseProposerReward := k.GetBaseProposerReward(ctx) bonusProposerReward := k.GetBonusProposerReward(ctx) @@ -33,7 +43,6 @@ func (k Keeper) AllocateTokens(ctx sdk.Context, percentVotes sdk.Dec, proposer s // allocate community funding communityTax := k.GetCommunityTax(ctx) communityFunding := feesCollectedDec.MulDec(communityTax) - feePool := k.GetFeePool(ctx) feePool.CommunityPool = feePool.CommunityPool.Plus(communityFunding) // set the global pool within the distribution module diff --git a/x/distribution/keeper/validator.go b/x/distribution/keeper/validator.go index 7b174cd1c..97eb5bc50 100644 --- a/x/distribution/keeper/validator.go +++ b/x/distribution/keeper/validator.go @@ -102,10 +102,6 @@ func (k Keeper) WithdrawValidatorRewardsAll(ctx sdk.Context, operatorAddr sdk.Va accAddr := sdk.AccAddress(operatorAddr.Bytes()) withdraw := k.withdrawDelegationRewardsAll(ctx, accAddr) - //if withdraw.AmountOf { - //return types.ErrNoValidatorDistInfo(k.codespace) - //} - // withdrawal validator commission rewards valInfo := k.GetValidatorDistInfo(ctx, operatorAddr) wc := k.GetWithdrawContext(ctx, operatorAddr) diff --git a/x/distribution/simulation/invariants.go b/x/distribution/simulation/invariants.go index ae4e74729..5e995978c 100644 --- a/x/distribution/simulation/invariants.go +++ b/x/distribution/simulation/invariants.go @@ -179,6 +179,5 @@ func CanWithdrawInvariant(k distr.Keeper, sk stake.Keeper) simulation.Invariant // all ok return nil - } } diff --git a/x/distribution/types/dec_coin.go b/x/distribution/types/dec_coin.go index c5d9f360a..221cc9c17 100644 --- a/x/distribution/types/dec_coin.go +++ b/x/distribution/types/dec_coin.go @@ -184,7 +184,7 @@ func (coins DecCoins) AmountOf(denom string) sdk.Dec { } } -// returns the amount of a denom from deccoins +// has a negative DecCoin amount func (coins DecCoins) HasNegative() bool { for _, coin := range coins { if coin.Amount.IsNegative() { diff --git a/x/distribution/types/validator_info.go b/x/distribution/types/validator_info.go index d7739359f..fe4b755d0 100644 --- a/x/distribution/types/validator_info.go +++ b/x/distribution/types/validator_info.go @@ -91,7 +91,7 @@ func (vi ValidatorDistInfo) TakeFeePoolRewards(wc WithdrawContext) ( if accum.GT(fp.TotalValAccum.Accum) { panic("individual accum should never be greater than the total") } - withdrawalTokens := fp.ValPool.MulDec(accum).QuoDec(fp.TotalValAccum.Accum) + withdrawalTokens := fp.ValPool.MulDec(accum).QuoDec(fp.TotalValAccum.Accum) // XXX ensure this doesn't cause problems remValPool := fp.ValPool.Minus(withdrawalTokens) commission := withdrawalTokens.MulDec(wc.CommissionRate) diff --git a/x/gov/simulation/msgs.go b/x/gov/simulation/msgs.go index b69d7c18c..5319ee7b2 100644 --- a/x/gov/simulation/msgs.go +++ b/x/gov/simulation/msgs.go @@ -192,7 +192,7 @@ func randomProposalID(r *rand.Rand, k gov.Keeper, ctx sdk.Context) (proposalID u if lastProposalID < 1 { return 0, false } - proposalID = uint64(r.Intn(int(lastProposalID))) + proposalID = uint64(r.Intn(1+int(lastProposalID)) - 1) return proposalID, true } diff --git a/x/mock/simulation/rand_util.go b/x/mock/simulation/rand_util.go index c40d2a65c..a57775ecb 100644 --- a/x/mock/simulation/rand_util.go +++ b/x/mock/simulation/rand_util.go @@ -62,3 +62,29 @@ func RandTimestamp(r *rand.Rand) time.Time { unixTime := r.Int63n(253373529600) return time.Unix(unixTime, 0) } + +// Derive a new rand deterministically from a rand. +// Unlike rand.New(rand.NewSource(seed)), the result is "more random" +// depending on the source and state of r. +// NOTE: not crypto safe. +func DeriveRand(r *rand.Rand) *rand.Rand { + const num = 8 // TODO what's a good number? Too large is too slow. + ms := multiSource(make([]rand.Source, num)) + for i := 0; i < num; i++ { + ms[i] = rand.NewSource(r.Int63()) + } + return rand.New(ms) +} + +type multiSource []rand.Source + +func (ms multiSource) Int63() (r int64) { + for _, source := range ms { + r ^= source.Int63() + } + return r +} + +func (ms multiSource) Seed(seed int64) { + panic("multiSource Seed should not be called") +} diff --git a/x/mock/simulation/simulate.go b/x/mock/simulation/simulate.go index 74446e290..21caecef2 100644 --- a/x/mock/simulation/simulate.go +++ b/x/mock/simulation/simulate.go @@ -249,9 +249,25 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params header.Height, totalNumBlocks, opCount, blocksize) lastBlocksizeState, blocksize = getBlockSize(r, params, lastBlocksizeState, avgBlockSize) + type opAndR struct { + op Operation + rand *rand.Rand + } + opAndRz := make([]opAndR, 0, blocksize) + // Predetermine the blocksize slice so that we can do things like block + // out certain operations without changing the ops that follow. for i := 0; i < blocksize; i++ { + opAndRz = append(opAndRz, opAndR{ + op: selectOp(r), + rand: DeriveRand(r), + }) + } - logUpdate, futureOps, err := selectOp(r)(r, app, ctx, accounts, event) + for i := 0; i < blocksize; i++ { + // NOTE: the Rand 'r' should not be used here. + opAndR := opAndRz[i] + op, r2 := opAndR.op, opAndR.rand + logUpdate, futureOps, err := op(r2, app, ctx, accounts, event) logWriter(logUpdate) if err != nil { displayLogs()