package keeper_test import ( "testing" "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/kava-labs/kava/app" "github.com/kava-labs/kava/x/bep3/keeper" "github.com/kava-labs/kava/x/bep3/types" "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" tmtime "github.com/tendermint/tendermint/types/time" ) const LongtermStorageDuration = 86400 type KeeperTestSuite struct { suite.Suite keeper keeper.Keeper app app.TestApp ctx sdk.Context } func (suite *KeeperTestSuite) SetupTest() { config := sdk.GetConfig() app.SetBech32AddressPrefixes(config) suite.ResetChain() return } func (suite *KeeperTestSuite) ResetChain() { tApp := app.NewTestApp() ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()}) keeper := tApp.GetBep3Keeper() suite.app = tApp suite.ctx = ctx suite.keeper = keeper } func (suite *KeeperTestSuite) TestGetSetAtomicSwap() { suite.ResetChain() // Set new atomic swap atomicSwap := atomicSwap(suite.ctx, 1) suite.keeper.SetAtomicSwap(suite.ctx, atomicSwap) // Check atomic swap in store s, found := suite.keeper.GetAtomicSwap(suite.ctx, atomicSwap.GetSwapID()) suite.True(found) suite.Equal(atomicSwap, s) // Check fake atomic swap not in store fakeSwapID := types.CalculateSwapID(atomicSwap.RandomNumberHash, TestUser2, "otheraddress") _, found = suite.keeper.GetAtomicSwap(suite.ctx, fakeSwapID) suite.False(found) } func (suite *KeeperTestSuite) TestRemoveAtomicSwap() { suite.ResetChain() // Set new atomic swap atomicSwap := atomicSwap(suite.ctx, 1) suite.keeper.SetAtomicSwap(suite.ctx, atomicSwap) // Check atomic swap in store s, found := suite.keeper.GetAtomicSwap(suite.ctx, atomicSwap.GetSwapID()) suite.True(found) suite.Equal(atomicSwap, s) suite.keeper.RemoveAtomicSwap(suite.ctx, atomicSwap.GetSwapID()) // Check atomic swap not in store _, found = suite.keeper.GetAtomicSwap(suite.ctx, atomicSwap.GetSwapID()) suite.False(found) } func (suite *KeeperTestSuite) TestIterateAtomicSwaps() { suite.ResetChain() // Set atomic swaps atomicSwaps := atomicSwaps(suite.ctx, 4) for _, s := range atomicSwaps { suite.keeper.SetAtomicSwap(suite.ctx, s) } // Read each atomic swap from the store var readAtomicSwaps types.AtomicSwaps suite.keeper.IterateAtomicSwaps(suite.ctx, func(a types.AtomicSwap) bool { readAtomicSwaps = append(readAtomicSwaps, a) return false }) // Check expected values suite.Equal(len(atomicSwaps), len(readAtomicSwaps)) } func (suite *KeeperTestSuite) TestGetAllAtomicSwaps() { suite.ResetChain() // Set atomic swaps atomicSwaps := atomicSwaps(suite.ctx, 4) for _, s := range atomicSwaps { suite.keeper.SetAtomicSwap(suite.ctx, s) } // Get and check atomic swaps res := suite.keeper.GetAllAtomicSwaps(suite.ctx) suite.Equal(4, len(res)) } func (suite *KeeperTestSuite) TestInsertIntoByBlockIndex() { suite.ResetChain() // Set new atomic swap in by block index atomicSwap := atomicSwap(suite.ctx, 1) suite.keeper.InsertIntoByBlockIndex(suite.ctx, atomicSwap) // Block index lacks getter methods, must use iteration to get count of swaps in store var swapIDs [][]byte suite.keeper.IterateAtomicSwapsByBlock(suite.ctx, uint64(atomicSwap.ExpireHeight+1), func(id []byte) bool { swapIDs = append(swapIDs, id) return false }) suite.Equal(len(swapIDs), 1) // Marshal the expected swapID cdc := suite.app.Codec() res, _ := cdc.MarshalBinaryBare(atomicSwap.GetSwapID()) expectedSwapID := res[1:] suite.Equal(expectedSwapID, swapIDs[0]) } func (suite *KeeperTestSuite) TestRemoveFromByBlockIndex() { suite.ResetChain() // Set new atomic swap in by block index atomicSwap := atomicSwap(suite.ctx, 1) suite.keeper.InsertIntoByBlockIndex(suite.ctx, atomicSwap) // Check stored data in block index var swapIDsPre [][]byte suite.keeper.IterateAtomicSwapsByBlock(suite.ctx, uint64(atomicSwap.ExpireHeight+1), func(id []byte) bool { swapIDsPre = append(swapIDsPre, id) return false }) suite.Equal(len(swapIDsPre), 1) suite.keeper.RemoveFromByBlockIndex(suite.ctx, atomicSwap) // Check stored data not in block index var swapIDsPost [][]byte suite.keeper.IterateAtomicSwapsByBlock(suite.ctx, uint64(atomicSwap.ExpireHeight+1), func(id []byte) bool { swapIDsPost = append(swapIDsPost, id) return false }) suite.Equal(len(swapIDsPost), 0) } func (suite *KeeperTestSuite) TestIterateAtomicSwapsByBlock() { suite.ResetChain() type args struct { blockCtx sdk.Context swap types.AtomicSwap } var testCases []args for i := 0; i < 8; i++ { // Set up context 100 blocks apart blockCtx := suite.ctx.WithBlockHeight(int64(i) * 100) // Initialize a new atomic swap (different randomNumberHash = different swap IDs) timestamp := tmtime.Now().Add(time.Duration(i) * time.Minute).Unix() randomNumber, _ := types.GenerateSecureRandomNumber() randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp) atomicSwap := types.NewAtomicSwap(cs(c("bnb", 50000)), randomNumberHash, blockCtx.BlockHeight(), timestamp, TestUser1, TestUser2, TestSenderOtherChain, TestRecipientOtherChain, 0, types.Open, true, types.Incoming) // Insert into block index suite.keeper.InsertIntoByBlockIndex(blockCtx, atomicSwap) // Add to local block index testCases = append(testCases, args{blockCtx, atomicSwap}) } // Set up the expected swap IDs for a given cutoff block cutoffBlock := int64(450) var expectedSwapIDs [][]byte for _, tc := range testCases { if tc.blockCtx.BlockHeight() < cutoffBlock || tc.blockCtx.BlockHeight() == cutoffBlock { expectedSwapIDs = append(expectedSwapIDs, tc.swap.GetSwapID()) } } // Read the swap IDs from store for a given cutoff block var readSwapIDs [][]byte suite.keeper.IterateAtomicSwapsByBlock(suite.ctx, uint64(cutoffBlock), func(id []byte) bool { readSwapIDs = append(readSwapIDs, id) return false }) suite.Equal(expectedSwapIDs, readSwapIDs) } func (suite *KeeperTestSuite) TestInsertIntoLongtermStorage() { suite.ResetChain() // Set atomic swap in longterm storage atomicSwap := atomicSwap(suite.ctx, 1) atomicSwap.ClosedBlock = suite.ctx.BlockHeight() suite.keeper.InsertIntoLongtermStorage(suite.ctx, atomicSwap) // Longterm storage lacks getter methods, must use iteration to get count of swaps in store var swapIDs [][]byte suite.keeper.IterateAtomicSwapsLongtermStorage(suite.ctx, uint64(atomicSwap.ClosedBlock+LongtermStorageDuration), func(id []byte) bool { swapIDs = append(swapIDs, id) return false }) suite.Equal(len(swapIDs), 1) // Marshal the expected swapID cdc := suite.app.Codec() res, _ := cdc.MarshalBinaryBare(atomicSwap.GetSwapID()) expectedSwapID := res[1:] suite.Equal(expectedSwapID, swapIDs[0]) } func (suite *KeeperTestSuite) TestRemoveFromLongtermStorage() { suite.ResetChain() // Set atomic swap in longterm storage atomicSwap := atomicSwap(suite.ctx, 1) atomicSwap.ClosedBlock = suite.ctx.BlockHeight() suite.keeper.InsertIntoLongtermStorage(suite.ctx, atomicSwap) // Longterm storage lacks getter methods, must use iteration to get count of swaps in store var swapIDs [][]byte suite.keeper.IterateAtomicSwapsLongtermStorage(suite.ctx, uint64(atomicSwap.ClosedBlock+LongtermStorageDuration), func(id []byte) bool { swapIDs = append(swapIDs, id) return false }) suite.Equal(len(swapIDs), 1) suite.keeper.RemoveFromLongtermStorage(suite.ctx, atomicSwap) // Check stored data not in block index var swapIDsPost [][]byte suite.keeper.IterateAtomicSwapsLongtermStorage(suite.ctx, uint64(atomicSwap.ClosedBlock+LongtermStorageDuration), func(id []byte) bool { swapIDsPost = append(swapIDsPost, id) return false }) suite.Equal(len(swapIDsPost), 0) } func (suite *KeeperTestSuite) TestIterateAtomicSwapsLongtermStorage() { suite.ResetChain() // Set up atomic swaps with stagged closed blocks var swaps types.AtomicSwaps for i := 0; i < 8; i++ { timestamp := tmtime.Now().Unix() randomNumber, _ := types.GenerateSecureRandomNumber() randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp) atomicSwap := types.NewAtomicSwap(cs(c("bnb", 50000)), randomNumberHash, suite.ctx.BlockHeight(), timestamp, TestUser1, TestUser2, TestSenderOtherChain, TestRecipientOtherChain, 100, types.Open, true, types.Incoming) // Set closed block staggered by 100 blocks and insert into longterm storage atomicSwap.ClosedBlock = int64(i) * 100 suite.keeper.InsertIntoLongtermStorage(suite.ctx, atomicSwap) // Add to local longterm storage swaps = append(swaps, atomicSwap) } // Set up the expected swap IDs for a given cutoff block. cutoffBlock := int64(LongtermStorageDuration + 350) var expectedSwapIDs [][]byte for _, swap := range swaps { if swap.ClosedBlock+LongtermStorageDuration < cutoffBlock || swap.ClosedBlock+LongtermStorageDuration == cutoffBlock { expectedSwapIDs = append(expectedSwapIDs, swap.GetSwapID()) } } // Read the swap IDs from store for a given cutoff block var readSwapIDs [][]byte suite.keeper.IterateAtomicSwapsLongtermStorage(suite.ctx, uint64(cutoffBlock), func(id []byte) bool { readSwapIDs = append(readSwapIDs, id) return false }) // At the cutoff block, iteration should return half of the swap IDs suite.Equal(len(swaps)/2, len(expectedSwapIDs)) suite.Equal(len(swaps)/2, len(readSwapIDs)) // Should be the same IDs suite.Equal(expectedSwapIDs, readSwapIDs) } func (suite *KeeperTestSuite) TestGetSetAssetSupply() { suite.ResetChain() denom := "bnb" // Put asset supply in store assetSupply := types.NewAssetSupply(denom, c(denom, 0), c(denom, 0), c(denom, 50000), c(denom, 100000)) suite.keeper.SetAssetSupply(suite.ctx, assetSupply, []byte(denom)) // Check asset in store storedAssetSupply, found := suite.keeper.GetAssetSupply(suite.ctx, []byte(denom)) suite.True(found) suite.Equal(assetSupply, storedAssetSupply) // Check fake asset supply not in store fakeDenom := "xyz" _, found = suite.keeper.GetAssetSupply(suite.ctx, []byte(fakeDenom)) suite.False(found) } func (suite *KeeperTestSuite) TestIterateAssetSupplies() { suite.ResetChain() // Set asset supplies supplies := assetSupplies(5) for _, supply := range supplies { suite.keeper.SetAssetSupply(suite.ctx, supply, []byte(supply.Denom)) } // Read each asset supply from the store var readSupplies types.AssetSupplies suite.keeper.IterateAssetSupplies(suite.ctx, func(a types.AssetSupply) bool { readSupplies = append(readSupplies, a) return false }) // Check expected values for i := 0; i < len(supplies); i++ { suite.Contains(readSupplies, supplies[i]) } } func (suite *KeeperTestSuite) TestGetAllAssetSupplies() { suite.ResetChain() // Set asset supplies count := 3 supplies := assetSupplies(count) for _, supply := range supplies { suite.keeper.SetAssetSupply(suite.ctx, supply, []byte(supply.Denom)) } // Get all asset supplies readSupplies := suite.keeper.GetAllAssetSupplies(suite.ctx) suite.Equal(count, len(readSupplies)) // Check expected values for i := 0; i < count; i++ { suite.Contains(readSupplies, supplies[i]) } } func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) }