Unverified Commit 3caf16b1 authored by Felix Lange's avatar Felix Lange Committed by GitHub

core: remove stray account creations in state transition (#16470)

The 'from' and 'to' methods on StateTransitions are reader methods and
shouldn't have inadvertent side effects on state.

It is safe to remove the check in 'from' because account existence is
implicitly checked by the nonce and balance checks. If the account has
non-zero balance or nonce, it must exist. Even if the sender account has
nonce zero at the start of the state transition or no balance, the nonce
is incremented before execution and the account will be created at that
time.

It is safe to remove the check in 'to' because the EVM creates the
account if necessary.

Fixes #15119
parent 30deb606
...@@ -132,28 +132,12 @@ func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, uint64, bool, ...@@ -132,28 +132,12 @@ func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, uint64, bool,
return NewStateTransition(evm, msg, gp).TransitionDb() return NewStateTransition(evm, msg, gp).TransitionDb()
} }
func (st *StateTransition) from() vm.AccountRef { // to returns the recipient of the message.
f := st.msg.From() func (st *StateTransition) to() common.Address {
if !st.state.Exist(f) { if st.msg == nil || st.msg.To() == nil /* contract creation */ {
st.state.CreateAccount(f) return common.Address{}
} }
return vm.AccountRef(f) return *st.msg.To()
}
func (st *StateTransition) to() vm.AccountRef {
if st.msg == nil {
return vm.AccountRef{}
}
to := st.msg.To()
if to == nil {
return vm.AccountRef{} // contract creation
}
reference := vm.AccountRef(*to)
if !st.state.Exist(*to) {
st.state.CreateAccount(*to)
}
return reference
} }
func (st *StateTransition) useGas(amount uint64) error { func (st *StateTransition) useGas(amount uint64) error {
...@@ -166,12 +150,8 @@ func (st *StateTransition) useGas(amount uint64) error { ...@@ -166,12 +150,8 @@ func (st *StateTransition) useGas(amount uint64) error {
} }
func (st *StateTransition) buyGas() error { func (st *StateTransition) buyGas() error {
var (
state = st.state
sender = st.from()
)
mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice) mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice)
if state.GetBalance(sender.Address()).Cmp(mgval) < 0 { if st.state.GetBalance(st.msg.From()).Cmp(mgval) < 0 {
return errInsufficientBalanceForGas return errInsufficientBalanceForGas
} }
if err := st.gp.SubGas(st.msg.Gas()); err != nil { if err := st.gp.SubGas(st.msg.Gas()); err != nil {
...@@ -180,20 +160,17 @@ func (st *StateTransition) buyGas() error { ...@@ -180,20 +160,17 @@ func (st *StateTransition) buyGas() error {
st.gas += st.msg.Gas() st.gas += st.msg.Gas()
st.initialGas = st.msg.Gas() st.initialGas = st.msg.Gas()
state.SubBalance(sender.Address(), mgval) st.state.SubBalance(st.msg.From(), mgval)
return nil return nil
} }
func (st *StateTransition) preCheck() error { func (st *StateTransition) preCheck() error {
msg := st.msg // Make sure this transaction's nonce is correct.
sender := st.from() if st.msg.CheckNonce() {
nonce := st.state.GetNonce(st.msg.From())
// Make sure this transaction's nonce is correct if nonce < st.msg.Nonce() {
if msg.CheckNonce() {
nonce := st.state.GetNonce(sender.Address())
if nonce < msg.Nonce() {
return ErrNonceTooHigh return ErrNonceTooHigh
} else if nonce > msg.Nonce() { } else if nonce > st.msg.Nonce() {
return ErrNonceTooLow return ErrNonceTooLow
} }
} }
...@@ -208,8 +185,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo ...@@ -208,8 +185,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
return return
} }
msg := st.msg msg := st.msg
sender := st.from() // err checked in preCheck sender := vm.AccountRef(msg.From())
homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber)
contractCreation := msg.To() == nil contractCreation := msg.To() == nil
...@@ -233,8 +209,8 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo ...@@ -233,8 +209,8 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value) ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value)
} else { } else {
// Increment the nonce for the next transaction // Increment the nonce for the next transaction
st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1) st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
ret, st.gas, vmerr = evm.Call(sender, st.to().Address(), st.data, st.gas, st.value) ret, st.gas, vmerr = evm.Call(sender, st.to(), st.data, st.gas, st.value)
} }
if vmerr != nil { if vmerr != nil {
log.Debug("VM returned with error", "err", vmerr) log.Debug("VM returned with error", "err", vmerr)
...@@ -260,10 +236,8 @@ func (st *StateTransition) refundGas() { ...@@ -260,10 +236,8 @@ func (st *StateTransition) refundGas() {
st.gas += refund st.gas += refund
// Return ETH for remaining gas, exchanged at the original rate. // Return ETH for remaining gas, exchanged at the original rate.
sender := st.from()
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)
st.state.AddBalance(sender.Address(), remaining) st.state.AddBalance(st.msg.From(), remaining)
// Also return remaining gas to the block gas counter so it is // Also return remaining gas to the block gas counter so it is
// available for the next transaction. // available for the next transaction.
......
...@@ -37,7 +37,6 @@ func TestState(t *testing.T) { ...@@ -37,7 +37,6 @@ func TestState(t *testing.T) {
// Expected failures: // Expected failures:
st.fails(`^stRevertTest/RevertPrecompiledTouch\.json/EIP158`, "bug in test") st.fails(`^stRevertTest/RevertPrecompiledTouch\.json/EIP158`, "bug in test")
st.fails(`^stRevertTest/RevertPrecompiledTouch\.json/Byzantium`, "bug in test") st.fails(`^stRevertTest/RevertPrecompiledTouch\.json/Byzantium`, "bug in test")
st.fails(`^stRandom2/randomStatetest64[45]\.json/(EIP150|Frontier|Homestead)/.*`, "known bug #15119")
st.walk(t, stateTestDir, func(t *testing.T, name string, test *StateTest) { st.walk(t, stateTestDir, func(t *testing.T, name string, test *StateTest) {
for _, subtest := range test.Subtests() { for _, subtest := range test.Subtests() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment