Fix non-deterministic map iteration in fuzzer (#2069)
* This demonstrates that the state machine is non-deterministic if there are more than two txs in a block. * fix non-deterministic map iteration * (squash this) fix build errors * (squash this) iterate using range
This commit is contained in:
parent
45bd414fc2
commit
8bb79d12ca
|
@ -130,17 +130,13 @@ func TestFullGaiaSimulation(t *testing.T) {
|
||||||
},
|
},
|
||||||
numBlocks,
|
numBlocks,
|
||||||
blockSize,
|
blockSize,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this not depend on Gaia or any of the modules,
|
// TODO: Make another test for the fuzzer itself, which just has noOp txs
|
||||||
// and place it in random_simulation_test.go
|
// and doesn't depend on gaia
|
||||||
//
|
|
||||||
// Test doesn't use `app.ExportAppStateAndValidators` as that panics with the following:
|
|
||||||
// panic: Stored pool should not have been nil [recovered]
|
|
||||||
// panic: Stored pool should not have been nil
|
|
||||||
// Change to `app.ExportAppStateAndValidators` once it is fixed
|
|
||||||
func TestAppStateDeterminism(t *testing.T) {
|
func TestAppStateDeterminism(t *testing.T) {
|
||||||
numTimesToRun := 5
|
numTimesToRun := 5
|
||||||
appHashList := make([]json.RawMessage, numTimesToRun)
|
appHashList := make([]json.RawMessage, numTimesToRun)
|
||||||
|
@ -152,27 +148,39 @@ func TestAppStateDeterminism(t *testing.T) {
|
||||||
app := NewGaiaApp(logger, db, nil)
|
app := NewGaiaApp(logger, db, nil)
|
||||||
|
|
||||||
noOpInvariant := func(t *testing.T, baseapp *baseapp.BaseApp, log string) {}
|
noOpInvariant := func(t *testing.T, baseapp *baseapp.BaseApp, log string) {}
|
||||||
noOpTestAndRunTx := func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
// noOpTestAndRunTx := func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||||
privKeys []crypto.PrivKey, log string, event func(string),
|
// privKeys []crypto.PrivKey, log string, event func(string),
|
||||||
) (action string, err sdk.Error) {
|
// ) (action string, err sdk.Error) {
|
||||||
return "", nil
|
// return "", nil
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Run randomized simulation
|
// Run randomized simulation
|
||||||
simulation.SimulateFromSeed(
|
simulation.SimulateFromSeed(
|
||||||
t, app.BaseApp, appStateFn, seed,
|
t, app.BaseApp, appStateFn, seed,
|
||||||
[]simulation.TestAndRunTx{
|
[]simulation.TestAndRunTx{
|
||||||
noOpTestAndRunTx,
|
banksim.TestAndRunSingleInputMsgSend(app.accountMapper),
|
||||||
|
govsim.SimulateMsgSubmitProposal(app.govKeeper, app.stakeKeeper),
|
||||||
|
govsim.SimulateMsgDeposit(app.govKeeper, app.stakeKeeper),
|
||||||
|
govsim.SimulateMsgVote(app.govKeeper, app.stakeKeeper),
|
||||||
|
stakesim.SimulateMsgCreateValidator(app.accountMapper, app.stakeKeeper),
|
||||||
|
stakesim.SimulateMsgEditValidator(app.stakeKeeper),
|
||||||
|
stakesim.SimulateMsgDelegate(app.accountMapper, app.stakeKeeper),
|
||||||
|
stakesim.SimulateMsgBeginUnbonding(app.accountMapper, app.stakeKeeper),
|
||||||
|
stakesim.SimulateMsgCompleteUnbonding(app.stakeKeeper),
|
||||||
|
stakesim.SimulateMsgBeginRedelegate(app.accountMapper, app.stakeKeeper),
|
||||||
|
stakesim.SimulateMsgCompleteRedelegate(app.stakeKeeper),
|
||||||
|
slashingsim.SimulateMsgUnrevoke(app.slashingKeeper),
|
||||||
},
|
},
|
||||||
[]simulation.RandSetup{},
|
[]simulation.RandSetup{},
|
||||||
[]simulation.Invariant{noOpInvariant},
|
[]simulation.Invariant{noOpInvariant},
|
||||||
0,
|
20,
|
||||||
10,
|
20,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
appHash := app.LastCommitID().Hash
|
appHash := app.LastCommitID().Hash
|
||||||
appHashList[i] = appHash
|
appHashList[i] = appHash
|
||||||
}
|
}
|
||||||
for i := 1; i < numTimesToRun; i++ {
|
for i := 1; i < numTimesToRun; i++ {
|
||||||
require.Equal(t, appHashList[0], appHashList[i])
|
require.Equal(t, appHashList[0], appHashList[i], "appHashes: %v", appHashList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,5 +42,6 @@ func TestBankWithRandomMessages(t *testing.T) {
|
||||||
TotalCoinsInvariant(mapper, func() sdk.Coins { return mapp.TotalCoinsSupply }),
|
TotalCoinsInvariant(mapper, func() sdk.Coins { return mapp.TotalCoinsSupply }),
|
||||||
},
|
},
|
||||||
30, 30,
|
30, 30,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,5 +64,6 @@ func TestGovWithRandomMessages(t *testing.T) {
|
||||||
}, []simulation.Invariant{
|
}, []simulation.Invariant{
|
||||||
AllInvariants(),
|
AllInvariants(),
|
||||||
}, 10, 100,
|
}, 10, 100,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -20,17 +21,17 @@ import (
|
||||||
// Simulate tests application by sending random messages.
|
// Simulate tests application by sending random messages.
|
||||||
func Simulate(
|
func Simulate(
|
||||||
t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, ops []TestAndRunTx, setups []RandSetup,
|
t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, ops []TestAndRunTx, setups []RandSetup,
|
||||||
invariants []Invariant, numBlocks int, blockSize int,
|
invariants []Invariant, numBlocks int, blockSize int, commit bool,
|
||||||
) {
|
) {
|
||||||
time := time.Now().UnixNano()
|
time := time.Now().UnixNano()
|
||||||
SimulateFromSeed(t, app, appStateFn, time, ops, setups, invariants, numBlocks, blockSize)
|
SimulateFromSeed(t, app, appStateFn, time, ops, setups, invariants, numBlocks, blockSize, commit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateFromSeed tests an application by running the provided
|
// SimulateFromSeed tests an application by running the provided
|
||||||
// operations, testing the provided invariants, but using the provided seed.
|
// operations, testing the provided invariants, but using the provided seed.
|
||||||
func SimulateFromSeed(
|
func SimulateFromSeed(
|
||||||
t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, seed int64, ops []TestAndRunTx, setups []RandSetup,
|
t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, seed int64, ops []TestAndRunTx, setups []RandSetup,
|
||||||
invariants []Invariant, numBlocks int, blockSize int,
|
invariants []Invariant, numBlocks int, blockSize int, commit bool,
|
||||||
) {
|
) {
|
||||||
log := fmt.Sprintf("Starting SimulateFromSeed with randomness created with seed %d", int(seed))
|
log := fmt.Sprintf("Starting SimulateFromSeed with randomness created with seed %d", int(seed))
|
||||||
fmt.Printf("%s\n", log)
|
fmt.Printf("%s\n", log)
|
||||||
|
@ -104,6 +105,9 @@ func SimulateFromSeed(
|
||||||
}
|
}
|
||||||
|
|
||||||
res := app.EndBlock(abci.RequestEndBlock{})
|
res := app.EndBlock(abci.RequestEndBlock{})
|
||||||
|
if commit {
|
||||||
|
app.Commit()
|
||||||
|
}
|
||||||
header.Height++
|
header.Height++
|
||||||
header.Time = header.Time.Add(time.Duration(minTimePerBlock) * time.Second).Add(time.Duration(int64(r.Intn(int(timeDiff)))) * time.Second)
|
header.Time = header.Time.Add(time.Duration(minTimePerBlock) * time.Second).Add(time.Duration(int64(r.Intn(int(timeDiff)))) * time.Second)
|
||||||
|
|
||||||
|
@ -123,6 +127,17 @@ func SimulateFromSeed(
|
||||||
DisplayEvents(events)
|
DisplayEvents(events)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getKeys(validators map[string]mockValidator) []string {
|
||||||
|
keys := make([]string, len(validators))
|
||||||
|
i := 0
|
||||||
|
for key := range validators {
|
||||||
|
keys[i] = key
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
// RandomRequestBeginBlock generates a list of signing validators according to the provided list of validators, signing fraction, and evidence fraction
|
// RandomRequestBeginBlock generates a list of signing validators according to the provided list of validators, signing fraction, and evidence fraction
|
||||||
func RandomRequestBeginBlock(t *testing.T, r *rand.Rand, validators map[string]mockValidator, livenessTransitions TransitionMatrix, evidenceFraction float64,
|
func RandomRequestBeginBlock(t *testing.T, r *rand.Rand, validators map[string]mockValidator, livenessTransitions TransitionMatrix, evidenceFraction float64,
|
||||||
pastTimes []time.Time, event func(string), header abci.Header, log string) abci.RequestBeginBlock {
|
pastTimes []time.Time, event func(string), header abci.Header, log string) abci.RequestBeginBlock {
|
||||||
|
@ -131,7 +146,9 @@ func RandomRequestBeginBlock(t *testing.T, r *rand.Rand, validators map[string]m
|
||||||
}
|
}
|
||||||
signingValidators := make([]abci.SigningValidator, len(validators))
|
signingValidators := make([]abci.SigningValidator, len(validators))
|
||||||
i := 0
|
i := 0
|
||||||
for _, mVal := range validators {
|
|
||||||
|
for _, key := range getKeys(validators) {
|
||||||
|
mVal := validators[key]
|
||||||
mVal.livenessState = livenessTransitions.NextState(r, mVal.livenessState)
|
mVal.livenessState = livenessTransitions.NextState(r, mVal.livenessState)
|
||||||
signed := true
|
signed := true
|
||||||
|
|
||||||
|
|
|
@ -57,5 +57,6 @@ func TestStakeWithRandomMessages(t *testing.T) {
|
||||||
}, []simulation.Invariant{
|
}, []simulation.Invariant{
|
||||||
AllInvariants(coinKeeper, stakeKeeper, mapp.AccountMapper),
|
AllInvariants(coinKeeper, stakeKeeper, mapp.AccountMapper),
|
||||||
}, 10, 100,
|
}, 10, 100,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue