prysm-pulse/beacon-chain/powchain/block_reader_test.go
Ivan Martinez 159ef3d702
Add cache to Eth1 RPC functions (#5347)
* ADd cache to other function and add comment

* Add cache for eth1data

* Fix test

* Reset cache before test

* Move cache to beacon node end

* Add metrics

* Disable blocktimebyheight cache

* Fix time
2020-04-09 14:29:09 -05:00

273 lines
7.6 KiB
Go

package powchain
import (
"bytes"
"context"
"math/big"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
gethTypes "github.com/ethereum/go-ethereum/core/types"
dbutil "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
contracts "github.com/prysmaticlabs/prysm/contracts/deposit-contract"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
)
var endpoint = "ws://127.0.0.1"
func setDefaultMocks(service *Service) *Service {
service.reader = &goodReader{}
service.blockFetcher = &goodFetcher{}
service.logger = &goodLogger{}
service.httpLogger = &goodLogger{}
service.stateNotifier = &goodNotifier{}
return service
}
func TestLatestMainchainInfo_OK(t *testing.T) {
testAcc, err := contracts.Setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
}
beaconDB := dbutil.SetupDB(t)
defer dbutil.TeardownDB(t, beaconDB)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
ETH1Endpoint: endpoint,
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
web3Service = setDefaultMocks(web3Service)
web3Service.rpcClient = &mockPOW.RPCClient{Backend: testAcc.Backend}
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
if err != nil {
t.Fatal(err)
}
testAcc.Backend.Commit()
exitRoutine := make(chan bool)
go func() {
web3Service.run(web3Service.ctx.Done())
<-exitRoutine
}()
header := &gethTypes.Header{
Number: big.NewInt(42),
Time: 308534400,
}
web3Service.headerChan <- header
web3Service.cancel()
exitRoutine <- true
if web3Service.latestEth1Data.BlockHeight != header.Number.Uint64() {
t.Errorf("block number not set, expected %v, got %v", header.Number, web3Service.latestEth1Data.BlockHeight)
}
if hexutil.Encode(web3Service.latestEth1Data.BlockHash) != header.Hash().Hex() {
t.Errorf("block hash not set, expected %v, got %#x", header.Hash().Hex(), web3Service.latestEth1Data.BlockHash)
}
if web3Service.latestEth1Data.BlockTime != header.Time {
t.Errorf("block time not set, expected %v, got %v", time.Unix(int64(header.Time), 0), web3Service.latestEth1Data.BlockTime)
}
blockInfoExistsInCache, info, err := web3Service.blockCache.BlockInfoByHash(bytesutil.ToBytes32(web3Service.latestEth1Data.BlockHash))
if err != nil {
t.Fatal(err)
}
if !blockInfoExistsInCache {
t.Error("Expected block info to exist in cache")
}
if info.Hash != bytesutil.ToBytes32(web3Service.latestEth1Data.BlockHash) {
t.Errorf(
"Expected block info hash to be %v, got %v",
bytesutil.ToBytes32(web3Service.latestEth1Data.BlockHash),
info.Hash,
)
}
}
func TestBlockHashByHeight_ReturnsHash(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
defer dbutil.TeardownDB(t, beaconDB)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
ETH1Endpoint: endpoint,
BeaconDB: beaconDB,
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
web3Service = setDefaultMocks(web3Service)
ctx := context.Background()
block := gethTypes.NewBlock(
&gethTypes.Header{
Number: big.NewInt(15),
Time: 150,
},
[]*gethTypes.Transaction{},
[]*gethTypes.Header{},
[]*gethTypes.Receipt{},
)
wanted := block.Hash()
hash, err := web3Service.BlockHashByHeight(ctx, big.NewInt(0))
if err != nil {
t.Fatalf("Could not get block hash with given height %v", err)
}
if !bytes.Equal(hash.Bytes(), wanted.Bytes()) {
t.Fatalf("Block hash did not equal expected hash, expected: %v, got: %v", wanted, hash)
}
exists, _, err := web3Service.blockCache.BlockInfoByHash(wanted)
if err != nil {
t.Fatal(err)
}
if !exists {
t.Error("Expected block info to be cached")
}
}
func TestBlockExists_ValidHash(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
defer dbutil.TeardownDB(t, beaconDB)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
ETH1Endpoint: endpoint,
BeaconDB: beaconDB,
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
web3Service = setDefaultMocks(web3Service)
block := gethTypes.NewBlock(
&gethTypes.Header{
Number: big.NewInt(0),
},
[]*gethTypes.Transaction{},
[]*gethTypes.Header{},
[]*gethTypes.Receipt{},
)
exists, height, err := web3Service.BlockExists(context.Background(), block.Hash())
if err != nil {
t.Fatalf("Could not get block hash with given height %v", err)
}
if !exists {
t.Fatal("Expected BlockExists to return true.")
}
if height.Cmp(block.Number()) != 0 {
t.Fatalf("Block height did not equal expected height, expected: %v, got: %v", big.NewInt(42), height)
}
exists, _, err = web3Service.blockCache.BlockInfoByHeight(height)
if err != nil {
t.Fatal(err)
}
if !exists {
t.Error("Expected block to be cached")
}
}
func TestBlockExists_InvalidHash(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
defer dbutil.TeardownDB(t, beaconDB)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
ETH1Endpoint: endpoint,
BeaconDB: beaconDB,
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
web3Service = setDefaultMocks(web3Service)
_, _, err = web3Service.BlockExists(context.Background(), common.BytesToHash([]byte{0}))
if err == nil {
t.Fatal("Expected BlockExists to error with invalid hash")
}
}
func TestBlockExists_UsesCachedBlockInfo(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
defer dbutil.TeardownDB(t, beaconDB)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
ETH1Endpoint: endpoint,
BeaconDB: beaconDB,
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
// nil blockFetcher would panic if cached value not used
web3Service.blockFetcher = nil
block := gethTypes.NewBlock(
&gethTypes.Header{
Number: big.NewInt(0),
},
[]*gethTypes.Transaction{},
[]*gethTypes.Header{},
[]*gethTypes.Receipt{},
)
if err := web3Service.blockCache.AddBlock(block); err != nil {
t.Fatal(err)
}
exists, height, err := web3Service.BlockExists(context.Background(), block.Hash())
if err != nil {
t.Fatalf("Could not get block hash with given height %v", err)
}
if !exists {
t.Fatal("Expected BlockExists to return true.")
}
if height.Cmp(block.Number()) != 0 {
t.Fatalf("Block height did not equal expected height, expected: %v, got: %v", big.NewInt(42), height)
}
}
func TestBlockNumberByTimestamp(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
defer dbutil.TeardownDB(t, beaconDB)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
ETH1Endpoint: endpoint,
BeaconDB: beaconDB,
})
if err != nil {
t.Fatal(err)
}
web3Service = setDefaultMocks(web3Service)
web3Service.client = nil
if cachedEth1VotingStartTime != 0 {
t.Fatalf("Expected cached result to be 0 initially, received %d", cachedEth1VotingStartTime)
}
ctx := context.Background()
bn, err := web3Service.BlockNumberByTimestamp(ctx, 150000 /* time */)
if err != nil {
t.Fatal(err)
}
if bn.Cmp(big.NewInt(0)) == 0 {
t.Error("Returned a block with zero number, expected to be non zero")
}
if cachedEth1VotingStartTime != 150000 {
t.Errorf("Expected cached voting start time to be equal to request, expected: %d, received: %d", 150000, cachedEth1VotingStartTime)
}
if bn.Cmp(cachedEth1DataBlockHeight) != 0 {
t.Errorf("Expected cached block height to be equal to result, expected: %d, received: %d", bn, cachedEth1DataBlockHeight)
}
}