Skip to content

Commit

Permalink
Merge pull request #12 from blockchaindevsh/fix_ValidateTransactionWi…
Browse files Browse the repository at this point in the history
…thState

make ValidateTransactionWithState also consider sgt balance
  • Loading branch information
blockchaindevsh authored Oct 13, 2024
2 parents 25669f6 + 0444929 commit 1ef7e80
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 15 deletions.
11 changes: 5 additions & 6 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,14 +260,14 @@ func init() {
slotArgs = abi.Arguments{{Name: "addr", Type: addressTy, Indexed: false}, {Name: "slot", Type: uint64Ty, Indexed: false}}
}

func targetSlot(account common.Address) (slot common.Hash) {
func TargetSGTBalanceSlot(account common.Address) (slot common.Hash) {
data, _ := slotArgs.Pack(account, BalancesSlot)
slot = crypto.Keccak256Hash(data)
return
}

func (st *StateTransition) GetSoulBalance(account common.Address) *uint256.Int {
slot := targetSlot(account)
slot := TargetSGTBalanceSlot(account)
value := st.state.GetState(types.SoulGasTokenAddr, slot)
balance := new(uint256.Int)
balance.SetBytes(value[:])
Expand All @@ -281,7 +281,7 @@ func (st *StateTransition) SubSoulBalance(account common.Address, amount *big.In
}

value := uint256.MustFromBig(current.Sub(current, amount)).Bytes32()
st.state.SetState(types.SoulGasTokenAddr, targetSlot(account), value)
st.state.SetState(types.SoulGasTokenAddr, TargetSGTBalanceSlot(account), value)

if st.evm.ChainConfig().IsOptimism() && st.evm.ChainConfig().Optimism.IsSoulBackedByNative {
st.state.SubBalance(types.SoulGasTokenAddr, uint256.MustFromBig(amount))
Expand All @@ -292,7 +292,7 @@ func (st *StateTransition) SubSoulBalance(account common.Address, amount *big.In
func (st *StateTransition) AddSoulBalance(account common.Address, amount *big.Int) {
current := st.GetSoulBalance(account).ToBig()
value := uint256.MustFromBig(current.Add(current, amount)).Bytes32()
st.state.SetState(types.SoulGasTokenAddr, targetSlot(account), value)
st.state.SetState(types.SoulGasTokenAddr, TargetSGTBalanceSlot(account), value)

if st.evm.ChainConfig().IsOptimism() && st.evm.ChainConfig().Optimism.IsSoulBackedByNative {
st.state.AddBalance(types.SoulGasTokenAddr, uint256.MustFromBig(amount))
Expand Down Expand Up @@ -338,8 +338,7 @@ func (st *StateTransition) buyGas() error {

st.gasFromSoul = false

// SoulGasToken doesn't support burning balance of zero account, so here we ensure that `gasFromSoul` is false for zero account.
if st.msg.From != (common.Address{}) && st.evm.ChainConfig().IsOptimism() && st.evm.ChainConfig().Optimism.UseSoulGasToken {
if st.evm.ChainConfig().IsOptimism() && st.evm.ChainConfig().Optimism.UseSoulGasToken {
have := st.GetSoulBalance(st.msg.From)
if have, want := have.ToBig(), new(big.Int).Sub(balanceCheck, st.msg.Value); have.Cmp(want) >= 0 {
if have, want := st.state.GetBalance(st.msg.From).ToBig(), st.msg.Value; have.Cmp(want) < 0 {
Expand Down
3 changes: 2 additions & 1 deletion core/txpool/blobpool/blobpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -1092,7 +1092,8 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error {
}
// Ensure the transaction adheres to the stateful pool filters (nonce, balance)
stateOpts := &txpool.ValidationOptionsWithState{
State: p.state,
State: p.state,
Chainconfig: p.chain.Config(),

FirstNonceGap: func(addr common.Address) uint64 {
// Nonce gaps are not permitted in the blob pool, the first gap will
Expand Down
3 changes: 2 additions & 1 deletion core/txpool/legacypool/legacypool.go
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,8 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro
// rules and adheres to some heuristic limits of the local node (price and size).
func (pool *LegacyPool) validateTx(tx *types.Transaction, local bool) error {
opts := &txpool.ValidationOptionsWithState{
State: pool.currentState,
State: pool.currentState,
Chainconfig: pool.chainconfig,

FirstNonceGap: nil, // Pool allows arbitrary arrival order, don't invalidate nonce gaps
UsedAndLeftSlots: func(addr common.Address) (int, int) {
Expand Down
24 changes: 17 additions & 7 deletions core/txpool/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
)

// L1 Info Gas Overhead is the amount of gas the the L1 info deposit consumes.
Expand Down Expand Up @@ -201,7 +202,8 @@ func validateBlobSidecar(hashes []common.Hash, sidecar *types.BlobTxSidecar) err
// ValidationOptionsWithState define certain differences between stateful transaction
// validation across the different pools without having to duplicate those checks.
type ValidationOptionsWithState struct {
State *state.StateDB // State database to check nonces and balances against
State *state.StateDB // State database to check nonces and balances against
Chainconfig *params.ChainConfig

// FirstNonceGap is an optional callback to retrieve the first nonce gap in
// the list of pooled transactions of a specific account. If this method is
Expand Down Expand Up @@ -254,27 +256,35 @@ func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, op
balance = opts.State.GetBalance(from).ToBig()
cost = tx.Cost()
)

sgtBalance := new(big.Int)
if opts.Chainconfig != nil && opts.Chainconfig.IsOptimism() && opts.Chainconfig.Optimism.UseSoulGasToken {
sgtBalanceSlot := core.TargetSGTBalanceSlot(from)
sgtBalanceValue := opts.State.GetState(types.SoulGasTokenAddr, sgtBalanceSlot)
sgtBalance = new(uint256.Int).SetBytes(sgtBalanceValue[:]).ToBig()
}

if opts.L1CostFn != nil {
if l1Cost := opts.L1CostFn(tx.RollupCostData()); l1Cost != nil { // add rollup cost
cost = cost.Add(cost, l1Cost)
}
}
if balance.Cmp(cost) < 0 {
return fmt.Errorf("%w: balance %v, tx cost %v, overshot %v", core.ErrInsufficientFunds, balance, cost, new(big.Int).Sub(cost, balance))
if balance.Cmp(cost) < 0 && sgtBalance.Cmp(cost) < 0 {
return fmt.Errorf("%w: balance %v, sgt balance:%v, tx cost %v, overshot %v", core.ErrInsufficientFunds, balance, sgtBalance, cost, new(big.Int).Sub(cost, balance))
}
// Ensure the transactor has enough funds to cover for replacements or nonce
// expansions without overdrafts
spent := opts.ExistingExpenditure(from)
if prev := opts.ExistingCost(from, tx.Nonce()); prev != nil {
bump := new(big.Int).Sub(cost, prev)
need := new(big.Int).Add(spent, bump)
if balance.Cmp(need) < 0 {
return fmt.Errorf("%w: balance %v, queued cost %v, tx bumped %v, overshot %v", core.ErrInsufficientFunds, balance, spent, bump, new(big.Int).Sub(need, balance))
if balance.Cmp(need) < 0 && sgtBalance.Cmp(need) < 0 {
return fmt.Errorf("%w: balance %v, sgt balance:%v, queued cost %v, tx bumped %v, overshot %v", core.ErrInsufficientFunds, balance, sgtBalance, spent, bump, new(big.Int).Sub(need, balance))
}
} else {
need := new(big.Int).Add(spent, cost)
if balance.Cmp(need) < 0 {
return fmt.Errorf("%w: balance %v, queued cost %v, tx cost %v, overshot %v", core.ErrInsufficientFunds, balance, spent, cost, new(big.Int).Sub(need, balance))
if balance.Cmp(need) < 0 && sgtBalance.Cmp(need) < 0 {
return fmt.Errorf("%w: balance %v, sgt balance:%v, queued cost %v, tx cost %v, overshot %v", core.ErrInsufficientFunds, balance, sgtBalance, spent, cost, new(big.Int).Sub(need, balance))
}
// Transaction takes a new nonce value out of the pool. Ensure it doesn't
// overflow the number of permitted transactions from a single account
Expand Down

0 comments on commit 1ef7e80

Please sign in to comment.