forked from 0xPolygonHermez/zkevm-node
-
Notifications
You must be signed in to change notification settings - Fork 0
/
effectivegasprice.go
154 lines (122 loc) · 5.53 KB
/
effectivegasprice.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package pool
import (
"bytes"
"errors"
"math/big"
"github.com/0xPolygonHermez/zkevm-node/log"
"github.com/0xPolygonHermez/zkevm-node/state"
)
var (
// ErrEffectiveGasPriceEmpty happens when the effectiveGasPrice or gasPrice is nil or zero
ErrEffectiveGasPriceEmpty = errors.New("effectiveGasPrice or gasPrice cannot be nil or zero")
// ErrEffectiveGasPriceIsZero happens when the calculated EffectiveGasPrice is zero
ErrEffectiveGasPriceIsZero = errors.New("effectiveGasPrice cannot be zero")
)
// EffectiveGasPrice implements the effective gas prices calculations and checks
type EffectiveGasPrice struct {
cfg EffectiveGasPriceCfg
}
// NewEffectiveGasPrice creates and initializes an instance of EffectiveGasPrice
func NewEffectiveGasPrice(cfg EffectiveGasPriceCfg) *EffectiveGasPrice {
if (cfg.EthTransferGasPrice != 0) && (cfg.EthTransferL1GasPriceFactor != 0) {
log.Fatalf("configuration error. Only one of the following config params EthTransferGasPrice or EthTransferL1GasPriceFactor from Pool.effectiveGasPrice section can be set to a value different to 0")
}
return &EffectiveGasPrice{
cfg: cfg,
}
}
// IsEnabled return if effectiveGasPrice calculation is enabled
func (e *EffectiveGasPrice) IsEnabled() bool {
return e.cfg.Enabled
}
// GetFinalDeviation return the value for the config parameter FinalDeviationPct
func (e *EffectiveGasPrice) GetFinalDeviation() uint64 {
return e.cfg.FinalDeviationPct
}
// GetTxAndL2GasPrice return the tx gas price and l2 suggested gas price to use in egp calculations
// If egp is disabled we will use a "simulated" tx and l2 gas price, that is calculated using the L2GasPriceSuggesterFactor config param
func (e *EffectiveGasPrice) GetTxAndL2GasPrice(txGasPrice *big.Int, l1GasPrice uint64, l2GasPrice uint64) (egpTxGasPrice *big.Int, egpL2GasPrice uint64) {
if !e.cfg.Enabled {
// If egp is not enabled we use the L2GasPriceSuggesterFactor to calculate the "simulated" suggested L2 gas price
gp := new(big.Int).SetUint64(uint64(e.cfg.L2GasPriceSuggesterFactor * float64(l1GasPrice)))
return gp, gp.Uint64()
} else {
return txGasPrice, l2GasPrice
}
}
// CalculateBreakEvenGasPrice calculates the break even gas price for a transaction
func (e *EffectiveGasPrice) CalculateBreakEvenGasPrice(rawTx []byte, txGasPrice *big.Int, txGasUsed uint64, l1GasPrice uint64) (*big.Int, error) {
const ethTransferGas = 21000
if l1GasPrice == 0 {
return nil, ErrZeroL1GasPrice
}
if txGasUsed == 0 {
// Returns tx.GasPrice as the breakEvenGasPrice
return txGasPrice, nil
}
// If the tx is a ETH transfer (gas == 21000) then check if we need to return a "fix" effective gas price
if txGasUsed == ethTransferGas {
if e.cfg.EthTransferGasPrice != 0 {
return new(big.Int).SetUint64(e.cfg.EthTransferGasPrice), nil
} else if e.cfg.EthTransferL1GasPriceFactor != 0 {
ethGasPrice := uint64(float64(l1GasPrice) * e.cfg.EthTransferL1GasPriceFactor)
if ethGasPrice == 0 {
ethGasPrice = 1
}
return new(big.Int).SetUint64(ethGasPrice), nil
}
}
// Get L2 Min Gas Price
l2MinGasPrice := uint64(float64(l1GasPrice) * e.cfg.L1GasPriceFactor)
txZeroBytes := uint64(bytes.Count(rawTx, []byte{0}))
txNonZeroBytes := uint64(len(rawTx)) - txZeroBytes + state.EfficiencyPercentageByteLength
// Calculate BreakEvenGasPrice
totalTxPrice := (txGasUsed * l2MinGasPrice) +
((txNonZeroBytes*e.cfg.ByteGasCost)+(txZeroBytes*e.cfg.ZeroByteGasCost))*l1GasPrice
breakEvenGasPrice := new(big.Int).SetUint64(uint64(float64(totalTxPrice/txGasUsed) * e.cfg.NetProfit))
if breakEvenGasPrice.Cmp(new(big.Int).SetUint64(0)) == 0 {
breakEvenGasPrice.SetUint64(1)
}
return breakEvenGasPrice, nil
}
// CalculateEffectiveGasPrice calculates the final effective gas price for a tx
func (e *EffectiveGasPrice) CalculateEffectiveGasPrice(rawTx []byte, txGasPrice *big.Int, txGasUsed uint64, l1GasPrice uint64, l2GasPrice uint64) (*big.Int, error) {
breakEvenGasPrice, err := e.CalculateBreakEvenGasPrice(rawTx, txGasPrice, txGasUsed, l1GasPrice)
if err != nil {
return nil, err
}
bfL2GasPrice := new(big.Float).SetUint64(l2GasPrice)
bfTxGasPrice := new(big.Float).SetInt(txGasPrice)
ratioPriority := new(big.Float).SetFloat64(1.0)
if bfL2GasPrice.Cmp(new(big.Float).SetUint64(0)) == 1 && bfTxGasPrice.Cmp(bfL2GasPrice) == 1 {
//ratioPriority = (txGasPrice / l2GasPrice)
ratioPriority = new(big.Float).Quo(bfTxGasPrice, bfL2GasPrice)
}
bfEffectiveGasPrice := new(big.Float).Mul(new(big.Float).SetInt(breakEvenGasPrice), ratioPriority)
effectiveGasPrice := new(big.Int)
bfEffectiveGasPrice.Int(effectiveGasPrice)
if effectiveGasPrice.Cmp(new(big.Int).SetUint64(0)) == 0 {
return nil, ErrEffectiveGasPriceIsZero
}
return effectiveGasPrice, nil
}
// CalculateEffectiveGasPricePercentage calculates the gas price's effective percentage
func (e *EffectiveGasPrice) CalculateEffectiveGasPricePercentage(gasPrice *big.Int, effectiveGasPrice *big.Int) (uint8, error) {
const bits = 256
var bitsBigInt = big.NewInt(bits)
if effectiveGasPrice == nil || gasPrice == nil ||
gasPrice.Cmp(big.NewInt(0)) == 0 || effectiveGasPrice.Cmp(big.NewInt(0)) == 0 {
return 0, ErrEffectiveGasPriceEmpty
}
if gasPrice.Cmp(effectiveGasPrice) <= 0 {
return state.MaxEffectivePercentage, nil
}
// Simulate Ceil with integer division
b := new(big.Int).Mul(effectiveGasPrice, bitsBigInt)
b = b.Add(b, gasPrice)
b = b.Sub(b, big.NewInt(1)) //nolint:gomnd
b = b.Div(b, gasPrice)
// At this point we have a percentage between 1-256, we need to sub 1 to have it between 0-255 (byte)
b = b.Sub(b, big.NewInt(1)) //nolint:gomnd
return uint8(b.Uint64()), nil
}