prysm-pulse/beacon-chain/powchain/log_processing_test.go
Raul Jordan cc741ed8af
Ensure New State Type Tests Pass in Prysm (#4646)
* begin state service

* begin on the state trie idea

* created beacon state structure

* add in the full clone getter

* return by value instead

* add all setters

* new state setters are being completed

* arrays roots exposed

*  close to finishing all these headerssss

* functionality complete

* added in proto benchmark test

* test for compatibility

* add test for compat

* comments fixed

* add clone

* add clone

* remove underlying copies

* make it immutable

* integrate it into chainservice

* revert

* wrap up comments for package

* address all comments and godocs

* address all comments

* clone the pending attestation properly

* properly clone remaining items

* tests pass fixed bug

* begin using it instead of head state

* prevent nil pointer exceptions

* begin using new struct in db

* integrated new type into db package

* add proper nil checks

* using new state in archiver

* refactored much of core

* editing all the precompute functions

* done with most core refactor

* fixed up some bugs in the clone comparisons

* append current epoch atts

* add missing setters

* add new setters

* fix other core methods

* fix up transition

* main service and forkchoice

* fix rpc

* integrated to powchain

* some more changes

* fix build

* improve processing of deposits

* fix error

* prevent panic

* comment

* fix process att

* gaz

* fix up att process

* resolve existing review comments

* resolve another batch of gh comments

* resolve broken cpt state

* revise testutil to use the new state

* begin updating the state transition func to pass in more compartmentalized args

* finish editing transition function to return errors

* block operations pretty much done with refactor

* state transition fully refactored

* got epoch processing completed

* fix build in fork choice

* fixing more of the build

* fix up broken sync package

* it builds nowww it buildssss

* revert registry changes

* Recompute on Read (#4627)

* compute on read

* fix up eth1 data votes

* looking into slashings bug introduced in core/

* able to advance more slots

* add logging

* can now sync with testnet yay

* remove the leaves algorithm and other merkle imports

* expose initialize unsafe funcs

* Update beacon-chain/db/kv/state.go

* lint

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* More Optimizations for New State (#4641)

* map optimization

* more optimizations

* use a custom hasher

* comment

* block operations optimizations

* Update beacon-chain/state/types.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* fixed up various operations to use the validator index map access

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* archiver tests pass

* fixing cache tests

* cache tests passing

* edited validator tests

* powchain tests passing

* halfway thru sync tests

* more sync test fixes

* add in tests for state/

* working through rpc tests

* assignments tests passed

* almost done with rpc/beacon tests

* resolved painful validator test

* fixed up even more tests

* resolve tests

* fix build

* reduce a randao mixes copy

* fixes under //beacon-chain/blockchain/...

* build //beacon-chain/core/...

* fixes

* Runtime Optimizations (#4648)

* parallelize shuffling

* clean up

* lint

* fix build

* use callback to read from registry

* fix array roots and size map

* new improvements

* reduce hash allocs

* improved shuffling

* terence's review

* use different method

* raul's comment

* new array roots

* remove clone in pre-compute

* Update beacon-chain/state/types.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* raul's review

* lint

* fix build issues

* fix visibility

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* fix visibility

* build works for all

* fix blockchain test

* fix a few tests

* fix more tests

* update validator in slashing

* archiver passing

* fixed rpc/validator

* progress on core tests

* resolve broken rpc tests

* blockchain tests passed

* fix up some tests in core

* fix message diff

* remove unnecessary save

* Save validator after slashing

* Update validators one by one

* another update

* fix everything

* fix more precompute tests

* fix blocks tests

* more elegant fix

* more helper fixes

* change back ?

* fix test

* fix skip slot

* fix test

* reset caches

* fix testutil

* raceoff fixed

* passing

* Retrieve cached state in the beginning

* lint

* Fixed tests part 1

* Fixed rest of the tests

* Minor changes to avoid copying, small refactor to reduce deplicated code

* Handle att req for slot 0

* New beacon state: Only populate merkle layers as needed, copy merkle layers on copy/clone. (#4689)

* Only populate merkle layers as needed, copy merkle layers on copy/clone.

* use custom copy

* Make maps of correct size

* slightly fast, doesn't wait for lock

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>

* Target root can't be 0x00

* Don't use cache for current slot (may not be the right fix)

* fixed up tests

* Remove some copy for init sync. Not sure if it is safe enough for runtime though... testing...

* Align with prev logic for process slots cachedState.Slot() < slot

* Fix Initial Sync Flag (#4692)

* fixes

* fix up some test failures due to lack of nil checks

* fix up some test failures due to lack of nil checks

* fix up imports

* revert some changes

* imports

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* resolving further conflicts

* Better skip slot cache (#4694)

* Return copy of skip slot cache state, disable skip slot cache on sync

* fix

* Fix pruning

* fix up issues with broken tests

Co-authored-by: Nishant Das <nish1993@hotmail.com>
Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
Co-authored-by: shayzluf <thezluf@gmail.com>
Co-authored-by: terence tsao <terence@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2020-01-31 12:57:01 -08:00

747 lines
24 KiB
Go

package powchain
import (
"bytes"
"context"
"encoding/binary"
"io/ioutil"
"math/big"
"testing"
"time"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
gethTypes "github.com/ethereum/go-ethereum/core/types"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
"github.com/prysmaticlabs/prysm/beacon-chain/db"
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/flags"
mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
contracts "github.com/prysmaticlabs/prysm/contracts/deposit-contract"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
"github.com/prysmaticlabs/prysm/shared/trieutil"
"github.com/sirupsen/logrus"
logTest "github.com/sirupsen/logrus/hooks/test"
"gopkg.in/d4l3k/messagediff.v1"
)
func init() {
logrus.SetLevel(logrus.DebugLevel)
logrus.SetOutput(ioutil.Discard)
}
func TestProcessDepositLog_OK(t *testing.T) {
hook := logTest.NewGlobal()
testutil.ResetCache()
testAcc, err := contracts.Setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
}
beaconDB := testDB.SetupDB(t)
defer testDB.TeardownDB(t, beaconDB)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
ETH1Endpoint: endpoint,
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
DepositCache: depositcache.NewDepositCache(),
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
if err != nil {
t.Fatal(err)
}
testAcc.Backend.Commit()
deposits, _, _ := testutil.DeterministicDepositsAndKeys(1)
_, depositRoots, err := testutil.DeterministicDepositTrie(len(deposits))
if err != nil {
t.Fatal(err)
}
data := deposits[0].Data
testAcc.TxOpts.Value = contracts.Amount32Eth()
testAcc.TxOpts.GasLimit = 1000000
if _, err := testAcc.Contract.Deposit(testAcc.TxOpts, data.PublicKey, data.WithdrawalCredentials, data.Signature, depositRoots[0]); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}
testAcc.Backend.Commit()
query := ethereum.FilterQuery{
Addresses: []common.Address{
web3Service.depositContractAddress,
},
}
logs, err := testAcc.Backend.FilterLogs(web3Service.ctx, query)
if err != nil {
t.Fatalf("Unable to retrieve logs %v", err)
}
if len(logs) == 0 {
t.Fatal("no logs")
}
web3Service.ProcessLog(context.Background(), logs[0])
testutil.AssertLogsDoNotContain(t, hook, "Could not unpack log")
testutil.AssertLogsDoNotContain(t, hook, "Could not save in trie")
testutil.AssertLogsDoNotContain(t, hook, "could not deserialize validator public key")
testutil.AssertLogsDoNotContain(t, hook, "could not convert bytes to signature")
testutil.AssertLogsDoNotContain(t, hook, "could not sign root for deposit data")
testutil.AssertLogsDoNotContain(t, hook, "deposit signature did not verify")
testutil.AssertLogsDoNotContain(t, hook, "could not tree hash deposit data")
testutil.AssertLogsDoNotContain(t, hook, "deposit merkle branch of deposit root did not verify for root")
testutil.AssertLogsContain(t, hook, "Deposit registered from deposit contract")
hook.Reset()
}
func TestProcessDepositLog_InsertsPendingDeposit(t *testing.T) {
hook := logTest.NewGlobal()
testAcc, err := contracts.Setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
}
beaconDB := testDB.SetupDB(t)
defer testDB.TeardownDB(t, beaconDB)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
ETH1Endpoint: endpoint,
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
DepositCache: depositcache.NewDepositCache(),
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
if err != nil {
t.Fatal(err)
}
testAcc.Backend.Commit()
deposits, _, _ := testutil.DeterministicDepositsAndKeys(1)
_, depositRoots, err := testutil.DeterministicDepositTrie(len(deposits))
if err != nil {
t.Fatal(err)
}
data := deposits[0].Data
testAcc.TxOpts.Value = contracts.Amount32Eth()
testAcc.TxOpts.GasLimit = 1000000
if _, err := testAcc.Contract.Deposit(testAcc.TxOpts, data.PublicKey, data.WithdrawalCredentials, data.Signature, depositRoots[0]); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}
if _, err := testAcc.Contract.Deposit(testAcc.TxOpts, data.PublicKey, data.WithdrawalCredentials, data.Signature, depositRoots[0]); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}
testAcc.Backend.Commit()
query := ethereum.FilterQuery{
Addresses: []common.Address{
web3Service.depositContractAddress,
},
}
logs, err := testAcc.Backend.FilterLogs(web3Service.ctx, query)
if err != nil {
t.Fatalf("Unable to retrieve logs %v", err)
}
web3Service.chainStartData.Chainstarted = true
web3Service.ProcessDepositLog(context.Background(), logs[0])
web3Service.ProcessDepositLog(context.Background(), logs[1])
pendingDeposits := web3Service.depositCache.PendingDeposits(context.Background(), nil /*blockNum*/)
if len(pendingDeposits) != 2 {
t.Errorf("Unexpected number of deposits. Wanted 2 deposit, got %+v", pendingDeposits)
}
hook.Reset()
}
func TestUnpackDepositLogData_OK(t *testing.T) {
testAcc, err := contracts.Setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
}
beaconDB := testDB.SetupDB(t)
defer testDB.TeardownDB(t, beaconDB)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
ETH1Endpoint: endpoint,
BeaconDB: beaconDB,
DepositContract: testAcc.ContractAddr,
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
if err != nil {
t.Fatal(err)
}
testAcc.Backend.Commit()
if err := web3Service.initDataFromContract(); err != nil {
t.Fatalf("Could not init from contract: %v", err)
}
deposits, _, _ := testutil.DeterministicDepositsAndKeys(1)
_, depositRoots, err := testutil.DeterministicDepositTrie(len(deposits))
if err != nil {
t.Fatal(err)
}
data := deposits[0].Data
testAcc.TxOpts.Value = contracts.Amount32Eth()
testAcc.TxOpts.GasLimit = 1000000
if _, err := testAcc.Contract.Deposit(testAcc.TxOpts, data.PublicKey, data.WithdrawalCredentials, data.Signature, depositRoots[0]); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}
testAcc.Backend.Commit()
query := ethereum.FilterQuery{
Addresses: []common.Address{
web3Service.depositContractAddress,
},
}
logz, err := testAcc.Backend.FilterLogs(web3Service.ctx, query)
if err != nil {
t.Fatalf("Unable to retrieve logs %v", err)
}
loggedPubkey, withCreds, _, loggedSig, index, err := contracts.UnpackDepositLogData(logz[0].Data)
if err != nil {
t.Fatalf("Unable to unpack logs %v", err)
}
if binary.LittleEndian.Uint64(index) != 0 {
t.Errorf("Retrieved merkle tree index is incorrect %d", index)
}
if !bytes.Equal(loggedPubkey, data.PublicKey) {
t.Errorf("Pubkey is not the same as the data that was put in %v", loggedPubkey)
}
if !bytes.Equal(loggedSig, data.Signature) {
t.Errorf("Proof of Possession is not the same as the data that was put in %v", loggedSig)
}
if !bytes.Equal(withCreds, data.WithdrawalCredentials) {
t.Errorf("Withdrawal Credentials is not the same as the data that was put in %v", withCreds)
}
}
func TestProcessETH2GenesisLog_8DuplicatePubkeys(t *testing.T) {
hook := logTest.NewGlobal()
testAcc, err := contracts.Setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
}
beaconDB := testDB.SetupDB(t)
defer testDB.TeardownDB(t, beaconDB)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
ETH1Endpoint: endpoint,
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
DepositCache: depositcache.NewDepositCache(),
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
if err != nil {
t.Fatal(err)
}
bConfig := params.MinimalSpecConfig()
bConfig.MinGenesisTime = 0
params.OverrideBeaconConfig(bConfig)
testAcc.Backend.Commit()
testAcc.Backend.AdjustTime(time.Duration(int64(time.Now().Nanosecond())))
deposits, _, _ := testutil.DeterministicDepositsAndKeys(1)
_, depositRoots, err := testutil.DeterministicDepositTrie(len(deposits))
if err != nil {
t.Fatal(err)
}
data := deposits[0].Data
testAcc.TxOpts.Value = contracts.Amount32Eth()
testAcc.TxOpts.GasLimit = 1000000
// 64 Validators are used as size required for beacon-chain to start. This number
// is defined in the deposit contract as the number required for the testnet. The actual number
// is 2**14
for i := 0; i < depositsReqForChainStart; i++ {
testAcc.TxOpts.Value = contracts.Amount32Eth()
if _, err := testAcc.Contract.Deposit(testAcc.TxOpts, data.PublicKey, data.WithdrawalCredentials, data.Signature, depositRoots[0]); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}
testAcc.Backend.Commit()
}
query := ethereum.FilterQuery{
Addresses: []common.Address{
web3Service.depositContractAddress,
},
}
logs, err := testAcc.Backend.FilterLogs(web3Service.ctx, query)
if err != nil {
t.Fatalf("Unable to retrieve logs %v", err)
}
for _, log := range logs {
web3Service.ProcessLog(context.Background(), log)
}
if web3Service.chainStartData.Chainstarted {
t.Error("Genesis has been triggered despite being 8 duplicate keys")
}
testutil.AssertLogsDoNotContain(t, hook, "Minimum number of validators reached for beacon-chain to start")
hook.Reset()
}
func TestProcessETH2GenesisLog(t *testing.T) {
config := &featureconfig.Flags{
CustomGenesisDelay: 0,
}
featureconfig.Init(config)
hook := logTest.NewGlobal()
testAcc, err := contracts.Setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
}
beaconDB := testDB.SetupDB(t)
defer testDB.TeardownDB(t, beaconDB)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
ETH1Endpoint: endpoint,
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
DepositCache: depositcache.NewDepositCache(),
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
if err != nil {
t.Fatal(err)
}
bConfig := params.MinimalSpecConfig()
bConfig.MinGenesisTime = 0
params.OverrideBeaconConfig(bConfig)
testAcc.Backend.Commit()
testAcc.Backend.AdjustTime(time.Duration(int64(time.Now().Nanosecond())))
deposits, _, _ := testutil.DeterministicDepositsAndKeys(uint64(depositsReqForChainStart))
_, roots, err := testutil.DeterministicDepositTrie(len(deposits))
if err != nil {
t.Fatal(err)
}
// 64 Validators are used as size required for beacon-chain to start. This number
// is defined in the deposit contract as the number required for the testnet. The actual number
// is 2**14
for i := 0; i < depositsReqForChainStart; i++ {
data := deposits[i].Data
testAcc.TxOpts.Value = contracts.Amount32Eth()
testAcc.TxOpts.GasLimit = 1000000
if _, err := testAcc.Contract.Deposit(testAcc.TxOpts, data.PublicKey, data.WithdrawalCredentials, data.Signature, roots[i]); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}
testAcc.Backend.Commit()
}
query := ethereum.FilterQuery{
Addresses: []common.Address{
web3Service.depositContractAddress,
},
}
logs, err := testAcc.Backend.FilterLogs(web3Service.ctx, query)
if err != nil {
t.Fatalf("Unable to retrieve logs %v", err)
}
if len(logs) != depositsReqForChainStart {
t.Fatalf(
"Did not receive enough logs, received %d, wanted %d",
len(logs),
depositsReqForChainStart,
)
}
// Set up our subscriber now to listen for the chain started event.
stateChannel := make(chan *feed.Event, 1)
stateSub := web3Service.stateNotifier.StateFeed().Subscribe(stateChannel)
defer stateSub.Unsubscribe()
for _, log := range logs {
web3Service.ProcessLog(context.Background(), log)
}
err = web3Service.ProcessETH1Block(context.Background(), big.NewInt(int64(logs[len(logs)-1].BlockNumber)))
if err != nil {
t.Fatal(err)
}
cachedDeposits := web3Service.ChainStartDeposits()
if len(cachedDeposits) != depositsReqForChainStart {
t.Fatalf(
"Did not cache the chain start deposits correctly, received %d, wanted %d",
len(cachedDeposits),
depositsReqForChainStart,
)
}
// Receive the chain started event.
for started := false; !started; {
select {
case event := <-stateChannel:
if event.Type == statefeed.ChainStarted {
started = true
}
}
}
testutil.AssertLogsDoNotContain(t, hook, "Unable to unpack ChainStart log data")
testutil.AssertLogsDoNotContain(t, hook, "Receipt root from log doesn't match the root saved in memory")
testutil.AssertLogsDoNotContain(t, hook, "Invalid timestamp from log")
testutil.AssertLogsContain(t, hook, "Minimum number of validators reached for beacon-chain to start")
hook.Reset()
}
func TestProcessETH2GenesisLog_CorrectNumOfDeposits(t *testing.T) {
hook := logTest.NewGlobal()
testAcc, err := contracts.Setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
}
kvStore := testDB.SetupDB(t)
defer testDB.TeardownDB(t, kvStore)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
ETH1Endpoint: endpoint,
DepositContract: testAcc.ContractAddr,
BeaconDB: kvStore,
DepositCache: depositcache.NewDepositCache(),
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
if err != nil {
t.Fatal(err)
}
web3Service.rpcClient = &mockPOW.RPCClient{Backend: testAcc.Backend}
web3Service.httpLogger = testAcc.Backend
web3Service.latestEth1Data.LastRequestedBlock = 0
web3Service.latestEth1Data.BlockHeight = 0
bConfig := params.MinimalSpecConfig()
bConfig.MinGenesisTime = 0
params.OverrideBeaconConfig(bConfig)
flags.Get().DeploymentBlock = 0
testAcc.Backend.Commit()
testAcc.Backend.AdjustTime(time.Duration(int64(time.Now().Nanosecond())))
totalNumOfDeposits := depositsReqForChainStart + 30
deposits, _, _ := testutil.DeterministicDepositsAndKeys(uint64(totalNumOfDeposits))
_, depositRoots, err := testutil.DeterministicDepositTrie(len(deposits))
if err != nil {
t.Fatal(err)
}
depositOffset := 5
// 64 Validators are used as size required for beacon-chain to start. This number
// is defined in the deposit contract as the number required for the testnet. The actual number
// is 2**14
for i := 0; i < totalNumOfDeposits; i++ {
data := deposits[i].Data
testAcc.TxOpts.Value = contracts.Amount32Eth()
testAcc.TxOpts.GasLimit = 1000000
if _, err := testAcc.Contract.Deposit(testAcc.TxOpts, data.PublicKey, data.WithdrawalCredentials, data.Signature, depositRoots[i]); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}
// pack 8 deposits into a block with an offset of
// 5
if (i+1)%8 == depositOffset {
testAcc.Backend.Commit()
}
}
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
// Set up our subscriber now to listen for the chain started event.
stateChannel := make(chan *feed.Event, 1)
stateSub := web3Service.stateNotifier.StateFeed().Subscribe(stateChannel)
defer stateSub.Unsubscribe()
err = web3Service.processPastLogs(context.Background())
if err != nil {
t.Fatal(err)
}
cachedDeposits := web3Service.ChainStartDeposits()
requiredDepsForChainstart := depositsReqForChainStart + depositOffset
if len(cachedDeposits) != requiredDepsForChainstart {
t.Fatalf(
"Did not cache the chain start deposits correctly, received %d, wanted %d",
len(cachedDeposits),
requiredDepsForChainstart,
)
}
// Receive the chain started event.
for started := false; !started; {
select {
case event := <-stateChannel:
if event.Type == statefeed.ChainStarted {
started = true
}
}
}
testutil.AssertLogsDoNotContain(t, hook, "Unable to unpack ChainStart log data")
testutil.AssertLogsDoNotContain(t, hook, "Receipt root from log doesn't match the root saved in memory")
testutil.AssertLogsDoNotContain(t, hook, "Invalid timestamp from log")
testutil.AssertLogsContain(t, hook, "Minimum number of validators reached for beacon-chain to start")
hook.Reset()
}
func TestWeb3ServiceProcessDepositLog_RequestMissedDeposits(t *testing.T) {
hook := logTest.NewGlobal()
testAcc, err := contracts.Setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
}
beaconDB := testDB.SetupDB(t)
defer testDB.TeardownDB(t, beaconDB)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
ETH1Endpoint: endpoint,
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
DepositCache: depositcache.NewDepositCache(),
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
if err != nil {
t.Fatal(err)
}
web3Service.httpLogger = testAcc.Backend
bConfig := params.MinimalSpecConfig()
bConfig.MinGenesisTime = 0
params.OverrideBeaconConfig(bConfig)
testAcc.Backend.Commit()
testAcc.Backend.AdjustTime(time.Duration(int64(time.Now().Nanosecond())))
depositsWanted := 10
deposits, _, _ := testutil.DeterministicDepositsAndKeys(uint64(depositsWanted))
_, depositRoots, err := testutil.DeterministicDepositTrie(len(deposits))
if err != nil {
t.Fatal(err)
}
for i := 0; i < depositsWanted; i++ {
data := deposits[i].Data
testAcc.TxOpts.Value = contracts.Amount32Eth()
testAcc.TxOpts.GasLimit = 1000000
if _, err := testAcc.Contract.Deposit(testAcc.TxOpts, data.PublicKey, data.WithdrawalCredentials, data.Signature, depositRoots[i]); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}
testAcc.Backend.Commit()
}
query := ethereum.FilterQuery{
Addresses: []common.Address{
web3Service.depositContractAddress,
},
}
logs, err := testAcc.Backend.FilterLogs(web3Service.ctx, query)
if err != nil {
t.Fatalf("Unable to retrieve logs %v", err)
}
if len(logs) != depositsWanted {
t.Fatalf(
"Did not receive enough logs, received %d, wanted %d",
len(logs),
depositsReqForChainStart,
)
}
logsToBeProcessed := append(logs[:depositsWanted-3], logs[depositsWanted-2:]...)
// we purposely miss processing the middle two logs so that the service, re-requests them
for _, log := range logsToBeProcessed {
if err := web3Service.ProcessLog(context.Background(), log); err != nil {
t.Fatal(err)
}
web3Service.latestEth1Data.LastRequestedBlock = log.BlockNumber
}
if web3Service.lastReceivedMerkleIndex != int64(depositsWanted-1) {
t.Errorf("missing logs were not re-requested. Wanted Index %d but got %d", depositsWanted-1, web3Service.lastReceivedMerkleIndex)
}
web3Service.lastReceivedMerkleIndex = -1
web3Service.latestEth1Data.LastRequestedBlock = 0
genSt, err := state.EmptyGenesisState()
if err != nil {
t.Fatal(err)
}
web3Service.preGenesisState = genSt
if err := web3Service.preGenesisState.SetEth1Data(&ethpb.Eth1Data{}); err != nil {
t.Fatal(err)
}
web3Service.chainStartData.ChainstartDeposits = []*ethpb.Deposit{}
web3Service.depositTrie, err = trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
if err != nil {
t.Fatal(err)
}
logsToBeProcessed = append(logs[:depositsWanted-8], logs[depositsWanted-2:]...)
// We purposely miss processing the middle 7 logs so that the service, re-requests them.
for _, log := range logsToBeProcessed {
if err := web3Service.ProcessLog(context.Background(), log); err != nil {
t.Fatal(err)
}
web3Service.latestEth1Data.LastRequestedBlock = log.BlockNumber
}
if web3Service.lastReceivedMerkleIndex != int64(depositsWanted-1) {
t.Errorf("Missing logs were not re-requested want = %d but got = %d", depositsWanted-1, web3Service.lastReceivedMerkleIndex)
}
hook.Reset()
}
func TestConsistentGenesisState(t *testing.T) {
t.Skip("Incorrect test setup")
testAcc, err := contracts.Setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
}
beaconDB := testDB.SetupDB(t)
defer testDB.TeardownDB(t, beaconDB)
web3Service := newPowchainService(t, testAcc, beaconDB)
testAcc.Backend.Commit()
testAcc.Backend.AdjustTime(time.Duration(int64(time.Now().Nanosecond())))
deposits, _, _ := testutil.DeterministicDepositsAndKeys(uint64(depositsReqForChainStart))
_, roots, err := testutil.DeterministicDepositTrie(len(deposits))
if err != nil {
t.Fatal(err)
}
ctx, cancel := context.WithCancel(context.Background())
go web3Service.run(ctx.Done())
// 64 Validators are used as size required for beacon-chain to start. This number
// is defined in the deposit contract as the number required for the testnet. The actual number
// is 2**14.
for i := 0; i < depositsReqForChainStart; i++ {
data := deposits[i].Data
testAcc.TxOpts.Value = contracts.Amount32Eth()
testAcc.TxOpts.GasLimit = 1000000
if _, err := testAcc.Contract.Deposit(testAcc.TxOpts, data.PublicKey, data.WithdrawalCredentials, data.Signature, roots[i]); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}
testAcc.Backend.Commit()
}
for i := 0; i < int(params.BeaconConfig().LogBlockDelay); i++ {
testAcc.Backend.Commit()
}
time.Sleep(2 * time.Second)
if !web3Service.chainStartData.Chainstarted {
t.Fatalf("Service hasn't chainstarted yet with a block height of %d", web3Service.latestEth1Data.BlockHeight)
}
// Advance 10 blocks.
for i := 0; i < 10; i++ {
testAcc.Backend.Commit()
}
// Tearing down to prevent registration error.
testDB.TeardownDB(t, beaconDB)
newBeaconDB := testDB.SetupDB(t)
defer testDB.TeardownDB(t, newBeaconDB)
newWeb3Service := newPowchainService(t, testAcc, newBeaconDB)
go newWeb3Service.run(ctx.Done())
time.Sleep(2 * time.Second)
if !newWeb3Service.chainStartData.Chainstarted {
t.Fatal("Service hasn't chainstarted yet")
}
diff, _ := messagediff.PrettyDiff(web3Service.chainStartData.Eth1Data, newWeb3Service.chainStartData.Eth1Data)
if diff != "" {
t.Errorf("Two services have different eth1data: %s", diff)
}
cancel()
}
func newPowchainService(t *testing.T, eth1Backend *contracts.TestAccount, beaconDB db.Database) *Service {
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
ETH1Endpoint: endpoint,
DepositContract: eth1Backend.ContractAddr,
BeaconDB: beaconDB,
DepositCache: depositcache.NewDepositCache(),
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(eth1Backend.ContractAddr, eth1Backend.Backend)
if err != nil {
t.Fatal(err)
}
web3Service.rpcClient = &mockPOW.RPCClient{Backend: eth1Backend.Backend}
web3Service.reader = &goodReader{backend: eth1Backend.Backend}
web3Service.blockFetcher = &goodFetcher{backend: eth1Backend.Backend}
web3Service.httpLogger = &goodLogger{backend: eth1Backend.Backend}
web3Service.logger = &goodLogger{backend: eth1Backend.Backend}
bConfig := params.MinimalSpecConfig()
bConfig.MinGenesisTime = 0
params.OverrideBeaconConfig(bConfig)
web3Service.headerChan = make(chan *gethTypes.Header)
return web3Service
}