diff --git a/api/coreservice_test.go b/api/coreservice_test.go index 27277e4914..23bbc88dc9 100644 --- a/api/coreservice_test.go +++ b/api/coreservice_test.go @@ -23,17 +23,33 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" "github.com/iotexproject/go-pkgs/hash" + "github.com/iotexproject/iotex-address/address" "github.com/iotexproject/iotex-core/action" + "github.com/iotexproject/iotex-core/action/protocol" + accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util" + "github.com/iotexproject/iotex-core/action/protocol/execution/evm" "github.com/iotexproject/iotex-core/actpool" "github.com/iotexproject/iotex-core/api/logfilter" "github.com/iotexproject/iotex-core/blockchain" "github.com/iotexproject/iotex-core/blockchain/block" "github.com/iotexproject/iotex-core/blockchain/blockdao" + "github.com/iotexproject/iotex-core/blockchain/filedao" + "github.com/iotexproject/iotex-core/blockchain/genesis" + "github.com/iotexproject/iotex-core/blockindex" + "github.com/iotexproject/iotex-core/db" + "github.com/iotexproject/iotex-core/server/itx/nodestats" + "github.com/iotexproject/iotex-core/state" "github.com/iotexproject/iotex-core/test/identityset" + mock_apitypes "github.com/iotexproject/iotex-core/test/mock/mock_apiresponder" + "github.com/iotexproject/iotex-core/test/mock/mock_blockchain" "github.com/iotexproject/iotex-core/test/mock/mock_blockdao" "github.com/iotexproject/iotex-core/test/mock/mock_blockindex" + "github.com/iotexproject/iotex-core/test/mock/mock_blocksync" "github.com/iotexproject/iotex-core/test/mock/mock_envelope" + "github.com/iotexproject/iotex-core/test/mock/mock_factory" "github.com/iotexproject/iotex-core/testutil" + "github.com/iotexproject/iotex-election/test/mock/mock_committee" + "github.com/iotexproject/iotex-election/types" "github.com/iotexproject/iotex-proto/golang/iotexapi" "github.com/iotexproject/iotex-proto/golang/iotextypes" ) @@ -212,29 +228,392 @@ func TestEstimateGasForAction(t *testing.T) { require.Contains(err.Error(), action.ErrNilProto.Error()) } +func TestElectionBuckets(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + t.Run("ElectionCommitteeIsNil", func(t *testing.T) { + cs := &coreService{} + _, err := cs.ElectionBuckets(uint64(0)) + require.ErrorContains(err, "Native election no supported") + }) + + var ( + committee = mock_committee.NewMockCommittee(ctrl) + cs = &coreService{ + electionCommittee: committee, + } + ) + + t.Run("FailedToNativeBucketsByEpoch", func(t *testing.T) { + committee.EXPECT().NativeBucketsByEpoch(gomock.Any()).Return(nil, errors.New(t.Name())).Times(1) + _, err := cs.ElectionBuckets(uint64(0)) + require.ErrorContains(err, t.Name()) + }) + + t.Run("ElectionBucketsSuccess", func(t *testing.T) { + vote, err := types.NewBucket( + time.Now().Add(-20*time.Hour), + time.Hour*3, + big.NewInt(9), + []byte("voter"), + []byte("candidate"), + false, + ) + require.NoError(err) + + committee.EXPECT().NativeBucketsByEpoch(gomock.Any()).Return([]*types.Bucket{vote}, nil).Times(1) + re, err := cs.ElectionBuckets(uint64(0)) + require.NoError(err) + require.Equal(1, len(re)) + require.Equal(vote.Voter(), re[0].Voter) + }) +} + +func TestTransactionLogByActionHash(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + t.Run("IndexerIsNil", func(t *testing.T) { + cs := &coreService{} + _, err := cs.TransactionLogByActionHash("") + require.ErrorContains(err, blockindex.ErrActionIndexNA.Error()) + }) + + var ( + blkDAO = mock_blockdao.NewMockBlockDAO(ctrl) + indexer = mock_blockindex.NewMockIndexer(ctrl) + cs = &coreService{ + dao: blkDAO, + indexer: indexer, + } + ) + + t.Run("NotContainsTxLog", func(t *testing.T) { + blkDAO.EXPECT().ContainsTransactionLog().Return(false).Times(1) + _, err := cs.TransactionLogByActionHash("") + require.ErrorContains(err, filedao.ErrNotSupported.Error()) + }) + + t.Run("FailedToDecodeString", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + blkDAO.EXPECT().ContainsTransactionLog().Return(true).Times(1) + + p = p.ApplyFuncReturn(hex.DecodeString, nil, errors.New(t.Name())) + + _, err := cs.TransactionLogByActionHash("") + require.ErrorContains(err, t.Name()) + }) + + t.Run("FailedToGetActionIndex", func(t *testing.T) { + t.Run("EqualErrNotExist", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + blkDAO.EXPECT().ContainsTransactionLog().Return(true).Times(1) + indexer.EXPECT().GetActionIndex(gomock.Any()).Return(nil, db.ErrNotExist).Times(1) + + p = p.ApplyFuncReturn(hex.DecodeString, []byte("actHash"), nil) + + _, err := cs.TransactionLogByActionHash("") + require.ErrorContains(err, db.ErrNotExist.Error()) + }) + + t.Run("NotEqualErrNotExist", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + blkDAO.EXPECT().ContainsTransactionLog().Return(true).Times(1) + indexer.EXPECT().GetActionIndex(gomock.Any()).Return(nil, errors.New(t.Name())).Times(1) + + p = p.ApplyFuncReturn(hex.DecodeString, []byte("actHash"), nil) + + _, err := cs.TransactionLogByActionHash("") + require.ErrorContains(err, t.Name()) + }) + }) + + t.Run("FailedToTransactionLogs", func(t *testing.T) { + t.Run("EqualErrNotExist", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + blkDAO.EXPECT().ContainsTransactionLog().Return(true).Times(1) + blkDAO.EXPECT().TransactionLogs(gomock.Any()).Return(nil, db.ErrNotExist).Times(1) + indexer.EXPECT().GetActionIndex(gomock.Any()).Return(&blockindex.ActionIndex{}, nil).Times(1) + + p = p.ApplyFuncReturn(hex.DecodeString, []byte("actHash"), nil) + + _, err := cs.TransactionLogByActionHash("") + require.ErrorContains(err, db.ErrNotExist.Error()) + }) + + t.Run("NotEqualErrNotExist", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + blkDAO.EXPECT().ContainsTransactionLog().Return(true).Times(1) + blkDAO.EXPECT().TransactionLogs(gomock.Any()).Return(nil, errors.New(t.Name())).Times(1) + indexer.EXPECT().GetActionIndex(gomock.Any()).Return(&blockindex.ActionIndex{}, nil).Times(1) + + p = p.ApplyFuncReturn(hex.DecodeString, []byte("actHash"), nil) + + _, err := cs.TransactionLogByActionHash("") + require.ErrorContains(err, t.Name()) + }) + }) + + t.Run("NotFound", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + blkDAO.EXPECT().ContainsTransactionLog().Return(true).Times(1) + blkDAO.EXPECT().TransactionLogs(gomock.Any()).Return(&iotextypes.TransactionLogs{}, nil).Times(1) + indexer.EXPECT().GetActionIndex(gomock.Any()).Return(&blockindex.ActionIndex{}, nil).Times(1) + + p = p.ApplyFuncReturn(hex.DecodeString, []byte("actHash"), nil) + + _, err := cs.TransactionLogByActionHash("") + require.ErrorContains(err, "transaction log not found for action") + }) +} + +func TestTransactionLogByBlockHeight(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + var ( + blkDAO = mock_blockdao.NewMockBlockDAO(ctrl) + cs = &coreService{dao: blkDAO} + ) + + t.Run("NotContainsTxLog", func(t *testing.T) { + blkDAO.EXPECT().ContainsTransactionLog().Return(false).Times(1) + _, _, err := cs.TransactionLogByBlockHeight(uint64(0)) + require.ErrorContains(err, filedao.ErrNotSupported.Error()) + }) + + t.Run("FailedToHeight", func(t *testing.T) { + blkDAO.EXPECT().ContainsTransactionLog().Return(true).Times(1) + blkDAO.EXPECT().Height().Return(uint64(0), errors.New(t.Name())).Times(1) + + _, _, err := cs.TransactionLogByBlockHeight(uint64(0)) + require.ErrorContains(err, t.Name()) + }) + + t.Run("CheckBlockHeight", func(t *testing.T) { + t.Run("BlockHeightLessThanOne", func(t *testing.T) { + blkDAO.EXPECT().ContainsTransactionLog().Return(true).Times(1) + blkDAO.EXPECT().Height().Return(uint64(0), nil).Times(1) + + _, _, err := cs.TransactionLogByBlockHeight(uint64(0)) + require.ErrorContains(err, "invalid block height") + }) + + t.Run("BlockHeightGreaterThanTip", func(t *testing.T) { + blkDAO.EXPECT().ContainsTransactionLog().Return(true).Times(1) + blkDAO.EXPECT().Height().Return(uint64(0), nil).Times(1) + + _, _, err := cs.TransactionLogByBlockHeight(uint64(2)) + require.ErrorContains(err, "invalid block height") + }) + }) + + t.Run("FailedToGetBlockHash", func(t *testing.T) { + t.Run("EqualErrNotExist", func(t *testing.T) { + blkDAO.EXPECT().ContainsTransactionLog().Return(true).Times(1) + blkDAO.EXPECT().Height().Return(uint64(2), nil).Times(1) + blkDAO.EXPECT().GetBlockHash(gomock.Any()).Return(hash.Hash256{}, db.ErrNotExist).Times(1) + + _, _, err := cs.TransactionLogByBlockHeight(uint64(1)) + require.ErrorContains(err, db.ErrNotExist.Error()) + }) + + t.Run("NotEqualErrNotExist", func(t *testing.T) { + blkDAO.EXPECT().ContainsTransactionLog().Return(true).Times(1) + blkDAO.EXPECT().Height().Return(uint64(2), nil).Times(1) + blkDAO.EXPECT().GetBlockHash(gomock.Any()).Return(hash.Hash256{}, errors.New(t.Name())).Times(1) + + _, _, err := cs.TransactionLogByBlockHeight(uint64(1)) + require.ErrorContains(err, t.Name()) + }) + }) + + t.Run("FailedToTransactionLogs", func(t *testing.T) { + t.Run("EqualErrNotExist", func(t *testing.T) { + blkDAO.EXPECT().ContainsTransactionLog().Return(true).Times(1) + blkDAO.EXPECT().Height().Return(uint64(2), nil).Times(1) + blkDAO.EXPECT().GetBlockHash(gomock.Any()).Return(hash.Hash256{}, nil).Times(1) + blkDAO.EXPECT().TransactionLogs(gomock.Any()).Return(nil, db.ErrNotExist).Times(1) + + blockIdentifier, _, err := cs.TransactionLogByBlockHeight(uint64(1)) + require.NoError(err) + require.Equal(uint64(1), blockIdentifier.Height) + }) + + t.Run("NotEqualErrNotExist", func(t *testing.T) { + blkDAO.EXPECT().ContainsTransactionLog().Return(true).Times(1) + blkDAO.EXPECT().Height().Return(uint64(2), nil).Times(1) + blkDAO.EXPECT().GetBlockHash(gomock.Any()).Return(hash.Hash256{}, nil).Times(1) + blkDAO.EXPECT().TransactionLogs(gomock.Any()).Return(nil, errors.New(t.Name())).Times(1) + + _, _, err := cs.TransactionLogByBlockHeight(uint64(1)) + require.ErrorContains(err, t.Name()) + }) + }) +} + func TestEstimateExecutionGasConsumption(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - svr, _, _, _, cleanCallback := setupTestCoreService() - defer cleanCallback() - callAddr := identityset.Address(29) - sc, err := action.NewExecution("", 0, big.NewInt(0), 0, big.NewInt(0), []byte{}) - require.NoError(err) + var ( + bc = mock_blockchain.NewMockBlockchain(ctrl) + sf = mock_factory.NewMockFactory(ctrl) + cs = &coreService{ + bc: bc, + sf: sf, + } + ctx = context.Background() + ) - //gasprice is zero - sc.SetGasPrice(big.NewInt(0)) - estimatedGas, err := svr.EstimateExecutionGasConsumption(context.Background(), sc, callAddr) - require.NoError(err) - require.Equal(uint64(10000), estimatedGas) + t.Run("FailedToAccountState", func(t *testing.T) { + p := NewPatches() + defer p.Reset() - //gasprice no zero, should return error before fixed - sc.SetGasPrice(big.NewInt(100)) - estimatedGas, err = svr.EstimateExecutionGasConsumption(context.Background(), sc, callAddr) - require.NoError(err) - require.Equal(uint64(10000), estimatedGas) + p = p.ApplyFuncReturn(genesis.WithGenesisContext, ctx) + p = p.ApplyFuncReturn(accountutil.AccountState, nil, errors.New(t.Name())) + + bc.EXPECT().Genesis().Return(genesis.Genesis{}).Times(1) + + _, err := cs.EstimateExecutionGasConsumption(ctx, &action.Execution{}, &address.AddrV1{}) + require.ErrorContains(err, t.Name()) + }) + + t.Run("FailedToCheckGasLimitEnough", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyFuncReturn(genesis.WithGenesisContext, ctx) + p = p.ApplyFuncReturn(accountutil.AccountState, &state.Account{}, nil) + p = p.ApplyFuncReturn(protocol.WithFeatureCtx, ctx) + p = p.ApplyFuncReturn(protocol.WithBlockCtx, ctx) + p = p.ApplyFuncReturn(protocol.MustGetFeatureCtx, protocol.FeatureCtx{RefactorFreshAccountConversion: true}) + p = p.ApplyMethodReturn(&state.Account{}, "PendingNonceConsideringFreshAccount", uint64(0)) + p = p.ApplyMethodReturn(&genesis.Blockchain{}, "BlockGasLimitByHeight", uint64(0)) + p = p.ApplyPrivateMethod( + cs, + "isGasLimitEnough", + func( + ctx context.Context, + caller address.Address, + sc *action.Execution, + ) (bool, *action.Receipt, error) { + return false, nil, errors.New(t.Name()) + }, + ) + + bc.EXPECT().Genesis().Return(genesis.Genesis{}).Times(2) + bc.EXPECT().TipHeight().Return(uint64(0)).Times(2) + + _, err := cs.EstimateExecutionGasConsumption(ctx, &action.Execution{}, &address.AddrV1{}) + require.ErrorContains(err, t.Name()) + }) + + t.Run("GasLimitNotEnough", func(t *testing.T) { + t.Run("ExecutionRevertMsgIsNil", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + receipt := &action.Receipt{} + p = p.ApplyFuncReturn(genesis.WithGenesisContext, ctx) + p = p.ApplyFuncReturn(accountutil.AccountState, &state.Account{}, nil) + p = p.ApplyFuncReturn(protocol.WithFeatureCtx, ctx) + p = p.ApplyFuncReturn(protocol.WithBlockCtx, ctx) + p = p.ApplyFuncReturn(protocol.MustGetFeatureCtx, protocol.FeatureCtx{}) + // pending nonce from state + p = p.ApplyMethodReturn(&state.Account{}, "PendingNonce", uint64(0)) + p = p.ApplyMethodReturn(&genesis.Blockchain{}, "BlockGasLimitByHeight", uint64(0)) + p = p.ApplyPrivateMethod( + cs, + "isGasLimitEnough", + func( + ctx context.Context, + caller address.Address, + sc *action.Execution, + ) (bool, *action.Receipt, error) { + return false, receipt, nil + }, + ) + p = p.ApplyMethodReturn(receipt, "ExecutionRevertMsg", "") + + bc.EXPECT().Genesis().Return(genesis.Genesis{}).Times(2) + bc.EXPECT().TipHeight().Return(uint64(0)).Times(2) + + _, err := cs.EstimateExecutionGasConsumption(ctx, &action.Execution{}, &address.AddrV1{}) + require.ErrorContains(err, "execution simulation failed:") + }) + + t.Run("ExecutionRevertMsgIsNotNil", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + receipt := &action.Receipt{} + p = p.ApplyFuncReturn(genesis.WithGenesisContext, ctx) + p = p.ApplyFuncReturn(accountutil.AccountState, &state.Account{}, nil) + p = p.ApplyFuncReturn(protocol.WithFeatureCtx, ctx) + p = p.ApplyFuncReturn(protocol.WithBlockCtx, ctx) + p = p.ApplyFuncReturn(protocol.MustGetFeatureCtx, protocol.FeatureCtx{RefactorFreshAccountConversion: true}) + // pending nonce from fresh account + p = p.ApplyMethodReturn(&state.Account{}, "PendingNonceConsideringFreshAccount", uint64(0)) + p = p.ApplyMethodReturn(&genesis.Blockchain{}, "BlockGasLimitByHeight", uint64(0)) + p = p.ApplyPrivateMethod( + cs, + "isGasLimitEnough", + func( + ctx context.Context, + caller address.Address, + sc *action.Execution, + ) (bool, *action.Receipt, error) { + return false, receipt, nil + }, + ) + p = p.ApplyMethodReturn(receipt, "ExecutionRevertMsg", "TestRevertMsg") + + bc.EXPECT().Genesis().Return(genesis.Genesis{}).Times(2) + bc.EXPECT().TipHeight().Return(uint64(0)).Times(2) + + _, err := cs.EstimateExecutionGasConsumption(ctx, &action.Execution{}, &address.AddrV1{}) + require.ErrorContains(err, "execution simulation is reverted due to the reason:") + }) + }) + + t.Run("EstimateExecutionGasConsumptionSuccess", func(t *testing.T) { + svr, _, _, _, cleanCallback := setupTestCoreService() + defer cleanCallback() + callAddr := identityset.Address(29) + sc, err := action.NewExecution("", 0, big.NewInt(0), 0, big.NewInt(0), []byte{}) + require.NoError(err) + + //gasprice is zero + sc.SetGasPrice(big.NewInt(0)) + estimatedGas, err := svr.EstimateExecutionGasConsumption(context.Background(), sc, callAddr) + require.NoError(err) + require.Equal(uint64(10000), estimatedGas) + + //gasprice no zero, should return error before fixed + sc.SetGasPrice(big.NewInt(100)) + estimatedGas, err = svr.EstimateExecutionGasConsumption(context.Background(), sc, callAddr) + require.NoError(err) + require.Equal(uint64(10000), estimatedGas) + }) } func TestTraceTransaction(t *testing.T) { @@ -485,3 +864,379 @@ func TestReverseActionsInBlock(t *testing.T) { require.Empty(actions) }) } + +func TestActions(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + indexer := mock_blockindex.NewMockIndexer(ctrl) + cs := &coreService{ + cfg: DefaultConfig, + indexer: indexer, + } + + t.Run("FailedToCheckActionIndex", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyPrivateMethod( + cs, + "checkActionIndex", + func() error { + return errors.New(t.Name()) + }, + ) + _, err := cs.Actions(0, 0) + require.EqualError(err, t.Name()) + }) + + t.Run("CountIsZero", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyPrivateMethod( + cs, + "checkActionIndex", + func() error { + return nil + }, + ) + + _, err := cs.Actions(0, 0) + require.ErrorContains(err, "count must be greater than zero") + }) + + t.Run("CountIsGreaterThanRange", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyPrivateMethod( + cs, + "checkActionIndex", + func() error { + return nil + }, + ) + + _, err := cs.Actions(0, 1001) + require.ErrorContains(err, "range exceeds the limit") + }) + + t.Run("FailedToGetTotalActions", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyPrivateMethod( + cs, + "checkActionIndex", + func() error { + return nil + }, + ) + + indexer.EXPECT().GetTotalActions().Return(uint64(0), errors.New(t.Name())).Times(1) + _, err := cs.Actions(0, 1) + require.ErrorContains(err, t.Name()) + }) + + t.Run("StartGreaterThanTotalActions", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyPrivateMethod( + cs, + "checkActionIndex", + func() error { + return nil + }, + ) + + // greater than totalActions + indexer.EXPECT().GetTotalActions().Return(uint64(0), nil).Times(1) + _, err := cs.Actions(1, 1) + require.ErrorContains(err, "start exceeds the total actions in the block") + + // equal totalActions + indexer.EXPECT().GetTotalActions().Return(uint64(2), nil).Times(1) + _, err = cs.Actions(2, 1) + require.ErrorContains(err, "start exceeds the total actions in the block") + }) + + t.Run("GetActionsFromIndexer", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyPrivateMethod( + cs, + "checkActionIndex", + func() error { + return nil + }, + ) + + indexer.EXPECT().GetTotalActions().Return(uint64(1), nil).Times(1) + p = p.ApplyPrivateMethod( + cs, + "getActionsFromIndex", + func(totalActions, start, count uint64) ([]*iotexapi.ActionInfo, error) { + return nil, nil + }, + ) + infos, err := cs.Actions(0, 1) + require.NoError(err) + require.Empty(infos) + }) +} + +func TestCheckActionIndex(t *testing.T) { + require := require.New(t) + + cs := &coreService{} + t.Run("IndexerIsNil", func(t *testing.T) { + err := cs.checkActionIndex() + require.ErrorContains(err, "no action index") + }) +} + +func TestReceiveBlock(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + listener := mock_apitypes.NewMockListener(ctrl) + cs := &coreService{ + readCache: &ReadCache{}, + chainListener: listener, + } + + t.Run("FailedToReceiveBlock", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyMethodReturn(cs.readCache, "Clear") + listener.EXPECT().ReceiveBlock(gomock.Any()).Return(errors.New(t.Name())).Times(1) + err := cs.ReceiveBlock(&block.Block{}) + require.ErrorContains(err, t.Name()) + }) + + t.Run("ReceiveBlockSuccess", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyMethodReturn(cs.readCache, "Clear") + listener.EXPECT().ReceiveBlock(gomock.Any()).Return(nil).Times(1) + err := cs.ReceiveBlock(&block.Block{}) + require.NoError(err) + }) +} + +func TestSimulateExecution(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + var ( + bc = mock_blockchain.NewMockBlockchain(ctrl) + dao = mock_blockdao.NewMockBlockDAO(ctrl) + cs = &coreService{ + bc: bc, + dao: dao, + } + ctx = context.Background() + ) + + t.Run("FailedToAccountState", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyFuncReturn(genesis.WithGenesisContext, ctx) + p = p.ApplyFuncReturn(accountutil.AccountState, nil, errors.New(t.Name())) + bc.EXPECT().Genesis().Return(genesis.Genesis{}).Times(1) + + _, _, err := cs.SimulateExecution(ctx, &address.AddrV1{}, &action.Execution{}) + require.ErrorContains(err, t.Name()) + }) + + t.Run("FailedToContext", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyFuncReturn(genesis.WithGenesisContext, ctx) + p = p.ApplyFuncReturn(accountutil.AccountState, &state.Account{}, nil) + bc.EXPECT().Genesis().Return(genesis.Genesis{}).Times(1) + bc.EXPECT().Context(gomock.Any()).Return(nil, errors.New(t.Name())).Times(1) + + _, _, err := cs.SimulateExecution(ctx, &address.AddrV1{}, &action.Execution{}) + require.ErrorContains(err, t.Name()) + }) + + t.Run("GetPendingNonceFromFreshAccount", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyFuncReturn(genesis.WithGenesisContext, ctx) + p = p.ApplyFuncReturn(accountutil.AccountState, &state.Account{}, nil) + p = p.ApplyFuncReturn(protocol.WithFeatureCtx, ctx) + p = p.ApplyFuncReturn(protocol.WithBlockCtx, ctx) + p = p.ApplyFuncReturn(protocol.MustGetFeatureCtx, protocol.FeatureCtx{RefactorFreshAccountConversion: true}) + p = p.ApplyMethodReturn(&state.Account{}, "PendingNonceConsideringFreshAccount", uint64(0)) + p = p.ApplyMethodReturn(&genesis.Blockchain{}, "BlockGasLimitByHeight", uint64(0)) + p = p.ApplyPrivateMethod( + cs, + "simulateExecution", + func(ctx context.Context, addr address.Address, exec *action.Execution, getBlockHash evm.GetBlockHash, getBlockTime evm.GetBlockTime) ([]byte, *action.Receipt, error) { + return []byte("success"), nil, nil + }, + ) + + bc.EXPECT().Genesis().Return(genesis.Genesis{}).Times(2) + bc.EXPECT().Context(gomock.Any()).Return(ctx, nil).Times(1) + bc.EXPECT().TipHeight().Return(uint64(0)).Times(2) + + bytes, _, err := cs.SimulateExecution(ctx, &address.AddrV1{}, &action.Execution{}) + require.NoError(err) + require.Equal([]byte("success"), bytes) + }) + + t.Run("GetPendingNonce", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyFuncReturn(genesis.WithGenesisContext, ctx) + p = p.ApplyFuncReturn(accountutil.AccountState, &state.Account{}, nil) + p = p.ApplyFuncReturn(protocol.WithFeatureCtx, ctx) + p = p.ApplyFuncReturn(protocol.WithBlockCtx, ctx) + p = p.ApplyFuncReturn(protocol.MustGetFeatureCtx, protocol.FeatureCtx{}) + p = p.ApplyMethodReturn(&state.Account{}, "PendingNonce", uint64(0)) + p = p.ApplyMethodReturn(&genesis.Blockchain{}, "BlockGasLimitByHeight", uint64(0)) + p = p.ApplyPrivateMethod( + cs, + "simulateExecution", + func(ctx context.Context, addr address.Address, exec *action.Execution, getBlockHash evm.GetBlockHash, getBlockTime evm.GetBlockTime) ([]byte, *action.Receipt, error) { + return []byte("success"), nil, nil + }, + ) + + bc.EXPECT().Genesis().Return(genesis.Genesis{}).Times(2) + bc.EXPECT().Context(gomock.Any()).Return(ctx, nil).Times(1) + bc.EXPECT().TipHeight().Return(uint64(0)).Times(2) + + bytes, _, err := cs.SimulateExecution(ctx, &address.AddrV1{}, &action.Execution{}) + require.NoError(err) + require.Equal([]byte("success"), bytes) + }) +} + +func TestSyncingProgress(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + bs := mock_blocksync.NewMockBlockSync(ctrl) + cs := &coreService{bs: bs} + bs.EXPECT().SyncStatus().Return(uint64(0), uint64(0), uint64(0), "").Times(1) + startingHeight, currentHeight, targetHeight := cs.SyncingProgress() + require.Equal(uint64(0), startingHeight) + require.Equal(uint64(0), currentHeight) + require.Equal(uint64(0), targetHeight) +} + +func TestTrack(t *testing.T) { + cs := &coreService{} + t.Run("ApiStatsIsNil", func(t *testing.T) { + cs.Track(nil, time.Now(), "", 0, true) + }) + + cs.apiStats = &nodestats.APILocalStats{} + t.Run("ApiStatsIsNotNil", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyFuncReturn(time.Since, time.Duration(0)) + p = p.ApplyMethodReturn(cs.apiStats, "ReportCall") + cs.Track(nil, time.Now(), "", 0, true) + }) +} + +func TestTraceTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + var ( + bc = mock_blockchain.NewMockBlockchain(ctrl) + cs = &coreService{ + bc: bc, + } + ctx = context.Background() + ) + + t.Run("ConfigIsNil", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyFuncReturn(logger.NewStructLogger, nil) + p = p.ApplyFuncReturn(protocol.WithVMConfigCtx, ctx) + p = p.ApplyFuncReturn(protocol.WithBlockCtx, ctx) + bc.EXPECT().Genesis().Return(genesis.Genesis{}).Times(1) + p = p.ApplyFuncReturn(genesis.WithGenesisContext, ctx) + p = p.ApplyFuncReturn(protocol.WithBlockchainCtx, ctx) + p = p.ApplyFuncReturn(protocol.WithFeatureCtx, ctx) + retval, receipt, tracer, err := cs.traceTx(ctx, nil, nil, func(ctx context.Context) ([]byte, *action.Receipt, error) { + return nil, nil, nil + }) + require.NoError(err) + require.Empty(retval) + require.Empty(receipt) + require.Empty(tracer) + }) + + t.Run("TracerIsNotNil", func(t *testing.T) { + + t.Run("FailedToParseDuration", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyFuncReturn(time.ParseDuration, nil, errors.New(t.Name())) + + testStr := "TestTracer" + _, _, _, err := cs.traceTx(ctx, nil, &tracers.TraceConfig{Tracer: &testStr, Timeout: &testStr}, func(ctx context.Context) ([]byte, *action.Receipt, error) { + return nil, nil, nil + }) + require.ErrorContains(err, t.Name()) + }) + + t.Run("FailedToNewTracer", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyMethodReturn(&tracers.DefaultDirectory, "New", nil, errors.New(t.Name())) + testStr := "TestTracer" + _, _, _, err := cs.traceTx(ctx, nil, &tracers.TraceConfig{Tracer: &testStr}, func(ctx context.Context) ([]byte, *action.Receipt, error) { + return nil, nil, nil + }) + require.ErrorContains(err, t.Name()) + }) + }) + + t.Run("TracerIsNil", func(t *testing.T) { + p := NewPatches() + defer p.Reset() + + p = p.ApplyFuncReturn(logger.NewStructLogger, nil) + p = p.ApplyFuncReturn(protocol.WithVMConfigCtx, ctx) + p = p.ApplyFuncReturn(protocol.WithBlockCtx, ctx) + bc.EXPECT().Genesis().Return(genesis.Genesis{}).Times(1) + p = p.ApplyFuncReturn(genesis.WithGenesisContext, ctx) + p = p.ApplyFuncReturn(protocol.WithBlockchainCtx, ctx) + p = p.ApplyFuncReturn(protocol.WithFeatureCtx, ctx) + retval, receipt, tracer, err := cs.traceTx(ctx, nil, &tracers.TraceConfig{}, func(ctx context.Context) ([]byte, *action.Receipt, error) { + return nil, nil, nil + }) + require.NoError(err) + require.Empty(retval) + require.Empty(receipt) + require.Empty(tracer) + }) +} diff --git a/misc/scripts/mockgen.sh b/misc/scripts/mockgen.sh index b4ec777c04..d52c72a29b 100755 --- a/misc/scripts/mockgen.sh +++ b/misc/scripts/mockgen.sh @@ -141,7 +141,11 @@ mockgen -destination=./test/mock/mock_blockindex/mock_blockindex.go \ -source=./blockindex/bloomfilterindexer.go \ -package=mock_blockindex \ BlockIndex - +mockgen -destination=./test/mock/mock_blockindex/mock_indexer.go \ + -source=blockindex/indexer.go \ + -package mock_blockindex \ + Indexer + mkdir -p ./test/mock/mock_web3server mockgen -destination=./test/mock/mock_web3server/mock_web3server.go \ -source=./api/web3server.go \ @@ -169,3 +173,9 @@ mockgen -destination=./test/mock/mock_blockdao/mock_blockindexer_withstart.go \ -package=mock_blockdao \ github.com/iotexproject/iotex-core/blockchain/blockdao \ BlockIndexerWithStart + +mkdir -p ./test/mock/mock_envelope +mockgen -destination=./test/mock/mock_envelope/mock_envelope.go \ + -source=./action/envelope.go \ + -package=mock_envelope \ + Envelope diff --git a/test/mock/mock_blockindex/mock_indexer.go b/test/mock/mock_blockindex/mock_indexer.go new file mode 100644 index 0000000000..5ca6f53619 --- /dev/null +++ b/test/mock/mock_blockindex/mock_indexer.go @@ -0,0 +1,243 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: blockindex/indexer.go + +// Package mock_blockindex is a generated GoMock package. +package mock_blockindex + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + hash "github.com/iotexproject/go-pkgs/hash" + block "github.com/iotexproject/iotex-core/blockchain/block" + blockindex "github.com/iotexproject/iotex-core/blockindex" +) + +// MockIndexer is a mock of Indexer interface. +type MockIndexer struct { + ctrl *gomock.Controller + recorder *MockIndexerMockRecorder +} + +// MockIndexerMockRecorder is the mock recorder for MockIndexer. +type MockIndexerMockRecorder struct { + mock *MockIndexer +} + +// NewMockIndexer creates a new mock instance. +func NewMockIndexer(ctrl *gomock.Controller) *MockIndexer { + mock := &MockIndexer{ctrl: ctrl} + mock.recorder = &MockIndexerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockIndexer) EXPECT() *MockIndexerMockRecorder { + return m.recorder +} + +// DeleteTipBlock mocks base method. +func (m *MockIndexer) DeleteTipBlock(arg0 context.Context, arg1 *block.Block) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteTipBlock", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteTipBlock indicates an expected call of DeleteTipBlock. +func (mr *MockIndexerMockRecorder) DeleteTipBlock(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteTipBlock", reflect.TypeOf((*MockIndexer)(nil).DeleteTipBlock), arg0, arg1) +} + +// GetActionCountByAddress mocks base method. +func (m *MockIndexer) GetActionCountByAddress(arg0 hash.Hash160) (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetActionCountByAddress", arg0) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetActionCountByAddress indicates an expected call of GetActionCountByAddress. +func (mr *MockIndexerMockRecorder) GetActionCountByAddress(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActionCountByAddress", reflect.TypeOf((*MockIndexer)(nil).GetActionCountByAddress), arg0) +} + +// GetActionHashFromIndex mocks base method. +func (m *MockIndexer) GetActionHashFromIndex(arg0, arg1 uint64) ([][]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetActionHashFromIndex", arg0, arg1) + ret0, _ := ret[0].([][]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetActionHashFromIndex indicates an expected call of GetActionHashFromIndex. +func (mr *MockIndexerMockRecorder) GetActionHashFromIndex(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActionHashFromIndex", reflect.TypeOf((*MockIndexer)(nil).GetActionHashFromIndex), arg0, arg1) +} + +// GetActionIndex mocks base method. +func (m *MockIndexer) GetActionIndex(arg0 []byte) (*blockindex.ActionIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetActionIndex", arg0) + ret0, _ := ret[0].(*blockindex.ActionIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetActionIndex indicates an expected call of GetActionIndex. +func (mr *MockIndexerMockRecorder) GetActionIndex(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActionIndex", reflect.TypeOf((*MockIndexer)(nil).GetActionIndex), arg0) +} + +// GetActionsByAddress mocks base method. +func (m *MockIndexer) GetActionsByAddress(arg0 hash.Hash160, arg1, arg2 uint64) ([][]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetActionsByAddress", arg0, arg1, arg2) + ret0, _ := ret[0].([][]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetActionsByAddress indicates an expected call of GetActionsByAddress. +func (mr *MockIndexerMockRecorder) GetActionsByAddress(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActionsByAddress", reflect.TypeOf((*MockIndexer)(nil).GetActionsByAddress), arg0, arg1, arg2) +} + +// GetBlockHash mocks base method. +func (m *MockIndexer) GetBlockHash(height uint64) (hash.Hash256, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBlockHash", height) + ret0, _ := ret[0].(hash.Hash256) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetBlockHash indicates an expected call of GetBlockHash. +func (mr *MockIndexerMockRecorder) GetBlockHash(height interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockHash", reflect.TypeOf((*MockIndexer)(nil).GetBlockHash), height) +} + +// GetBlockHeight mocks base method. +func (m *MockIndexer) GetBlockHeight(hash hash.Hash256) (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBlockHeight", hash) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetBlockHeight indicates an expected call of GetBlockHeight. +func (mr *MockIndexerMockRecorder) GetBlockHeight(hash interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockHeight", reflect.TypeOf((*MockIndexer)(nil).GetBlockHeight), hash) +} + +// GetBlockIndex mocks base method. +func (m *MockIndexer) GetBlockIndex(arg0 uint64) (*blockindex.BlockIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBlockIndex", arg0) + ret0, _ := ret[0].(*blockindex.BlockIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetBlockIndex indicates an expected call of GetBlockIndex. +func (mr *MockIndexerMockRecorder) GetBlockIndex(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockIndex", reflect.TypeOf((*MockIndexer)(nil).GetBlockIndex), arg0) +} + +// GetTotalActions mocks base method. +func (m *MockIndexer) GetTotalActions() (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTotalActions") + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTotalActions indicates an expected call of GetTotalActions. +func (mr *MockIndexerMockRecorder) GetTotalActions() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTotalActions", reflect.TypeOf((*MockIndexer)(nil).GetTotalActions)) +} + +// Height mocks base method. +func (m *MockIndexer) Height() (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Height") + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Height indicates an expected call of Height. +func (mr *MockIndexerMockRecorder) Height() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Height", reflect.TypeOf((*MockIndexer)(nil).Height)) +} + +// PutBlock mocks base method. +func (m *MockIndexer) PutBlock(arg0 context.Context, arg1 *block.Block) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PutBlock", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// PutBlock indicates an expected call of PutBlock. +func (mr *MockIndexerMockRecorder) PutBlock(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutBlock", reflect.TypeOf((*MockIndexer)(nil).PutBlock), arg0, arg1) +} + +// PutBlocks mocks base method. +func (m *MockIndexer) PutBlocks(arg0 context.Context, arg1 []*block.Block) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PutBlocks", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// PutBlocks indicates an expected call of PutBlocks. +func (mr *MockIndexerMockRecorder) PutBlocks(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutBlocks", reflect.TypeOf((*MockIndexer)(nil).PutBlocks), arg0, arg1) +} + +// Start mocks base method. +func (m *MockIndexer) Start(arg0 context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Start", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Start indicates an expected call of Start. +func (mr *MockIndexerMockRecorder) Start(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockIndexer)(nil).Start), arg0) +} + +// Stop mocks base method. +func (m *MockIndexer) Stop(arg0 context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Stop", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Stop indicates an expected call of Stop. +func (mr *MockIndexerMockRecorder) Stop(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockIndexer)(nil).Stop), arg0) +} diff --git a/test/mock/mock_envelope/mock_envelope.go b/test/mock/mock_envelope/mock_envelope.go index 243baf2a40..99019077cd 100644 --- a/test/mock/mock_envelope/mock_envelope.go +++ b/test/mock/mock_envelope/mock_envelope.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: action/Envelope.go +// Source: action/envelope.go // Package mock_envelope is a generated GoMock package. package mock_envelope