Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable epochs handler to data trie #4680

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cmd/node/config/enableEpochs.toml
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@
# FixOldTokenLiquidityEnableEpoch represents the epoch when the fix for old token liquidity is enabled
FixOldTokenLiquidityEnableEpoch = 1

# AutoBalanceDataTriesEnableEpoch represents the epoch when the data tries are automatically balanced by inserting at the hashed key instead of the normal key
AutoBalanceDataTriesEnableEpoch = 1

# SetSenderInEeiOutputTransferEnableEpoch represents the epoch when setting the sender in eei output transfers will be enabled
SetSenderInEeiOutputTransferEnableEpoch = 4

Expand Down
1 change: 1 addition & 0 deletions common/enablers/enableEpochsHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ func (handler *enableEpochsHandler) EpochConfirmed(epoch uint32, _ uint64) {
handler.setFlagValue(epoch >= handler.enableEpochsConfig.RefactorPeersMiniBlocksEnableEpoch, handler.refactorPeersMiniBlocksFlag, "refactorPeersMiniBlocksFlag")
handler.setFlagValue(epoch >= handler.enableEpochsConfig.FixAsyncCallBackArgsListEnableEpoch, handler.fixAsyncCallBackArgsList, "fixAsyncCallBackArgsList")
handler.setFlagValue(epoch >= handler.enableEpochsConfig.FixOldTokenLiquidityEnableEpoch, handler.fixOldTokenLiquidity, "fixOldTokenLiquidity")
handler.setFlagValue(epoch >= handler.enableEpochsConfig.AutoBalanceDataTriesEnableEpoch, handler.autoBalanceDataTriesFlag, "autoBalanceDataTriesFlag")
}

func (handler *enableEpochsHandler) setFlagValue(value bool, flag *atomic.Flag, flagName string) {
Expand Down
4 changes: 4 additions & 0 deletions common/enablers/enableEpochsHandler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func createEnableEpochsConfig() config.EnableEpochs {
CheckExecuteOnReadOnlyEnableEpoch: 70,
FixAsyncCallBackArgsListEnableEpoch: 71,
FixOldTokenLiquidityEnableEpoch: 72,
AutoBalanceDataTriesEnableEpoch: 73,
}
}

Expand Down Expand Up @@ -204,6 +205,7 @@ func TestNewEnableEpochsHandler_EpochConfirmed(t *testing.T) {
assert.True(t, handler.IsCheckExecuteOnReadOnlyFlagEnabled())
assert.True(t, handler.IsChangeDelegationOwnerFlagEnabled())
assert.True(t, handler.IsFixOldTokenLiquidityEnabled())
assert.True(t, handler.IsAutoBalanceDataTriesEnabled())
})
t.Run("flags with == condition should be set, along with all >=", func(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -299,6 +301,7 @@ func TestNewEnableEpochsHandler_EpochConfirmed(t *testing.T) {
assert.True(t, handler.IsChangeDelegationOwnerFlagEnabled())
assert.True(t, handler.IsFixAsyncCallBackArgsListFlagEnabled())
assert.True(t, handler.IsFixOldTokenLiquidityEnabled())
assert.True(t, handler.IsAutoBalanceDataTriesEnabled())
})
t.Run("flags with < should be set", func(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -389,5 +392,6 @@ func TestNewEnableEpochsHandler_EpochConfirmed(t *testing.T) {
assert.False(t, handler.IsChangeDelegationOwnerFlagEnabled())
assert.False(t, handler.IsFixAsyncCallBackArgsListFlagEnabled())
assert.False(t, handler.IsFixOldTokenLiquidityEnabled())
assert.False(t, handler.IsAutoBalanceDataTriesEnabled())
})
}
7 changes: 7 additions & 0 deletions common/enablers/epochFlags.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type epochFlagsHolder struct {
refactorPeersMiniBlocksFlag *atomic.Flag
fixAsyncCallBackArgsList *atomic.Flag
fixOldTokenLiquidity *atomic.Flag
autoBalanceDataTriesFlag *atomic.Flag
}

func newEpochFlagsHolder() *epochFlagsHolder {
Expand Down Expand Up @@ -167,6 +168,7 @@ func newEpochFlagsHolder() *epochFlagsHolder {
refactorPeersMiniBlocksFlag: &atomic.Flag{},
fixAsyncCallBackArgsList: &atomic.Flag{},
fixOldTokenLiquidity: &atomic.Flag{},
autoBalanceDataTriesFlag: &atomic.Flag{},
}
}

Expand Down Expand Up @@ -622,3 +624,8 @@ func (holder *epochFlagsHolder) IsFixAsyncCallBackArgsListFlagEnabled() bool {
func (holder *epochFlagsHolder) IsFixOldTokenLiquidityEnabled() bool {
return holder.fixOldTokenLiquidity.IsSet()
}

// IsAutoBalanceDataTriesEnabled returns true if autoBalanceDataTriesFlag is enabled
func (holder *epochFlagsHolder) IsAutoBalanceDataTriesEnabled() bool {
return holder.autoBalanceDataTriesFlag.IsSet()
}
1 change: 1 addition & 0 deletions common/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ type EnableEpochsHandler interface {
IsRefactorPeersMiniBlocksFlagEnabled() bool
IsFixAsyncCallBackArgsListFlagEnabled() bool
IsFixOldTokenLiquidityEnabled() bool
IsAutoBalanceDataTriesEnabled() bool

IsInterfaceNil() bool
}
1 change: 1 addition & 0 deletions config/epochConfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ type EnableEpochs struct {
FixOldTokenLiquidityEnableEpoch uint32
SetSenderInEeiOutputTransferEnableEpoch uint32
RefactorPeersMiniBlocksEnableEpoch uint32
AutoBalanceDataTriesEnableEpoch uint32
BLSMultiSignerEnableEpoch []MultiSignerConfig
}

Expand Down
17 changes: 14 additions & 3 deletions epochStart/metachain/baseRewards_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -826,15 +826,20 @@ func TestBaseRewardsCreator_isSystemDelegationSC(t *testing.T) {
require.False(t, isDelegationSCAddress)

// peer account
peerAccount, err := state.NewPeerAccount([]byte("addressPeer"), &hashingMocks.HasherMock{}, &testscommon.MarshalizerMock{})
peerAccount, err := state.NewPeerAccount([]byte("addressPeer"))
require.Nil(t, err)
err = rwd.userAccountsDB.SaveAccount(peerAccount)
require.Nil(t, err)
isDelegationSCAddress = rwd.isSystemDelegationSC(peerAccount.AddressBytes())
require.False(t, isDelegationSCAddress)

argsAccCreation := state.ArgsAccountCreation{
Hasher: &hashingMocks.HasherMock{},
Marshaller: &testscommon.MarshalizerMock{},
EnableEpochsHandler: &testscommon.EnableEpochsHandlerStub{},
}
// existing user account
userAccount, err := state.NewUserAccount([]byte("userAddress"), &hashingMocks.HasherMock{}, &testscommon.MarshalizerMock{})
userAccount, err := state.NewUserAccount([]byte("userAddress"), argsAccCreation)
require.Nil(t, err)

userAccount.SetDataTrie(&trieMock.TrieStub{
Expand Down Expand Up @@ -1141,7 +1146,13 @@ func getBaseRewardsArguments() BaseRewardsCreatorArgs {
storageManagerArgs.Hasher = hasher

trieFactoryManager, _ := trie.CreateTrieStorageManager(storageManagerArgs, options)
userAccountsDB := createAccountsDB(hasher, marshalizer, factory.NewAccountCreator(), trieFactoryManager)
argsAccCreator := state.ArgsAccountCreation{
Hasher: hasher,
Marshaller: marshalizer,
EnableEpochsHandler: &testscommon.EnableEpochsHandlerStub{},
}
accCreator, _ := factory.NewAccountCreator(argsAccCreator)
userAccountsDB := createAccountsDB(hasher, marshalizer, accCreator, trieFactoryManager)
shardCoordinator := mock.NewMultiShardsCoordinatorMock(2)
shardCoordinator.CurrentShard = core.MetachainShardId
shardCoordinator.ComputeIdCalled = func(address []byte) uint32 {
Expand Down
11 changes: 9 additions & 2 deletions epochStart/metachain/systemSCs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -912,8 +912,15 @@ func createFullArgumentsForSystemSCProcessing(enableEpochsConfig config.EnableEp
storageManagerArgs.CheckpointsStorer = trieStorer

trieFactoryManager, _ := trie.CreateTrieStorageManager(storageManagerArgs, options)
userAccountsDB := createAccountsDB(hasher, marshalizer, factory.NewAccountCreator(), trieFactoryManager)
peerAccountsDB := createAccountsDB(hasher, marshalizer, factory.NewPeerAccountCreator(), trieFactoryManager)
argsAccCreator := state.ArgsAccountCreation{
Hasher: hasher,
Marshaller: marshalizer,
EnableEpochsHandler: &testscommon.EnableEpochsHandlerStub{},
}
accCreator, _ := factory.NewAccountCreator(argsAccCreator)
peerAccCreator := factory.NewPeerAccountCreator()
userAccountsDB := createAccountsDB(hasher, marshalizer, accCreator, trieFactoryManager)
peerAccountsDB := createAccountsDB(hasher, marshalizer, peerAccCreator, trieFactoryManager)
en := forking.NewGenericEpochNotifier()
epochsConfig := &config.EpochConfig{
EnableEpochs: enableEpochsConfig,
Expand Down
9 changes: 8 additions & 1 deletion factory/processing/blockProcessorCreator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,17 @@ func Test_newBlockProcessorCreatorForMeta(t *testing.T) {
trieStorageManagers[trieFactory.UserAccountTrie] = storageManagerUser
trieStorageManagers[trieFactory.PeerAccountTrie] = storageManagerPeer

argsAccCreator := state.ArgsAccountCreation{
Hasher: coreComponents.Hasher(),
Marshaller: coreComponents.InternalMarshalizer(),
EnableEpochsHandler: coreComponents.EnableEpochsHandler(),
}
accCreator, _ := factoryState.NewAccountCreator(argsAccCreator)

accounts, err := createAccountAdapter(
&mock.MarshalizerMock{},
&hashingMocks.HasherMock{},
factoryState.NewAccountCreator(),
accCreator,
trieStorageManagers[trieFactory.UserAccountTrie],
)
require.Nil(t, err)
Expand Down
7 changes: 6 additions & 1 deletion factory/processing/processComponents.go
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,12 @@ func (pcf *processComponentsFactory) indexGenesisAccounts() error {
}

func (pcf *processComponentsFactory) unmarshalUserAccount(address []byte, userAccountsBytes []byte) (state.UserAccountHandler, error) {
userAccount, err := state.NewUserAccount(address, pcf.coreData.Hasher(), pcf.coreData.InternalMarshalizer())
argsAccCreation := state.ArgsAccountCreation{
Hasher: pcf.coreData.Hasher(),
Marshaller: pcf.coreData.InternalMarshalizer(),
EnableEpochsHandler: pcf.coreData.EnableEpochsHandler(),
}
userAccount, err := state.NewUserAccount(address, argsAccCreation)
if err != nil {
return nil, err
}
Expand Down
11 changes: 10 additions & 1 deletion factory/state/stateComponents.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,16 @@ func (scf *stateComponentsFactory) Create() (*stateComponents, error) {
}

func (scf *stateComponentsFactory) createAccountsAdapters(triesContainer common.TriesHolder) (state.AccountsAdapter, state.AccountsAdapter, state.AccountsRepository, error) {
accountFactory := factoryState.NewAccountCreator()
argsAccCreator := state.ArgsAccountCreation{
Hasher: scf.core.Hasher(),
Marshaller: scf.core.InternalMarshalizer(),
EnableEpochsHandler: scf.core.EnableEpochsHandler(),
}
accountFactory, err := factoryState.NewAccountCreator(argsAccCreator)
if err != nil {
return nil, nil, nil, err
}

merkleTrie := triesContainer.Get([]byte(trieFactory.UserAccountTrie))
storagePruning, err := scf.newStoragePruningManager()
if err != nil {
Expand Down
16 changes: 14 additions & 2 deletions genesis/process/genesisBlockCreator.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/ElrondNetwork/elrond-go/process"
"github.com/ElrondNetwork/elrond-go/process/smartContract/hooks"
"github.com/ElrondNetwork/elrond-go/sharding"
"github.com/ElrondNetwork/elrond-go/state"
factoryState "github.com/ElrondNetwork/elrond-go/state/factory"
"github.com/ElrondNetwork/elrond-go/statusHandler"
"github.com/ElrondNetwork/elrond-go/storage"
Expand Down Expand Up @@ -114,6 +115,7 @@ func (gbc *genesisBlockCreator) createHardForkImportHandler() error {
ShardID: gbc.arg.ShardCoordinator.SelfId(),
StorageConfig: gbc.arg.HardForkConfig.ImportStateStorageConfig,
TrieStorageManagers: gbc.arg.TrieStorageManagers,
EnableEpochsHandler: gbc.arg.Core.EnableEpochsHandler(),
}
importHandler, err := hardfork.NewStateImport(argsHardForkImport)
if err != nil {
Expand Down Expand Up @@ -475,12 +477,22 @@ func (gbc *genesisBlockCreator) getNewArgForShard(shardID uint32) (ArgsGenesisBl
newArgument.Data = newArgument.Data.Clone().(dataComponentsHandler)
return newArgument, nil
}

newArgument := gbc.arg // copy the arguments

argsAccCreator := state.ArgsAccountCreation{
Hasher: newArgument.Core.Hasher(),
Marshaller: newArgument.Core.InternalMarshalizer(),
EnableEpochsHandler: newArgument.Core.EnableEpochsHandler(),
}
accCreator, err := factoryState.NewAccountCreator(argsAccCreator)
if err != nil {
return ArgsGenesisBlockCreator{}, err
}

newArgument.Accounts, err = createAccountAdapter(
newArgument.Core.InternalMarshalizer(),
newArgument.Core.Hasher(),
factoryState.NewAccountCreator(),
accCreator,
gbc.arg.TrieStorageManagers[triesFactory.UserAccountTrie],
)
if err != nil {
Expand Down
11 changes: 9 additions & 2 deletions genesis/process/genesisBlockCreator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,18 @@ func createMockArgument(
SelfShardId: 0,
}

var err error
argsAccCreator := state.ArgsAccountCreation{
Hasher: &hashingMocks.HasherMock{},
Marshaller: &mock.MarshalizerMock{},
EnableEpochsHandler: &testscommon.EnableEpochsHandlerStub{},
}
accCreator, err := factoryState.NewAccountCreator(argsAccCreator)
require.Nil(t, err)

arg.Accounts, err = createAccountAdapter(
&mock.MarshalizerMock{},
&hashingMocks.HasherMock{},
factoryState.NewAccountCreator(),
accCreator,
trieStorageManagers[factory.UserAccountTrie],
)
require.Nil(t, err)
Expand Down
17 changes: 14 additions & 3 deletions integrationTests/state/stateTrie/stateTrie_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1057,12 +1057,17 @@ func createAccounts(
maxTrieLevelInMemory := uint(5)
tr, _ := trie.NewTrie(trieStorage, integrationTests.TestMarshalizer, integrationTests.TestHasher, maxTrieLevelInMemory)
spm, _ := storagePruningManager.NewStoragePruningManager(ewl, 10)

argsAccCreator := state.ArgsAccountCreation{
Hasher: integrationTests.TestHasher,
Marshaller: integrationTests.TestMarshalizer,
EnableEpochsHandler: &testscommon.EnableEpochsHandlerStub{},
}
accCreator, _ := factory.NewAccountCreator(argsAccCreator)
argsAccountsDB := state.ArgsAccountsDB{
Trie: tr,
Hasher: integrationTests.TestHasher,
Marshaller: integrationTests.TestMarshalizer,
AccountFactory: factory.NewAccountCreator(),
AccountFactory: accCreator,
StoragePruningManager: spm,
ProcessingMode: common.Normal,
ProcessStatusHandler: &testscommon.ProcessStatusHandlerStub{},
Expand Down Expand Up @@ -2401,12 +2406,18 @@ func createAccountsDBTestSetup() *state.AccountsDB {
maxTrieLevelInMemory := uint(5)
tr, _ := trie.NewTrie(trieStorage, integrationTests.TestMarshalizer, integrationTests.TestHasher, maxTrieLevelInMemory)
spm, _ := storagePruningManager.NewStoragePruningManager(ewl, 10)
argsAccCreator := state.ArgsAccountCreation{
Hasher: integrationTests.TestHasher,
Marshaller: integrationTests.TestMarshalizer,
EnableEpochsHandler: &testscommon.EnableEpochsHandlerStub{},
}
accCreator, _ := factory.NewAccountCreator(argsAccCreator)

argsAccountsDB := state.ArgsAccountsDB{
Trie: tr,
Hasher: integrationTests.TestHasher,
Marshaller: integrationTests.TestMarshalizer,
AccountFactory: factory.NewAccountCreator(),
AccountFactory: accCreator,
StoragePruningManager: spm,
ProcessingMode: common.Normal,
ProcessStatusHandler: &testscommon.ProcessStatusHandlerStub{},
Expand Down
33 changes: 26 additions & 7 deletions integrationTests/testInitializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,11 +436,20 @@ func CreateTrieStorageManager(store storage.Storer) (common.StorageManager, stor
func CreateAccountsDB(
accountType Type,
trieStorageManager common.StorageManager,
) (*state.AccountsDB, common.Trie) {
return CreateAccountsDBWithEnableEpochsHandler(accountType, trieStorageManager, &testscommon.EnableEpochsHandlerStub{})
}

// CreateAccountsDBWithEnableEpochsHandler creates a new AccountsDb with the given enableEpochsHandler
func CreateAccountsDBWithEnableEpochsHandler(
accountType Type,
trieStorageManager common.StorageManager,
enableEpochsHandler common.EnableEpochsHandler,
) (*state.AccountsDB, common.Trie) {
tr, _ := trie.NewTrie(trieStorageManager, TestMarshalizer, TestHasher, maxTrieLevelInMemory)

ewl, _ := evictionWaitingList.NewEvictionWaitingList(100, database.NewMemDB(), TestMarshalizer)
accountFactory := getAccountFactory(accountType)
accountFactory, _ := getAccountFactory(accountType, enableEpochsHandler)
spm, _ := storagePruningManager.NewStoragePruningManager(ewl, 10)
args := state.ArgsAccountsDB{
Trie: tr,
Expand All @@ -457,14 +466,19 @@ func CreateAccountsDB(
return adb, tr
}

func getAccountFactory(accountType Type) state.AccountFactory {
func getAccountFactory(accountType Type, enableEpochsHandler common.EnableEpochsHandler) (state.AccountFactory, error) {
switch accountType {
case UserAccount:
return factory.NewAccountCreator()
argsAccCreator := state.ArgsAccountCreation{
Hasher: TestHasher,
Marshaller: TestMarshalizer,
EnableEpochsHandler: enableEpochsHandler,
}
return factory.NewAccountCreator(argsAccCreator)
case ValidatorAccount:
return factory.NewPeerAccountCreator()
return factory.NewPeerAccountCreator(), nil
default:
return nil
return nil, fmt.Errorf("invalid account type provided")
}
}

Expand Down Expand Up @@ -803,7 +817,7 @@ func CreateGenesisMetaBlock(

newBlkc, _ := blockchain.NewMetaChain(&statusHandlerMock.AppStatusHandlerStub{})
trieStorage, _ := CreateTrieStorageManager(CreateMemUnit())
newAccounts, _ := CreateAccountsDB(UserAccount, trieStorage)
newAccounts, _ := CreateAccountsDBWithEnableEpochsHandler(UserAccount, trieStorage, coreComponents.EnableEpochsHandler())

argsMetaGenesis.ShardCoordinator = newShardCoordinator
argsMetaGenesis.Accounts = newAccounts
Expand Down Expand Up @@ -900,7 +914,12 @@ func GenerateAddressJournalAccountAccountsDB() ([]byte, state.UserAccountHandler
adr := CreateRandomAddress()
trieStorage, _ := CreateTrieStorageManager(CreateMemUnit())
adb, _ := CreateAccountsDB(UserAccount, trieStorage)
account, _ := state.NewUserAccount(adr, TestHasher, TestMarshaller)
argsAccCreation := state.ArgsAccountCreation{
Hasher: TestHasher,
Marshaller: TestMarshaller,
EnableEpochsHandler: &testscommon.EnableEpochsHandlerStub{},
}
account, _ := state.NewUserAccount(adr, argsAccCreation)

return adr, account, adb
}
Expand Down
8 changes: 4 additions & 4 deletions integrationTests/testProcessorNode.go
Original file line number Diff line number Diff line change
Expand Up @@ -522,11 +522,11 @@ func (tpn *TestProcessorNode) initAccountDBsWithPruningStorer() {
trieStorageManager := CreateTrieStorageManagerWithPruningStorer(tpn.ShardCoordinator, tpn.EpochStartNotifier)
tpn.TrieContainer = state.NewDataTriesHolder()
var stateTrie common.Trie
tpn.AccntState, stateTrie = CreateAccountsDB(UserAccount, trieStorageManager)
tpn.AccntState, stateTrie = CreateAccountsDBWithEnableEpochsHandler(UserAccount, trieStorageManager, tpn.EnableEpochsHandler)
tpn.TrieContainer.Put([]byte(trieFactory.UserAccountTrie), stateTrie)

var peerTrie common.Trie
tpn.PeerState, peerTrie = CreateAccountsDB(ValidatorAccount, trieStorageManager)
tpn.PeerState, peerTrie = CreateAccountsDBWithEnableEpochsHandler(ValidatorAccount, trieStorageManager, tpn.EnableEpochsHandler)
tpn.TrieContainer.Put([]byte(trieFactory.PeerAccountTrie), peerTrie)

tpn.TrieStorageManagers = make(map[string]common.StorageManager)
Expand All @@ -538,11 +538,11 @@ func (tpn *TestProcessorNode) initAccountDBs(store storage.Storer) {
trieStorageManager, _ := CreateTrieStorageManager(store)
tpn.TrieContainer = state.NewDataTriesHolder()
var stateTrie common.Trie
tpn.AccntState, stateTrie = CreateAccountsDB(UserAccount, trieStorageManager)
tpn.AccntState, stateTrie = CreateAccountsDBWithEnableEpochsHandler(UserAccount, trieStorageManager, tpn.EnableEpochsHandler)
tpn.TrieContainer.Put([]byte(trieFactory.UserAccountTrie), stateTrie)

var peerTrie common.Trie
tpn.PeerState, peerTrie = CreateAccountsDB(ValidatorAccount, trieStorageManager)
tpn.PeerState, peerTrie = CreateAccountsDBWithEnableEpochsHandler(ValidatorAccount, trieStorageManager, tpn.EnableEpochsHandler)
tpn.TrieContainer.Put([]byte(trieFactory.PeerAccountTrie), peerTrie)

tpn.TrieStorageManagers = make(map[string]common.StorageManager)
Expand Down
Loading