tests: fix state test error checking (#25702)

Some tests define an 'expectException' error but the tests runner does not check for conditions where this test value is filled (error expected) but in which no error is returned by the test runner.

An example of this scenario is GeneralStateTests/stTransactionTest/HighGasPrice.json, which expects a 'TR_NoFunds' error, but the test runner does not return any error.

Signed-off-by: meows <b5c6@protonmail.com>
This commit is contained in:
meowsbits 2022-09-26 07:00:56 -07:00 committed by GitHub
parent 7227c9ef07
commit 3ec6fe6101
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 17 deletions

@ -57,12 +57,12 @@ func TestState(t *testing.T) {
// Broken tests:
// Expected failures:
//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/0`, "bug in test")
//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/3`, "bug in test")
//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/0`, "bug in test")
//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/3`, "bug in test")
//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/0`, "bug in test")
//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/3`, "bug in test")
// st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/0`, "bug in test")
// st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/3`, "bug in test")
// st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/0`, "bug in test")
// st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/3`, "bug in test")
// st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/0`, "bug in test")
// st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/3`, "bug in test")
// For Istanbul, older tests were moved into LegacyTests
for _, dir := range []string{
@ -78,10 +78,6 @@ func TestState(t *testing.T) {
t.Run(key+"/trie", func(t *testing.T) {
withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error {
_, _, err := test.Run(subtest, vmconfig, false)
if err != nil && len(test.json.Post[subtest.Fork][subtest.Index].ExpectException) > 0 {
// Ignore expected errors (TODO MariusVanDerWijden check error string)
return nil
}
return st.checkFailure(t, err)
})
})
@ -93,10 +89,6 @@ func TestState(t *testing.T) {
return err
}
}
if err != nil && len(test.json.Post[subtest.Fork][subtest.Index].ExpectException) > 0 {
// Ignore expected errors (TODO MariusVanDerWijden check error string)
return nil
}
return st.checkFailure(t, err)
})
})

@ -159,11 +159,39 @@ func (t *StateTest) Subtests() []StateSubtest {
return sub
}
// checkError checks if the error returned by the state transition matches any expected error.
// A failing expectation returns a wrapped version of the original error, if any,
// or a new error detailing the failing expectation.
// This function does not return or modify the original error, it only evaluates and returns expectations for the error.
func (t *StateTest) checkError(subtest StateSubtest, err error) error {
expectedError := t.json.Post[subtest.Fork][subtest.Index].ExpectException
if err == nil && expectedError == "" {
return nil
}
if err == nil && expectedError != "" {
return fmt.Errorf("expected error %q, got no error", expectedError)
}
if err != nil && expectedError == "" {
return fmt.Errorf("unexpected error: %w", err)
}
if err != nil && expectedError != "" {
// Ignore expected errors (TODO MariusVanDerWijden check error string)
return nil
}
return nil
}
// Run executes a specific subtest and verifies the post-state and logs
func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bool) (*snapshot.Tree, *state.StateDB, error) {
snaps, statedb, root, err := t.RunNoVerify(subtest, vmconfig, snapshotter)
if checkedErr := t.checkError(subtest, err); checkedErr != nil {
return snaps, statedb, checkedErr
}
// The error has been checked; if it was unexpected, it's already returned.
if err != nil {
return snaps, statedb, err
// Here, an error exists but it was expected.
// We do not check the post state or logs.
return snaps, statedb, nil
}
post := t.json.Post[subtest.Fork][subtest.Index]
// N.B: We need to do this in a two-step process, because the first Commit takes care
@ -231,7 +259,8 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
snapshot := statedb.Snapshot()
gaspool := new(core.GasPool)
gaspool.AddGas(block.GasLimit())
if _, err := core.ApplyMessage(evm, msg, gaspool); err != nil {
_, err = core.ApplyMessage(evm, msg, gaspool)
if err != nil {
statedb.RevertToSnapshot(snapshot)
}
// Add 0-value mining reward. This only makes a difference in the cases
@ -244,7 +273,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
statedb.Commit(config.IsEIP158(block.Number()))
// And _now_ get the state root
root := statedb.IntermediateRoot(config.IsEIP158(block.Number()))
return snaps, statedb, root, nil
return snaps, statedb, root, err
}
func (t *StateTest) gasLimit(subtest StateSubtest) uint64 {