github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/account/protocol_test.go (about)

     1  // Copyright (c) 2019 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 account
     7  
     8  import (
     9  	"context"
    10  	"math/big"
    11  	"testing"
    12  
    13  	"github.com/golang/mock/gomock"
    14  	"github.com/iotexproject/iotex-address/address"
    15  	"github.com/stretchr/testify/require"
    16  
    17  	"github.com/iotexproject/iotex-core/action/protocol"
    18  	accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util"
    19  	"github.com/iotexproject/iotex-core/action/protocol/rewarding"
    20  	"github.com/iotexproject/iotex-core/blockchain/genesis"
    21  	"github.com/iotexproject/iotex-core/db/batch"
    22  	"github.com/iotexproject/iotex-core/state"
    23  	"github.com/iotexproject/iotex-core/test/identityset"
    24  	"github.com/iotexproject/iotex-core/test/mock/mock_chainmanager"
    25  )
    26  
    27  func TestLoadOrCreateAccountState(t *testing.T) {
    28  	require := require.New(t)
    29  
    30  	ctrl := gomock.NewController(t)
    31  	sm := mock_chainmanager.NewMockStateManager(ctrl)
    32  	cb := batch.NewCachedBatch()
    33  	sm.EXPECT().State(gomock.Any(), gomock.Any()).DoAndReturn(
    34  		func(account interface{}, opts ...protocol.StateOption) (uint64, error) {
    35  			cfg, err := protocol.CreateStateConfig(opts...)
    36  			if err != nil {
    37  				return 0, err
    38  			}
    39  			val, err := cb.Get("state", cfg.Key)
    40  			if err != nil {
    41  				return 0, state.ErrStateNotExist
    42  			}
    43  			return 0, state.Deserialize(account, val)
    44  		}).AnyTimes()
    45  	sm.EXPECT().PutState(gomock.Any(), gomock.Any()).DoAndReturn(
    46  		func(account interface{}, opts ...protocol.StateOption) (uint64, error) {
    47  			cfg, err := protocol.CreateStateConfig(opts...)
    48  			if err != nil {
    49  				return 0, err
    50  			}
    51  			ss, err := state.Serialize(account)
    52  			if err != nil {
    53  				return 0, err
    54  			}
    55  			cb.Put("state", cfg.Key, ss, "failed to put state")
    56  			return 0, nil
    57  		}).AnyTimes()
    58  
    59  	for _, test := range []struct {
    60  		accountType   int32
    61  		addr          address.Address
    62  		expectedNonce uint64
    63  	}{
    64  		{
    65  			0,
    66  			identityset.Address(27),
    67  			uint64(0x1),
    68  		},
    69  		{
    70  			1,
    71  			identityset.Address(28),
    72  			uint64(0x0),
    73  		},
    74  	} {
    75  		var (
    76  			s   *state.Account
    77  			err error
    78  		)
    79  		if test.accountType == 0 {
    80  			s, err = accountutil.LoadAccount(sm, test.addr, state.LegacyNonceAccountTypeOption())
    81  		} else {
    82  			s, err = accountutil.LoadAccount(sm, test.addr)
    83  		}
    84  		require.NoError(err)
    85  		require.Equal(big.NewInt(0), s.Balance)
    86  		require.Equal(test.accountType, s.AccountType())
    87  		require.Equal(test.expectedNonce, s.PendingNonce())
    88  
    89  		if test.accountType == 0 {
    90  			require.NoError(createAccount(sm, test.addr.String(), big.NewInt(5), state.LegacyNonceAccountTypeOption()))
    91  			s, err = accountutil.LoadAccount(sm, test.addr, state.LegacyNonceAccountTypeOption())
    92  		} else {
    93  			require.NoError(createAccount(sm, test.addr.String(), big.NewInt(5)))
    94  			s, err = accountutil.LoadAccount(sm, test.addr)
    95  		}
    96  		require.NoError(err)
    97  		require.Equal("5", s.Balance.String())
    98  		require.Equal(test.accountType, s.AccountType())
    99  		require.Equal(test.expectedNonce, s.PendingNonce())
   100  	}
   101  }
   102  
   103  func TestProtocol_Initialize(t *testing.T) {
   104  	require := require.New(t)
   105  	ctrl := gomock.NewController(t)
   106  	sm := mock_chainmanager.NewMockStateManager(ctrl)
   107  	cb := batch.NewCachedBatch()
   108  	sm.EXPECT().State(gomock.Any(), gomock.Any()).DoAndReturn(
   109  		func(account interface{}, opts ...protocol.StateOption) (uint64, error) {
   110  			cfg, err := protocol.CreateStateConfig(opts...)
   111  			if err != nil {
   112  				return 0, err
   113  			}
   114  			val, err := cb.Get("state", cfg.Key)
   115  			if err != nil {
   116  				return 0, state.ErrStateNotExist
   117  			}
   118  			return 0, state.Deserialize(account, val)
   119  		}).AnyTimes()
   120  	sm.EXPECT().PutState(gomock.Any(), gomock.Any()).DoAndReturn(
   121  		func(account interface{}, opts ...protocol.StateOption) (uint64, error) {
   122  			cfg, err := protocol.CreateStateConfig(opts...)
   123  			if err != nil {
   124  				return 0, err
   125  			}
   126  			ss, err := state.Serialize(account)
   127  			if err != nil {
   128  				return 0, err
   129  			}
   130  			cb.Put("state", cfg.Key, ss, "failed to put state")
   131  			return 0, nil
   132  		}).AnyTimes()
   133  
   134  	ge := genesis.Default
   135  	ge.Account.InitBalanceMap = map[string]string{
   136  		identityset.Address(0).String(): "100",
   137  	}
   138  	ctx := protocol.WithBlockCtx(context.Background(), protocol.BlockCtx{
   139  		BlockHeight: 0,
   140  	})
   141  	ctx = protocol.WithFeatureCtx(genesis.WithGenesisContext(ctx, ge))
   142  	p := NewProtocol(rewarding.DepositGas)
   143  	require.NoError(
   144  		p.CreateGenesisStates(
   145  			ctx,
   146  			sm,
   147  		),
   148  	)
   149  
   150  	ge.Account.InitBalanceMap[identityset.Address(1).String()] = "-1"
   151  	require.Error(
   152  		p.CreateGenesisStates(
   153  			ctx,
   154  			sm,
   155  		),
   156  	)
   157  
   158  	require.Error(createAccount(sm, identityset.Address(0).String(), big.NewInt(0)))
   159  	acc0, err := accountutil.LoadAccount(sm, identityset.Address(0))
   160  	require.NoError(err)
   161  	require.Equal(big.NewInt(100), acc0.Balance)
   162  }
   163  
   164  func TestRegisterOrForceRegister(t *testing.T) {
   165  	require := require.New(t)
   166  
   167  	p := NewProtocol(rewarding.DepositGas)
   168  	require.Equal(protocolID, p.Name())
   169  
   170  	registry := protocol.NewRegistry()
   171  	require.NoError(p.Register(registry))
   172  	require.Error(p.Register(registry))
   173  	require.NoError(p.ForceRegister(registry))
   174  
   175  	foundP := FindProtocol(registry)
   176  	require.Equal(p, foundP)
   177  
   178  	require.Nil(FindProtocol(nil))
   179  
   180  	registry = protocol.NewRegistry()
   181  	require.Nil(FindProtocol(registry))
   182  }
   183  
   184  // TestAssertZeroBlockHeight tests the assertZeroBlockHeight funcs
   185  func TestAssertZeroBlockHeight(t *testing.T) {
   186  	require := require.New(t)
   187  
   188  	p := NewProtocol(rewarding.DepositGas)
   189  	require.NoError(p.assertZeroBlockHeight(0))
   190  	// should return an error if height is not zero
   191  	require.Error(p.assertZeroBlockHeight(1))
   192  }
   193  
   194  func TestAssertAmountsAndEqualLength(t *testing.T) {
   195  	require := require.New(t)
   196  
   197  	p := NewProtocol(rewarding.DepositGas)
   198  	amounts := []*big.Int{
   199  		big.NewInt(0),
   200  		big.NewInt(1),
   201  		big.NewInt(2),
   202  	}
   203  	require.NoError(p.assertAmounts(amounts))
   204  	amounts[0] = big.NewInt(-1)
   205  	require.Error(p.assertAmounts(amounts))
   206  
   207  	addrs := []address.Address{
   208  		&address.AddrV1{},
   209  		&address.AddrV1{},
   210  		&address.AddrV1{},
   211  	}
   212  	require.NoError(p.assertEqualLength(addrs, amounts))
   213  	addrs = addrs[:2]
   214  	require.Error(p.assertEqualLength(addrs, amounts))
   215  }