@@ -24,6 +24,7 @@ import (
24
24
"strings"
25
25
"time"
26
26
27
+ "github.com/Fantom-foundation/lachesis-base/inter/idx"
27
28
"github.com/davecgh/go-spew/spew"
28
29
"github.com/ethereum/go-ethereum/accounts"
29
30
"github.com/ethereum/go-ethereum/accounts/abi"
@@ -46,8 +47,10 @@ import (
46
47
"github.com/tyler-smith/go-bip39"
47
48
48
49
"github.com/Fantom-foundation/go-opera/evmcore"
50
+ "github.com/Fantom-foundation/go-opera/gossip/gasprice"
49
51
"github.com/Fantom-foundation/go-opera/opera"
50
52
"github.com/Fantom-foundation/go-opera/utils/gsignercache"
53
+ "github.com/Fantom-foundation/go-opera/utils/piecefunc"
51
54
)
52
55
53
56
var (
@@ -84,6 +87,103 @@ func (s *PublicEthereumAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.
84
87
return (* hexutil .Big )(tipcap ), err
85
88
}
86
89
90
+ type feeHistoryResult struct {
91
+ OldestBlock * hexutil.Big `json:"oldestBlock"`
92
+ Reward [][]* hexutil.Big `json:"reward,omitempty"`
93
+ BaseFee []* hexutil.Big `json:"baseFeePerGas,omitempty"`
94
+ GasUsedRatio []float64 `json:"gasUsedRatio"`
95
+ }
96
+
97
+ func scaleGasTip (tip , baseFee * big.Int , ratio uint64 ) * big.Int {
98
+ // max((SuggestedGasTip+minGasPrice)*0.6-minGasPrice, 0)
99
+ min := baseFee
100
+ est := new (big.Int ).Set (tip )
101
+ est .Add (est , min )
102
+ est .Mul (est , new (big.Int ).SetUint64 (ratio ))
103
+ est .Div (est , gasprice .DecimalUnitBn )
104
+ est .Sub (est , min )
105
+ if est .Sign () < 0 {
106
+ return new (big.Int )
107
+ }
108
+
109
+ return est
110
+ }
111
+
112
+ var tipScaleRatio = piecefunc .NewFunc ([]piecefunc.Dot {
113
+ {
114
+ X : 0 ,
115
+ Y : 0.7 * gasprice .DecimalUnit ,
116
+ },
117
+ {
118
+ X : 0.2 * gasprice .DecimalUnit ,
119
+ Y : 1.0 * gasprice .DecimalUnit ,
120
+ },
121
+ {
122
+ X : 0.8 * gasprice .DecimalUnit ,
123
+ Y : 1.2 * gasprice .DecimalUnit ,
124
+ },
125
+ {
126
+ X : 1.0 * gasprice .DecimalUnit ,
127
+ Y : 2.0 * gasprice .DecimalUnit ,
128
+ },
129
+ })
130
+
131
+ var errInvalidPercentile = errors .New ("invalid reward percentile" )
132
+
133
+ func (s * PublicEthereumAPI ) FeeHistory (ctx context.Context , blockCount rpc.DecimalOrHex , lastBlock rpc.BlockNumber , rewardPercentiles []float64 ) (* feeHistoryResult , error ) {
134
+ res := & feeHistoryResult {}
135
+ res .Reward = make ([][]* hexutil.Big , 0 , blockCount )
136
+ res .BaseFee = make ([]* hexutil.Big , 0 , blockCount )
137
+ res .GasUsedRatio = make ([]float64 , 0 , blockCount )
138
+ res .OldestBlock = (* hexutil .Big )(new (big.Int ))
139
+
140
+ // validate input parameters
141
+ if blockCount == 0 {
142
+ return res , nil
143
+ }
144
+ if blockCount > 1024 {
145
+ blockCount = 1024
146
+ }
147
+ for i , p := range rewardPercentiles {
148
+ if p < 0 || p > 100 {
149
+ return nil , fmt .Errorf ("%w: %f" , errInvalidPercentile , p )
150
+ }
151
+ if i > 0 && p < rewardPercentiles [i - 1 ] {
152
+ return nil , fmt .Errorf ("%w: #%d:%f > #%d:%f" , errInvalidPercentile , i - 1 , rewardPercentiles [i - 1 ], i , p )
153
+ }
154
+ }
155
+ last , err := s .b .ResolveRpcBlockNumberOrHash (ctx , rpc.BlockNumberOrHash {BlockNumber : & lastBlock })
156
+ if err != nil {
157
+ return nil , err
158
+ }
159
+ oldest := last
160
+ if oldest > idx .Block (blockCount ) {
161
+ oldest -= idx .Block (blockCount - 1 )
162
+ } else {
163
+ oldest = 0
164
+ }
165
+
166
+ baseFee := s .b .MinGasPrice ()
167
+ goldTip , err := s .b .SuggestGasTipCap (ctx )
168
+ if err != nil {
169
+ return nil , err
170
+ }
171
+
172
+ tips := make ([]* hexutil.Big , 0 , len (rewardPercentiles ))
173
+ for _ , p := range rewardPercentiles {
174
+ ratio := tipScaleRatio (uint64 (gasprice .DecimalUnit * p / 100.0 ))
175
+ scaledTip := scaleGasTip (goldTip , baseFee , ratio )
176
+ tips = append (tips , (* hexutil .Big )(scaledTip ))
177
+ }
178
+ res .OldestBlock .ToInt ().SetUint64 (uint64 (oldest ))
179
+ for i := uint64 (0 ); i < uint64 (last - oldest + 1 ); i ++ {
180
+ res .Reward = append (res .Reward , tips )
181
+ res .BaseFee = append (res .BaseFee , (* hexutil .Big )(baseFee ))
182
+ res .GasUsedRatio = append (res .GasUsedRatio , 0.99 )
183
+ }
184
+ return res , nil
185
+ }
186
+
87
187
// Syncing returns true if node is syncing
88
188
func (s * PublicEthereumAPI ) Syncing () (interface {}, error ) {
89
189
progress := s .b .Progress ()
0 commit comments