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

support special project free gas #131

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cmd/txpool/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/gateway-fm/cdk-erigon-lib/kv/remotedbserver"
"github.com/gateway-fm/cdk-erigon-lib/txpool/txpoolcfg"
"github.com/gateway-fm/cdk-erigon-lib/types"
jsoniter "github.com/json-iterator/go"
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest"
common2 "github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/eth/ethconfig"
Expand Down Expand Up @@ -66,6 +67,8 @@ var (
freeGasExAddrs []string
freeGasCountPerAddr uint64
freeGasLimit uint64
enableFreeGasList bool
freeGasList string
)

func init() {
Expand Down Expand Up @@ -99,6 +102,8 @@ func init() {
rootCmd.Flags().StringSliceVar(&freeGasExAddrs, utils.TxPoolFreeGasExAddrs.Name, ethconfig.DeprecatedDefaultTxPoolConfig.FreeGasExAddrs, utils.TxPoolFreeGasExAddrs.Usage)
rootCmd.PersistentFlags().Uint64Var(&freeGasCountPerAddr, utils.TxPoolFreeGasCountPerAddr.Name, ethconfig.DeprecatedDefaultTxPoolConfig.FreeGasCountPerAddr, utils.TxPoolFreeGasCountPerAddr.Usage)
rootCmd.PersistentFlags().Uint64Var(&freeGasLimit, utils.TxPoolFreeGasLimit.Name, ethconfig.DeprecatedDefaultTxPoolConfig.FreeGasLimit, utils.TxPoolFreeGasLimit.Usage)
rootCmd.Flags().BoolVar(&enableFreeGasList, utils.TxPoolEnableFreeGasList.Name, ethconfig.DeprecatedDefaultTxPoolConfig.EnableFreeGasList, utils.TxPoolEnableFreeGasList.Usage)
rootCmd.PersistentFlags().StringVar(&freeGasList, utils.TxPoolFreeGasList.Name, "", utils.TxPoolFreeGasList.Usage)
}

var rootCmd = &cobra.Command{
Expand Down Expand Up @@ -203,6 +208,12 @@ func doTxpool(ctx context.Context) error {
}
ethCfg.DeprecatedTxPool.FreeGasCountPerAddr = freeGasCountPerAddr
ethCfg.DeprecatedTxPool.FreeGasLimit = freeGasLimit
ethCfg.DeprecatedTxPool.EnableFreeGasList = enableFreeGasList
if len(freeGasList) > 0 {
if err := jsoniter.UnmarshalFromString(freeGasList, &ethCfg.DeprecatedTxPool.FreeGasList); err != nil {
panic("unable to unmarshal freeGasList:" + err.Error())
}
}

newTxs := make(chan types.Announcements, 1024)
defer close(newTxs)
Expand Down
20 changes: 20 additions & 0 deletions cmd/utils/flags_xlayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package utils

import (
"fmt"
jsoniter "github.com/json-iterator/go"
"math/big"
"time"

Expand Down Expand Up @@ -94,6 +95,14 @@ var (
Name: "txpool.freegaslimit",
Usage: "FreeGasLimit is the max gas allowed use to do a free gas tx",
}
TxPoolEnableFreeGasList = cli.BoolFlag{
Name: "txpool.enablefreegaslist",
Usage: "Enable or disable free gas for a special project",
}
TxPoolFreeGasList = cli.StringFlag{
Name: "txpool.freegaslist",
Usage: "FreeGasList is the special project of XLayer. Use json string",
}
// Gas Pricer
GpoTypeFlag = cli.StringFlag{
Name: "gpo.type",
Expand Down Expand Up @@ -308,6 +317,17 @@ func setTxPoolXLayer(ctx *cli.Context, cfg *ethconfig.DeprecatedTxPoolConfig) {
if ctx.IsSet(TxPoolFreeGasLimit.Name) {
cfg.FreeGasLimit = ctx.Uint64(TxPoolFreeGasLimit.Name)
}
if ctx.IsSet(TxPoolEnableFreeGasList.Name) {
cfg.EnableFreeGasList = ctx.Bool(TxPoolEnableFreeGasList.Name)
}
if ctx.IsSet(TxPoolFreeGasList.Name) {
freeGasListStr := ctx.String(TxPoolFreeGasList.Name)
if len(freeGasListStr) > 0 {
if err := jsoniter.UnmarshalFromString(freeGasListStr, &cfg.FreeGasList); err != nil {
panic("unable to unmarshal freeGasList:" + err.Error())
}
}
}
}

// SetApolloGPOXLayer is a public wrapper function to internally call setGPO
Expand Down
14 changes: 14 additions & 0 deletions eth/ethconfig/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,19 @@ type DeprecatedTxPoolConfig struct {
FreeGasCountPerAddr uint64
// FreeGasLimit is the max gas allowed use to do a free gas tx
FreeGasLimit uint64
// EnableFreeGasList enable the special project of XLayer for free gas
EnableFreeGasList bool
// FreeGasList is the special project of XLayer
FreeGasList []FreeGasInfo
}

// FreeGasInfo contains the details for what tx should be free
type FreeGasInfo struct {
Name string `json:"name"`
FromList []string `json:"from_list"`
ToList []string `json:"to_list"`
MethodSigs []string `json:"method_sigs"`
GasPriceMultiple uint64 `json:"gas_price_multiple"`
}

// DeprecatedDefaultTxPoolConfig contains the default configurations for the transaction
Expand All @@ -89,6 +102,7 @@ var DeprecatedDefaultTxPoolConfig = DeprecatedTxPoolConfig{
FreeGasExAddrs: []string{},
FreeGasCountPerAddr: 3,
FreeGasLimit: 21000,
EnableFreeGasList: false,
}

var DefaultTxPool2Config = func(pool1Cfg DeprecatedTxPoolConfig) txpoolcfg.Config {
Expand Down
4 changes: 3 additions & 1 deletion test/config/test.erigon.seq.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ txpool.gaspricemultiple : 2
txpool.blockedlist: ["0xdD2FD4581271e230360230F9337D5c0430Bf44C0"]
txpool.enablefreegasbynonce : true
txpool.freegascountperaddr : 100
txpool.enablefreegaslist : true
txpool.freegaslist : '[{"name":"test", "from_list":["0xaaa"], "to_list":[], "method_sigs":[], "gas_price_multiple": 1}]'

gpo.type: "follower"
gpo.update-period: "2s"
Expand All @@ -88,4 +90,4 @@ networkid: 195

pprof: true
pprof.port: 6060
pprof.addr: 127.0.0.1
pprof.addr: 127.0.0.1
2 changes: 2 additions & 0 deletions turbo/cli/default_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,4 +269,6 @@ var DefaultFlags = []cli.Flag{
&utils.TxPoolFreeGasCountPerAddr,
&utils.TxPoolFreeGasExAddrs,
&utils.TxPoolFreeGasLimit,
&utils.TxPoolEnableFreeGasList,
&utils.TxPoolFreeGasList,
}
10 changes: 10 additions & 0 deletions zk/apollo/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,13 @@ func (cfg *ApolloConfig) CheckFreeGasExAddr(localFreeGasExAddrs []string, addr l
}
return containsAddress(localFreeGasExAddrs, addr)
}

func (cfg *ApolloConfig) GetEnableFreeGasList(localEnableFreeGasList bool) bool {
cfg.RLock()
defer cfg.RUnlock()

if cfg.isPoolEnabled() {
return cfg.EthCfg.DeprecatedTxPool.EnableFreeGasList
}
return localEnableFreeGasList
}
22 changes: 19 additions & 3 deletions zk/txpool/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,8 @@ func New(newTxs chan types.Announcements, coreDB kv.RoDB, cfg txpoolcfg.Config,
for _, sender := range cfg.TracedSenders {
tracedSenders[common.BytesToAddress([]byte(sender))] = struct{}{}
}
return &TxPool{

tp := &TxPool{
lock: &sync.Mutex{},
byHash: map[string]*metaTx{},
isLocalLRU: localsHistory,
Expand Down Expand Up @@ -404,9 +405,24 @@ func New(newTxs chan types.Announcements, coreDB kv.RoDB, cfg txpoolcfg.Config,
FreeGasExAddrs: ethCfg.DeprecatedTxPool.FreeGasExAddrs,
FreeGasCountPerAddr: ethCfg.DeprecatedTxPool.FreeGasCountPerAddr,
FreeGasLimit: ethCfg.DeprecatedTxPool.FreeGasLimit,
EnableFreeGasList: ethCfg.DeprecatedTxPool.EnableFreeGasList,
},
freeGasAddrs: map[string]bool{},
}, nil
}
tp.setFreeGasList(ethCfg.DeprecatedTxPool.FreeGasList)
return tp, nil
}

func (p *TxPool) setFreeGasList(freeGasList []ethconfig.FreeGasInfo) {
p.xlayerCfg.FreeGasFromNameMap = make(map[string]string)
p.xlayerCfg.FreeGasList = make(map[string]*ethconfig.FreeGasInfo, len(freeGasList))
for _, info := range freeGasList {
for _, from := range info.FromList {
p.xlayerCfg.FreeGasFromNameMap[from] = info.Name
}
infoCopy := info
p.xlayerCfg.FreeGasList[info.Name] = &infoCopy
}
}

func (p *TxPool) OnNewBlock(ctx context.Context, stateChanges *remote.StateChangeBatch, unwindTxs, minedTxs types.TxSlots, tx kv.Tx) error {
Expand Down Expand Up @@ -745,7 +761,7 @@ func (p *TxPool) validateTx(txn *types.TxSlot, isLocal bool, stateCache kvcache.
if p.gpCache != nil {
rgp = p.gpCache.GetLatestRawGP()
}
if !p.isFreeGasXLayer(txn.SenderID) && uint256.NewInt(rgp.Uint64()).Cmp(&txn.FeeCap) == 1 {
if !p.isFreeGasXLayer(txn.SenderID, txn) && uint256.NewInt(rgp.Uint64()).Cmp(&txn.FeeCap) == 1 {
if txn.Traced {
log.Info(fmt.Sprintf("TX TRACING: validateTx underpriced idHash=%x local=%t, feeCap=%d, cfg.MinFeeCap=%d", txn.IDHash, isLocal, txn.FeeCap, p.cfg.MinFeeCap))
}
Expand Down
91 changes: 84 additions & 7 deletions zk/txpool/pool_xlayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,21 @@ package txpool

import (
"math/big"
"strings"

"github.com/gateway-fm/cdk-erigon-lib/common"
"github.com/gateway-fm/cdk-erigon-lib/types"
ecommon "github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/eth/ethconfig"
"github.com/ledgerwatch/erigon/zkevm/hex"
)

// free gas tx type
const (
notFree = iota
claim
freeByNonce
specialProject
)

// XLayerConfig contains the X Layer configs for the txpool
Expand All @@ -26,6 +39,11 @@ type XLayerConfig struct {
FreeGasCountPerAddr uint64
// FreeGasLimit is the max gas allowed use to do a free gas tx
FreeGasLimit uint64
// For special project
// EnableFreeGasList enable the special project of XLayer for free gas
EnableFreeGasList bool
FreeGasFromNameMap map[string]string // map[from]projectName
FreeGasList map[string]*ethconfig.FreeGasInfo // map[projectName]FreeGasInfo
}

type GPCache interface {
Expand All @@ -44,6 +62,25 @@ type ApolloConfig interface {
CheckWhitelistAddr(localWhitelist []string, addr common.Address) bool
CheckFreeClaimAddr(localFreeClaimGasAddrs []string, addr common.Address) bool
CheckFreeGasExAddr(localFreeGasExAddrs []string, addr common.Address) bool
GetEnableFreeGasList(localEnableFreeGasList bool) bool
}

func contains(addresses []string, addr common.Address) bool {
for _, item := range addresses {
if common.HexToAddress(item) == addr {
return true
}
}
return false
}

func containsMethod(data string, methods []string) bool {
for _, m := range methods {
if strings.HasPrefix(data, m) {
return true
}
}
return false
}

// SetApolloConfig sets the apollo config with the node's apollo config
Expand All @@ -64,20 +101,60 @@ func (p *TxPool) checkFreeGasExAddrXLayer(senderID uint64) bool {
return p.apolloCfg.CheckFreeGasExAddr(p.xlayerCfg.FreeGasExAddrs, addr)
}

func (p *TxPool) checkFreeGasAddrXLayer(senderID uint64) (bool, bool) {
func (p *TxPool) checkFreeGasAddrXLayer(senderID uint64, tx *types.TxSlot) (freeType int, gpMul uint64) {
addr, ok := p.senders.senderID2Addr[senderID]
if !ok {
return false, false
return
}

// is claim tx
if p.apolloCfg.CheckFreeClaimAddr(p.xlayerCfg.FreeClaimGasAddrs, addr) {
return true, true
return claim, p.xlayerCfg.GasPriceMultiple
}

// special project
if p.apolloCfg.GetEnableFreeGasList(p.xlayerCfg.EnableFreeGasList) {
fromToName, freeGpList := p.xlayerCfg.FreeGasFromNameMap, p.xlayerCfg.FreeGasList

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should add E2E test to cover this case

info := freeGpList[fromToName[addr.String()]]
if info != nil &&
contains(info.ToList, tx.To) &&
containsMethod("0x"+ecommon.Bytes2Hex(tx.Rlp), info.MethodSigs) {
return specialProject, info.GasPriceMultiple
}
}

// new bridge address
free := p.freeGasAddrs[addr.String()]
return free, false
if free {
return freeByNonce, 1
}

return notFree, 0
}

func (p *TxPool) setFreeGasByNonceCache(senderID uint64, mt *metaTx, isClaim bool) {
if p.xlayerCfg.EnableFreeGasByNonce {
if p.checkFreeGasExAddrXLayer(senderID) {
inputHex := hex.EncodeToHex(mt.Tx.Rlp)
if strings.HasPrefix(inputHex, "0xa9059cbb") && len(inputHex) > 74 {
addrHex := "0x" + inputHex[10:74]
p.freeGasAddrs[addrHex] = true
} else {
p.freeGasAddrs[mt.Tx.To.Hex()] = true
}
} else if isClaim && mt.Tx.Nonce < p.xlayerCfg.FreeGasCountPerAddr {
inputHex := hex.EncodeToHex(mt.Tx.Rlp)
if len(inputHex) > 4554 {
addrHex := "0x" + inputHex[4490:4554]
p.freeGasAddrs[addrHex] = true
} else {
p.freeGasAddrs[mt.Tx.To.Hex()] = true
}
}
}
}

func (p *TxPool) isFreeGasXLayer(senderID uint64) bool {
free, _ := p.checkFreeGasAddrXLayer(senderID)
return free
func (p *TxPool) isFreeGasXLayer(senderID uint64, tx *types.TxSlot) bool {
freeType, _ := p.checkFreeGasAddrXLayer(senderID, tx)
return freeType > notFree
}
Loading
Loading