github.com/iotexproject/iotex-core@v1.14.1-rc1/e2etest/rewarding_test.go (about) 1 package e2etest 2 3 import ( 4 "context" 5 "fmt" 6 "math/big" 7 "math/rand" 8 "os" 9 "strconv" 10 "sync" 11 "testing" 12 "time" 13 14 "github.com/cenkalti/backoff" 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 "go.uber.org/zap" 18 "google.golang.org/grpc" 19 20 "github.com/iotexproject/go-pkgs/crypto" 21 "github.com/iotexproject/go-pkgs/hash" 22 "github.com/iotexproject/iotex-proto/golang/iotexapi" 23 "github.com/iotexproject/iotex-proto/golang/iotextypes" 24 25 "github.com/iotexproject/iotex-core/action" 26 "github.com/iotexproject/iotex-core/action/protocol" 27 accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util" 28 "github.com/iotexproject/iotex-core/action/protocol/rewarding" 29 "github.com/iotexproject/iotex-core/api" 30 "github.com/iotexproject/iotex-core/blockchain" 31 "github.com/iotexproject/iotex-core/blockchain/genesis" 32 "github.com/iotexproject/iotex-core/config" 33 "github.com/iotexproject/iotex-core/pkg/log" 34 "github.com/iotexproject/iotex-core/pkg/probe" 35 "github.com/iotexproject/iotex-core/pkg/util/fileutil" 36 "github.com/iotexproject/iotex-core/server/itx" 37 "github.com/iotexproject/iotex-core/state/factory" 38 "github.com/iotexproject/iotex-core/test/identityset" 39 "github.com/iotexproject/iotex-core/testutil" 40 "github.com/iotexproject/iotex-core/tools/util" 41 ) 42 43 type claimTestCaseID int 44 45 const ( 46 //To claim amount 0 47 caseClaimZero claimTestCaseID = iota 48 //To claim all unclaimed balance 49 caseClaimAll 50 //To claim more than unclaimed balance 51 caseClaimMoreThanBalance 52 //To claim only part of available balance 53 caseClaimPartOfBalance 54 //To claim a negative amount 55 caseClaimNegative 56 //To claim with an operator address other than the rewarding address 57 caseClaimToNonRewardingAddr 58 //Total number of claim test cases, keep this at the bottom the enum 59 totalClaimCasesNum 60 ) 61 62 func TestBlockReward(t *testing.T) { 63 r := require.New(t) 64 testTriePath, err := testutil.PathOfTempFile("trie") 65 r.NoError(err) 66 testDBPath, err := testutil.PathOfTempFile("db") 67 r.NoError(err) 68 testIndexPath, err := testutil.PathOfTempFile("index") 69 r.NoError(err) 70 testConsensusPath, err := testutil.PathOfTempFile("cons") 71 r.NoError(err) 72 testContractIndexPath, err := testutil.PathOfTempFile("contractindex") 73 r.NoError(err) 74 testSGDIndexPath, err := testutil.PathOfTempFile("sgdindex") 75 r.NoError(err) 76 cfg := config.Default 77 cfg.Consensus.Scheme = config.RollDPoSScheme 78 cfg.Genesis.NumDelegates = 1 79 cfg.Genesis.NumSubEpochs = 10 80 cfg.Genesis.Delegates = []genesis.Delegate{ 81 { 82 OperatorAddrStr: identityset.Address(0).String(), 83 RewardAddrStr: identityset.Address(0).String(), 84 VotesStr: "10", 85 }, 86 } 87 cfg.Genesis.BlockInterval = time.Second 88 cfg.Consensus.RollDPoS.FSM.AcceptBlockTTL = 300 * time.Millisecond 89 cfg.Consensus.RollDPoS.FSM.AcceptProposalEndorsementTTL = 300 * time.Millisecond 90 cfg.Consensus.RollDPoS.FSM.AcceptLockEndorsementTTL = 300 * time.Millisecond 91 cfg.Consensus.RollDPoS.FSM.CommitTTL = 100 * time.Millisecond 92 cfg.Consensus.RollDPoS.ConsensusDBPath = testConsensusPath 93 cfg.Genesis.EnableGravityChainVoting = false 94 cfg.Chain.ProducerPrivKey = identityset.PrivateKey(0).HexString() 95 cfg.Chain.TrieDBPatchFile = "" 96 cfg.Chain.TrieDBPath = testTriePath 97 cfg.Chain.ChainDBPath = testDBPath 98 cfg.Chain.IndexDBPath = testIndexPath 99 cfg.Chain.ContractStakingIndexDBPath = testContractIndexPath 100 cfg.Chain.SGDIndexDBPath = testSGDIndexPath 101 cfg.Network.Port = testutil.RandomPort() 102 cfg.Genesis.PollMode = "lifeLong" 103 104 svr, err := itx.NewServer(cfg) 105 require.NoError(t, err) 106 require.NoError(t, svr.Start(context.Background())) 107 defer func() { 108 require.NoError(t, svr.Stop(context.Background())) 109 }() 110 111 require.NoError(t, testutil.WaitUntil(100*time.Millisecond, 20*time.Second, func() (b bool, e error) { 112 return svr.ChainService(1).Blockchain().TipHeight() >= 5, nil 113 })) 114 115 ctx := protocol.WithBlockCtx( 116 context.Background(), 117 protocol.BlockCtx{ 118 BlockHeight: 0, 119 }, 120 ) 121 ctx = genesis.WithGenesisContext(ctx, cfg.Genesis) 122 ctx = protocol.WithFeatureCtx(ctx) 123 124 rp := rewarding.FindProtocol(svr.ChainService(1).Registry()) 125 require.NotNil(t, rp) 126 sf := svr.ChainService(1).StateFactory() 127 128 sk, err := crypto.HexStringToPrivateKey(cfg.Chain.ProducerPrivKey) 129 require.NoError(t, err) 130 addr := sk.PublicKey().Address() 131 require.NotNil(t, addr) 132 133 blockReward, err := rp.BlockReward(ctx, sf) 134 require.NoError(t, err) 135 balance, _, err := rp.UnclaimedBalance(ctx, sf, addr) 136 require.NoError(t, err) 137 assert.True(t, balance.Cmp(big.NewInt(0).Mul(blockReward, big.NewInt(5))) <= 0) 138 139 for i := 1; i <= 5; i++ { 140 blk, err := svr.ChainService(1).BlockDAO().GetBlockByHeight(uint64(i)) 141 require.NoError(t, err) 142 ok := false 143 var gr *action.GrantReward 144 for _, act := range blk.Body.Actions { 145 gr, ok = act.Action().(*action.GrantReward) 146 if ok { 147 assert.Equal(t, uint64(i), gr.Height()) 148 break 149 } 150 } 151 assert.True(t, ok) 152 } 153 } 154 155 func TestBlockEpochReward(t *testing.T) { 156 // TODO: fix the test 157 t.Skip() 158 159 dbFilePaths := make([]string, 0) 160 161 //Test will stop after reaching this height 162 runToHeight := uint64(60) 163 164 //Number of nodes 165 numNodes := 4 166 167 // Set mini-cluster configurations 168 rand.Seed(time.Now().UnixNano()) 169 configs := make([]config.Config, numNodes) 170 for i := 0; i < numNodes; i++ { 171 chainDBPath := fmt.Sprintf("./chain%d.db", i+1) 172 dbFilePaths = append(dbFilePaths, chainDBPath) 173 trieDBPath := fmt.Sprintf("./trie%d.db", i+1) 174 dbFilePaths = append(dbFilePaths, trieDBPath) 175 indexDBPath := fmt.Sprintf("./index%d.db", i+1) 176 dbFilePaths = append(dbFilePaths, indexDBPath) 177 contractIndexDBPath := fmt.Sprintf("./contractindex%d.db", i+1) 178 dbFilePaths = append(dbFilePaths, contractIndexDBPath) 179 consensusDBPath := fmt.Sprintf("./consensus%d.db", i+1) 180 dbFilePaths = append(dbFilePaths, consensusDBPath) 181 networkPort := 4689 + i 182 apiPort := 14014 + i 183 HTTPStatsPort := 8080 + i 184 HTTPAdminPort := 9009 + i 185 cfg := newConfig(chainDBPath, trieDBPath, indexDBPath, contractIndexDBPath, identityset.PrivateKey(i), 186 networkPort, apiPort, uint64(numNodes)) 187 cfg.Consensus.RollDPoS.ConsensusDBPath = consensusDBPath 188 if i == 0 { 189 cfg.Network.BootstrapNodes = []string{} 190 cfg.Network.MasterKey = "bootnode" 191 } 192 193 //Set Operator and Reward address 194 cfg.Genesis.Delegates[i].RewardAddrStr = identityset.Address(i + numNodes).String() 195 cfg.Genesis.Delegates[i].OperatorAddrStr = identityset.Address(i).String() 196 //Generate random votes from [1000,2000] 197 cfg.Genesis.Delegates[i].VotesStr = strconv.Itoa(1000 + rand.Intn(1000)) 198 cfg.System.HTTPStatsPort = HTTPStatsPort 199 cfg.System.HTTPAdminPort = HTTPAdminPort 200 configs[i] = cfg 201 } 202 203 for _, dbFilePath := range dbFilePaths { 204 if fileutil.FileExists(dbFilePath) && os.RemoveAll(dbFilePath) != nil { 205 log.L().Error("Failed to delete db file") 206 } 207 } 208 209 defer func() { 210 for _, dbFilePath := range dbFilePaths { 211 if fileutil.FileExists(dbFilePath) && os.RemoveAll(dbFilePath) != nil { 212 log.L().Error("Failed to delete db file") 213 } 214 } 215 216 }() 217 // Create mini-cluster 218 svrs := make([]*itx.Server, numNodes) 219 for i := 0; i < numNodes; i++ { 220 svr, err := itx.NewServer(configs[i]) 221 if err != nil { 222 log.L().Fatal("Failed to create server.", zap.Error(err)) 223 } 224 svrs[i] = svr 225 } 226 227 // Start mini-cluster 228 for i := 0; i < numNodes; i++ { 229 go itx.StartServer(context.Background(), svrs[i], probe.New(7788+i), configs[i]) 230 } 231 232 // target address for grpc connection. Default is "127.0.0.1:14014" 233 grpcAddr := "127.0.0.1:14014" 234 235 grpcctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 236 defer cancel() 237 conn, err := grpc.DialContext(grpcctx, grpcAddr, grpc.WithBlock(), grpc.WithInsecure()) 238 if err != nil { 239 log.L().Error("Failed to connect to API server.") 240 } 241 defer conn.Close() 242 243 client := iotexapi.NewAPIServiceClient(conn) 244 245 // Get each server's parameters: rewarding protocol, working set, block chain etc. 246 rps := make([]*rewarding.Protocol, numNodes) 247 sfs := make([]factory.Factory, numNodes) 248 chains := make([]blockchain.Blockchain, numNodes) 249 apis := make([]*api.ServerV2, numNodes) 250 //Map of expected unclaimed balance for each reward address 251 exptUnclaimed := make(map[string]*big.Int, numNodes) 252 //Map of real unclaimed balance for each reward address 253 unClaimedBalances := make(map[string]*big.Int, numNodes) 254 //Map of initial balance of both reward and operator address 255 initBalances := make(map[string]*big.Int, numNodes) 256 //Map of claimed amount for each reward address 257 claimedAmount := make(map[string]*big.Int, numNodes) 258 //Map to translate from operator address to reward address 259 getRewardAddStr := make(map[string]string) 260 261 for i := 0; i < numNodes; i++ { 262 rp := rewarding.FindProtocol(svrs[i].ChainService(configs[i].Chain.ID).Registry()) 263 require.NotNil(t, rp) 264 rps[i] = rp 265 266 sfs[i] = svrs[i].ChainService(configs[i].Chain.ID).StateFactory() 267 268 chains[i] = svrs[i].ChainService(configs[i].Chain.ID).Blockchain() 269 apis[i] = svrs[i].APIServer(configs[i].Chain.ID) 270 271 rewardAddr := identityset.Address(i + numNodes) 272 rewardAddrStr := identityset.Address(i + numNodes).String() 273 exptUnclaimed[rewardAddrStr] = big.NewInt(0) 274 ctx := genesis.WithGenesisContext(context.Background(), configs[i].Genesis) 275 initState, err := accountutil.AccountState(ctx, sfs[i], rewardAddr) 276 require.NoError(t, err) 277 initBalances[rewardAddrStr] = initState.Balance 278 279 operatorAddr := identityset.Address(i) 280 operatorAddrStr := identityset.Address(i).String() 281 initState, err = accountutil.AccountState(ctx, sfs[i], operatorAddr) 282 require.NoError(t, err) 283 initBalances[operatorAddrStr] = initState.Balance 284 285 claimedAmount[rewardAddrStr] = big.NewInt(0) 286 287 getRewardAddStr[identityset.Address(i).String()] = rewardAddrStr 288 289 } 290 291 blocksPerEpoch := configs[0].Genesis.Blockchain.NumDelegates * configs[0].Genesis.Blockchain.NumSubEpochs 292 293 blockReward, err := rps[0].BlockReward(context.Background(), sfs[0]) 294 require.NoError(t, err) 295 296 //Calculate epoch reward shares for each delegate based on their weight (votes number) 297 epochReward, err := rps[0].EpochReward(context.Background(), sfs[0]) 298 require.NoError(t, err) 299 epRwdShares := make(map[string]*big.Int, numNodes) 300 301 totalVotes := big.NewInt(0) 302 for i := 0; i < numNodes; i++ { 303 totalVotes = totalVotes.Add(configs[0].Genesis.Delegates[i].Votes(), totalVotes) 304 } 305 306 for i := 0; i < numNodes; i++ { 307 tempShare := big.NewInt(0).Mul(epochReward, configs[0].Genesis.Delegates[i].Votes()) 308 rewardAddrStr := identityset.Address(i + numNodes).String() 309 epRwdShares[rewardAddrStr] = big.NewInt(0).Div(tempShare, totalVotes) 310 } 311 312 //Map from action hash to expected result(Fail-false or Success-true), storing pending injected claim actions, 313 pendingClaimActions := make(map[hash.Hash256]bool) 314 //Start testing 315 preHeight := uint64(0) 316 preEpochNum := uint64(0) 317 preExpectHigh := uint64(0) 318 319 fmt.Println("Starting test") 320 321 if err := testutil.WaitUntil(100*time.Millisecond, 120*time.Second, func() (bool, error) { 322 height := chains[0].TipHeight() 323 324 //New height is reached, need to update block reward 325 if height > preHeight { 326 327 err = testutil.WaitUntil(100*time.Millisecond, 15*time.Second, func() (bool, error) { 328 //This Waituntil block guarantees that we can get a consistent snapshot of the followings at some height: 329 // 1) all unclaimed balance live 330 // 2) expected unclaimed balance 331 // The test keeps comparing these values (after Waituntil block) to make sure everything is correct 332 curHigh := chains[0].TipHeight() 333 334 //check pending Claim actions, if a claim is executed, then adjust the expectation accordingly 335 //Wait until all the pending actions are settled 336 updateExpectationWithPendingClaimList(t, apis[0].CoreService(), exptUnclaimed, claimedAmount, pendingClaimActions) 337 if len(pendingClaimActions) > 0 { 338 // if there is pending action, retry 339 return false, nil 340 } 341 342 for i := 0; i < numNodes; i++ { 343 rewardAddr := identityset.Address(i + numNodes) 344 unClaimedBalances[rewardAddr.String()], _, err = 345 rps[0].UnclaimedBalance(context.Background(), sfs[0], rewardAddr) 346 } 347 348 if curHigh != chains[0].TipHeight() { 349 return false, nil 350 } 351 352 //add expected block/epoch reward 353 for h := preExpectHigh + 1; h <= curHigh; h++ { 354 //Add block reward to current block producer 355 header, err := chains[0].BlockHeaderByHeight(h) 356 require.NoError(t, err) 357 exptUnclaimed[getRewardAddStr[header.ProducerAddress()]] = 358 big.NewInt(0).Add(exptUnclaimed[getRewardAddStr[header.ProducerAddress()]], blockReward) 359 360 //update Epoch rewards 361 epochNum := h / blocksPerEpoch 362 if epochNum > preEpochNum { 363 require.Equal(t, epochNum, preEpochNum+1) 364 preEpochNum = epochNum 365 366 //Add normal epoch reward 367 for i := 0; i < numNodes; i++ { 368 rewardAddrStr := identityset.Address(i + numNodes).String() 369 expectAfterEpoch := big.NewInt(0).Add(exptUnclaimed[rewardAddrStr], epRwdShares[rewardAddrStr]) 370 exptUnclaimed[rewardAddrStr] = expectAfterEpoch 371 } 372 //Add foundation bonus 373 foundationBonusLastEpoch, err := rps[0].FoundationBonusLastEpoch(context.Background(), sfs[0]) 374 require.NoError(t, err) 375 foundationBonus, err := rps[0].FoundationBonus(context.Background(), sfs[0]) 376 require.NoError(t, err) 377 if epochNum <= foundationBonusLastEpoch { 378 for i := 0; i < numNodes; i++ { 379 rewardAddrStr := identityset.Address(i + numNodes).String() 380 expectAfterEpochBonus := big.NewInt(0).Add(exptUnclaimed[rewardAddrStr], foundationBonus) 381 exptUnclaimed[rewardAddrStr] = expectAfterEpochBonus 382 } 383 } 384 385 } 386 preExpectHigh = h 387 } 388 389 //check pending Claim actions, if a claim is executed, then adjust the expectation accordingly 390 updateExpectationWithPendingClaimList(t, apis[0].CoreService(), exptUnclaimed, claimedAmount, pendingClaimActions) 391 392 curHighCheck := chains[0].TipHeight() 393 preHeight = curHighCheck 394 //If chain height changes, we need to take snapshot again. 395 return curHigh == curHighCheck, nil 396 397 }) 398 require.NoError(t, err) 399 400 //Comparing the expected and real unclaimed balance 401 for i := 0; i < numNodes; i++ { 402 rewardAddrStr := identityset.Address(i + numNodes).String() 403 404 fmt.Println("Server ", i, " ", rewardAddrStr, 405 " unclaimed ", unClaimedBalances[rewardAddrStr].String(), " height ", preHeight) 406 fmt.Println("Server ", i, " ", rewardAddrStr, 407 " expected ", exptUnclaimed[rewardAddrStr].String()) 408 409 require.Equal(t, exptUnclaimed[rewardAddrStr].String(), unClaimedBalances[rewardAddrStr].String()) 410 } 411 412 // perform a random claim and record the amount 413 // chose a random node to claim 414 d := rand.Intn(numNodes) 415 var amount *big.Int 416 rewardAddrStr := identityset.Address(d + numNodes).String() 417 rewardPriKey := identityset.PrivateKey(d + numNodes) 418 expectedSuccess := true 419 420 rand.Seed(time.Now().UnixNano()) 421 switch r := rand.Intn(int(totalClaimCasesNum)); claimTestCaseID(r) { 422 case caseClaimZero: 423 //Claim 0 424 amount = big.NewInt(0) 425 case caseClaimAll: 426 //Claim all 427 amount = exptUnclaimed[rewardAddrStr] 428 case caseClaimMoreThanBalance: 429 //Claim more than available unclaimed balance 430 amount = big.NewInt(0).Mul(exptUnclaimed[rewardAddrStr], big.NewInt(2)) 431 case caseClaimPartOfBalance: 432 //Claim random part of available 433 amount = big.NewInt(0).Div(exptUnclaimed[rewardAddrStr], big.NewInt(int64(rand.Intn(100000)))) 434 case caseClaimNegative: 435 //Claim negative 436 amount = big.NewInt(-100000) 437 expectedSuccess = false 438 case caseClaimToNonRewardingAddr: 439 //Claim to operator address instead of reward address 440 rewardPriKey = identityset.PrivateKey(d) 441 amount = big.NewInt(12345) 442 expectedSuccess = false 443 } 444 445 injectClaim(t, nil, client, rewardPriKey, amount, 446 expectedSuccess, 3, 1, pendingClaimActions) 447 448 } 449 450 return height > runToHeight, nil 451 }); err != nil { 452 453 log.L().Error(err.Error()) 454 } 455 456 //Wait until all the pending actions are settled 457 err = testutil.WaitUntil(100*time.Millisecond, 40*time.Second, func() (bool, error) { 458 updateExpectationWithPendingClaimList(t, apis[0].CoreService(), exptUnclaimed, claimedAmount, pendingClaimActions) 459 return len(pendingClaimActions) == 0, nil 460 }) 461 require.NoError(t, err) 462 463 for i := 0; i < numNodes; i++ { 464 //Check Reward address balance 465 rewardAddr := identityset.Address(i + numNodes) 466 rewardAddrStr := rewardAddr.String() 467 endState, err := accountutil.AccountState( 468 genesis.WithGenesisContext(context.Background(), configs[0].Genesis), 469 sfs[0], 470 rewardAddr, 471 ) 472 require.NoError(t, err) 473 fmt.Println("Server ", i, " ", rewardAddrStr, " Closing Balance ", endState.Balance.String()) 474 expectBalance := big.NewInt(0).Add(initBalances[rewardAddrStr], claimedAmount[rewardAddrStr]) 475 fmt.Println("Server ", i, " ", rewardAddrStr, "Expected Balance ", expectBalance.String()) 476 require.Equal(t, expectBalance.String(), endState.Balance.String()) 477 478 //Make sure the non-reward addresses have not received money 479 operatorAddr := identityset.Address(i) 480 operatorAddrStr := identityset.Address(i).String() 481 operatorState, err := accountutil.AccountState( 482 genesis.WithGenesisContext(context.Background(), configs[i].Genesis), 483 sfs[i], 484 operatorAddr, 485 ) 486 require.NoError(t, err) 487 require.Equal(t, initBalances[operatorAddrStr], operatorState.Balance) 488 } 489 } 490 491 func injectClaim( 492 t *testing.T, 493 wg *sync.WaitGroup, 494 c iotexapi.APIServiceClient, 495 beneficiaryPri crypto.PrivateKey, 496 amount *big.Int, 497 expectedSuccess bool, 498 retryNum int, 499 retryInterval int, 500 pendingClaimActions map[hash.Hash256]bool, 501 ) { 502 if wg != nil { 503 wg.Add(1) 504 } 505 payload := []byte{} 506 beneficiaryAddr := beneficiaryPri.PublicKey().Address() 507 require.NotNil(t, beneficiaryAddr) 508 ctx := context.Background() 509 request := iotexapi.GetAccountRequest{Address: beneficiaryAddr.String()} 510 response, err := c.GetAccount(ctx, &request) 511 require.NoError(t, err) 512 nonce := response.AccountMeta.PendingNonce 513 514 b := &action.ClaimFromRewardingFundBuilder{} 515 act := b.SetAmount(amount).SetData(payload).Build() 516 bd := &action.EnvelopeBuilder{} 517 elp := bd.SetNonce(nonce). 518 SetGasPrice(big.NewInt(0)). 519 SetGasLimit(100000). 520 SetAction(&act).Build() 521 522 selp, err := action.Sign(elp, beneficiaryPri) 523 require.NoError(t, err) 524 525 bo := backoff.WithMaxRetries(backoff.NewConstantBackOff(time.Duration(retryInterval)*time.Second), uint64(retryNum)) 526 if err := backoff.Retry(func() error { 527 _, err := c.SendAction(context.Background(), &iotexapi.SendActionRequest{Action: selp.Proto()}) 528 return err 529 }, bo); err != nil { 530 log.L().Error("Failed to inject claim", zap.Error(err)) 531 } 532 533 if err == nil { 534 selpHash, err1 := selp.Hash() 535 if err1 != nil { 536 log.L().Error("Failed to get hash", zap.Error(err1)) 537 } 538 pendingClaimActions[selpHash] = expectedSuccess 539 } 540 541 if wg != nil { 542 wg.Done() 543 } 544 } 545 546 func updateExpectationWithPendingClaimList( 547 t *testing.T, 548 api api.CoreService, 549 exptUnclaimed map[string]*big.Int, 550 claimedAmount map[string]*big.Int, 551 pendingClaimActions map[hash.Hash256]bool, 552 ) bool { 553 updated := false 554 for selpHash, expectedSuccess := range pendingClaimActions { 555 receipt, err := util.GetReceiptByAction(api, selpHash) 556 if err == nil { 557 actInfo, err := util.GetActionByActionHash(api, selpHash) 558 require.NoError(t, err) 559 addr := actInfo.GetSender() 560 require.NotNil(t, addr) 561 562 act := &action.ClaimFromRewardingFund{} 563 err = act.LoadProto(actInfo.GetAction().Core.GetClaimFromRewardingFund()) 564 require.NoError(t, err) 565 amount := act.Amount() 566 567 if receipt.Status == uint64(iotextypes.ReceiptStatus_Success) { 568 newExpectUnclaimed := big.NewInt(0).Sub(exptUnclaimed[addr], amount) 569 exptUnclaimed[addr] = newExpectUnclaimed 570 571 newClaimedAmount := big.NewInt(0).Add(claimedAmount[addr], amount) 572 claimedAmount[addr] = newClaimedAmount 573 updated = true 574 575 //An test case expected to fail should never success 576 require.NotEqual(t, expectedSuccess, false) 577 } 578 579 delete(pendingClaimActions, selpHash) 580 } 581 } 582 583 return updated 584 } 585 586 func newConfig( 587 chainDBPath, 588 trieDBPath, 589 indexDBPath, 590 contractIndexDBPath string, 591 producerPriKey crypto.PrivateKey, 592 networkPort, 593 apiPort int, 594 numNodes uint64, 595 ) config.Config { 596 cfg := config.Default 597 598 cfg.Network.Port = networkPort 599 cfg.Network.BootstrapNodes = []string{"/ip4/127.0.0.1/tcp/4689/ipfs/12D3KooWJwW6pUpTkxPTMv84RPLPMQVEAjZ6fvJuX4oZrvW5DAGQ"} 600 601 cfg.Chain.ID = 1 602 cfg.Chain.ChainDBPath = chainDBPath 603 cfg.Chain.TrieDBPath = trieDBPath 604 cfg.Chain.IndexDBPath = indexDBPath 605 cfg.Chain.ContractStakingIndexDBPath = contractIndexDBPath 606 cfg.Chain.ProducerPrivKey = producerPriKey.HexString() 607 cfg.Chain.EnableAsyncIndexWrite = false 608 609 cfg.ActPool.MinGasPriceStr = big.NewInt(0).String() 610 611 cfg.Consensus.Scheme = config.RollDPoSScheme 612 cfg.Consensus.RollDPoS.FSM.UnmatchedEventInterval = 120 * time.Millisecond 613 cfg.Consensus.RollDPoS.FSM.AcceptBlockTTL = 200 * time.Millisecond 614 cfg.Consensus.RollDPoS.FSM.AcceptProposalEndorsementTTL = 100 * time.Millisecond 615 cfg.Consensus.RollDPoS.FSM.AcceptLockEndorsementTTL = 100 * time.Millisecond 616 cfg.Consensus.RollDPoS.FSM.CommitTTL = 100 * time.Millisecond 617 cfg.Consensus.RollDPoS.FSM.EventChanSize = 100000 618 cfg.Consensus.RollDPoS.ToleratedOvertime = 1200 * time.Millisecond 619 cfg.Consensus.RollDPoS.Delay = 6 * time.Second 620 621 cfg.API.GRPCPort = apiPort 622 623 cfg.Genesis.Blockchain.NumSubEpochs = 4 624 cfg.Genesis.Blockchain.NumDelegates = numNodes 625 cfg.Genesis.Blockchain.TimeBasedRotation = true 626 cfg.Genesis.Delegates = cfg.Genesis.Delegates[0:numNodes] 627 cfg.Genesis.BlockInterval = 500 * time.Millisecond 628 cfg.Genesis.EnableGravityChainVoting = true 629 cfg.Genesis.Rewarding.FoundationBonusLastEpoch = 2 630 631 return cfg 632 }