From ddb907c7b739905d778d7e4902affe2dbb07efa1 Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Fri, 19 Apr 2024 16:59:05 +0300 Subject: [PATCH 1/3] - fixed the initialization of the chain simulator when working with 0 value activation epochs --- epochStart/metachain/legacySystemSCs.go | 3 +- errors/errors.go | 3 + .../disabled/epochStartSystemSCProcessor.go | 42 ++++++++++++++ factory/interface.go | 1 + factory/mock/processComponentsStub.go | 6 ++ factory/processing/blockProcessorCreator.go | 3 + .../processing/blockProcessorCreator_test.go | 7 ++- factory/processing/export_test.go | 6 +- factory/processing/processComponents.go | 2 + .../processing/processComponentsHandler.go | 15 +++++ .../processComponentsHandler_test.go | 2 + .../stakingProvider/delegation_test.go | 58 +++++++++++++++++++ .../mock/processComponentsStub.go | 6 ++ node/chainSimulator/chainSimulator.go | 33 +++++++++-- .../components/processComponents.go | 7 +++ .../components/processComponents_test.go | 1 + .../components/testOnlyProcessingNode.go | 5 ++ node/chainSimulator/process/interface.go | 1 + testscommon/chainSimulator/nodeHandlerMock.go | 9 +++ 19 files changed, 200 insertions(+), 10 deletions(-) create mode 100644 factory/disabled/epochStartSystemSCProcessor.go diff --git a/epochStart/metachain/legacySystemSCs.go b/epochStart/metachain/legacySystemSCs.go index 677cbcb682b..0db6a39916f 100644 --- a/epochStart/metachain/legacySystemSCs.go +++ b/epochStart/metachain/legacySystemSCs.go @@ -151,7 +151,8 @@ func (s *legacySystemSCProcessor) processLegacy( } } - if s.flagChangeMaxNodesEnabled.IsSet() { + // the updateMaxNodes call needs the StakingV2Flag functionality to be enabled. Otherwise, the call will error + if s.flagChangeMaxNodesEnabled.IsSet() && s.enableEpochsHandler.IsFlagEnabled(common.StakingV2Flag) { err := s.updateMaxNodes(validatorsInfoMap, nonce) if err != nil { return err diff --git a/errors/errors.go b/errors/errors.go index 771c65adc07..dd475327876 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -595,3 +595,6 @@ var ErrInvalidNodeOperationMode = errors.New("invalid node operation mode") // ErrNilSentSignatureTracker defines the error for setting a nil SentSignatureTracker var ErrNilSentSignatureTracker = errors.New("nil sent signature tracker") + +// ErrNilEpochSystemSCProcessor defines the error for setting a nil EpochSystemSCProcessor +var ErrNilEpochSystemSCProcessor = errors.New("nil epoch system SC processor") diff --git a/factory/disabled/epochStartSystemSCProcessor.go b/factory/disabled/epochStartSystemSCProcessor.go new file mode 100644 index 00000000000..7d9e8720a79 --- /dev/null +++ b/factory/disabled/epochStartSystemSCProcessor.go @@ -0,0 +1,42 @@ +package disabled + +import ( + "github.com/multiversx/mx-chain-core-go/data" + "github.com/multiversx/mx-chain-core-go/data/block" + "github.com/multiversx/mx-chain-go/epochStart" + "github.com/multiversx/mx-chain-go/state" +) + +type epochStartSystemSCProcessor struct { +} + +// NewDisabledEpochStartSystemSC creates a new disabled EpochStartSystemSCProcessor instance +func NewDisabledEpochStartSystemSC() *epochStartSystemSCProcessor { + return &epochStartSystemSCProcessor{} +} + +// ToggleUnStakeUnBond returns nil +func (e *epochStartSystemSCProcessor) ToggleUnStakeUnBond(_ bool) error { + return nil +} + +// ProcessSystemSmartContract returns nil +func (e *epochStartSystemSCProcessor) ProcessSystemSmartContract( + _ state.ShardValidatorsInfoMapHandler, + _ data.HeaderHandler, +) error { + return nil +} + +// ProcessDelegationRewards returns nil +func (e *epochStartSystemSCProcessor) ProcessDelegationRewards( + _ block.MiniBlockSlice, + _ epochStart.TransactionCacher, +) error { + return nil +} + +// IsInterfaceNil returns true if there is no value under the interface +func (e *epochStartSystemSCProcessor) IsInterfaceNil() bool { + return e == nil +} diff --git a/factory/interface.go b/factory/interface.go index ede9f39089b..0f1c237d0d9 100644 --- a/factory/interface.go +++ b/factory/interface.go @@ -310,6 +310,7 @@ type ProcessComponentsHolder interface { AccountsParser() genesis.AccountsParser ReceiptsRepository() ReceiptsRepository SentSignaturesTracker() process.SentSignaturesTracker + EpochSystemSCProcessor() process.EpochStartSystemSCProcessor IsInterfaceNil() bool } diff --git a/factory/mock/processComponentsStub.go b/factory/mock/processComponentsStub.go index e646958281c..32bbfaf2df3 100644 --- a/factory/mock/processComponentsStub.go +++ b/factory/mock/processComponentsStub.go @@ -57,6 +57,7 @@ type ProcessComponentsMock struct { AccountsParserInternal genesis.AccountsParser ReceiptsRepositoryInternal factory.ReceiptsRepository SentSignaturesTrackerInternal process.SentSignaturesTracker + EpochSystemSCProcessorInternal process.EpochStartSystemSCProcessor } // Create - @@ -284,6 +285,11 @@ func (pcm *ProcessComponentsMock) SentSignaturesTracker() process.SentSignatures return pcm.SentSignaturesTrackerInternal } +// EpochSystemSCProcessor - +func (pcm *ProcessComponentsMock) EpochSystemSCProcessor() process.EpochStartSystemSCProcessor { + return pcm.EpochSystemSCProcessorInternal +} + // IsInterfaceNil - func (pcm *ProcessComponentsMock) IsInterfaceNil() bool { return pcm == nil diff --git a/factory/processing/blockProcessorCreator.go b/factory/processing/blockProcessorCreator.go index 7db9e20cf7d..2cf54aaa955 100644 --- a/factory/processing/blockProcessorCreator.go +++ b/factory/processing/blockProcessorCreator.go @@ -50,6 +50,7 @@ import ( type blockProcessorAndVmFactories struct { blockProcessor process.BlockProcessor vmFactoryForProcessing process.VirtualMachinesContainerFactory + epochSystemSCProcessor process.EpochStartSystemSCProcessor } func (pcf *processComponentsFactory) newBlockProcessor( @@ -453,6 +454,7 @@ func (pcf *processComponentsFactory) newShardBlockProcessor( blockProcessorComponents := &blockProcessorAndVmFactories{ blockProcessor: blockProcessor, vmFactoryForProcessing: vmFactory, + epochSystemSCProcessor: factoryDisabled.NewDisabledEpochStartSystemSC(), } pcf.stakingDataProviderAPI = factoryDisabled.NewDisabledStakingDataProvider() @@ -982,6 +984,7 @@ func (pcf *processComponentsFactory) newMetaBlockProcessor( blockProcessorComponents := &blockProcessorAndVmFactories{ blockProcessor: metaProcessor, vmFactoryForProcessing: vmFactory, + epochSystemSCProcessor: epochStartSystemSCProcessor, } return blockProcessorComponents, nil diff --git a/factory/processing/blockProcessorCreator_test.go b/factory/processing/blockProcessorCreator_test.go index 3ecc3432f9e..099fec4a82d 100644 --- a/factory/processing/blockProcessorCreator_test.go +++ b/factory/processing/blockProcessorCreator_test.go @@ -1,6 +1,7 @@ package processing_test import ( + "fmt" "sync" "testing" @@ -40,7 +41,7 @@ func Test_newBlockProcessorCreatorForShard(t *testing.T) { _, err = pcf.Create() require.NoError(t, err) - bp, err := pcf.NewBlockProcessor( + bp, epochStartSCProc, err := pcf.NewBlockProcessor( &testscommon.RequestHandlerStub{}, &processMocks.ForkDetectorStub{}, &mock.EpochStartTriggerStub{}, @@ -60,6 +61,7 @@ func Test_newBlockProcessorCreatorForShard(t *testing.T) { require.NoError(t, err) require.NotNil(t, bp) + require.Equal(t, "*disabled.epochStartSystemSCProcessor", fmt.Sprintf("%T", epochStartSCProc)) } func Test_newBlockProcessorCreatorForMeta(t *testing.T) { @@ -166,7 +168,7 @@ func Test_newBlockProcessorCreatorForMeta(t *testing.T) { _, err = pcf.Create() require.NoError(t, err) - bp, err := pcf.NewBlockProcessor( + bp, epochStartSCProc, err := pcf.NewBlockProcessor( &testscommon.RequestHandlerStub{}, &processMocks.ForkDetectorStub{}, &mock.EpochStartTriggerStub{}, @@ -186,6 +188,7 @@ func Test_newBlockProcessorCreatorForMeta(t *testing.T) { require.NoError(t, err) require.NotNil(t, bp) + require.Equal(t, "*metachain.systemSCProcessor", fmt.Sprintf("%T", epochStartSCProc)) } func createAccountAdapter( diff --git a/factory/processing/export_test.go b/factory/processing/export_test.go index 50c5123634c..76e84d75fee 100644 --- a/factory/processing/export_test.go +++ b/factory/processing/export_test.go @@ -25,7 +25,7 @@ func (pcf *processComponentsFactory) NewBlockProcessor( blockProcessingCutoff cutoff.BlockProcessingCutoffHandler, missingTrieNodesNotifier common.MissingTrieNodesNotifier, sentSignaturesTracker process.SentSignaturesTracker, -) (process.BlockProcessor, error) { +) (process.BlockProcessor, process.EpochStartSystemSCProcessor, error) { blockProcessorComponents, err := pcf.newBlockProcessor( requestHandler, forkDetector, @@ -44,10 +44,10 @@ func (pcf *processComponentsFactory) NewBlockProcessor( sentSignaturesTracker, ) if err != nil { - return nil, err + return nil, nil, err } - return blockProcessorComponents.blockProcessor, nil + return blockProcessorComponents.blockProcessor, blockProcessorComponents.epochSystemSCProcessor, nil } // CreateAPITransactionEvaluator - diff --git a/factory/processing/processComponents.go b/factory/processing/processComponents.go index 72d75c69dc3..352343ce102 100644 --- a/factory/processing/processComponents.go +++ b/factory/processing/processComponents.go @@ -131,6 +131,7 @@ type processComponents struct { accountsParser genesis.AccountsParser receiptsRepository mainFactory.ReceiptsRepository sentSignaturesTracker process.SentSignaturesTracker + epochSystemSCProcessor process.EpochStartSystemSCProcessor } // ProcessComponentsFactoryArgs holds the arguments needed to create a process components factory @@ -751,6 +752,7 @@ func (pcf *processComponentsFactory) Create() (*processComponents, error) { currentEpochProvider: currentEpochProvider, vmFactoryForTxSimulator: vmFactoryForTxSimulate, vmFactoryForProcessing: blockProcessorComponents.vmFactoryForProcessing, + epochSystemSCProcessor: blockProcessorComponents.epochSystemSCProcessor, scheduledTxsExecutionHandler: scheduledTxsExecutionHandler, txsSender: txsSenderWithAccumulator, hardforkTrigger: hardforkTrigger, diff --git a/factory/processing/processComponentsHandler.go b/factory/processing/processComponentsHandler.go index a5b71ca3b28..28b3c4b0eed 100644 --- a/factory/processing/processComponentsHandler.go +++ b/factory/processing/processComponentsHandler.go @@ -177,6 +177,9 @@ func (m *managedProcessComponents) CheckSubcomponents() error { if check.IfNil(m.processComponents.sentSignaturesTracker) { return errors.ErrNilSentSignatureTracker } + if check.IfNil(m.processComponents.epochSystemSCProcessor) { + return errors.ErrNilEpochSystemSCProcessor + } return nil } @@ -673,6 +676,18 @@ func (m *managedProcessComponents) SentSignaturesTracker() process.SentSignature return m.processComponents.sentSignaturesTracker } +// EpochSystemSCProcessor returns the epoch start system SC processor +func (m *managedProcessComponents) EpochSystemSCProcessor() process.EpochStartSystemSCProcessor { + m.mutProcessComponents.RLock() + defer m.mutProcessComponents.RUnlock() + + if m.processComponents == nil { + return nil + } + + return m.processComponents.epochSystemSCProcessor +} + // IsInterfaceNil returns true if the interface is nil func (m *managedProcessComponents) IsInterfaceNil() bool { return m == nil diff --git a/factory/processing/processComponentsHandler_test.go b/factory/processing/processComponentsHandler_test.go index 36638afacfd..2aec3cb8c6e 100644 --- a/factory/processing/processComponentsHandler_test.go +++ b/factory/processing/processComponentsHandler_test.go @@ -93,6 +93,7 @@ func TestManagedProcessComponents_Create(t *testing.T) { require.True(t, check.IfNil(managedProcessComponents.FullArchivePeerShardMapper())) require.True(t, check.IfNil(managedProcessComponents.FullArchiveInterceptorsContainer())) require.True(t, check.IfNil(managedProcessComponents.SentSignaturesTracker())) + require.True(t, check.IfNil(managedProcessComponents.EpochSystemSCProcessor())) err := managedProcessComponents.Create() require.NoError(t, err) @@ -137,6 +138,7 @@ func TestManagedProcessComponents_Create(t *testing.T) { require.False(t, check.IfNil(managedProcessComponents.FullArchivePeerShardMapper())) require.False(t, check.IfNil(managedProcessComponents.FullArchiveInterceptorsContainer())) require.False(t, check.IfNil(managedProcessComponents.SentSignaturesTracker())) + require.False(t, check.IfNil(managedProcessComponents.EpochSystemSCProcessor())) require.Equal(t, factory.ProcessComponentsName, managedProcessComponents.String()) }) diff --git a/integrationTests/chainSimulator/staking/stakingProvider/delegation_test.go b/integrationTests/chainSimulator/staking/stakingProvider/delegation_test.go index 653ab74f031..e61166264bb 100644 --- a/integrationTests/chainSimulator/staking/stakingProvider/delegation_test.go +++ b/integrationTests/chainSimulator/staking/stakingProvider/delegation_test.go @@ -83,6 +83,13 @@ func TestChainSimulator_MakeNewContractFromValidatorData(t *testing.T) { NumNodesWaitingListMeta: 3, NumNodesWaitingListShard: 3, AlterConfigsFunction: func(cfg *config.Configs) { + maxNodesChangeEnableEpoch := cfg.EpochConfig.EnableEpochs.MaxNodesChangeEnableEpoch + blsMultiSignerEnableEpoch := cfg.EpochConfig.EnableEpochs.BLSMultiSignerEnableEpoch + + cfg.EpochConfig.EnableEpochs = config.EnableEpochs{} + cfg.EpochConfig.EnableEpochs.MaxNodesChangeEnableEpoch = maxNodesChangeEnableEpoch + cfg.EpochConfig.EnableEpochs.BLSMultiSignerEnableEpoch = blsMultiSignerEnableEpoch + cfg.EpochConfig.EnableEpochs.StakingV4Step1EnableEpoch = 100 cfg.EpochConfig.EnableEpochs.StakingV4Step2EnableEpoch = 101 cfg.EpochConfig.EnableEpochs.StakingV4Step3EnableEpoch = 102 @@ -98,6 +105,57 @@ func TestChainSimulator_MakeNewContractFromValidatorData(t *testing.T) { testChainSimulatorMakeNewContractFromValidatorData(t, cs, 1) }) + // Test scenario done in staking 3.5 phase (staking v4 is not active) + // 1. Add a new validator private key in the multi key handler + // 2. Set the initial state for the owner and the 2 delegators + // 3. Do a stake transaction for the validator key and test that the new key is on queue and topup is 500 + // 4. Execute the MakeNewContractFromValidatorData transaction and test that the key is on queue and topup is 500 + // 5. Execute 2 delegation operations of 100 EGLD each, check the topup is 700 + // 6. Execute 2 unDelegate operations of 100 EGLD each, check the topup is back to 500 + t.Run("staking ph 4 is not active and all is done in epoch 0", func(t *testing.T) { + 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) { + maxNodesChangeEnableEpoch := cfg.EpochConfig.EnableEpochs.MaxNodesChangeEnableEpoch + blsMultiSignerEnableEpoch := cfg.EpochConfig.EnableEpochs.BLSMultiSignerEnableEpoch + + // set all activation epoch values on 0 + cfg.EpochConfig.EnableEpochs = config.EnableEpochs{} + cfg.EpochConfig.EnableEpochs.MaxNodesChangeEnableEpoch = maxNodesChangeEnableEpoch + cfg.EpochConfig.EnableEpochs.BLSMultiSignerEnableEpoch = blsMultiSignerEnableEpoch + + cfg.EpochConfig.EnableEpochs.StakingV4Step1EnableEpoch = 100 + cfg.EpochConfig.EnableEpochs.StakingV4Step2EnableEpoch = 101 + cfg.EpochConfig.EnableEpochs.StakingV4Step3EnableEpoch = 102 + + cfg.EpochConfig.EnableEpochs.MaxNodesChangeEnableEpoch[2].EpochEnable = 102 + }, + }) + require.Nil(t, err) + require.NotNil(t, cs) + + defer cs.Close() + + // we need a little time to enable the VM queries on the http server + time.Sleep(time.Second) + // also, propose a couple of blocks + err = cs.GenerateBlocks(3) + require.Nil(t, err) + + testChainSimulatorMakeNewContractFromValidatorData(t, cs, 0) + }) + // Test scenario done in staking v4 phase step 1 // 1. Add a new validator private key in the multi key handler // 2. Set the initial state for the owner and the 2 delegators diff --git a/integrationTests/mock/processComponentsStub.go b/integrationTests/mock/processComponentsStub.go index e0407b5d6f9..11d4f4ce69d 100644 --- a/integrationTests/mock/processComponentsStub.go +++ b/integrationTests/mock/processComponentsStub.go @@ -60,6 +60,7 @@ type ProcessComponentsStub struct { ReceiptsRepositoryInternal factory.ReceiptsRepository ESDTDataStorageHandlerForAPIInternal vmcommon.ESDTNFTStorageHandler SentSignaturesTrackerInternal process.SentSignaturesTracker + EpochSystemSCProcessorInternal process.EpochStartSystemSCProcessor } // Create - @@ -296,6 +297,11 @@ func (pcs *ProcessComponentsStub) SentSignaturesTracker() process.SentSignatures return pcs.SentSignaturesTrackerInternal } +// EpochSystemSCProcessor - +func (pcs *ProcessComponentsStub) EpochSystemSCProcessor() process.EpochStartSystemSCProcessor { + return pcs.EpochSystemSCProcessorInternal +} + // IsInterfaceNil - func (pcs *ProcessComponentsStub) IsInterfaceNil() bool { return pcs == nil diff --git a/node/chainSimulator/chainSimulator.go b/node/chainSimulator/chainSimulator.go index 8bffcb6c63a..4a0bfcb636e 100644 --- a/node/chainSimulator/chainSimulator.go +++ b/node/chainSimulator/chainSimulator.go @@ -130,6 +130,31 @@ func (s *simulator) createChainHandlers(args ArgsChainSimulator) error { shardID := node.GetShardCoordinator().SelfId() s.nodes[shardID] = node s.handlers = append(s.handlers, chainHandler) + + if node.GetShardCoordinator().SelfId() == core.MetachainShardId { + currentRootHash, errRootHash := node.GetProcessComponents().ValidatorsStatistics().RootHash() + if errRootHash != nil { + return errRootHash + } + + allValidatorsInfo, errGet := node.GetProcessComponents().ValidatorsStatistics().GetValidatorInfoForRootHash(currentRootHash) + if errRootHash != nil { + return errGet + } + + err = node.GetProcessComponents().EpochSystemSCProcessor().ProcessSystemSmartContract( + allValidatorsInfo, + node.GetDataComponents().Blockchain().GetGenesisHeader(), + ) + if err != nil { + return err + } + + _, err = node.GetStateComponents().AccountsAdapter().Commit() + if err != nil { + return err + } + } } s.initialWalletKeys = outputConfigs.InitialWallets @@ -411,17 +436,17 @@ func (s *simulator) SetStateMultiple(stateSlice []*dtos.AddressState) error { defer s.mutex.Unlock() addressConverter := s.nodes[core.MetachainShardId].GetCoreComponents().AddressPubKeyConverter() - for _, state := range stateSlice { - addressBytes, err := addressConverter.Decode(state.Address) + for _, stateValue := range stateSlice { + addressBytes, err := addressConverter.Decode(stateValue.Address) if err != nil { return err } if bytes.Equal(addressBytes, core.SystemAccountAddress) { - err = s.setStateSystemAccount(state) + err = s.setStateSystemAccount(stateValue) } else { shardID := sharding.ComputeShardID(addressBytes, s.numOfShards) - err = s.nodes[shardID].SetStateForAddress(addressBytes, state) + err = s.nodes[shardID].SetStateForAddress(addressBytes, stateValue) } if err != nil { return err diff --git a/node/chainSimulator/components/processComponents.go b/node/chainSimulator/components/processComponents.go index efa7af79c10..3bfd598f98d 100644 --- a/node/chainSimulator/components/processComponents.go +++ b/node/chainSimulator/components/processComponents.go @@ -98,6 +98,7 @@ type processComponentsHolder struct { esdtDataStorageHandlerForAPI vmcommon.ESDTNFTStorageHandler accountsParser genesis.AccountsParser sentSignatureTracker process.SentSignaturesTracker + epochStartSystemSCProcessor process.EpochStartSystemSCProcessor managedProcessComponentsCloser io.Closer } @@ -270,6 +271,7 @@ func CreateProcessComponents(args ArgsProcessComponentsHolder) (*processComponen esdtDataStorageHandlerForAPI: managedProcessComponents.ESDTDataStorageHandlerForAPI(), accountsParser: managedProcessComponents.AccountsParser(), sentSignatureTracker: managedProcessComponents.SentSignaturesTracker(), + epochStartSystemSCProcessor: managedProcessComponents.EpochSystemSCProcessor(), managedProcessComponentsCloser: managedProcessComponents, } @@ -481,6 +483,11 @@ func (p *processComponentsHolder) ReceiptsRepository() factory.ReceiptsRepositor return p.receiptsRepository } +// EpochSystemSCProcessor returns the epoch start system SC processor +func (p *processComponentsHolder) EpochSystemSCProcessor() process.EpochStartSystemSCProcessor { + return p.epochStartSystemSCProcessor +} + // Close will call the Close methods on all inner components func (p *processComponentsHolder) Close() error { return p.managedProcessComponentsCloser.Close() diff --git a/node/chainSimulator/components/processComponents_test.go b/node/chainSimulator/components/processComponents_test.go index 4628bbc4f66..efc5590e7f4 100644 --- a/node/chainSimulator/components/processComponents_test.go +++ b/node/chainSimulator/components/processComponents_test.go @@ -407,6 +407,7 @@ func TestProcessComponentsHolder_Getters(t *testing.T) { require.NotNil(t, comp.ESDTDataStorageHandlerForAPI()) require.NotNil(t, comp.AccountsParser()) require.NotNil(t, comp.ReceiptsRepository()) + require.NotNil(t, comp.EpochSystemSCProcessor()) require.Nil(t, comp.CheckSubcomponents()) require.Empty(t, comp.String()) diff --git a/node/chainSimulator/components/testOnlyProcessingNode.go b/node/chainSimulator/components/testOnlyProcessingNode.go index e08f4fc1367..7b375ae08cb 100644 --- a/node/chainSimulator/components/testOnlyProcessingNode.go +++ b/node/chainSimulator/components/testOnlyProcessingNode.go @@ -370,6 +370,11 @@ func (node *testOnlyProcessingNode) GetCoreComponents() factory.CoreComponentsHo return node.CoreComponentsHolder } +// GetDataComponents will return the data components +func (node *testOnlyProcessingNode) GetDataComponents() factory.DataComponentsHolder { + return node.DataComponentsHolder +} + // GetStateComponents will return the state components func (node *testOnlyProcessingNode) GetStateComponents() factory.StateComponentsHolder { return node.StateComponentsHolder diff --git a/node/chainSimulator/process/interface.go b/node/chainSimulator/process/interface.go index 6dc0b84fa02..ee54998dc7f 100644 --- a/node/chainSimulator/process/interface.go +++ b/node/chainSimulator/process/interface.go @@ -17,6 +17,7 @@ type NodeHandler interface { GetShardCoordinator() sharding.Coordinator GetCryptoComponents() factory.CryptoComponentsHolder GetCoreComponents() factory.CoreComponentsHolder + GetDataComponents() factory.DataComponentsHolder GetStateComponents() factory.StateComponentsHolder GetFacadeHandler() shared.FacadeHandler GetStatusCoreComponents() factory.StatusCoreComponentsHolder diff --git a/testscommon/chainSimulator/nodeHandlerMock.go b/testscommon/chainSimulator/nodeHandlerMock.go index 23941f914eb..52b72a17acc 100644 --- a/testscommon/chainSimulator/nodeHandlerMock.go +++ b/testscommon/chainSimulator/nodeHandlerMock.go @@ -17,6 +17,7 @@ type NodeHandlerMock struct { GetShardCoordinatorCalled func() sharding.Coordinator GetCryptoComponentsCalled func() factory.CryptoComponentsHolder GetCoreComponentsCalled func() factory.CoreComponentsHolder + GetDataComponentsCalled func() factory.DataComponentsHandler GetStateComponentsCalled func() factory.StateComponentsHolder GetFacadeHandlerCalled func() shared.FacadeHandler GetStatusCoreComponentsCalled func() factory.StatusCoreComponentsHolder @@ -73,6 +74,14 @@ func (mock *NodeHandlerMock) GetCoreComponents() factory.CoreComponentsHolder { return nil } +// GetDataComponents - +func (mock *NodeHandlerMock) GetDataComponents() factory.DataComponentsHolder { + if mock.GetDataComponentsCalled != nil { + return mock.GetDataComponentsCalled() + } + return nil +} + // GetStateComponents - func (mock *NodeHandlerMock) GetStateComponents() factory.StateComponentsHolder { if mock.GetStateComponentsCalled != nil { From ec6236c52bb80ddf867cb59d12506e52a0dfa6db Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Tue, 23 Apr 2024 11:03:36 +0300 Subject: [PATCH 2/3] - added RemoveAccounts feature on the chain simulator --- node/chainSimulator/chainSimulator.go | 37 ++++++ node/chainSimulator/chainSimulator_test.go | 115 ++++++++++++++++++ .../components/testOnlyProcessingNode.go | 12 ++ node/chainSimulator/process/interface.go | 1 + testscommon/chainSimulator/nodeHandlerMock.go | 10 ++ 5 files changed, 175 insertions(+) diff --git a/node/chainSimulator/chainSimulator.go b/node/chainSimulator/chainSimulator.go index 4a0bfcb636e..d70921984e3 100644 --- a/node/chainSimulator/chainSimulator.go +++ b/node/chainSimulator/chainSimulator.go @@ -456,6 +456,32 @@ func (s *simulator) SetStateMultiple(stateSlice []*dtos.AddressState) error { return nil } +// RemoveAccounts will try to remove all accounts data for the addresses provided +func (s *simulator) RemoveAccounts(addresses []string) error { + s.mutex.Lock() + defer s.mutex.Unlock() + + addressConverter := s.nodes[core.MetachainShardId].GetCoreComponents().AddressPubKeyConverter() + for _, address := range addresses { + addressBytes, err := addressConverter.Decode(address) + if err != nil { + return err + } + + if bytes.Equal(addressBytes, core.SystemAccountAddress) { + err = s.removeAllSystemAccounts() + } else { + shardID := sharding.ComputeShardID(addressBytes, s.numOfShards) + err = s.nodes[shardID].RemoveAccount(addressBytes) + } + if err != nil { + return err + } + } + + return nil +} + // SendTxAndGenerateBlockTilTxIsExecuted will send the provided transaction and generate block until the transaction is executed func (s *simulator) SendTxAndGenerateBlockTilTxIsExecuted(txToSend *transaction.Transaction, maxNumOfBlocksToGenerateWhenExecutingTx int) (*transaction.ApiTransactionResult, error) { result, err := s.SendTxsAndGenerateBlocksTilAreExecuted([]*transaction.Transaction{txToSend}, maxNumOfBlocksToGenerateWhenExecutingTx) @@ -581,6 +607,17 @@ func (s *simulator) setStateSystemAccount(state *dtos.AddressState) error { return nil } +func (s *simulator) removeAllSystemAccounts() error { + for shard, node := range s.nodes { + err := node.RemoveAccount(core.SystemAccountAddress) + if err != nil { + return fmt.Errorf("%w for shard %d", err, shard) + } + } + + return nil +} + // GetAccount will fetch the account of the provided address func (s *simulator) GetAccount(address dtos.WalletAddress) (api.AccountResponse, error) { destinationShardID := s.GetNodeHandler(0).GetShardCoordinator().ComputeId(address.Bytes) diff --git a/node/chainSimulator/chainSimulator_test.go b/node/chainSimulator/chainSimulator_test.go index 1a65b37ff78..e4092a16b9c 100644 --- a/node/chainSimulator/chainSimulator_test.go +++ b/node/chainSimulator/chainSimulator_test.go @@ -264,6 +264,121 @@ func TestChainSimulator_SetEntireState(t *testing.T) { require.Equal(t, accountState.RootHash, base64.StdEncoding.EncodeToString(account.RootHash)) } +func TestChainSimulator_SetEntireStateWithRemoval(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + startTime := time.Now().Unix() + roundDurationInMillis := uint64(6000) + roundsPerEpoch := core.OptionalUint64{ + HasValue: true, + Value: 20, + } + chainSimulator, err := NewChainSimulator(ArgsChainSimulator{ + BypassTxSignatureCheck: false, + TempDir: t.TempDir(), + PathToInitialConfig: defaultPathToInitialConfig, + NumOfShards: 3, + GenesisTimestamp: startTime, + RoundDurationInMillis: roundDurationInMillis, + RoundsPerEpoch: roundsPerEpoch, + ApiInterface: api.NewNoApiInterface(), + MinNodesPerShard: 1, + MetaChainMinNodes: 1, + }) + require.Nil(t, err) + require.NotNil(t, chainSimulator) + + defer chainSimulator.Close() + + // activate the auto balancing tries so the results will be the same + err = chainSimulator.GenerateBlocks(30) + require.Nil(t, err) + + balance := "431271308732096033771131" + contractAddress := "erd1qqqqqqqqqqqqqpgqmzzm05jeav6d5qvna0q2pmcllelkz8xddz3syjszx5" + accountState := &dtos.AddressState{ + Address: contractAddress, + Nonce: new(uint64), + Balance: balance, + Code: "0061736d010000000129086000006000017f60027f7f017f60027f7f0060017f0060037f7f7f017f60037f7f7f0060017f017f0290020b03656e7619626967496e74476574556e7369676e6564417267756d656e74000303656e760f6765744e756d417267756d656e7473000103656e760b7369676e616c4572726f72000303656e76126d42756666657253746f726167654c6f6164000203656e76176d427566666572546f426967496e74556e7369676e6564000203656e76196d42756666657246726f6d426967496e74556e7369676e6564000203656e76136d42756666657253746f7261676553746f7265000203656e760f6d4275666665725365744279746573000503656e760e636865636b4e6f5061796d656e74000003656e7614626967496e7446696e697368556e7369676e6564000403656e7609626967496e744164640006030b0a010104070301000000000503010003060f027f0041a080080b7f0041a080080b074607066d656d6f7279020004696e697400110667657453756d00120361646400130863616c6c4261636b00140a5f5f646174615f656e6403000b5f5f686561705f6261736503010aca010a0e01017f4100100c2200100020000b1901017f419c8008419c800828020041016b220036020020000b1400100120004604400f0b4180800841191002000b16002000100c220010031a2000100c220010041a20000b1401017f100c2202200110051a2000200210061a0b1301017f100c220041998008410310071a20000b1401017f10084101100d100b210010102000100f0b0e0010084100100d1010100e10090b2201037f10084101100d100b210110102202100e220020002001100a20022000100f0b0300010b0b2f0200418080080b1c77726f6e67206e756d626572206f6620617267756d656e747373756d00419c80080b049cffffff", + CodeHash: "n9EviPlHS6EV+3Xp0YqP28T0IUfeAFRFBIRC1Jw6pyU=", + RootHash: "eqIumOaMn7G5cNSViK3XHZIW/C392ehfHxOZkHGp+Gc=", // root hash with auto balancing enabled + CodeMetadata: "BQY=", + Owner: "erd1ss6u80ruas2phpmr82r42xnkd6rxy40g9jl69frppl4qez9w2jpsqj8x97", + DeveloperRewards: "5401004999998", + Keys: map[string]string{ + "73756d": "0a", + }, + } + + err = chainSimulator.SetStateMultiple([]*dtos.AddressState{accountState}) + require.Nil(t, err) + + err = chainSimulator.GenerateBlocks(2) + require.Nil(t, err) + + nodeHandler := chainSimulator.GetNodeHandler(1) + scAddress, _ := nodeHandler.GetCoreComponents().AddressPubKeyConverter().Decode(contractAddress) + res, _, err := nodeHandler.GetFacadeHandler().ExecuteSCQuery(&process.SCQuery{ + ScAddress: scAddress, + FuncName: "getSum", + CallerAddr: nil, + BlockNonce: core.OptionalUint64{}, + }) + require.Nil(t, err) + + counterValue := big.NewInt(0).SetBytes(res.ReturnData[0]).Int64() + require.Equal(t, 10, int(counterValue)) + + account, _, err := nodeHandler.GetFacadeHandler().GetAccount(contractAddress, coreAPI.AccountQueryOptions{}) + require.Nil(t, err) + require.Equal(t, accountState.Balance, account.Balance) + require.Equal(t, accountState.DeveloperRewards, account.DeveloperReward) + require.Equal(t, accountState.Code, account.Code) + require.Equal(t, accountState.CodeHash, base64.StdEncoding.EncodeToString(account.CodeHash)) + require.Equal(t, accountState.CodeMetadata, base64.StdEncoding.EncodeToString(account.CodeMetadata)) + require.Equal(t, accountState.Owner, account.OwnerAddress) + require.Equal(t, accountState.RootHash, base64.StdEncoding.EncodeToString(account.RootHash)) + + // Now we remove the account + err = chainSimulator.RemoveAccounts([]string{contractAddress}) + require.Nil(t, err) + + err = chainSimulator.GenerateBlocks(2) + require.Nil(t, err) + + account, _, err = nodeHandler.GetFacadeHandler().GetAccount(contractAddress, coreAPI.AccountQueryOptions{}) + require.Nil(t, err) + require.Equal(t, "0", account.Balance) + require.Equal(t, "0", account.DeveloperReward) + require.Equal(t, "", account.Code) + require.Equal(t, "", base64.StdEncoding.EncodeToString(account.CodeHash)) + require.Equal(t, "", base64.StdEncoding.EncodeToString(account.CodeMetadata)) + require.Equal(t, "", account.OwnerAddress) + require.Equal(t, "", base64.StdEncoding.EncodeToString(account.RootHash)) + + // Set the state again + err = chainSimulator.SetStateMultiple([]*dtos.AddressState{accountState}) + require.Nil(t, err) + + err = chainSimulator.GenerateBlocks(2) + require.Nil(t, err) + + account, _, err = nodeHandler.GetFacadeHandler().GetAccount(contractAddress, coreAPI.AccountQueryOptions{}) + require.Nil(t, err) + + require.Equal(t, accountState.Balance, account.Balance) + require.Equal(t, accountState.DeveloperRewards, account.DeveloperReward) + require.Equal(t, accountState.Code, account.Code) + require.Equal(t, accountState.CodeHash, base64.StdEncoding.EncodeToString(account.CodeHash)) + require.Equal(t, accountState.CodeMetadata, base64.StdEncoding.EncodeToString(account.CodeMetadata)) + require.Equal(t, accountState.Owner, account.OwnerAddress) + require.Equal(t, accountState.RootHash, base64.StdEncoding.EncodeToString(account.RootHash)) + +} + func TestChainSimulator_GetAccount(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") diff --git a/node/chainSimulator/components/testOnlyProcessingNode.go b/node/chainSimulator/components/testOnlyProcessingNode.go index 7b375ae08cb..1aec0201e6c 100644 --- a/node/chainSimulator/components/testOnlyProcessingNode.go +++ b/node/chainSimulator/components/testOnlyProcessingNode.go @@ -491,6 +491,18 @@ func (node *testOnlyProcessingNode) SetStateForAddress(address []byte, addressSt return err } +// RemoveAccount will remove the account for the given address +func (node *testOnlyProcessingNode) RemoveAccount(address []byte) error { + accountsAdapter := node.StateComponentsHolder.AccountsAdapter() + err := accountsAdapter.RemoveAccount(address) + if err != nil { + return err + } + + _, err = accountsAdapter.Commit() + return err +} + func setNonceAndBalanceForAccount(userAccount state.UserAccountHandler, nonce *uint64, balance string) error { if nonce != nil { // set nonce to zero diff --git a/node/chainSimulator/process/interface.go b/node/chainSimulator/process/interface.go index ee54998dc7f..d7b0f15820e 100644 --- a/node/chainSimulator/process/interface.go +++ b/node/chainSimulator/process/interface.go @@ -23,6 +23,7 @@ type NodeHandler interface { GetStatusCoreComponents() factory.StatusCoreComponentsHolder SetKeyValueForAddress(addressBytes []byte, state map[string]string) error SetStateForAddress(address []byte, state *dtos.AddressState) error + RemoveAccount(address []byte) error Close() error IsInterfaceNil() bool } diff --git a/testscommon/chainSimulator/nodeHandlerMock.go b/testscommon/chainSimulator/nodeHandlerMock.go index 52b72a17acc..9e0a2ca4d3b 100644 --- a/testscommon/chainSimulator/nodeHandlerMock.go +++ b/testscommon/chainSimulator/nodeHandlerMock.go @@ -23,6 +23,7 @@ type NodeHandlerMock struct { GetStatusCoreComponentsCalled func() factory.StatusCoreComponentsHolder SetKeyValueForAddressCalled func(addressBytes []byte, state map[string]string) error SetStateForAddressCalled func(address []byte, state *dtos.AddressState) error + RemoveAccountCalled func(address []byte) error CloseCalled func() error } @@ -122,6 +123,15 @@ func (mock *NodeHandlerMock) SetStateForAddress(address []byte, state *dtos.Addr return nil } +// RemoveAccount - +func (mock *NodeHandlerMock) RemoveAccount(address []byte) error { + if mock.RemoveAccountCalled != nil { + return mock.RemoveAccountCalled(address) + } + + return nil +} + // Close - func (mock *NodeHandlerMock) Close() error { if mock.CloseCalled != nil { From e4338c6574b0a120a002346c15f96c1ecd84d562 Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Tue, 23 Apr 2024 11:55:40 +0300 Subject: [PATCH 3/3] - removed useless empty line --- node/chainSimulator/chainSimulator_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/node/chainSimulator/chainSimulator_test.go b/node/chainSimulator/chainSimulator_test.go index e4092a16b9c..23bbb007f8b 100644 --- a/node/chainSimulator/chainSimulator_test.go +++ b/node/chainSimulator/chainSimulator_test.go @@ -376,7 +376,6 @@ func TestChainSimulator_SetEntireStateWithRemoval(t *testing.T) { require.Equal(t, accountState.CodeMetadata, base64.StdEncoding.EncodeToString(account.CodeMetadata)) require.Equal(t, accountState.Owner, account.OwnerAddress) require.Equal(t, accountState.RootHash, base64.StdEncoding.EncodeToString(account.RootHash)) - } func TestChainSimulator_GetAccount(t *testing.T) {