193 lines
6.1 KiB
Go
193 lines
6.1 KiB
Go
package itests
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"sort"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/filecoin-project/go-jsonrpc"
|
|
"github.com/filecoin-project/go-state-types/abi"
|
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
|
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
|
"github.com/filecoin-project/lotus/itests/kit"
|
|
"github.com/filecoin-project/lotus/lib/result"
|
|
"github.com/filecoin-project/lotus/node/impl/full"
|
|
)
|
|
|
|
// calculateExpectations calculates the expected number of items to be included in the response
|
|
// of eth_feeHistory. It takes care of null rounds by finding the closet tipset with height
|
|
// smaller than startHeight, and then looks back at requestAmount of items. It also considers
|
|
// scenarios where there are not enough items to look back.
|
|
func calculateExpectations(tsHeights []int, requestAmount, startHeight int) (count, oldestHeight int) {
|
|
latestIdx := sort.SearchInts(tsHeights, startHeight)
|
|
// SearchInts returns the index of the number that's larger than the target if the target
|
|
// doesn't exist. However, we're looking for the closet number that's smaller that the target
|
|
for tsHeights[latestIdx] > startHeight {
|
|
latestIdx--
|
|
}
|
|
cnt := requestAmount
|
|
oldestIdx := latestIdx - requestAmount + 1
|
|
if oldestIdx < 0 {
|
|
cnt = latestIdx + 1
|
|
oldestIdx = 0
|
|
}
|
|
return cnt, tsHeights[oldestIdx]
|
|
}
|
|
|
|
func TestEthFeeHistory(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
kit.QuietAllLogsExcept()
|
|
|
|
blockTime := 100 * time.Millisecond
|
|
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
|
defer cancel()
|
|
|
|
miner := ens.InterconnectAll().BeginMining(blockTime)
|
|
|
|
client.WaitTillChain(ctx, kit.HeightAtLeast(7))
|
|
miner[0].InjectNulls(abi.ChainEpoch(5))
|
|
|
|
// Wait for the network to create at least 20 tipsets
|
|
client.WaitTillChain(ctx, kit.HeightAtLeast(20))
|
|
for _, m := range miner {
|
|
m.Pause()
|
|
}
|
|
|
|
ch, err := client.ChainNotify(ctx)
|
|
require.NoError(err)
|
|
|
|
// Wait for 5 seconds of inactivity
|
|
func() {
|
|
for {
|
|
select {
|
|
case <-ch:
|
|
continue
|
|
case <-time.After(5 * time.Second):
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
currTs, err := client.ChainHead(ctx)
|
|
require.NoError(err)
|
|
|
|
var tsHeights []int
|
|
for currTs.Height() != 0 {
|
|
tsHeights = append(tsHeights, int(currTs.Height()))
|
|
currTs, err = client.ChainGetTipSet(ctx, currTs.Parents())
|
|
require.NoError(err)
|
|
}
|
|
|
|
sort.Ints(tsHeights)
|
|
|
|
// because of the deferred execution, the last tipset is not executed yet,
|
|
// and the one before the last one is the last executed tipset,
|
|
// which corresponds to the "latest" tag in EthGetBlockByNumber
|
|
latestBlk := ethtypes.EthUint64(tsHeights[len(tsHeights)-2])
|
|
blk, err := client.EthGetBlockByNumber(ctx, "latest", false)
|
|
require.NoError(err)
|
|
require.Equal(blk.Number, latestBlk)
|
|
|
|
assertHistory := func(history *ethtypes.EthFeeHistory, requestAmount, startHeight int) {
|
|
amount, oldest := calculateExpectations(tsHeights, requestAmount, startHeight)
|
|
require.Equal(amount+1, len(history.BaseFeePerGas))
|
|
require.Equal(amount, len(history.GasUsedRatio))
|
|
require.Equal(ethtypes.EthUint64(oldest), history.OldestBlock)
|
|
}
|
|
|
|
history, err := client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
|
json.Marshal([]interface{}{5, "0x10"}),
|
|
).Assert(require.NoError))
|
|
require.NoError(err)
|
|
assertHistory(&history, 5, 16)
|
|
require.Nil(history.Reward)
|
|
|
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
|
json.Marshal([]interface{}{"5", "0x10"}),
|
|
).Assert(require.NoError))
|
|
require.NoError(err)
|
|
assertHistory(&history, 5, 16)
|
|
require.Nil(history.Reward)
|
|
|
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
|
json.Marshal([]interface{}{5, "latest"}),
|
|
).Assert(require.NoError))
|
|
require.NoError(err)
|
|
assertHistory(&history, 5, int(latestBlk))
|
|
require.Nil(history.Reward)
|
|
|
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
|
json.Marshal([]interface{}{"0x10", "0x12"}),
|
|
).Assert(require.NoError))
|
|
require.NoError(err)
|
|
assertHistory(&history, 16, 18)
|
|
require.Nil(history.Reward)
|
|
|
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
|
json.Marshal([]interface{}{5, "0x10"}),
|
|
).Assert(require.NoError))
|
|
require.NoError(err)
|
|
assertHistory(&history, 5, 16)
|
|
require.Nil(history.Reward)
|
|
|
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
|
json.Marshal([]interface{}{5, "10"}),
|
|
).Assert(require.NoError))
|
|
require.NoError(err)
|
|
assertHistory(&history, 5, 10)
|
|
require.Nil(history.Reward)
|
|
|
|
// test when the requested number of blocks is longer than chain length
|
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
|
json.Marshal([]interface{}{"0x30", "latest"}),
|
|
).Assert(require.NoError))
|
|
require.NoError(err)
|
|
assertHistory(&history, 48, int(latestBlk))
|
|
require.Nil(history.Reward)
|
|
|
|
// test when the requested number of blocks is longer than chain length
|
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
|
json.Marshal([]interface{}{"0x30", "10"}),
|
|
).Assert(require.NoError))
|
|
require.NoError(err)
|
|
assertHistory(&history, 48, 10)
|
|
require.Nil(history.Reward)
|
|
|
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
|
json.Marshal([]interface{}{5, "10", &[]float64{25, 50, 75}}),
|
|
).Assert(require.NoError))
|
|
require.NoError(err)
|
|
assertHistory(&history, 5, 10)
|
|
require.NotNil(history.Reward)
|
|
require.Equal(5, len(*history.Reward))
|
|
for _, arr := range *history.Reward {
|
|
require.Equal(3, len(arr))
|
|
for _, item := range arr {
|
|
require.Equal(ethtypes.EthBigInt(types.NewInt(full.MinGasPremium)), item)
|
|
}
|
|
}
|
|
|
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
|
json.Marshal([]interface{}{1025, "10", &[]float64{25, 50, 75}}),
|
|
).Assert(require.NoError))
|
|
require.Error(err)
|
|
|
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
|
json.Marshal([]interface{}{5, "10", &[]float64{75, 50}}),
|
|
).Assert(require.NoError))
|
|
require.Error(err)
|
|
|
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
|
json.Marshal([]interface{}{5, "10", &[]float64{}}),
|
|
).Assert(require.NoError))
|
|
require.NoError(err)
|
|
}
|