@@ -24,6 +24,7 @@ import (
2424 "strings"
2525 "time"
2626
27+ "github.com/Fantom-foundation/lachesis-base/inter/idx"
2728 "github.com/davecgh/go-spew/spew"
2829 "github.com/ethereum/go-ethereum/accounts"
2930 "github.com/ethereum/go-ethereum/accounts/abi"
@@ -46,8 +47,10 @@ import (
4647 "github.com/tyler-smith/go-bip39"
4748
4849 "github.com/Fantom-foundation/go-opera/evmcore"
50+ "github.com/Fantom-foundation/go-opera/gossip/gasprice"
4951 "github.com/Fantom-foundation/go-opera/opera"
5052 "github.com/Fantom-foundation/go-opera/utils/gsignercache"
53+ "github.com/Fantom-foundation/go-opera/utils/piecefunc"
5154)
5255
5356var (
@@ -84,6 +87,103 @@ func (s *PublicEthereumAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.
8487 return (* hexutil .Big )(tipcap ), err
8588}
8689
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+
87187// Syncing returns true if node is syncing
88188func (s * PublicEthereumAPI ) Syncing () (interface {}, error ) {
89189 progress := s .b .Progress ()
0 commit comments