From 99c9793df2e82c06f614ac83cae71de7ccf3afca Mon Sep 17 00:00:00 2001 From: robertsasu Date: Fri, 29 Mar 2024 10:35:24 +0200 Subject: [PATCH 1/7] fixed unstaked list on delegation when nodes are unstaked from queue --- vm/systemSmartContracts/delegation.go | 3 +- vm/systemSmartContracts/eei.go | 4 +++ vm/systemSmartContracts/stakingWaitingList.go | 34 +++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/vm/systemSmartContracts/delegation.go b/vm/systemSmartContracts/delegation.go index ac33ba81da2..ab5c97cfce0 100644 --- a/vm/systemSmartContracts/delegation.go +++ b/vm/systemSmartContracts/delegation.go @@ -2322,7 +2322,8 @@ func (d *delegation) deleteDelegatorIfNeeded(address []byte, delegator *Delegato } func (d *delegation) unStakeAtEndOfEpoch(args *vmcommon.ContractCallInput) vmcommon.ReturnCode { - if !bytes.Equal(args.CallerAddr, d.endOfEpochAddr) { + if !bytes.Equal(args.CallerAddr, d.endOfEpochAddr) && + !bytes.Equal(args.CallerAddr, d.stakingSCAddr) { d.eei.AddReturnMessage("can be called by end of epoch address only") return vmcommon.UserError } diff --git a/vm/systemSmartContracts/eei.go b/vm/systemSmartContracts/eei.go index 55f554d11b0..3f251a6cca4 100644 --- a/vm/systemSmartContracts/eei.go +++ b/vm/systemSmartContracts/eei.go @@ -144,6 +144,8 @@ func (host *vmContext) GetStorageFromAddress(address []byte, key []byte) []byte if value, isInMap := storageAdrMap[string(key)]; isInMap { return value } + } else { + storageAdrMap = make(map[string][]byte) } data, _, err := host.blockChainHook.GetStorageData(address, key) @@ -151,6 +153,8 @@ func (host *vmContext) GetStorageFromAddress(address []byte, key []byte) []byte return nil } + storageAdrMap[string(key)] = data + return data } diff --git a/vm/systemSmartContracts/stakingWaitingList.go b/vm/systemSmartContracts/stakingWaitingList.go index e1d0ff00cb4..1ab917a9269 100644 --- a/vm/systemSmartContracts/stakingWaitingList.go +++ b/vm/systemSmartContracts/stakingWaitingList.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/hex" "fmt" + "github.com/multiversx/mx-chain-core-go/core" "math" "math/big" "strconv" @@ -824,6 +825,8 @@ func (s *stakingSC) unStakeAllNodesFromQueue(args *vmcommon.ContractCallInput) v return vmcommon.Ok } + orderedListOwners := make([]string, 0) + mapOwnerKeys := make(map[string][][]byte) for i, blsKey := range waitingListData.blsKeys { registrationData := waitingListData.stakedDataList[i] @@ -835,11 +838,42 @@ func (s *stakingSC) unStakeAllNodesFromQueue(args *vmcommon.ContractCallInput) v // delete element from waiting list inWaitingListKey := createWaitingListKey(blsKey) s.eei.SetStorage(inWaitingListKey, nil) + + ownerAddr := string(registrationData.OwnerAddress) + _, exists := mapOwnerKeys[ownerAddr] + if !exists { + mapOwnerKeys[ownerAddr] = make([][]byte, 0) + orderedListOwners = append(orderedListOwners, ownerAddr) + } + + mapOwnerKeys[ownerAddr] = append(mapOwnerKeys[ownerAddr], blsKey) } // delete waiting list head element s.eei.SetStorage([]byte(waitingListHeadKey), nil) + // call unStakeAtEndOfEpoch from the delegation contracts to compute the new unStaked list + for _, owner := range orderedListOwners { + listOfKeys := mapOwnerKeys[owner] + + if s.eei.BlockChainHook().GetShardOfAddress([]byte(owner)) != core.MetachainShardId { + continue + } + + unStakeCall := "unStakeAtEndOfEpoch" + for _, key := range listOfKeys { + unStakeCall += "@" + hex.EncodeToString(key) + } + vmOutput, err := s.eei.ExecuteOnDestContext([]byte(owner), args.RecipientAddr, big.NewInt(0), []byte(unStakeCall)) + if err != nil { + s.eei.AddReturnMessage(err.Error()) + return vmcommon.UserError + } + if vmOutput.ReturnCode != vmcommon.Ok { + return vmOutput.ReturnCode + } + } + return vmcommon.Ok } From 60782049181eb301a5ba08a8db8383f58e8ac8c9 Mon Sep 17 00:00:00 2001 From: robertsasu Date: Fri, 29 Mar 2024 11:59:51 +0200 Subject: [PATCH 2/7] fixed unstaked list on delegation when nodes are unstaked from queue --- vm/systemSmartContracts/stakingWaitingList.go | 27 +++-- vm/systemSmartContracts/staking_test.go | 104 ++++++++++++++++++ 2 files changed, 122 insertions(+), 9 deletions(-) diff --git a/vm/systemSmartContracts/stakingWaitingList.go b/vm/systemSmartContracts/stakingWaitingList.go index 1ab917a9269..e08b16b3cde 100644 --- a/vm/systemSmartContracts/stakingWaitingList.go +++ b/vm/systemSmartContracts/stakingWaitingList.go @@ -4,11 +4,11 @@ import ( "bytes" "encoding/hex" "fmt" - "github.com/multiversx/mx-chain-core-go/core" "math" "math/big" "strconv" + "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/vm" vmcommon "github.com/multiversx/mx-chain-vm-common-go" @@ -829,7 +829,6 @@ func (s *stakingSC) unStakeAllNodesFromQueue(args *vmcommon.ContractCallInput) v mapOwnerKeys := make(map[string][][]byte) for i, blsKey := range waitingListData.blsKeys { registrationData := waitingListData.stakedDataList[i] - result := s.doUnStake(blsKey, registrationData) if result != vmcommon.Ok { return result @@ -864,19 +863,29 @@ func (s *stakingSC) unStakeAllNodesFromQueue(args *vmcommon.ContractCallInput) v for _, key := range listOfKeys { unStakeCall += "@" + hex.EncodeToString(key) } - vmOutput, err := s.eei.ExecuteOnDestContext([]byte(owner), args.RecipientAddr, big.NewInt(0), []byte(unStakeCall)) - if err != nil { - s.eei.AddReturnMessage(err.Error()) - return vmcommon.UserError - } - if vmOutput.ReturnCode != vmcommon.Ok { - return vmOutput.ReturnCode + returnCode := s.executeOnStakeAtEndOfEpoch([]byte(owner), listOfKeys, args.RecipientAddr) + if returnCode != vmcommon.Ok { + return returnCode } } return vmcommon.Ok } +func (s *stakingSC) executeOnStakeAtEndOfEpoch(destinationAddress []byte, listOfKeys [][]byte, senderAddress []byte) vmcommon.ReturnCode { + unStakeCall := "unStakeAtEndOfEpoch" + for _, key := range listOfKeys { + unStakeCall += "@" + hex.EncodeToString(key) + } + vmOutput, err := s.eei.ExecuteOnDestContext(destinationAddress, senderAddress, big.NewInt(0), []byte(unStakeCall)) + if err != nil { + s.eei.AddReturnMessage(err.Error()) + return vmcommon.UserError + } + + return vmOutput.ReturnCode +} + func (s *stakingSC) cleanAdditionalQueue(args *vmcommon.ContractCallInput) vmcommon.ReturnCode { if !s.enableEpochsHandler.IsFlagEnabled(common.CorrectLastUnJailedFlag) { s.eei.AddReturnMessage("invalid method to call") diff --git a/vm/systemSmartContracts/staking_test.go b/vm/systemSmartContracts/staking_test.go index 53d78208cf1..68bc5c0b7f8 100644 --- a/vm/systemSmartContracts/staking_test.go +++ b/vm/systemSmartContracts/staking_test.go @@ -3706,3 +3706,107 @@ func TestStakingSc_UnStakeAllFromQueue(t *testing.T) { doGetStatus(t, stakingSmartContract, eei, []byte("thirdKey "), "staked") doGetStatus(t, stakingSmartContract, eei, []byte("fourthKey"), "staked") } + +func TestStakingSc_UnStakeAllFromQueueWithDelegationContracts(t *testing.T) { + t.Parallel() + + blockChainHook := &mock.BlockChainHookStub{} + blockChainHook.GetStorageDataCalled = func(accountsAddress []byte, index []byte) ([]byte, uint32, error) { + return nil, 0, nil + } + blockChainHook.GetShardOfAddressCalled = func(address []byte) uint32 { + return core.MetachainShardId + } + + eei := createDefaultEei() + eei.blockChainHook = blockChainHook + eei.SetSCAddress([]byte("addr")) + + delegationSC, _ := createDelegationContractAndEEI() + delegationSC.eei = eei + + systemSCContainerStub := &mock.SystemSCContainerStub{GetCalled: func(key []byte) (vm.SystemSmartContract, error) { + return delegationSC, nil + }} + _ = eei.SetSystemSCContainer(systemSCContainerStub) + + stakingAccessAddress := vm.ValidatorSCAddress + args := createMockStakingScArguments() + args.StakingAccessAddr = stakingAccessAddress + args.StakingSCConfig.MaxNumberOfNodesForStake = 1 + enableEpochsHandler, _ := args.EnableEpochsHandler.(*enableEpochsHandlerMock.EnableEpochsHandlerStub) + args.Eei = eei + args.StakingSCConfig.UnBondPeriod = 100 + stakingSmartContract, _ := NewStakingSmartContract(args) + + stakerAddress := []byte("stakerAddr") + + blockChainHook.CurrentNonceCalled = func() uint64 { + return 1 + } + + enableEpochsHandler.AddActiveFlags(common.StakingV2Flag) + enableEpochsHandler.AddActiveFlags(common.StakeFlag) + + // do stake should work + doStake(t, stakingSmartContract, stakingAccessAddress, stakerAddress, []byte("firstKey ")) + doStake(t, stakingSmartContract, stakingAccessAddress, stakerAddress, []byte("secondKey")) + doStake(t, stakingSmartContract, stakingAccessAddress, stakerAddress, []byte("thirdKey ")) + doStake(t, stakingSmartContract, stakingAccessAddress, stakerAddress, []byte("fourthKey")) + + waitingReturn := doGetWaitingListRegisterNonceAndRewardAddress(t, stakingSmartContract, eei) + assert.Equal(t, len(waitingReturn), 9) + + dStatus := &DelegationContractStatus{ + StakedKeys: make([]*NodesData, 4), + NotStakedKeys: nil, + UnStakedKeys: nil, + NumUsers: 0, + } + dStatus.StakedKeys[0] = &NodesData{BLSKey: []byte("firstKey ")} + dStatus.StakedKeys[1] = &NodesData{BLSKey: []byte("secondKey")} + dStatus.StakedKeys[2] = &NodesData{BLSKey: []byte("thirdKey ")} + dStatus.StakedKeys[3] = &NodesData{BLSKey: []byte("fourthKey")} + + marshaledData, _ := delegationSC.marshalizer.Marshal(dStatus) + eei.SetStorageForAddress(stakerAddress, []byte(delegationStatusKey), marshaledData) + + arguments := CreateVmContractCallInput() + arguments.RecipientAddr = vm.StakingSCAddress + validatorData := &ValidatorDataV2{ + TotalStakeValue: big.NewInt(400), + TotalUnstaked: big.NewInt(0), + RewardAddress: stakerAddress, + BlsPubKeys: [][]byte{[]byte("firstKey "), []byte("secondKey"), []byte("thirdKey "), []byte("fourthKey")}, + } + arguments.CallerAddr = stakingSmartContract.endOfEpochAccessAddr + marshaledData, _ = stakingSmartContract.marshalizer.Marshal(validatorData) + eei.SetStorageForAddress(vm.ValidatorSCAddress, stakerAddress, marshaledData) + + enableEpochsHandler.AddActiveFlags(common.StakingV4Step1Flag) + enableEpochsHandler.AddActiveFlags(common.StakingV4StartedFlag) + + arguments.Function = "unStakeAllNodesFromQueue" + retCode := stakingSmartContract.Execute(arguments) + fmt.Println(eei.returnMessage) + assert.Equal(t, retCode, vmcommon.Ok) + + assert.Equal(t, len(eei.GetStorage([]byte(waitingListHeadKey))), 0) + newHead, _ := stakingSmartContract.getWaitingListHead() + assert.Equal(t, uint32(0), newHead.Length) // no entries in the queue list + + marshaledData = eei.GetStorageFromAddress(stakerAddress, []byte(delegationStatusKey)) + _ = stakingSmartContract.marshalizer.Unmarshal(dStatus, marshaledData) + assert.Equal(t, len(dStatus.UnStakedKeys), 3) + assert.Equal(t, len(dStatus.StakedKeys), 1) + + doGetStatus(t, stakingSmartContract, eei, []byte("secondKey"), "unStaked") + + // stake them again - as they were deleted from waiting list + doStake(t, stakingSmartContract, stakingAccessAddress, stakerAddress, []byte("thirdKey ")) + doStake(t, stakingSmartContract, stakingAccessAddress, stakerAddress, []byte("fourthKey")) + + // surprisingly, the queue works again as we did not activate the staking v4 + doGetStatus(t, stakingSmartContract, eei, []byte("thirdKey "), "staked") + doGetStatus(t, stakingSmartContract, eei, []byte("fourthKey"), "staked") +} From 1e79ea7f4614cae0a0dfefdf3b4d2c1821f6cb6a Mon Sep 17 00:00:00 2001 From: miiu Date: Fri, 29 Mar 2024 14:19:16 +0200 Subject: [PATCH 3/7] staking provider with node scenario --- .../stakingProviderWithNodesinQueue_test.go | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go diff --git a/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go b/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go new file mode 100644 index 00000000000..6bf887840c1 --- /dev/null +++ b/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go @@ -0,0 +1,130 @@ +package staking + +import ( + "encoding/hex" + "fmt" + "github.com/multiversx/mx-chain-core-go/core" + "github.com/multiversx/mx-chain-core-go/data/transaction" + "github.com/multiversx/mx-chain-go/config" + "github.com/multiversx/mx-chain-go/node/chainSimulator" + "github.com/multiversx/mx-chain-go/node/chainSimulator/components/api" + "github.com/multiversx/mx-chain-go/node/chainSimulator/configs" + "github.com/multiversx/mx-chain-go/vm" + "github.com/stretchr/testify/require" + "math/big" + "testing" + "time" +) + +func TestStakingProviderWithNodes(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + stakingV4ActivationEpoch := uint32(2) + + t.Run("staking ph 4 step 1 active", func(t *testing.T) { + testStakingProviderWithNodesReStakeUnStaked(t, stakingV4ActivationEpoch) + }) + + t.Run("staking ph 4 step 2 active", func(t *testing.T) { + testStakingProviderWithNodesReStakeUnStaked(t, stakingV4ActivationEpoch+1) + }) + + t.Run("staking ph 4 step 3 active", func(t *testing.T) { + testStakingProviderWithNodesReStakeUnStaked(t, stakingV4ActivationEpoch+2) + }) +} + +func testStakingProviderWithNodesReStakeUnStaked(t *testing.T, stakingV4ActivationEpoch uint32) { + roundDurationInMillis := uint64(6000) + roundsPerEpoch := core.OptionalUint64{ + HasValue: true, + Value: 20, + } + + cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ + BypassTxSignatureCheck: false, + TempDir: t.TempDir(), + PathToInitialConfig: defaultPathToInitialConfig, + NumOfShards: 3, + GenesisTimestamp: time.Now().Unix(), + RoundDurationInMillis: roundDurationInMillis, + RoundsPerEpoch: roundsPerEpoch, + ApiInterface: api.NewNoApiInterface(), + MinNodesPerShard: 3, + MetaChainMinNodes: 3, + NumNodesWaitingListMeta: 3, + NumNodesWaitingListShard: 3, + AlterConfigsFunction: func(cfg *config.Configs) { + configs.SetStakingV4ActivationEpochs(cfg, stakingV4ActivationEpoch) + }, + }) + require.Nil(t, err) + require.NotNil(t, cs) + defer cs.Close() + + mintValue := big.NewInt(0).Mul(big.NewInt(5000), oneEGLD) + validatorOwner, err := cs.GenerateAndMintWalletAddress(0, mintValue) + require.Nil(t, err) + require.Nil(t, err) + + err = cs.GenerateBlocksUntilEpochIsReached(1) + require.Nil(t, err) + + // create delegation contract + stakeValue, _ := big.NewInt(0).SetString("4250000000000000000000", 10) + dataField := "createNewDelegationContract@00@0ea1" + txStake := generateTransaction(validatorOwner.Bytes, getNonce(t, cs, validatorOwner), vm.DelegationManagerSCAddress, stakeValue, dataField, 80_000_000) + stakeTx, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(txStake, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, stakeTx) + + delegationAddress := stakeTx.Logs.Events[2].Address + delegationAddressBytes, _ := cs.GetNodeHandler(0).GetCoreComponents().AddressPubKeyConverter().Decode(delegationAddress) + + // add nodes in queue + _, blsKeys, err := chainSimulator.GenerateBlsPrivateKeys(1) + require.Nil(t, err) + + txDataFieldAddNodes := fmt.Sprintf("addNodes@%s@%s", blsKeys[0], mockBLSSignature+"02") + ownerNonce := getNonce(t, cs, validatorOwner) + txAddNodes := generateTransaction(validatorOwner.Bytes, ownerNonce, delegationAddressBytes, big.NewInt(0), txDataFieldAddNodes, gasLimitForStakeOperation) + addNodesTx, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(txAddNodes, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, addNodesTx) + + txDataFieldStakeNodes := fmt.Sprintf("stakeNodes@%s", blsKeys[0]) + ownerNonce = getNonce(t, cs, validatorOwner) + txStakeNodes := generateTransaction(validatorOwner.Bytes, ownerNonce, delegationAddressBytes, big.NewInt(0), txDataFieldStakeNodes, gasLimitForStakeOperation) + + stakeNodesTxs, err := cs.SendTxsAndGenerateBlocksTilAreExecuted([]*transaction.Transaction{txStakeNodes}, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.Equal(t, 1, len(stakeNodesTxs)) + + metachainNode := cs.GetNodeHandler(core.MetachainShardId) + decodedBLSKey0, _ := hex.DecodeString(blsKeys[0]) + status := getBLSKeyStatus(t, metachainNode, decodedBLSKey0) + require.Equal(t, "queued", status) + + // activate staking v4 + err = cs.GenerateBlocksUntilEpochIsReached(int32(stakingV4ActivationEpoch)) + require.Nil(t, err) + + status = getBLSKeyStatus(t, metachainNode, decodedBLSKey0) + require.Equal(t, "unStaked", status) + + ownerNonce = getNonce(t, cs, validatorOwner) + reStakeTxData := fmt.Sprintf("reStakeUnStakedNodes@%s", blsKeys[0]) + reStakeNodes := generateTransaction(validatorOwner.Bytes, ownerNonce, delegationAddressBytes, big.NewInt(0), reStakeTxData, gasLimitForStakeOperation) + reStakeTx, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(reStakeNodes, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, reStakeTx) + + status = getBLSKeyStatus(t, metachainNode, decodedBLSKey0) + require.Equal(t, "staked", status) + + err = cs.GenerateBlocks(20) + + checkValidatorStatus(t, cs, blsKeys[0], "auction") +} From bb090cebe542f89d152764b7709f30a358d41456 Mon Sep 17 00:00:00 2001 From: miiu Date: Fri, 29 Mar 2024 14:21:20 +0200 Subject: [PATCH 4/7] fix linter --- .../staking/stakingProviderWithNodesinQueue_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go b/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go index 6bf887840c1..db417bbee1f 100644 --- a/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go +++ b/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go @@ -125,6 +125,7 @@ func testStakingProviderWithNodesReStakeUnStaked(t *testing.T, stakingV4Activati require.Equal(t, "staked", status) err = cs.GenerateBlocks(20) + require.Nil(t, err) checkValidatorStatus(t, cs, blsKeys[0], "auction") } From 1f2fae1e7239aed9d6a392db483124724623e669 Mon Sep 17 00:00:00 2001 From: miiu Date: Fri, 29 Mar 2024 14:37:58 +0200 Subject: [PATCH 5/7] fixes after review --- .../staking/stakingProviderWithNodesinQueue_test.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go b/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go index db417bbee1f..57377c47bd6 100644 --- a/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go +++ b/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go @@ -3,6 +3,10 @@ package staking import ( "encoding/hex" "fmt" + "math/big" + "testing" + "time" + "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/data/transaction" "github.com/multiversx/mx-chain-go/config" @@ -11,9 +15,6 @@ import ( "github.com/multiversx/mx-chain-go/node/chainSimulator/configs" "github.com/multiversx/mx-chain-go/vm" "github.com/stretchr/testify/require" - "math/big" - "testing" - "time" ) func TestStakingProviderWithNodes(t *testing.T) { @@ -124,6 +125,10 @@ func testStakingProviderWithNodesReStakeUnStaked(t *testing.T, stakingV4Activati status = getBLSKeyStatus(t, metachainNode, decodedBLSKey0) require.Equal(t, "staked", status) + result := getAllNodeStates(t, metachainNode, delegationAddressBytes) + require.NotNil(t, result) + require.Equal(t, "staked", result[blsKeys[0]]) + err = cs.GenerateBlocks(20) require.Nil(t, err) From 028f6a379467d28fb0f79870fe8cb93b111f1386 Mon Sep 17 00:00:00 2001 From: miiu Date: Fri, 29 Mar 2024 14:41:15 +0200 Subject: [PATCH 6/7] extra check --- .../staking/stakingProviderWithNodesinQueue_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go b/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go index 57377c47bd6..af50d56c821 100644 --- a/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go +++ b/integrationTests/chainSimulator/staking/stakingProviderWithNodesinQueue_test.go @@ -115,6 +115,10 @@ func testStakingProviderWithNodesReStakeUnStaked(t *testing.T, stakingV4Activati status = getBLSKeyStatus(t, metachainNode, decodedBLSKey0) require.Equal(t, "unStaked", status) + result := getAllNodeStates(t, metachainNode, delegationAddressBytes) + require.NotNil(t, result) + require.Equal(t, "unStaked", result[blsKeys[0]]) + ownerNonce = getNonce(t, cs, validatorOwner) reStakeTxData := fmt.Sprintf("reStakeUnStakedNodes@%s", blsKeys[0]) reStakeNodes := generateTransaction(validatorOwner.Bytes, ownerNonce, delegationAddressBytes, big.NewInt(0), reStakeTxData, gasLimitForStakeOperation) @@ -125,7 +129,7 @@ func testStakingProviderWithNodesReStakeUnStaked(t *testing.T, stakingV4Activati status = getBLSKeyStatus(t, metachainNode, decodedBLSKey0) require.Equal(t, "staked", status) - result := getAllNodeStates(t, metachainNode, delegationAddressBytes) + result = getAllNodeStates(t, metachainNode, delegationAddressBytes) require.NotNil(t, result) require.Equal(t, "staked", result[blsKeys[0]]) From c227dd5091341af24887b610a4b4eefcdeaed878 Mon Sep 17 00:00:00 2001 From: miiu Date: Tue, 2 Apr 2024 12:13:50 +0300 Subject: [PATCH 7/7] extend unit test and fixes --- vm/systemSmartContracts/staking_test.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/vm/systemSmartContracts/staking_test.go b/vm/systemSmartContracts/staking_test.go index 68bc5c0b7f8..fb92a574945 100644 --- a/vm/systemSmartContracts/staking_test.go +++ b/vm/systemSmartContracts/staking_test.go @@ -3755,7 +3755,7 @@ func TestStakingSc_UnStakeAllFromQueueWithDelegationContracts(t *testing.T) { doStake(t, stakingSmartContract, stakingAccessAddress, stakerAddress, []byte("fourthKey")) waitingReturn := doGetWaitingListRegisterNonceAndRewardAddress(t, stakingSmartContract, eei) - assert.Equal(t, len(waitingReturn), 9) + requireSliceContains(t, waitingReturn, [][]byte{[]byte("secondKey"), []byte("thirdKey "), []byte("fourthKey")}) dStatus := &DelegationContractStatus{ StakedKeys: make([]*NodesData, 4), @@ -3801,12 +3801,19 @@ func TestStakingSc_UnStakeAllFromQueueWithDelegationContracts(t *testing.T) { assert.Equal(t, len(dStatus.StakedKeys), 1) doGetStatus(t, stakingSmartContract, eei, []byte("secondKey"), "unStaked") + doGetStatus(t, stakingSmartContract, eei, []byte("thirdKey "), "unStaked") + doGetStatus(t, stakingSmartContract, eei, []byte("fourthKey"), "unStaked") // stake them again - as they were deleted from waiting list doStake(t, stakingSmartContract, stakingAccessAddress, stakerAddress, []byte("thirdKey ")) doStake(t, stakingSmartContract, stakingAccessAddress, stakerAddress, []byte("fourthKey")) - // surprisingly, the queue works again as we did not activate the staking v4 doGetStatus(t, stakingSmartContract, eei, []byte("thirdKey "), "staked") doGetStatus(t, stakingSmartContract, eei, []byte("fourthKey"), "staked") } + +func requireSliceContains(t *testing.T, s1, s2 [][]byte) { + for _, elemInS2 := range s2 { + require.Contains(t, s1, elemInS2) + } +}