state_transition.go 12.9 KB
Newer Older
1
// Copyright 2014 The go-ethereum Authors
2
// This file is part of the go-ethereum library.
3
//
4
// The go-ethereum library is free software: you can redistribute it and/or modify
5 6 7 8
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
9
// The go-ethereum library is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 13 14
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
15
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16

obscuren's avatar
obscuren committed
17
package core
18 19

import (
20
	"fmt"
21
	"math"
22
	"math/big"
23

obscuren's avatar
obscuren committed
24
	"github.com/ethereum/go-ethereum/common"
25
	cmath "github.com/ethereum/go-ethereum/common/math"
26
	"github.com/ethereum/go-ethereum/core/types"
obscuren's avatar
obscuren committed
27
	"github.com/ethereum/go-ethereum/core/vm"
28
	"github.com/ethereum/go-ethereum/crypto"
29
	"github.com/ethereum/go-ethereum/params"
30 31
)

32 33
var emptyCodeHash = crypto.Keccak256Hash(nil)

obscuren's avatar
obscuren committed
34
/*
35 36 37
The State Transitioning Model

A state transition is a change made when a transaction is applied to the current world state
38
The state transitioning model does all the necessary work to work out a valid new state root.
39 40 41 42 43 44 45 46 47 48 49 50

1) Nonce handling
2) Pre pay gas
3) Create a new state object if the recipient is \0*32
4) Value transfer
== If contract creation ==
  4a) Attempt to run transaction data
  4b) If valid, use result as code for the new state object
== end ==
5) Run Script section
6) Derive new state root
*/
51
type StateTransition struct {
52 53 54 55
	gp         *GasPool
	msg        Message
	gas        uint64
	gasPrice   *big.Int
56 57
	gasFeeCap  *big.Int
	gasTipCap  *big.Int
58
	initialGas uint64
59 60 61
	value      *big.Int
	data       []byte
	state      vm.StateDB
62
	evm        *vm.EVM
63 64
}

65
// Message represents a message sent to a contract.
66
type Message interface {
67
	From() common.Address
68
	To() *common.Address
69 70

	GasPrice() *big.Int
71 72
	GasFeeCap() *big.Int
	GasTipCap() *big.Int
73
	Gas() uint64
74 75 76
	Value() *big.Int

	Nonce() uint64
77
	IsFake() bool
78
	Data() []byte
79
	AccessList() types.AccessList
80
}
obscuren's avatar
obscuren committed
81

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
// ExecutionResult includes all output after executing given evm
// message no matter the execution itself is successful or not.
type ExecutionResult struct {
	UsedGas    uint64 // Total used gas but include the refunded gas
	Err        error  // Any error encountered during the execution(listed in core/vm/errors.go)
	ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
}

// Unwrap returns the internal evm error which allows us for further
// analysis outside.
func (result *ExecutionResult) Unwrap() error {
	return result.Err
}

// Failed returns the indicator whether the execution is successful or not
func (result *ExecutionResult) Failed() bool { return result.Err != nil }

// Return is a helper function to help caller distinguish between revert reason
// and function return. Return returns the data after execution if no error occurs.
func (result *ExecutionResult) Return() []byte {
	if result.Err != nil {
		return nil
	}
	return common.CopyBytes(result.ReturnData)
}

// Revert returns the concrete revert reason if the execution is aborted by `REVERT`
// opcode. Note the reason can be nil if no data supplied with revert opcode.
func (result *ExecutionResult) Revert() []byte {
	if result.Err != vm.ErrExecutionReverted {
		return nil
	}
	return common.CopyBytes(result.ReturnData)
}

117
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
118
func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool) (uint64, error) {
119 120
	// Set the starting gas for the raw transaction
	var gas uint64
121
	if isContractCreation && isHomestead {
122
		gas = params.TxGasContractCreation
123
	} else {
124
		gas = params.TxGas
125
	}
126
	// Bump the required gas by the amount of transactional data
127
	if len(data) > 0 {
128 129
		// Zero and non-zero bytes are priced differently
		var nz uint64
130 131 132 133
		for _, byt := range data {
			if byt != 0 {
				nz++
			}
obscuren's avatar
obscuren committed
134
		}
135
		// Make sure we don't exceed uint64 for all data combinations
136 137 138 139 140
		nonZeroGas := params.TxDataNonZeroGasFrontier
		if isEIP2028 {
			nonZeroGas = params.TxDataNonZeroGasEIP2028
		}
		if (math.MaxUint64-gas)/nonZeroGas < nz {
141
			return 0, ErrGasUintOverflow
142
		}
143
		gas += nz * nonZeroGas
144 145 146

		z := uint64(len(data)) - nz
		if (math.MaxUint64-gas)/params.TxDataZeroGas < z {
147
			return 0, ErrGasUintOverflow
148 149
		}
		gas += z * params.TxDataZeroGas
obscuren's avatar
obscuren committed
150
	}
151 152 153 154
	if accessList != nil {
		gas += uint64(len(accessList)) * params.TxAccessListAddressGas
		gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas
	}
155
	return gas, nil
obscuren's avatar
obscuren committed
156 157
}

158
// NewStateTransition initialises and returns a new state transition object.
159
func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
160
	return &StateTransition{
161 162 163 164 165 166 167 168 169
		gp:        gp,
		evm:       evm,
		msg:       msg,
		gasPrice:  msg.GasPrice(),
		gasFeeCap: msg.GasFeeCap(),
		gasTipCap: msg.GasTipCap(),
		value:     msg.Value(),
		data:      msg.Data(),
		state:     evm.StateDB,
170
	}
171 172 173 174 175 176 177 178 179
}

// ApplyMessage computes the new state by applying the given message
// against the old state within the environment.
//
// ApplyMessage returns the bytes returned by any EVM execution (if it took place),
// the gas used (which includes gas refunds) and an error if it failed. An error always
// indicates a core error meaning that the message would always fail for that particular
// state and would never be accepted within a block.
180
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) {
181
	return NewStateTransition(evm, msg, gp).TransitionDb()
182 183
}

184 185 186 187
// to returns the recipient of the message.
func (st *StateTransition) to() common.Address {
	if st.msg == nil || st.msg.To() == nil /* contract creation */ {
		return common.Address{}
188
	}
189
	return *st.msg.To()
190 191
}

192
func (st *StateTransition) buyGas() error {
193 194 195
	mgval := new(big.Int).SetUint64(st.msg.Gas())
	mgval = mgval.Mul(mgval, st.gasPrice)
	balanceCheck := mgval
196
	if st.gasFeeCap != nil {
197
		balanceCheck = new(big.Int).SetUint64(st.msg.Gas())
198
		balanceCheck = balanceCheck.Mul(balanceCheck, st.gasFeeCap)
199
		balanceCheck.Add(balanceCheck, st.value)
200 201
	}
	if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 {
202
		return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), have, want)
203
	}
204
	if err := st.gp.SubGas(st.msg.Gas()); err != nil {
205 206
		return err
	}
207
	st.gas += st.msg.Gas()
208

209
	st.initialGas = st.msg.Gas()
210
	st.state.SubBalance(st.msg.From(), mgval)
211 212 213
	return nil
}

214
func (st *StateTransition) preCheck() error {
215 216 217
	// Only check transactions that are not fake
	if !st.msg.IsFake() {
		// Make sure this transaction's nonce is correct.
218 219 220 221 222 223 224
		stNonce := st.state.GetNonce(st.msg.From())
		if msgNonce := st.msg.Nonce(); stNonce < msgNonce {
			return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
				st.msg.From().Hex(), msgNonce, stNonce)
		} else if stNonce > msgNonce {
			return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
				st.msg.From().Hex(), msgNonce, stNonce)
225 226 227
		} else if stNonce+1 < stNonce {
			return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
				st.msg.From().Hex(), stNonce)
228
		}
229 230 231 232 233
		// Make sure the sender is an EOA
		if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) {
			return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
				st.msg.From().Hex(), codeHash)
		}
234
	}
235
	// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
236
	if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) {
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
		// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
		if !st.evm.Config.NoBaseFee || st.gasFeeCap.BitLen() > 0 || st.gasTipCap.BitLen() > 0 {
			if l := st.gasFeeCap.BitLen(); l > 256 {
				return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh,
					st.msg.From().Hex(), l)
			}
			if l := st.gasTipCap.BitLen(); l > 256 {
				return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh,
					st.msg.From().Hex(), l)
			}
			if st.gasFeeCap.Cmp(st.gasTipCap) < 0 {
				return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap,
					st.msg.From().Hex(), st.gasTipCap, st.gasFeeCap)
			}
			// This will panic if baseFee is nil, but basefee presence is verified
			// as part of header validation.
			if st.gasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
				return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow,
					st.msg.From().Hex(), st.gasFeeCap, st.evm.Context.BaseFee)
			}
257 258
		}
	}
259
	return st.buyGas()
260 261
}

262
// TransitionDb will transition the state by applying the current message and
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
// returning the evm execution result with following fields.
//
// - used gas:
//      total gas used (including gas being refunded)
// - returndata:
//      the returned data from evm
// - concrete execution error:
//      various **EVM** error which aborts the execution,
//      e.g. ErrOutOfGas, ErrExecutionReverted
//
// However if any consensus issue encountered, return the error directly with
// nil evm execution result.
func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
	// First check this message satisfies all consensus rules before
	// applying the message. The rules include these clauses
	//
	// 1. the nonce of the message caller is correct
	// 2. caller has enough balance to cover transaction fee(gaslimit * gasprice)
	// 3. the amount of gas required is available in the block
	// 4. the purchased gas is enough to cover intrinsic usage
	// 5. there is no overflow when calculating intrinsic gas
	// 6. caller has enough balance to cover asset transfer for **topmost** call

	// Check clauses 1-3, buy gas if everything is correct
	if err := st.preCheck(); err != nil {
		return nil, err
289
	}
290 291 292 293 294 295 296 297 298 299 300 301 302 303

	if st.evm.Config.Debug {
		st.evm.Config.Tracer.CaptureTxStart(st.initialGas)
		defer func() {
			st.evm.Config.Tracer.CaptureTxEnd(st.gas)
		}()
	}

	var (
		msg              = st.msg
		sender           = vm.AccountRef(msg.From())
		rules            = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil)
		contractCreation = msg.To() == nil
	)
304

305
	// Check clauses 4-5, subtract intrinsic gas if everything is correct
306
	gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul)
307
	if err != nil {
308
		return nil, err
309
	}
310
	if st.gas < gas {
311
		return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas)
312
	}
313
	st.gas -= gas
314

315
	// Check clause 6
316
	if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) {
317
		return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex())
318
	}
319 320

	// Set up the initial access list.
321
	if rules.IsBerlin {
322
		st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
323
	}
324
	var (
325 326
		ret   []byte
		vmerr error // vm errors do not effect consensus and are therefore not assigned to err
327
	)
328
	if contractCreation {
329
		ret, _, st.gas, vmerr = st.evm.Create(sender, st.data, st.gas, st.value)
obscuren's avatar
obscuren committed
330
	} else {
obscuren's avatar
obscuren committed
331
		// Increment the nonce for the next transaction
332
		st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
333
		ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value)
334
	}
335

336
	if !rules.IsLondon {
337 338 339 340 341 342
		// Before EIP-3529: refunds were capped to gasUsed / 2
		st.refundGas(params.RefundQuotient)
	} else {
		// After EIP-3529: refunds are capped to gasUsed / 5
		st.refundGas(params.RefundQuotientEIP3529)
	}
343
	effectiveTip := st.gasPrice
344
	if rules.IsLondon {
345
		effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee))
346
	}
347 348 349 350 351 352 353 354 355 356

	if st.evm.Config.NoBaseFee && st.gasFeeCap.Sign() == 0 && st.gasTipCap.Sign() == 0 {
		// Skip fee payment when NoBaseFee is set and the fee fields
		// are 0. This avoids a negative effectiveTip being applied to
		// the coinbase when simulating calls.
	} else {
		fee := new(big.Int).SetUint64(st.gasUsed())
		fee.Mul(fee, effectiveTip)
		st.state.AddBalance(st.evm.Context.Coinbase, fee)
	}
357

358 359 360 361 362
	return &ExecutionResult{
		UsedGas:    st.gasUsed(),
		Err:        vmerr,
		ReturnData: ret,
	}, nil
363
}
obscuren's avatar
obscuren committed
364

365 366 367
func (st *StateTransition) refundGas(refundQuotient uint64) {
	// Apply refund counter, capped to a refund quotient
	refund := st.gasUsed() / refundQuotient
368 369 370 371
	if refund > st.state.GetRefund() {
		refund = st.state.GetRefund()
	}
	st.gas += refund
372

373 374
	// Return ETH for remaining gas, exchanged at the original rate.
	remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)
375
	st.state.AddBalance(st.msg.From(), remaining)
obscuren's avatar
obscuren committed
376

377 378
	// Also return remaining gas to the block gas counter so it is
	// available for the next transaction.
379
	st.gp.AddGas(st.gas)
obscuren's avatar
obscuren committed
380 381
}

382 383 384
// gasUsed returns the amount of gas used up by the state transition.
func (st *StateTransition) gasUsed() uint64 {
	return st.initialGas - st.gas
obscuren's avatar
obscuren committed
385
}