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

Merge release/v1.0.0 to develop #82

Merged
merged 11 commits into from
Apr 28, 2024
4 changes: 2 additions & 2 deletions .github/workflows/check-make-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ jobs:
submodules: recursive
token: ${{ secrets.PAT }}
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@v5
with:
golang-version: 1.19
go-version: '1.20'
- name: Checking Make Build
run: |
sudo apt update
Expand Down
2 changes: 1 addition & 1 deletion accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
return 0, err
}
if failed {
if result != nil && result.Err != vm.ErrOutOfGas {
if result != nil && !errors.Is(result.Err, vm.ErrOutOfGas) {
if len(result.Revert()) > 0 {
return 0, newRevertError(result)
}
Expand Down
7 changes: 1 addition & 6 deletions common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func (h UnprefixedHash) MarshalText() ([]byte, error) {
return []byte(hex.EncodeToString(h[:])), nil
}

// ///////// Address
/////////// Address

// Address represents the 20 byte address of an Ethereum account.
type Address [AddressLength]byte
Expand Down Expand Up @@ -309,11 +309,6 @@ func (a *Address) SetBytes(b []byte) {
copy(a[AddressLength-len(b):], b)
}

// Cmp compares two addresses.
func (a Address) Cmp(other Address) int {
return bytes.Compare(a[:], other[:])
}

// MarshalText returns the hex representation of a.
func (a Address) MarshalText() ([]byte, error) {
return hexutil.Bytes(a[:]).MarshalText()
Expand Down
8 changes: 8 additions & 0 deletions core/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ var (
// than required to start the invocation.
ErrIntrinsicGas = errors.New("intrinsic gas too low")

// ErrInsufficientGasForL1Cost is returned if the transaction is specified to use less gas
// than required for l1Cost.
ErrInsufficientGasForL1Cost = errors.New("insufficient gas for l1Cost. Please use estimateGas to get gasLimit")

// ErrTxTypeNotSupported is returned if a transaction is not supported in the
// current network configuration.
ErrTxTypeNotSupported = types.ErrTxTypeNotSupported
Expand All @@ -98,6 +102,10 @@ var (
// base fee of the block.
ErrFeeCapTooLow = errors.New("max fee per gas less than block base fee")

// ErrGasPriceTooLow is returned if the transaction gasPrice is less than the
// base fee of the block for legacy tx
ErrGasPriceTooLow = errors.New("legacy tx's gasPrice less than block base fee")

// ErrSenderNoEOA is returned if the sender of a transaction is a contract.
ErrSenderNoEOA = errors.New("sender not an eoa")

Expand Down
72 changes: 21 additions & 51 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,9 @@ var (
// 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
RefundedGas uint64 // Total gas refunded after execution
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)
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
Expand Down Expand Up @@ -237,11 +236,6 @@ func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, err
return NewStateTransition(evm, msg, gp).TransitionDb()
}

// CalculateL1Cost calculates the L1 cost for a transaction without modifying the state.
func CalculateL1Cost(evm *vm.EVM, msg *Message, gp *GasPool) (*big.Int, error) {
return NewStateTransition(evm, msg, gp).CalculateL1Cost()
}

// StateTransition represents a state transition.
//
// == The State Transitioning Model
Expand Down Expand Up @@ -291,23 +285,6 @@ func (st *StateTransition) to() common.Address {
return *st.msg.To
}

// CalculateL1Cost calculates the L1 cost for a transaction without modifying the state.
func (st *StateTransition) CalculateL1Cost() (*big.Int, error) {
var l1Cost *big.Int

// Calculate rollup gas data from the message if necessary
if st.msg.RunMode == GasEstimationMode || st.msg.RunMode == GasEstimationWithSkipCheckBalanceMode {
st.CalculateRollupGasDataFromMessage()
}

// Calculate L1 cost if L1CostFunc is defined and not in EthcallMode
if st.evm.Context.L1CostFunc != nil && st.msg.RunMode != EthcallMode {
l1Cost = st.evm.Context.L1CostFunc(st.evm.Context.BlockNumber.Uint64(), st.evm.Context.Time, st.msg.RollupDataGas, st.msg.IsDepositTx, st.msg.To)
}

return l1Cost, nil
}

func (st *StateTransition) buyGas() (*big.Int, error) {
if err := st.applyMetaTransaction(); err != nil {
return nil, err
Expand Down Expand Up @@ -468,9 +445,9 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
st.state.AddBalance(st.msg.From, mint)
}

// Mint BVM_ETH
//Mint BVM_ETH
rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil, st.evm.Context.Time)
// add eth value
//add eth value
if ethValue := st.msg.ETHValue; ethValue != nil && ethValue.Cmp(big.NewInt(0)) != 0 {
st.mintBVMETH(ethValue, rules)
}
Expand Down Expand Up @@ -546,6 +523,7 @@ func (st *StateTransition) innerTransitionDb() (*ExecutionResult, error) {
if err != nil {
return nil, err
}

if !st.msg.IsDepositTx && !st.msg.IsSystemTx {
gas = gas * tokenRatio
}
Expand All @@ -558,12 +536,9 @@ func (st *StateTransition) innerTransitionDb() (*ExecutionResult, error) {
if !st.msg.IsDepositTx && !st.msg.IsSystemTx {
if st.msg.GasPrice.Cmp(common.Big0) > 0 && l1Cost != nil {
l1Gas = new(big.Int).Div(l1Cost, st.msg.GasPrice).Uint64()
if st.msg.GasLimit < l1Gas {
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, l1Gas)
}
}
if st.gasRemaining < l1Gas {
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, l1Gas)
return nil, fmt.Errorf("%w: have %d, want %d", ErrInsufficientGasForL1Cost, st.gasRemaining, l1Gas)
}
st.gasRemaining -= l1Gas
if tokenRatio > 0 {
Expand Down Expand Up @@ -616,24 +591,22 @@ func (st *StateTransition) innerTransitionDb() (*ExecutionResult, error) {
// Note for deposit tx there is no ETH refunded for unused gas, but that's taken care of by the fact that gasPrice
// is always 0 for deposit tx. So calling refundGas will ensure the gasUsed accounting is correct without actually
// changing the sender's balance
var gasRefund uint64
if !st.msg.IsDepositTx && !st.msg.IsSystemTx {
if !rules.IsLondon {
// Before EIP-3529: refunds were capped to gasUsed / 2
gasRefund = st.refundGas(params.RefundQuotient, tokenRatio)
st.refundGas(params.RefundQuotient, tokenRatio)
} else {
// After EIP-3529: refunds are capped to gasUsed / 5
gasRefund = st.refundGas(params.RefundQuotientEIP3529, tokenRatio)
st.refundGas(params.RefundQuotientEIP3529, tokenRatio)
}
}

if st.msg.IsDepositTx && rules.IsOptimismRegolith {
// Skip coinbase payments for deposit tx in Regolith
return &ExecutionResult{
UsedGas: st.gasUsed(),
RefundedGas: gasRefund,
Err: vmerr,
ReturnData: ret,
UsedGas: st.gasUsed(),
Err: vmerr,
ReturnData: ret,
}, nil
}
effectiveTip := msg.GasPrice
Expand All @@ -656,24 +629,23 @@ func (st *StateTransition) innerTransitionDb() (*ExecutionResult, error) {
if optimismConfig := st.evm.ChainConfig().Optimism; optimismConfig != nil && rules.IsOptimismBedrock {
st.state.AddBalance(params.OptimismBaseFeeRecipient, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.evm.Context.BaseFee))
// Can not collect l1 fee here again, all l1 fee has been collected by CoinBase & OptimismBaseFeeRecipient
// if cost := st.evm.Context.L1CostFunc(st.evm.Context.BlockNumber.Uint64(), st.evm.Context.Time, st.msg.RollupDataGas, st.msg.IsDepositTx); cost != nil {
//if cost := st.evm.Context.L1CostFunc(st.evm.Context.BlockNumber.Uint64(), st.evm.Context.Time, st.msg.RollupDataGas, st.msg.IsDepositTx); cost != nil {
// st.state.AddBalance(params.OptimismL1FeeRecipient, cost)
// }
//}
}

return &ExecutionResult{
UsedGas: st.gasUsed(),
RefundedGas: gasRefund,
Err: vmerr,
ReturnData: ret,
UsedGas: st.gasUsed(),
Err: vmerr,
ReturnData: ret,
}, nil
}

func (st *StateTransition) refundGas(refundQuotient, tokenRatio uint64) uint64 {
func (st *StateTransition) refundGas(refundQuotient, tokenRatio uint64) {
if st.msg.RunMode == GasEstimationWithSkipCheckBalanceMode || st.msg.RunMode == EthcallMode {
st.gasRemaining = st.gasRemaining * tokenRatio
st.gp.AddGas(st.gasRemaining)
return 0
return
}
// Apply refund counter, capped to a refund quotient
refund := st.gasUsed() / refundQuotient
Expand All @@ -699,8 +671,6 @@ func (st *StateTransition) refundGas(refundQuotient, tokenRatio uint64) uint64 {
// Also return remaining gas to the block gas counter so it is
// available for the next transaction.
st.gp.AddGas(st.gasRemaining)

return refund
}

// gasUsed returns the amount of gas used up by the state transition.
Expand Down Expand Up @@ -801,7 +771,7 @@ func (st *StateTransition) generateBVMETHMintEvent(mintAddress common.Address, m
topics := make([]common.Hash, 2)
topics[0] = methodHash
topics[1] = mintAddress.Hash()
// data means the mint amount in MINT EVENT.
//data means the mint amount in MINT EVENT.
d := common.HexToHash(common.Bytes2Hex(mintValue.Bytes())).Bytes()
st.evm.StateDB.AddLog(&types.Log{
Address: BVM_ETH_ADDR,
Expand All @@ -820,7 +790,7 @@ func (st *StateTransition) generateBVMETHTransferEvent(from, to common.Address,
topics[0] = methodHash
topics[1] = from.Hash()
topics[2] = to.Hash()
// data means the transfer amount in Transfer EVENT.
//data means the transfer amount in Transfer EVENT.
data := common.HexToHash(common.Bytes2Hex(amount.Bytes())).Bytes()
st.evm.StateDB.AddLog(&types.Log{
Address: BVM_ETH_ADDR,
Expand Down
53 changes: 47 additions & 6 deletions core/txpool/txpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"time"

"github.com/ethereum/go-ethereum/common"
cmath "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/common/prque"
"github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/core"
Expand Down Expand Up @@ -688,7 +689,8 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
// Transactor should have enough funds to cover the costs
// cost == V + GP * GL
cost := tx.Cost()
if l1Cost := pool.l1CostFn(tx.RollupDataGas(), tx.IsDepositTx(), tx.To()); l1Cost != nil { // add rollup cost
var l1Cost *big.Int
if l1Cost = pool.l1CostFn(tx.RollupDataGas(), tx.IsDepositTx(), tx.To()); l1Cost != nil { // add rollup cost
cost = cost.Add(cost, l1Cost)
}

Expand Down Expand Up @@ -731,11 +733,20 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
sum := new(big.Int).Add(cost, list.totalcost)
if repl := list.txs.Get(tx.Nonce()); repl != nil {
// Deduct the cost of a transaction replaced by this
replL1Cost := repl.Cost()
if l1Cost := pool.l1CostFn(tx.RollupDataGas(), tx.IsDepositTx(), tx.To()); l1Cost != nil { // add rollup cost
replL1Cost = replL1Cost.Add(cost, l1Cost)
replCost := repl.Cost()
if replL1Cost := pool.l1CostFn(repl.RollupDataGas(), repl.IsDepositTx(), repl.To()); replL1Cost != nil { // add rollup cost
replCost = replCost.Add(cost, replL1Cost)
}
sum.Sub(sum, replL1Cost)
replMetaTxParams, err := types.DecodeAndVerifyMetaTxParams(repl, pool.chainconfig.IsMetaTxV2(pool.chain.CurrentBlock().Time))
if err != nil {
return err
}
if replMetaTxParams != nil {
replTxGasCost := new(big.Int).Sub(repl.Cost(), repl.Value())
sponsorAmount, _ := types.CalculateSponsorPercentAmount(replMetaTxParams, replTxGasCost)
replCost = new(big.Int).Sub(replCost, sponsorAmount)
}
sum.Sub(sum, replCost)
}
if userBalance.Cmp(sum) < 0 {
log.Trace("Replacing transactions would overdraft", "sender", from, "balance", userBalance, "required", sum)
Expand All @@ -753,6 +764,36 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
if tx.Gas() < intrGas*tokenRatio {
return core.ErrIntrinsicGas
}

gasRemaining := big.NewInt(int64(tx.Gas() - intrGas*tokenRatio))
baseFee := pool.chain.CurrentBlock().BaseFee

if tx.Type() == types.LegacyTxType {
if tx.GasPrice().Cmp(baseFee) < 0 {
return core.ErrGasPriceTooLow
}

// legacyTxL1Cost gas used to cover L1 Cost for legacy tx
legacyTxL1Cost := new(big.Int).Mul(tx.GasPrice(), gasRemaining)
if l1Cost != nil && legacyTxL1Cost.Cmp(l1Cost) <= 0 {
return core.ErrInsufficientGasForL1Cost
}
} else if tx.Type() == types.DynamicFeeTxType {
// When feecap is smaller than basefee, submission is meaningless.
// Report an error quickly instead of getting stuck in txpool.
if tx.GasFeeCap().Cmp(baseFee) < 0 { // Consistent with legacy tx verification
return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", core.ErrFeeCapTooLow,
from.Hex(), tx.GasFeeCap(), baseFee)
}

// dynamicBaseFeeTxL1Cost gas used to cover L1 Cost for dynamic fee tx
effectiveGas := cmath.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee), tx.GasFeeCap())
dynamicFeeTxL1Cost := new(big.Int).Mul(effectiveGas, gasRemaining)
if l1Cost != nil && dynamicFeeTxL1Cost.Cmp(l1Cost) <= 0 {
return core.ErrInsufficientGasForL1Cost
}
}

return nil
}

Expand Down Expand Up @@ -1508,9 +1549,9 @@ func (pool *TxPool) validateMetaTxList(list *list) ([]*types.Transaction, *big.I
sponsorAmountAccumulated = big.NewInt(0)
}
sponsorAmountAccumulated = big.NewInt(0).Add(sponsorAmountAccumulated, sponsorAmount)
sponsorCostSumPerSponsor[metaTxParams.GasFeeSponsor] = sponsorAmountAccumulated
if pool.currentState.GetBalance(metaTxParams.GasFeeSponsor).Cmp(sponsorAmountAccumulated) >= 0 {
sponsorCostSum = new(big.Int).Add(sponsorCostSum, sponsorAmount)
sponsorCostSumPerSponsor[metaTxParams.GasFeeSponsor] = sponsorAmountAccumulated
} else {
invalidMetaTxs = append(invalidMetaTxs, tx)
continue
Expand Down
2 changes: 1 addition & 1 deletion eth/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -985,7 +985,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
config.BlockOverrides.Apply(&vmctx)
}
// Execute the trace
msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee(), core.EthcallMode)
msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee(), core.EthcallMode, args.GasPrice)
if err != nil {
return nil, err
}
Expand Down
10 changes: 5 additions & 5 deletions graphql/graphql.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,16 @@ func (b *Long) UnmarshalGraphQL(input interface{}) error {
switch input := input.(type) {
case string:
// uncomment to support hex values
// if strings.HasPrefix(input, "0x") {
//if strings.HasPrefix(input, "0x") {
// // apply leniency and support hex representations of longs.
// value, err := hexutil.DecodeUint64(input)
// *b = Long(value)
// return err
// } else {
//} else {
value, err := strconv.ParseInt(input, 10, 64)
*b = Long(value)
return err
// }
//}
case int32:
*b = Long(input)
case int64:
Expand Down Expand Up @@ -1070,7 +1070,7 @@ func (b *Block) Call(ctx context.Context, args struct {
return nil, err
}
}
result, err := ethapi.DoCall(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, b.r.backend.RPCEVMTimeout(), b.r.backend.RPCGasCap(), core.EthcallMode)
result, err := ethapi.DoCall(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, b.r.backend.RPCEVMTimeout(), b.r.backend.RPCGasCap(), core.EthcallMode, args.Data.GasPrice)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1140,7 +1140,7 @@ func (p *Pending) Call(ctx context.Context, args struct {
Data ethapi.TransactionArgs
}) (*CallResult, error) {
pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
result, err := ethapi.DoCall(ctx, p.r.backend, args.Data, pendingBlockNr, nil, p.r.backend.RPCEVMTimeout(), p.r.backend.RPCGasCap(), core.EthcallMode)
result, err := ethapi.DoCall(ctx, p.r.backend, args.Data, pendingBlockNr, nil, p.r.backend.RPCEVMTimeout(), p.r.backend.RPCGasCap(), core.EthcallMode, args.Data.GasPrice)
if err != nil {
return nil, err
}
Expand Down
Loading