From dfd4004da922d7dd99b11bb9b643f1b222979459 Mon Sep 17 00:00:00 2001 From: robertsasu Date: Mon, 22 Jan 2024 11:04:39 +0200 Subject: [PATCH 01/10] do not activate more nodes on stake if too many nodes --- vm/systemSmartContracts/validator.go | 19 ++++++++----------- vm/systemSmartContracts/validator_test.go | 5 +---- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/vm/systemSmartContracts/validator.go b/vm/systemSmartContracts/validator.go index 509ec89b624..1adc60976d2 100644 --- a/vm/systemSmartContracts/validator.go +++ b/vm/systemSmartContracts/validator.go @@ -1064,17 +1064,14 @@ func (v *validatorSC) stake(args *vmcommon.ContractCallInput) vmcommon.ReturnCod } } - v.activateStakingFor( - blsKeys, - registrationData, - validatorConfig.NodePrice, - registrationData.RewardAddress, - args.CallerAddr, - ) - - if v.isNumberOfNodesTooHigh(registrationData) { - v.eei.AddReturnMessage("number of nodes is too high") - return vmcommon.UserError + if !v.isNumberOfNodesTooHigh(registrationData) { + v.activateStakingFor( + blsKeys, + registrationData, + validatorConfig.NodePrice, + registrationData.RewardAddress, + args.CallerAddr, + ) } err = v.saveRegistrationData(args.CallerAddr, registrationData) diff --git a/vm/systemSmartContracts/validator_test.go b/vm/systemSmartContracts/validator_test.go index 12d66464625..d2504cde21c 100644 --- a/vm/systemSmartContracts/validator_test.go +++ b/vm/systemSmartContracts/validator_test.go @@ -460,9 +460,6 @@ func TestStakingValidatorSC_ExecuteStakeTooManyNodes(t *testing.T) { } return nil } - eei.AddReturnMessageCalled = func(msg string) { - assert.Equal(t, msg, "number of nodes is too high") - } key1 := []byte("Key1") key2 := []byte("Key2") @@ -472,7 +469,7 @@ func TestStakingValidatorSC_ExecuteStakeTooManyNodes(t *testing.T) { arguments.Arguments = [][]byte{big.NewInt(3).Bytes(), key1, []byte("msg1"), key2, []byte("msg2"), key3, []byte("msg3")} errCode := stakingValidatorSc.Execute(arguments) - assert.Equal(t, vmcommon.UserError, errCode) + assert.Equal(t, vmcommon.Ok, errCode) } func TestStakingValidatorSC_ExecuteStakeAddedNewPubKeysShouldWork(t *testing.T) { From 94244afbca4db253cc76d17d5f9202fc79975084 Mon Sep 17 00:00:00 2001 From: robertsasu Date: Tue, 23 Jan 2024 10:27:17 +0200 Subject: [PATCH 02/10] do not activate more nodes on stake if too many nodes --- vm/systemSmartContracts/delegation.go | 19 +++++++++++++++++++ vm/systemSmartContracts/validator.go | 8 ++++++++ 2 files changed, 27 insertions(+) diff --git a/vm/systemSmartContracts/delegation.go b/vm/systemSmartContracts/delegation.go index c65afdf6942..e457e9157f2 100644 --- a/vm/systemSmartContracts/delegation.go +++ b/vm/systemSmartContracts/delegation.go @@ -1215,6 +1215,12 @@ func (d *delegation) stakeNodes(args *vmcommon.ContractCallInput) vmcommon.Retur return vmOutput.ReturnCode } + allLogs := d.eei.GetLogs() + if tooManyNodesLogs(allLogs) { + d.eei.AddReturnMessage(numberOfNodesTooHigh) + return vmcommon.UserError + } + err = d.updateDelegationStatusAfterStake(status, vmOutput.ReturnData, args.Arguments) if err != nil { d.eei.AddReturnMessage(err.Error()) @@ -1226,6 +1232,19 @@ func (d *delegation) stakeNodes(args *vmcommon.ContractCallInput) vmcommon.Retur return vmcommon.Ok } +func tooManyNodesLogs(logEntries []*vmcommon.LogEntry) bool { + for _, logEntry := range logEntries { + if len(logEntry.Topics) > 1 { + continue + } + if !bytes.Equal(logEntry.Topics[0], []byte(numberOfNodesTooHigh)) { + return true + } + } + + return false +} + func (d *delegation) updateDelegationStatusAfterStake( status *DelegationContractStatus, returnData [][]byte, diff --git a/vm/systemSmartContracts/validator.go b/vm/systemSmartContracts/validator.go index 1adc60976d2..081a1e848f7 100644 --- a/vm/systemSmartContracts/validator.go +++ b/vm/systemSmartContracts/validator.go @@ -22,6 +22,7 @@ import ( const unJailedFunds = "unJailFunds" const unStakeUnBondPauseKey = "unStakeUnBondPause" const minPercentage = 0.0001 +const numberOfNodesTooHigh = "number of nodes too high, no new nodes activated" var zero = big.NewInt(0) @@ -1072,6 +1073,13 @@ func (v *validatorSC) stake(args *vmcommon.ContractCallInput) vmcommon.ReturnCod registrationData.RewardAddress, args.CallerAddr, ) + } else { + entry := &vmcommon.LogEntry{ + Identifier: []byte(args.Function), + Address: args.RecipientAddr, + Topics: [][]byte{[]byte(numberOfNodesTooHigh)}, + } + v.eei.AddLogEntry(entry) } err = v.saveRegistrationData(args.CallerAddr, registrationData) From 4f408b0a00f51b0dd729061a01280b0b66ec3516 Mon Sep 17 00:00:00 2001 From: robertsasu Date: Tue, 23 Jan 2024 10:50:49 +0200 Subject: [PATCH 03/10] fixes after review --- vm/systemSmartContracts/delegation.go | 2 +- vm/systemSmartContracts/validator_test.go | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/vm/systemSmartContracts/delegation.go b/vm/systemSmartContracts/delegation.go index e457e9157f2..e1304eca90d 100644 --- a/vm/systemSmartContracts/delegation.go +++ b/vm/systemSmartContracts/delegation.go @@ -1234,7 +1234,7 @@ func (d *delegation) stakeNodes(args *vmcommon.ContractCallInput) vmcommon.Retur func tooManyNodesLogs(logEntries []*vmcommon.LogEntry) bool { for _, logEntry := range logEntries { - if len(logEntry.Topics) > 1 { + if len(logEntry.Topics) != 1 { continue } if !bytes.Equal(logEntry.Topics[0], []byte(numberOfNodesTooHigh)) { diff --git a/vm/systemSmartContracts/validator_test.go b/vm/systemSmartContracts/validator_test.go index d2504cde21c..3cb475eb9e2 100644 --- a/vm/systemSmartContracts/validator_test.go +++ b/vm/systemSmartContracts/validator_test.go @@ -460,6 +460,11 @@ func TestStakingValidatorSC_ExecuteStakeTooManyNodes(t *testing.T) { } return nil } + called := false + eei.AddLogEntryCalled = func(entry *vmcommon.LogEntry) { + called = true + assert.Equal(t, entry.Topics[0], []byte(numberOfNodesTooHigh)) + } key1 := []byte("Key1") key2 := []byte("Key2") @@ -470,6 +475,7 @@ func TestStakingValidatorSC_ExecuteStakeTooManyNodes(t *testing.T) { errCode := stakingValidatorSc.Execute(arguments) assert.Equal(t, vmcommon.Ok, errCode) + assert.True(t, called) } func TestStakingValidatorSC_ExecuteStakeAddedNewPubKeysShouldWork(t *testing.T) { From a22a39bf5da9a13de388a75f00b31346449825ac Mon Sep 17 00:00:00 2001 From: MariusC Date: Tue, 30 Jan 2024 11:37:56 +0200 Subject: [PATCH 04/10] FEAT: Ugly delegation test with addNodes and stakeNodes within and above node limits --- vm/systemSmartContracts/delegation.go | 2 +- vm/systemSmartContracts/delegation_test.go | 147 ++++++++++++++++++++- 2 files changed, 145 insertions(+), 4 deletions(-) diff --git a/vm/systemSmartContracts/delegation.go b/vm/systemSmartContracts/delegation.go index e1304eca90d..cb882fccb1a 100644 --- a/vm/systemSmartContracts/delegation.go +++ b/vm/systemSmartContracts/delegation.go @@ -1237,7 +1237,7 @@ func tooManyNodesLogs(logEntries []*vmcommon.LogEntry) bool { if len(logEntry.Topics) != 1 { continue } - if !bytes.Equal(logEntry.Topics[0], []byte(numberOfNodesTooHigh)) { + if bytes.Equal(logEntry.Topics[0], []byte(numberOfNodesTooHigh)) { return true } } diff --git a/vm/systemSmartContracts/delegation_test.go b/vm/systemSmartContracts/delegation_test.go index c26f1ff516b..a934548d941 100644 --- a/vm/systemSmartContracts/delegation_test.go +++ b/vm/systemSmartContracts/delegation_test.go @@ -16,6 +16,7 @@ import ( "github.com/multiversx/mx-chain-go/config" "github.com/multiversx/mx-chain-go/process/smartContract/hooks" "github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock" + "github.com/multiversx/mx-chain-go/testscommon/shardingMocks" stateMock "github.com/multiversx/mx-chain-go/testscommon/state" "github.com/multiversx/mx-chain-go/vm" "github.com/multiversx/mx-chain-go/vm/mock" @@ -59,7 +60,7 @@ func createMockArgumentsForDelegation() ArgsNewDelegation { } } -func addValidatorAndStakingScToVmContext(eei *vmContext) { +func addValidatorAndStakingScToVmContext(eei *vmContext, blsKeys ...[]byte) { validatorArgs := createMockArgumentsForValidatorSC() validatorArgs.Eei = eei validatorArgs.StakingSCConfig.GenesisNodePrice = "100" @@ -78,13 +79,14 @@ func addValidatorAndStakingScToVmContext(eei *vmContext) { return stakingSc, nil } + blsPubKeys := getInputBlsKeysOrDefaultIfEmpty(blsKeys...) if bytes.Equal(key, vm.ValidatorSCAddress) { enableEpochsHandler.AddActiveFlags(common.StakingV2Flag) _ = validatorSc.saveRegistrationData([]byte("addr"), &ValidatorDataV2{ RewardAddress: []byte("rewardAddr"), TotalStakeValue: big.NewInt(1000), LockedStake: big.NewInt(500), - BlsPubKeys: [][]byte{[]byte("blsKey1"), []byte("blsKey2")}, + BlsPubKeys: blsPubKeys, TotalUnstaked: big.NewInt(150), UnstakedInfo: []*UnstakedValue{ { @@ -96,7 +98,7 @@ func addValidatorAndStakingScToVmContext(eei *vmContext) { UnstakedValue: big.NewInt(80), }, }, - NumRegistered: 2, + NumRegistered: uint32(len(blsKeys)), }) validatorSc.unBondPeriod = 50 return validatorSc, nil @@ -106,6 +108,19 @@ func addValidatorAndStakingScToVmContext(eei *vmContext) { }}) } +func getInputBlsKeysOrDefaultIfEmpty(blsKeys ...[]byte) [][]byte { + ret := make([][]byte, 0) + for _, blsKey := range blsKeys { + ret = append(ret, blsKey) + } + + if len(ret) == 0 { + return [][]byte{[]byte("blsKey1"), []byte("blsKey2")} + } + + return ret +} + func getDefaultVmInputForFunc(funcName string, args [][]byte) *vmcommon.ContractCallInput { return &vmcommon.ContractCallInput{ VMInput: vmcommon.VMInput{ @@ -5043,3 +5058,129 @@ func TestDelegationSystemSC_SynchronizeOwner(t *testing.T) { eei.ResetReturnMessage() }) } + +func TestDelegationSystemSC_ExecuteAddNodesStakedInStakingV4(t *testing.T) { + t.Parallel() + + sig := []byte("sig1") + args := createMockArgumentsForDelegation() + args.EnableEpochsHandler = enableEpochsHandlerMock.NewEnableEpochsHandlerStub( + common.StakingV4Step1Flag, + common.StakingV4Step2Flag, + common.StakingV4Step3Flag, + + common.DelegationSmartContractFlag, + common.StakingV2FlagAfterEpoch, + common.AddTokensToDelegationFlag, + common.DeleteDelegatorAfterClaimRewardsFlag, + common.ComputeRewardCheckpointFlag, + common.ValidatorToDelegationFlag, + common.ReDelegateBelowMinCheckFlag, + common.MultiClaimOnDelegationFlag, + ) + eei := createDefaultEei() + delegationsMap := map[string][]byte{} + delegationsMap[ownerKey] = []byte("owner") + eei.storageUpdate[string(eei.scAddress)] = delegationsMap + args.Eei = eei + + d, _ := NewDelegationSystemSC(args) + key1 := &NodesData{ + BLSKey: []byte("blsKey1"), + } + key2 := &NodesData{ + BLSKey: []byte("blsKey2"), + } + dStatus := &DelegationContractStatus{ + StakedKeys: []*NodesData{key1, key2}, + } + _ = d.saveDelegationStatus(dStatus) + + globalFund := &GlobalFundData{ + TotalActive: big.NewInt(400), + } + _ = d.saveGlobalFundData(globalFund) + addValidatorAndStakingScToVmContext2(eei, [][]byte{[]byte("blsKey1"), []byte("blsKey2")}) + dStatus, _ = d.getDelegationStatus() + require.Equal(t, 2, len(dStatus.StakedKeys)) + require.Equal(t, 0, len(dStatus.UnStakedKeys)) + require.Equal(t, 0, len(dStatus.NotStakedKeys)) + + newBlsKey := []byte("newBlsKey") + vmInput := getDefaultVmInputForFunc("addNodes", [][]byte{newBlsKey, sig}) + output := d.Execute(vmInput) + require.Equal(t, vmcommon.Ok, output) + + vmInput = getDefaultVmInputForFunc("stakeNodes", [][]byte{newBlsKey}) + output = d.Execute(vmInput) + require.Equal(t, vmcommon.Ok, output) + + dStatus, _ = d.getDelegationStatus() + require.Equal(t, 3, len(dStatus.StakedKeys)) + require.Equal(t, 0, len(dStatus.UnStakedKeys)) + require.Equal(t, 0, len(dStatus.NotStakedKeys)) + + addValidatorAndStakingScToVmContext2(eei, [][]byte{[]byte("blsKey1"), []byte("blsKey2"), newBlsKey}) + + newBlsKey2 := []byte("newBlsKey2") + vmInput = getDefaultVmInputForFunc("addNodes", [][]byte{newBlsKey2, sig}) + output = d.Execute(vmInput) + require.Equal(t, vmcommon.Ok, output) + + vmInput = getDefaultVmInputForFunc("stakeNodes", [][]byte{newBlsKey2}) + output = d.Execute(vmInput) + require.Equal(t, vmcommon.UserError, output) + require.True(t, strings.Contains(eei.returnMessage, numberOfNodesTooHigh)) + + dStatus, _ = d.getDelegationStatus() + require.Equal(t, 3, len(dStatus.StakedKeys)) + require.Equal(t, 0, len(dStatus.UnStakedKeys)) + require.Equal(t, 1, len(dStatus.NotStakedKeys)) +} + +func addValidatorAndStakingScToVmContext2(eei *vmContext, blsKeys [][]byte) { + validatorArgs := createMockArgumentsForValidatorSC() + validatorArgs.StakingSCConfig.NodeLimitPercentage = 1 + validatorArgs.Eei = eei + validatorArgs.StakingSCConfig.GenesisNodePrice = "100" + validatorArgs.StakingSCAddress = vm.StakingSCAddress + validatorArgs.NodesCoordinator = &shardingMocks.NodesCoordinatorStub{GetNumTotalEligibleCalled: func() uint64 { + return 3 + }} + validatorSc, _ := NewValidatorSmartContract(validatorArgs) + + stakingArgs := createMockStakingScArguments() + stakingArgs.Eei = eei + stakingSc, _ := NewStakingSmartContract(stakingArgs) + + _ = eei.SetSystemSCContainer(&mock.SystemSCContainerStub{GetCalled: func(key []byte) (contract vm.SystemSmartContract, err error) { + if bytes.Equal(key, vm.StakingSCAddress) { + return stakingSc, nil + } + + if bytes.Equal(key, vm.ValidatorSCAddress) { + _ = validatorSc.saveRegistrationData([]byte("addr"), &ValidatorDataV2{ + RewardAddress: []byte("rewardAddr"), + TotalStakeValue: big.NewInt(1000), + LockedStake: big.NewInt(500), + BlsPubKeys: blsKeys, + TotalUnstaked: big.NewInt(150), + UnstakedInfo: []*UnstakedValue{ + { + UnstakedEpoch: 10, + UnstakedValue: big.NewInt(60), + }, + { + UnstakedEpoch: 50, + UnstakedValue: big.NewInt(80), + }, + }, + NumRegistered: uint32(len(blsKeys)), + }) + validatorSc.unBondPeriod = 50 + return validatorSc, nil + } + + return nil, nil + }}) +} From 8a13c0cc49cab8edec4e80d38e5551445ceb257c Mon Sep 17 00:00:00 2001 From: MariusC Date: Tue, 30 Jan 2024 12:32:46 +0200 Subject: [PATCH 05/10] CLN: Unit test with addNodes and stakeNodes within and above node limits --- vm/systemSmartContracts/delegation_test.go | 50 ++++++++++------------ 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/vm/systemSmartContracts/delegation_test.go b/vm/systemSmartContracts/delegation_test.go index a934548d941..a3812174b93 100644 --- a/vm/systemSmartContracts/delegation_test.go +++ b/vm/systemSmartContracts/delegation_test.go @@ -60,7 +60,7 @@ func createMockArgumentsForDelegation() ArgsNewDelegation { } } -func addValidatorAndStakingScToVmContext(eei *vmContext, blsKeys ...[]byte) { +func addValidatorAndStakingScToVmContext(eei *vmContext) { validatorArgs := createMockArgumentsForValidatorSC() validatorArgs.Eei = eei validatorArgs.StakingSCConfig.GenesisNodePrice = "100" @@ -79,14 +79,13 @@ func addValidatorAndStakingScToVmContext(eei *vmContext, blsKeys ...[]byte) { return stakingSc, nil } - blsPubKeys := getInputBlsKeysOrDefaultIfEmpty(blsKeys...) if bytes.Equal(key, vm.ValidatorSCAddress) { enableEpochsHandler.AddActiveFlags(common.StakingV2Flag) _ = validatorSc.saveRegistrationData([]byte("addr"), &ValidatorDataV2{ RewardAddress: []byte("rewardAddr"), TotalStakeValue: big.NewInt(1000), LockedStake: big.NewInt(500), - BlsPubKeys: blsPubKeys, + BlsPubKeys: [][]byte{[]byte("blsKey1"), []byte("blsKey2")}, TotalUnstaked: big.NewInt(150), UnstakedInfo: []*UnstakedValue{ { @@ -98,7 +97,7 @@ func addValidatorAndStakingScToVmContext(eei *vmContext, blsKeys ...[]byte) { UnstakedValue: big.NewInt(80), }, }, - NumRegistered: uint32(len(blsKeys)), + NumRegistered: 2, }) validatorSc.unBondPeriod = 50 return validatorSc, nil @@ -108,19 +107,6 @@ func addValidatorAndStakingScToVmContext(eei *vmContext, blsKeys ...[]byte) { }}) } -func getInputBlsKeysOrDefaultIfEmpty(blsKeys ...[]byte) [][]byte { - ret := make([][]byte, 0) - for _, blsKey := range blsKeys { - ret = append(ret, blsKey) - } - - if len(ret) == 0 { - return [][]byte{[]byte("blsKey1"), []byte("blsKey2")} - } - - return ret -} - func getDefaultVmInputForFunc(funcName string, args [][]byte) *vmcommon.ContractCallInput { return &vmcommon.ContractCallInput{ VMInput: vmcommon.VMInput{ @@ -5068,6 +5054,7 @@ func TestDelegationSystemSC_ExecuteAddNodesStakedInStakingV4(t *testing.T) { common.StakingV4Step1Flag, common.StakingV4Step2Flag, common.StakingV4Step3Flag, + common.StakeLimitsFlag, common.DelegationSmartContractFlag, common.StakingV2FlagAfterEpoch, @@ -5085,11 +5072,14 @@ func TestDelegationSystemSC_ExecuteAddNodesStakedInStakingV4(t *testing.T) { args.Eei = eei d, _ := NewDelegationSystemSC(args) + + blsKey1 := []byte("blsKey1") + blsKey2 := []byte("blsKey2") key1 := &NodesData{ - BLSKey: []byte("blsKey1"), + BLSKey: blsKey1, } key2 := &NodesData{ - BLSKey: []byte("blsKey2"), + BLSKey: blsKey2, } dStatus := &DelegationContractStatus{ StakedKeys: []*NodesData{key1, key2}, @@ -5100,18 +5090,20 @@ func TestDelegationSystemSC_ExecuteAddNodesStakedInStakingV4(t *testing.T) { TotalActive: big.NewInt(400), } _ = d.saveGlobalFundData(globalFund) - addValidatorAndStakingScToVmContext2(eei, [][]byte{[]byte("blsKey1"), []byte("blsKey2")}) + + addValidatorAndStakingScToVmContextWithBlsKeys(eei, [][]byte{blsKey1, blsKey2}) + dStatus, _ = d.getDelegationStatus() require.Equal(t, 2, len(dStatus.StakedKeys)) require.Equal(t, 0, len(dStatus.UnStakedKeys)) require.Equal(t, 0, len(dStatus.NotStakedKeys)) - newBlsKey := []byte("newBlsKey") - vmInput := getDefaultVmInputForFunc("addNodes", [][]byte{newBlsKey, sig}) + newBlsKey1 := []byte("newBlsKey1") + vmInput := getDefaultVmInputForFunc("addNodes", [][]byte{newBlsKey1, sig}) output := d.Execute(vmInput) require.Equal(t, vmcommon.Ok, output) - vmInput = getDefaultVmInputForFunc("stakeNodes", [][]byte{newBlsKey}) + vmInput = getDefaultVmInputForFunc("stakeNodes", [][]byte{newBlsKey1}) output = d.Execute(vmInput) require.Equal(t, vmcommon.Ok, output) @@ -5120,7 +5112,7 @@ func TestDelegationSystemSC_ExecuteAddNodesStakedInStakingV4(t *testing.T) { require.Equal(t, 0, len(dStatus.UnStakedKeys)) require.Equal(t, 0, len(dStatus.NotStakedKeys)) - addValidatorAndStakingScToVmContext2(eei, [][]byte{[]byte("blsKey1"), []byte("blsKey2"), newBlsKey}) + addValidatorAndStakingScToVmContextWithBlsKeys(eei, [][]byte{blsKey1, blsKey2, newBlsKey1}) newBlsKey2 := []byte("newBlsKey2") vmInput = getDefaultVmInputForFunc("addNodes", [][]byte{newBlsKey2, sig}) @@ -5138,15 +5130,17 @@ func TestDelegationSystemSC_ExecuteAddNodesStakedInStakingV4(t *testing.T) { require.Equal(t, 1, len(dStatus.NotStakedKeys)) } -func addValidatorAndStakingScToVmContext2(eei *vmContext, blsKeys [][]byte) { +func addValidatorAndStakingScToVmContextWithBlsKeys(eei *vmContext, blsKeys [][]byte) { validatorArgs := createMockArgumentsForValidatorSC() validatorArgs.StakingSCConfig.NodeLimitPercentage = 1 validatorArgs.Eei = eei validatorArgs.StakingSCConfig.GenesisNodePrice = "100" validatorArgs.StakingSCAddress = vm.StakingSCAddress - validatorArgs.NodesCoordinator = &shardingMocks.NodesCoordinatorStub{GetNumTotalEligibleCalled: func() uint64 { - return 3 - }} + validatorArgs.NodesCoordinator = &shardingMocks.NodesCoordinatorStub{ + GetNumTotalEligibleCalled: func() uint64 { + return 3 + }, + } validatorSc, _ := NewValidatorSmartContract(validatorArgs) stakingArgs := createMockStakingScArguments() From 5159c7f230d26b62b138a079e3a38e753d057f50 Mon Sep 17 00:00:00 2001 From: MariusC Date: Tue, 30 Jan 2024 13:06:07 +0200 Subject: [PATCH 06/10] CLN: Add extra explanatory vm error message for too many nodes --- vm/systemSmartContracts/delegation.go | 23 +++++++++++++++------- vm/systemSmartContracts/delegation_test.go | 2 ++ vm/systemSmartContracts/validator.go | 8 +++++++- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/vm/systemSmartContracts/delegation.go b/vm/systemSmartContracts/delegation.go index cb882fccb1a..ac33ba81da2 100644 --- a/vm/systemSmartContracts/delegation.go +++ b/vm/systemSmartContracts/delegation.go @@ -1216,8 +1216,9 @@ func (d *delegation) stakeNodes(args *vmcommon.ContractCallInput) vmcommon.Retur } allLogs := d.eei.GetLogs() - if tooManyNodesLogs(allLogs) { - d.eei.AddReturnMessage(numberOfNodesTooHigh) + tooManyNodesErrMsg := getTooManyNodesErrMsg(allLogs) + if len(tooManyNodesErrMsg) != 0 { + d.eei.AddReturnMessage(tooManyNodesErrMsg) return vmcommon.UserError } @@ -1232,17 +1233,25 @@ func (d *delegation) stakeNodes(args *vmcommon.ContractCallInput) vmcommon.Retur return vmcommon.Ok } -func tooManyNodesLogs(logEntries []*vmcommon.LogEntry) bool { +func getTooManyNodesErrMsg(logEntries []*vmcommon.LogEntry) string { for _, logEntry := range logEntries { - if len(logEntry.Topics) != 1 { + topics := logEntry.Topics + if len(topics) != 3 { continue } - if bytes.Equal(logEntry.Topics[0], []byte(numberOfNodesTooHigh)) { - return true + if bytes.Equal(topics[0], []byte(numberOfNodesTooHigh)) { + return formatTooManyNodesMsg(topics) } } - return false + return "" +} + +func formatTooManyNodesMsg(topics [][]byte) string { + numRegisteredBlsKeys := big.NewInt(0).SetBytes(topics[1]).Int64() + nodeLimit := big.NewInt(0).SetBytes(topics[2]).Int64() + return fmt.Sprintf("%s, num registered bls keys: %d, node limit: %d", + numberOfNodesTooHigh, numRegisteredBlsKeys, nodeLimit) } func (d *delegation) updateDelegationStatusAfterStake( diff --git a/vm/systemSmartContracts/delegation_test.go b/vm/systemSmartContracts/delegation_test.go index a3812174b93..8936be6ae7d 100644 --- a/vm/systemSmartContracts/delegation_test.go +++ b/vm/systemSmartContracts/delegation_test.go @@ -5123,6 +5123,8 @@ func TestDelegationSystemSC_ExecuteAddNodesStakedInStakingV4(t *testing.T) { output = d.Execute(vmInput) require.Equal(t, vmcommon.UserError, output) require.True(t, strings.Contains(eei.returnMessage, numberOfNodesTooHigh)) + require.True(t, strings.Contains(eei.returnMessage, "num registered bls keys: 4")) + require.True(t, strings.Contains(eei.returnMessage, "node limit: 3")) dStatus, _ = d.getDelegationStatus() require.Equal(t, 3, len(dStatus.StakedKeys)) diff --git a/vm/systemSmartContracts/validator.go b/vm/systemSmartContracts/validator.go index 081a1e848f7..dbcd79ae883 100644 --- a/vm/systemSmartContracts/validator.go +++ b/vm/systemSmartContracts/validator.go @@ -1074,10 +1074,16 @@ func (v *validatorSC) stake(args *vmcommon.ContractCallInput) vmcommon.ReturnCod args.CallerAddr, ) } else { + numRegisteredBlsKeys := int64(len(registrationData.BlsPubKeys)) + nodeLimit := int64(float64(v.nodesCoordinator.GetNumTotalEligible()) * v.nodeLimitPercentage) entry := &vmcommon.LogEntry{ Identifier: []byte(args.Function), Address: args.RecipientAddr, - Topics: [][]byte{[]byte(numberOfNodesTooHigh)}, + Topics: [][]byte{ + []byte(numberOfNodesTooHigh), + big.NewInt(numRegisteredBlsKeys).Bytes(), + big.NewInt(nodeLimit).Bytes(), + }, } v.eei.AddLogEntry(entry) } From 7f58cea0e46888c5780a7aaa9319ccfad845ab3f Mon Sep 17 00:00:00 2001 From: MariusC Date: Tue, 30 Jan 2024 13:09:51 +0200 Subject: [PATCH 07/10] CLN: Add calcNodeLimit func --- vm/systemSmartContracts/validator.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vm/systemSmartContracts/validator.go b/vm/systemSmartContracts/validator.go index dbcd79ae883..d2f6148c002 100644 --- a/vm/systemSmartContracts/validator.go +++ b/vm/systemSmartContracts/validator.go @@ -936,8 +936,12 @@ func (v *validatorSC) isNumberOfNodesTooHigh(registrationData *ValidatorDataV2) return false } + return len(registrationData.BlsPubKeys) > v.calcNodeLimit() +} + +func (v *validatorSC) calcNodeLimit() int { nodeLimit := float64(v.nodesCoordinator.GetNumTotalEligible()) * v.nodeLimitPercentage - return len(registrationData.BlsPubKeys) > int(nodeLimit) + return int(nodeLimit) } func (v *validatorSC) stake(args *vmcommon.ContractCallInput) vmcommon.ReturnCode { @@ -1075,7 +1079,7 @@ func (v *validatorSC) stake(args *vmcommon.ContractCallInput) vmcommon.ReturnCod ) } else { numRegisteredBlsKeys := int64(len(registrationData.BlsPubKeys)) - nodeLimit := int64(float64(v.nodesCoordinator.GetNumTotalEligible()) * v.nodeLimitPercentage) + nodeLimit := int64(v.calcNodeLimit()) entry := &vmcommon.LogEntry{ Identifier: []byte(args.Function), Address: args.RecipientAddr, From 2923c4dc4d64aa10fdc902666ec47c543352a763 Mon Sep 17 00:00:00 2001 From: MariusC Date: Tue, 30 Jan 2024 15:35:19 +0200 Subject: [PATCH 08/10] FIX: Config values --- cmd/node/config/systemSmartContractsConfig.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/node/config/systemSmartContractsConfig.toml b/cmd/node/config/systemSmartContractsConfig.toml index dcc01dc7f51..efcf86ce248 100644 --- a/cmd/node/config/systemSmartContractsConfig.toml +++ b/cmd/node/config/systemSmartContractsConfig.toml @@ -11,8 +11,8 @@ MaxNumberOfNodesForStake = 36 UnJailValue = "2500000000000000000" #0.1% of genesis node price ActivateBLSPubKeyMessageVerification = false - StakeLimitPercentage = 0.01 #fraction of value 0.01 - 1% - NodeLimitPercentage = 0.005 #fraction of value 0.005 - 0.5% + StakeLimitPercentage = 1.0 #fraction of value 1 - 100%, for the time being no stake limit + NodeLimitPercentage = 0.1 #fraction of value 0.1 - 10% [ESDTSystemSCConfig] BaseIssuingCost = "5000000000000000000" #5 eGLD From d836893b051a7f39fb9932519d38cd201aa9eb0f Mon Sep 17 00:00:00 2001 From: MariusC Date: Tue, 30 Jan 2024 15:39:13 +0200 Subject: [PATCH 09/10] FIX: Unit test name --- vm/systemSmartContracts/delegation_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/systemSmartContracts/delegation_test.go b/vm/systemSmartContracts/delegation_test.go index 8936be6ae7d..4dcab8d7e44 100644 --- a/vm/systemSmartContracts/delegation_test.go +++ b/vm/systemSmartContracts/delegation_test.go @@ -5045,7 +5045,7 @@ func TestDelegationSystemSC_SynchronizeOwner(t *testing.T) { }) } -func TestDelegationSystemSC_ExecuteAddNodesStakedInStakingV4(t *testing.T) { +func TestDelegationSystemSC_ExecuteAddNodesStakeNodesWithNodesLimit(t *testing.T) { t.Parallel() sig := []byte("sig1") From 7cc9bc975c9070a871409318a7279b903131cefd Mon Sep 17 00:00:00 2001 From: MariusC Date: Tue, 30 Jan 2024 16:49:17 +0200 Subject: [PATCH 10/10] FIX: Func name --- vm/systemSmartContracts/validator.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vm/systemSmartContracts/validator.go b/vm/systemSmartContracts/validator.go index d2f6148c002..e7e02c5e55e 100644 --- a/vm/systemSmartContracts/validator.go +++ b/vm/systemSmartContracts/validator.go @@ -936,10 +936,10 @@ func (v *validatorSC) isNumberOfNodesTooHigh(registrationData *ValidatorDataV2) return false } - return len(registrationData.BlsPubKeys) > v.calcNodeLimit() + return len(registrationData.BlsPubKeys) > v.computeNodeLimit() } -func (v *validatorSC) calcNodeLimit() int { +func (v *validatorSC) computeNodeLimit() int { nodeLimit := float64(v.nodesCoordinator.GetNumTotalEligible()) * v.nodeLimitPercentage return int(nodeLimit) } @@ -1079,7 +1079,7 @@ func (v *validatorSC) stake(args *vmcommon.ContractCallInput) vmcommon.ReturnCod ) } else { numRegisteredBlsKeys := int64(len(registrationData.BlsPubKeys)) - nodeLimit := int64(v.calcNodeLimit()) + nodeLimit := int64(v.computeNodeLimit()) entry := &vmcommon.LogEntry{ Identifier: []byte(args.Function), Address: args.RecipientAddr,