github.com/iotexproject/iotex-core@v1.14.1-rc1/blockindex/indexbuilder_test.go (about) 1 package blockindex 2 3 import ( 4 "context" 5 "math/big" 6 "testing" 7 "time" 8 9 "github.com/iotexproject/go-pkgs/hash" 10 "github.com/pkg/errors" 11 "github.com/stretchr/testify/require" 12 13 "github.com/iotexproject/iotex-core/action" 14 "github.com/iotexproject/iotex-core/action/protocol" 15 "github.com/iotexproject/iotex-core/blockchain" 16 "github.com/iotexproject/iotex-core/blockchain/block" 17 "github.com/iotexproject/iotex-core/blockchain/blockdao" 18 "github.com/iotexproject/iotex-core/blockchain/filedao" 19 "github.com/iotexproject/iotex-core/blockchain/genesis" 20 "github.com/iotexproject/iotex-core/db" 21 "github.com/iotexproject/iotex-core/test/identityset" 22 "github.com/iotexproject/iotex-core/testutil" 23 ) 24 25 func TestIndexBuilder(t *testing.T) { 26 require := require.New(t) 27 28 blks := getTestBlocks(t) 29 30 t1Hash, _ := blks[0].Actions[0].Hash() 31 t4Hash, _ := blks[0].Actions[1].Hash() 32 e1Hash, _ := blks[0].Actions[2].Hash() 33 t2Hash, _ := blks[1].Actions[0].Hash() 34 t5Hash, _ := blks[1].Actions[1].Hash() 35 e2Hash, _ := blks[1].Actions[2].Hash() 36 t3Hash, _ := blks[2].Actions[0].Hash() 37 t6Hash, _ := blks[2].Actions[1].Hash() 38 e3Hash, _ := blks[2].Actions[2].Hash() 39 40 type index struct { 41 addr hash.Hash160 42 hashes [][]byte 43 } 44 45 indexTests := struct { 46 total uint64 47 hashTotal [][]byte 48 actions [4]index 49 }{ 50 9, 51 [][]byte{t1Hash[:], t4Hash[:], e1Hash[:], t2Hash[:], t5Hash[:], e2Hash[:], t3Hash[:], t6Hash[:], e3Hash[:]}, 52 [4]index{ 53 {hash.BytesToHash160(identityset.Address(28).Bytes()), 54 [][]byte{t1Hash[:], t4Hash[:], e1Hash[:], t6Hash[:]}}, 55 {hash.BytesToHash160(identityset.Address(29).Bytes()), 56 [][]byte{t4Hash[:], t2Hash[:], t5Hash[:], e2Hash[:]}}, 57 {hash.BytesToHash160(identityset.Address(30).Bytes()), 58 [][]byte{t5Hash[:], t3Hash[:], t6Hash[:], e3Hash[:]}}, 59 {hash.BytesToHash160(identityset.Address(31).Bytes()), 60 [][]byte{e1Hash[:], e2Hash[:], e3Hash[:]}}, 61 }, 62 } 63 64 testIndexer := func(dao blockdao.BlockDAO, indexer Indexer, t *testing.T) { 65 ctx := protocol.WithBlockchainCtx( 66 genesis.WithGenesisContext(context.Background(), genesis.Default), 67 protocol.BlockchainCtx{ 68 ChainID: blockchain.DefaultConfig.ID, 69 }) 70 require.NoError(dao.Start(ctx)) 71 require.NoError(indexer.Start(ctx)) 72 ib := &IndexBuilder{ 73 dao: dao, 74 indexer: indexer, 75 genesis: genesis.Default, 76 } 77 defer func() { 78 require.NoError(ib.Stop(ctx)) 79 require.NoError(dao.Stop(ctx)) 80 }() 81 82 // put 2 blocks first 83 require.NoError(dao.PutBlock(ctx, blks[0])) 84 require.NoError(dao.PutBlock(ctx, blks[1])) 85 startHeight, err := ib.indexer.Height() 86 require.NoError(err) 87 require.EqualValues(0, startHeight) 88 tipHeight, err := dao.Height() 89 require.NoError(err) 90 require.EqualValues(2, tipHeight) 91 92 // init() should build index for first 2 blocks 93 require.NoError(ib.init(ctx)) 94 height, err := ib.indexer.Height() 95 require.NoError(err) 96 require.EqualValues(2, height) 97 98 // test handle 1 new block 99 require.NoError(dao.PutBlock(ctx, blks[2])) 100 ib.ReceiveBlock(blks[2]) 101 time.Sleep(500 * time.Millisecond) 102 103 height, err = ib.indexer.Height() 104 require.NoError(err) 105 require.EqualValues(3, height) 106 107 // Test GetActionIndex 108 actIndex, err := indexer.GetActionIndex(t1Hash[:]) 109 require.NoError(err) 110 require.Equal(blks[0].Height(), actIndex.BlockHeight()) 111 actIndex, err = indexer.GetActionIndex(t2Hash[:]) 112 require.NoError(err) 113 require.Equal(blks[1].Height(), actIndex.BlockHeight()) 114 actIndex, err = indexer.GetActionIndex(t3Hash[:]) 115 require.NoError(err) 116 require.Equal(blks[2].Height(), actIndex.BlockHeight()) 117 118 // Test get actions 119 total, err := indexer.GetTotalActions() 120 require.NoError(err) 121 require.EqualValues(indexTests.total, total) 122 _, err = indexer.GetActionHashFromIndex(1, total) 123 require.Equal(db.ErrInvalid, errors.Cause(err)) 124 actions, err := indexer.GetActionHashFromIndex(0, total) 125 require.NoError(err) 126 require.Equal(actions, indexTests.hashTotal) 127 for j := range indexTests.actions { 128 actionCount, err := indexer.GetActionCountByAddress(indexTests.actions[j].addr) 129 require.NoError(err) 130 require.EqualValues(len(indexTests.actions[j].hashes), actionCount) 131 if actionCount > 0 { 132 actions, err := indexer.GetActionsByAddress(indexTests.actions[j].addr, 0, actionCount) 133 require.NoError(err) 134 require.Equal(actions, indexTests.actions[j].hashes) 135 } 136 } 137 138 for i := 0; i < 3; i++ { 139 amount := big.NewInt(0) 140 tsfs, _ := classifyActions(blks[i].Actions) 141 for _, tsf := range tsfs { 142 amount.Add(amount, tsf.Amount()) 143 } 144 145 // test getNumActions/getTranferAmount 146 index, err := indexer.GetBlockIndex(blks[i].Height()) 147 require.NoError(err) 148 require.Equal(blks[i].HashBlock(), hash.BytesToHash256(index.Hash())) 149 require.EqualValues(len(blks[i].Actions), index.NumAction()) 150 require.Equal(amount, index.TsfAmount()) 151 } 152 } 153 154 path := "test-indexer" 155 testPath, err := testutil.PathOfTempFile(path) 156 require.NoError(err) 157 indexPath, err := testutil.PathOfTempFile(path) 158 require.NoError(err) 159 defer func() { 160 testutil.CleanupPath(testPath) 161 testutil.CleanupPath(indexPath) 162 }() 163 cfg := db.DefaultConfig 164 cfg.DbPath = testPath 165 filestore, err := filedao.NewFileDAO(cfg, block.NewDeserializer(blockchain.DefaultConfig.EVMNetworkID)) 166 require.NoError(err) 167 memstore, err := filedao.NewFileDAOInMemForTest() 168 require.NoError(err) 169 for _, v := range []struct { 170 dao blockdao.BlockDAO 171 inMem bool 172 }{ 173 { 174 memstore, true, 175 }, 176 { 177 filestore, false, 178 }, 179 } { 180 t.Run("test indexbuilder", func(t *testing.T) { 181 var ( 182 indexer Indexer 183 err error 184 ) 185 if v.inMem { 186 indexer, err = NewIndexer(db.NewMemKVStore(), hash.ZeroHash256) 187 } else { 188 cfg.DbPath = indexPath 189 indexer, err = NewIndexer(db.NewBoltDB(cfg), hash.ZeroHash256) 190 } 191 require.NoError(err) 192 testIndexer(v.dao, indexer, t) 193 }) 194 } 195 } 196 197 // classifyActions classfies actions 198 func classifyActions(actions []*action.SealedEnvelope) ([]*action.Transfer, []*action.Execution) { 199 tsfs := make([]*action.Transfer, 0) 200 exes := make([]*action.Execution, 0) 201 for _, elp := range actions { 202 act := elp.Action() 203 switch act := act.(type) { 204 case *action.Transfer: 205 tsfs = append(tsfs, act) 206 case *action.Execution: 207 exes = append(exes, act) 208 } 209 } 210 return tsfs, exes 211 }