github.com/iotexproject/iotex-core@v1.14.1-rc1/api/serverV2_integrity_test.go (about) 1 // Copyright (c) 2022 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 api 7 8 import ( 9 "context" 10 "encoding/hex" 11 "math/big" 12 "testing" 13 "time" 14 15 "github.com/iotexproject/go-pkgs/crypto" 16 "github.com/iotexproject/go-pkgs/hash" 17 "github.com/iotexproject/iotex-proto/golang/iotextypes" 18 "github.com/pkg/errors" 19 "github.com/stretchr/testify/require" 20 "google.golang.org/protobuf/proto" 21 22 "github.com/iotexproject/iotex-core/action" 23 "github.com/iotexproject/iotex-core/action/protocol" 24 "github.com/iotexproject/iotex-core/action/protocol/account" 25 accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util" 26 "github.com/iotexproject/iotex-core/action/protocol/execution" 27 "github.com/iotexproject/iotex-core/action/protocol/poll" 28 "github.com/iotexproject/iotex-core/action/protocol/rewarding" 29 "github.com/iotexproject/iotex-core/action/protocol/rolldpos" 30 "github.com/iotexproject/iotex-core/actpool" 31 "github.com/iotexproject/iotex-core/blockchain" 32 "github.com/iotexproject/iotex-core/blockchain/block" 33 "github.com/iotexproject/iotex-core/blockchain/blockdao" 34 "github.com/iotexproject/iotex-core/blockchain/filedao" 35 "github.com/iotexproject/iotex-core/blockchain/genesis" 36 "github.com/iotexproject/iotex-core/blockindex" 37 "github.com/iotexproject/iotex-core/consensus" 38 "github.com/iotexproject/iotex-core/db" 39 "github.com/iotexproject/iotex-core/pkg/unit" 40 "github.com/iotexproject/iotex-core/state/factory" 41 "github.com/iotexproject/iotex-core/test/identityset" 42 "github.com/iotexproject/iotex-core/testutil" 43 ) 44 45 type testConfig struct { 46 api Config 47 genesis genesis.Genesis 48 actPoll actpool.Config 49 chain blockchain.Config 50 consensus consensus.Config 51 db db.Config 52 indexer blockindex.Config 53 } 54 55 var ( 56 _testTransfer1, _ = action.SignedTransfer(identityset.Address(30).String(), identityset.PrivateKey(27), 1, 57 big.NewInt(10), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64)) 58 _transferHash1, _ = _testTransfer1.Hash() 59 _testTransfer2, _ = action.SignedTransfer(identityset.Address(30).String(), identityset.PrivateKey(30), 5, 60 big.NewInt(2), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64)) 61 _transferHash2, _ = _testTransfer2.Hash() 62 63 _testExecution1, _ = action.SignedExecution(identityset.Address(31).String(), identityset.PrivateKey(30), 6, 64 big.NewInt(1), testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64), []byte{1}) 65 _executionHash1, _ = _testExecution1.Hash() 66 _testExecution3, _ = action.SignedExecution(identityset.Address(31).String(), identityset.PrivateKey(28), 2, 67 big.NewInt(1), testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64), []byte{1}) 68 _executionHash3, _ = _testExecution3.Hash() 69 70 _blkHash = map[uint64]string{} 71 _implicitLogs = map[hash.Hash256]*block.TransactionLog{} 72 ) 73 74 func addTestingBlocks(bc blockchain.Blockchain, ap actpool.ActPool) error { 75 ctx := context.Background() 76 addr0 := identityset.Address(27).String() 77 addr1 := identityset.Address(28).String() 78 addr2 := identityset.Address(29).String() 79 addr3 := identityset.Address(30).String() 80 priKey3 := identityset.PrivateKey(30) 81 addr4 := identityset.Address(31).String() 82 // Add block 1 83 // Producer transfer--> C 84 _implicitLogs[_transferHash1] = block.NewTransactionLog(_transferHash1, 85 []*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_NATIVE_TRANSFER, "10", addr0, addr3)}, 86 ) 87 88 blk1Time := testutil.TimestampNow() 89 if err := ap.Add(ctx, _testTransfer1); err != nil { 90 return err 91 } 92 blk, err := bc.MintNewBlock(blk1Time) 93 if err != nil { 94 return err 95 } 96 if err := bc.CommitBlock(blk); err != nil { 97 return err 98 } 99 ap.Reset() 100 h := blk.HashBlock() 101 _blkHash[1] = hex.EncodeToString(h[:]) 102 103 // Add block 2 104 // Charlie transfer--> A, B, D, P 105 // Charlie transfer--> C 106 // Charlie exec--> D 107 recipients := []string{addr1, addr2, addr4, addr0} 108 for i, recipient := range recipients { 109 selp, err := action.SignedTransfer(recipient, priKey3, uint64(i+1), big.NewInt(1), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64)) 110 if err != nil { 111 return err 112 } 113 if err := ap.Add(ctx, selp); err != nil { 114 return err 115 } 116 selpHash, err := selp.Hash() 117 if err != nil { 118 return err 119 } 120 _implicitLogs[selpHash] = block.NewTransactionLog(selpHash, 121 []*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_NATIVE_TRANSFER, "1", addr3, recipient)}, 122 ) 123 } 124 _implicitLogs[_transferHash2] = block.NewTransactionLog(_transferHash2, 125 []*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_NATIVE_TRANSFER, "2", addr3, addr3)}, 126 ) 127 if err := ap.Add(ctx, _testTransfer2); err != nil { 128 return err 129 } 130 _implicitLogs[_executionHash1] = block.NewTransactionLog( 131 _executionHash1, 132 []*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_IN_CONTRACT_TRANSFER, "1", addr3, addr4)}, 133 ) 134 if err := ap.Add(ctx, _testExecution1); err != nil { 135 return err 136 } 137 if blk, err = bc.MintNewBlock(blk1Time.Add(time.Second)); err != nil { 138 return err 139 } 140 if err := bc.CommitBlock(blk); err != nil { 141 return err 142 } 143 ap.Reset() 144 h = blk.HashBlock() 145 _blkHash[2] = hex.EncodeToString(h[:]) 146 147 // Add block 3 148 // Empty actions 149 if blk, err = bc.MintNewBlock(blk1Time.Add(time.Second * 2)); err != nil { 150 return err 151 } 152 if err := bc.CommitBlock(blk); err != nil { 153 return err 154 } 155 ap.Reset() 156 h = blk.HashBlock() 157 _blkHash[3] = hex.EncodeToString(h[:]) 158 159 // Add block 4 160 // Charlie transfer--> C 161 // Alfa transfer--> A 162 // Charlie exec--> D 163 // Alfa exec--> D 164 tsf1, err := action.SignedTransfer(addr3, priKey3, uint64(7), big.NewInt(1), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64)) 165 if err != nil { 166 return err 167 } 168 tsf1Hash, err := tsf1.Hash() 169 if err != nil { 170 return err 171 } 172 _implicitLogs[tsf1Hash] = block.NewTransactionLog(tsf1Hash, 173 []*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_NATIVE_TRANSFER, "1", addr3, addr3)}, 174 ) 175 if err := ap.Add(ctx, tsf1); err != nil { 176 return err 177 } 178 tsf2, err := action.SignedTransfer(addr1, identityset.PrivateKey(28), uint64(1), big.NewInt(1), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64)) 179 if err != nil { 180 return err 181 } 182 tsf2Hash, err := tsf2.Hash() 183 if err != nil { 184 return err 185 } 186 _implicitLogs[tsf2Hash] = block.NewTransactionLog(tsf2Hash, 187 []*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_NATIVE_TRANSFER, "1", addr1, addr1)}, 188 ) 189 if err := ap.Add(ctx, tsf2); err != nil { 190 return err 191 } 192 execution1, err := action.SignedExecution(addr4, priKey3, 8, 193 big.NewInt(2), testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64), []byte{1}) 194 if err != nil { 195 return err 196 } 197 execution1Hash, err := execution1.Hash() 198 if err != nil { 199 return err 200 } 201 _implicitLogs[execution1Hash] = block.NewTransactionLog( 202 execution1Hash, 203 []*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_IN_CONTRACT_TRANSFER, "2", addr3, addr4)}, 204 ) 205 if err := ap.Add(ctx, execution1); err != nil { 206 return err 207 } 208 _implicitLogs[_executionHash3] = block.NewTransactionLog( 209 _executionHash3, 210 []*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_IN_CONTRACT_TRANSFER, "1", addr1, addr4)}, 211 ) 212 if err := ap.Add(ctx, _testExecution3); err != nil { 213 return err 214 } 215 if blk, err = bc.MintNewBlock(blk1Time.Add(time.Second * 3)); err != nil { 216 return err 217 } 218 h = blk.HashBlock() 219 _blkHash[4] = hex.EncodeToString(h[:]) 220 return bc.CommitBlock(blk) 221 } 222 223 func deployContractV2(bc blockchain.Blockchain, dao blockdao.BlockDAO, actPool actpool.ActPool, key crypto.PrivateKey, nonce, height uint64, code string) (string, error) { 224 data, _ := hex.DecodeString(code) 225 ex1, err := action.SignedExecution(action.EmptyAddress, key, nonce, big.NewInt(0), 500000, big.NewInt(testutil.TestGasPriceInt64), data) 226 if err != nil { 227 return "", err 228 } 229 h1, err := ex1.Hash() 230 if err != nil { 231 return "", err 232 } 233 if err := actPool.Add(context.Background(), ex1); err != nil { 234 return "", err 235 } 236 blk, err := bc.MintNewBlock(testutil.TimestampNow()) 237 if err != nil { 238 return "", err 239 } 240 if err := bc.CommitBlock(blk); err != nil { 241 return "", err 242 } 243 actPool.Reset() 244 // get deployed contract address 245 for _, receipt := range blk.Receipts { 246 if receipt.ActionHash == h1 { 247 return receipt.ContractAddress, nil 248 } 249 } 250 return "", errors.New("failed to find execution receipt") 251 } 252 253 func addActsToActPool(ctx context.Context, ap actpool.ActPool) error { 254 // Producer transfer--> A 255 tsf1, err := action.SignedTransfer(identityset.Address(28).String(), identityset.PrivateKey(27), 2, big.NewInt(20), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64)) 256 if err != nil { 257 return err 258 } 259 // Producer transfer--> P 260 tsf2, err := action.SignedTransfer(identityset.Address(27).String(), identityset.PrivateKey(27), 3, big.NewInt(20), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64)) 261 if err != nil { 262 return err 263 } 264 // Producer transfer--> B 265 tsf3, err := action.SignedTransfer(identityset.Address(29).String(), identityset.PrivateKey(27), 4, big.NewInt(20), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64)) 266 if err != nil { 267 return err 268 } 269 // Producer exec--> D 270 execution1, err := action.SignedExecution(identityset.Address(31).String(), identityset.PrivateKey(27), 5, 271 big.NewInt(1), testutil.TestGasLimit, big.NewInt(10), []byte{1}) 272 if err != nil { 273 return err 274 } 275 276 if err := ap.Add(ctx, tsf1); err != nil { 277 return err 278 } 279 if err := ap.Add(ctx, tsf2); err != nil { 280 return err 281 } 282 if err := ap.Add(ctx, tsf3); err != nil { 283 return err 284 } 285 return ap.Add(ctx, execution1) 286 } 287 288 func setupChain(cfg testConfig) (blockchain.Blockchain, blockdao.BlockDAO, blockindex.Indexer, blockindex.BloomFilterIndexer, factory.Factory, actpool.ActPool, *protocol.Registry, string, error) { 289 cfg.chain.ProducerPrivKey = hex.EncodeToString(identityset.PrivateKey(0).Bytes()) 290 registry := protocol.NewRegistry() 291 factoryCfg := factory.GenerateConfig(cfg.chain, cfg.genesis) 292 sf, err := factory.NewFactory(factoryCfg, db.NewMemKVStore(), factory.RegistryOption(registry)) 293 if err != nil { 294 return nil, nil, nil, nil, nil, nil, nil, "", err 295 } 296 ap, err := setupActPool(cfg.genesis, sf, cfg.actPoll) 297 if err != nil { 298 return nil, nil, nil, nil, nil, nil, nil, "", err 299 } 300 cfg.genesis.InitBalanceMap[identityset.Address(27).String()] = unit.ConvertIotxToRau(10000000000).String() 301 cfg.genesis.InitBalanceMap[identityset.Address(28).String()] = unit.ConvertIotxToRau(10000000000).String() 302 // create indexer 303 indexer, err := blockindex.NewIndexer(db.NewMemKVStore(), cfg.genesis.Hash()) 304 if err != nil { 305 return nil, nil, nil, nil, nil, nil, nil, "", errors.New("failed to create indexer") 306 } 307 testPath, _ := testutil.PathOfTempFile("bloomfilter") 308 cfg.db.DbPath = testPath 309 bfIndexer, err := blockindex.NewBloomfilterIndexer(db.NewBoltDB(cfg.db), cfg.indexer) 310 if err != nil { 311 return nil, nil, nil, nil, nil, nil, nil, "", errors.New("failed to create bloomfilter indexer") 312 } 313 // create BlockDAO 314 store, err := filedao.NewFileDAOInMemForTest() 315 if err != nil { 316 return nil, nil, nil, nil, nil, nil, nil, "", errors.Wrap(err, "failed to create dao in memory") 317 } 318 dao := blockdao.NewBlockDAOWithIndexersAndCache(store, []blockdao.BlockIndexer{sf, indexer, bfIndexer}, 16) 319 if dao == nil { 320 return nil, nil, nil, nil, nil, nil, nil, "", errors.New("failed to create blockdao") 321 } 322 // create chain 323 bc := blockchain.NewBlockchain( 324 cfg.chain, 325 cfg.genesis, 326 dao, 327 factory.NewMinter(sf, ap), 328 blockchain.BlockValidatorOption(block.NewValidator( 329 sf, 330 protocol.NewGenericValidator(sf, accountutil.AccountState), 331 )), 332 ) 333 if bc == nil { 334 return nil, nil, nil, nil, nil, nil, nil, "", errors.New("failed to create blockchain") 335 } 336 defer func() { 337 testutil.CleanupPath(testPath) 338 }() 339 340 acc := account.NewProtocol(rewarding.DepositGas) 341 evm := execution.NewProtocol(dao.GetBlockHash, rewarding.DepositGasWithSGD, nil, func(u uint64) (time.Time, error) { return time.Time{}, nil }) 342 p := poll.NewLifeLongDelegatesProtocol(cfg.genesis.Delegates) 343 rolldposProtocol := rolldpos.NewProtocol( 344 genesis.Default.NumCandidateDelegates, 345 genesis.Default.NumDelegates, 346 genesis.Default.NumSubEpochs, 347 rolldpos.EnableDardanellesSubEpoch(cfg.genesis.DardanellesBlockHeight, cfg.genesis.DardanellesNumSubEpochs), 348 ) 349 r := rewarding.NewProtocol(cfg.genesis.Rewarding) 350 351 if err := rolldposProtocol.Register(registry); err != nil { 352 return nil, nil, nil, nil, nil, nil, nil, "", err 353 } 354 if err := acc.Register(registry); err != nil { 355 return nil, nil, nil, nil, nil, nil, nil, "", err 356 } 357 if err := evm.Register(registry); err != nil { 358 return nil, nil, nil, nil, nil, nil, nil, "", err 359 } 360 if err := r.Register(registry); err != nil { 361 return nil, nil, nil, nil, nil, nil, nil, "", err 362 } 363 if err := p.Register(registry); err != nil { 364 return nil, nil, nil, nil, nil, nil, nil, "", err 365 } 366 367 return bc, dao, indexer, bfIndexer, sf, ap, registry, testPath, nil 368 } 369 370 func setupActPool(g genesis.Genesis, sf factory.Factory, cfg actpool.Config) (actpool.ActPool, error) { 371 ap, err := actpool.NewActPool(g, sf, cfg) 372 if err != nil { 373 return nil, err 374 } 375 376 ap.AddActionEnvelopeValidators(protocol.NewGenericValidator(sf, accountutil.AccountState)) 377 378 return ap, nil 379 } 380 381 func newConfig() testConfig { 382 cfg := testConfig{ 383 api: DefaultConfig, 384 genesis: genesis.Default, 385 actPoll: actpool.DefaultConfig, 386 chain: blockchain.DefaultConfig, 387 consensus: consensus.DefaultConfig, 388 db: db.DefaultConfig, 389 indexer: blockindex.DefaultConfig, 390 } 391 392 testTriePath, err := testutil.PathOfTempFile("trie") 393 if err != nil { 394 panic(err) 395 } 396 testDBPath, err := testutil.PathOfTempFile("db") 397 if err != nil { 398 panic(err) 399 } 400 testIndexPath, err := testutil.PathOfTempFile("index") 401 if err != nil { 402 panic(err) 403 } 404 testSystemLogPath, err := testutil.PathOfTempFile("systemlog") 405 if err != nil { 406 panic(err) 407 } 408 defer func() { 409 testutil.CleanupPath(testTriePath) 410 testutil.CleanupPath(testDBPath) 411 testutil.CleanupPath(testIndexPath) 412 testutil.CleanupPath(testSystemLogPath) 413 }() 414 415 cfg.chain.TrieDBPath = testTriePath 416 cfg.chain.ChainDBPath = testDBPath 417 cfg.chain.IndexDBPath = testIndexPath 418 cfg.chain.EVMNetworkID = _evmNetworkID 419 cfg.chain.EnableAsyncIndexWrite = false 420 cfg.genesis.EnableGravityChainVoting = true 421 cfg.actPoll.MinGasPriceStr = "0" 422 cfg.api.RangeQueryLimit = 100 423 cfg.api.GRPCPort = 0 424 cfg.api.HTTPPort = 0 425 cfg.api.WebSocketPort = 0 426 return cfg 427 } 428 429 func createServerV2(cfg testConfig, needActPool bool) (*ServerV2, blockchain.Blockchain, blockdao.BlockDAO, blockindex.Indexer, *protocol.Registry, actpool.ActPool, string, error) { 430 // TODO (zhi): revise 431 bc, dao, indexer, bfIndexer, sf, ap, registry, bfIndexFile, err := setupChain(cfg) 432 if err != nil { 433 return nil, nil, nil, nil, nil, nil, "", err 434 } 435 436 ctx := context.Background() 437 438 // Start blockchain 439 if err := bc.Start(ctx); err != nil { 440 return nil, nil, nil, nil, nil, nil, "", err 441 } 442 // Add testing blocks 443 if err := addTestingBlocks(bc, ap); err != nil { 444 return nil, nil, nil, nil, nil, nil, "", err 445 } 446 447 if needActPool { 448 // Add actions to actpool 449 ctx = protocol.WithRegistry(ctx, registry) 450 if err := addActsToActPool(ctx, ap); err != nil { 451 return nil, nil, nil, nil, nil, nil, "", err 452 } 453 } 454 opts := []Option{WithBroadcastOutbound(func(ctx context.Context, chainID uint32, msg proto.Message) error { 455 return nil 456 })} 457 svr, err := NewServerV2(cfg.api, bc, nil, sf, dao, indexer, bfIndexer, ap, registry, func(u uint64) (time.Time, error) { return time.Time{}, nil }, opts...) 458 if err != nil { 459 return nil, nil, nil, nil, nil, nil, "", err 460 } 461 return svr, bc, dao, indexer, registry, ap, bfIndexFile, nil 462 } 463 464 func TestServerV2Integrity(t *testing.T) { 465 require := require.New(t) 466 cfg := newConfig() 467 cfg.api.GRPCPort = testutil.RandomPort() 468 svr, _, _, _, _, _, bfIndexFile, err := createServerV2(cfg, false) 469 require.NoError(err) 470 defer func() { 471 testutil.CleanupPath(bfIndexFile) 472 }() 473 ctx := context.Background() 474 475 err = svr.Start(ctx) 476 require.NoError(err) 477 478 err = testutil.WaitUntil(100*time.Millisecond, 3*time.Second, func() (bool, error) { 479 err = svr.Stop(ctx) 480 return err == nil, err 481 }) 482 require.NoError(err) 483 }