github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/c_llr_callbacks_test.go (about)

     1  package gossip
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"math/big"
     8  	"math/rand"
     9  	"reflect"
    10  	"sync"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/status-im/keycard-go/hexutils"
    15  	"github.com/stretchr/testify/require"
    16  	"github.com/stretchr/testify/suite"
    17  	"github.com/unicornultrafoundation/go-helios/hash"
    18  	"github.com/unicornultrafoundation/go-helios/native/idx"
    19  	"github.com/unicornultrafoundation/go-helios/native/pos"
    20  	"github.com/unicornultrafoundation/go-helios/u2udb"
    21  	"github.com/unicornultrafoundation/go-u2u/common"
    22  	"github.com/unicornultrafoundation/go-u2u/core/types"
    23  	"github.com/unicornultrafoundation/go-u2u/rlp"
    24  	"github.com/unicornultrafoundation/go-u2u/rpc"
    25  
    26  	"github.com/unicornultrafoundation/go-u2u/eventcheck"
    27  	"github.com/unicornultrafoundation/go-u2u/eventcheck/epochcheck"
    28  	"github.com/unicornultrafoundation/go-u2u/evmcore"
    29  	"github.com/unicornultrafoundation/go-u2u/gossip/contract/ballot"
    30  	"github.com/unicornultrafoundation/go-u2u/gossip/filters"
    31  	"github.com/unicornultrafoundation/go-u2u/native"
    32  	"github.com/unicornultrafoundation/go-u2u/native/ibr"
    33  	"github.com/unicornultrafoundation/go-u2u/native/ier"
    34  )
    35  
    36  type IntegrationTestSuite struct {
    37  	suite.Suite
    38  
    39  	startEpoch, lastEpoch idx.Epoch
    40  	generator, processor  *testEnv
    41  	epochToEvsMap         map[idx.Epoch][]*native.LlrSignedEpochVote
    42  	bvs                   []*native.LlrSignedBlockVotes
    43  	blockIndices          []idx.Block
    44  }
    45  
    46  func (s *IntegrationTestSuite) SetupTest() {
    47  	const (
    48  		rounds        = 20
    49  		validatorsNum = 10
    50  		startEpoch    = 1
    51  	)
    52  
    53  	//creating generator and processor
    54  	generator := newTestEnv(startEpoch, validatorsNum)
    55  	processor := newTestEnv(startEpoch, validatorsNum)
    56  
    57  	proposals := [][32]byte{
    58  		ballotOption("Option 1"),
    59  		ballotOption("Option 2"),
    60  		ballotOption("Option 3"),
    61  	}
    62  
    63  	for n := uint64(0); n < rounds; n++ {
    64  		txs := make([]*types.Transaction, validatorsNum)
    65  		for i := idx.Validator(0); i < validatorsNum; i++ {
    66  			_, tx, cBallot, err := ballot.DeployBallot(generator.Pay(idx.ValidatorID(i+1)), generator, proposals)
    67  			s.Require().NoError(err)
    68  			s.Require().NotNil(cBallot)
    69  			s.Require().NotNil(tx)
    70  			txs[i] = tx
    71  		}
    72  		tm := sameEpoch
    73  		if n%10 == 0 {
    74  			tm = nextEpoch
    75  		}
    76  
    77  		rr, err := generator.ApplyTxs(tm, txs...)
    78  		s.Require().NoError(err)
    79  		for _, r := range rr {
    80  			s.Require().Len(r.Logs, 3)
    81  			for _, l := range r.Logs {
    82  				s.Require().NotNil(l)
    83  			}
    84  		}
    85  	}
    86  
    87  	s.startEpoch = startEpoch
    88  	s.generator = generator
    89  	s.processor = processor
    90  
    91  	s.epochToEvsMap = fetchEvs(s.generator)
    92  	bvs, blockIndices := fetchBvsBlockIdxs(s.generator)
    93  	s.bvs = bvs
    94  	s.blockIndices = blockIndices
    95  	s.lastEpoch = generator.store.GetEpoch()
    96  }
    97  
    98  func (s *IntegrationTestSuite) TearDownSuite() {
    99  	s.T().Log("tearing down test suite")
   100  	s.generator.Close()
   101  	s.processor.Close()
   102  }
   103  
   104  // fetchEvs fetches LlrSignedEpochVotes from generator
   105  func fetchEvs(generator *testEnv) map[idx.Epoch][]*native.LlrSignedEpochVote {
   106  	m := make(map[idx.Epoch][]*native.LlrSignedEpochVote)
   107  	it := generator.store.table.LlrEpochVotes.NewIterator(nil, nil)
   108  	defer it.Release()
   109  	for it.Next() {
   110  		ev := &native.LlrSignedEpochVote{}
   111  		if err := rlp.DecodeBytes(it.Value(), ev); err != nil {
   112  			generator.store.Log.Crit("Failed to decode epoch vote", "err", err)
   113  		}
   114  
   115  		if ev != nil {
   116  			m[ev.Val.Epoch] = append(m[ev.Val.Epoch], ev)
   117  		}
   118  	}
   119  	return m
   120  }
   121  
   122  // fetchBvsBlockIdxs fetches block indices of blocks that have min 4 LLR votes.
   123  func fetchBvsBlockIdxs(generator *testEnv) ([]*native.LlrSignedBlockVotes, []idx.Block) {
   124  	var bvs []*native.LlrSignedBlockVotes
   125  	blockIdxCountMap := make(map[idx.Block]uint64)
   126  
   127  	// fetching blockIndices with at least minVoteCount
   128  	fetchBlockIdxs := func(blockIdxCountMap map[idx.Block]uint64) (blockIndices []idx.Block) {
   129  		const minVoteCount = 4
   130  		for blockIdx, count := range blockIdxCountMap {
   131  			if count >= minVoteCount {
   132  				blockIndices = append(blockIndices, blockIdx)
   133  			}
   134  		}
   135  		return
   136  	}
   137  
   138  	// compute how any votes have been given for a particular block idx
   139  	fillblockIdxCountMap := func(bv *native.LlrSignedBlockVotes) {
   140  		start, end := bv.Val.Start, bv.Val.Start+idx.Block(len(bv.Val.Votes))-1
   141  
   142  		for b := start; start != 0 && b <= end; b++ {
   143  			blockIdxCountMap[b] += 1
   144  		}
   145  	}
   146  
   147  	it := generator.store.table.LlrBlockVotes.NewIterator(nil, nil)
   148  	defer it.Release()
   149  	for it.Next() {
   150  		bv := &native.LlrSignedBlockVotes{}
   151  		if err := rlp.DecodeBytes(it.Value(), bv); err != nil {
   152  			generator.store.Log.Crit("Failed to decode block vote while running ", "err", err)
   153  		}
   154  
   155  		if bv != nil {
   156  			fillblockIdxCountMap(bv)
   157  			bvs = append(bvs, bv)
   158  		}
   159  	}
   160  
   161  	return bvs, fetchBlockIdxs(blockIdxCountMap)
   162  }
   163  
   164  // txByBlockSubsetOf iterates over procMap keys and checks equality of transaction hashes of genenerator and processor
   165  func txByBlockSubsetOf(t *testing.T, procMap, genMap map[idx.Block]types.Transactions) {
   166  	// assert len(procBlockToTxsMap.keys()) <= len(genBlockToTxsMap.keys()")
   167  	require.LessOrEqual(t, len(reflect.ValueOf(procMap).MapKeys()), len(reflect.ValueOf(genMap).MapKeys()), "The number of keys does not match")
   168  	for b, txs := range procMap {
   169  		genTxs, ok := genMap[b]
   170  		require.True(t, ok)
   171  		require.Equal(t, len(txs), len(genTxs))
   172  		for i, tx := range txs {
   173  			require.Equal(t, tx.Hash().Hex(), genTxs[i].Hash().Hex())
   174  		}
   175  	}
   176  }
   177  
   178  // checkLogsEquality checks equality of logs slice field byf ield
   179  func checkLogsEquality(t *testing.T, genLogs, procLogs []*types.Log) {
   180  	require.Equal(t, len(genLogs), len(procLogs))
   181  	for i, procLog := range procLogs {
   182  		// compare all fields
   183  		require.Equal(t, procLog.Address.Hex(), genLogs[i].Address.Hex())
   184  		require.Equal(t, procLog.BlockHash.Hex(), genLogs[i].BlockHash.Hex())
   185  		require.Equal(t, procLog.BlockNumber, genLogs[i].BlockNumber)
   186  		require.Equal(t, hexutils.BytesToHex(procLog.Data), hexutils.BytesToHex(genLogs[i].Data))
   187  		require.Equal(t, procLog.Index, genLogs[i].Index)
   188  		require.Equal(t, procLog.Removed, genLogs[i].Removed)
   189  
   190  		for j, topic := range procLog.Topics {
   191  			require.Equal(t, topic.Hex(), genLogs[i].Topics[j].Hex())
   192  		}
   193  
   194  		require.Equal(t, procLog.TxHash.Hex(), genLogs[i].TxHash.Hex())
   195  		require.Equal(t, procLog.TxIndex, genLogs[i].TxIndex)
   196  	}
   197  }
   198  
   199  type testParams struct {
   200  	t            *testing.T
   201  	genEvmBlock  *evmcore.EvmBlock
   202  	procEvmBlock *evmcore.EvmBlock
   203  	genReceipts  types.Receipts
   204  	procReceipts types.Receipts
   205  }
   206  
   207  func newTestParams(t *testing.T, genEvmBlock, procEvmBlock *evmcore.EvmBlock, genReceipts, procReceipts types.Receipts) testParams {
   208  	return testParams{t, genEvmBlock, procEvmBlock, genReceipts, procReceipts}
   209  }
   210  
   211  func (p testParams) compareEvmBlocks() {
   212  	// comparing all fields of genEvmBlock and procEvmBlock
   213  	require.Equal(p.t, p.genEvmBlock.Number, p.procEvmBlock.Number)
   214  	require.Equal(p.t, p.genEvmBlock.Hash, p.procEvmBlock.Hash)
   215  	require.Equal(p.t, p.genEvmBlock.ParentHash, p.procEvmBlock.ParentHash)
   216  	require.Equal(p.t, p.genEvmBlock.Root, p.procEvmBlock.Root)
   217  	require.Equal(p.t, p.genEvmBlock.TxHash, p.procEvmBlock.TxHash)
   218  	require.Equal(p.t, p.genEvmBlock.Time, p.procEvmBlock.Time)
   219  	require.Equal(p.t, p.genEvmBlock.GasLimit, p.procEvmBlock.GasLimit)
   220  	require.Equal(p.t, p.genEvmBlock.GasUsed, p.procEvmBlock.GasUsed)
   221  	require.Equal(p.t, p.genEvmBlock.BaseFee, p.procEvmBlock.BaseFee)
   222  }
   223  
   224  func (p testParams) compareReceipts() {
   225  	require.Equal(p.t, len(p.genReceipts), len(p.procReceipts))
   226  	// compare every field except logs, I compare them separately
   227  	for i, initRec := range p.genReceipts {
   228  		require.Equal(p.t, initRec.Type, p.procReceipts[i].Type)
   229  		require.Equal(p.t, hexutils.BytesToHex(initRec.PostState), hexutils.BytesToHex(p.procReceipts[i].PostState))
   230  		require.Equal(p.t, initRec.Status, p.procReceipts[i].Status)
   231  		require.Equal(p.t, initRec.CumulativeGasUsed, p.procReceipts[i].CumulativeGasUsed)
   232  		require.Equal(p.t, hexutils.BytesToHex(initRec.Bloom.Bytes()), hexutils.BytesToHex(p.procReceipts[i].Bloom.Bytes()))
   233  		require.Equal(p.t, initRec.TxHash.Hex(), p.procReceipts[i].TxHash.Hex())
   234  		require.Equal(p.t, initRec.ContractAddress.Hex(), p.procReceipts[i].ContractAddress.Hex())
   235  		require.Equal(p.t, initRec.GasUsed, p.procReceipts[i].GasUsed)
   236  		require.Equal(p.t, initRec.BlockHash.String(), p.procReceipts[i].BlockHash.String())
   237  		require.Equal(p.t, initRec.BlockNumber, p.procReceipts[i].BlockNumber)
   238  		require.Equal(p.t, initRec.TransactionIndex, p.procReceipts[i].TransactionIndex)
   239  	}
   240  }
   241  
   242  func (p testParams) compareLogs(initLogs2D, procLogs2D [][]*types.Log) {
   243  	require.Equal(p.t, len(initLogs2D), len(procLogs2D))
   244  	for i, initLogs := range initLogs2D {
   245  		checkLogsEquality(p.t, initLogs, procLogs2D[i])
   246  	}
   247  }
   248  
   249  func (p testParams) serializeAndCompare(val1, val2 interface{}) {
   250  	// serialize val1 and val2
   251  	buf1, err := rlp.EncodeToBytes(val1)
   252  	require.NotNil(p.t, buf1)
   253  	require.NoError(p.t, err)
   254  	buf2, err := rlp.EncodeToBytes(val2)
   255  	require.NotNil(p.t, buf2)
   256  	require.NoError(p.t, err)
   257  
   258  	// compare serialized representation of val1 and val2
   259  	require.Equal(p.t, hexutils.BytesToHex(buf1), hexutils.BytesToHex(buf2))
   260  }
   261  
   262  func (p testParams) compareTransactions(initiator, processor *testEnv) {
   263  	ctx := context.Background()
   264  	require.Equal(p.t, len(p.genEvmBlock.Transactions), len(p.procEvmBlock.Transactions))
   265  	for i, tx := range p.genEvmBlock.Transactions {
   266  		txHash := tx.Hash()
   267  		initTx, _, _, err := initiator.EthAPI.GetTransaction(ctx, txHash)
   268  		require.NoError(p.t, err)
   269  
   270  		procTx, _, _, err := processor.EthAPI.GetTransaction(ctx, txHash)
   271  		require.NoError(p.t, err)
   272  
   273  		require.Equal(p.t, txHash.Hex(), p.procEvmBlock.Transactions[i].Hash().Hex())
   274  		require.Equal(p.t, txHash.Hex(), initTx.Hash().Hex())
   275  		require.Equal(p.t, txHash.Hex(), procTx.Hash().Hex())
   276  	}
   277  }
   278  
   279  func fetchTxsbyBlock(env *testEnv) map[idx.Block]types.Transactions {
   280  	m := make(map[idx.Block]types.Transactions)
   281  	it := env.store.table.Blocks.NewIterator(nil, nil)
   282  	defer it.Release()
   283  	for it.Next() {
   284  		block := &native.Block{}
   285  		if err := rlp.DecodeBytes(it.Value(), block); err != nil {
   286  			env.store.Log.Crit("Failed to decode block", "err", err)
   287  		}
   288  
   289  		if block != nil {
   290  			n := idx.BytesToBlock(it.Key())
   291  			txs := env.store.GetBlockTxs(n, block)
   292  			m[n] = txs
   293  		}
   294  	}
   295  	return m
   296  }
   297  
   298  type repeater struct {
   299  	generator     *testEnv
   300  	processor     *testEnv
   301  	bvs           []*native.LlrSignedBlockVotes
   302  	blockIndices  []idx.Block
   303  	epochToEvsMap map[idx.Epoch][]*native.LlrSignedEpochVote
   304  	t             *testing.T
   305  }
   306  
   307  func newRepeater(s *IntegrationTestSuite) repeater {
   308  	return repeater{
   309  		generator:     s.generator,
   310  		processor:     s.processor,
   311  		bvs:           s.bvs,
   312  		blockIndices:  s.blockIndices,
   313  		epochToEvsMap: s.epochToEvsMap,
   314  		t:             s.T(),
   315  	}
   316  }
   317  
   318  // processBlockVotesRecords processes block votes. Moreover, it processes block records for every block index that has minimum 4 LLr Votes.
   319  // If ProcessFullBlockRecord returns an error, omit it in fullRepeater scenario, but not in testRepeater scenario.
   320  func (r repeater) processBlockVotesRecords(isTestRepeater bool) {
   321  	for _, bv := range r.bvs {
   322  		r.processor.ProcessBlockVotes(*bv)
   323  	}
   324  
   325  	for _, blockIdx := range r.blockIndices {
   326  		if br := r.generator.store.GetFullBlockRecord(blockIdx); br != nil {
   327  			ibr := ibr.LlrIdxFullBlockRecord{LlrFullBlockRecord: *br, Idx: blockIdx}
   328  			err := r.processor.ProcessFullBlockRecord(ibr)
   329  			if err == nil {
   330  				continue
   331  			}
   332  
   333  			// do not ingore this error in testRepeater
   334  			if isTestRepeater {
   335  				require.NoError(r.t, err)
   336  			} else {
   337  				// omit this error in fullRepeater
   338  				require.EqualError(r.t, err, eventcheck.ErrAlreadyProcessedBR.Error())
   339  			}
   340  
   341  		} else {
   342  			r.generator.Log.Crit("Empty full block record popped up")
   343  		}
   344  	}
   345  }
   346  
   347  // processEpochVotesRecords processes each epoch vote. Additionally, it processes epoch block records in range [startEpoch+1; lastEpoch]
   348  func (r repeater) processEpochVotesRecords(startEpoch, lastEpoch idx.Epoch) {
   349  	// invoke repeater.ProcessEpochVote and ProcessFullEpochRecord for epoch in range [2; lastepoch]
   350  	for e := idx.Epoch(startEpoch + 1); e <= lastEpoch; e++ {
   351  		epochVotes, ok := r.epochToEvsMap[e]
   352  		if !ok {
   353  			r.processor.store.Log.Crit("Failed to fetch epoch votes for a given epoch")
   354  		}
   355  
   356  		for _, v := range epochVotes {
   357  			require.NoError(r.t, r.processor.ProcessEpochVote(*v))
   358  		}
   359  
   360  		if er := r.generator.store.GetFullEpochRecord(e); er != nil {
   361  			ier := ier.LlrIdxFullEpochRecord{LlrFullEpochRecord: *er, Idx: e}
   362  			require.NoError(r.t, r.processor.ProcessFullEpochRecord(ier))
   363  		}
   364  	}
   365  }
   366  
   367  // compareERHashes compares epoch recors hashes. Moreover, it checks equality of hashes of epoch and block states.
   368  func (r repeater) compareERHashes(startEpoch, lastEpoch idx.Epoch) {
   369  	for e := startEpoch; e <= lastEpoch; e++ {
   370  
   371  		genBs, genEs := r.generator.store.GetHistoryBlockEpochState(e)
   372  		repBs, repEs := r.processor.store.GetHistoryBlockEpochState(e)
   373  		require.Equal(r.t, genBs.Hash().Hex(), repBs.Hash().Hex())
   374  		require.Equal(r.t, genEs.Hash().Hex(), repEs.Hash().Hex())
   375  
   376  		genEr := r.generator.store.GetFullEpochRecord(e)
   377  		repEr := r.processor.store.GetFullEpochRecord(e)
   378  		require.Equal(r.t, genEr.Hash().Hex(), repEr.Hash().Hex())
   379  	}
   380  }
   381  
   382  // compareParams checks equality of different parameters such as BlockByHash, BlockByNumber, Receipts, Logs
   383  func (r repeater) compareParams() {
   384  	ctx := context.Background()
   385  
   386  	// compare blockbyNumber
   387  	for _, blockIdx := range r.blockIndices {
   388  
   389  		// comparing EvmBlock by calling BlockByHash
   390  		genEvmBlock, err := r.generator.EthAPI.BlockByNumber(ctx, rpc.BlockNumber(blockIdx))
   391  		require.NotNil(r.t, genEvmBlock)
   392  		require.NoError(r.t, err)
   393  
   394  		procEvmBlock, err := r.processor.EthAPI.BlockByNumber(ctx, rpc.BlockNumber(blockIdx))
   395  		require.NotNil(r.t, procEvmBlock)
   396  		require.NoError(r.t, err)
   397  
   398  		// compare Receipts
   399  		genReceipts := r.generator.store.evm.GetReceipts(blockIdx, r.generator.EthAPI.signer, genEvmBlock.Hash, genEvmBlock.Transactions)
   400  		require.NotNil(r.t, genReceipts)
   401  		procReceipts := r.processor.store.evm.GetReceipts(blockIdx, r.processor.EthAPI.signer, procEvmBlock.Hash, procEvmBlock.Transactions)
   402  		require.NotNil(r.t, procReceipts)
   403  
   404  		testParams := newTestParams(r.t, genEvmBlock, procEvmBlock, genReceipts, procReceipts)
   405  		testParams.compareEvmBlocks()
   406  
   407  		r.t.Log("comparing receipts")
   408  		testParams.compareReceipts()
   409  
   410  		// comparing evmBlock by calling BlockByHash
   411  		genEvmBlock, err = r.generator.EthAPI.BlockByHash(ctx, genEvmBlock.Hash)
   412  		require.NotNil(r.t, genEvmBlock)
   413  		require.NoError(r.t, err)
   414  		procEvmBlock, err = r.processor.EthAPI.BlockByHash(ctx, procEvmBlock.Hash)
   415  		require.NotNil(r.t, procEvmBlock)
   416  		require.NoError(r.t, err)
   417  
   418  		testParams = newTestParams(r.t, genEvmBlock, procEvmBlock, genReceipts, procReceipts)
   419  		testParams.compareEvmBlocks()
   420  
   421  		// compare Logs
   422  		genLogs, err := r.generator.EthAPI.GetLogs(ctx, genEvmBlock.Hash)
   423  		require.NoError(r.t, err)
   424  
   425  		procLogs, err := r.processor.EthAPI.GetLogs(ctx, genEvmBlock.Hash)
   426  		require.NoError(r.t, err)
   427  
   428  		r.t.Log("comparing logs")
   429  		testParams.serializeAndCompare(genLogs, procLogs)
   430  		testParams.compareLogs(genLogs, procLogs)
   431  
   432  		// compare ReceiptForStorage
   433  		genBR := r.generator.store.GetFullBlockRecord(blockIdx)
   434  		procBR := r.processor.store.GetFullBlockRecord(blockIdx)
   435  		testParams.serializeAndCompare(genBR.Receipts, procBR.Receipts)
   436  
   437  		// compare BR hashes
   438  		require.Equal(r.t, genBR.Hash().Hex(), procBR.Hash().Hex())
   439  
   440  		// compare transactions
   441  		testParams.compareTransactions(r.generator, r.processor)
   442  	}
   443  }
   444  
   445  // compareLogsByFilterCriteria introduces testing logic for GetLogs function for generator and processor
   446  func (r repeater) compareLogsByFilterCriteria() {
   447  	var crit filters.FilterCriteria
   448  
   449  	blockIdxLogsMap := func() map[idx.Block][]*types.Log {
   450  		ctx := context.Background()
   451  		m := make(map[idx.Block][]*types.Log, len(r.blockIndices))
   452  
   453  		for _, blockIdx := range r.blockIndices {
   454  			block, err := r.generator.EthAPI.BlockByNumber(ctx, rpc.BlockNumber(blockIdx))
   455  			require.NotNil(r.t, block)
   456  			require.NoError(r.t, err)
   457  			receipts := r.generator.store.evm.GetReceipts(blockIdx, r.generator.EthAPI.signer, block.Hash, block.Transactions)
   458  			for _, r := range receipts {
   459  				// we add only non empty logs
   460  				if len(r.Logs) > 0 {
   461  					m[blockIdx] = append(m[blockIdx], r.Logs...)
   462  				}
   463  			}
   464  
   465  		}
   466  		return m
   467  	}()
   468  
   469  	findLastNonEmptyLogs := func() (idx.Block, []*types.Log, error) {
   470  		for i := len(r.blockIndices) - 1; i >= 0; i-- {
   471  			logs, ok := blockIdxLogsMap[r.blockIndices[i]]
   472  			if !ok {
   473  				continue
   474  			}
   475  			if len(logs) > 0 {
   476  				return r.blockIndices[i], logs, nil
   477  			}
   478  		}
   479  
   480  		return 0, nil, errors.New("all blocks have no logs")
   481  	}
   482  
   483  	lastBlockNumber, lastLogs, err := findLastNonEmptyLogs()
   484  	require.NoError(r.t, err)
   485  	require.NotNil(r.t, lastLogs)
   486  
   487  	defaultCrit := filters.FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(int64(lastBlockNumber/2 + 1))}
   488  
   489  	ctx := context.Background()
   490  
   491  	config := filters.DefaultConfig()
   492  	config.UnindexedLogsBlockRangeLimit = idx.Block(1000)
   493  	genApi := filters.NewPublicFilterAPI(r.generator.EthAPI, config)
   494  	require.NotNil(r.t, genApi)
   495  
   496  	procApi := filters.NewPublicFilterAPI(r.processor.EthAPI, config)
   497  	require.NotNil(r.t, procApi)
   498  
   499  	defaultLogs, err := genApi.GetLogs(ctx, defaultCrit)
   500  	require.NoError(r.t, err)
   501  	require.NotNil(r.t, defaultLogs)
   502  	require.NotEqual(r.t, defaultLogs, []*types.Log{})
   503  
   504  	findFirstNonEmptyLogs := func() (idx.Block, []*types.Log, error) {
   505  		for _, blockIdx := range r.blockIndices {
   506  			logs, ok := blockIdxLogsMap[blockIdx]
   507  			if !ok {
   508  				continue
   509  			}
   510  			if len(logs) > 0 {
   511  				return blockIdx, logs, nil
   512  			}
   513  		}
   514  
   515  		return 0, nil, errors.New("all blocks have no logs")
   516  	}
   517  
   518  	fetchFirstAddrFromLogs := func(logs []*types.Log) (common.Address, error) {
   519  		for i := range logs {
   520  			if logs[i] != nil && logs[i].Address != (common.Address{}) {
   521  				return logs[i].Address, nil
   522  			}
   523  		}
   524  
   525  		return common.Address{}, errors.New("no address can be found in logs")
   526  	}
   527  
   528  	fetchFirstTopicFromLogs := func(logs []*types.Log) (common.Hash, error) {
   529  		for i := range logs {
   530  			if logs[i] != nil && logs[i].Topics[0] != (common.Hash{}) {
   531  				return logs[i].Topics[0], nil
   532  			}
   533  		}
   534  		return common.Hash{}, errors.New("no topic can be found in logs")
   535  	}
   536  
   537  	fetchRandomTopicFromLogs := func(logs []*types.Log) common.Hash {
   538  		rand.Seed(time.Now().Unix())
   539  		l := rand.Int() % len(logs) // pick log at random
   540  
   541  		rand.Seed(time.Now().Unix())
   542  		t := rand.Int() % len(logs[l].Topics) // pick topic at random
   543  
   544  		return logs[l].Topics[t]
   545  	}
   546  
   547  	fetchRandomAddrFromLogs := func(logs []*types.Log) common.Address {
   548  		rand.Seed(time.Now().Unix())
   549  		l := rand.Int() % len(logs) // pick log at random
   550  
   551  		return logs[l].Address
   552  	}
   553  
   554  	blockNumber, logs, err := findFirstNonEmptyLogs()
   555  	require.NoError(r.t, err)
   556  	require.NotNil(r.t, logs)
   557  
   558  	firstAddr, err := fetchFirstAddrFromLogs(logs)
   559  	require.NoError(r.t, err)
   560  
   561  	firstTopic, err := fetchFirstTopicFromLogs(logs)
   562  	require.NoError(r.t, err)
   563  
   564  	lastAddr, err := fetchFirstAddrFromLogs(lastLogs)
   565  	require.NoError(r.t, err)
   566  
   567  	lastTopic, err := fetchFirstTopicFromLogs(lastLogs)
   568  	require.NoError(r.t, err)
   569  
   570  	testCases := []struct {
   571  		name    string
   572  		pretest func()
   573  		success bool
   574  	}{
   575  		{"single valid address",
   576  			func() {
   577  				crit = filters.FilterCriteria{
   578  					FromBlock: big.NewInt(int64(blockNumber)),
   579  					ToBlock:   big.NewInt(int64(blockNumber)),
   580  					Addresses: []common.Address{firstAddr},
   581  				}
   582  			},
   583  			true,
   584  		},
   585  		{"single invalid address",
   586  			func() {
   587  				invalidAddr := common.BytesToAddress([]byte("invalid address"))
   588  				crit = filters.FilterCriteria{
   589  					FromBlock: big.NewInt(int64(blockNumber)),
   590  					ToBlock:   big.NewInt(int64(blockNumber)),
   591  					Addresses: []common.Address{invalidAddr},
   592  				}
   593  			},
   594  			false,
   595  		},
   596  		{"invalid block range",
   597  			func() {
   598  				crit = filters.FilterCriteria{
   599  					FromBlock: big.NewInt(int64(blockNumber) + 1),
   600  					ToBlock:   big.NewInt(int64(blockNumber) + 2),
   601  					Addresses: []common.Address{firstAddr},
   602  				}
   603  			},
   604  			false,
   605  		},
   606  		{"block range 1-1000",
   607  			func() {
   608  				crit = defaultCrit
   609  			},
   610  			true,
   611  		},
   612  		{"block range 1-1000 and first topic",
   613  			func() {
   614  				crit = defaultCrit
   615  				crit.Topics = [][]common.Hash{{firstTopic}}
   616  			},
   617  			true,
   618  		},
   619  		{"block range 1-1000 and random topic",
   620  			func() {
   621  				randomTopic := fetchRandomTopicFromLogs(defaultLogs)
   622  				crit = defaultCrit
   623  				crit.Topics = [][]common.Hash{{randomTopic}}
   624  			},
   625  			true,
   626  		},
   627  		{"block range 1-1000 and first address",
   628  			func() {
   629  				crit = defaultCrit
   630  				crit.Addresses = []common.Address{firstAddr}
   631  			},
   632  			true,
   633  		},
   634  		{"block range 1-1000 and random address",
   635  			func() {
   636  				randomAddress := fetchRandomAddrFromLogs(defaultLogs)
   637  				crit = defaultCrit
   638  				crit.Addresses = []common.Address{randomAddress}
   639  			},
   640  			true,
   641  		},
   642  		{"block range 1 to lastBlockNumber",
   643  			func() {
   644  				crit = filters.FilterCriteria{
   645  					FromBlock: big.NewInt(int64(1)),
   646  					ToBlock:   big.NewInt(int64(lastBlockNumber)),
   647  				}
   648  			},
   649  			true,
   650  		},
   651  		{"block range 1 to lastBlockNumber and last topic",
   652  			func() {
   653  				crit = filters.FilterCriteria{
   654  					FromBlock: big.NewInt(int64(1)),
   655  					ToBlock:   big.NewInt(int64(lastBlockNumber)),
   656  					Topics:    [][]common.Hash{{lastTopic}},
   657  				}
   658  			},
   659  			true,
   660  		},
   661  		{"block range 1 to lastBlockNumber, last address",
   662  			func() {
   663  				crit = filters.FilterCriteria{
   664  					FromBlock: big.NewInt(int64(1)),
   665  					ToBlock:   big.NewInt(int64(lastBlockNumber)),
   666  					Addresses: []common.Address{lastAddr},
   667  				}
   668  			},
   669  			true,
   670  		},
   671  
   672  		{"block range is nil and last address",
   673  			func() {
   674  				crit = filters.FilterCriteria{
   675  					Addresses: []common.Address{lastAddr},
   676  				}
   677  			},
   678  			true,
   679  		},
   680  		{"block range is nil and invalid address",
   681  			func() {
   682  				invalidAddr := common.BytesToAddress([]byte("invalid addr"))
   683  				crit = filters.FilterCriteria{
   684  					Addresses: []common.Address{invalidAddr},
   685  				}
   686  			},
   687  			false,
   688  		},
   689  	}
   690  
   691  	for _, tc := range testCases {
   692  		tc := tc
   693  		r.t.Run(tc.name, func(t *testing.T) {
   694  			tc.pretest()
   695  			genLogs, genErr := genApi.GetLogs(ctx, crit)
   696  			procLogs, procErr := procApi.GetLogs(ctx, crit)
   697  			if tc.success {
   698  				require.NoError(t, procErr)
   699  				require.NoError(t, genErr)
   700  				checkLogsEquality(t, genLogs, procLogs)
   701  			} else {
   702  				require.Equal(t, genLogs, []*types.Log{})
   703  				require.Equal(t, procLogs, []*types.Log{})
   704  			}
   705  		})
   706  	}
   707  
   708  	// iterative tests with random address and random topic
   709  	itTestCases := []struct {
   710  		name    string
   711  		rounds  int
   712  		pretest func()
   713  	}{
   714  		{"block range 1-1000 and random topic",
   715  			100,
   716  			func() {
   717  				randomTopic := fetchRandomTopicFromLogs(defaultLogs)
   718  				crit = defaultCrit
   719  				crit.Topics = [][]common.Hash{{randomTopic}}
   720  			},
   721  		},
   722  		{"block range 1-1000 and random address",
   723  			100,
   724  			func() {
   725  				randomAddress := fetchRandomAddrFromLogs(defaultLogs)
   726  				crit = defaultCrit
   727  				crit.Addresses = []common.Address{randomAddress}
   728  			},
   729  		},
   730  	}
   731  
   732  	for _, tc := range itTestCases {
   733  		tc := tc
   734  		r.t.Run(tc.name, func(t *testing.T) {
   735  			for i := 0; i < tc.rounds; i++ {
   736  				tc.pretest()
   737  				genLogs, genErr := genApi.GetLogs(ctx, crit)
   738  				procLogs, procErr := procApi.GetLogs(ctx, crit)
   739  				require.NoError(t, procErr)
   740  				require.NoError(t, genErr)
   741  				checkLogsEquality(t, genLogs, procLogs)
   742  			}
   743  		})
   744  	}
   745  }
   746  
   747  // use command `go test  -timeout 120s  -run ^TestIntegrationTestSuite$ -testify.m TestRepeater` to run test scenario
   748  func (s *IntegrationTestSuite) TestRepeater() {
   749  	repeater := newRepeater(s)
   750  	repeater.processEpochVotesRecords(s.startEpoch, s.lastEpoch)
   751  	repeater.processBlockVotesRecords(true)
   752  
   753  	s.Require().NoError(s.generator.store.Commit())
   754  	s.Require().NoError(s.processor.store.Commit())
   755  
   756  	// Compare transaction hashes
   757  	s.T().Log("Checking procBlockToTxsMap <= genBlockToTxsMap")
   758  	genBlockToTxsMap := fetchTxsbyBlock(s.generator)
   759  	procBlockToTxsMap := fetchTxsbyBlock(s.processor)
   760  	txByBlockSubsetOf(s.T(), procBlockToTxsMap, genBlockToTxsMap)
   761  
   762  	// compare ER hashes
   763  	repeater.compareERHashes(s.startEpoch+1, s.lastEpoch)
   764  	// compare different parameters such as Logs,Receipts, Blockhash etc
   765  	repeater.compareParams()
   766  
   767  	// compare Logs by different criteria
   768  	repeater.compareLogsByFilterCriteria()
   769  }
   770  
   771  // use command `go test  -timeout 120s  -run ^TestIntegrationTestSuite$ -testify.m TestFullRepeater` to run test scenario
   772  func (s *IntegrationTestSuite) TestFullRepeater() {
   773  
   774  	fullRepeater := newRepeater(s)
   775  
   776  	wg := new(sync.WaitGroup)
   777  	wg.Add(2)
   778  	go func() {
   779  		defer wg.Done()
   780  		// process LLR epochVotes in fullRepeater
   781  		fullRepeater.processEpochVotesRecords(s.startEpoch, s.lastEpoch)
   782  
   783  		// process LLR block votes and BRs in fullReapeter
   784  		fullRepeater.processBlockVotesRecords(false)
   785  
   786  	}()
   787  
   788  	go func() {
   789  		defer wg.Done()
   790  		events := func() (events []*native.EventPayload) {
   791  			it := s.generator.store.table.Events.NewIterator(nil, nil)
   792  			defer it.Release()
   793  			for it.Next() {
   794  				e := &native.EventPayload{}
   795  				if err := rlp.DecodeBytes(it.Value(), e); err != nil {
   796  					s.generator.store.Log.Crit("Failed to decode event", "err", err)
   797  				}
   798  				if e != nil {
   799  					events = append(events, e)
   800  				}
   801  			}
   802  			return
   803  		}()
   804  
   805  		for _, e := range events {
   806  			s.processor.engineMu.Lock()
   807  			s.Require().NoError(s.processor.processEvent(e))
   808  			s.processor.engineMu.Unlock()
   809  		}
   810  	}()
   811  
   812  	wg.Wait()
   813  
   814  	// Comparing the store states
   815  	fetchTable := func(table u2udb.Store) map[string]string {
   816  		var m = make(map[string]string)
   817  		it := table.NewIterator(nil, nil)
   818  		defer it.Release()
   819  		for it.Next() {
   820  			key, value := it.Key(), it.Value()
   821  			m[string(key)] = string(value)
   822  		}
   823  		return m
   824  	}
   825  
   826  	s.Require().NoError(s.generator.store.Commit())
   827  	s.Require().NoError(s.processor.store.Commit())
   828  
   829  	// Comparing generator and fullRepeater states
   830  
   831  	// 1.Comparing Tx hashes
   832  	s.T().Log("Checking genBlockToTxsMap <= procRepBlockToTxsMap")
   833  	genBlockToTxsMap := fetchTxsbyBlock(s.generator)
   834  	procBlockToTxsMap := fetchTxsbyBlock(s.processor)
   835  	txByBlockSubsetOf(s.T(), procBlockToTxsMap, genBlockToTxsMap)
   836  
   837  	// 2.Compare BlockByNumber,BlockByhash, GetReceipts, GetLogs
   838  	fullRepeater.compareParams()
   839  
   840  	// 2. Comparing mainDb of generator and fullRepeater
   841  	genKVDB, _ := s.generator.store.dbs.OpenDB("gossip")
   842  	fullRepKVDB, _ := s.processor.store.dbs.OpenDB("gossip")
   843  	genKVMap := fetchTable(genKVDB)
   844  	fullRepKVMap := fetchTable(fullRepKVDB)
   845  
   846  	subsetOf := func(aa, bb map[string]string) {
   847  		for _k, _v := range aa {
   848  			k, v := []byte(_k), []byte(_v)
   849  			if k[0] == 0 || k[0] == 'x' || k[0] == 'X' || k[0] == 'b' || k[0] == 'S' {
   850  				continue
   851  			}
   852  			s.Require().Equal(hexutils.BytesToHex(v), hexutils.BytesToHex([]byte(bb[_k])))
   853  		}
   854  	}
   855  
   856  	checkEqual := func(aa, bb map[string]string) {
   857  		subsetOf(aa, bb)
   858  		subsetOf(bb, aa)
   859  	}
   860  
   861  	s.T().Log("Checking genKVs == fullKVs")
   862  	checkEqual(genKVMap, fullRepKVMap)
   863  
   864  	genKVMapAfterIndexLogsDB, _ := s.generator.store.dbs.OpenDB("gossip")
   865  	fullRepKVMapAfterIndexLogsDB, _ := s.processor.store.dbs.OpenDB("gossip")
   866  	genKVMapAfterIndexLogs := fetchTable(genKVMapAfterIndexLogsDB)
   867  	fullRepKVMapAfterIndexLogs := fetchTable(fullRepKVMapAfterIndexLogsDB)
   868  
   869  	// comparing the states
   870  	checkEqual(genKVMap, genKVMapAfterIndexLogs)
   871  	checkEqual(fullRepKVMap, fullRepKVMapAfterIndexLogs)
   872  	checkEqual(genKVMapAfterIndexLogs, fullRepKVMapAfterIndexLogs)
   873  
   874  	fullRepeater.compareLogsByFilterCriteria()
   875  }
   876  
   877  func TestLlrIntegrationTestSuite(t *testing.T) {
   878  	t.Skip() // skip until fixed
   879  	suite.Run(t, new(IntegrationTestSuite))
   880  }
   881  
   882  func TestBlockAndEpochRecords(t *testing.T) {
   883  	t.Skip() // skip until fixed
   884  	const (
   885  		validatorsNum = 10
   886  		startEpoch    = 1
   887  	)
   888  	// setup testEnv
   889  	env := newTestEnv(startEpoch, validatorsNum)
   890  
   891  	// 1.create epoch record er1 manually
   892  	er1 := ier.LlrIdxFullEpochRecord{Idx: idx.Epoch(startEpoch) + 1}
   893  	er1Hash := er1.Hash()
   894  	// 3. process ER1, the error will be popped up.
   895  	require.EqualError(t, env.ProcessFullEpochRecord(er1), eventcheck.ErrUndecidedER.Error())
   896  
   897  	// 2.create block record manually
   898  	br1 := ibr.LlrIdxFullBlockRecord{Idx: idx.Block(2)}
   899  	br1Hash := br1.Hash()
   900  	//3. process BR1, the error will popped up
   901  	require.EqualError(t, env.ProcessFullBlockRecord(br1), eventcheck.ErrUndecidedBR.Error())
   902  
   903  	// 4.create less than 1/3W+1 epoch votes, ER1 still should not be processed
   904  	for i := 1; i < 4; i++ {
   905  		e := fakeEvent(0, 0, true, 2, i, er1Hash)
   906  		ev := native.AsSignedEpochVote(e)
   907  		require.NoError(t, env.ProcessEpochVote(ev))
   908  	}
   909  	require.EqualError(t, env.ProcessFullEpochRecord(er1), eventcheck.ErrUndecidedER.Error())
   910  
   911  	// 5. add one more epoch vote,so 4 = 1/3W+1. Hence, ER1 has to be processed.
   912  	fmt.Println("adding 4th epoch vote")
   913  	e := fakeEvent(0, 0, true, 2, 4, er1Hash)
   914  	ev := native.AsSignedEpochVote(e)
   915  	require.NoError(t, env.ProcessEpochVote(ev))
   916  	require.NoError(t, env.ProcessFullEpochRecord(er1))
   917  
   918  	// 6.create epoch record er2  of same epoch as er1, but with another name.
   919  	er2 := ier.LlrIdxFullEpochRecord{Idx: idx.Epoch(startEpoch + 1)}
   920  	// 7.Get an error that the er has been already processed.
   921  	require.EqualError(t, env.ProcessFullEpochRecord(er2), eventcheck.ErrAlreadyProcessedER.Error())
   922  
   923  	//8. try to process Br1 with one vote with the same epoch as er1. it will(*Validators).GetWeightByIdx(...)
   924  	e = fakeEvent(1, er1.Idx, false, 0, 0, br1Hash)
   925  	bv := native.AsSignedBlockVotes(e)
   926  	require.EqualError(t, env.ProcessBlockVotes(bv), errValidatorNotExist.Error()) //cause there are no validators
   927  	require.EqualError(t, env.ProcessFullBlockRecord(br1), eventcheck.ErrUndecidedBR.Error())
   928  
   929  	//9,10. process er1 and er2. it should yield an ErrAlreadyProcessedER error
   930  	require.EqualError(t, env.ProcessFullEpochRecord(er1), eventcheck.ErrAlreadyProcessedER.Error())
   931  	require.EqualError(t, env.ProcessFullEpochRecord(er2), eventcheck.ErrAlreadyProcessedER.Error())
   932  
   933  	//11 add votes < 1/3W+1 for Br1. Record still should not be processed.
   934  	fmt.Println("adding 3 votes for br1")
   935  	for i := 5; i < 8; i++ {
   936  		e := fakeEvent(1, 0, false, 0, i, br1Hash)
   937  		bv := native.AsSignedBlockVotes(e)
   938  		require.NoError(t, env.ProcessBlockVotes(bv))
   939  	}
   940  	require.EqualError(t, env.ProcessFullBlockRecord(br1), eventcheck.ErrUndecidedBR.Error())
   941  
   942  	//12 add one vote for br1, then we have 1/3W+1 votes
   943  	fmt.Println("adding 4th block vote to make up to match 1/3W+1")
   944  	e = fakeEvent(1, 0, true, 2, 8, br1Hash)
   945  	bv = native.AsSignedBlockVotes(e)
   946  	require.NoError(t, env.ProcessBlockVotes(bv))
   947  
   948  	// 13. create one more record of the same block, but different.
   949  	br2 := ibr.LlrIdxFullBlockRecord{LlrFullBlockRecord: ibr.LlrFullBlockRecord{GasUsed: 100505}, Idx: idx.Block(2)}
   950  
   951  	// 14. process br2. It should output an error, that block record hash is mismatched.
   952  	require.EqualError(t, env.ProcessFullBlockRecord(br2), errors.New("block record hash mismatch").Error())
   953  
   954  	// 15 process br1
   955  	require.NoError(t, env.ProcessFullBlockRecord(br1))
   956  
   957  	//16 process br1 and br2, they should yield an error that they have been already processed
   958  	require.EqualError(t, env.ProcessFullBlockRecord(br1), eventcheck.ErrAlreadyProcessedBR.Error())
   959  	require.EqualError(t, env.ProcessFullBlockRecord(br2), eventcheck.ErrAlreadyProcessedBR.Error())
   960  }
   961  
   962  // can not import it from native package (((
   963  
   964  func fakeEvent(bvsNum int, bvEpoch idx.Epoch, ersNum bool, evEpoch idx.Epoch, valID int, recordHash hash.Hash) *native.EventPayload {
   965  	random := &native.MutableEventPayload{}
   966  	r := rand.New(rand.NewSource(int64(0)))
   967  	random.SetVersion(1)
   968  	random.SetEpoch(2)
   969  	random.SetNetForkID(0)
   970  	random.SetLamport(idx.Lamport(rand.Intn(100) + 900))
   971  	random.SetExtra([]byte{byte(r.Uint32())})
   972  	random.SetSeq(idx.Event(r.Uint32() >> 8))
   973  	random.SetCreator(idx.ValidatorID(valID))
   974  	random.SetFrame(idx.Frame(r.Uint32() >> 16))
   975  	random.SetCreationTime(native.Timestamp(r.Uint64()))
   976  	random.SetMedianTime(native.Timestamp(r.Uint64()))
   977  	random.SetGasPowerUsed(r.Uint64())
   978  	random.SetGasPowerLeft(native.GasPowerLeft{[2]uint64{r.Uint64(), r.Uint64()}})
   979  
   980  	bvs := native.LlrBlockVotes{}
   981  	if bvsNum > 0 {
   982  		bvs.Start = 2
   983  		switch {
   984  		case bvEpoch > 0:
   985  			bvs.Epoch = bvEpoch
   986  			random.SetEpoch(bvEpoch)
   987  		default:
   988  			bvs.Epoch = 1
   989  			random.SetEpoch(1)
   990  		}
   991  	}
   992  
   993  	for i := 0; i < bvsNum; i++ {
   994  		bvs.Votes = append(bvs.Votes, recordHash)
   995  	}
   996  
   997  	ev := native.LlrEpochVote{}
   998  	if ersNum {
   999  		ev.Epoch = evEpoch
  1000  		ev.Vote = recordHash
  1001  	}
  1002  
  1003  	random.SetEpochVote(ev)
  1004  	random.SetBlockVotes(bvs)
  1005  	random.SetPayloadHash(native.CalcPayloadHash(random))
  1006  
  1007  	parent := native.MutableEventPayload{}
  1008  	parent.SetVersion(1)
  1009  	parent.SetLamport(random.Lamport() - 500)
  1010  	parent.SetEpoch(random.Epoch())
  1011  	random.SetParents(hash.Events{parent.Build().ID()})
  1012  
  1013  	return random.Build()
  1014  }
  1015  
  1016  func randBig(r *rand.Rand) *big.Int {
  1017  	b := make([]byte, r.Intn(8))
  1018  	_, _ = r.Read(b)
  1019  	if len(b) == 0 {
  1020  		b = []byte{0}
  1021  	}
  1022  	return new(big.Int).SetBytes(b)
  1023  }
  1024  
  1025  func randBytes(r *rand.Rand, size int) []byte {
  1026  	b := make([]byte, size)
  1027  	r.Read(b)
  1028  	return b
  1029  }
  1030  
  1031  func randAddrPtr(r *rand.Rand) *common.Address {
  1032  	addr := randAddr(r)
  1033  	return &addr
  1034  }
  1035  
  1036  func randAddr(r *rand.Rand) common.Address {
  1037  	addr := common.Address{}
  1038  	r.Read(addr[:])
  1039  	return addr
  1040  }
  1041  
  1042  func randAccessList(r *rand.Rand, maxAddrs, maxKeys int) types.AccessList {
  1043  	accessList := make(types.AccessList, r.Intn(maxAddrs))
  1044  	for i := range accessList {
  1045  		accessList[i].Address = randAddr(r)
  1046  		accessList[i].StorageKeys = make([]common.Hash, r.Intn(maxKeys))
  1047  		for j := range accessList[i].StorageKeys {
  1048  			r.Read(accessList[i].StorageKeys[j][:])
  1049  		}
  1050  	}
  1051  	return accessList
  1052  }
  1053  
  1054  func TestEpochRecordWithDiffValidators(t *testing.T) {
  1055  	const (
  1056  		validatorsNum = 10
  1057  		startEpoch    = 2
  1058  	)
  1059  	require := require.New(t)
  1060  	// setup testEnv
  1061  	env := newTestEnv(startEpoch, validatorsNum)
  1062  
  1063  	// Стартвые валидаторы имеют равномерные веса, стартовая эпоха - 2
  1064  	bs, es := env.store.GetHistoryBlockEpochState(startEpoch)
  1065  
  1066  	// get new validators with different votes
  1067  	newVals := func() *pos.Validators {
  1068  		builder := pos.NewBuilder()
  1069  		defaultWeight := pos.Weight(111022302)
  1070  		for i := idx.ValidatorID(1); i <= 10; i++ {
  1071  			w := defaultWeight
  1072  			if i%2 == 0 {
  1073  				w -= 10021567
  1074  			} else {
  1075  				w += 10021567
  1076  			}
  1077  			builder.Set(i, w)
  1078  		}
  1079  		return builder.Build()
  1080  	}()
  1081  
  1082  	// save new validators to state of epoch 2
  1083  	esCopy := es.Copy()
  1084  	esCopy.Validators = newVals
  1085  
  1086  	// process ER of 3rd epoch
  1087  	er := ier.LlrIdxFullEpochRecord{
  1088  		LlrFullEpochRecord: ier.LlrFullEpochRecord{*bs, esCopy},
  1089  		Idx:                idx.Epoch(startEpoch + 1),
  1090  	}
  1091  	erHash := er.Hash()
  1092  
  1093  	for i := 1; i <= 4; i++ {
  1094  		e := fakeEvent(0, 0, true, startEpoch+1, i, erHash)
  1095  		ev := native.AsSignedEpochVote(e)
  1096  		// process validators with equal weights
  1097  		require.NoError(env.ProcessEpochVote(ev))
  1098  	}
  1099  
  1100  	require.NoError(env.ProcessFullEpochRecord(er))
  1101  
  1102  	// process ER of 4th epoch with validators with different weights
  1103  
  1104  	// get bs and es of 3rd apoch
  1105  	bs, es = env.store.GetHistoryBlockEpochState(startEpoch + 1)
  1106  
  1107  	// put es and bs of 3rd apoch at LlrIdxFullEpochRecord of epoch 4
  1108  	er = ier.LlrIdxFullEpochRecord{
  1109  		LlrFullEpochRecord: ier.LlrFullEpochRecord{*bs, *es},
  1110  		Idx:                idx.Epoch(startEpoch + 2)}
  1111  	erHash = er.Hash()
  1112  
  1113  	// confirm with votes of different weights
  1114  	for i := 1; i <= 5; i++ {
  1115  		e := fakeEvent(0, 0, true, startEpoch+2, i, erHash)
  1116  		ev := native.AsSignedEpochVote(e)
  1117  		require.NoError(env.ProcessEpochVote(ev))
  1118  	}
  1119  
  1120  	// process ER of epoch 4
  1121  	require.NoError(env.ProcessFullEpochRecord(er))
  1122  
  1123  	// process ER for epoch 5 and yield an error cause the total weight of validators is less than threshold 1/3W+1
  1124  	bs, es = env.store.GetHistoryBlockEpochState(startEpoch + 2)
  1125  
  1126  	// yield validators with unequal weights to process in epoch 6
  1127  	newVals, partialWeight := func() (*pos.Validators, pos.Weight) {
  1128  		builder := pos.NewBuilder()
  1129  		w := pos.Weight(1000)
  1130  
  1131  		// set 7 validators with weight 1000
  1132  		var partialWeight pos.Weight
  1133  		for i := idx.ValidatorID(1); i <= 7; i++ {
  1134  			partialWeight += w
  1135  			builder.Set(i, w)
  1136  		}
  1137  
  1138  		w = pos.Weight(1000000)
  1139  		//set 8th, 9th and 10th validatora with weight 1000000
  1140  		for i := idx.ValidatorID(8); i <= 10; i++ {
  1141  			builder.Set(i, w)
  1142  		}
  1143  
  1144  		return builder.Build(), partialWeight
  1145  	}()
  1146  
  1147  	// save new validators to state
  1148  	esCopy = es.Copy()
  1149  	esCopy.Validators = newVals
  1150  
  1151  	er = ier.LlrIdxFullEpochRecord{
  1152  		LlrFullEpochRecord: ier.LlrFullEpochRecord{*bs, esCopy},
  1153  		Idx:                idx.Epoch(startEpoch + 3),
  1154  	}
  1155  	erHash = er.Hash()
  1156  
  1157  	for i := 1; i <= 10; i++ {
  1158  		e := fakeEvent(0, 0, true, startEpoch+3, i, erHash)
  1159  		ev := native.AsSignedEpochVote(e)
  1160  		require.NoError(env.ProcessEpochVote(ev))
  1161  	}
  1162  
  1163  	require.NoError(env.ProcessFullEpochRecord(er))
  1164  
  1165  	// process ER with epoch 6
  1166  	bs, es = env.store.GetHistoryBlockEpochState(startEpoch + 3)
  1167  
  1168  	er = ier.LlrIdxFullEpochRecord{
  1169  		LlrFullEpochRecord: ier.LlrFullEpochRecord{*bs, *es},
  1170  		Idx:                idx.Epoch(startEpoch + 4),
  1171  	}
  1172  	erHash = er.Hash()
  1173  
  1174  	for i := 1; i <= 7; i++ {
  1175  		e := fakeEvent(0, 0, true, startEpoch+4, i, erHash)
  1176  		ev := native.AsSignedEpochVote(e)
  1177  		require.NoError(env.ProcessEpochVote(ev))
  1178  	}
  1179  
  1180  	// process ER for epoch 6
  1181  	// threshold weight is 1002334 = 1/3W+1
  1182  	// 7 validators with total weight 7000 is less than threshold weight
  1183  	// so 7 votes are not enough
  1184  	totalWeight := newVals.TotalWeight()
  1185  	thresholdWeight := pos.Weight(totalWeight/3 + 1)
  1186  	require.Less(partialWeight, thresholdWeight)
  1187  	require.EqualError(env.ProcessFullEpochRecord(er), eventcheck.ErrUndecidedER.Error())
  1188  }
  1189  
  1190  func TestProcessEpochVotesWonErNil(t *testing.T) {
  1191  
  1192  	const (
  1193  		validatorsNum = 10
  1194  		startEpoch    = 2
  1195  	)
  1196  
  1197  	require := require.New(t)
  1198  
  1199  	// setup testEnv
  1200  	env := newTestEnv(startEpoch, validatorsNum)
  1201  
  1202  	newVals, partialWeight := func() (*pos.Validators, pos.Weight) {
  1203  		builder := pos.NewBuilder()
  1204  		w := pos.Weight(1000)
  1205  
  1206  		// set 5 validators with weight 1000
  1207  		var partialWeight pos.Weight
  1208  		for i := idx.ValidatorID(1); i < 5; i++ {
  1209  			partialWeight += w
  1210  			builder.Set(i, w)
  1211  		}
  1212  
  1213  		w = pos.Weight(10000)
  1214  		//set 8th, 9th and 10th validatora with weight 10000
  1215  		for i := idx.ValidatorID(5); i <= 10; i++ {
  1216  			builder.Set(i, w)
  1217  			if i == idx.ValidatorID(9) || i == idx.ValidatorID(10) {
  1218  				continue
  1219  			}
  1220  			partialWeight += w
  1221  		}
  1222  
  1223  		return builder.Build(), partialWeight
  1224  	}()
  1225  
  1226  	bs, es := env.store.GetHistoryBlockEpochState(startEpoch)
  1227  
  1228  	esCopy := es.Copy()
  1229  	esCopy.Validators = newVals
  1230  
  1231  	er := ier.LlrIdxFullEpochRecord{
  1232  		LlrFullEpochRecord: ier.LlrFullEpochRecord{*bs, esCopy},
  1233  		Idx:                idx.Epoch(startEpoch + 1),
  1234  	}
  1235  	erHash := er.Hash()
  1236  
  1237  	// process validators with equal weights
  1238  	for i := 1; i <= 4; i++ {
  1239  		e := fakeEvent(0, 0, true, startEpoch+1, i, erHash)
  1240  		ev := native.AsSignedEpochVote(e)
  1241  		require.NoError(env.ProcessEpochVote(ev))
  1242  	}
  1243  
  1244  	require.NoError(env.ProcessFullEpochRecord(er))
  1245  
  1246  	bs, es = env.store.GetHistoryBlockEpochState(startEpoch + 1)
  1247  
  1248  	er = ier.LlrIdxFullEpochRecord{
  1249  		LlrFullEpochRecord: ier.LlrFullEpochRecord{*bs, *es},
  1250  		Idx:                idx.Epoch(startEpoch + 2),
  1251  	}
  1252  	erHash = er.Hash()
  1253  
  1254  	// process  validators with inequal weighs
  1255  	// total weights of all validators
  1256  	for i := 1; i <= 8; i++ {
  1257  		e := fakeEvent(0, 0, true, startEpoch+2, i, erHash)
  1258  		ev := native.AsSignedEpochVote(e)
  1259  		require.NoError(env.ProcessEpochVote(ev))
  1260  	}
  1261  
  1262  	res := env.store.GetLlrEpochResult(startEpoch + 2)
  1263  	require.NotNil(res)
  1264  	require.NotNil(erHash.Hex(), res.Hex())
  1265  
  1266  	llrs := env.store.GetLlrState()
  1267  	actualLowestEpochToDecide := llrs.LowestEpochToDecide
  1268  	expectedLowestEpochToDecide := idx.Epoch(actualizeLowestIndex(uint64(llrs.LowestEpochToDecide), uint64(startEpoch+2),
  1269  		func(u uint64) bool {
  1270  			return env.store.GetLlrEpochResult(idx.Epoch(u)) != nil
  1271  		}))
  1272  	require.Equal(actualLowestEpochToDecide, expectedLowestEpochToDecide)
  1273  
  1274  	totalWeight := newVals.TotalWeight()
  1275  	thresholdWeight := pos.Weight(totalWeight/3 + 1)
  1276  	require.GreaterOrEqual(partialWeight, thresholdWeight)
  1277  
  1278  	require.NoError(env.ProcessFullEpochRecord(er))
  1279  }
  1280  
  1281  func TestProcessEpochVotesWonErNotNilDoubleSign(t *testing.T) {
  1282  
  1283  	const (
  1284  		validatorsNum = 10
  1285  		startEpoch    = 2
  1286  	)
  1287  
  1288  	require := require.New(t)
  1289  
  1290  	// setup testEnv
  1291  	env := newTestEnv(startEpoch, validatorsNum)
  1292  
  1293  	newVals := func() *pos.Validators {
  1294  		builder := pos.NewBuilder()
  1295  		w := pos.Weight(1000)
  1296  
  1297  		//thresholdweight totalWeight(8200)/3 +1 = 2734
  1298  		// set 8 validators with weight 1000
  1299  
  1300  		for i := idx.ValidatorID(1); i <= 8; i++ {
  1301  			//partialWeight += w
  1302  			builder.Set(i, w)
  1303  		}
  1304  
  1305  		w = pos.Weight(100)
  1306  		//set 9th and 10th validatora with weight 100
  1307  		for i := idx.ValidatorID(9); i <= 10; i++ {
  1308  			builder.Set(i, w)
  1309  		}
  1310  
  1311  		return builder.Build()
  1312  	}()
  1313  
  1314  	bs, es := env.store.GetHistoryBlockEpochState(startEpoch)
  1315  
  1316  	esCopy := es.Copy()
  1317  	esCopy.Validators = newVals
  1318  
  1319  	er := ier.LlrIdxFullEpochRecord{
  1320  		LlrFullEpochRecord: ier.LlrFullEpochRecord{*bs, esCopy},
  1321  		Idx:                idx.Epoch(startEpoch + 1),
  1322  	}
  1323  	erHash := er.Hash()
  1324  
  1325  	// process validators with equal weights
  1326  	for i := 1; i <= 4; i++ {
  1327  		e := fakeEvent(0, 0, true, startEpoch+1, i, erHash)
  1328  		ev := native.AsSignedEpochVote(e)
  1329  		require.NoError(env.ProcessEpochVote(ev))
  1330  	}
  1331  
  1332  	require.NoError(env.ProcessFullEpochRecord(er))
  1333  
  1334  	bs, es = env.store.GetHistoryBlockEpochState(startEpoch + 1)
  1335  
  1336  	er = ier.LlrIdxFullEpochRecord{
  1337  		LlrFullEpochRecord: ier.LlrFullEpochRecord{*bs, *es},
  1338  		Idx:                idx.Epoch(startEpoch + 2),
  1339  	}
  1340  
  1341  	require.Equal(er.Hash().Hex(), erHash.Hex())
  1342  
  1343  	// process  validators with inequal weighs
  1344  	for i := 1; i <= 3; i++ {
  1345  		e := fakeEvent(0, 0, true, startEpoch+2, i, erHash)
  1346  		ev := native.AsSignedEpochVote(e)
  1347  		require.NoError(env.ProcessEpochVote(ev))
  1348  
  1349  		// output error if an event has been previously processed
  1350  		require.EqualError(env.ProcessEpochVote(ev), eventcheck.ErrAlreadyProcessedEV.Error())
  1351  	}
  1352  
  1353  	res1 := env.store.GetLlrEpochResult(startEpoch + 2)
  1354  	require.Equal(res1.Hex(), erHash.Hex())
  1355  
  1356  	// Unvoted validators submit their votes for invalid hash record to cause doublesign
  1357  	// the weight of these validators is 3000 that is >= w/3+1
  1358  	invalidHash := hash.HexToHash("0x12")
  1359  	for i := 5; i <= 7; i++ {
  1360  		e := fakeEvent(0, 0, true, startEpoch+2, i, invalidHash)
  1361  		ev := native.AsSignedEpochVote(e)
  1362  		require.NoError(env.ProcessEpochVote(ev))
  1363  	}
  1364  
  1365  	// checking double sign
  1366  	wonEr := env.store.GetLlrEpochResult(startEpoch + 2) // erHash
  1367  	require.NotNil(wonEr)                                // wonEr != nil
  1368  	require.Equal(wonEr.Hex(), erHash.Hex())
  1369  	require.NotEqual(wonEr.Hex(), invalidHash.Hex()) // *wonEr != ev
  1370  
  1371  	// processing an event with incorrect epoch will result in eventcheck.ErrUnknownEpochEV error
  1372  	i := 9
  1373  	invalidEpoch := idx.Epoch(1)
  1374  	e := fakeEvent(0, 0, true, invalidEpoch, i, erHash)
  1375  	require.EqualError(env.ProcessEpochVote(native.AsSignedEpochVote(e)), eventcheck.ErrUnknownEpochEV.Error())
  1376  
  1377  	// processing an event with incorrect epoch will result in eventcheck.ErrUnknownEpochEV error
  1378  	i = 10
  1379  	invalidEpoch = idx.Epoch(20)
  1380  	e = fakeEvent(0, 0, true, invalidEpoch, i, erHash)
  1381  	require.EqualError(env.ProcessEpochVote(native.AsSignedEpochVote(e)), eventcheck.ErrUnknownEpochEV.Error())
  1382  
  1383  	require.NoError(env.ProcessFullEpochRecord(er))
  1384  
  1385  	// check that unvoted validators with less weight than 1/3w+1 can not damage LLR
  1386  
  1387  	bs, es = env.store.GetHistoryBlockEpochState(startEpoch + 2)
  1388  
  1389  	er = ier.LlrIdxFullEpochRecord{
  1390  		LlrFullEpochRecord: ier.LlrFullEpochRecord{*bs, *es},
  1391  		Idx:                idx.Epoch(startEpoch + 3),
  1392  	}
  1393  
  1394  	// total weight = 2000, threshold 1/3w+1 is 2733
  1395  	for i := 1; i < 3; i++ {
  1396  		e := fakeEvent(0, 0, true, startEpoch+3, i, invalidHash)
  1397  		ev := native.AsSignedEpochVote(e)
  1398  		require.NoError(env.ProcessEpochVote(ev))
  1399  	}
  1400  
  1401  	wonEr = env.store.GetLlrEpochResult(startEpoch + 3)
  1402  	require.Nil(wonEr)
  1403  
  1404  	require.EqualError(env.ProcessFullEpochRecord(er), eventcheck.ErrUndecidedER.Error())
  1405  }
  1406  
  1407  func TestProcessBlockVotesDoubleSign(t *testing.T) {
  1408  	const (
  1409  		validatorsNum = 10
  1410  		startEpoch    = 1
  1411  	)
  1412  
  1413  	require := require.New(t)
  1414  
  1415  	// setup testEnv
  1416  	env := newTestEnv(startEpoch, validatorsNum)
  1417  
  1418  	br1 := ibr.LlrIdxFullBlockRecord{Idx: idx.Block(2)}
  1419  	br1Hash := br1.Hash()
  1420  
  1421  	// adding 4 votes for br1 it excceeds 1/3W+1 since all weights are equal
  1422  	for i := 1; i <= 4; i++ {
  1423  		e := fakeEvent(1, 0, false, 0, i, br1Hash)
  1424  		bv := native.AsSignedBlockVotes(e)
  1425  		require.NoError(env.ProcessBlockVotes(bv))
  1426  		require.EqualError(env.ProcessBlockVotes(bv), eventcheck.ErrAlreadyProcessedBVs.Error())
  1427  	}
  1428  
  1429  	wonBr := env.store.GetLlrBlockResult(idx.Block(2))
  1430  	require.NotNil(wonBr)
  1431  	require.Equal(wonBr.Hex(), br1Hash.Hex())
  1432  
  1433  	// compare llrs.LowestBlockToDecide
  1434  	llrs := env.store.GetLlrState()
  1435  	actualLowestBlockToDecide := llrs.LowestBlockToDecide
  1436  	expectedLowestBlockToDecide := idx.Block(actualizeLowestIndex(uint64(llrs.LowestBlockToDecide), uint64(2), func(u uint64) bool {
  1437  		return env.store.GetLlrBlockResult(idx.Block(u)) != nil
  1438  	}))
  1439  	require.Equal(actualLowestBlockToDecide, expectedLowestBlockToDecide)
  1440  
  1441  	// doublesign scenario
  1442  	invalidHash := hash.HexToHash("0x12")
  1443  	for i := 1; i <= 4; i++ {
  1444  		e := fakeEvent(1, 0, false, 0, i, invalidHash)
  1445  		bv := native.AsSignedBlockVotes(e)
  1446  		require.NoError(env.ProcessBlockVotes(bv))
  1447  	}
  1448  
  1449  	wonBr = env.store.GetLlrBlockResult(idx.Block(2)) //br1Hash
  1450  	require.NotNil(wonBr)
  1451  	require.NotEqual(wonBr.Hex(), invalidHash.Hex()) // *wonBr != bv
  1452  }
  1453  
  1454  /*
  1455  
  1456  Blockvotes test cases
  1457  1) hash of block record incorrect, block N does not belong epoch E,
  1458  block vote for correct/incorrect hash
  1459  validators from enother epoch
  1460  2) hash of block record correct, block N does not belong epoch E, block vote for correct/incorrect hash   validators >= 1/3W ,validators <=1/3W -> error anticipated
  1461  3) hash of block record correct, block N belongs epoch E, block vote for correct/incorrect hash validators >= 1/3W ,validators <=1/3W
  1462  
  1463  
  1464  Переменные             Значения
  1465  hash of block record   correct | incorrect
  1466  block N                belongs to epoch E | does not belong to epoch E
  1467  validators             have total weight <= 1/3W | have total weights >= 1/3W | vote for correct/incorrect hash record | vote for correct/ incorrect epoch | have equal weights or not | vote for block N or for incorrect block
  1468  
  1469  vote for a block
  1470  
  1471  
  1472  type BlockCtx struct {
  1473  	Idx     idx.Block
  1474  	Time    native.Timestamp
  1475  	Atropos hash.Event
  1476  }
  1477  
  1478      highestBlock.Idx = blockIdx
  1479  	highestBlock.Atropos = block.Atropos
  1480  	highestBlock.Time = block.Time
  1481  	blockproc.BlockState{
  1482  		LastBlock:             highestBlock,
  1483  
  1484  	}
  1485  
  1486  TODO test with not random validators
  1487  
  1488  */
  1489  
  1490  func TestBlockVotesTests(t *testing.T) {
  1491  	const (
  1492  		validatorsNum = 10
  1493  		startEpoch    = 1
  1494  	)
  1495  
  1496  	require := require.New(t)
  1497  
  1498  	// setup testEnv
  1499  	env := newTestEnv(startEpoch, validatorsNum)
  1500  
  1501  	bs, es := env.store.GetHistoryBlockEpochState(startEpoch)
  1502  
  1503  	newVals := func() *pos.Validators {
  1504  		builder := pos.NewBuilder()
  1505  		w := pos.Weight(1000)
  1506  
  1507  		//thresholdweight totalWeight(8200)/3 +1 = 2734
  1508  		// set 8 validators with weight 1000
  1509  
  1510  		for i := idx.ValidatorID(1); i <= 8; i++ {
  1511  			//partialWeight += w
  1512  			builder.Set(i, w)
  1513  		}
  1514  
  1515  		w = pos.Weight(100)
  1516  		//set 9th and 10th validatora with weight 100
  1517  		for i := idx.ValidatorID(9); i <= 10; i++ {
  1518  			builder.Set(i, w)
  1519  		}
  1520  
  1521  		return builder.Build()
  1522  	}()
  1523  
  1524  	// save new validators to state of epoch 2
  1525  	esCopy := es.Copy()
  1526  	esCopy.Validators = newVals
  1527  
  1528  	// process ER of 3rd epoch
  1529  	er := ier.LlrIdxFullEpochRecord{
  1530  		LlrFullEpochRecord: ier.LlrFullEpochRecord{*bs, esCopy},
  1531  		Idx:                idx.Epoch(startEpoch + 1),
  1532  	}
  1533  	erHash := er.Hash()
  1534  
  1535  	incorrectValEvent := fakeEvent(0, 0, true, startEpoch+1, validatorsNum+1, erHash)
  1536  	ev := native.AsSignedEpochVote(incorrectValEvent)
  1537  	require.NoError(env.checkers.Basiccheck.ValidateEV(ev))
  1538  	require.EqualError(env.checkers.Heavycheck.ValidateEV(ev), epochcheck.ErrAuth.Error())
  1539  	require.EqualError(env.ProcessEpochVote(ev), errValidatorNotExist.Error())
  1540  
  1541  	for i := 1; i <= 4; i++ {
  1542  		e := fakeEvent(0, 0, true, startEpoch+1, i, erHash)
  1543  		ev := native.AsSignedEpochVote(e)
  1544  		// process validators with equal weights
  1545  		require.NoError(env.checkers.Basiccheck.ValidateEV(ev))
  1546  		// TODO debug it require.NoError(env.checkers.Heavycheck.ValidateEV(ev))
  1547  		require.NoError(env.ProcessEpochVote(ev))
  1548  	}
  1549  
  1550  	require.NoError(env.ProcessFullEpochRecord(er))
  1551  
  1552  	bs, es = env.store.GetHistoryBlockEpochState(startEpoch + 1)
  1553  
  1554  	er = ier.LlrIdxFullEpochRecord{
  1555  		LlrFullEpochRecord: ier.LlrFullEpochRecord{*bs, *es},
  1556  		Idx:                idx.Epoch(startEpoch + 2)}
  1557  	erHash = er.Hash()
  1558  
  1559  	br := ibr.LlrIdxFullBlockRecord{Idx: idx.Block(2)}
  1560  	brHash := br.Hash()
  1561  
  1562  	//we can votr for validators with the different weights
  1563  	incorrectBVEpoch := idx.Epoch(3)
  1564  	e := fakeEvent(1, incorrectBVEpoch, false, 0, 1, brHash)
  1565  	bvs := native.AsSignedBlockVotes(e)
  1566  	require.NoError(env.checkers.Basiccheck.ValidateBVs(bvs))
  1567  	//	require.NoError(env.checkers.Heavycheck.ValidateBVs(bvs)) debug it event has whone signature
  1568  	require.EqualError(env.ProcessBlockVotes(bvs), eventcheck.ErrUnknownEpochBVs.Error())
  1569  
  1570  	// ьфлу туц е
  1571  
  1572  	//require.EqualError(env.ProcessBlockVotes(bvs), eventcheck.ErrAlreadyProcessedBVs.Error())
  1573  
  1574  	/*
  1575  		for i := 5; i < 8; i++ {
  1576  			e := fakeEvent(20, 0, false, 0, i, brHash)
  1577  			bvs := native.AsSignedBlockVotes(e)
  1578  			require.NoError(env.checkers.Basiccheck.ValidateBVs(bvs))
  1579  			require.NoError(env.checkers.Heavycheck.ValidateBVs(bvs))
  1580  			require.NoError(env.ProcessBlockVotes(bvs))
  1581  		}
  1582  	*/
  1583  }
  1584  
  1585  func fakeEventWithLamport(bv native.LlrBlockVotes, ev native.LlrEpochVote, lamport idx.Lamport) *native.EventPayload {
  1586  	me := &native.MutableEventPayload{}
  1587  	me.SetVersion(1)
  1588  	me.SetEpoch(2)
  1589  	me.SetNetForkID(0)
  1590  	me.SetLamport(lamport)
  1591  	me.SetCreator(idx.ValidatorID(1))
  1592  	me.SetBlockVotes(bv)
  1593  	me.SetEpochVote(ev)
  1594  	me.SetPayloadHash(native.CalcPayloadHash(me))
  1595  	return me.Build()
  1596  }
  1597  
  1598  func TestProcessBlockVotesOneValidatorMultipleBvs(t *testing.T) {
  1599  	t.Skip() // skip until fixed
  1600  	const (
  1601  		validatorsNum = 10
  1602  		startEpoch    = 2
  1603  	)
  1604  
  1605  	br := ibr.LlrIdxFullBlockRecord{Idx: idx.Block(2)}
  1606  	brHash := br.Hash()
  1607  
  1608  	require := require.New(t)
  1609  
  1610  	getBv := func(start idx.Block, epoch idx.Epoch, vote hash.Hash, bvNum int) native.LlrBlockVotes {
  1611  		bv := native.LlrBlockVotes{
  1612  			Start: start,
  1613  			Epoch: epoch,
  1614  		}
  1615  
  1616  		for i := 0; i < bvNum; i++ {
  1617  			bv.Votes = append(bv.Votes, vote)
  1618  		}
  1619  
  1620  		return bv
  1621  	}
  1622  
  1623  	testCases := []struct {
  1624  		name    string
  1625  		pretest func(*testEnv)
  1626  	}{
  1627  		{
  1628  			"bv with different Start",
  1629  			func(env *testEnv) {
  1630  				EventWithBvCorrectStart := fakeEventWithLamport(getBv(2, 2, brHash, 1), native.LlrEpochVote{}, idx.Lamport(rand.Intn(100)))
  1631  				require.NoError(env.ProcessBlockVotes(native.AsSignedBlockVotes(EventWithBvCorrectStart)))
  1632  
  1633  				randLamport := idx.Lamport(rand.Intn(100))
  1634  				for i := 0; i < 9; i++ {
  1635  					bv := getBv(idx.Block(i+1), 2, brHash, 1)
  1636  					e := fakeEventWithLamport(bv, native.LlrEpochVote{}, randLamport)
  1637  					require.NoError(env.ProcessBlockVotes(native.AsSignedBlockVotes(e)))
  1638  				}
  1639  			},
  1640  		},
  1641  		{
  1642  			"bv with different votes",
  1643  			func(env *testEnv) {
  1644  				randLamport := idx.Lamport(rand.Intn(100))
  1645  				for i := 0; i < 10; i++ {
  1646  					bv := getBv(2, 2, brHash, i)
  1647  					e := fakeEventWithLamport(bv, native.LlrEpochVote{}, randLamport)
  1648  					require.NoError(env.ProcessBlockVotes(native.AsSignedBlockVotes(e)))
  1649  				}
  1650  			},
  1651  		},
  1652  		{
  1653  			"bv with different Lamport",
  1654  			func(env *testEnv) {
  1655  				bv := getBv(2, 2, brHash, 1)
  1656  				for i := 0; i < 9; i++ {
  1657  					randLamport := idx.Lamport(rand.Intn(1000))
  1658  					e := fakeEventWithLamport(bv, native.LlrEpochVote{}, randLamport)
  1659  					require.NoError(env.ProcessBlockVotes(native.AsSignedBlockVotes(e)))
  1660  				}
  1661  			},
  1662  		},
  1663  	}
  1664  
  1665  	for _, tc := range testCases {
  1666  		tc := tc
  1667  		t.Run(tc.name, func(t *testing.T) {
  1668  			env := newTestEnv(startEpoch, validatorsNum)
  1669  			tc.pretest(env)
  1670  			require.EqualError(env.ProcessFullBlockRecord(br), eventcheck.ErrUndecidedBR.Error())
  1671  		})
  1672  	}
  1673  }
  1674  
  1675  func TestProcessEpochVotesOneValidatorMultipleEvsDiffLamport(t *testing.T) {
  1676  	const (
  1677  		validatorsNum = 5
  1678  		startEpoch    = 2
  1679  	)
  1680  
  1681  	require := require.New(t)
  1682  
  1683  	getEv := func(epoch idx.Epoch, vote hash.Hash) native.LlrEpochVote {
  1684  		return native.LlrEpochVote{
  1685  			Epoch: epoch,
  1686  			Vote:  vote,
  1687  		}
  1688  	}
  1689  
  1690  	env := newTestEnv(startEpoch, validatorsNum)
  1691  
  1692  	er := ier.LlrIdxFullEpochRecord{Idx: idx.Epoch(startEpoch) + 1}
  1693  	erHash := er.Hash()
  1694  
  1695  	for i := 0; i < validatorsNum; i++ {
  1696  		randLamport := idx.Lamport(rand.Intn(1000))
  1697  		e := fakeEventWithLamport(native.LlrBlockVotes{}, getEv(startEpoch+1, erHash), randLamport)
  1698  		require.NoError(env.ProcessEpochVote(native.AsSignedEpochVote(e)))
  1699  	}
  1700  
  1701  	require.EqualError(env.ProcessFullEpochRecord(er), eventcheck.ErrUndecidedER.Error())
  1702  }