Skip to content

Commit

Permalink
Make tx/message data get accessed consistently through st.msg (ethere…
Browse files Browse the repository at this point in the history
  • Loading branch information
roberto-bayardo authored Oct 13, 2022
1 parent 0aa8f1d commit 91322eb
Showing 1 changed file with 41 additions and 53 deletions.
94 changes: 41 additions & 53 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,11 @@ The state transitioning model does all the necessary work to work out a valid ne
6) Derive new state root
*/
type StateTransition struct {
gp *GasPool
msg Message
gas uint64
gasPrice *big.Int
gasFeeCap *big.Int
gasTipCap *big.Int
maxFeePerDataGas *big.Int
initialGas uint64
value *big.Int
data []byte
state vm.StateDB
evm *vm.EVM
gp *GasPool
msg Message
gasRemaining uint64
state vm.StateDB
evm *vm.EVM
}

// Message represents a message sent to a contract.
Expand Down Expand Up @@ -169,16 +162,10 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b
// NewStateTransition initialises and returns a new state transition object.
func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
return &StateTransition{
gp: gp,
evm: evm,
msg: msg,
gasPrice: msg.GasPrice(),
gasFeeCap: msg.GasFeeCap(),
gasTipCap: msg.GasTipCap(),
maxFeePerDataGas: msg.MaxFeePerDataGas(),
value: msg.Value(),
data: msg.Data(),
state: evm.StateDB,
gp: gp,
evm: evm,
msg: msg,
state: evm.StateDB,
}
}

Expand All @@ -203,7 +190,7 @@ func (st *StateTransition) to() common.Address {

func (st *StateTransition) buyGas() error {
mgval := new(big.Int).SetUint64(st.msg.Gas())
mgval = mgval.Mul(mgval, st.gasPrice)
mgval = mgval.Mul(mgval, st.msg.GasPrice())

// compute data fee for eip-4844 data blobs if any
dgval := new(big.Int)
Expand All @@ -219,14 +206,14 @@ func (st *StateTransition) buyGas() error {

// perform the required user balance checks
balanceRequired := new(big.Int)
if st.gasFeeCap == nil {
if st.msg.GasFeeCap() == nil {
balanceRequired.Set(mgval)
} else {
balanceRequired.Add(st.value, dgval)
balanceRequired.Add(st.msg.Value(), dgval)
// EIP-1559 mandates that the sender has enough balance to cover not just actual fee but
// the max gas fee, so we compute this upper bound rather than use mgval here.
maxGasFee := new(big.Int).SetUint64(st.msg.Gas())
maxGasFee.Mul(maxGasFee, st.gasFeeCap)
maxGasFee.Mul(maxGasFee, st.msg.GasFeeCap())
balanceRequired.Add(balanceRequired, maxGasFee)
}
if have, want := st.state.GetBalance(st.msg.From()), balanceRequired; have.Cmp(want) < 0 {
Expand All @@ -237,8 +224,7 @@ func (st *StateTransition) buyGas() error {
if err := st.gp.SubGas(st.msg.Gas()); err != nil {
return err
}
st.gas += st.msg.Gas()
st.initialGas = st.msg.Gas()
st.gasRemaining += st.msg.Gas()
if err := st.gp.SubDataGas(dataGasUsed); err != nil {
return err
}
Expand Down Expand Up @@ -270,37 +256,39 @@ func (st *StateTransition) preCheck() error {
st.msg.From().Hex(), codeHash)
}
}
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
// Make sure that transaction GasFeeCap is greater than the baseFee (post london)
if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) {
gasFeeCap := st.msg.GasFeeCap()
gasTipCap := st.msg.GasTipCap()
// 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 {
if !st.evm.Config.NoBaseFee || gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 {
if l := 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 {
if l := 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 {
if gasFeeCap.Cmp(gasTipCap) < 0 {
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap,
st.msg.From().Hex(), st.gasTipCap, st.gasFeeCap)
st.msg.From().Hex(), gasTipCap, 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 {
if 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)
st.msg.From().Hex(), gasFeeCap, st.evm.Context.BaseFee)
}
}
}
usesDataGas := st.dataGasUsed().Sign() > 0
if usesDataGas && st.evm.ChainConfig().IsSharding(st.evm.Context.BlockNumber) {
dataGasPrice := misc.GetDataGasPrice(st.evm.Context.ExcessDataGas)
if dataGasPrice.Cmp(st.maxFeePerDataGas) > 0 {
if dataGasPrice.Cmp(st.msg.MaxFeePerDataGas()) > 0 {
return fmt.Errorf("%w: address %v, maxFeePerDataGas: %v dataGasPrice: %v, excessDataGas: %v",
ErrMaxFeePerDataGas,
st.msg.From().Hex(), st.maxFeePerDataGas, dataGasPrice, st.evm.Context.ExcessDataGas)
st.msg.From().Hex(), st.msg.MaxFeePerDataGas(), dataGasPrice, st.evm.Context.ExcessDataGas)
}
}
return st.buyGas()
Expand Down Expand Up @@ -338,9 +326,9 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
}

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

Expand All @@ -357,14 +345,14 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
EIP4844: rules.IsSharding,
}
// Check clauses 4-5, subtract intrinsic gas if everything is correct
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, intrinsicGasRules)
gas, err := IntrinsicGas(msg.Data(), st.msg.AccessList(), contractCreation, intrinsicGasRules)
if err != nil {
return nil, err
}
if st.gas < gas {
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas)
if st.gasRemaining < gas {
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
}
st.gas -= gas
st.gasRemaining -= gas

// Check clause 6
if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) {
Expand All @@ -380,11 +368,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
vmerr error // vm errors do not effect consensus and are therefore not assigned to err
)
if contractCreation {
ret, _, st.gas, vmerr = st.evm.Create(sender, st.data, st.gas, st.value)
ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data(), st.gasRemaining, msg.Value())
} else {
// Increment the nonce for the next transaction
st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value)
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data(), st.gasRemaining, msg.Value())
}

// Note that unlike regular gas, data fee gas is not refunded if the tx is reverted, per
Expand All @@ -397,12 +385,12 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
st.refundGas(params.RefundQuotientEIP3529)
}

effectiveTip := st.gasPrice
effectiveTip := msg.GasPrice()
if rules.IsLondon {
effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee))
effectiveTip = cmath.BigMin(msg.GasTipCap(), new(big.Int).Sub(msg.GasFeeCap(), st.evm.Context.BaseFee))
}

if st.evm.Config.NoBaseFee && st.gasFeeCap.Sign() == 0 && st.gasTipCap.Sign() == 0 {
if st.evm.Config.NoBaseFee && msg.GasFeeCap().Sign() == 0 && msg.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.
Expand All @@ -425,20 +413,20 @@ func (st *StateTransition) refundGas(refundQuotient uint64) {
if refund > st.state.GetRefund() {
refund = st.state.GetRefund()
}
st.gas += refund
st.gasRemaining += refund

// Return ETH for remaining gas, exchanged at the original rate.
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice())
st.state.AddBalance(st.msg.From(), remaining)

// Also return remaining gas to the block gas counter so it is
// available for the next transaction.
st.gp.AddGas(st.gas)
st.gp.AddGas(st.gasRemaining)
}

// gasUsed returns the amount of gas used up by the state transition.
func (st *StateTransition) gasUsed() uint64 {
return st.initialGas - st.gas
return st.msg.Gas() - st.gasRemaining
}

func (st *StateTransition) dataGasUsed() *big.Int {
Expand Down

0 comments on commit 91322eb

Please sign in to comment.