github.com/iotexproject/iotex-core@v1.14.1-rc1/blockchain/filedao/testing.go (about) 1 // Copyright (c) 2020 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package filedao 7 8 import ( 9 "context" 10 "encoding/hex" 11 "math/big" 12 "testing" 13 14 "github.com/pkg/errors" 15 "github.com/stretchr/testify/require" 16 17 "github.com/iotexproject/go-pkgs/cache" 18 "github.com/iotexproject/go-pkgs/hash" 19 "github.com/iotexproject/iotex-proto/golang/iotextypes" 20 21 "github.com/iotexproject/iotex-core/action" 22 "github.com/iotexproject/iotex-core/blockchain/block" 23 "github.com/iotexproject/iotex-core/blockchain/genesis" 24 "github.com/iotexproject/iotex-core/db" 25 "github.com/iotexproject/iotex-core/db/batch" 26 "github.com/iotexproject/iotex-core/test/identityset" 27 "github.com/iotexproject/iotex-core/testutil" 28 ) 29 30 var _defaultEVMNetworkID uint32 = 4689 31 32 type ( 33 // testInMemFd is an in-memory FileDAO 34 testInMemFd struct { 35 *fileDAOv2 36 } 37 38 // testFailPutBlock will fail PutBlock() at certain height 39 testFailPutBlock struct { 40 *fileDAO 41 failHeight uint64 42 } 43 ) 44 45 func newTestInMemFd() (*testInMemFd, error) { 46 v2, err := newFileDAOv2InMem(1) 47 if err != nil { 48 return nil, err 49 } 50 return &testInMemFd{fileDAOv2: v2}, nil 51 } 52 53 // newFileDAOv2InMem creates a in-memory new v2 fileDAO 54 func newFileDAOv2InMem(bottom uint64) (*fileDAOv2, error) { 55 if bottom == 0 { 56 return nil, ErrNotSupported 57 } 58 59 fd := fileDAOv2{ 60 header: &FileHeader{ 61 Version: FileV2, 62 Compressor: "", 63 BlockStoreSize: 16, 64 Start: bottom, 65 }, 66 tip: &FileTip{ 67 Height: bottom - 1, 68 }, 69 blkStorePbCache: cache.NewThreadSafeLruCache(16), 70 blkCache: cache.NewThreadSafeLruCache(256), 71 receiptCache: cache.NewThreadSafeLruCache(256), 72 kvStore: db.NewMemKVStore(), 73 batch: batch.NewBatch(), 74 deser: block.NewDeserializer(_defaultEVMNetworkID), 75 } 76 return &fd, nil 77 } 78 79 func (fd *testInMemFd) GetBlockHash(height uint64) (hash.Hash256, error) { 80 if height == 0 { 81 return block.GenesisHash(), nil 82 } 83 return fd.fileDAOv2.GetBlockHash(height) 84 } 85 86 func (fd *testInMemFd) GetBlockHeight(h hash.Hash256) (uint64, error) { 87 if h == block.GenesisHash() { 88 return 0, nil 89 } 90 return fd.fileDAOv2.GetBlockHeight(h) 91 } 92 93 func (fd *testInMemFd) GetBlock(h hash.Hash256) (*block.Block, error) { 94 if h == block.GenesisHash() { 95 return block.GenesisBlock(), nil 96 } 97 return fd.fileDAOv2.GetBlock(h) 98 } 99 100 func (fd *testInMemFd) GetBlockByHeight(height uint64) (*block.Block, error) { 101 if height == 0 { 102 return block.GenesisBlock(), nil 103 } 104 return fd.fileDAOv2.GetBlockByHeight(height) 105 } 106 107 func (fd *testInMemFd) Header(h hash.Hash256) (*block.Header, error) { 108 blk, err := fd.GetBlock(h) 109 if err != nil { 110 return nil, err 111 } 112 return &blk.Header, nil 113 } 114 115 func (fd *testInMemFd) HeaderByHeight(height uint64) (*block.Header, error) { 116 blk, err := fd.GetBlockByHeight(height) 117 if err != nil { 118 return nil, err 119 } 120 return &blk.Header, nil 121 } 122 123 func (fd *testInMemFd) FooterByHeight(height uint64) (*block.Footer, error) { 124 blk, err := fd.GetBlockByHeight(height) 125 if err != nil { 126 return nil, err 127 } 128 return &blk.Footer, nil 129 } 130 131 func (fd *testInMemFd) PutBlock(ctx context.Context, blk *block.Block) error { 132 // bail out if block already exists 133 h := blk.HashBlock() 134 if _, err := fd.GetBlockHeight(h); err == nil { 135 return ErrAlreadyExist 136 } 137 return fd.fileDAOv2.PutBlock(ctx, blk) 138 } 139 140 func newTestFailPutBlock(fd *fileDAO, height uint64) FileDAO { 141 return &testFailPutBlock{fileDAO: fd, failHeight: height} 142 } 143 144 func (tf *testFailPutBlock) PutBlock(ctx context.Context, blk *block.Block) error { 145 // bail out if block already exists 146 h := blk.HashBlock() 147 if _, err := tf.GetBlockHeight(h); err == nil { 148 return ErrAlreadyExist 149 } 150 151 // check if we need to split DB 152 if tf.cfg.V2BlocksToSplitDB > 0 { 153 if err := tf.prepNextDbFile(blk.Height()); err != nil { 154 return err 155 } 156 } 157 158 if tf.failHeight == blk.Height() { 159 return ErrInvalidTipHeight 160 } 161 return tf.currFd.PutBlock(ctx, blk) 162 } 163 164 func testCommitBlocks(t *testing.T, fd BaseFileDAO, start, end uint64, h hash.Hash256) error { 165 ctx := context.Background() 166 builder := block.NewTestingBuilder() 167 for i := start; i <= end; i++ { 168 blk := createTestingBlock(builder, i, h) 169 if err := fd.PutBlock(ctx, blk); err != nil { 170 return err 171 } 172 h = blk.HashBlock() 173 } 174 return nil 175 } 176 177 func testVerifyChainDB(t *testing.T, fd FileDAO, start, end uint64) { 178 r := require.New(t) 179 180 height, err := fd.Height() 181 r.NoError(err) 182 r.Equal(end, height) 183 for i := end; i >= start; i-- { 184 h, err := fd.GetBlockHash(i) 185 r.NoError(err) 186 height, err = fd.GetBlockHeight(h) 187 r.NoError(err) 188 r.Equal(height, i) 189 blk, err := fd.GetBlockByHeight(i) 190 r.NoError(err) 191 r.Equal(h, blk.HashBlock()) 192 receipt, err := fd.GetReceipts(i) 193 r.NoError(err) 194 r.EqualValues(1, receipt[0].Status) 195 r.Equal(height, receipt[0].BlockHeight) 196 r.Equal(blk.Header.PrevHash(), receipt[0].ActionHash) 197 log, err := fd.TransactionLogs(i) 198 r.NoError(err) 199 r.NotNil(log) 200 l := log.Logs[0] 201 r.Equal(receipt[0].ActionHash[:], l.ActionHash) 202 r.EqualValues(1, l.NumTransactions) 203 tx := l.Transactions[0] 204 r.Equal(big.NewInt(100).String(), tx.Amount) 205 r.Equal(hex.EncodeToString(l.ActionHash[:]), tx.Sender) 206 r.Equal(hex.EncodeToString(l.ActionHash[:]), tx.Recipient) 207 r.Equal(iotextypes.TransactionLogType_NATIVE_TRANSFER, tx.Type) 208 209 if false { 210 // test DeleteTipBlock() 211 r.NoError(fd.DeleteTipBlock()) 212 _, err = fd.GetBlockHash(i) 213 r.Equal(db.ErrNotExist, err) 214 _, err = fd.GetBlockHeight(h) 215 r.Equal(db.ErrNotExist, errors.Cause(err)) 216 _, err = fd.GetBlock(h) 217 r.Equal(db.ErrNotExist, errors.Cause(err)) 218 _, err = fd.GetBlockByHeight(i) 219 r.Equal(db.ErrNotExist, errors.Cause(err)) 220 _, err = fd.GetReceipts(i) 221 r.Equal(db.ErrNotExist, errors.Cause(err)) 222 _, err = fd.TransactionLogs(i) 223 r.Equal(ErrNotSupported, err) 224 } 225 } 226 } 227 228 func createTestingBlock(builder *block.TestingBuilder, height uint64, h hash.Hash256) *block.Block { 229 block.LoadGenesisHash(&genesis.Default) 230 r := &action.Receipt{ 231 Status: 1, 232 BlockHeight: height, 233 ActionHash: h, 234 } 235 blk, _ := builder. 236 SetHeight(height). 237 SetPrevBlockHash(h). 238 SetReceipts([]*action.Receipt{ 239 r.AddTransactionLogs(&action.TransactionLog{ 240 Type: iotextypes.TransactionLogType_NATIVE_TRANSFER, 241 Amount: big.NewInt(100), 242 Sender: hex.EncodeToString(h[:]), 243 Recipient: hex.EncodeToString(h[:]), 244 }), 245 }). 246 SetTimeStamp(testutil.TimestampNow().UTC()). 247 SignAndBuild(identityset.PrivateKey(27)) 248 return &blk 249 }