Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: check if sender is EOA #23303

Merged
merged 8 commits into from Aug 7, 2021
3 changes: 3 additions & 0 deletions core/error.go
Expand Up @@ -87,4 +87,7 @@ var (
// ErrFeeCapTooLow is returned if the transaction fee cap is less than the
// the base fee of the block.
ErrFeeCapTooLow = errors.New("max fee per gas less than block base fee")

// ErrSenderNoEOA is returned if the sender of a transaction is a contract.
ErrSenderNoEOA = errors.New("sender not an eoa")
)
42 changes: 41 additions & 1 deletion core/state_processor_test.go
Expand Up @@ -195,7 +195,7 @@ func TestStateProcessorErrors(t *testing.T) {
}
}

// One final error is ErrTxTypeNotSupported. For this, we need an older chain
// ErrTxTypeNotSupported, For this, we need an older chain
{
var (
db = rawdb.NewMemoryDatabase()
Expand Down Expand Up @@ -244,6 +244,46 @@ func TestStateProcessorErrors(t *testing.T) {
}
}
}

// ErrSenderNoEOA, for this we need the sender to have contract code
{
var (
db = rawdb.NewMemoryDatabase()
gspec = &Genesis{
Config: config,
Alloc: GenesisAlloc{
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
Balance: big.NewInt(1000000000000000000), // 1 ether
Nonce: 0,
Code: common.FromHex("0xB0B0FACE"),
},
},
}
genesis = gspec.MustCommit(db)
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
)
defer blockchain.Stop()
for i, tt := range []struct {
txs []*types.Transaction
want string
}{
{ // ErrSenderNoEOA
txs: []*types.Transaction{
mkDynamicTx(0, common.Address{}, params.TxGas-1000, big.NewInt(0), big.NewInt(0)),
},
want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: sender not an eoa: address 0x71562b71999873DB5b286dF957af199Ec94617F7, codehash: 0x9280914443471259d4570a8661015ae4a5b80186dbc619658fb494bebc3da3d1",
},
} {
block := GenerateBadBlock(genesis, ethash.NewFaker(), tt.txs, gspec.Config)
_, err := blockchain.InsertChain(types.Blocks{block})
if err == nil {
t.Fatal("block imported without errors")
}
if have, want := err.Error(), tt.want; have != want {
t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want)
}
}
}
}

// GenerateBadBlock constructs a "block" which contains the transactions. The transactions are not expected to be
Expand Down
8 changes: 8 additions & 0 deletions core/state_transition.go
Expand Up @@ -25,9 +25,12 @@ import (
cmath "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)

var emptyCodeHash = crypto.Keccak256Hash(nil)

/*
The State Transitioning Model

Expand Down Expand Up @@ -220,6 +223,11 @@ func (st *StateTransition) preCheck() error {
st.msg.From().Hex(), msgNonce, stNonce)
}
}
// Make sure the sender is an EOA
if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you check against the zero hash? That should never happen.

return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
rjl493456442 marked this conversation as resolved.
Show resolved Hide resolved
st.msg.From().Hex(), codeHash)
}
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) {
// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
Expand Down
10 changes: 5 additions & 5 deletions eth/tracers/api_test.go
Expand Up @@ -417,24 +417,24 @@ func TestOverriddenTraceCall(t *testing.T) {
},
},
}
for _, testspec := range testSuite {
for i, testspec := range testSuite {
result, err := api.TraceCall(context.Background(), testspec.call, rpc.BlockNumberOrHash{BlockNumber: &testspec.blockNumber}, testspec.config)
if testspec.expectErr != nil {
if err == nil {
t.Errorf("Expect error %v, get nothing", testspec.expectErr)
t.Errorf("test %d: want error %v, have nothing", i, testspec.expectErr)
continue
}
if !errors.Is(err, testspec.expectErr) {
t.Errorf("Error mismatch, want %v, get %v", testspec.expectErr, err)
t.Errorf("test %d: error mismatch, want %v, have %v", i, testspec.expectErr, err)
}
} else {
if err != nil {
t.Errorf("Expect no error, get %v", err)
t.Errorf("test %d: want no error, have %v", i, err)
continue
}
ret := new(callTrace)
if err := json.Unmarshal(result.(json.RawMessage), ret); err != nil {
t.Fatalf("failed to unmarshal trace result: %v", err)
t.Fatalf("test %d: failed to unmarshal trace result: %v", i, err)
}
if !jsonEqual(ret, testspec.expect) {
// uncomment this for easier debugging
Expand Down
37 changes: 29 additions & 8 deletions tests/init_test.go
Expand Up @@ -34,10 +34,10 @@ import (
)

var (
baseDir = filepath.Join(".", "testdata")
blockTestDir = filepath.Join(baseDir, "BlockchainTests")
stateTestDir = filepath.Join(baseDir, "GeneralStateTests")
legacyStateTestDir = filepath.Join(baseDir, "LegacyTests", "Constantinople", "GeneralStateTests")
baseDir = filepath.Join(".", "testdata")
blockTestDir = filepath.Join(baseDir, "BlockchainTests")
stateTestDir = filepath.Join(baseDir, "GeneralStateTests")
//legacyStateTestDir = filepath.Join(baseDir, "LegacyTests", "Constantinople", "GeneralStateTests")
transactionTestDir = filepath.Join(baseDir, "TransactionTests")
vmTestDir = filepath.Join(baseDir, "VMTests")
rlpTestDir = filepath.Join(baseDir, "RLPTests")
Expand Down Expand Up @@ -89,10 +89,11 @@ func findLine(data []byte, offset int64) (line int) {

// testMatcher controls skipping and chain config assignment to tests.
type testMatcher struct {
configpat []testConfig
failpat []testFailure
skiploadpat []*regexp.Regexp
slowpat []*regexp.Regexp
configpat []testConfig
failpat []testFailure
skiploadpat []*regexp.Regexp
slowpat []*regexp.Regexp
runonlylistpat *regexp.Regexp
}

type testConfig struct {
Expand Down Expand Up @@ -123,6 +124,10 @@ func (tm *testMatcher) fails(pattern string, reason string) {
tm.failpat = append(tm.failpat, testFailure{regexp.MustCompile(pattern), reason})
}

func (tm *testMatcher) runonly(pattern string) {
tm.runonlylistpat = regexp.MustCompile(pattern)
}

// config defines chain config for tests matching the pattern.
func (tm *testMatcher) config(pattern string, cfg params.ChainConfig) {
tm.configpat = append(tm.configpat, testConfig{regexp.MustCompile(pattern), cfg})
Expand Down Expand Up @@ -212,6 +217,11 @@ func (tm *testMatcher) runTestFile(t *testing.T, path, name string, runTest inte
if r, _ := tm.findSkip(name); r != "" {
t.Skip(r)
}
if tm.runonlylistpat != nil {
if !tm.runonlylistpat.MatchString(name) {
t.Skip("Skipped by runonly")
}
}
t.Parallel()

// Load the file as map[string]<testType>.
Expand Down Expand Up @@ -265,3 +275,14 @@ func runTestFunc(runTest interface{}, t *testing.T, name string, m reflect.Value
m.MapIndex(reflect.ValueOf(key)),
})
}

func TestMatcherRunonlylist(t *testing.T) {
t.Parallel()
tm := new(testMatcher)
tm.runonly("invalid*")
tm.walk(t, rlpTestDir, func(t *testing.T, name string, test *RLPTest) {
if name[:len("invalidRLPTest.json")] != "invalidRLPTest.json" {
t.Fatalf("invalid test found: %s != invalidRLPTest.json", name)
}
})
}
7 changes: 5 additions & 2 deletions tests/state_test.go
Expand Up @@ -45,7 +45,8 @@ func TestState(t *testing.T) {

// Uses 1GB RAM per tested fork
st.skipLoad(`^stStaticCall/static_Call1MB`)

// Un-skip this when https://github.com/ethereum/tests/issues/908 is closed
st.skipLoad(`^stQuadraticComplexityTest/QuadraticComplexitySolidity_CallDataCopy`)
// Broken tests:
// Expected failures:
//st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/0`, "bug in test")
Expand All @@ -58,7 +59,9 @@ func TestState(t *testing.T) {
// For Istanbul, older tests were moved into LegacyTests
for _, dir := range []string{
stateTestDir,
legacyStateTestDir,
// legacy state tests are disabled, due to them not being
// regenerated for the no-sender-eoa change.
//legacyStateTestDir,
} {
st.walk(t, dir, func(t *testing.T, name string, test *StateTest) {
for _, subtest := range test.Subtests() {
Expand Down