diff --git a/Makefile b/Makefile index 16a8b61f..bf38da18 100644 --- a/Makefile +++ b/Makefile @@ -168,6 +168,13 @@ start-network-babe: cd ../../../..; \ WASMTIME_BACKTRACE_DETAILS=1 RUST_LOG=runtime=trace ./target/release/substrate-node --dev --execution=wasm +start-network: + cp build/runtime.wasm polkadot-sdk/substrate/bin/node-template/runtime.wasm; \ + cd polkadot-sdk/substrate/bin/node-template/node; \ + cargo build --release; \ + cd ../../../..; \ + WASMTIME_BACKTRACE_DETAILS=1 RUST_LOG=runtime=trace ./target/release/node-template --dev --execution=wasm + parachain-build: cp $(BUILD_PATH)/parachain.wasm polkadot-sdk/cumulus/polkadot-parachain/src/chain_spec/runtime.wasm; \ cd polkadot-sdk; \ diff --git a/api/benchmarking/module.go b/api/benchmarking/module.go index cf9494bd..9e12c0b0 100644 --- a/api/benchmarking/module.go +++ b/api/benchmarking/module.go @@ -275,6 +275,7 @@ func (m Module) originAndMaybeAccount(benchmarkConfig benchmarking.BenchmarkConf func (m Module) whitelistWellKnownKeys() { keySystemHash := m.hashing.Twox128([]byte("System")) + keyBalancesHash := m.hashing.Twox128([]byte("Balances")) keyBlockWeight := m.hashing.Twox128([]byte("BlockWeight")) keyExecutionPhaseHash := m.hashing.Twox128([]byte("ExecutionPhase")) keyEventCountHash := m.hashing.Twox128([]byte("EventCount")) @@ -282,7 +283,7 @@ func (m Module) whitelistWellKnownKeys() { keyNumberHash := m.hashing.Twox128([]byte("Number")) keyTotalIssuanceHash := m.hashing.Twox128([]byte("TotalIssuance")) - benchmarking.SetWhitelist(append(keySystemHash, keyTotalIssuanceHash...)) + benchmarking.SetWhitelist(append(keyBalancesHash, keyTotalIssuanceHash...)) benchmarking.SetWhitelist(append(keySystemHash, keyBlockWeight...)) benchmarking.SetWhitelist(append(keySystemHash, keyNumberHash...)) benchmarking.SetWhitelist(append(keySystemHash, keyExecutionPhaseHash...)) diff --git a/api/metadata/module.go b/api/metadata/module.go index 1d0bb1bd..ee8d1c1b 100644 --- a/api/metadata/module.go +++ b/api/metadata/module.go @@ -299,6 +299,14 @@ func (m Module) basicTypes() sc.Sequence[primitives.MetadataType] { primitives.NewMetadataTypeParameter(metadata.TypesH256, "T"), ), + primitives.NewMetadataType( + metadata.TypesCompactU128, + "compact U128", + primitives.NewMetadataTypeDefinitionCompact( + sc.ToCompact(metadata.PrimitiveTypesU128), + ), + ), + primitives.NewMetadataTypeWithPath(metadata.TypesAddress32, "Address32", sc.Sequence[sc.Str]{"sp_core", "crypto", "AccountId32"}, primitives.NewMetadataTypeDefinitionComposite( sc.Sequence[primitives.MetadataTypeDefinitionField]{primitives.NewMetadataTypeDefinitionFieldWithName(metadata.TypesFixedSequence32U8, "[u8; 32]")}, )), @@ -355,8 +363,8 @@ func (m Module) basicTypes() sc.Sequence[primitives.MetadataType] { sc.Sequence[primitives.MetadataTypeDefinitionField]{ primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "free", "Balance"), primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "reserved", "Balance"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "misc_frozen", "Balance"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "fee_frozen", "Balance"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "frozen", "Balance"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "flags", "ExtraFlags"), }, )), primitives.NewMetadataTypeWithPath(metadata.TypesAccountInfo, "AccountInfo", sc.Sequence[sc.Str]{"frame_system", "AccountInfo"}, primitives.NewMetadataTypeDefinitionComposite( @@ -609,17 +617,17 @@ func (m Module) basicTypes() sc.Sequence[primitives.MetadataType] { primitives.NewMetadataTypeWithPath(metadata.TypesTokenError, "TokenError", sc.Sequence[sc.Str]{"sp_runtime", "TokenError"}, primitives.NewMetadataTypeDefinitionVariant( sc.Sequence[primitives.MetadataDefinitionVariant]{ primitives.NewMetadataDefinitionVariant( - "NoFunds", + "FundsUnavailable", sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - primitives.TokenErrorNoFunds, - "TokenError.NoFunds"), + primitives.TokenErrorFundsUnavailable, + "TokenError.FundsUnavailable"), primitives.NewMetadataDefinitionVariant( - "WouldDie", + "OnlyProvider", sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - primitives.TokenErrorWouldDie, - "TokenError.WouldDie"), + primitives.TokenErrorOnlyProvider, + "TokenError.OnlyProvider"), primitives.NewMetadataDefinitionVariant( - "Mandatory", + "BelowMinimum", sc.Sequence[primitives.MetadataTypeDefinitionField]{}, primitives.TokenErrorBelowMinimum, "TokenError.BelowMinimum"), @@ -643,6 +651,21 @@ func (m Module) basicTypes() sc.Sequence[primitives.MetadataType] { sc.Sequence[primitives.MetadataTypeDefinitionField]{}, primitives.TokenErrorUnsupported, "TokenError.Unsupported"), + primitives.NewMetadataDefinitionVariant( + "CannotCreateHold", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + primitives.TokenErrorCannotCreateHold, + "TokenError.CannotCreateHold"), + primitives.NewMetadataDefinitionVariant( + "NotExpendable", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + primitives.TokenErrorNotExpendable, + "TokenError.NotExpendable"), + primitives.NewMetadataDefinitionVariant( + "Blocked", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + primitives.TokenErrorBlocked, + "TokenError.Blocked"), })), primitives.NewMetadataTypeWithPath(metadata.TypesArithmeticError, "ArithmeticError", sc.Sequence[sc.Str]{"sp_arithmetic", "ArithmeticError"}, primitives.NewMetadataTypeDefinitionVariant( sc.Sequence[primitives.MetadataDefinitionVariant]{ diff --git a/build/parachain.wasm b/build/parachain.wasm index d019f55d..05825bd5 100755 Binary files a/build/parachain.wasm and b/build/parachain.wasm differ diff --git a/build/runtime-benchmarks.wasm b/build/runtime-benchmarks.wasm index adc0c89e..e469a2d1 100755 Binary files a/build/runtime-benchmarks.wasm and b/build/runtime-benchmarks.wasm differ diff --git a/build/runtime.wasm b/build/runtime.wasm index 1cd7657d..e469a2d1 100755 Binary files a/build/runtime.wasm and b/build/runtime.wasm differ diff --git a/constants/currency.go b/constants/currency.go index a9be5d08..39ab71b3 100644 --- a/constants/currency.go +++ b/constants/currency.go @@ -13,5 +13,6 @@ const ( var ( Zero = sc.NewU128(0) + One = sc.NewU128(1) DefaultTip = Zero ) diff --git a/constants/metadata/metadata.go b/constants/metadata/metadata.go index 1688e400..19a8901d 100644 --- a/constants/metadata/metadata.go +++ b/constants/metadata/metadata.go @@ -53,6 +53,7 @@ const ( TypesBalancesEvent TypesBalanceStatus + TypesBalancesAdjustDirection TypesVecTopics TypesLastRuntimeUpgradeInfo TypesSystemErrors diff --git a/docs/docs/development/modules.md b/docs/docs/development/modules.md index c645d6a6..2cb20433 100644 --- a/docs/docs/development/modules.md +++ b/docs/docs/development/modules.md @@ -37,11 +37,11 @@ These modules provide features than can be useful for your blockchain and can be In addition to functional modules, which are useful for any blockchain, there are modules that provide features specifically for blockchain integration with a relay chain. -| Name | Description | -|-----------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------| -| [aura_ext](https://github.com/limechain/gosemble/tree/develop/frame/aura_ext) | Provides AURA Consensus for parachains. | -| [parachain_info](https://github.com/limechain/gosemble/tree/develop/frame/parachain_info) | Stores the parachain id. | -| [parachain_system](https://github.com/limechain/gosemble/tree/develop/frame/parachain_system) | Provides basic functionality for cumulus-based parachains. Does not process messages. | +| Name | Description | +|-----------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------| +| [aura_ext](https://github.com/limechain/gosemble/tree/develop/frame/aura_ext) | Provides AURA Consensus for parachains. | +| [parachain_info](https://github.com/limechain/gosemble/tree/develop/frame/parachain_info) | Stores the parachain id. | +| [parachain_system](https://github.com/limechain/gosemble/tree/develop/frame/parachain_system) | Provides basic functionality for cumulus-based parachains. Does not process XCM messages. | ## Structure diff --git a/frame/balances/call_force_adjust_total_issuance.go b/frame/balances/call_force_adjust_total_issuance.go new file mode 100644 index 00000000..d08abe39 --- /dev/null +++ b/frame/balances/call_force_adjust_total_issuance.go @@ -0,0 +1,135 @@ +package balances + +import ( + "bytes" + + sc "github.com/LimeChain/goscale" + "github.com/LimeChain/gosemble/constants" + "github.com/LimeChain/gosemble/frame/balances/types" + primitives "github.com/LimeChain/gosemble/primitives/types" +) + +type callForceAdjustTotalIssuance struct { + primitives.Callable + storage *storage + eventDepositor primitives.EventDepositor +} + +func newCallForceAdjustTotalIssuance(moduleId sc.U8, functionId sc.U8, eventDepositor primitives.EventDepositor, storage *storage) primitives.Call { + return callForceAdjustTotalIssuance{ + Callable: primitives.Callable{ + ModuleId: moduleId, + FunctionId: functionId, + Arguments: sc.NewVaryingData(types.AdjustDirection{}, sc.Compact{Number: sc.U128{}}), + }, + eventDepositor: eventDepositor, + storage: storage, + } +} + +func (c callForceAdjustTotalIssuance) DecodeArgs(buffer *bytes.Buffer) (primitives.Call, error) { + direction, err := types.DecodeAdjustDirection(buffer) + if err != nil { + return nil, err + } + delta, err := sc.DecodeCompact[sc.U128](buffer) + if err != nil { + return nil, err + } + c.Arguments = sc.NewVaryingData( + direction, + delta, + ) + + return c, nil +} + +func (c callForceAdjustTotalIssuance) Encode(buffer *bytes.Buffer) error { + return c.Callable.Encode(buffer) +} + +func (c callForceAdjustTotalIssuance) Bytes() []byte { + return c.Callable.Bytes() +} + +func (c callForceAdjustTotalIssuance) ModuleIndex() sc.U8 { return c.Callable.ModuleIndex() } + +func (c callForceAdjustTotalIssuance) FunctionIndex() sc.U8 { return c.Callable.FunctionIndex() } + +func (c callForceAdjustTotalIssuance) Args() sc.VaryingData { return c.Callable.Args() } + +func (c callForceAdjustTotalIssuance) BaseWeight() primitives.Weight { + return callForceAdjustTotalIssuanceWeight() +} + +func (_ callForceAdjustTotalIssuance) WeighData(baseWeight primitives.Weight) primitives.Weight { + return primitives.WeightFromParts(baseWeight.RefTime, 0) +} + +func (_ callForceAdjustTotalIssuance) ClassifyDispatch(baseWeight primitives.Weight) primitives.DispatchClass { + return primitives.NewDispatchClassNormal() +} + +func (_ callForceAdjustTotalIssuance) PaysFee(baseWeight primitives.Weight) primitives.Pays { + return primitives.PaysYes +} + +func (_ callForceAdjustTotalIssuance) Docs() string { + return "Adjust the total issuance in a saturating way. Can only be called by root and always needs a positive `delta`." +} + +func (c callForceAdjustTotalIssuance) Dispatch(origin primitives.RuntimeOrigin, args sc.VaryingData) (primitives.PostDispatchInfo, error) { + if !origin.IsRootOrigin() { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorBadOrigin() + } + direction, ok := args[0].(types.AdjustDirection) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid direction value when dispatching callForceAdjustTotalIssuance") + } + deltaCompact, ok := args[1].(sc.Compact) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid amount value when dispatching call force free") + } + + delta, ok := deltaCompact.Number.(sc.U128) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid Compact field delta when dispatch call_force_adjust_total_issuance") + } + + if delta.Lte(constants.Zero) { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorModule(primitives.CustomModuleError{ + Index: c.ModuleId, + Err: sc.U32(ErrorDeltaZero), + Message: sc.NewOption[sc.Str](nil), + }) + } + + totalIssuance, err := c.storage.TotalIssuance.Get() + if err != nil { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther(sc.Str(err.Error())) + } + + var newIssuance sc.U128 + if direction.IsIncrease() { + newIssuance = sc.SaturatingAddU128(totalIssuance, delta) + } else { + newIssuance = sc.SaturatingSubU128(totalIssuance, delta) + } + + inactiveIssuance, err := c.storage.InactiveIssuance.Get() + if err != nil { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther(sc.Str(err.Error())) + } + + if inactiveIssuance.Gt(newIssuance) { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorModule(primitives.CustomModuleError{ + Index: c.ModuleId, + Err: sc.U32(ErrorIssuanceDeactivated), + Message: sc.NewOption[sc.Str](nil), + }) + } + c.storage.TotalIssuance.Put(newIssuance) + c.eventDepositor.DepositEvent(newEventTotalIssuanceForced(c.ModuleId, totalIssuance, newIssuance)) + + return primitives.PostDispatchInfo{}, nil +} diff --git a/frame/balances/call_force_adjust_total_issuance_weight.go b/frame/balances/call_force_adjust_total_issuance_weight.go new file mode 100644 index 00000000..4e1373b5 --- /dev/null +++ b/frame/balances/call_force_adjust_total_issuance_weight.go @@ -0,0 +1,7 @@ +package balances + +import primitives "github.com/LimeChain/gosemble/primitives/types" + +func callForceAdjustTotalIssuanceWeight() primitives.Weight { + return primitives.WeightFromParts(6507000, 0) +} diff --git a/frame/balances/call_force_free.go b/frame/balances/call_force_free.go deleted file mode 100644 index d5a0633c..00000000 --- a/frame/balances/call_force_free.go +++ /dev/null @@ -1,160 +0,0 @@ -package balances - -import ( - "bytes" - "errors" - - sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/constants" - "github.com/LimeChain/gosemble/primitives/log" - "github.com/LimeChain/gosemble/primitives/types" - primitives "github.com/LimeChain/gosemble/primitives/types" -) - -type callForceFree struct { - primitives.Callable - transfer - logger log.RuntimeLogger -} - -func newCallForceFree(moduleId sc.U8, functionId sc.U8, storedMap primitives.StoredMap, constants *consts, mutator accountMutator, logger log.RuntimeLogger) primitives.Call { - call := callForceFree{ - Callable: primitives.Callable{ - ModuleId: moduleId, - FunctionId: functionId, - Arguments: sc.NewVaryingData(types.MultiAddress{}, sc.U128{}), - }, - transfer: newTransfer(moduleId, storedMap, constants, mutator), - logger: logger, - } - - return call -} - -func (c callForceFree) DecodeArgs(buffer *bytes.Buffer) (primitives.Call, error) { - who, err := types.DecodeMultiAddress(buffer) - if err != nil { - return nil, err - } - amount, err := sc.DecodeU128(buffer) - if err != nil { - return nil, err - } - c.Arguments = sc.NewVaryingData( - who, - amount, - ) - return c, nil -} - -func (c callForceFree) Encode(buffer *bytes.Buffer) error { - return c.Callable.Encode(buffer) -} - -func (c callForceFree) Bytes() []byte { - return c.Callable.Bytes() -} - -func (c callForceFree) ModuleIndex() sc.U8 { - return c.Callable.ModuleIndex() -} - -func (c callForceFree) FunctionIndex() sc.U8 { - return c.Callable.FunctionIndex() -} - -func (c callForceFree) Args() sc.VaryingData { - return c.Callable.Args() -} - -func (c callForceFree) BaseWeight() types.Weight { - return callForceFreeWeight(c.constants.DbWeight) -} - -func (_ callForceFree) WeighData(baseWeight types.Weight) types.Weight { - return types.WeightFromParts(baseWeight.RefTime, 0) -} - -func (_ callForceFree) ClassifyDispatch(baseWeight types.Weight) types.DispatchClass { - return types.NewDispatchClassNormal() -} - -func (_ callForceFree) PaysFee(baseWeight types.Weight) types.Pays { - return types.PaysYes -} - -func (_ callForceFree) Docs() string { - return "Unreserve some balance from a user by force." -} - -func (c callForceFree) Dispatch(origin types.RuntimeOrigin, args sc.VaryingData) (types.PostDispatchInfo, error) { - amount, ok := args[1].(sc.U128) - if !ok { - return types.PostDispatchInfo{}, errors.New("invalid amount value when dispatching call force free") - } - return types.PostDispatchInfo{}, c.forceFree(origin, args[0].(types.MultiAddress), amount) -} - -// forceFree frees some balance from a user by force. -// Can only be called by ROOT. -// Consider Substrate fn force_unreserve -func (c callForceFree) forceFree(origin types.RawOrigin, who types.MultiAddress, amount sc.U128) error { - if !origin.IsRootOrigin() { - return types.NewDispatchErrorBadOrigin() - } - - target, err := types.Lookup(who) - if err != nil { - c.logger.Debugf("Failed to lookup [%s]", who.Bytes()) - return types.NewDispatchErrorCannotLookup() - } - - if _, err := c.force(target, amount); err != nil { - return types.NewDispatchErrorOther(sc.Str(err.Error())) - } - - return nil -} - -// forceFree frees funds, returning the amount that has not been freed. -func (c callForceFree) force(who primitives.AccountId, value sc.U128) (sc.U128, error) { - if value.Eq(constants.Zero) { - return constants.Zero, nil - } - - account, err := c.storedMap.Get(who) - if err != nil { - return sc.U128{}, err - } - - totalBalance := account.Data.Total() - if totalBalance.Eq(constants.Zero) { - return value, nil - } - - result, err := c.accountMutator.tryMutateAccount( - who, - func(account *types.AccountData, _ bool) (sc.Encodable, error) { - return removeReserveAndFree(account, value), nil - }, - ) - - if err != nil { - return sc.NewU128(0), err - } - - actual := result.(primitives.Balance) - c.storedMap.DepositEvent(newEventUnreserved(c.ModuleId, who, actual)) - - return value.Sub(actual), nil -} - -// removeReserveAndFree frees reserved value from the account. -func removeReserveAndFree(account *types.AccountData, value sc.U128) primitives.Balance { - actual := sc.Min128(account.Reserved, value) - account.Reserved = account.Reserved.Sub(actual) - - account.Free = sc.SaturatingAddU128(account.Free, actual) - - return actual -} diff --git a/frame/balances/call_force_free_test.go b/frame/balances/call_force_free_test.go deleted file mode 100644 index 3abf8a5f..00000000 --- a/frame/balances/call_force_free_test.go +++ /dev/null @@ -1,295 +0,0 @@ -package balances - -import ( - "bytes" - "errors" - "testing" - - sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/constants" - "github.com/LimeChain/gosemble/mocks" - primitives "github.com/LimeChain/gosemble/primitives/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -const ( - moduleId = 5 -) - -var ( - accountInfo = primitives.AccountInfo{ - Data: primitives.AccountData{ - Free: sc.NewU128(4), - Reserved: primitives.Balance{}, - MiscFrozen: primitives.Balance{}, - FeeFrozen: primitives.Balance{}, - }, - } - dbWeight = primitives.RuntimeDbWeight{ - Read: 1, - Write: 2, - } - baseWeight = primitives.WeightFromParts(124, 123) - targetAddress = primitives.NewMultiAddressId(constants.ZeroAccountId) - targetValue = sc.NewU128(5) - mockTypeMutateAccountDataBool = mock.AnythingOfType("func(*types.AccountData, bool) (goscale.Encodable, error)") - argsBytesCallForceFree = sc.NewVaryingData(primitives.MultiAddress{}, sc.U128{}).Bytes() - mockStoredMap *mocks.StoredMap - errPanic = errors.New("panic") -) - -func Test_Call_ForceFree_new(t *testing.T) { - target := setupCallForceFree() - expected := callForceFree{ - Callable: primitives.Callable{ - ModuleId: moduleId, - FunctionId: functionForceFreeIndex, - Arguments: sc.NewVaryingData(primitives.MultiAddress{}, sc.U128{}), - }, - transfer: transfer{ - moduleId: moduleId, - storedMap: mockStoredMap, - constants: testConstants, - accountMutator: mockMutator, - }, - logger: logger, - } - - assert.Equal(t, expected, target) -} - -func Test_Call_ForceFree_DecodeArgs(t *testing.T) { - amount := sc.NewU128(5) - buf := bytes.NewBuffer(append(targetAddress.Bytes(), amount.Bytes()...)) - - target := setupCallForceFree() - call, err := target.DecodeArgs(buf) - assert.Nil(t, err) - - assert.Equal(t, sc.NewVaryingData(targetAddress, amount), call.Args()) -} - -func Test_Call_ForceFree_Encode(t *testing.T) { - target := setupCallForceFree() - expectedBuffer := bytes.NewBuffer(append([]byte{moduleId, functionForceFreeIndex}, argsBytesCallForceFree...)) - buf := &bytes.Buffer{} - - err := target.Encode(buf) - - assert.NoError(t, err) - assert.Equal(t, expectedBuffer, buf) -} - -func Test_Call_ForceFree_Bytes(t *testing.T) { - expected := append([]byte{moduleId, functionForceFreeIndex}, argsBytesCallForceFree...) - - target := setupCallForceFree() - - assert.Equal(t, expected, target.Bytes()) -} - -func Test_Call_ForceFree_ModuleIndex(t *testing.T) { - target := setupCallForceFree() - - assert.Equal(t, sc.U8(moduleId), target.ModuleIndex()) -} - -func TestCall_ForceFree_FunctionIndex(t *testing.T) { - target := setupCallForceFree() - - assert.Equal(t, sc.U8(functionForceFreeIndex), target.FunctionIndex()) -} - -func Test_Call_ForceFree_EncodeWithArgs(t *testing.T) { - expectedBuffer := bytes.NewBuffer([]byte{moduleId, functionForceFreeIndex}) - bArgs := append(targetAddress.Bytes(), targetValue.Bytes()...) - expectedBuffer.Write(bArgs) - - buf := bytes.NewBuffer(bArgs) - - target := setupCallForceFree() - call, err := target.DecodeArgs(buf) - assert.Nil(t, err) - - buf.Reset() - call.Encode(buf) - - assert.Equal(t, expectedBuffer, buf) -} - -func Test_Call_ForceFree_BaseWeight(t *testing.T) { - target := setupCallForceFree() - - assert.Equal(t, callForceFreeWeight(dbWeight), target.BaseWeight()) -} - -func Test_Call_ForceFree_WeighData(t *testing.T) { - target := setupCallForceFree() - assert.Equal(t, primitives.WeightFromParts(124, 0), target.WeighData(baseWeight)) -} - -func Test_Call_ForceFree_ClassifyDispatch(t *testing.T) { - target := setupCallForceFree() - - assert.Equal(t, primitives.NewDispatchClassNormal(), target.ClassifyDispatch(baseWeight)) -} - -func Test_Call_ForceFree_PaysFee(t *testing.T) { - target := setupCallForceFree() - - assert.Equal(t, primitives.PaysYes, target.PaysFee(baseWeight)) -} - -func Test_Call_ForceFree_Dispatch_Success(t *testing.T) { - target := setupCallForceFree() - actual := sc.NewU128(1) - mutateResult := actual - targetAddressAccId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - event := newEventUnreserved(moduleId, targetAddressAccId, actual) - - mockStoredMap.On("Get", targetAddressAccId).Return(accountInfo, nil) - mockMutator.On("tryMutateAccount", - targetAddressAccId, - mockTypeMutateAccountDataBool). - Return(mutateResult, nil) - mockStoredMap.On("DepositEvent", event) - - _, err = target.Dispatch(primitives.NewRawOriginRoot(), sc.NewVaryingData(targetAddress, targetValue)) - assert.Nil(t, err) - mockStoredMap.AssertCalled(t, "Get", targetAddressAccId) - mockMutator.AssertCalled(t, - "tryMutateAccount", - targetAddressAccId, - mockTypeMutateAccountDataBool, - ) - mockStoredMap.AssertCalled(t, "DepositEvent", event) -} - -func Test_Call_ForceFree_Dispatch_InvalidOrigin(t *testing.T) { - target := setupCallForceFree() - - _, dispatchErr := target.Dispatch(primitives.NewRawOriginNone(), sc.NewVaryingData(targetAddress, targetValue)) - - assert.Equal(t, primitives.NewDispatchErrorBadOrigin(), dispatchErr) - mockStoredMap.AssertNotCalled(t, "Get", mock.Anything) - mockMutator.AssertNotCalled(t, "tryMutateAccount", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_ForceFree_Dispatch_InvalidArgs(t *testing.T) { - target := setupCallForceFree() - - _, dispatchErr := target.Dispatch(primitives.NewRawOriginNone(), sc.NewVaryingData(targetAddress, sc.NewU64(0))) - - assert.Equal(t, errors.New("invalid amount value when dispatching call force free"), dispatchErr) - mockStoredMap.AssertNotCalled(t, "Get", mock.Anything) - mockMutator.AssertNotCalled(t, "tryMutateAccount", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_ForceFree_Dispatch_InvalidLookup(t *testing.T) { - target := setupCallForceFree() - - _, dispatchErr := target.Dispatch(primitives.NewRawOriginRoot(), sc.NewVaryingData(primitives.NewMultiAddress20(primitives.Address20{}), targetValue)) - - assert.Equal(t, primitives.NewDispatchErrorCannotLookup(), dispatchErr) - targetAddressAccId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - mockStoredMap.AssertNotCalled(t, "Get", targetAddressAccId) - mockMutator.AssertNotCalled(t, "tryMutateAccount", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_ForceFree_Dispatch_ZeroBalance(t *testing.T) { - target := setupCallForceFree() - - _, dispatchErr := target.Dispatch(primitives.NewRawOriginRoot(), sc.NewVaryingData(targetAddress, constants.Zero)) - - assert.Nil(t, dispatchErr) - targetAddressAccId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - mockStoredMap.AssertNotCalled(t, "Get", targetAddressAccId) - mockMutator.AssertNotCalled(t, "tryMutateAccount", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_ForceFree_Dispatch_ZeroTotalStorageBalance(t *testing.T) { - target := setupCallForceFree() - accountInfo := primitives.AccountInfo{Data: primitives.AccountData{}} - - targetAddressAccId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - mockStoredMap.On("Get", targetAddressAccId).Return(accountInfo, nil) - - _, dispatchErr := target.Dispatch(primitives.NewRawOriginRoot(), sc.NewVaryingData(targetAddress, targetValue)) - - assert.Nil(t, dispatchErr) - mockStoredMap.AssertCalled(t, "Get", targetAddressAccId) - mockMutator.AssertNotCalled(t, "tryMutateAccount", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_ForceFree_Dispatch_Other(t *testing.T) { - target := setupCallForceFree() - accountInfo := primitives.AccountInfo{Data: primitives.AccountData{}} - - targetAddressAccId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - - mockStoredMap.On("Get", targetAddressAccId).Return(accountInfo, errPanic) - - _, dispatchErr := target.Dispatch(primitives.NewRawOriginRoot(), sc.NewVaryingData(targetAddress, targetValue)) - - assert.Equal(t, primitives.NewDispatchErrorOther(sc.Str(errPanic.Error())), dispatchErr) - mockStoredMap.AssertCalled(t, "Get", targetAddressAccId) - mockMutator.AssertNotCalled(t, "tryMutateAccount", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_ForceFree_Dispatch_Mutation_Fails(t *testing.T) { - target := setupCallForceFree() - - expectedErr := primitives.NewDispatchErrorOther(sc.Str(errPanic.Error())) - targetAddressAccId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - mockStoredMap.On("Get", targetAddressAccId).Return(accountInfo, nil) - mockMutator.On("tryMutateAccount", - targetAddressAccId, - mockTypeMutateAccountDataBool, - ).Return(sc.Empty{}, errPanic) - - _, dispatchErr := target.Dispatch(primitives.NewRawOriginRoot(), sc.NewVaryingData(targetAddress, targetValue)) - - assert.Equal(t, expectedErr, dispatchErr) - mockStoredMap.AssertCalled(t, "Get", targetAddressAccId) - mockMutator.AssertCalled(t, - "tryMutateAccount", - targetAddressAccId, - mockTypeMutateAccountDataBool, - ) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_removeReserveAndFree(t *testing.T) { - value := sc.NewU128(4) - accountData := &primitives.AccountData{ - Free: sc.NewU128(1), - Reserved: sc.NewU128(10), - } - expectedResult := value - - result := removeReserveAndFree(accountData, value) - - assert.Equal(t, expectedResult, result) - assert.Equal(t, sc.NewU128(6), accountData.Reserved) - assert.Equal(t, sc.NewU128(5), accountData.Free) -} - -func setupCallForceFree() primitives.Call { - mockStoredMap = new(mocks.StoredMap) - mockMutator = new(mockAccountMutator) - - return newCallForceFree(moduleId, sc.U8(functionForceFreeIndex), mockStoredMap, testConstants, mockMutator, logger) -} diff --git a/frame/balances/call_force_free_weight.go b/frame/balances/call_force_free_weight.go deleted file mode 100644 index 92eba18c..00000000 --- a/frame/balances/call_force_free_weight.go +++ /dev/null @@ -1,17 +0,0 @@ -// THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:29:46.221953 +0200 EET m=+0.227937584`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` - -// Summary: -// BaseExtrinsicTime: 718350000, BaseReads: 1, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 718350, MinReads: 1, MinWrites: 1 - -package balances - -import ( - primitives "github.com/LimeChain/gosemble/primitives/types" -) - -func callForceFreeWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(718350000, 0). - SaturatingAdd(dbWeight.Reads(1)). - SaturatingAdd(dbWeight.Writes(1)) -} diff --git a/frame/balances/call_force_set_balance.go b/frame/balances/call_force_set_balance.go new file mode 100644 index 00000000..b53ec4b6 --- /dev/null +++ b/frame/balances/call_force_set_balance.go @@ -0,0 +1,143 @@ +package balances + +import ( + "bytes" + + sc "github.com/LimeChain/goscale" + "github.com/LimeChain/gosemble/constants" + primitives "github.com/LimeChain/gosemble/primitives/types" +) + +type callForceSetBalance struct { + primitives.Callable + module Module +} + +func newCallForceSetBalance(moduleId sc.U8, functionId sc.U8, module Module) primitives.Call { + return callForceSetBalance{ + Callable: primitives.Callable{ + ModuleId: moduleId, + FunctionId: functionId, + Arguments: sc.NewVaryingData(primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}), + }, + module: module, + } +} + +func (c callForceSetBalance) DecodeArgs(buffer *bytes.Buffer) (primitives.Call, error) { + who, err := primitives.DecodeMultiAddress(buffer) + if err != nil { + return nil, err + } + value, err := sc.DecodeCompact[sc.U128](buffer) + if err != nil { + return nil, err + } + + c.Arguments = sc.NewVaryingData( + who, + value, + ) + + return c, nil +} + +func (c callForceSetBalance) Bytes() []byte { + return c.Callable.Bytes() +} + +func (c callForceSetBalance) ModuleIndex() sc.U8 { + return c.Callable.ModuleIndex() +} + +func (c callForceSetBalance) FunctionIndex() sc.U8 { + return c.Callable.FunctionIndex() +} + +func (c callForceSetBalance) Args() sc.VaryingData { + return c.Callable.Args() +} + +func (c callForceSetBalance) BaseWeight() primitives.Weight { + return callForceSetBalanceCreatingWeight(c.module.DbWeight()).Max(callForceSetBalanceKillingWeight(c.module.DbWeight())) +} + +func (_ callForceSetBalance) WeighData(baseWeight primitives.Weight) primitives.Weight { + return primitives.WeightFromParts(baseWeight.RefTime, 0) +} + +func (_ callForceSetBalance) ClassifyDispatch(baseWeight primitives.Weight) primitives.DispatchClass { + return primitives.NewDispatchClassNormal() +} + +func (_ callForceSetBalance) PaysFee(baseWeight primitives.Weight) primitives.Pays { + return primitives.PaysYes +} + +func (_ callForceSetBalance) Docs() string { + return "Set the regular balance of a given account. The dispatch origin for this call is `root`." +} + +func (c callForceSetBalance) Dispatch(origin primitives.RuntimeOrigin, args sc.VaryingData) (primitives.PostDispatchInfo, error) { + if !origin.IsRootOrigin() { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorBadOrigin() + } + + dest, ok := args[0].(primitives.MultiAddress) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid destination value in callForceSetBalance") + } + + who, err := primitives.Lookup(dest) + if err != nil { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorCannotLookup() + } + + valueCompact, ok := args[1].(sc.Compact) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid compact value in callForceSetBalance") + } + value, ok := valueCompact.Number.(sc.U128) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid U128 value in callForceSetBalance") + } + + return primitives.PostDispatchInfo{}, c.setBalance(who, value) +} + +func (c callForceSetBalance) setBalance(who primitives.AccountId, newFree sc.U128) error { + wipeOut := newFree.Lt(c.module.ExistentialDeposit()) + if wipeOut { + newFree = constants.Zero + } + + result, err := c.module.MutateAccountHandlingDust(who, + func(accountData *primitives.AccountData, bool bool) (sc.Encodable, error) { + oldFree := accountData.Free + accountData.Free = newFree + + return oldFree, nil + }, + ) + if err != nil { + return err + } + oldFree, ok := result.(primitives.Balance) + if !ok { + return primitives.NewDispatchErrorOther("could not cast oldFree in callForceSetBalance") + } + + if newFree.Gt(oldFree) { + if err := newPositiveImbalance(newFree.Sub(oldFree), c.module.TotalIssuance()).Drop(); err != nil { + return primitives.NewDispatchErrorOther(sc.Str(err.Error())) + } + } else if newFree.Lt(oldFree) { + if err := newNegativeImbalance(oldFree.Sub(newFree), c.module.TotalIssuance()).Drop(); err != nil { + return primitives.NewDispatchErrorOther(sc.Str(err.Error())) + } + } + + c.module.DepositEvent(newEventBalanceSet(c.ModuleId, who, newFree)) + + return nil +} diff --git a/frame/balances/call_force_set_balance_creating_weight.go b/frame/balances/call_force_set_balance_creating_weight.go new file mode 100644 index 00000000..99a22ab4 --- /dev/null +++ b/frame/balances/call_force_set_balance_creating_weight.go @@ -0,0 +1,17 @@ +// THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE +// DATE: `2024-06-12 10:03:13.846885 +0300 EEST m=+0.902492501`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` + +// Summary: +// BaseExtrinsicTime: 926900000, BaseReads: 1, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 926900, MinReads: 1, MinWrites: 1 + +package balances + +import ( + primitives "github.com/LimeChain/gosemble/primitives/types" +) + +func callForceSetBalanceCreatingWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { + return primitives.WeightFromParts(926900000, 0). + SaturatingAdd(dbWeight.Reads(1)). + SaturatingAdd(dbWeight.Writes(1)) +} diff --git a/frame/balances/call_force_set_balance_killing_weight.go b/frame/balances/call_force_set_balance_killing_weight.go new file mode 100644 index 00000000..17d8729b --- /dev/null +++ b/frame/balances/call_force_set_balance_killing_weight.go @@ -0,0 +1,17 @@ +// THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE +// DATE: `2024-06-12 10:03:14.114874 +0300 EEST m=+1.170481084`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` + +// Summary: +// BaseExtrinsicTime: 1822350000, BaseReads: 1, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 1822350, MinReads: 1, MinWrites: 1 + +package balances + +import ( + primitives "github.com/LimeChain/gosemble/primitives/types" +) + +func callForceSetBalanceKillingWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { + return primitives.WeightFromParts(1822350000, 0). + SaturatingAdd(dbWeight.Reads(1)). + SaturatingAdd(dbWeight.Writes(1)) +} diff --git a/frame/balances/call_force_set_balance_test.go b/frame/balances/call_force_set_balance_test.go new file mode 100644 index 00000000..cbb01c41 --- /dev/null +++ b/frame/balances/call_force_set_balance_test.go @@ -0,0 +1,265 @@ +package balances + +import ( + "bytes" + "errors" + "testing" + + sc "github.com/LimeChain/goscale" + "github.com/LimeChain/gosemble/mocks" + primitives "github.com/LimeChain/gosemble/primitives/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +var ( + callSetBalanceArgsBytes = sc.NewVaryingData(primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}).Bytes() +) + +func setupCallForceSetBalance() primitives.Call { + mockBalances = new(MockModule) + mockStoredMap = new(mocks.StoredMap) + mockTotalIssuance = new(mocks.StorageValue[sc.U128]) + + return newCallForceSetBalance(moduleId, functionForceSetBalance, mockBalances) +} + +func Test_Call_SetBalance_new(t *testing.T) { + target := setupCallForceSetBalance() + + expected := callForceSetBalance{ + Callable: primitives.Callable{ + ModuleId: moduleId, + FunctionId: functionForceSetBalance, + Arguments: sc.NewVaryingData(primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}), + }, + module: mockBalances, + } + + assert.Equal(t, expected, target) +} + +func Test_Call_SetBalance_DecodeArgs(t *testing.T) { + freeAmount := sc.ToCompact(sc.NewU128(1)) + + buf := &bytes.Buffer{} + buf.Write(targetMultiAddress.Bytes()) + buf.Write(freeAmount.Bytes()) + + target := setupCallForceSetBalance() + + call, err := target.DecodeArgs(buf) + + assert.Nil(t, err) + assert.Equal(t, sc.NewVaryingData(targetMultiAddress, freeAmount), call.Args()) +} + +func Test_Call_SetBalance_Encode(t *testing.T) { + target := setupCallForceSetBalance() + + expectedBuffer := bytes.NewBuffer(append([]byte{byte(moduleId), byte(functionForceSetBalance)}, callSetBalanceArgsBytes...)) + buf := &bytes.Buffer{} + + err := target.Encode(buf) + + assert.NoError(t, err) + assert.Equal(t, expectedBuffer, buf) +} + +func Test_Call_SetBalance_Bytes(t *testing.T) { + expected := append([]byte{byte(moduleId), byte(functionForceSetBalance)}, callSetBalanceArgsBytes...) + + target := setupCallForceSetBalance() + + assert.Equal(t, expected, target.Bytes()) +} + +func Test_Call_SetBalance_ModuleIndex(t *testing.T) { + target := setupCallForceSetBalance() + + assert.Equal(t, sc.U8(moduleId), target.ModuleIndex()) +} + +func Test_Call_SetBalance_FunctionIndex(t *testing.T) { + target := setupCallForceSetBalance() + + assert.Equal(t, sc.U8(functionForceSetBalance), target.FunctionIndex()) +} + +func Test_Call_SetBalance_BaseWeight(t *testing.T) { + target := setupCallForceSetBalance() + + mockBalances.On("DbWeight").Return(dbWeight) + + result := target.BaseWeight() + + assert.Equal(t, callForceSetBalanceCreatingWeight(dbWeight).Max(callForceSetBalanceKillingWeight(dbWeight)), result) + + mockBalances.AssertCalled(t, "DbWeight") +} + +func Test_Call_SetBalance_WeighData(t *testing.T) { + target := setupCallForceSetBalance() + + assert.Equal(t, primitives.WeightFromParts(124, 0), target.WeighData(baseWeight)) +} + +func Test_Call_SetBalance_ClassifyDispatch(t *testing.T) { + target := setupCallForceSetBalance() + + assert.Equal(t, primitives.NewDispatchClassNormal(), target.ClassifyDispatch(baseWeight)) +} + +func Test_Call_SetBalance_PaysFee(t *testing.T) { + target := setupCallForceSetBalance() + + assert.Equal(t, primitives.PaysYes, target.PaysFee(baseWeight)) +} + +func Test_Call_SetBalance_Dispatch_Success(t *testing.T) { + target := setupCallForceSetBalance() + + newFree := sc.NewU128(0) + + mockBalances.On("ExistentialDeposit").Return(sc.NewU128(1)) + mockBalances.On("MutateAccountHandlingDust", targetAddress, mockTypeMutateAccountDataBool).Return(primitives.Balance{}, nil) + mockBalances.On("DepositEvent", newEventBalanceSet(moduleId, targetAddress, newFree)).Return() + + _, err := target.Dispatch(primitives.NewRawOriginRoot(), sc.NewVaryingData(targetMultiAddress, sc.ToCompact(newFree))) + + assert.NoError(t, err) + + mockBalances.AssertCalled(t, "ExistentialDeposit") + mockBalances.AssertCalled(t, "MutateAccountHandlingDust", targetAddress, mockTypeMutateAccountDataBool) + mockTotalIssuance.AssertNotCalled(t, "Get") + mockTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) + mockBalances.AssertCalled(t, "DepositEvent", newEventBalanceSet(moduleId, targetAddress, newFree)) +} + +func Test_Call_SetBalance_Dispatch_BadOrigin(t *testing.T) { + target := setupCallForceSetBalance() + + _, err := target.Dispatch(primitives.NewRawOriginNone(), sc.NewVaryingData(targetMultiAddress, sc.ToCompact(newFree))) + + assert.Equal(t, primitives.NewDispatchErrorBadOrigin(), err) + + mockBalances.AssertNotCalled(t, "ExistentialDeposit") + mockBalances.AssertNotCalled(t, "MutateAccountHandlingDust", targetAddress, mockTypeMutateAccountDataBool) + mockTotalIssuance.AssertNotCalled(t, "Get") + mockTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) + mockBalances.AssertNotCalled(t, "DepositEvent", newEventBalanceSet(moduleId, targetAddress, newFree)) +} + +func Test_Call_SetBalance_Dispatch_CannotLookup(t *testing.T) { + target := setupCallForceSetBalance() + + _, err := target.Dispatch( + primitives.NewRawOriginRoot(), + sc.NewVaryingData(primitives.NewMultiAddress20(primitives.Address20{}), sc.ToCompact(newFree)), + ) + + assert.Equal(t, primitives.NewDispatchErrorCannotLookup(), err) + mockBalances.AssertNotCalled(t, "ExistentialDeposit") + mockBalances.AssertNotCalled(t, "MutateAccountHandlingDust", targetAddress, mockTypeMutateAccountDataBool) + mockTotalIssuance.AssertNotCalled(t, "Get") + mockTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) + mockBalances.AssertNotCalled(t, "DepositEvent", newEventBalanceSet(moduleId, targetAddress, newFree)) +} + +func Test_Call_SetBalance_Dispatch_InvalidArg_Free_InvalidCompact(t *testing.T) { + target := setupCallForceSetBalance() + + _, err := target.Dispatch( + primitives.NewRawOriginRoot(), + sc.NewVaryingData(targetMultiAddress, sc.NewU128(0)), + ) + + assert.Equal(t, primitives.NewDispatchErrorOther("invalid compact value in callForceSetBalance"), err) + + mockBalances.AssertNotCalled(t, "ExistentialDeposit") + mockBalances.AssertNotCalled(t, "MutateAccountHandlingDust", targetAddress, mockTypeMutateAccountDataBool) + mockTotalIssuance.AssertNotCalled(t, "Get") + mockTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) + mockBalances.AssertNotCalled(t, "DepositEvent", newEventBalanceSet(moduleId, targetAddress, newFree)) +} + +func Test_Call_SetBalance_Dispatch_InvalidArg_Free_InvalidCompactNumber(t *testing.T) { + target := setupCallForceSetBalance() + + _, err := target.Dispatch( + primitives.NewRawOriginRoot(), + sc.NewVaryingData(targetMultiAddress, sc.Compact{}), + ) + + assert.Equal(t, primitives.NewDispatchErrorOther("invalid U128 value in callForceSetBalance"), err) + + mockBalances.AssertNotCalled(t, "ExistentialDeposit") + mockBalances.AssertNotCalled(t, "MutateAccountHandlingDust", targetAddress, mockTypeMutateAccountDataBool) + mockTotalIssuance.AssertNotCalled(t, "Get") + mockTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) + mockBalances.AssertNotCalled(t, "DepositEvent", newEventBalanceSet(moduleId, targetAddress, newFree)) +} + +func Test_Call_SetBalance_setBalance_Success(t *testing.T) { + target, ok := setupCallForceSetBalance().(callForceSetBalance) + assert.True(t, ok) + + mockBalances.On("ExistentialDeposit").Return(sc.NewU128(1)) + mockBalances.On("MutateAccountHandlingDust", targetAddress, mockTypeMutateAccountDataBool).Return(primitives.Balance{}, nil) + mockBalances.On("TotalIssuance").Return(mockTotalIssuance) + mockTotalIssuance.On("Get").Return(sc.NewU128(1), nil) + mockTotalIssuance.On("Put", sc.NewU128(6)).Return().Once() + mockBalances.On("DepositEvent", newEventBalanceSet(moduleId, targetAddress, newFree)).Return() + + result := target.setBalance(targetAddress, newFree) + + assert.Nil(t, result) + mockBalances.AssertCalled(t, "ExistentialDeposit") + mockBalances.AssertCalled(t, "MutateAccountHandlingDust", targetAddress, mockTypeMutateAccountDataBool) + mockBalances.AssertCalled(t, "TotalIssuance") + mockTotalIssuance.AssertCalled(t, "Get") + mockTotalIssuance.AssertCalled(t, "Put", sc.NewU128(6)) + mockBalances.AssertCalled(t, "DepositEvent", newEventBalanceSet(moduleId, targetAddress, newFree)) +} + +func Test_Call_SetBalance_setBalance_Success_LessThanExistentialDeposit(t *testing.T) { + target, ok := setupCallForceSetBalance().(callForceSetBalance) + assert.True(t, ok) + + newFree := sc.NewU128(0) + mockBalances.On("ExistentialDeposit").Return(sc.NewU128(1)) + mockBalances.On("MutateAccountHandlingDust", targetAddress, mockTypeMutateAccountDataBool).Return(primitives.Balance(sc.NewU128(1)), nil) + mockBalances.On("TotalIssuance").Return(mockTotalIssuance) + mockTotalIssuance.On("Get").Return(sc.NewU128(1), nil) + mockTotalIssuance.On("Put", sc.NewU128(0)).Return().Once() + mockBalances.On("DepositEvent", newEventBalanceSet(moduleId, targetAddress, newFree)).Return() + + result := target.setBalance(targetAddress, newFree) + + assert.Nil(t, result) + mockBalances.AssertCalled(t, "ExistentialDeposit") + mockBalances.AssertCalled(t, "MutateAccountHandlingDust", targetAddress, mockTypeMutateAccountDataBool) + mockBalances.AssertCalled(t, "TotalIssuance") + mockTotalIssuance.AssertCalled(t, "Get") + mockTotalIssuance.AssertCalled(t, "Put", sc.NewU128(0)) + mockBalances.AssertCalled(t, "DepositEvent", newEventBalanceSet(moduleId, targetAddress, newFree)) +} + +func Test_Call_SetBalance_setBalance_tryMutateAccount_Fails(t *testing.T) { + target, ok := setupCallForceSetBalance().(callForceSetBalance) + assert.True(t, ok) + + expectedErr := errors.New("some MutateAccountHandlingDust error") + mockBalances.On("ExistentialDeposit").Return(sc.NewU128(1)) + mockBalances.On("MutateAccountHandlingDust", targetAddress, mockTypeMutateAccountDataBool).Return(primitives.Balance{}, expectedErr) + + result := target.setBalance(targetAddress, targetValue) + + assert.Equal(t, expectedErr, result) + mockBalances.AssertCalled(t, "ExistentialDeposit") + mockBalances.AssertCalled(t, "MutateAccountHandlingDust", targetAddress, mockTypeMutateAccountDataBool) + mockBalances.AssertNotCalled(t, "TotalIssuance") + mockTotalIssuance.AssertNotCalled(t, "Get") + mockTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) + mockBalances.AssertNotCalled(t, "DepositEvent", mock.Anything) +} diff --git a/frame/balances/call_force_transfer.go b/frame/balances/call_force_transfer.go index 9befdb12..605c309d 100644 --- a/frame/balances/call_force_transfer.go +++ b/frame/balances/call_force_transfer.go @@ -2,37 +2,35 @@ package balances import ( "bytes" - "errors" sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/primitives/types" + "github.com/LimeChain/gosemble/frame/balances/types" primitives "github.com/LimeChain/gosemble/primitives/types" ) type callForceTransfer struct { primitives.Callable - transfer + module module } -func newCallForceTransfer(moduleId sc.U8, functionId sc.U8, storedMap primitives.StoredMap, constants *consts, mutator accountMutator) primitives.Call { - call := callForceTransfer{ +func newCallForceTransfer(moduleId sc.U8, functionId sc.U8, module module) primitives.Call { + return callForceTransfer{ Callable: primitives.Callable{ ModuleId: moduleId, FunctionId: functionId, - Arguments: sc.NewVaryingData(types.MultiAddress{}, types.MultiAddress{}, sc.Compact{Number: sc.U128{}}), + Arguments: sc.NewVaryingData(primitives.MultiAddress{}, primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}), }, - transfer: newTransfer(moduleId, storedMap, constants, mutator), + module: module, } - - return call } func (c callForceTransfer) DecodeArgs(buffer *bytes.Buffer) (primitives.Call, error) { - source, err := types.DecodeMultiAddress(buffer) + from, err := primitives.DecodeMultiAddress(buffer) if err != nil { return nil, err } - dest, err := types.DecodeMultiAddress(buffer) + + dest, err := primitives.DecodeMultiAddress(buffer) if err != nil { return nil, err } @@ -40,11 +38,13 @@ func (c callForceTransfer) DecodeArgs(buffer *bytes.Buffer) (primitives.Call, er if err != nil { return nil, err } + c.Arguments = sc.NewVaryingData( - source, + from, dest, value, ) + return c, nil } @@ -68,53 +68,59 @@ func (c callForceTransfer) Args() sc.VaryingData { return c.Callable.Args() } -func (c callForceTransfer) BaseWeight() types.Weight { - return callForceTransferWeight(c.constants.DbWeight) +func (c callForceTransfer) BaseWeight() primitives.Weight { + return callForceTransferWeight(c.module.constants.DbWeight) } -func (_ callForceTransfer) WeighData(baseWeight types.Weight) types.Weight { - return types.WeightFromParts(baseWeight.RefTime, 0) +func (_ callForceTransfer) WeighData(baseWeight primitives.Weight) primitives.Weight { + return primitives.WeightFromParts(baseWeight.RefTime, 0) } -func (_ callForceTransfer) ClassifyDispatch(baseWeight types.Weight) types.DispatchClass { - return types.NewDispatchClassNormal() +func (_ callForceTransfer) ClassifyDispatch(baseWeight primitives.Weight) primitives.DispatchClass { + return primitives.NewDispatchClassNormal() } -func (_ callForceTransfer) PaysFee(baseWeight types.Weight) types.Pays { - return types.PaysYes -} - -func (c callForceTransfer) Dispatch(origin types.RuntimeOrigin, args sc.VaryingData) (types.PostDispatchInfo, error) { - valueCompact, ok := args[2].(sc.Compact) - if !ok { - return types.PostDispatchInfo{}, errors.New("invalid Compact value when dispatching call_force_transfer") - } - value, ok := valueCompact.Number.(sc.U128) - if !ok { - return types.PostDispatchInfo{}, errors.New("invalid Compact field number when dispatching call_force_transfer") - } - return types.PostDispatchInfo{}, c.forceTransfer(origin, args[0].(types.MultiAddress), args[1].(types.MultiAddress), value) +func (_ callForceTransfer) PaysFee(baseWeight primitives.Weight) primitives.Pays { + return primitives.PaysYes } func (_ callForceTransfer) Docs() string { - return "Exactly as `transfer`, except the origin must be root and the source account may be specified." + return "Exactly as `transfer_allow_death`, except the origin must be root and the source account may be specified." } -// forceTransfer transfers liquid free balance from `source` to `dest`. -// Can only be called by ROOT. -func (c callForceTransfer) forceTransfer(origin types.RawOrigin, source types.MultiAddress, dest types.MultiAddress, value sc.U128) error { +func (c callForceTransfer) Dispatch(origin primitives.RuntimeOrigin, args sc.VaryingData) (primitives.PostDispatchInfo, error) { if !origin.IsRootOrigin() { - return types.NewDispatchErrorBadOrigin() + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorBadOrigin() + } + + fromMultiAddress, ok := args[0].(primitives.MultiAddress) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid from value in callForceTransfer") } - sourceAddress, err := types.Lookup(source) + from, err := primitives.Lookup(fromMultiAddress) if err != nil { - return types.NewDispatchErrorCannotLookup() + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorCannotLookup() } - destinationAddress, err := types.Lookup(dest) + + toMultiAddress, ok := args[1].(primitives.MultiAddress) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid to value in callForceTransfer") + } + + to, err := primitives.Lookup(toMultiAddress) if err != nil { - return types.NewDispatchErrorCannotLookup() + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorCannotLookup() + } + + valueCompact, ok := args[2].(sc.Compact) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid compact value in callForceTransfer") + } + value, ok := valueCompact.Number.(sc.U128) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid u128 value in callForceTransfer") } - return c.transfer.trans(sourceAddress, destinationAddress, value, types.ExistenceRequirementAllowDeath) + return primitives.PostDispatchInfo{}, c.module.transfer(from, to, value, types.PreservationExpendable) } diff --git a/frame/balances/call_force_transfer_test.go b/frame/balances/call_force_transfer_test.go deleted file mode 100644 index 61b549b3..00000000 --- a/frame/balances/call_force_transfer_test.go +++ /dev/null @@ -1,211 +0,0 @@ -package balances - -import ( - "bytes" - "errors" - "testing" - - sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/mocks" - primitives "github.com/LimeChain/gosemble/primitives/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -var ( - callForceTransferArgsBytes = sc.NewVaryingData(primitives.MultiAddress{}, primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}).Bytes() -) - -func Test_Call_ForceTransfer_new(t *testing.T) { - target := setupCallForceTransfer() - expected := callForceTransfer{ - Callable: primitives.Callable{ - ModuleId: moduleId, - FunctionId: functionForceTransferIndex, - Arguments: sc.NewVaryingData(primitives.MultiAddress{}, primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}), - }, - transfer: transfer{ - moduleId: moduleId, - storedMap: mockStoredMap, - constants: testConstants, - accountMutator: mockMutator, - }, - } - - assert.Equal(t, expected, target) -} - -func Test_Call_ForceTransfer_DecodeArgs(t *testing.T) { - amount := sc.ToCompact(sc.NewU128(1)) - buf := &bytes.Buffer{} - buf.Write(fromAddress.Bytes()) - buf.Write(toAddress.Bytes()) - buf.Write(amount.Bytes()) - - target := setupCallForceTransfer() - call, err := target.DecodeArgs(buf) - assert.Nil(t, err) - - assert.Equal(t, sc.NewVaryingData(fromAddress, toAddress, amount), call.Args()) -} - -func Test_Call_ForceTransfer_Encode(t *testing.T) { - target := setupCallForceTransfer() - expectedBuffer := bytes.NewBuffer(append([]byte{moduleId, functionForceTransferIndex}, callForceTransferArgsBytes...)) - buf := &bytes.Buffer{} - - err := target.Encode(buf) - - assert.NoError(t, err) - assert.Equal(t, expectedBuffer, buf) -} - -func Test_Call_ForceTransfer_Bytes(t *testing.T) { - expected := append([]byte{moduleId, functionForceTransferIndex}, callForceTransferArgsBytes...) - - target := setupCallForceTransfer() - - assert.Equal(t, expected, target.Bytes()) -} - -func Test_Call_ForceTransfer_ModuleIndex(t *testing.T) { - target := setupCallForceTransfer() - - assert.Equal(t, sc.U8(moduleId), target.ModuleIndex()) -} - -func Test_Call_ForceTransfer_FunctionIndex(t *testing.T) { - target := setupCallForceTransfer() - - assert.Equal(t, sc.U8(functionForceTransferIndex), target.FunctionIndex()) -} - -func Test_Call_ForceTransfer_BaseWeight(t *testing.T) { - target := setupCallForceTransfer() - - assert.Equal(t, callForceTransferWeight(dbWeight), target.BaseWeight()) -} - -func Test_Call_ForceTransfer_WeighData(t *testing.T) { - target := setupCallForceTransfer() - assert.Equal(t, primitives.WeightFromParts(124, 0), target.WeighData(baseWeight)) -} - -func Test_Call_ForceTransfer_ClassifyDispatch(t *testing.T) { - target := setupCallForceTransfer() - - assert.Equal(t, primitives.NewDispatchClassNormal(), target.ClassifyDispatch(baseWeight)) -} - -func Test_Call_ForceTransfer_PaysFee(t *testing.T) { - target := setupCallForceTransfer() - - assert.Equal(t, primitives.PaysYes, target.PaysFee(baseWeight)) -} - -func Test_Call_ForceTransfer_Dispatch_Success(t *testing.T) { - target := setupCallForceTransfer() - - fromAddressAccId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - toAddressAccId, err := toAddress.AsAccountId() - assert.Nil(t, err) - - mockMutator.On( - "tryMutateAccountWithDust", - toAddressAccId, - mockTypeMutateAccountDataBool, - ). - Return(sc.Empty{}, nil) - mockStoredMap.On( - "DepositEvent", - newEventTransfer(moduleId, fromAddressAccId, toAddressAccId, targetValue), - ). - Return() - - _, dispatchErr := target.Dispatch(primitives.NewRawOriginRoot(), sc.NewVaryingData(fromAddress, toAddress, sc.ToCompact(targetValue))) - - assert.Nil(t, dispatchErr) - mockMutator.AssertCalled(t, - "tryMutateAccountWithDust", - toAddressAccId, - mockTypeMutateAccountDataBool, - ) - mockStoredMap.AssertCalled(t, - "DepositEvent", - newEventTransfer(moduleId, fromAddressAccId, toAddressAccId, targetValue), - ) -} - -func Test_Call_ForceTransfer_Dispatch_InvalidBadOrigin(t *testing.T) { - target := setupCallForceTransfer() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginNone(), - sc.NewVaryingData(fromAddress, toAddress, sc.ToCompact(targetValue))) - - assert.Equal(t, primitives.NewDispatchErrorBadOrigin(), dispatchErr) - mockMutator.AssertNotCalled(t, "tryMutateAccountWithDust", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_ForceTransfer_Dispatch_InvalidArg_InvalidCompact(t *testing.T) { - target := setupCallForceTransfer() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginNone(), - sc.NewVaryingData(fromAddress, toAddress, sc.NewU128(0))) - - assert.Equal(t, errors.New("invalid Compact value when dispatching call_force_transfer"), dispatchErr) - - mockMutator.AssertNotCalled(t, "tryMutateAccountWithDust", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) - -} - -func Test_Call_ForceTransfer_Dispatch_InvalidArg_InvalidCompactNumber(t *testing.T) { - target := setupCallForceTransfer() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginNone(), - sc.NewVaryingData(fromAddress, toAddress, sc.Compact{})) - - assert.Equal(t, errors.New("invalid Compact field number when dispatching call_force_transfer"), dispatchErr) - - mockMutator.AssertNotCalled(t, "tryMutateAccountWithDust", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_ForceTransfer_Dispatch_CannotLookup_Source(t *testing.T) { - target := setupCallForceTransfer() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginRoot(), - sc.NewVaryingData(primitives.NewMultiAddress20(primitives.Address20{}), toAddress, sc.ToCompact(targetValue)), - ) - - assert.Equal(t, primitives.NewDispatchErrorCannotLookup(), dispatchErr) - mockMutator.AssertNotCalled(t, "tryMutateAccountWithDust", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_ForceTransfer_Dispatch_CannotLookup_Dest(t *testing.T) { - target := setupCallForceTransfer() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginRoot(), - sc.NewVaryingData(fromAddress, primitives.NewMultiAddress20(primitives.Address20{}), sc.ToCompact(targetValue)), - ) - - assert.Equal(t, primitives.NewDispatchErrorCannotLookup(), dispatchErr) - mockMutator.AssertNotCalled(t, "tryMutateAccountWithDust", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func setupCallForceTransfer() primitives.Call { - mockStoredMap = new(mocks.StoredMap) - mockMutator = new(mockAccountMutator) - - return newCallForceTransfer(moduleId, functionForceTransferIndex, mockStoredMap, testConstants, mockMutator) -} diff --git a/frame/balances/call_force_transfer_weight.go b/frame/balances/call_force_transfer_weight.go index d7c7ce3e..cd171163 100644 --- a/frame/balances/call_force_transfer_weight.go +++ b/frame/balances/call_force_transfer_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:29:46.460939 +0200 EET m=+0.466925209`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:13.581823 +0300 EEST m=+0.637431126`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 1773600000, BaseReads: 2, BaseWrites: 2, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 1773600, MinReads: 2, MinWrites: 2 +// BaseExtrinsicTime: 3846750000, BaseReads: 2, BaseWrites: 2, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 3846750, MinReads: 2, MinWrites: 2 package balances @@ -11,7 +11,7 @@ import ( ) func callForceTransferWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(1773600000, 0). + return primitives.WeightFromParts(3846750000, 0). SaturatingAdd(dbWeight.Reads(2)). SaturatingAdd(dbWeight.Writes(2)) } diff --git a/frame/balances/call_force_unreserve.go b/frame/balances/call_force_unreserve.go new file mode 100644 index 00000000..ca8b515b --- /dev/null +++ b/frame/balances/call_force_unreserve.go @@ -0,0 +1,110 @@ +package balances + +import ( + "bytes" + + sc "github.com/LimeChain/goscale" + primitives "github.com/LimeChain/gosemble/primitives/types" +) + +type callForceUnreserve struct { + primitives.Callable + module Module +} + +func newCallForceUnreserve(moduleId sc.U8, functionId sc.U8, module Module) primitives.Call { + return callForceUnreserve{ + Callable: primitives.Callable{ + ModuleId: moduleId, + FunctionId: functionId, + Arguments: sc.NewVaryingData(primitives.MultiAddress{}, sc.U128{}), + }, + module: module, + } +} + +func (c callForceUnreserve) DecodeArgs(buffer *bytes.Buffer) (primitives.Call, error) { + who, err := primitives.DecodeMultiAddress(buffer) + if err != nil { + return nil, err + } + value, err := sc.DecodeU128(buffer) + if err != nil { + return nil, err + } + + c.Arguments = sc.NewVaryingData( + who, + value, + ) + + return c, nil +} + +func (c callForceUnreserve) Encode(buffer *bytes.Buffer) error { + return c.Callable.Encode(buffer) +} + +func (c callForceUnreserve) Bytes() []byte { + return c.Callable.Bytes() +} + +func (c callForceUnreserve) ModuleIndex() sc.U8 { + return c.Callable.ModuleIndex() +} + +func (c callForceUnreserve) FunctionIndex() sc.U8 { + return c.Callable.FunctionIndex() +} + +func (c callForceUnreserve) Args() sc.VaryingData { + return c.Callable.Args() +} + +func (c callForceUnreserve) BaseWeight() primitives.Weight { + return callForceUnreserveWeight(c.module.DbWeight()) +} + +func (_ callForceUnreserve) WeighData(baseWeight primitives.Weight) primitives.Weight { + return primitives.WeightFromParts(baseWeight.RefTime, 0) +} + +func (_ callForceUnreserve) ClassifyDispatch(baseWeight primitives.Weight) primitives.DispatchClass { + return primitives.NewDispatchClassNormal() +} + +func (_ callForceUnreserve) PaysFee(baseWeight primitives.Weight) primitives.Pays { + return primitives.PaysYes +} + +func (_ callForceUnreserve) Docs() string { + return "Unreserve some balance from a user by force." +} + +func (c callForceUnreserve) Dispatch(origin primitives.RuntimeOrigin, args sc.VaryingData) (primitives.PostDispatchInfo, error) { + if !origin.IsRootOrigin() { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorBadOrigin() + } + + whoMultiAddress, ok := args[0].(primitives.MultiAddress) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid destination value in callForceUnreserve") + } + + who, err := primitives.Lookup(whoMultiAddress) + if err != nil { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorCannotLookup() + } + + value, ok := args[1].(sc.U128) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid u128 value in callForceUnreserve") + } + + _, err = c.module.Unreserve(who, value) + if err != nil { + return primitives.PostDispatchInfo{}, err + } + + return primitives.PostDispatchInfo{}, nil +} diff --git a/frame/balances/call_force_unreserve_test.go b/frame/balances/call_force_unreserve_test.go new file mode 100644 index 00000000..840f70fe --- /dev/null +++ b/frame/balances/call_force_unreserve_test.go @@ -0,0 +1,205 @@ +package balances + +import ( + "bytes" + "errors" + "testing" + + sc "github.com/LimeChain/goscale" + "github.com/LimeChain/gosemble/constants" + "github.com/LimeChain/gosemble/mocks" + primitives "github.com/LimeChain/gosemble/primitives/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +var ( + argsBytesCallForceFree = sc.NewVaryingData(primitives.MultiAddress{}, sc.U128{}).Bytes() + errPanic = errors.New("panic") +) + +var ( + mockBalances *MockModule +) + +func setupCallForceUnreserve() primitives.Call { + mockBalances = new(MockModule) + mockStoredMap = new(mocks.StoredMap) + + return newCallForceUnreserve(moduleId, functionForceUnreserve, mockBalances) +} + +func Test_Call_ForceFree_new(t *testing.T) { + target := setupCallForceUnreserve() + + expected := callForceUnreserve{ + Callable: primitives.Callable{ + ModuleId: moduleId, + FunctionId: functionForceUnreserve, + Arguments: sc.NewVaryingData(primitives.MultiAddress{}, sc.U128{}), + }, + module: mockBalances, + } + + assert.Equal(t, expected, target) +} + +func Test_Call_ForceFree_DecodeArgs(t *testing.T) { + amount := sc.NewU128(5) + buf := bytes.NewBuffer(append(targetMultiAddress.Bytes(), amount.Bytes()...)) + + target := setupCallForceUnreserve() + + call, err := target.DecodeArgs(buf) + assert.Nil(t, err) + + assert.Equal(t, sc.NewVaryingData(targetMultiAddress, amount), call.Args()) +} + +func Test_Call_ForceFree_Encode(t *testing.T) { + target := setupCallForceUnreserve() + + expectedBuffer := bytes.NewBuffer(append([]byte{byte(moduleId), byte(functionForceUnreserve)}, argsBytesCallForceFree...)) + buf := &bytes.Buffer{} + + err := target.Encode(buf) + + assert.NoError(t, err) + assert.Equal(t, expectedBuffer, buf) +} + +func Test_Call_ForceFree_Bytes(t *testing.T) { + expected := append([]byte{byte(moduleId), byte(functionForceUnreserve)}, argsBytesCallForceFree...) + + target := setupCallForceUnreserve() + + assert.Equal(t, expected, target.Bytes()) +} + +func Test_Call_ForceFree_ModuleIndex(t *testing.T) { + target := setupCallForceUnreserve() + + assert.Equal(t, sc.U8(moduleId), target.ModuleIndex()) +} + +func TestCall_ForceFree_FunctionIndex(t *testing.T) { + target := setupCallForceUnreserve() + + assert.Equal(t, sc.U8(functionForceUnreserve), target.FunctionIndex()) +} + +func Test_Call_ForceFree_EncodeWithArgs(t *testing.T) { + expectedBuffer := bytes.NewBuffer([]byte{byte(moduleId), byte(functionForceUnreserve)}) + bArgs := append(targetMultiAddress.Bytes(), targetValue.Bytes()...) + expectedBuffer.Write(bArgs) + + buf := bytes.NewBuffer(bArgs) + + target := setupCallForceUnreserve() + call, err := target.DecodeArgs(buf) + assert.Nil(t, err) + + buf.Reset() + call.Encode(buf) + + assert.Equal(t, expectedBuffer, buf) +} + +func Test_Call_ForceFree_BaseWeight(t *testing.T) { + target := setupCallForceUnreserve() + + mockBalances.On("DbWeight").Return(dbWeight) + + result := target.BaseWeight() + + assert.Equal(t, callForceUnreserveWeight(dbWeight), result) + mockBalances.AssertCalled(t, "DbWeight") +} + +func Test_Call_ForceFree_WeighData(t *testing.T) { + target := setupCallForceUnreserve() + + assert.Equal(t, primitives.WeightFromParts(124, 0), target.WeighData(baseWeight)) +} + +func Test_Call_ForceFree_ClassifyDispatch(t *testing.T) { + target := setupCallForceUnreserve() + + assert.Equal(t, primitives.NewDispatchClassNormal(), target.ClassifyDispatch(baseWeight)) +} + +func Test_Call_ForceFree_PaysFee(t *testing.T) { + target := setupCallForceUnreserve() + + assert.Equal(t, primitives.PaysYes, target.PaysFee(baseWeight)) +} + +func Test_Call_ForceFree_Dispatch_Success(t *testing.T) { + target := setupCallForceUnreserve() + + // TODO: add test in module.go + // actual := sc.NewU128(1) + // event := newEventUnreserved(moduleId, targetAddressAccId, actual) + // mockStoredMap.On("Get", targetAddressAccId).Return(accountInfo, nil) + // mockStoredMap.On("DepositEvent", event) + + mockBalances.On("Unreserve", targetAddress, targetValue).Return(targetValue, nil) + + _, err := target.Dispatch(primitives.NewRawOriginRoot(), sc.NewVaryingData(targetMultiAddress, targetValue)) + + assert.Nil(t, err) + mockBalances.AssertCalled(t, "Unreserve", targetAddress, targetValue) +} + +func Test_Call_ForceFree_Dispatch_InvalidOrigin(t *testing.T) { + target := setupCallForceUnreserve() + + _, dispatchErr := target.Dispatch(primitives.NewRawOriginNone(), sc.NewVaryingData(targetAddress, targetValue)) + + assert.Equal(t, primitives.NewDispatchErrorBadOrigin(), dispatchErr) + mockBalances.AssertNotCalled(t, "Unreserve", mock.Anything, mock.Anything) +} + +func Test_Call_ForceFree_Dispatch_InvalidArgs(t *testing.T) { + target := setupCallForceUnreserve() + + _, dispatchErr := target.Dispatch(primitives.NewRawOriginRoot(), sc.NewVaryingData(targetMultiAddress, sc.NewU64(0))) + + assert.Equal(t, primitives.NewDispatchErrorOther("invalid u128 value in callForceUnreserve"), dispatchErr) + mockBalances.AssertNotCalled(t, "Unreserve", mock.Anything, mock.Anything) +} + +func Test_Call_ForceFree_Dispatch_InvalidLookup(t *testing.T) { + target := setupCallForceUnreserve() + + _, dispatchErr := target.Dispatch(primitives.NewRawOriginRoot(), sc.NewVaryingData(primitives.NewMultiAddress20(primitives.Address20{}), targetValue)) + + assert.Equal(t, primitives.NewDispatchErrorCannotLookup(), dispatchErr) + mockBalances.AssertNotCalled(t, "Unreserve", mock.Anything, mock.Anything) +} + +func Test_Call_ForceFree_Dispatch_ZeroBalance(t *testing.T) { + target := setupCallForceUnreserve() + + mockBalances.On("Unreserve", targetAddress, constants.Zero).Return(targetValue, nil) + + _, dispatchErr := target.Dispatch(primitives.NewRawOriginRoot(), sc.NewVaryingData(targetMultiAddress, constants.Zero)) + + assert.Nil(t, dispatchErr) + mockBalances.AssertCalled(t, "Unreserve", targetAddress, constants.Zero) +} + +func Test_removeReserveAndFree(t *testing.T) { + value := sc.NewU128(4) + accountData := &primitives.AccountData{ + Free: sc.NewU128(1), + Reserved: sc.NewU128(10), + } + expectedResult := value + + result := removeReserveAndFree(accountData, value) + + assert.Equal(t, expectedResult, result) + assert.Equal(t, sc.NewU128(6), accountData.Reserved) + assert.Equal(t, sc.NewU128(5), accountData.Free) +} diff --git a/frame/balances/call_force_unreserve_weight.go b/frame/balances/call_force_unreserve_weight.go new file mode 100644 index 00000000..c41fce91 --- /dev/null +++ b/frame/balances/call_force_unreserve_weight.go @@ -0,0 +1,17 @@ +// THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE +// DATE: `2024-06-12 10:03:13.249334 +0300 EEST m=+0.304943917`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` + +// Summary: +// BaseExtrinsicTime: 1846650000, BaseReads: 1, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 1846650, MinReads: 1, MinWrites: 1 + +package balances + +import ( + primitives "github.com/LimeChain/gosemble/primitives/types" +) + +func callForceUnreserveWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { + return primitives.WeightFromParts(1846650000, 0). + SaturatingAdd(dbWeight.Reads(1)). + SaturatingAdd(dbWeight.Writes(1)) +} diff --git a/frame/balances/call_set_balance.go b/frame/balances/call_set_balance.go deleted file mode 100644 index f8f80e40..00000000 --- a/frame/balances/call_set_balance.go +++ /dev/null @@ -1,206 +0,0 @@ -package balances - -import ( - "bytes" - "errors" - - sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/frame/support" - "github.com/LimeChain/gosemble/primitives/types" -) - -type callSetBalance struct { - types.Callable - constants *consts - storedMap types.StoredMap - accountMutator accountMutator - issuance support.StorageValue[sc.U128] -} - -func newCallSetBalance(moduleId sc.U8, functionId sc.U8, storedMap types.StoredMap, constants *consts, mutator accountMutator, issuance support.StorageValue[sc.U128]) types.Call { - call := callSetBalance{ - Callable: types.Callable{ - ModuleId: moduleId, - FunctionId: functionId, - Arguments: sc.NewVaryingData(types.MultiAddress{}, sc.Compact{Number: sc.U128{}}, sc.Compact{Number: sc.U128{}}), - }, - constants: constants, - storedMap: storedMap, - accountMutator: mutator, - issuance: issuance, - } - - return call -} - -func (c callSetBalance) DecodeArgs(buffer *bytes.Buffer) (types.Call, error) { - targetAddress, err := types.DecodeMultiAddress(buffer) - if err != nil { - return nil, err - } - newFree, err := sc.DecodeCompact[sc.U128](buffer) - if err != nil { - return nil, err - } - newReserved, err := sc.DecodeCompact[sc.U128](buffer) - if err != nil { - return nil, err - } - - c.Arguments = sc.NewVaryingData( - targetAddress, - newFree, - newReserved, - ) - return c, nil -} - -func (c callSetBalance) Encode(buffer *bytes.Buffer) error { - return c.Callable.Encode(buffer) -} - -func (c callSetBalance) Bytes() []byte { - return c.Callable.Bytes() -} - -func (c callSetBalance) ModuleIndex() sc.U8 { - return c.Callable.ModuleIndex() -} - -func (c callSetBalance) FunctionIndex() sc.U8 { - return c.Callable.FunctionIndex() -} - -func (c callSetBalance) Args() sc.VaryingData { - return c.Callable.Args() -} - -func (c callSetBalance) BaseWeight() types.Weight { - return callSetBalanceCreatingWeight(c.constants.DbWeight).Max(callSetBalanceKillingWeight(c.constants.DbWeight)) -} - -func (_ callSetBalance) IsInherent() bool { - return false -} - -func (_ callSetBalance) WeighData(baseWeight types.Weight) types.Weight { - return types.WeightFromParts(baseWeight.RefTime, 0) -} - -func (_ callSetBalance) ClassifyDispatch(baseWeight types.Weight) types.DispatchClass { - return types.NewDispatchClassNormal() -} - -func (_ callSetBalance) PaysFee(baseWeight types.Weight) types.Pays { - return types.PaysYes -} - -func (c callSetBalance) Dispatch(origin types.RuntimeOrigin, args sc.VaryingData) (types.PostDispatchInfo, error) { - compactFree, ok := args[1].(sc.Compact) - if !ok { - return types.PostDispatchInfo{}, errors.New("invalid free compact value when dispatching balance call set") - } - newFree, ok := compactFree.Number.(sc.U128) - if !ok { - return types.PostDispatchInfo{}, errors.New("invalid free compact number when dispatching balance call set") - } - - compactReserved, ok := args[2].(sc.Compact) - if !ok { - return types.PostDispatchInfo{}, errors.New("invalid reserved compact value when dispatching balance call set") - } - newReserved, ok := compactReserved.Number.(sc.U128) - if !ok { - return types.PostDispatchInfo{}, errors.New("invalid reserved compact number when dispatching balance call set") - } - return types.PostDispatchInfo{}, c.setBalance(origin, args[0].(types.MultiAddress), newFree, newReserved) -} - -func (_ callSetBalance) Docs() string { - return "Set the balances of a given account." -} - -// setBalance sets the balance of a given account. -// Changes free and reserve balance of `who`, -// including the total issuance. -// Can only be called by ROOT. -func (c callSetBalance) setBalance(origin types.RawOrigin, who types.MultiAddress, newFree sc.U128, newReserved sc.U128) error { - if !origin.IsRootOrigin() { - return types.NewDispatchErrorBadOrigin() - } - - address, err := types.Lookup(who) - if err != nil { - return types.NewDispatchErrorCannotLookup() - } - - sum := newFree.Add(newReserved) - - if sum.Lt(c.constants.ExistentialDeposit) { - newFree = sc.NewU128(0) - newReserved = sc.NewU128(0) - } - - result, err := c.accountMutator.tryMutateAccount( - address, - func(account *types.AccountData, _ bool) (sc.Encodable, error) { - oldFree, oldReserved := updateAccount(account, newFree, newReserved) - return sc.NewVaryingData(oldFree, oldReserved), nil - }, - ) - if err != nil { - return err - } - - parsedResult := result.(sc.VaryingData) - oldFree := parsedResult[0].(types.Balance) - oldReserved := parsedResult[1].(types.Balance) - - if newFree.Gt(oldFree) { - if err := newPositiveImbalance(newFree.Sub(oldFree), c.issuance).Drop(); err != nil { - return types.NewDispatchErrorOther(sc.Str(err.Error())) - } - - } else if newFree.Lt(oldFree) { - if err := newNegativeImbalance(oldFree.Sub(newFree), c.issuance).Drop(); err != nil { - return types.NewDispatchErrorOther(sc.Str(err.Error())) - } - } - - if newReserved.Gt(oldReserved) { - if err := newPositiveImbalance(newReserved.Sub(oldReserved), c.issuance).Drop(); err != nil { - return types.NewDispatchErrorOther(sc.Str(err.Error())) - } - } else if newReserved.Lt(oldReserved) { - if err := newNegativeImbalance(oldReserved.Sub(newReserved), c.issuance).Drop(); err != nil { - return types.NewDispatchErrorOther(sc.Str(err.Error())) - } - - } - - whoAccountId, errAccId := who.AsAccountId() - if errAccId != nil { - return types.NewDispatchErrorOther(sc.Str(errAccId.Error())) - } - - c.storedMap.DepositEvent( - newEventBalanceSet( - c.ModuleId, - whoAccountId, - newFree, - newReserved, - ), - ) - return nil -} - -// updateAccount updates the reserved and free amounts and returns the old amounts -func updateAccount(account *types.AccountData, newFree, newReserved sc.U128) (oldFree, oldReserved types.Balance) { - oldFree = account.Free - oldReserved = account.Reserved - - account.Free = newFree - account.Reserved = newReserved - - return oldFree, oldReserved -} diff --git a/frame/balances/call_set_balance_creating_weight.go b/frame/balances/call_set_balance_creating_weight.go deleted file mode 100644 index c9ae4a9c..00000000 --- a/frame/balances/call_set_balance_creating_weight.go +++ /dev/null @@ -1,17 +0,0 @@ -// THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:29:46.663185 +0200 EET m=+0.669171917`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` - -// Summary: -// BaseExtrinsicTime: 705450000, BaseReads: 2, BaseWrites: 2, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 705450, MinReads: 2, MinWrites: 2 - -package balances - -import ( - primitives "github.com/LimeChain/gosemble/primitives/types" -) - -func callSetBalanceCreatingWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(705450000, 0). - SaturatingAdd(dbWeight.Reads(2)). - SaturatingAdd(dbWeight.Writes(2)) -} diff --git a/frame/balances/call_set_balance_killing_weight.go b/frame/balances/call_set_balance_killing_weight.go deleted file mode 100644 index f4ae34a4..00000000 --- a/frame/balances/call_set_balance_killing_weight.go +++ /dev/null @@ -1,17 +0,0 @@ -// THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:29:46.885726 +0200 EET m=+0.891715167`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` - -// Summary: -// BaseExtrinsicTime: 947950000, BaseReads: 2, BaseWrites: 2, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 947950, MinReads: 2, MinWrites: 2 - -package balances - -import ( - primitives "github.com/LimeChain/gosemble/primitives/types" -) - -func callSetBalanceKillingWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(947950000, 0). - SaturatingAdd(dbWeight.Reads(2)). - SaturatingAdd(dbWeight.Writes(2)) -} diff --git a/frame/balances/call_set_balance_test.go b/frame/balances/call_set_balance_test.go deleted file mode 100644 index 25f7486a..00000000 --- a/frame/balances/call_set_balance_test.go +++ /dev/null @@ -1,482 +0,0 @@ -package balances - -import ( - "bytes" - "errors" - "testing" - - sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/mocks" - primitives "github.com/LimeChain/gosemble/primitives/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -var ( - newFree = sc.NewU128(5) - newReserved = sc.NewU128(6) - oldFree = sc.NewU128(4) - oldReserved = sc.NewU128(3) - - callSetBalanceArgsBytes = sc.NewVaryingData(primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}, sc.Compact{Number: sc.U128{}}).Bytes() -) - -func Test_Call_SetBalance_new(t *testing.T) { - target := setupCallSetBalance() - expected := callSetBalance{ - Callable: primitives.Callable{ - ModuleId: moduleId, - FunctionId: functionSetBalanceIndex, - Arguments: sc.NewVaryingData(primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}, sc.Compact{Number: sc.U128{}}), - }, - constants: testConstants, - storedMap: mockStoredMap, - accountMutator: mockMutator, - issuance: mockStorageTotalIssuance, - } - - assert.Equal(t, expected, target) -} - -func Test_Call_SetBalance_DecodeArgs(t *testing.T) { - freeAmount := sc.ToCompact(sc.NewU128(1)) - reserveAmount := sc.ToCompact(sc.NewU128(1)) - buf := &bytes.Buffer{} - buf.Write(targetAddress.Bytes()) - buf.Write(freeAmount.Bytes()) - buf.Write(reserveAmount.Bytes()) - - target := setupCallSetBalance() - call, err := target.DecodeArgs(buf) - assert.Nil(t, err) - - assert.Equal(t, sc.NewVaryingData(targetAddress, freeAmount, reserveAmount), call.Args()) -} - -func Test_Call_SetBalance_Encode(t *testing.T) { - target := setupCallSetBalance() - expectedBuffer := bytes.NewBuffer(append([]byte{moduleId, functionSetBalanceIndex}, callSetBalanceArgsBytes...)) - buf := &bytes.Buffer{} - - err := target.Encode(buf) - - assert.NoError(t, err) - assert.Equal(t, expectedBuffer, buf) -} - -func Test_Call_SetBalance_Bytes(t *testing.T) { - expected := append([]byte{moduleId, functionSetBalanceIndex}, callSetBalanceArgsBytes...) - - target := setupCallSetBalance() - - assert.Equal(t, expected, target.Bytes()) -} - -func Test_Call_SetBalance_ModuleIndex(t *testing.T) { - target := setupCallSetBalance() - - assert.Equal(t, sc.U8(moduleId), target.ModuleIndex()) -} - -func Test_Call_SetBalance_FunctionIndex(t *testing.T) { - target := setupCallSetBalance() - - assert.Equal(t, sc.U8(functionSetBalanceIndex), target.FunctionIndex()) -} - -func Test_Call_SetBalance_BaseWeight(t *testing.T) { - target := setupCallSetBalance() - - assert.Equal(t, callSetBalanceCreatingWeight(dbWeight).Max(callSetBalanceKillingWeight(dbWeight)), target.BaseWeight()) -} - -func Test_Call_SetBalance_IsInherent(t *testing.T) { - target, ok := setupCallSetBalance().(callSetBalance) - assert.True(t, ok) - assert.Equal(t, false, target.IsInherent()) -} - -func Test_Call_SetBalance_WeighData(t *testing.T) { - target := setupCallSetBalance() - assert.Equal(t, primitives.WeightFromParts(124, 0), target.WeighData(baseWeight)) -} - -func Test_Call_SetBalance_ClassifyDispatch(t *testing.T) { - target := setupCallSetBalance() - - assert.Equal(t, primitives.NewDispatchClassNormal(), target.ClassifyDispatch(baseWeight)) -} - -func Test_Call_SetBalance_PaysFee(t *testing.T) { - target := setupCallSetBalance() - - assert.Equal(t, primitives.PaysYes, target.PaysFee(baseWeight)) -} - -func Test_Call_SetBalance_Dispatch_Success(t *testing.T) { - newFree := sc.NewU128(0) - newReserved := sc.NewU128(0) - target := setupCallSetBalance() - - expectedResult := sc.NewVaryingData(sc.NewU128(0), sc.NewU128(0)) - - targetAddressAccId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - - mockMutator.On( - "tryMutateAccount", - targetAddressAccId, - mockTypeMutateAccountDataBool, - ). - Return(expectedResult, nil) - mockStoredMap.On("DepositEvent", newEventBalanceSet(moduleId, targetAddressAccId, newFree, newReserved)) - - _, dispatchErr := target.Dispatch(primitives.NewRawOriginRoot(), sc.NewVaryingData(targetAddress, sc.ToCompact(newFree), sc.ToCompact(newReserved))) - - assert.NoError(t, dispatchErr) - mockStorageTotalIssuance.AssertNotCalled(t, "Get") - mockStorageTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) - mockMutator.AssertCalled(t, - "tryMutateAccount", - targetAddressAccId, - mockTypeMutateAccountDataBool, - ) - mockStoredMap.AssertCalled(t, - "DepositEvent", - newEventBalanceSet(moduleId, targetAddressAccId, newFree, newReserved), - ) -} - -func Test_Call_SetBalance_Dispatch_BadOrigin(t *testing.T) { - target := setupCallSetBalance() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginNone(), - sc.NewVaryingData(targetAddress, sc.ToCompact(newFree), sc.ToCompact(newReserved))) - - assert.Equal(t, primitives.NewDispatchErrorBadOrigin(), dispatchErr) - mockMutator.AssertNotCalled(t, "tryMutateAccount", mock.Anything, mock.Anything) - mockStorageTotalIssuance.AssertNotCalled(t, "Get") - mockStorageTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_SetBalance_Dispatch_CannotLookup(t *testing.T) { - target := setupCallSetBalance() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginRoot(), - sc.NewVaryingData(primitives.NewMultiAddress20(primitives.Address20{}), sc.ToCompact(newFree), sc.ToCompact(newReserved))) - - assert.Equal(t, primitives.NewDispatchErrorCannotLookup(), dispatchErr) - mockMutator.AssertNotCalled(t, "tryMutateAccount", mock.Anything, mock.Anything) - mockStorageTotalIssuance.AssertNotCalled(t, "Get") - mockStorageTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_SetBalance_Dispatch_InvalidArg_Free_InvalidCompact(t *testing.T) { - target := setupCallSetBalance() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginRoot(), - sc.NewVaryingData(primitives.NewMultiAddress20(primitives.Address20{}), sc.NewU128(0), sc.ToCompact(newReserved))) - - assert.Equal(t, errors.New("invalid free compact value when dispatching balance call set"), dispatchErr) - - mockMutator.AssertNotCalled(t, "tryMutateAccount", mock.Anything, mock.Anything) - mockStorageTotalIssuance.AssertNotCalled(t, "Get") - mockStorageTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_SetBalance_Dispatch_InvalidArg_Free_InvalidCompactNumber(t *testing.T) { - target := setupCallSetBalance() - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginRoot(), - sc.NewVaryingData(primitives.NewMultiAddress20(primitives.Address20{}), sc.Compact{}, sc.ToCompact(newReserved))) - - assert.Equal(t, errors.New("invalid free compact number when dispatching balance call set"), dispatchErr) - - mockMutator.AssertNotCalled(t, "tryMutateAccount", mock.Anything, mock.Anything) - mockStorageTotalIssuance.AssertNotCalled(t, "Get") - mockStorageTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_SetBalance_Dispatch_InvalidArg_Reserved_InvalidCompact(t *testing.T) { - target := setupCallSetBalance() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginRoot(), - sc.NewVaryingData(primitives.NewMultiAddress20(primitives.Address20{}), sc.ToCompact(newFree), sc.NewU128(0))) - - assert.Equal(t, errors.New("invalid reserved compact value when dispatching balance call set"), dispatchErr) - - mockMutator.AssertNotCalled(t, "tryMutateAccount", mock.Anything, mock.Anything) - mockStorageTotalIssuance.AssertNotCalled(t, "Get") - mockStorageTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_SetBalance_Dispatch_InvalidArg_Reserved_InvalidCompactNumber(t *testing.T) { - target := setupCallSetBalance() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginRoot(), - sc.NewVaryingData(primitives.NewMultiAddress20(primitives.Address20{}), sc.ToCompact(newFree), sc.Compact{})) - - assert.Equal(t, errors.New("invalid reserved compact number when dispatching balance call set"), dispatchErr) - - mockMutator.AssertNotCalled(t, "tryMutateAccount", mock.Anything, mock.Anything) - mockStorageTotalIssuance.AssertNotCalled(t, "Get") - mockStorageTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_SetBalance_setBalance_Success(t *testing.T) { - target, ok := setupCallSetBalance().(callSetBalance) - assert.True(t, ok) - expectedResult := sc.NewVaryingData(oldFree, oldReserved) - - targetAddressAccId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - - mockMutator.On( - "tryMutateAccount", - targetAddressAccId, - mockTypeMutateAccountDataBool, - ).Return(expectedResult, nil) - mockStorageTotalIssuance.On("Get").Return(sc.NewU128(1), nil) // positive imbalance - mockStorageTotalIssuance.On("Put", newFree.Sub(oldFree).Add(sc.NewU128(1))). - Return().Once() // newFree positive imbalance - mockStorageTotalIssuance.On("Put", newReserved.Sub(oldReserved).Add(sc.NewU128(1))). - Return().Once() // newReserved positive imbalance - mockStoredMap.On( - "DepositEvent", - newEventBalanceSet(moduleId, targetAddressAccId, newFree, newReserved)) - - result := target.setBalance(primitives.NewRawOriginRoot(), targetAddress, newFree, newReserved) - - assert.Nil(t, result) - mockMutator.AssertCalled(t, - "tryMutateAccount", - targetAddressAccId, - mockTypeMutateAccountDataBool, - ) - mockStorageTotalIssuance.AssertNumberOfCalls(t, "Get", 2) - mockStorageTotalIssuance.AssertNumberOfCalls(t, "Put", 2) - mockStorageTotalIssuance.AssertCalled(t, "Put", newFree.Sub(oldFree).Add(sc.NewU128(1))) - mockStorageTotalIssuance.AssertCalled(t, "Put", newReserved.Sub(oldReserved).Add(sc.NewU128(1))) - mockStoredMap.AssertCalled(t, - "DepositEvent", - newEventBalanceSet(moduleId, targetAddressAccId, newFree, newReserved), - ) -} - -func Test_Call_SetBalance_setBalance_Success_LessThanExistentialDeposit(t *testing.T) { - newFree := sc.NewU128(0) - newReserved := sc.NewU128(0) - target, ok := setupCallSetBalance().(callSetBalance) - assert.True(t, ok) - expectedResult := sc.NewVaryingData(sc.NewU128(0), sc.NewU128(0)) - - targetAddressAccId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - - mockMutator.On( - "tryMutateAccount", - targetAddressAccId, - mockTypeMutateAccountDataBool, - ).Return(expectedResult, nil) - mockStoredMap.On( - "DepositEvent", - newEventBalanceSet(moduleId, targetAddressAccId, newFree, newReserved)) - - result := target.setBalance(primitives.NewRawOriginRoot(), targetAddress, newFree, newReserved) - - assert.Nil(t, result) - mockStorageTotalIssuance.AssertNotCalled(t, "Get") - mockStorageTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) - mockMutator.AssertCalled(t, - "tryMutateAccount", - targetAddressAccId, - mockTypeMutateAccountDataBool, - ) - mockStoredMap.AssertCalled(t, - "DepositEvent", - newEventBalanceSet(moduleId, targetAddressAccId, newFree, newReserved), - ) -} - -func Test_Call_SetBalance_setBalance_Success_NegativeImbalance(t *testing.T) { - newFree := sc.NewU128(1) - newReserved := sc.NewU128(1) - target, ok := setupCallSetBalance().(callSetBalance) - assert.True(t, ok) - expectedResult := sc.NewVaryingData(oldFree, oldReserved) - - targetAddressAccId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - - mockMutator.On("tryMutateAccount", - targetAddressAccId, - mockTypeMutateAccountDataBool, - ).Return(expectedResult, nil) - mockStorageTotalIssuance.On("Get").Return(oldReserved.Add(oldFree), nil).Once() // newFree negative imbalance - mockStorageTotalIssuance.On("Put", oldFree).Return().Once() // newFree negative imbalance - mockStorageTotalIssuance.On("Get").Return(sc.NewU128(4), nil).Once() // newReserved negative imbalance - mockStorageTotalIssuance.On("Put", sc.NewU128(2)).Return().Once() // newReserved negative imbalance - mockStoredMap.On("DepositEvent", newEventBalanceSet(moduleId, targetAddressAccId, newFree, newReserved)) - - result := target.setBalance(primitives.NewRawOriginRoot(), targetAddress, newFree, newReserved) - - assert.Nil(t, result) - mockMutator.AssertCalled(t, - "tryMutateAccount", - targetAddressAccId, - mockTypeMutateAccountDataBool, - ) - mockStorageTotalIssuance.AssertNumberOfCalls(t, "Get", 2) - mockStorageTotalIssuance.AssertNumberOfCalls(t, "Put", 2) - mockStorageTotalIssuance.AssertCalled(t, "Put", sc.NewU128(4)) - mockStorageTotalIssuance.AssertCalled(t, "Put", sc.NewU128(2)) - mockStoredMap.AssertCalled(t, - "DepositEvent", - newEventBalanceSet(moduleId, targetAddressAccId, newFree, newReserved), - ) -} - -func Test_Call_SetBalance_setBalance_InvalidOrigin(t *testing.T) { - target, ok := setupCallSetBalance().(callSetBalance) - assert.True(t, ok) - - result := target.setBalance(primitives.NewRawOriginNone(), targetAddress, targetValue, targetValue) - - assert.Equal(t, primitives.NewDispatchErrorBadOrigin(), result) - mockMutator.AssertNotCalled(t, "tryMutateAccount", mock.Anything, mock.Anything) - mockStorageTotalIssuance.AssertNotCalled(t, "Get") - mockStorageTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_SetBalance_setBalance_Lookup(t *testing.T) { - target, ok := setupCallSetBalance().(callSetBalance) - assert.True(t, ok) - - result := target.setBalance(primitives.NewRawOriginRoot(), primitives.NewMultiAddress20(primitives.Address20{}), targetValue, targetValue) - - assert.Equal(t, primitives.NewDispatchErrorCannotLookup(), result) - mockMutator.AssertNotCalled(t, "tryMutateAccount", mock.Anything, mock.Anything) - mockStorageTotalIssuance.AssertNotCalled(t, "Get") - mockStorageTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_SetBalance_setBalance_tryMutateAccount_Fails(t *testing.T) { - target, ok := setupCallSetBalance().(callSetBalance) - assert.True(t, ok) - expectedErr := primitives.NewDispatchErrorBadOrigin() - - targetAddressAccId, errAccId := targetAddress.AsAccountId() - assert.Nil(t, errAccId) - - mockMutator.On( - "tryMutateAccount", - targetAddressAccId, - mockTypeMutateAccountDataBool, - ).Return(sc.Empty{}, expectedErr) - - result := target.setBalance(primitives.NewRawOriginRoot(), targetAddress, targetValue, targetValue) - - assert.Equal(t, expectedErr, result) - mockMutator.AssertCalled(t, - "tryMutateAccount", - targetAddressAccId, - mockTypeMutateAccountDataBool, - ) - mockStorageTotalIssuance.AssertNotCalled(t, "Get") - mockStorageTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_SetBalance_setBalance_Drop(t *testing.T) { - for _, tt := range []struct { - name string - newFree, newReserved, oldFree, oldReserved sc.U128 - }{ - { - name: "newFree.Gt(oldFree)", - newFree: sc.NewU128(1), - oldFree: sc.NewU128(0), - }, - { - name: "newFree.Lt(oldFree)", - newFree: sc.NewU128(0), - oldFree: sc.NewU128(1), - }, - { - name: "newReserved.Gt(oldReserved)", - newReserved: sc.NewU128(1), - oldReserved: sc.NewU128(0), - }, - { - name: "newReserved.Lt(oldReserved)", - newReserved: sc.NewU128(0), - oldReserved: sc.NewU128(1), - }, - } { - t.Run(tt.name, func(t *testing.T) { - target, ok := setupCallSetBalance().(callSetBalance) - assert.True(t, ok) - - mockMutator.On( - "tryMutateAccount", - mock.Anything, - mock.Anything, - ).Return(sc.NewVaryingData(tt.oldFree, tt.oldReserved), nil) - - mockStorageTotalIssuance.On("Put", mock.Anything) - mockStoredMap.On("DepositEvent", mock.Anything).Return() - mockStorageTotalIssuance.On("Get").Return(sc.NewU128(0), errors.New("drop")).Once() - - result := target.setBalance(primitives.NewRawOriginRoot(), targetAddress, tt.newFree, tt.newReserved) - - assert.Equal(t, primitives.NewDispatchErrorOther("drop"), result) - }) - } -} - -func Test_Call_SetBalance_updateAccount(t *testing.T) { - expectedOldFree := sc.NewU128(1) - expectedOldReserved := sc.NewU128(2) - newFree := sc.NewU128(5) - newReserved := sc.NewU128(6) - - account := &primitives.AccountData{ - Free: expectedOldFree, - Reserved: expectedOldReserved, - MiscFrozen: sc.NewU128(3), - FeeFrozen: sc.NewU128(4), - } - expectAccount := &primitives.AccountData{ - Free: newFree, - Reserved: newReserved, - MiscFrozen: sc.NewU128(3), - FeeFrozen: sc.NewU128(4), - } - - oldFree, oldReserved := updateAccount(account, newFree, newReserved) - - assert.Equal(t, expectedOldFree, oldFree) - assert.Equal(t, expectedOldReserved, oldReserved) - assert.Equal(t, expectAccount, account) -} - -func setupCallSetBalance() primitives.Call { - mockStoredMap = new(mocks.StoredMap) - mockMutator = new(mockAccountMutator) - mockStorageTotalIssuance = new(mocks.StorageValue[sc.U128]) - - return newCallSetBalance(moduleId, functionSetBalanceIndex, mockStoredMap, testConstants, mockMutator, mockStorageTotalIssuance).(callSetBalance) -} diff --git a/frame/balances/call_transfer.go b/frame/balances/call_transfer.go deleted file mode 100644 index 6e932491..00000000 --- a/frame/balances/call_transfer.go +++ /dev/null @@ -1,231 +0,0 @@ -package balances - -import ( - "bytes" - "errors" - "reflect" - - sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/constants" - "github.com/LimeChain/gosemble/primitives/types" - primitives "github.com/LimeChain/gosemble/primitives/types" -) - -type callTransfer struct { - primitives.Callable - transfer -} - -func newCallTransfer(moduleId sc.U8, functionId sc.U8, storedMap primitives.StoredMap, constants *consts, - mutator accountMutator) primitives.Call { - call := callTransfer{ - Callable: primitives.Callable{ - ModuleId: moduleId, - FunctionId: functionId, - Arguments: sc.NewVaryingData(primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}), - }, - transfer: newTransfer(moduleId, storedMap, constants, mutator), - } - - return call -} - -func (c callTransfer) DecodeArgs(buffer *bytes.Buffer) (primitives.Call, error) { - dest, err := types.DecodeMultiAddress(buffer) - if err != nil { - return nil, err - } - balance, err := sc.DecodeCompact[sc.U128](buffer) - if err != nil { - return nil, err - } - c.Arguments = sc.NewVaryingData( - dest, - balance, - ) - return c, nil -} - -func (c callTransfer) Encode(buffer *bytes.Buffer) error { - return c.Callable.Encode(buffer) -} - -func (c callTransfer) Bytes() []byte { - return c.Callable.Bytes() -} - -func (c callTransfer) ModuleIndex() sc.U8 { - return c.Callable.ModuleIndex() -} - -func (c callTransfer) FunctionIndex() sc.U8 { - return c.Callable.FunctionIndex() -} - -func (c callTransfer) Args() sc.VaryingData { - return c.Callable.Args() -} - -func (c callTransfer) BaseWeight() types.Weight { - return callTransferWeight(c.constants.DbWeight) -} - -func (_ callTransfer) WeighData(baseWeight types.Weight) types.Weight { - return types.WeightFromParts(baseWeight.RefTime, 0) -} - -func (_ callTransfer) ClassifyDispatch(baseWeight types.Weight) types.DispatchClass { - return types.NewDispatchClassNormal() -} - -func (_ callTransfer) PaysFee(baseWeight types.Weight) types.Pays { - return types.PaysYes -} - -func (c callTransfer) Dispatch(origin types.RuntimeOrigin, args sc.VaryingData) (types.PostDispatchInfo, error) { - valueCompact, ok := args[1].(sc.Compact) - if !ok { - return types.PostDispatchInfo{}, errors.New("invalid compact value when dispatching call transfer") - } - value, ok := valueCompact.Number.(sc.U128) - if !ok { - return types.PostDispatchInfo{}, errors.New("invalid compact number field when dispatching call transfer") - } - return types.PostDispatchInfo{}, c.transfer.transfer(origin, args[0].(types.MultiAddress), value) -} - -func (_ transfer) Docs() string { - return "Transfer some liquid free balance to another account." -} - -type transfer struct { - moduleId sc.U8 - storedMap primitives.StoredMap - constants *consts - accountMutator accountMutator -} - -func newTransfer(moduleId sc.U8, storedMap primitives.StoredMap, constants *consts, mutator accountMutator) transfer { - return transfer{ - moduleId: moduleId, - storedMap: storedMap, - constants: constants, - accountMutator: mutator, - } -} - -// transfer transfers liquid free balance from `source` to `dest`. -// Increases the free balance of `dest` and decreases the free balance of `origin` transactor. -// Must be signed by the transactor. -func (t transfer) transfer(origin types.RawOrigin, dest types.MultiAddress, value sc.U128) error { - if !origin.IsSignedOrigin() { - return types.NewDispatchErrorBadOrigin() - } - - to, err := types.Lookup(dest) - if err != nil { - return types.NewDispatchErrorCannotLookup() - } - - transactor, originErr := origin.AsSigned() - if originErr != nil { - return primitives.NewDispatchErrorOther(sc.Str(originErr.Error())) - } - - return t.trans(transactor, to, value, types.ExistenceRequirementAllowDeath) -} - -// trans transfers `value` free balance from `from` to `to`. -// Does not do anything if value is 0 or `from` and `to` are the same. -func (t transfer) trans(from types.AccountId, to types.AccountId, value sc.U128, existenceRequirement types.ExistenceRequirement) error { - if value.Eq(constants.Zero) || reflect.DeepEqual(from, to) { - return nil - } - - _, err := t.accountMutator.tryMutateAccountWithDust(to, func(toAccount *types.AccountData, _ bool) (sc.Encodable, error) { - return t.accountMutator.tryMutateAccountWithDust(from, func(fromAccount *types.AccountData, _ bool) (sc.Encodable, error) { - return t.sanityChecks(from, fromAccount, toAccount, value, existenceRequirement) - }) - }) - if err != nil { - return err - } - - t.storedMap.DepositEvent(newEventTransfer(t.moduleId, from, to, value)) - return nil -} - -// sanityChecks checks the following: -// `fromAccount` has sufficient balance -// `toAccount` balance does not overflow -// `toAccount` total balance is more than the existential deposit -// `fromAccount` can withdraw `value` -// the existence requirements for `fromAccount` -// Updates the balances of `fromAccount` and `toAccount`. -func (t transfer) sanityChecks(from types.AccountId, fromAccount *types.AccountData, toAccount *types.AccountData, value sc.U128, existenceRequirement primitives.ExistenceRequirement) (sc.Encodable, error) { - fromFree, err := sc.CheckedSubU128(fromAccount.Free, value) - if err != nil { - return nil, types.NewDispatchErrorModule(types.CustomModuleError{ - Index: t.moduleId, - Err: sc.U32(ErrorInsufficientBalance), - Message: sc.NewOption[sc.Str](nil), - }) - } - fromAccount.Free = fromFree - - toFree, err := sc.CheckedAddU128(toAccount.Free, value) - if err != nil { - return nil, types.NewDispatchErrorArithmetic(types.NewArithmeticErrorOverflow()) - } - toAccount.Free = toFree - - if toAccount.Total().Lt(t.constants.ExistentialDeposit) { - return nil, types.NewDispatchErrorModule(types.CustomModuleError{ - Index: t.moduleId, - Err: sc.U32(ErrorExistentialDeposit), - Message: sc.NewOption[sc.Str](nil), - }) - } - - if err := t.accountMutator.ensureCanWithdraw(from, value, types.ReasonsAll, fromAccount.Free); err != nil { - return nil, err - } - - canDecProviders, err := t.storedMap.CanDecProviders(from) - if err != nil { - return nil, types.NewDispatchErrorOther(sc.Str(err.Error())) - } - - allowDeath := existenceRequirement == types.ExistenceRequirementAllowDeath - allowDeath = allowDeath && canDecProviders - - if !(allowDeath || fromAccount.Total().Gt(t.constants.ExistentialDeposit)) { - return nil, types.NewDispatchErrorModule(types.CustomModuleError{ - Index: t.moduleId, - Err: sc.U32(ErrorKeepAlive), - Message: sc.NewOption[sc.Str](nil), - }) - } - - return nil, nil -} - -func (t transfer) reducibleBalance(who types.AccountId, keepAlive bool) (types.Balance, error) { - account, err := t.storedMap.Get(who) - if err != nil { - return types.Balance{}, err - } - accountData := account.Data - - liquid := sc.SaturatingSubU128(accountData.Free, sc.Max128(accountData.FeeFrozen, accountData.MiscFrozen)) - canDecProviders, err := t.storedMap.CanDecProviders(who) - if err != nil { - return types.Balance{}, err - } - if canDecProviders && !keepAlive { - return liquid, nil - } - - mustRemainToExist := sc.SaturatingSubU128(t.constants.ExistentialDeposit, accountData.Total().Sub(liquid)) - return sc.SaturatingSubU128(liquid, mustRemainToExist), nil -} diff --git a/frame/balances/call_transfer_all.go b/frame/balances/call_transfer_all.go index 00ca3677..2e90dc1c 100644 --- a/frame/balances/call_transfer_all.go +++ b/frame/balances/call_transfer_all.go @@ -4,44 +4,42 @@ import ( "bytes" sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/primitives/log" - "github.com/LimeChain/gosemble/primitives/types" + "github.com/LimeChain/gosemble/frame/balances/types" primitives "github.com/LimeChain/gosemble/primitives/types" ) type callTransferAll struct { primitives.Callable - transfer - logger log.RuntimeLogger + module module } -func newCallTransferAll(moduleId sc.U8, functionId sc.U8, storedMap primitives.StoredMap, constants *consts, mutator accountMutator, logger log.RuntimeLogger) primitives.Call { - call := callTransferAll{ +func newCallTransferAll(moduleId sc.U8, functionId sc.U8, module module) primitives.Call { + return callTransferAll{ Callable: primitives.Callable{ ModuleId: moduleId, FunctionId: functionId, - Arguments: sc.NewVaryingData(types.MultiAddress{}, sc.Bool(true)), + Arguments: sc.NewVaryingData(primitives.MultiAddress{}, sc.Bool(true)), }, - transfer: newTransfer(moduleId, storedMap, constants, mutator), - logger: logger, + module: module, } - - return call } func (c callTransferAll) DecodeArgs(buffer *bytes.Buffer) (primitives.Call, error) { - dest, err := types.DecodeMultiAddress(buffer) + dest, err := primitives.DecodeMultiAddress(buffer) if err != nil { return nil, err } + keepAlive, err := sc.DecodeBool(buffer) if err != nil { return nil, err } + c.Arguments = sc.NewVaryingData( dest, keepAlive, ) + return c, nil } @@ -65,61 +63,70 @@ func (c callTransferAll) Args() sc.VaryingData { return c.Callable.Args() } -func (c callTransferAll) BaseWeight() types.Weight { - return callTransferAllWeight(c.constants.DbWeight) -} - -func (_ callTransferAll) WeighData(baseWeight types.Weight) types.Weight { - return types.WeightFromParts(baseWeight.RefTime, 0) +func (c callTransferAll) BaseWeight() primitives.Weight { + return callTransferAllWeight(c.module.constants.DbWeight) } -func (_ callTransferAll) ClassifyDispatch(baseWeight types.Weight) types.DispatchClass { - return types.NewDispatchClassNormal() +func (_ callTransferAll) WeighData(baseWeight primitives.Weight) primitives.Weight { + return primitives.WeightFromParts(baseWeight.RefTime, 0) } -func (_ callTransferAll) PaysFee(baseWeight types.Weight) types.Pays { - return types.PaysYes +func (_ callTransferAll) ClassifyDispatch(baseWeight primitives.Weight) primitives.DispatchClass { + return primitives.NewDispatchClassNormal() } -func (c callTransferAll) Dispatch(origin types.RuntimeOrigin, args sc.VaryingData) (types.PostDispatchInfo, error) { - return types.PostDispatchInfo{}, c.transferAll(origin, args[0].(types.MultiAddress), bool(args[1].(sc.Bool))) +func (_ callTransferAll) PaysFee(baseWeight primitives.Weight) primitives.Pays { + return primitives.PaysYes } func (_ callTransferAll) Docs() string { - return "Transfer the entire transferable balance from the caller account." + return "Transfer the entire transferable balance from the caller account." + + " NOTE: This function only attempts to transfer _transferable_ balances. This means that " + + "any locked, reserved, or existential deposits (when `keep_alive` is `true`), will not be " + + "transferred by this function. To ensure that this function results in a killed account," + + " you might need to prepare the account by removing any reference counters, storage " + + "deposits, etc... " + + "The dispatch origin of this call must be Signed. " + + "- `dest`: The recipient of the transfer. " + + "- `keep_alive`: A boolean to determine if the `transfer_all` operation should send all " + + "of the funds the account has, causing the sender account to be killed (false), or " + + "transfer everything except at least the existential deposit, which will guarantee to keep the sender account alive (true)." } -// transferAll transfers the entire transferable balance from `origin` to `dest`. -// By transferable it means that any locked or reserved amounts will not be transferred. -// `keepAlive`: A boolean to determine if the `transfer_all` operation should send all -// the funds the account has, causing the sender account to be killed (false), or -// transfer everything except at least the existential deposit, which will guarantee to -// keep the sender account alive (true). -func (c callTransferAll) transferAll(origin types.RawOrigin, dest types.MultiAddress, keepAlive bool) error { +func (c callTransferAll) Dispatch(origin primitives.RuntimeOrigin, args sc.VaryingData) (primitives.PostDispatchInfo, error) { if !origin.IsSignedOrigin() { - return types.NewDispatchErrorBadOrigin() + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorBadOrigin() } - transactor, err := origin.AsSigned() - if err != nil { - return primitives.NewDispatchErrorOther(sc.Str(err.Error())) + from, originErr := origin.AsSigned() + if originErr != nil { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther(sc.Str(originErr.Error())) + } + + dest, ok := args[0].(primitives.MultiAddress) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid destination value in callTransferAll") } - reducibleBalance, err := c.reducibleBalance(transactor, keepAlive) + to, err := primitives.Lookup(dest) if err != nil { - return primitives.NewDispatchErrorOther(sc.Str(err.Error())) + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorCannotLookup() } - to, errLookup := types.Lookup(dest) - if errLookup != nil { - c.logger.Debugf("Failed to lookup [%s]", dest.Bytes()) - return types.NewDispatchErrorCannotLookup() + keepAlive, ok := args[1].(sc.Bool) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid keepAlive value in callTransferAll") } - keep := types.ExistenceRequirementKeepAlive - if !keepAlive { - keep = types.ExistenceRequirementAllowDeath + preservation := types.PreservationExpendable + if keepAlive { + preservation = types.PreservationPreserve + } + + reducibleBalance, err := c.module.reducibleBalance(from, preservation, types.FortitudePolite) + if err != nil { + return primitives.PostDispatchInfo{}, err } - return c.transfer.trans(transactor, to, reducibleBalance, keep) + return primitives.PostDispatchInfo{}, c.module.transfer(from, to, reducibleBalance, preservation) } diff --git a/frame/balances/call_transfer_all_test.go b/frame/balances/call_transfer_all_test.go deleted file mode 100644 index 9de134e5..00000000 --- a/frame/balances/call_transfer_all_test.go +++ /dev/null @@ -1,242 +0,0 @@ -package balances - -import ( - "bytes" - "testing" - - sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/mocks" - primitives "github.com/LimeChain/gosemble/primitives/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -var ( - transferAllArgsBytes = sc.NewVaryingData(primitives.MultiAddress{}, sc.Bool(true)).Bytes() -) - -func Test_Call_TransferAll_new(t *testing.T) { - target := setupCallTransferAll() - expected := callTransferAll{ - Callable: primitives.Callable{ - ModuleId: moduleId, - FunctionId: functionTransferAllIndex, - Arguments: sc.NewVaryingData(primitives.MultiAddress{}, sc.Bool(true)), - }, - transfer: transfer{ - moduleId: moduleId, - storedMap: mockStoredMap, - constants: testConstants, - accountMutator: mockMutator, - }, - logger: logger, - } - - assert.Equal(t, expected, target) -} - -func Test_Call_TransferAll_DecodeArgs(t *testing.T) { - keepAlive := sc.Bool(true) - buf := bytes.NewBuffer(append(targetAddress.Bytes(), keepAlive.Bytes()...)) - - target := setupCallTransferAll() - call, err := target.DecodeArgs(buf) - assert.Nil(t, err) - - assert.Equal(t, sc.NewVaryingData(targetAddress, keepAlive), call.Args()) -} - -func Test_Call_TransferAll_Encode(t *testing.T) { - target := setupCallTransferAll() - expectedBuffer := bytes.NewBuffer(append([]byte{moduleId, functionTransferAllIndex}, transferAllArgsBytes...)) - buf := &bytes.Buffer{} - - err := target.Encode(buf) - - assert.NoError(t, err) - assert.Equal(t, expectedBuffer, buf) -} - -func Test_Call_TransferAll_Bytes(t *testing.T) { - expected := append([]byte{moduleId, functionTransferAllIndex}, transferAllArgsBytes...) - - target := setupCallTransferAll() - - assert.Equal(t, expected, target.Bytes()) -} - -func Test_Call_TransferAll_ModuleIndex(t *testing.T) { - target := setupCallTransferAll() - - assert.Equal(t, sc.U8(moduleId), target.ModuleIndex()) -} - -func Test_Call_TransferAll_FunctionIndex(t *testing.T) { - target := setupCallTransferAll() - - assert.Equal(t, sc.U8(functionTransferAllIndex), target.FunctionIndex()) -} - -func Test_Call_TransferAll_BaseWeight(t *testing.T) { - target := setupCallTransferAll() - - assert.Equal(t, callTransferAllWeight(dbWeight), target.BaseWeight()) -} - -func Test_Call_TransferAll_WeighData(t *testing.T) { - target := setupCallTransferAll() - assert.Equal(t, primitives.WeightFromParts(124, 0), target.WeighData(baseWeight)) -} - -func Test_Call_TransferAll_ClassifyDispatch(t *testing.T) { - target := setupCallTransferAll() - - assert.Equal(t, primitives.NewDispatchClassNormal(), target.ClassifyDispatch(baseWeight)) -} - -func Test_Call_TransferAll_PaysFee(t *testing.T) { - target := setupCallTransferAll() - - assert.Equal(t, primitives.PaysYes, target.PaysFee(baseWeight)) -} - -func Test_Call_TransferAll_Dispatch_Success(t *testing.T) { - target := setupCallTransferAll() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - toAddressId, err := toAddress.AsAccountId() - assert.Nil(t, err) - - mockStoredMap.On("Get", fromAddressId).Return(accountInfo, nil) - mockStoredMap.On("CanDecProviders", fromAddressId).Return(true, nil) - mockMutator.On("tryMutateAccountWithDust", - toAddressId, - mockTypeMutateAccountDataBool, - ).Return(sc.Empty{}, nil) - mockStoredMap.On( - "DepositEvent", - newEventTransfer( - moduleId, - fromAddressId, - toAddressId, - accountInfo.Data.Free.Sub(sc.NewU128(1)), - ), - ). - Return() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginSigned(fromAddressId), - sc.NewVaryingData(toAddress, sc.Bool(true)), - ) - - assert.Nil(t, dispatchErr) - mockStoredMap.AssertCalled(t, "Get", fromAddressId) - mockStoredMap.AssertCalled(t, "CanDecProviders", fromAddressId) - mockMutator.AssertCalled(t, - "tryMutateAccountWithDust", - toAddressId, - mockTypeMutateAccountDataBool, - ) - mockStoredMap.AssertCalled(t, - "DepositEvent", - newEventTransfer( - moduleId, - fromAddressId, - toAddressId, - accountInfo.Data.Free.Sub(sc.NewU128(1)), - ), - ) -} - -func Test_Call_TransferAll_Dispatch_BadOrigin(t *testing.T) { - target := setupCallTransferAll() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginNone(), - sc.NewVaryingData(fromAddress, sc.Bool(true)), - ) - - assert.Equal(t, primitives.NewDispatchErrorBadOrigin(), dispatchErr) - mockStoredMap.AssertNotCalled(t, "Get", mock.Anything) - mockStoredMap.AssertNotCalled(t, "CanDecProviders", mock.Anything) - mockMutator.AssertNotCalled(t, "tryMutateAccountWithDust", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_TransferAll_Dispatch_CannotLookup(t *testing.T) { - target := setupCallTransferAll() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - mockStoredMap.On("Get", fromAddressId).Return(accountInfo, nil) - mockStoredMap.On("CanDecProviders", fromAddressId).Return(true, nil) - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginSigned(fromAddressId), - sc.NewVaryingData(primitives.NewMultiAddress20(primitives.Address20{}), sc.Bool(true)), - ) - - assert.Equal(t, primitives.NewDispatchErrorCannotLookup(), dispatchErr) - mockStoredMap.AssertCalled(t, "Get", fromAddressId) - mockStoredMap.AssertCalled(t, "CanDecProviders", fromAddressId) - mockMutator.AssertNotCalled(t, "tryMutateAccountWithDust", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_TransferAll_Dispatch_AllowDeath(t *testing.T) { - target := setupCallTransferAll() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - toAddressId, err := toAddress.AsAccountId() - assert.Nil(t, err) - - mockStoredMap.On("Get", fromAddressId).Return(accountInfo, nil) - mockStoredMap.On("CanDecProviders", fromAddressId).Return(true, nil) - mockMutator.On( - "tryMutateAccountWithDust", - toAddressId, - mockTypeMutateAccountDataBool, - ).Return(sc.Empty{}, nil) - mockStoredMap.On( - "DepositEvent", - newEventTransfer( - moduleId, - fromAddressId, - toAddressId, - accountInfo.Data.Free, - ), - ).Return() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginSigned(fromAddressId), - sc.NewVaryingData(toAddress, sc.Bool(false))) - - assert.Nil(t, dispatchErr) - mockStoredMap.AssertCalled(t, "Get", fromAddressId) - mockStoredMap.AssertCalled(t, "CanDecProviders", fromAddressId) - mockMutator.AssertCalled(t, - "tryMutateAccountWithDust", - toAddressId, - mockTypeMutateAccountDataBool, - ) - mockStoredMap.AssertCalled(t, - "DepositEvent", - newEventTransfer( - moduleId, - fromAddressId, - toAddressId, - accountInfo.Data.Free, - ), - ) -} - -func setupCallTransferAll() primitives.Call { - mockStoredMap = new(mocks.StoredMap) - mockMutator = new(mockAccountMutator) - - return newCallTransferAll(moduleId, functionTransferAllIndex, mockStoredMap, testConstants, mockMutator, logger) -} diff --git a/frame/balances/call_transfer_all_weight.go b/frame/balances/call_transfer_all_weight.go index 26c1daf4..69f34b45 100644 --- a/frame/balances/call_transfer_all_weight.go +++ b/frame/balances/call_transfer_all_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:29:47.11569 +0200 EET m=+1.121679876`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:14.427591 +0300 EEST m=+1.483197667`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 2083900000, BaseReads: 1, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 2083900, MinReads: 1, MinWrites: 1 +// BaseExtrinsicTime: 4129900000, BaseReads: 1, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 4129900, MinReads: 1, MinWrites: 1 package balances @@ -11,7 +11,7 @@ import ( ) func callTransferAllWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(2083900000, 0). + return primitives.WeightFromParts(4129900000, 0). SaturatingAdd(dbWeight.Reads(1)). SaturatingAdd(dbWeight.Writes(1)) } diff --git a/frame/balances/call_transfer_allow_death.go b/frame/balances/call_transfer_allow_death.go new file mode 100644 index 00000000..8e7785db --- /dev/null +++ b/frame/balances/call_transfer_allow_death.go @@ -0,0 +1,119 @@ +package balances + +import ( + "bytes" + + sc "github.com/LimeChain/goscale" + "github.com/LimeChain/gosemble/frame/balances/types" + primitives "github.com/LimeChain/gosemble/primitives/types" +) + +type callTransferAllowDeath struct { + primitives.Callable + module module +} + +func newCallTransferAllowDeath(moduleId sc.U8, functionId sc.U8, module module) primitives.Call { + return callTransferAllowDeath{ + Callable: primitives.Callable{ + ModuleId: moduleId, + FunctionId: functionId, + Arguments: sc.NewVaryingData(primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}), + }, + module: module, + } +} + +func (c callTransferAllowDeath) DecodeArgs(buffer *bytes.Buffer) (primitives.Call, error) { + dest, err := primitives.DecodeMultiAddress(buffer) + if err != nil { + return nil, err + } + value, err := sc.DecodeCompact[sc.U128](buffer) + if err != nil { + return nil, err + } + + c.Arguments = sc.NewVaryingData( + dest, + value, + ) + + return c, nil +} + +func (c callTransferAllowDeath) Encode(buffer *bytes.Buffer) error { + return c.Callable.Encode(buffer) +} + +func (c callTransferAllowDeath) Bytes() []byte { + return c.Callable.Bytes() +} + +func (c callTransferAllowDeath) ModuleIndex() sc.U8 { + return c.Callable.ModuleIndex() +} + +func (c callTransferAllowDeath) FunctionIndex() sc.U8 { + return c.Callable.FunctionIndex() +} + +func (c callTransferAllowDeath) Args() sc.VaryingData { + return c.Callable.Args() +} + +func (c callTransferAllowDeath) BaseWeight() primitives.Weight { + return callTransferAllowDeathWeight(c.module.constants.DbWeight) +} + +func (_ callTransferAllowDeath) WeighData(baseWeight primitives.Weight) primitives.Weight { + return primitives.WeightFromParts(baseWeight.RefTime, 0) +} + +func (_ callTransferAllowDeath) ClassifyDispatch(baseWeight primitives.Weight) primitives.DispatchClass { + return primitives.NewDispatchClassNormal() +} + +func (_ callTransferAllowDeath) PaysFee(baseWeight primitives.Weight) primitives.Pays { + return primitives.PaysYes +} + +func (_ callTransferAllowDeath) Docs() string { + return "Transfer some liquid free balance to another account. " + + "`transfer_allow_death` will set the `FreeBalance` of the sender and receiver. " + + " If the sender's account is below the existential deposit as a result" + + " of the transfer, the account will be reaped." + + "The dispatch origin for this call must be `Signed` by the transactor." +} + +func (c callTransferAllowDeath) Dispatch(origin primitives.RuntimeOrigin, args sc.VaryingData) (primitives.PostDispatchInfo, error) { + if !origin.IsSignedOrigin() { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorBadOrigin() + } + + from, originErr := origin.AsSigned() + if originErr != nil { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther(sc.Str(originErr.Error())) + } + + dest, ok := args[0].(primitives.MultiAddress) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid destination value in callTransferAllowDeath") + } + + to, err := primitives.Lookup(dest) + if err != nil { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorCannotLookup() + } + + valueCompact, ok := args[1].(sc.Compact) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid compact value in callTransferAllowDeath") + } + value, ok := valueCompact.Number.(sc.U128) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid U128 value in callTransferAllowDeath") + } + + return primitives.PostDispatchInfo{}, c.module.transfer(from, to, value, types.PreservationExpendable) +} diff --git a/frame/balances/call_transfer_allow_death_weight.go b/frame/balances/call_transfer_allow_death_weight.go new file mode 100644 index 00000000..87a51679 --- /dev/null +++ b/frame/balances/call_transfer_allow_death_weight.go @@ -0,0 +1,17 @@ +// THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE +// DATE: `2024-06-12 10:03:15.039506 +0300 EEST m=+2.095111417`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` + +// Summary: +// BaseExtrinsicTime: 3975150000, BaseReads: 1, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 3975150, MinReads: 1, MinWrites: 1 + +package balances + +import ( + primitives "github.com/LimeChain/gosemble/primitives/types" +) + +func callTransferAllowDeathWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { + return primitives.WeightFromParts(3975150000, 0). + SaturatingAdd(dbWeight.Reads(1)). + SaturatingAdd(dbWeight.Writes(1)) +} diff --git a/frame/balances/call_transfer_keep_alive.go b/frame/balances/call_transfer_keep_alive.go index 8b9460c4..111e9656 100644 --- a/frame/balances/call_transfer_keep_alive.go +++ b/frame/balances/call_transfer_keep_alive.go @@ -2,33 +2,30 @@ package balances import ( "bytes" - "errors" sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/primitives/types" + "github.com/LimeChain/gosemble/frame/balances/types" primitives "github.com/LimeChain/gosemble/primitives/types" ) type callTransferKeepAlive struct { primitives.Callable - transfer + module module } -func newCallTransferKeepAlive(moduleId sc.U8, functionId sc.U8, storedMap primitives.StoredMap, constants *consts, mutator accountMutator) primitives.Call { - call := callTransferKeepAlive{ +func newCallTransferKeepAlive(moduleId sc.U8, functionId sc.U8, module module) primitives.Call { + return callTransferKeepAlive{ Callable: primitives.Callable{ ModuleId: moduleId, FunctionId: functionId, - Arguments: sc.NewVaryingData(types.MultiAddress{}, sc.Compact{Number: sc.U128{}}), + Arguments: sc.NewVaryingData(primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}), }, - transfer: newTransfer(moduleId, storedMap, constants, mutator), + module: module, } - - return call } func (c callTransferKeepAlive) DecodeArgs(buffer *bytes.Buffer) (primitives.Call, error) { - dest, err := types.DecodeMultiAddress(buffer) + dest, err := primitives.DecodeMultiAddress(buffer) if err != nil { return nil, err } @@ -36,10 +33,12 @@ func (c callTransferKeepAlive) DecodeArgs(buffer *bytes.Buffer) (primitives.Call if err != nil { return nil, err } + c.Arguments = sc.NewVaryingData( dest, value, ) + return c, nil } @@ -63,52 +62,57 @@ func (c callTransferKeepAlive) Args() sc.VaryingData { return c.Callable.Args() } -func (c callTransferKeepAlive) BaseWeight() types.Weight { - return callTransferKeepAliveWeight(c.constants.DbWeight) +func (c callTransferKeepAlive) BaseWeight() primitives.Weight { + return callTransferKeepAliveWeight(c.module.constants.DbWeight) } -func (_ callTransferKeepAlive) WeighData(baseWeight types.Weight) types.Weight { - return types.WeightFromParts(baseWeight.RefTime, 0) +func (_ callTransferKeepAlive) WeighData(baseWeight primitives.Weight) primitives.Weight { + return primitives.WeightFromParts(baseWeight.RefTime, 0) } -func (_ callTransferKeepAlive) ClassifyDispatch(baseWeight types.Weight) types.DispatchClass { - return types.NewDispatchClassNormal() +func (_ callTransferKeepAlive) ClassifyDispatch(baseWeight primitives.Weight) primitives.DispatchClass { + return primitives.NewDispatchClassNormal() } -func (_ callTransferKeepAlive) PaysFee(baseWeight types.Weight) types.Pays { - return types.PaysYes +func (_ callTransferKeepAlive) PaysFee(baseWeight primitives.Weight) primitives.Pays { + return primitives.PaysYes } func (_ callTransferKeepAlive) Docs() string { - return "Same as the [`transfer`] call, but with a check that the transfer will not kill the origin account." -} - -func (c callTransferKeepAlive) Dispatch(origin types.RuntimeOrigin, args sc.VaryingData) (types.PostDispatchInfo, error) { - valueCompact, ok := args[1].(sc.Compact) - if !ok { - return types.PostDispatchInfo{}, errors.New("invalid compact value when dispatching call transfer keep alive") - } - value, ok := valueCompact.Number.(sc.U128) - if !ok { - return types.PostDispatchInfo{}, errors.New("invalid compact number field when dispatching call transfer keep alive") - } - return types.PostDispatchInfo{}, c.transferKeepAlive(origin, args[0].(types.MultiAddress), value) + return "Same as the [`transfer_allow_death`] call, but with a check that the transfer will not " + + "kill the origin account. " + + "99% of the time you want [`transfer_allow_death`] instead. " + + "[`transfer_allow_death`]: struct.Pallet.html#method.transfer" } -// transferKeepAlive is similar to transfer, but includes a check that the origin transactor will not be "killed". -func (c callTransferKeepAlive) transferKeepAlive(origin types.RawOrigin, dest types.MultiAddress, value sc.U128) error { +func (c callTransferKeepAlive) Dispatch(origin primitives.RuntimeOrigin, args sc.VaryingData) (primitives.PostDispatchInfo, error) { if !origin.IsSignedOrigin() { - return types.NewDispatchErrorBadOrigin() + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorBadOrigin() } - transactor, originErr := origin.AsSigned() + + from, originErr := origin.AsSigned() if originErr != nil { - return primitives.NewDispatchErrorOther(sc.Str(originErr.Error())) + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther(sc.Str(originErr.Error())) + } + + dest, ok := args[0].(primitives.MultiAddress) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid destination value in callTransferKeepAlive") } - address, err := types.Lookup(dest) + to, err := primitives.Lookup(dest) if err != nil { - return types.NewDispatchErrorCannotLookup() + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorCannotLookup() + } + + valueCompact, ok := args[1].(sc.Compact) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid compact value in callTransferKeepAlive") + } + value, ok := valueCompact.Number.(sc.U128) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid U128 value in callTransferKeepAlive") } - return c.transfer.trans(transactor, address, value, types.ExistenceRequirementKeepAlive) + return primitives.PostDispatchInfo{}, c.module.transfer(from, to, value, types.PreservationPreserve) } diff --git a/frame/balances/call_transfer_keep_alive_test.go b/frame/balances/call_transfer_keep_alive_test.go deleted file mode 100644 index 1c9d9ed1..00000000 --- a/frame/balances/call_transfer_keep_alive_test.go +++ /dev/null @@ -1,209 +0,0 @@ -package balances - -import ( - "bytes" - "errors" - "testing" - - sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/mocks" - primitives "github.com/LimeChain/gosemble/primitives/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -var ( - transferKeepAliveArgsBytes = sc.NewVaryingData(primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}).Bytes() -) - -func Test_Call_TransferKeepAlive_new(t *testing.T) { - target := setupCallTransferKeepAlive() - expected := callTransferKeepAlive{ - Callable: primitives.Callable{ - ModuleId: moduleId, - FunctionId: functionTransferKeepAliveIndex, - Arguments: sc.NewVaryingData(primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}), - }, - transfer: transfer{ - moduleId: moduleId, - storedMap: mockStoredMap, - constants: testConstants, - accountMutator: mockMutator, - }, - } - - assert.Equal(t, expected, target) -} - -func Test_Call_TransferKeepAlive_DecodeArgs(t *testing.T) { - amount := sc.ToCompact(sc.NewU128(1)) - buf := bytes.NewBuffer(append(targetAddress.Bytes(), amount.Bytes()...)) - - target := setupCallTransferKeepAlive() - call, err := target.DecodeArgs(buf) - assert.Nil(t, err) - - assert.Equal(t, sc.NewVaryingData(targetAddress, amount), call.Args()) -} - -func Test_Call_TransferKeepAlive_Encode(t *testing.T) { - target := setupCallTransferKeepAlive() - expectedBuffer := bytes.NewBuffer(append([]byte{moduleId, functionTransferKeepAliveIndex}, transferKeepAliveArgsBytes...)) - buf := &bytes.Buffer{} - - err := target.Encode(buf) - - assert.NoError(t, err) - assert.Equal(t, expectedBuffer, buf) -} - -func Test_Call_TransferKeepAlive_Bytes(t *testing.T) { - expected := append([]byte{moduleId, functionTransferKeepAliveIndex}, transferKeepAliveArgsBytes...) - - target := setupCallTransferKeepAlive() - - assert.Equal(t, expected, target.Bytes()) -} - -func Test_Call_TransferKeepAlive_ModuleIndex(t *testing.T) { - target := setupCallTransferKeepAlive() - - assert.Equal(t, sc.U8(moduleId), target.ModuleIndex()) -} - -func Test_Call_TransferKeepAlive_FunctionIndex(t *testing.T) { - target := setupCallTransferKeepAlive() - - assert.Equal(t, sc.U8(functionTransferKeepAliveIndex), target.FunctionIndex()) -} - -func Test_Call_TransferKeepAlive_BaseWeight(t *testing.T) { - target := setupCallTransferKeepAlive() - - assert.Equal(t, callTransferKeepAliveWeight(dbWeight), target.BaseWeight()) -} - -func Test_Call_TransferKeepAlive_WeighData(t *testing.T) { - target := setupCallTransferKeepAlive() - assert.Equal(t, primitives.WeightFromParts(124, 0), target.WeighData(baseWeight)) -} - -func Test_Call_TransferKeepAlive_ClassifyDispatch(t *testing.T) { - target := setupCallTransferKeepAlive() - - assert.Equal(t, primitives.NewDispatchClassNormal(), target.ClassifyDispatch(baseWeight)) -} - -func Test_Call_TransferKeepAlive_PaysFee(t *testing.T) { - target := setupCallTransferKeepAlive() - - assert.Equal(t, primitives.PaysYes, target.PaysFee(baseWeight)) -} - -func Test_Call_TransferKeepAlive_Dispatch_Success(t *testing.T) { - target := setupCallTransferKeepAlive() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - toAddressId, err := toAddress.AsAccountId() - assert.Nil(t, err) - - mockMutator.On( - "tryMutateAccountWithDust", - toAddressId, - mockTypeMutateAccountDataBool, - ).Return(sc.Empty{}, nil) - mockStoredMap.On( - "DepositEvent", - newEventTransfer( - moduleId, - fromAddressId, - toAddressId, - targetValue, - ), - ).Return() - - _, dispatchErr := target.Dispatch(primitives.NewRawOriginSigned(fromAddressId), sc.NewVaryingData(toAddress, sc.ToCompact(targetValue))) - - assert.Nil(t, dispatchErr) - mockMutator.AssertCalled(t, - "tryMutateAccountWithDust", - toAddressId, - mockTypeMutateAccountDataBool, - ) - mockStoredMap.AssertCalled(t, - "DepositEvent", - newEventTransfer( - moduleId, - fromAddressId, - toAddressId, - targetValue, - ), - ) -} - -func Test_Call_TransferKeepAlive_Dispatch_BadOrigin(t *testing.T) { - target := setupCallTransferKeepAlive() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginNone(), - sc.NewVaryingData(fromAddress, sc.ToCompact(targetValue)), - ) - - assert.Equal(t, primitives.NewDispatchErrorBadOrigin(), dispatchErr) - mockMutator.AssertNotCalled(t, "tryMutateAccountWithDust", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_TransferKeepAlive_Dispatch_InvalidArgs_InvalidCompact(t *testing.T) { - target := setupCallTransferKeepAlive() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginNone(), - sc.NewVaryingData(fromAddress, sc.NewU64(0)), - ) - - assert.Equal(t, errors.New("invalid compact value when dispatching call transfer keep alive"), dispatchErr) - - mockMutator.AssertNotCalled(t, "tryMutateAccountWithDust", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_TransferKeepAlive_Dispatch_InvalidArgs_InvalidCompactNumber(t *testing.T) { - target := setupCallTransferKeepAlive() - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginNone(), - sc.NewVaryingData(fromAddress, sc.Compact{}), - ) - - assert.Equal(t, errors.New("invalid compact number field when dispatching call transfer keep alive"), dispatchErr) - - mockMutator.AssertNotCalled(t, "tryMutateAccountWithDust", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_Call_TransferKeepAlive_Dispatch_CannotLookup(t *testing.T) { - target := setupCallTransferKeepAlive() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - _, dispatchErr := target. - Dispatch( - primitives.NewRawOriginSigned(fromAddressId), - sc.NewVaryingData(primitives.NewMultiAddress20(primitives.Address20{}), sc.ToCompact(targetValue)), - ) - - assert.Equal(t, primitives.NewDispatchErrorCannotLookup(), dispatchErr) - mockMutator.AssertNotCalled(t, "tryMutateAccountWithDust", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func setupCallTransferKeepAlive() primitives.Call { - mockStoredMap = new(mocks.StoredMap) - mockMutator = new(mockAccountMutator) - - return newCallTransferKeepAlive(moduleId, functionTransferKeepAliveIndex, mockStoredMap, testConstants, mockMutator) -} diff --git a/frame/balances/call_transfer_keep_alive_weight.go b/frame/balances/call_transfer_keep_alive_weight.go index 5fcabd26..a45fbb26 100644 --- a/frame/balances/call_transfer_keep_alive_weight.go +++ b/frame/balances/call_transfer_keep_alive_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:29:47.333995 +0200 EET m=+1.339986542`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:14.734411 +0300 EEST m=+1.790017042`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 1782050000, BaseReads: 1, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 1782050, MinReads: 1, MinWrites: 1 +// BaseExtrinsicTime: 3709350000, BaseReads: 1, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 3709350, MinReads: 1, MinWrites: 1 package balances @@ -11,7 +11,7 @@ import ( ) func callTransferKeepAliveWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(1782050000, 0). + return primitives.WeightFromParts(3709350000, 0). SaturatingAdd(dbWeight.Reads(1)). SaturatingAdd(dbWeight.Writes(1)) } diff --git a/frame/balances/call_transfer_test.go b/frame/balances/call_transfer_test.go deleted file mode 100644 index bcb84c0f..00000000 --- a/frame/balances/call_transfer_test.go +++ /dev/null @@ -1,499 +0,0 @@ -package balances - -import ( - "bytes" - "errors" - "testing" - - sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/constants" - "github.com/LimeChain/gosemble/mocks" - primitives "github.com/LimeChain/gosemble/primitives/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -var ( - maxLocks = sc.U32(5) - maxReserves = sc.U32(6) - existentialDeposit = sc.NewU128(1) - mockMutator *mockAccountMutator - testConstants = newConstants(dbWeight, maxLocks, maxReserves, existentialDeposit) - - fromAccountData *primitives.AccountData - toAccountData *primitives.AccountData - - fromAddress = primitives. - NewMultiAddressId(constants.OneAccountId) - toAddress = primitives. - NewMultiAddressId(constants.TwoAccountId) - argsBytes = sc.NewVaryingData(primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}).Bytes() - - callTransferArgsBytes = sc.NewVaryingData(primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}).Bytes() -) - -func Test_Call_Transfer_New(t *testing.T) { - target := setupCallTransfer() - expected := callTransfer{ - Callable: primitives.Callable{ - ModuleId: moduleId, - FunctionId: functionTransferIndex, - Arguments: sc.NewVaryingData(primitives.MultiAddress{}, sc.Compact{Number: sc.U128{}}), - }, - transfer: transfer{ - moduleId: moduleId, - storedMap: mockStoredMap, - constants: testConstants, - accountMutator: mockMutator, - }, - } - - assert.Equal(t, expected, target) -} - -func Test_Call_Transfer_DecodeArgs(t *testing.T) { - amount := sc.ToCompact(sc.NewU128(5)) - buf := bytes.NewBuffer(append(targetAddress.Bytes(), amount.Bytes()...)) - - target := setupCallTransfer() - call, err := target.DecodeArgs(buf) - assert.Nil(t, err) - - assert.Equal(t, sc.NewVaryingData(targetAddress, amount), call.Args()) -} - -func Test_Call_Transfer_Encode(t *testing.T) { - target := setupCallTransfer() - expectedBuffer := bytes.NewBuffer(append([]byte{moduleId, functionTransferIndex}, callTransferArgsBytes...)) - buf := &bytes.Buffer{} - - err := target.Encode(buf) - - assert.NoError(t, err) - assert.Equal(t, expectedBuffer, buf) -} - -func Test_Call_Transfer_Bytes(t *testing.T) { - expected := append([]byte{moduleId, functionTransferIndex}, callTransferArgsBytes...) - - target := setupCallTransfer() - - assert.Equal(t, expected, target.Bytes()) -} - -func Test_Call_Transfer_ModuleIndex(t *testing.T) { - target := setupCallTransfer() - - assert.Equal(t, sc.U8(moduleId), target.ModuleIndex()) -} - -func Test_Call_Transfer_FunctionIndex(t *testing.T) { - target := setupCallTransfer() - - assert.Equal(t, sc.U8(functionTransferIndex), target.FunctionIndex()) -} - -func Test_Call_Transfer_BaseWeight(t *testing.T) { - target := setupCallTransfer() - - assert.Equal(t, callTransferWeight(dbWeight), target.BaseWeight()) -} - -func Test_Call_Transfer_WeighData(t *testing.T) { - target := setupCallTransfer() - assert.Equal(t, primitives.WeightFromParts(124, 0), target.WeighData(baseWeight)) -} - -func Test_Call_Transfer_ClassifyDispatch(t *testing.T) { - target := setupCallTransfer() - - assert.Equal(t, primitives.NewDispatchClassNormal(), target.ClassifyDispatch(baseWeight)) -} - -func Test_Call_Transfer_PaysFee(t *testing.T) { - target := setupCallTransfer() - - assert.Equal(t, primitives.PaysYes, target.PaysFee(baseWeight)) -} - -func Test_Call_Transfer_Dispatch_Success(t *testing.T) { - target := setupCallTransfer() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - _, dispatchErr := target. - Dispatch(primitives.NewRawOriginSigned(fromAddressId), sc.NewVaryingData(fromAddress, sc.ToCompact(targetValue))) - - assert.Nil(t, dispatchErr) -} - -func Test_Call_Transfer_Dispatch_BadOrigin(t *testing.T) { - target := setupCallTransfer() - - _, dispatchErr := target.Dispatch(primitives.NewRawOriginNone(), sc.NewVaryingData(toAddress, sc.ToCompact(targetValue))) - - assert.Equal(t, primitives.NewDispatchErrorBadOrigin(), dispatchErr) -} - -func Test_Call_Transfer_Dispatch_InvalidArg_InvalidCompactAmount(t *testing.T) { - target := setupCallTransfer() - - _, dispatchErr := target.Dispatch(primitives.NewRawOriginNone(), sc.NewVaryingData(toAddress, sc.NewU64(0))) - - assert.Equal(t, errors.New("invalid compact value when dispatching call transfer"), dispatchErr) -} - -func Test_Call_Transfer_Dispatch_InvalidArg_InvalidCompactNumber(t *testing.T) { - target := setupCallTransfer() - - _, dispatchErr := target.Dispatch(primitives.NewRawOriginNone(), sc.NewVaryingData(toAddress, sc.Compact{})) - - assert.Equal(t, errors.New("invalid compact number field when dispatching call transfer"), dispatchErr) -} - -func Test_Call_Transfer_Dispatch_CannotLookup(t *testing.T) { - target := setupCallTransfer() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - _, dispatchErr := target.Dispatch( - primitives.NewRawOriginSigned(fromAddressId), - sc.NewVaryingData(primitives.NewMultiAddress20(primitives.Address20{}), sc.ToCompact(targetValue)), - ) - - assert.Equal(t, primitives.NewDispatchErrorCannotLookup(), dispatchErr) -} - -func Test_transfer_New(t *testing.T) { - target := setupTransfer() - expected := transfer{ - moduleId: moduleId, - storedMap: mockStoredMap, - constants: testConstants, - accountMutator: mockMutator, - } - - assert.Equal(t, expected, target) -} - -func Test_transfer_Success(t *testing.T) { - target := setupTransfer() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - result := target.transfer(primitives.NewRawOriginSigned(fromAddressId), fromAddress, targetValue) - - assert.Nil(t, result) -} - -func Test_transfer_InvalidOrigin(t *testing.T) { - target := setupTransfer() - - result := target.transfer(primitives.NewRawOriginRoot(), toAddress, targetValue) - - assert.Equal(t, primitives.NewDispatchErrorBadOrigin(), result) -} - -func Test_transfer_InvalidLookup(t *testing.T) { - target := setupTransfer() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - result := target. - transfer(primitives.NewRawOriginSigned(fromAddressId), primitives.NewMultiAddress20(primitives.Address20{}), targetValue) - - assert.Equal(t, primitives.NewDispatchErrorCannotLookup(), result) -} - -func Test_transfer_trans_Success(t *testing.T) { - target := setupTransfer() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - toAddressId, err := toAddress.AsAccountId() - assert.Nil(t, err) - - mockMutator.On( - "tryMutateAccountWithDust", - toAddressId, - mockTypeMutateAccountDataBool, - ).Return(sc.Empty{}, nil) - mockStoredMap.On( - "DepositEvent", - newEventTransfer(moduleId, fromAddressId, toAddressId, targetValue), - ).Return() - - result := target.trans(fromAddressId, toAddressId, targetValue, primitives.ExistenceRequirementKeepAlive) - - assert.Nil(t, result) - mockMutator.AssertCalled(t, - "tryMutateAccountWithDust", - toAddressId, - mockTypeMutateAccountDataBool, - ) - mockStoredMap.AssertCalled(t, - "DepositEvent", - newEventTransfer(moduleId, fromAddressId, toAddressId, targetValue), - ) -} - -func Test_transfer_trans_ZeroValue(t *testing.T) { - target := setupTransfer() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - toAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - result := target.trans(fromAddressId, toAddressId, sc.NewU128(0), primitives.ExistenceRequirementAllowDeath) - - assert.Nil(t, result) - mockMutator.AssertNotCalled(t, "tryMutateAccountWithDust", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_transfer_trans_EqualFromTo(t *testing.T) { - target := setupTransfer() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - result := target.trans(fromAddressId, fromAddressId, targetValue, primitives.ExistenceRequirementAllowDeath) - - assert.Nil(t, result) - mockMutator.AssertNotCalled(t, "tryMutateAccountWithDust", mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_transfer_trans_MutateAccountWithDust_Fails(t *testing.T) { - target := setupTransfer() - expectedErr := primitives.NewDispatchErrorBadOrigin() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - toAddressId, err := toAddress.AsAccountId() - assert.Nil(t, err) - - mockMutator.On( - "tryMutateAccountWithDust", - toAddressId, - mockTypeMutateAccountDataBool, - ).Return(sc.Empty{}, expectedErr) - - result := target.trans(fromAddressId, toAddressId, targetValue, primitives.ExistenceRequirementKeepAlive) - - assert.Equal(t, expectedErr, result) - mockMutator.AssertCalled(t, - "tryMutateAccountWithDust", - toAddressId, - mockTypeMutateAccountDataBool, - ) - mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) -} - -func Test_transfer_sanityChecks_Success(t *testing.T) { - target := setupTransfer() - - targetAddressId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - - mockMutator.On("ensureCanWithdraw", targetAddressId, targetValue, primitives.ReasonsAll, sc.NewU128(0)).Return(nil) - mockStoredMap.On("CanDecProviders", targetAddressId).Return(true, nil) - - result, err := target.sanityChecks(targetAddressId, fromAccountData, toAccountData, targetValue, primitives.ExistenceRequirementAllowDeath) - - assert.Nil(t, err) - assert.Nil(t, result) - assert.Equal(t, sc.NewU128(0), fromAccountData.Free) - assert.Equal(t, sc.NewU128(6), toAccountData.Free) - mockMutator.AssertCalled(t, "ensureCanWithdraw", targetAddressId, targetValue, primitives.ReasonsAll, sc.NewU128(0)) - mockStoredMap.AssertCalled(t, "CanDecProviders", targetAddressId) -} - -func Test_transfer_sanityChecks_InsufficientBalance(t *testing.T) { - target := setupTransfer() - expectedErr := primitives.NewDispatchErrorModule(primitives.CustomModuleError{ - Index: moduleId, - Err: sc.U32(ErrorInsufficientBalance), - Message: sc.NewOption[sc.Str](nil), - }) - - targetAddressId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - - _, err = target.sanityChecks(targetAddressId, fromAccountData, toAccountData, sc.NewU128(6), primitives.ExistenceRequirementKeepAlive) - - assert.Equal(t, expectedErr, err) - assert.Equal(t, sc.NewU128(5), fromAccountData.Free) - assert.Equal(t, sc.NewU128(1), toAccountData.Free) - mockMutator.AssertNotCalled(t, "ensureCanWithdraw", mock.Anything, mock.Anything, mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "CanDecProviders", mock.Anything) -} - -func Test_transfer_sanityChecks_ArithmeticOverflow(t *testing.T) { - target := setupTransfer() - expectedErr := primitives.NewDispatchErrorArithmetic(primitives.NewArithmeticErrorOverflow()) - toAccountData.Free = sc.MaxU128() - - targetAddressId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - - _, err = target.sanityChecks(targetAddressId, fromAccountData, toAccountData, sc.NewU128(1), primitives.ExistenceRequirementKeepAlive) - - assert.Equal(t, expectedErr, err) - assert.Equal(t, sc.NewU128(4), fromAccountData.Free) - assert.Equal(t, sc.MaxU128(), toAccountData.Free) - mockMutator.AssertNotCalled(t, "ensureCanWithdraw", mock.Anything, mock.Anything, mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "CanDecProviders", mock.Anything) -} - -func Test_transfer_sanityChecks_ExistentialDeposit(t *testing.T) { - target := setupTransfer() - expectedErr := primitives.NewDispatchErrorModule(primitives.CustomModuleError{ - Index: moduleId, - Err: sc.U32(ErrorExistentialDeposit), - Message: sc.NewOption[sc.Str](nil), - }) - toAccountData.Free = sc.NewU128(0) - - targetAddressId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - - _, err = target.sanityChecks(targetAddressId, fromAccountData, toAccountData, sc.NewU128(0), primitives.ExistenceRequirementKeepAlive) - - assert.Equal(t, expectedErr, err) - assert.Equal(t, sc.NewU128(5), fromAccountData.Free) - assert.Equal(t, sc.NewU128(0), toAccountData.Free) - mockMutator.AssertNotCalled(t, "ensureCanWithdraw", mock.Anything, mock.Anything, mock.Anything, mock.Anything) - mockStoredMap.AssertNotCalled(t, "CanDecProviders", mock.Anything) -} - -func Test_transfer_sanityChecks_CannotWithdraw(t *testing.T) { - target := setupTransfer() - expectedErr := primitives.NewDispatchErrorCannotLookup() - - targetAddressId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - - mockMutator.On("ensureCanWithdraw", targetAddressId, targetValue, primitives.ReasonsAll, sc.NewU128(0)).Return(expectedErr) - - _, err = target.sanityChecks(targetAddressId, fromAccountData, toAccountData, targetValue, primitives.ExistenceRequirementAllowDeath) - - assert.Equal(t, expectedErr, err) - assert.Equal(t, sc.NewU128(0), fromAccountData.Free) - assert.Equal(t, sc.NewU128(6), toAccountData.Free) - mockMutator.AssertCalled(t, "ensureCanWithdraw", targetAddressId, targetValue, primitives.ReasonsAll, sc.NewU128(0)) -} - -func Test_transfer_sanityChecks_KeepAlive(t *testing.T) { - target := setupTransfer() - expectedErr := primitives.NewDispatchErrorModule(primitives.CustomModuleError{ - Index: moduleId, - Err: sc.U32(ErrorKeepAlive), - Message: sc.NewOption[sc.Str](nil), - }) - - targetAddressId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - - mockMutator.On("ensureCanWithdraw", targetAddressId, targetValue, primitives.ReasonsAll, sc.NewU128(0)).Return(nil) - mockStoredMap.On("CanDecProviders", targetAddressId).Return(false, nil) - - _, err = target.sanityChecks(targetAddressId, fromAccountData, toAccountData, targetValue, primitives.ExistenceRequirementAllowDeath) - - assert.Equal(t, expectedErr, err) - assert.Equal(t, sc.NewU128(0), fromAccountData.Free) - assert.Equal(t, sc.NewU128(6), toAccountData.Free) - mockMutator.AssertCalled(t, "ensureCanWithdraw", targetAddressId, targetValue, primitives.ReasonsAll, sc.NewU128(0)) - mockStoredMap.AssertCalled(t, "CanDecProviders", targetAddressId) -} - -func Test_transfer_sanityChecks_CanDecProviders_Error(t *testing.T) { - target := setupTransfer() - - targetAddressId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - - mockErr := errors.New("err") - expectedErr := primitives.NewDispatchErrorOther(sc.Str(mockErr.Error())) - - mockMutator.On("ensureCanWithdraw", targetAddressId, targetValue, primitives.ReasonsAll, sc.NewU128(0)).Return(nil) - mockStoredMap.On("CanDecProviders", targetAddressId).Return(true, mockErr) - - _, err = target.sanityChecks(targetAddressId, fromAccountData, toAccountData, targetValue, primitives.ExistenceRequirementAllowDeath) - - assert.Equal(t, expectedErr, err) - mockMutator.AssertCalled(t, "ensureCanWithdraw", targetAddressId, targetValue, primitives.ReasonsAll, sc.NewU128(0)) - mockStoredMap.AssertCalled(t, "CanDecProviders", targetAddressId) -} - -func Test_transfer_reducibleBalance_NotKeepAlive(t *testing.T) { - target := setupTransfer() - - targetAddressId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - - mockStoredMap.On("Get", targetAddressId).Return(accountInfo, nil) - mockStoredMap.On("CanDecProviders", targetAddressId).Return(true, nil) - - result, err := target.reducibleBalance(targetAddressId, false) - assert.Nil(t, err) - - assert.Equal(t, accountInfo.Data.Free, result) - mockStoredMap.AssertCalled(t, "Get", targetAddressId) - mockStoredMap.AssertCalled(t, "CanDecProviders", targetAddressId) -} - -func Test_transfer_reducibleBalance_KeepAlive(t *testing.T) { - target := setupTransfer() - - targetAddressId, err := targetAddress.AsAccountId() - assert.Nil(t, err) - - mockStoredMap.On("Get", targetAddressId).Return(accountInfo, nil) - mockStoredMap.On("CanDecProviders", targetAddressId).Return(false, nil) - - result, err := target.reducibleBalance(targetAddressId, true) - assert.Nil(t, err) - - assert.Equal(t, accountInfo.Data.Free.Sub(existentialDeposit), result) - mockStoredMap.AssertCalled(t, "Get", targetAddressId) - mockStoredMap.AssertCalled(t, "CanDecProviders", targetAddressId) -} - -func setupCallTransfer() primitives.Call { - mockStoredMap = new(mocks.StoredMap) - mockMutator = new(mockAccountMutator) - - fromAccountData = &primitives.AccountData{ - Free: sc.NewU128(5), - } - - toAccountData = &primitives.AccountData{ - Free: sc.NewU128(1), - } - - return newCallTransfer(moduleId, functionTransferIndex, mockStoredMap, testConstants, mockMutator) -} - -func setupTransfer() transfer { - mockStoredMap = new(mocks.StoredMap) - mockMutator = new(mockAccountMutator) - - fromAccountData = &primitives.AccountData{ - Free: sc.NewU128(5), - } - - toAccountData = &primitives.AccountData{ - Free: sc.NewU128(1), - } - - return newTransfer(moduleId, mockStoredMap, testConstants, mockMutator) -} diff --git a/frame/balances/call_transfer_weight.go b/frame/balances/call_transfer_weight.go deleted file mode 100644 index a917bc71..00000000 --- a/frame/balances/call_transfer_weight.go +++ /dev/null @@ -1,17 +0,0 @@ -// THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:29:47.551814 +0200 EET m=+1.557806584`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` - -// Summary: -// BaseExtrinsicTime: 1778550000, BaseReads: 1, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 1778550, MinReads: 1, MinWrites: 1 - -package balances - -import ( - primitives "github.com/LimeChain/gosemble/primitives/types" -) - -func callTransferWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(1778550000, 0). - SaturatingAdd(dbWeight.Reads(1)). - SaturatingAdd(dbWeight.Writes(1)) -} diff --git a/frame/balances/call_upgrade_accounts.go b/frame/balances/call_upgrade_accounts.go new file mode 100644 index 00000000..0546f840 --- /dev/null +++ b/frame/balances/call_upgrade_accounts.go @@ -0,0 +1,101 @@ +package balances + +import ( + "bytes" + + sc "github.com/LimeChain/goscale" + primitives "github.com/LimeChain/gosemble/primitives/types" +) + +type callUpgradeAccounts struct { + primitives.Callable + module module +} + +func newCallUpgradeAccounts(moduleId sc.U8, functionId sc.U8, module module) primitives.Call { + return callUpgradeAccounts{ + Callable: primitives.Callable{ + ModuleId: moduleId, + FunctionId: functionId, + Arguments: sc.NewVaryingData(sc.Sequence[primitives.AccountId]{}), + }, + module: module, + } +} + +func (c callUpgradeAccounts) DecodeArgs(buffer *bytes.Buffer) (primitives.Call, error) { + who, err := primitives.DecodeSequenceAccountId(buffer) + if err != nil { + return nil, err + } + + c.Arguments = sc.NewVaryingData(who) + + return c, nil +} + +func (c callUpgradeAccounts) Encode(buffer *bytes.Buffer) error { + return c.Callable.Encode(buffer) +} + +func (c callUpgradeAccounts) Bytes() []byte { + return c.Callable.Bytes() +} + +func (c callUpgradeAccounts) ModuleIndex() sc.U8 { return c.Callable.ModuleIndex() } + +func (c callUpgradeAccounts) FunctionIndex() sc.U8 { return c.Callable.FunctionIndex() } + +func (c callUpgradeAccounts) Args() sc.VaryingData { return c.Callable.Args() } + +func (c callUpgradeAccounts) BaseWeight() primitives.Weight { + accounts := c.Arguments[0].(sc.Sequence[primitives.AccountId]) + return callUpgradeAccountsWeight(c.module.constants.DbWeight, sc.U64(len(accounts))) +} + +func (_ callUpgradeAccounts) WeighData(baseWeight primitives.Weight) primitives.Weight { + return primitives.WeightFromParts(baseWeight.RefTime, 0) +} + +func (_ callUpgradeAccounts) ClassifyDispatch(baseWeight primitives.Weight) primitives.DispatchClass { + return primitives.NewDispatchClassNormal() +} + +func (_ callUpgradeAccounts) PaysFee(baseWeight primitives.Weight) primitives.Pays { + return primitives.PaysYes +} + +func (_ callUpgradeAccounts) Docs() string { + return "Upgrade a specified `account`." +} + +func (c callUpgradeAccounts) Dispatch(origin primitives.RuntimeOrigin, args sc.VaryingData) (primitives.PostDispatchInfo, error) { + if !origin.IsSignedOrigin() { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorBadOrigin() + } + + who, ok := args[0].(sc.Sequence[primitives.AccountId]) + if !ok { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther("invalid argument in callUpgradeAccounts") + } + if len(who) == 0 { + return primitives.PostDispatchInfo{PaysFee: primitives.PaysYes}, nil + } + + upgradeCount := 0 + for _, accountId := range who { + upgraded, err := c.module.ensureUpgraded(accountId) + if err != nil { + return primitives.PostDispatchInfo{}, primitives.NewDispatchErrorOther(sc.Str(err.Error())) + } + if upgraded { + upgradeCount += 1 + } + } + upgraded := (upgradeCount * 100) / len(who) + if upgraded > 90 { + return primitives.PostDispatchInfo{PaysFee: primitives.PaysNo}, nil + } + + return primitives.PostDispatchInfo{PaysFee: primitives.PaysYes}, nil +} diff --git a/frame/balances/call_upgrade_accounts_weight.go b/frame/balances/call_upgrade_accounts_weight.go new file mode 100644 index 00000000..0229993d --- /dev/null +++ b/frame/balances/call_upgrade_accounts_weight.go @@ -0,0 +1,14 @@ +package balances + +import ( + sc "github.com/LimeChain/goscale" + primitives "github.com/LimeChain/gosemble/primitives/types" +) + +func callUpgradeAccountsWeight(dbWeight primitives.RuntimeDbWeight, length sc.U64) primitives.Weight { + return primitives.WeightFromParts(16118000, 990). + SaturatingAdd(primitives.WeightFromParts(13327660, 0).SaturatingMul(length)). + SaturatingAdd(dbWeight.Reads(1).SaturatingMul(length)). + SaturatingAdd(dbWeight.Writes(1).SaturatingMul(length)). + SaturatingAdd(primitives.WeightFromParts(0, 2603).SaturatingMul(length)) +} diff --git a/frame/balances/errors.go b/frame/balances/errors.go index 7c1de932..613005cc 100644 --- a/frame/balances/errors.go +++ b/frame/balances/errors.go @@ -8,8 +8,12 @@ const ( ErrorLiquidityRestrictions ErrorInsufficientBalance ErrorExistentialDeposit - ErrorKeepAlive + ErrorExpendability ErrorExistingVestingSchedule ErrorDeadAccount ErrorTooManyReserves + ErrorTooManyHolds + ErrorTooManyFreezes + ErrorIssuanceDeactivated + ErrorDeltaZero ) diff --git a/frame/balances/events.go b/frame/balances/events.go index 77a29c69..98bb5145 100644 --- a/frame/balances/events.go +++ b/frame/balances/events.go @@ -21,6 +21,18 @@ const ( EventDeposit EventWithdraw EventSlashed + EventMinted + EventBurned + EventSuspended + EventRestored + EventUpgraded + EventIssued + EventRescinded + EventLocked + EventUnlocked + EventFrozen + EventThawed + EventTotalIssuanceForced ) var ( @@ -40,8 +52,8 @@ func newEventTransfer(moduleIndex sc.U8, from primitives.AccountId, to primitive return primitives.NewEvent(moduleIndex, EventTransfer, from, to, amount) } -func newEventBalanceSet(moduleIndex sc.U8, account primitives.AccountId, free primitives.Balance, reserved primitives.Balance) primitives.Event { - return primitives.NewEvent(moduleIndex, EventBalanceSet, account, free, reserved) +func newEventBalanceSet(moduleIndex sc.U8, account primitives.AccountId, free primitives.Balance) primitives.Event { + return primitives.NewEvent(moduleIndex, EventBalanceSet, account, free) } func newEventReserved(moduleIndex sc.U8, account primitives.AccountId, amount primitives.Balance) primitives.Event { @@ -68,6 +80,54 @@ func newEventSlashed(moduleIndex sc.U8, account primitives.AccountId, amount pri return primitives.NewEvent(moduleIndex, EventSlashed, account, amount) } +func newEventMinted(moduleIndex sc.U8, account primitives.AccountId, amount primitives.Balance) primitives.Event { + return primitives.NewEvent(moduleIndex, EventMinted, account, amount) +} + +func newEventBurned(moduleIndex sc.U8, account primitives.AccountId, amount primitives.Balance) primitives.Event { + return primitives.NewEvent(moduleIndex, EventBurned, account, amount) +} + +func newEventSuspended(moduleIndex sc.U8, account primitives.AccountId, amount primitives.Balance) primitives.Event { + return primitives.NewEvent(moduleIndex, EventSuspended, account, amount) +} + +func newEventRestored(moduleIndex sc.U8, account primitives.AccountId, amount primitives.Balance) primitives.Event { + return primitives.NewEvent(moduleIndex, EventRestored, account, amount) +} + +func newEventUpgraded(moduleIndex sc.U8, account primitives.AccountId) primitives.Event { + return primitives.NewEvent(moduleIndex, EventUpgraded, account) +} + +func newEventIssued(moduleIndex sc.U8, account primitives.AccountId) primitives.Event { + return primitives.NewEvent(moduleIndex, EventIssued, account) +} + +func newEventRescinded(moduleIndex sc.U8, account primitives.AccountId) primitives.Event { + return primitives.NewEvent(moduleIndex, EventRescinded, account) +} + +func newEventLocked(moduleIndex sc.U8, account primitives.AccountId, amount primitives.Balance) primitives.Event { + return primitives.NewEvent(moduleIndex, EventLocked, account, amount) +} + +func newEventUnlocked(moduleIndex sc.U8, account primitives.AccountId, amount primitives.Balance) primitives.Event { + return primitives.NewEvent(moduleIndex, EventUnlocked, account, amount) +} + +func newEventFrozen(moduleIndex sc.U8, account primitives.AccountId, amount primitives.Balance) primitives.Event { + return primitives.NewEvent(moduleIndex, EventFrozen, account, amount) +} + +func newEventThawed(moduleIndex sc.U8, account primitives.AccountId, amount primitives.Balance) primitives.Event { + return primitives.NewEvent(moduleIndex, EventThawed, account, amount) +} + +func newEventTotalIssuanceForced(moduleIndex sc.U8, old, new primitives.Balance) primitives.Event { + return primitives.NewEvent(moduleIndex, EventTotalIssuanceForced, old, new) +} + func DecodeEvent(moduleIndex sc.U8, buffer *bytes.Buffer) (primitives.Event, error) { decodedModuleIndex, err := sc.DecodeU8(buffer) if err != nil { @@ -126,11 +186,7 @@ func DecodeEvent(moduleIndex sc.U8, buffer *bytes.Buffer) (primitives.Event, err if err != nil { return primitives.Event{}, err } - reserved, err := sc.DecodeU128(buffer) - if err != nil { - return primitives.Event{}, err - } - return newEventBalanceSet(moduleIndex, account, free, reserved), nil + return newEventBalanceSet(moduleIndex, account, free), nil case EventReserved: account, err := primitives.DecodeAccountId(buffer) if err != nil { @@ -199,6 +255,16 @@ func DecodeEvent(moduleIndex sc.U8, buffer *bytes.Buffer) (primitives.Event, err return primitives.Event{}, err } return newEventSlashed(moduleIndex, account, amount), nil + case EventTotalIssuanceForced: + old, err := sc.DecodeU128(buffer) + if err != nil { + return primitives.Event{}, err + } + new, err := sc.DecodeU128(buffer) + if err != nil { + return primitives.Event{}, err + } + return newEventTotalIssuanceForced(moduleIndex, old, new), nil default: return primitives.Event{}, errInvalidEventType } diff --git a/frame/balances/events_test.go b/frame/balances/events_test.go index 2c8f6ce5..d3fee4bf 100644 --- a/frame/balances/events_test.go +++ b/frame/balances/events_test.go @@ -11,11 +11,11 @@ import ( ) func Test_Balances_DecodeEvent_Endowed(t *testing.T) { - targetAddressId, err := targetAddress.AsAccountId() + targetAddressId, err := targetMultiAddress.AsAccountId() assert.Nil(t, err) buffer := &bytes.Buffer{} - buffer.WriteByte(moduleId) + buffer.WriteByte(byte(moduleId)) buffer.Write(EventEndowed.Bytes()) buffer.Write(targetAddressId.Bytes()) buffer.Write(targetValue.Bytes()) @@ -24,16 +24,17 @@ func Test_Balances_DecodeEvent_Endowed(t *testing.T) { assert.Nil(t, err) assert.Equal(t, - primitives.Event{sc.NewVaryingData(sc.U8(moduleId), EventEndowed, targetAddressId, targetValue)}, + primitives.Event{VaryingData: sc.NewVaryingData(sc.U8(moduleId), EventEndowed, targetAddressId, targetValue)}, result, ) } func Test_Balances_DecodeEvent_DustLost(t *testing.T) { - targetAddressId, err := targetAddress.AsAccountId() + targetAddressId, err := targetMultiAddress.AsAccountId() assert.Nil(t, err) + buffer := &bytes.Buffer{} - buffer.WriteByte(moduleId) + buffer.WriteByte(byte(moduleId)) buffer.Write(EventDustLost.Bytes()) buffer.Write(targetAddressId.Bytes()) buffer.Write(targetValue.Bytes()) @@ -42,59 +43,52 @@ func Test_Balances_DecodeEvent_DustLost(t *testing.T) { assert.Nil(t, err) assert.Equal(t, - primitives.Event{sc.NewVaryingData(sc.U8(moduleId), EventDustLost, targetAddressId, targetValue)}, + primitives.Event{VaryingData: sc.NewVaryingData(sc.U8(moduleId), EventDustLost, targetAddressId, targetValue)}, result, ) } func Test_Balances_DecodeEvent_Transfer(t *testing.T) { - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - toAddressAccountId, err := toAddress.AsAccountId() - assert.Nil(t, err) - buffer := &bytes.Buffer{} - buffer.WriteByte(moduleId) + buffer.WriteByte(byte(moduleId)) buffer.Write(EventTransfer.Bytes()) - buffer.Write(fromAddressId.Bytes()) - buffer.Write(toAddressAccountId.Bytes()) + buffer.Write(fromAddress.Bytes()) + buffer.Write(toAddress.Bytes()) buffer.Write(targetValue.Bytes()) result, _ := DecodeEvent(moduleId, buffer) assert.Equal(t, - primitives.Event{sc.NewVaryingData(sc.U8(moduleId), EventTransfer, fromAddressId, toAddressAccountId, targetValue)}, + primitives.Event{VaryingData: sc.NewVaryingData(sc.U8(moduleId), EventTransfer, fromAddress, toAddress, targetValue)}, result, ) } func Test_Balances_DecodeEvent_BalanceSet(t *testing.T) { - targetAddressId, err := targetAddress.AsAccountId() + targetAddressId, err := targetMultiAddress.AsAccountId() assert.Nil(t, err) buffer := &bytes.Buffer{} - buffer.WriteByte(moduleId) + buffer.WriteByte(byte(moduleId)) buffer.Write(EventBalanceSet.Bytes()) buffer.Write(targetAddressId.Bytes()) buffer.Write(newFree.Bytes()) - buffer.Write(newReserved.Bytes()) result, err := DecodeEvent(moduleId, buffer) assert.Nil(t, err) assert.Equal(t, - primitives.Event{sc.NewVaryingData(sc.U8(moduleId), EventBalanceSet, targetAddressId, newFree, newReserved)}, + primitives.Event{VaryingData: sc.NewVaryingData(sc.U8(moduleId), EventBalanceSet, targetAddressId, newFree)}, result, ) } func Test_Balances_DecodeEvent_Reserved(t *testing.T) { - targetAddressId, err := targetAddress.AsAccountId() + targetAddressId, err := targetMultiAddress.AsAccountId() assert.Nil(t, err) buffer := &bytes.Buffer{} - buffer.WriteByte(moduleId) + buffer.WriteByte(byte(moduleId)) buffer.Write(EventReserved.Bytes()) buffer.Write(targetAddressId.Bytes()) buffer.Write(targetValue.Bytes()) @@ -103,17 +97,17 @@ func Test_Balances_DecodeEvent_Reserved(t *testing.T) { assert.Nil(t, err) assert.Equal(t, - primitives.Event{sc.NewVaryingData(sc.U8(moduleId), EventReserved, targetAddressId, targetValue)}, + primitives.Event{VaryingData: sc.NewVaryingData(sc.U8(moduleId), EventReserved, targetAddressId, targetValue)}, result, ) } func Test_Balances_DecodeEvent_Unreserved(t *testing.T) { - targetAddressId, err := targetAddress.AsAccountId() + targetAddressId, err := targetMultiAddress.AsAccountId() assert.Nil(t, err) buffer := &bytes.Buffer{} - buffer.WriteByte(moduleId) + buffer.WriteByte(byte(moduleId)) buffer.Write(EventUnreserved.Bytes()) buffer.Write(targetAddressId.Bytes()) buffer.Write(targetValue.Bytes()) @@ -122,21 +116,17 @@ func Test_Balances_DecodeEvent_Unreserved(t *testing.T) { assert.Nil(t, err) assert.Equal(t, - primitives.Event{sc.NewVaryingData(sc.U8(moduleId), EventUnreserved, targetAddressId, targetValue)}, + primitives.Event{VaryingData: sc.NewVaryingData(sc.U8(moduleId), EventUnreserved, targetAddressId, targetValue)}, result, ) } func Test_Balances_DecodeEvent_ReserveRepatriated(t *testing.T) { - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - toAddressAccountId, err := toAddress.AsAccountId() - assert.Nil(t, err) buffer := &bytes.Buffer{} - buffer.WriteByte(moduleId) + buffer.WriteByte(byte(moduleId)) buffer.Write(EventReserveRepatriated.Bytes()) - buffer.Write(fromAddressId.Bytes()) - buffer.Write(toAddressAccountId.Bytes()) + buffer.Write(fromAddress.Bytes()) + buffer.Write(toAddress.Bytes()) buffer.Write(targetValue.Bytes()) buffer.Write(types.BalanceStatusFree.Bytes()) @@ -144,22 +134,22 @@ func Test_Balances_DecodeEvent_ReserveRepatriated(t *testing.T) { assert.Nil(t, err) assert.Equal(t, - primitives.Event{sc.NewVaryingData( + primitives.Event{VaryingData: sc.NewVaryingData( sc.U8(moduleId), EventReserveRepatriated, - fromAddressId, - toAddressAccountId, + fromAddress, + toAddress, targetValue, types.BalanceStatusFree)}, result, ) } func Test_Balances_DecodeEvent_Deposit(t *testing.T) { - targetAddressId, err := targetAddress.AsAccountId() + targetAddressId, err := targetMultiAddress.AsAccountId() assert.Nil(t, err) buffer := &bytes.Buffer{} - buffer.WriteByte(moduleId) + buffer.WriteByte(byte(moduleId)) buffer.Write(EventDeposit.Bytes()) buffer.Write(targetAddressId.Bytes()) buffer.Write(targetValue.Bytes()) @@ -168,17 +158,17 @@ func Test_Balances_DecodeEvent_Deposit(t *testing.T) { assert.Nil(t, err) assert.Equal(t, - primitives.Event{sc.NewVaryingData(sc.U8(moduleId), EventDeposit, targetAddressId, targetValue)}, + primitives.Event{VaryingData: sc.NewVaryingData(sc.U8(moduleId), EventDeposit, targetAddressId, targetValue)}, result, ) } func Test_Balances_DecodeEvent_Withdraw(t *testing.T) { - targetAddressId, err := targetAddress.AsAccountId() + targetAddressId, err := targetMultiAddress.AsAccountId() assert.Nil(t, err) buffer := &bytes.Buffer{} - buffer.WriteByte(moduleId) + buffer.WriteByte(byte(moduleId)) buffer.Write(EventWithdraw.Bytes()) buffer.Write(targetAddressId.Bytes()) buffer.Write(targetValue.Bytes()) @@ -187,17 +177,17 @@ func Test_Balances_DecodeEvent_Withdraw(t *testing.T) { assert.Nil(t, err) assert.Equal(t, - primitives.Event{sc.NewVaryingData(sc.U8(moduleId), EventWithdraw, targetAddressId, targetValue)}, + primitives.Event{VaryingData: sc.NewVaryingData(sc.U8(moduleId), EventWithdraw, targetAddressId, targetValue)}, result, ) } func Test_Balances_DecodeEvent_Slashed(t *testing.T) { - targetAddressId, err := targetAddress.AsAccountId() + targetAddressId, err := targetMultiAddress.AsAccountId() assert.Nil(t, err) buffer := &bytes.Buffer{} - buffer.WriteByte(moduleId) + buffer.WriteByte(byte(moduleId)) buffer.Write(EventSlashed.Bytes()) buffer.Write(targetAddressId.Bytes()) buffer.Write(targetValue.Bytes()) @@ -206,24 +196,26 @@ func Test_Balances_DecodeEvent_Slashed(t *testing.T) { assert.Nil(t, err) assert.Equal(t, - primitives.Event{sc.NewVaryingData(sc.U8(moduleId), EventSlashed, targetAddressId, targetValue)}, + primitives.Event{VaryingData: sc.NewVaryingData(sc.U8(moduleId), EventSlashed, targetAddressId, targetValue)}, result, ) } func Test_Balances_DecodeEvent_InvalidModule(t *testing.T) { buffer := &bytes.Buffer{} - buffer.WriteByte(0) + buffer.WriteByte(byte(moduleId + 1)) _, err := DecodeEvent(moduleId, buffer) + assert.Equal(t, errInvalidEventModule, err) } func Test_Balances_DecodeEvent_InvalidType(t *testing.T) { buffer := &bytes.Buffer{} - buffer.WriteByte(moduleId) + buffer.WriteByte(byte(moduleId)) buffer.WriteByte(255) _, err := DecodeEvent(moduleId, buffer) + assert.Equal(t, errInvalidEventType, err) } diff --git a/frame/balances/genesis_builder.go b/frame/balances/genesis_builder.go index 01a5abf8..c00cc81c 100644 --- a/frame/balances/genesis_builder.go +++ b/frame/balances/genesis_builder.go @@ -21,6 +21,7 @@ type genesisConfigAccountBalance struct { AccountId types.AccountId Balance types.Balance } + type GenesisConfig struct { Balances []genesisConfigAccountBalance } @@ -77,14 +78,15 @@ func (gc *GenesisConfig) UnmarshalJSON(data []byte) error { return nil } -func (m Module) CreateDefaultConfig() ([]byte, error) { + +func (m module) CreateDefaultConfig() ([]byte, error) { gc := &genesisConfigJsonStruct{} gc.BalancesGenesisConfig.Balances = [][2]interface{}{} return json.Marshal(gc) } -func (m Module) BuildConfig(config []byte) error { +func (m module) BuildConfig(config []byte) error { gc := GenesisConfig{} if err := json.Unmarshal(config, &gc); err != nil { return err @@ -102,13 +104,17 @@ func (m Module) BuildConfig(config []byte) error { totalIssuance = totalIssuance.Add(b.Balance) - _, err := m.Config.StoredMap.TryMutateExists( - b.AccountId, - func(maybeAccount *types.AccountData) (sc.Encodable, error) { - oldFree, oldReserved := updateAccount(maybeAccount, b.Balance, sc.NewU128(0)) - return sc.NewVaryingData(oldFree, oldReserved), nil - }, - ) + _, err := m.Config.StoredMap.IncProviders(b.AccountId) + if err != nil { + return err + } + + _, err = m.Config.StoredMap.Insert(b.AccountId, types.AccountData{ + Free: b.Balance, + Reserved: sc.NewU128(0), + Frozen: sc.NewU128(0), + Flags: types.DefaultExtraFlags, + }) if err != nil { return err } diff --git a/frame/balances/genesis_builder_test.go b/frame/balances/genesis_builder_test.go index fa3e6a9e..c30b8578 100644 --- a/frame/balances/genesis_builder_test.go +++ b/frame/balances/genesis_builder_test.go @@ -5,19 +5,30 @@ import ( "testing" sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/mocks" "github.com/LimeChain/gosemble/primitives/types" + primitives "github.com/LimeChain/gosemble/primitives/types" "github.com/centrifuge/go-substrate-rpc-client/v4/signature" "github.com/stretchr/testify/assert" ) var ( validGcJson = "{\"balances\":{\"balances\":[[\"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY\",1]]}}" - accId, _ = types.NewAccountId(sc.BytesToSequenceU8(signature.TestKeyringPairAlice.PublicKey)...) + accountId, _ = types.NewAccountId(sc.BytesToSequenceU8(signature.TestKeyringPairAlice.PublicKey)...) balanceOne = sc.NewU128(uint64(1)) balanceOverMaxUint64, _ = sc.NewU128FromString("184467440737095516150") ) +func Test_GenesisConfig_CreateDefaultConfig(t *testing.T) { + target := setupModule() + + expectedGc := []byte("{\"balances\":{\"balances\":[]}}") + + gc, err := target.CreateDefaultConfig() + + assert.NoError(t, err) + assert.Equal(t, expectedGc, gc) +} + func Test_GenesisConfig_BuildConfig(t *testing.T) { for _, tt := range []struct { name string @@ -68,38 +79,29 @@ func Test_GenesisConfig_BuildConfig(t *testing.T) { gcJson: "{\"balances\":{\"balances\":[[\"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY\",0]]}}", expectedErr: errBalanceBelowExistentialDeposit, }, - { - name: "TryMutateExists error", - gcJson: validGcJson, - tryMutateExistsErr: errors.New("err"), - expectedErr: errors.New("err"), - }, } { t.Run(tt.name, func(t *testing.T) { target := setupModule() - mockTotalIssuance := new(mocks.StorageValue[sc.U128]) - target.storage.TotalIssuance = mockTotalIssuance - mockStoredMap.On("TryMutateExists", accId, mockTypeMutateAccountData).Return(tt.balance, tt.tryMutateExistsErr) + data := types.AccountData{ + Free: tt.balance, + Reserved: sc.NewU128(0), + Frozen: sc.NewU128(0), + Flags: types.DefaultExtraFlags, + } + + mockStoredMap.On("IncProviders", accountId).Return(primitives.IncRefStatus(0), nil) + mockStoredMap.On("Insert", accountId, data).Return(sc.Empty{}, nil) mockTotalIssuance.On("Put", tt.balance).Return() err := target.BuildConfig([]byte(tt.gcJson)) - assert.Equal(t, tt.expectedErr, err) + assert.Equal(t, tt.expectedErr, err) if tt.shouldAssertCalled { + mockStoredMap.AssertCalled(t, "IncProviders", accountId) + mockStoredMap.AssertCalled(t, "Insert", accountId, data) mockTotalIssuance.AssertCalled(t, "Put", tt.balance) - mockStoredMap.AssertCalled(t, "TryMutateExists", accId, mockTypeMutateAccountData) } }) } } - -func Test_GenesisConfig_CreateDefaultConfig(t *testing.T) { - target := setupModule() - - expectedGc := []byte("{\"balances\":{\"balances\":[]}}") - - gc, err := target.CreateDefaultConfig() - assert.NoError(t, err) - assert.Equal(t, expectedGc, gc) -} diff --git a/frame/balances/metadata.go b/frame/balances/metadata.go new file mode 100644 index 00000000..e7f05676 --- /dev/null +++ b/frame/balances/metadata.go @@ -0,0 +1,451 @@ +package balances + +import ( + "reflect" + + sc "github.com/LimeChain/goscale" + "github.com/LimeChain/gosemble/constants/metadata" + "github.com/LimeChain/gosemble/frame/balances/types" + primitives "github.com/LimeChain/gosemble/primitives/types" +) + +func (m module) Metadata() primitives.MetadataModule { + mdConstants := metadataConstants{ + ExistentialDeposit: primitives.ExistentialDeposit{U128: m.constants.ExistentialDeposit}, + MaxLocks: primitives.MaxLocks{U32: m.constants.MaxLocks}, + MaxReserves: primitives.MaxReserves{U32: m.constants.MaxReserves}, + } + + moduleMdConstants := m.mdGenerator.BuildModuleConstants(reflect.ValueOf(mdConstants)) + + dataV14 := primitives.MetadataModuleV14{ + Name: m.name(), + Storage: m.metadataStorage(), + Call: sc.NewOption[sc.Compact](sc.ToCompact(metadata.BalancesCalls)), + CallDef: sc.NewOption[primitives.MetadataDefinitionVariant]( + primitives.NewMetadataDefinitionVariantStr( + m.name(), + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithName(metadata.BalancesCalls, "self::sp_api_hidden_includes_construct_runtime::hidden_include::dispatch\n::CallableCallFor"), + }, + m.Index, + "Call.Balances"), + ), + Event: sc.NewOption[sc.Compact](sc.ToCompact(metadata.TypesBalancesEvent)), + EventDef: sc.NewOption[primitives.MetadataDefinitionVariant]( + primitives.NewMetadataDefinitionVariantStr( + m.name(), + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithName(metadata.TypesBalancesEvent, "pallet_balances::Event"), + }, + m.Index, + "Events.Balances"), + ), + Constants: moduleMdConstants, + Error: sc.NewOption[sc.Compact](sc.ToCompact(metadata.TypesBalancesErrors)), + ErrorDef: sc.NewOption[primitives.MetadataDefinitionVariant]( + primitives.NewMetadataDefinitionVariantStr( + m.name(), + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionField(metadata.TypesBalancesErrors), + }, + m.Index, + "Errors.Balances"), + ), + Index: m.Index, + } + + m.mdGenerator.AppendMetadataTypes(m.metadataTypes()) + + return primitives.MetadataModule{ + Version: primitives.ModuleVersion14, + ModuleV14: dataV14, + } +} + +func (m module) metadataStorage() sc.Option[primitives.MetadataModuleStorage] { + return sc.NewOption[primitives.MetadataModuleStorage](primitives.MetadataModuleStorage{ + Prefix: m.name(), + Items: sc.Sequence[primitives.MetadataModuleStorageEntry]{ + primitives.NewMetadataModuleStorageEntry( + "TotalIssuance", + primitives.MetadataModuleStorageEntryModifierDefault, + primitives.NewMetadataModuleStorageEntryDefinitionPlain(sc.ToCompact(metadata.PrimitiveTypesU128)), + "The total units issued in the system."), + primitives.NewMetadataModuleStorageEntry( + "InactiveIssuance", + primitives.MetadataModuleStorageEntryModifierDefault, + primitives.NewMetadataModuleStorageEntryDefinitionPlain(sc.ToCompact(metadata.PrimitiveTypesU128)), + "The total units of outstanding deactivated balance in the system."), + }, + }) +} + +func (m module) metadataTypes() sc.Sequence[primitives.MetadataType] { + return sc.Sequence[primitives.MetadataType]{ + primitives.NewMetadataTypeWithPath( + metadata.TypesBalancesEvent, + "pallet_balances pallet Event", + sc.Sequence[sc.Str]{"pallet_balances", "pallet", "Event"}, + primitives.NewMetadataTypeDefinitionVariant( + sc.Sequence[primitives.MetadataDefinitionVariant]{ + primitives.NewMetadataDefinitionVariant( + "Endowed", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "account", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "free_balance", "T::Balance"), + }, + EventEndowed, + "Event.Endowed"), + primitives.NewMetadataDefinitionVariant( + "DustLost", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "account", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventDustLost, + "Events.DustLost"), + primitives.NewMetadataDefinitionVariant( + "Transfer", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "from", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "to", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventTransfer, + "Events.Transfer"), + primitives.NewMetadataDefinitionVariant( + "BalanceSet", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "free", "T::Balance"), + }, + EventBalanceSet, + "Events.BalanceSet"), + primitives.NewMetadataDefinitionVariant( + "Reserved", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventReserved, + "Events.Reserved"), + primitives.NewMetadataDefinitionVariant( + "Unreserved", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventUnreserved, + "Events.Unreserved"), + primitives.NewMetadataDefinitionVariant( + "ReserveRepatriated", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "from", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "to", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesBalanceStatus, "destination_status", "Status"), + }, + EventReserveRepatriated, + "Events.ReserveRepatriated"), + primitives.NewMetadataDefinitionVariant( + "Deposit", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventDeposit, + "Event.Deposit"), + primitives.NewMetadataDefinitionVariant( + "Withdraw", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventWithdraw, + "Event.Withdraw"), + primitives.NewMetadataDefinitionVariant( + "Slashed", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventSlashed, + "Event.Slashed"), + primitives.NewMetadataDefinitionVariant( + "Minted", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventMinted, + "Event.Minted"), + primitives.NewMetadataDefinitionVariant( + "Burned", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventBurned, + "Event.Burned"), + primitives.NewMetadataDefinitionVariant( + "Suspended", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventBurned, + "Event.Suspended"), + primitives.NewMetadataDefinitionVariant( + "Restored", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventRestored, + "Event.Restored"), + primitives.NewMetadataDefinitionVariant( + "Upgraded", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + }, + EventUpgraded, + "Event.Upgraded"), + primitives.NewMetadataDefinitionVariant( + "Issued", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + }, + EventIssued, + "Event.Issued"), + primitives.NewMetadataDefinitionVariant( + "Rescinded", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + }, + EventRescinded, + "Event.Rescinded"), + primitives.NewMetadataDefinitionVariant( + "Locked", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventLocked, + "Event.Locked"), + primitives.NewMetadataDefinitionVariant( + "Unlocked", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventUnlocked, + "Event.Unlocked"), + primitives.NewMetadataDefinitionVariant( + "Frozen", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventFrozen, + "Event.Frozen"), + primitives.NewMetadataDefinitionVariant( + "Thawed", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventThawed, + "Event.Thawed"), + primitives.NewMetadataDefinitionVariant( + "TotalIssuanceForced", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "old", "T::Balance"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "new", "T::Balance"), + }, + EventThawed, + "Event.TotalIssuanceForced"), + }, + ), + ), + primitives.NewMetadataTypeWithPath(metadata.TypesBalanceStatus, + "BalanceStatus", + sc.Sequence[sc.Str]{"frame_support", "traits", "tokens", "misc", "BalanceStatus"}, + primitives.NewMetadataTypeDefinitionVariant( + sc.Sequence[primitives.MetadataDefinitionVariant]{ + primitives.NewMetadataDefinitionVariant( + "Free", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + types.BalanceStatusFree, + "BalanceStatus.Free"), + primitives.NewMetadataDefinitionVariant( + "Reserved", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + types.BalanceStatusReserved, + "BalanceStatus.Reserved"), + }, + ), + ), + + primitives.NewMetadataTypeWithPath(metadata.TypesBalancesAdjustDirection, + "AdjustDirection", + sc.Sequence[sc.Str]{"frame_support", "traits", "tokens", "misc", "AdjustDirection"}, primitives.NewMetadataTypeDefinitionVariant( + sc.Sequence[primitives.MetadataDefinitionVariant]{ + primitives.NewMetadataDefinitionVariant( + "Increase", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + types.AdjustDirectionIncrease, + "AdjustDirection.Increase"), + primitives.NewMetadataDefinitionVariant( + "Decrease", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + types.AdjustDirectionDecrease, + "AdjustDirection.Decrease"), + }, + ), + ), + + primitives.NewMetadataTypeWithParams(metadata.TypesBalancesErrors, + "pallet_balances pallet Error", + sc.Sequence[sc.Str]{"pallet_balances", "pallet", "Error"}, + primitives.NewMetadataTypeDefinitionVariant( + sc.Sequence[primitives.MetadataDefinitionVariant]{ + primitives.NewMetadataDefinitionVariant( + "VestingBalance", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorVestingBalance, + "Vesting balance too high to send value"), + primitives.NewMetadataDefinitionVariant( + "LiquidityRestrictions", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorLiquidityRestrictions, + "Account liquidity restrictions prevent withdrawal"), + primitives.NewMetadataDefinitionVariant( + "InsufficientBalance", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorInsufficientBalance, + "Balance too low to send value."), + primitives.NewMetadataDefinitionVariant( + "ExistentialDeposit", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorExistentialDeposit, + "Value too low to create account due to existential deposit"), + primitives.NewMetadataDefinitionVariant( + "Expendability", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorExpendability, + "Transfer/payment would kill account"), + primitives.NewMetadataDefinitionVariant( + "ExistingVestingSchedule", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorExistingVestingSchedule, + "A vesting schedule already exists for this account"), + primitives.NewMetadataDefinitionVariant( + "DeadAccount", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorDeadAccount, + "Beneficiary account must pre-exist"), + primitives.NewMetadataDefinitionVariant( + "TooManyReserves", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorTooManyReserves, + "Number of named reserves exceed MaxReserves"), + primitives.NewMetadataDefinitionVariant( + "TooManyHolds", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorTooManyHolds, + "Number of holds exceed `VariantCountOf`."), + primitives.NewMetadataDefinitionVariant( + "TooManyFreezes", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorTooManyFreezes, + "Number of freezes exceed `MaxFreezes`."), + primitives.NewMetadataDefinitionVariant( + "IssuanceDeactivated", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorIssuanceDeactivated, + "The issuance cannot be modified since it is already deactivated."), + primitives.NewMetadataDefinitionVariant( + "DeltaZero", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorDeltaZero, + "The delta cannot be zero."), + }), + sc.Sequence[primitives.MetadataTypeParameter]{ + primitives.NewMetadataEmptyTypeParameter("T"), + primitives.NewMetadataEmptyTypeParameter("I"), + }), + + primitives.NewMetadataTypeWithParam(metadata.BalancesCalls, + "Balance calls", + sc.Sequence[sc.Str]{"pallet_balances", "pallet", "Call"}, + primitives.NewMetadataTypeDefinitionVariant( + sc.Sequence[primitives.MetadataDefinitionVariant]{ + primitives.NewMetadataDefinitionVariant( + "transfer_allow_death", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesMultiAddress, "dest", "MultiAddress"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesCompactU128, "value", "T::Balance"), + }, + functionTransferAllowDeath, + "Transfer some liquid free balance to another account."), + primitives.NewMetadataDefinitionVariant( + "force_transfer", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesMultiAddress, "source", "MultiAddress"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesMultiAddress, "dest", "MultiAddress"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesCompactU128, "value", "T::Balance"), + }, + functionForceTransfer, + "Exactly as `transfer_allow_death`, except the origin must be root and the source account may be specified."), + primitives.NewMetadataDefinitionVariant( + "transfer_keep_alive", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesMultiAddress, "dest", "MultiAddress"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesCompactU128, "value", "T::Balance"), + }, + functionTransferKeepAlive, + "Same as the [`transfer_allow_death`] call, but with a check that the transfer will not kill the origin account."), + primitives.NewMetadataDefinitionVariant( + "transfer_all", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesMultiAddress, "dest", "MultiAddress"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesBool, "keep_alive", "bool"), + }, + functionTransferAll, + "Transfer the entire transferable balance from the caller account."), + primitives.NewMetadataDefinitionVariant( + "force_unreserve", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesMultiAddress, "who", "MultiAddress"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + functionForceUnreserve, + "Unreserve some balance from a user by force."), + primitives.NewMetadataDefinitionVariant( + "upgrade_accounts", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesSequenceAddress32, "who", "Vec"), + }, + functionForceUpgradeAccounts, + "Upgrade a specified account."), + primitives.NewMetadataDefinitionVariant( + "force_set_balance", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesMultiAddress, "who", "MultiAddress"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesCompactU128, "new_free", "T::Balance"), + }, + functionForceSetBalance, + "Set the regular balance of a given account."), + primitives.NewMetadataDefinitionVariant( + "force_adjust_total_issuance", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesBalancesAdjustDirection, "direction", "AdjustmentDireciton"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesCompactU128, "delta", "T::Balance"), + }, + functionForceAdjustTotalIssuance, + "Adjust the total issuance in a saturating way."), + }), + primitives.NewMetadataEmptyTypeParameter("T")), + } +} diff --git a/frame/balances/metadata_test.go b/frame/balances/metadata_test.go new file mode 100644 index 00000000..648e2287 --- /dev/null +++ b/frame/balances/metadata_test.go @@ -0,0 +1,472 @@ +package balances + +import ( + "testing" + + sc "github.com/LimeChain/goscale" + "github.com/LimeChain/gosemble/constants/metadata" + "github.com/LimeChain/gosemble/frame/balances/types" + primitives "github.com/LimeChain/gosemble/primitives/types" + "github.com/stretchr/testify/assert" +) + +func Test_Module_Metadata(t *testing.T) { + target = setupModule() + + expectedMetadataTypes := sc.Sequence[primitives.MetadataType]{ + primitives.NewMetadataTypeWithPath( + metadata.TypesBalancesEvent, + "pallet_balances pallet Event", + sc.Sequence[sc.Str]{"pallet_balances", "pallet", "Event"}, + primitives.NewMetadataTypeDefinitionVariant( + sc.Sequence[primitives.MetadataDefinitionVariant]{ + primitives.NewMetadataDefinitionVariant( + "Endowed", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "account", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "free_balance", "T::Balance"), + }, + EventEndowed, + "Event.Endowed"), + primitives.NewMetadataDefinitionVariant( + "DustLost", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "account", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventDustLost, + "Events.DustLost"), + primitives.NewMetadataDefinitionVariant( + "Transfer", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "from", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "to", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventTransfer, + "Events.Transfer"), + primitives.NewMetadataDefinitionVariant( + "BalanceSet", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "free", "T::Balance"), + }, + EventBalanceSet, + "Events.BalanceSet"), + primitives.NewMetadataDefinitionVariant( + "Reserved", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventReserved, + "Events.Reserved"), + primitives.NewMetadataDefinitionVariant( + "Unreserved", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventUnreserved, + "Events.Unreserved"), + primitives.NewMetadataDefinitionVariant( + "ReserveRepatriated", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "from", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "to", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesBalanceStatus, "destination_status", "Status"), + }, + EventReserveRepatriated, + "Events.ReserveRepatriated"), + primitives.NewMetadataDefinitionVariant( + "Deposit", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventDeposit, + "Event.Deposit"), + primitives.NewMetadataDefinitionVariant( + "Withdraw", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventWithdraw, + "Event.Withdraw"), + primitives.NewMetadataDefinitionVariant( + "Slashed", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventSlashed, + "Event.Slashed"), + primitives.NewMetadataDefinitionVariant( + "Minted", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventMinted, + "Event.Minted"), + primitives.NewMetadataDefinitionVariant( + "Burned", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventBurned, + "Event.Burned"), + primitives.NewMetadataDefinitionVariant( + "Suspended", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventBurned, + "Event.Suspended"), + primitives.NewMetadataDefinitionVariant( + "Restored", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventRestored, + "Event.Restored"), + primitives.NewMetadataDefinitionVariant( + "Upgraded", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + }, + EventUpgraded, + "Event.Upgraded"), + primitives.NewMetadataDefinitionVariant( + "Issued", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + }, + EventIssued, + "Event.Issued"), + primitives.NewMetadataDefinitionVariant( + "Rescinded", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + }, + EventRescinded, + "Event.Rescinded"), + primitives.NewMetadataDefinitionVariant( + "Locked", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventLocked, + "Event.Locked"), + primitives.NewMetadataDefinitionVariant( + "Unlocked", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventUnlocked, + "Event.Unlocked"), + primitives.NewMetadataDefinitionVariant( + "Frozen", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventFrozen, + "Event.Frozen"), + primitives.NewMetadataDefinitionVariant( + "Thawed", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + EventThawed, + "Event.Thawed"), + primitives.NewMetadataDefinitionVariant( + "TotalIssuanceForced", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "old", "T::Balance"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "new", "T::Balance"), + }, + EventThawed, + "Event.TotalIssuanceForced"), + }, + ), + ), + primitives.NewMetadataTypeWithPath(metadata.TypesBalanceStatus, + "BalanceStatus", + sc.Sequence[sc.Str]{"frame_support", "traits", "tokens", "misc", "BalanceStatus"}, + primitives.NewMetadataTypeDefinitionVariant( + sc.Sequence[primitives.MetadataDefinitionVariant]{ + primitives.NewMetadataDefinitionVariant( + "Free", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + types.BalanceStatusFree, + "BalanceStatus.Free"), + primitives.NewMetadataDefinitionVariant( + "Reserved", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + types.BalanceStatusReserved, + "BalanceStatus.Reserved"), + }, + ), + ), + + primitives.NewMetadataTypeWithPath(metadata.TypesBalancesAdjustDirection, + "AdjustDirection", + sc.Sequence[sc.Str]{"frame_support", "traits", "tokens", "misc", "AdjustDirection"}, primitives.NewMetadataTypeDefinitionVariant( + sc.Sequence[primitives.MetadataDefinitionVariant]{ + primitives.NewMetadataDefinitionVariant( + "Increase", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + types.AdjustDirectionIncrease, + "AdjustDirection.Increase"), + primitives.NewMetadataDefinitionVariant( + "Decrease", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + types.AdjustDirectionDecrease, + "AdjustDirection.Decrease"), + }, + ), + ), + + primitives.NewMetadataTypeWithParams(metadata.TypesBalancesErrors, + "pallet_balances pallet Error", + sc.Sequence[sc.Str]{"pallet_balances", "pallet", "Error"}, + primitives.NewMetadataTypeDefinitionVariant( + sc.Sequence[primitives.MetadataDefinitionVariant]{ + primitives.NewMetadataDefinitionVariant( + "VestingBalance", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorVestingBalance, + "Vesting balance too high to send value"), + primitives.NewMetadataDefinitionVariant( + "LiquidityRestrictions", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorLiquidityRestrictions, + "Account liquidity restrictions prevent withdrawal"), + primitives.NewMetadataDefinitionVariant( + "InsufficientBalance", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorInsufficientBalance, + "Balance too low to send value."), + primitives.NewMetadataDefinitionVariant( + "ExistentialDeposit", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorExistentialDeposit, + "Value too low to create account due to existential deposit"), + primitives.NewMetadataDefinitionVariant( + "Expendability", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorExpendability, + "Transfer/payment would kill account"), + primitives.NewMetadataDefinitionVariant( + "ExistingVestingSchedule", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorExistingVestingSchedule, + "A vesting schedule already exists for this account"), + primitives.NewMetadataDefinitionVariant( + "DeadAccount", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorDeadAccount, + "Beneficiary account must pre-exist"), + primitives.NewMetadataDefinitionVariant( + "TooManyReserves", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorTooManyReserves, + "Number of named reserves exceed MaxReserves"), + primitives.NewMetadataDefinitionVariant( + "TooManyHolds", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorTooManyHolds, + "Number of holds exceed `VariantCountOf`."), + primitives.NewMetadataDefinitionVariant( + "TooManyFreezes", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorTooManyFreezes, + "Number of freezes exceed `MaxFreezes`."), + primitives.NewMetadataDefinitionVariant( + "IssuanceDeactivated", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorIssuanceDeactivated, + "The issuance cannot be modified since it is already deactivated."), + primitives.NewMetadataDefinitionVariant( + "DeltaZero", + sc.Sequence[primitives.MetadataTypeDefinitionField]{}, + ErrorDeltaZero, + "The delta cannot be zero."), + }), + sc.Sequence[primitives.MetadataTypeParameter]{ + primitives.NewMetadataEmptyTypeParameter("T"), + primitives.NewMetadataEmptyTypeParameter("I"), + }), + + primitives.NewMetadataTypeWithParam(metadata.BalancesCalls, + "Balance calls", + sc.Sequence[sc.Str]{"pallet_balances", "pallet", "Call"}, + primitives.NewMetadataTypeDefinitionVariant( + sc.Sequence[primitives.MetadataDefinitionVariant]{ + primitives.NewMetadataDefinitionVariant( + "transfer_allow_death", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesMultiAddress, "dest", "MultiAddress"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesCompactU128, "value", "T::Balance"), + }, + functionTransferAllowDeath, + "Transfer some liquid free balance to another account."), + primitives.NewMetadataDefinitionVariant( + "force_transfer", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesMultiAddress, "source", "MultiAddress"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesMultiAddress, "dest", "MultiAddress"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesCompactU128, "value", "T::Balance"), + }, + functionForceTransfer, + "Exactly as `transfer_allow_death`, except the origin must be root and the source account may be specified."), + primitives.NewMetadataDefinitionVariant( + "transfer_keep_alive", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesMultiAddress, "dest", "MultiAddress"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesCompactU128, "value", "T::Balance"), + }, + functionTransferKeepAlive, + "Same as the [`transfer_allow_death`] call, but with a check that the transfer will not kill the origin account."), + primitives.NewMetadataDefinitionVariant( + "transfer_all", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesMultiAddress, "dest", "MultiAddress"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesBool, "keep_alive", "bool"), + }, + functionTransferAll, + "Transfer the entire transferable balance from the caller account."), + primitives.NewMetadataDefinitionVariant( + "force_unreserve", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesMultiAddress, "who", "MultiAddress"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), + }, + functionForceUnreserve, + "Unreserve some balance from a user by force."), + primitives.NewMetadataDefinitionVariant( + "upgrade_accounts", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesSequenceAddress32, "who", "Vec"), + }, + functionForceUpgradeAccounts, + "Upgrade a specified account."), + primitives.NewMetadataDefinitionVariant( + "force_set_balance", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesMultiAddress, "who", "MultiAddress"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesCompactU128, "new_free", "T::Balance"), + }, + functionForceSetBalance, + "Set the regular balance of a given account."), + primitives.NewMetadataDefinitionVariant( + "force_adjust_total_issuance", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesBalancesAdjustDirection, "direction", "AdjustmentDireciton"), + primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesCompactU128, "delta", "T::Balance"), + }, + functionForceAdjustTotalIssuance, + "Adjust the total issuance in a saturating way."), + }), + primitives.NewMetadataEmptyTypeParameter("T")), + } + + expectedMetadataV14 := primitives.MetadataModuleV14{ + Name: "Balances", + Storage: sc.NewOption[primitives.MetadataModuleStorage](primitives.MetadataModuleStorage{ + Prefix: "Balances", + Items: sc.Sequence[primitives.MetadataModuleStorageEntry]{ + primitives.NewMetadataModuleStorageEntry( + "TotalIssuance", + primitives.MetadataModuleStorageEntryModifierDefault, + primitives.NewMetadataModuleStorageEntryDefinitionPlain(sc.ToCompact(metadata.PrimitiveTypesU128)), + "The total units issued in the system."), + primitives.NewMetadataModuleStorageEntry( + "InactiveIssuance", + primitives.MetadataModuleStorageEntryModifierDefault, + primitives.NewMetadataModuleStorageEntryDefinitionPlain(sc.ToCompact(metadata.PrimitiveTypesU128)), + "The total units of outstanding deactivated balance in the system."), + }, + }), + Call: sc.NewOption[sc.Compact](sc.ToCompact(metadata.BalancesCalls)), + CallDef: sc.NewOption[primitives.MetadataDefinitionVariant]( + primitives.NewMetadataDefinitionVariantStr( + "Balances", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithName( + metadata.BalancesCalls, + "self::sp_api_hidden_includes_construct_runtime::hidden_include::dispatch\n::CallableCallFor", + ), + }, + moduleId, + "Call.Balances", + ), + ), + Event: sc.NewOption[sc.Compact](sc.ToCompact(metadata.TypesBalancesEvent)), + EventDef: sc.NewOption[primitives.MetadataDefinitionVariant]( + primitives.NewMetadataDefinitionVariantStr( + "Balances", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionFieldWithName( + metadata.TypesBalancesEvent, + "pallet_balances::Event", + ), + }, + moduleId, + "Events.Balances", + ), + ), + Constants: sc.Sequence[primitives.MetadataModuleConstant]{ + primitives.NewMetadataModuleConstant( + "ExistentialDeposit", + sc.ToCompact(metadata.PrimitiveTypesU128), + sc.BytesToSequenceU8(target.constants.ExistentialDeposit.Bytes()), + "The minimum amount required to keep an account open. MUST BE GREATER THAN ZERO!", + ), + primitives.NewMetadataModuleConstant( + "MaxLocks", + sc.ToCompact(metadata.PrimitiveTypesU32), + sc.BytesToSequenceU8(target.constants.MaxLocks.Bytes()), + "The maximum number of locks that should exist on an account. Not strictly enforced, but used for weight estimation.", + ), + primitives.NewMetadataModuleConstant( + "MaxReserves", + sc.ToCompact(metadata.PrimitiveTypesU32), + sc.BytesToSequenceU8(target.constants.MaxReserves.Bytes()), + "The maximum number of named reserves that can exist on an account.", + ), + }, + Error: sc.NewOption[sc.Compact](sc.ToCompact(metadata.TypesBalancesErrors)), + ErrorDef: sc.NewOption[primitives.MetadataDefinitionVariant]( + primitives.NewMetadataDefinitionVariantStr( + "Balances", + sc.Sequence[primitives.MetadataTypeDefinitionField]{ + primitives.NewMetadataTypeDefinitionField(metadata.TypesBalancesErrors), + }, + moduleId, + "Errors.Balances", + ), + ), + Index: moduleId, + } + + expectMetadataModule := primitives.MetadataModule{ + Version: primitives.ModuleVersion14, + ModuleV14: expectedMetadataV14, + } + + resultMetadataModule := target.Metadata() + resultTypes := mdGenerator.GetMetadataTypes() + + assert.Equal(t, expectedMetadataTypes, resultTypes) + assert.Equal(t, expectMetadataModule, resultMetadataModule) +} diff --git a/frame/balances/mock_transfer_test.go b/frame/balances/mock_transfer_test.go deleted file mode 100644 index 0a04c9fd..00000000 --- a/frame/balances/mock_transfer_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package balances - -import ( - sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/primitives/types" - "github.com/stretchr/testify/mock" -) - -type mockAccountMutator struct { - mock.Mock -} - -func (m *mockAccountMutator) ensureCanWithdraw(who types.AccountId, amount sc.U128, reasons types.Reasons, newBalance sc.U128) error { - args := m.Called(who, amount, reasons, newBalance) - - if args[0] != nil { - return args[0].(error) - } - - return nil -} - -func (m *mockAccountMutator) tryMutateAccountWithDust(who types.AccountId, f func(who *types.AccountData, bool bool) (sc.Encodable, error)) (sc.Encodable, error) { - args := m.Called(who, f) - - if args[1] != nil { - return args[0].(sc.Encodable), args[1].(error) - } - - return args[0].(sc.Encodable), nil -} - -func (m *mockAccountMutator) tryMutateAccount(who types.AccountId, f func(who *types.AccountData, bool bool) (sc.Encodable, error)) (sc.Encodable, error) { - args := m.Called(who, f) - - if args[1] != nil { - return args[0].(sc.Encodable), args[1].(error) - } - - return args[0].(sc.Encodable), nil -} diff --git a/frame/balances/module.go b/frame/balances/module.go index 51342665..294f45e1 100644 --- a/frame/balances/module.go +++ b/frame/balances/module.go @@ -1,31 +1,49 @@ package balances import ( + "encoding/hex" "reflect" + "github.com/LimeChain/goscale" sc "github.com/LimeChain/goscale" "github.com/LimeChain/gosemble/constants" - "github.com/LimeChain/gosemble/constants/metadata" "github.com/LimeChain/gosemble/frame/balances/types" + "github.com/LimeChain/gosemble/frame/support" "github.com/LimeChain/gosemble/hooks" "github.com/LimeChain/gosemble/primitives/log" primitives "github.com/LimeChain/gosemble/primitives/types" ) const ( - functionTransferIndex = iota - functionSetBalanceIndex - functionForceTransferIndex - functionTransferKeepAliveIndex - functionTransferAllIndex - functionForceFreeIndex + functionTransferAllowDeath sc.U8 = iota + functionForceTransfer sc.U8 = 2 + functionTransferKeepAlive sc.U8 = 3 + functionTransferAll sc.U8 = 4 + functionForceUnreserve sc.U8 = 5 + functionForceUpgradeAccounts sc.U8 = 6 + functionForceSetBalance sc.U8 = 8 + functionForceAdjustTotalIssuance sc.U8 = 9 ) const ( name = sc.Str("Balances") ) -type Module struct { +type Module interface { + primitives.Module + + DepositIntoExisting(who primitives.AccountId, value sc.U128) (primitives.Balance, error) + Withdraw(who primitives.AccountId, value sc.U128, reasons sc.U8, liveness primitives.ExistenceRequirement) (primitives.Balance, error) + MutateAccountHandlingDust(who primitives.AccountId, f func(who *primitives.AccountData, bool bool) (sc.Encodable, error)) (sc.Encodable, error) + Unreserve(who primitives.AccountId, value sc.U128) (sc.U128, error) + + DepositEvent(event primitives.Event) + DbWeight() primitives.RuntimeDbWeight + ExistentialDeposit() sc.U128 + TotalIssuance() support.StorageValue[goscale.U128] +} + +type module struct { primitives.DefaultInherentProvider hooks.DefaultDispatchModule Index sc.U8 @@ -34,85 +52,148 @@ type Module struct { storage *storage functions map[sc.U8]primitives.Call mdGenerator *primitives.MetadataTypeGenerator + logger log.RuntimeLogger } -func New(index sc.U8, config *Config, logger log.RuntimeLogger, mdGenerator *primitives.MetadataTypeGenerator) Module { +func New(index sc.U8, config *Config, mdGenerator *primitives.MetadataTypeGenerator, logger log.RuntimeLogger) Module { constants := newConstants(config.DbWeight, config.MaxLocks, config.MaxReserves, config.ExistentialDeposit) storage := newStorage(config.Storage) - module := Module{ + moduleInstance := module{ Index: index, Config: config, constants: constants, storage: storage, mdGenerator: mdGenerator, + logger: logger, } functions := make(map[sc.U8]primitives.Call) - functions[functionTransferIndex] = newCallTransfer(index, functionTransferIndex, config.StoredMap, constants, module) - functions[functionSetBalanceIndex] = newCallSetBalance(index, functionSetBalanceIndex, config.StoredMap, constants, module, storage.TotalIssuance) - functions[functionForceTransferIndex] = newCallForceTransfer(index, functionForceTransferIndex, config.StoredMap, constants, module) - functions[functionTransferKeepAliveIndex] = newCallTransferKeepAlive(index, functionTransferKeepAliveIndex, config.StoredMap, constants, module) - functions[functionTransferAllIndex] = newCallTransferAll(index, functionTransferAllIndex, config.StoredMap, constants, module, logger) - functions[functionForceFreeIndex] = newCallForceFree(index, functionForceFreeIndex, config.StoredMap, constants, module, logger) - - module.functions = functions - - return module + functions[functionTransferAllowDeath] = newCallTransferAllowDeath(index, functionTransferAllowDeath, moduleInstance) + functions[functionForceTransfer] = newCallForceTransfer(index, functionForceTransfer, moduleInstance) + functions[functionTransferKeepAlive] = newCallTransferKeepAlive(index, functionTransferKeepAlive, moduleInstance) + functions[functionTransferAll] = newCallTransferAll(index, functionTransferAll, moduleInstance) + functions[functionForceUnreserve] = newCallForceUnreserve(index, functionForceUnreserve, moduleInstance) + functions[functionForceUpgradeAccounts] = newCallUpgradeAccounts(index, functionForceUpgradeAccounts, moduleInstance) + functions[functionForceSetBalance] = newCallForceSetBalance(index, functionForceSetBalance, moduleInstance) + functions[functionForceAdjustTotalIssuance] = newCallForceAdjustTotalIssuance(index, functionForceAdjustTotalIssuance, config.StoredMap, storage) + + moduleInstance.functions = functions + + return moduleInstance } -func (m Module) GetIndex() sc.U8 { +func (m module) GetIndex() sc.U8 { return m.Index } -func (m Module) name() sc.Str { +func (m module) name() sc.Str { return name } -func (m Module) Functions() map[sc.U8]primitives.Call { +func (m module) Functions() map[sc.U8]primitives.Call { return m.functions } -func (m Module) PreDispatch(_ primitives.Call) (sc.Empty, error) { +func (m module) PreDispatch(_ primitives.Call) (sc.Empty, error) { return sc.Empty{}, nil } -func (m Module) ValidateUnsigned(_ primitives.TransactionSource, _ primitives.Call) (primitives.ValidTransaction, error) { +func (m module) ValidateUnsigned(_ primitives.TransactionSource, _ primitives.Call) (primitives.ValidTransaction, error) { return primitives.ValidTransaction{}, primitives.NewTransactionValidityError(primitives.NewUnknownTransactionNoUnsignedValidator()) } // DepositIntoExisting deposits `value` into the free balance of an existing target account `who`. // If `value` is 0, it does nothing. -func (m Module) DepositIntoExisting(who primitives.AccountId, value sc.U128) (primitives.Balance, error) { +func (m module) DepositIntoExisting(who primitives.AccountId, value sc.U128) (primitives.Balance, error) { if value.Eq(constants.Zero) { return sc.NewU128(0), nil } - result, err := m.tryMutateAccount( + result, err := m.tryMutateAccountHandlingDust( who, - func(account *primitives.AccountData, isNew bool) (sc.Encodable, error) { - return m.deposit(who, account, isNew, value) + func(accountData *primitives.AccountData, isNew bool) (sc.Encodable, error) { + return m.deposit(who, accountData, isNew, value) }, ) + if err != nil { + return primitives.Balance{}, err + } - return result.(primitives.Balance), err + return result.(primitives.Balance), nil } -// Withdraw withdraws `value` free balance from `who`, respecting existence requirements. -// Does not do anything if value is 0. -func (m Module) Withdraw(who primitives.AccountId, value sc.U128, reasons sc.U8, liveness primitives.ExistenceRequirement) (primitives.Balance, error) { +func (m module) Withdraw(who primitives.AccountId, value sc.U128, reasons sc.U8, liveness primitives.ExistenceRequirement) (primitives.Balance, error) { if value.Eq(constants.Zero) { return sc.NewU128(0), nil } - result, err := m.tryMutateAccount(who, func(account *primitives.AccountData, _ bool) (sc.Encodable, error) { - return m.withdraw(who, value, account, reasons, liveness) - }) + result, err := m.tryMutateAccountHandlingDust( + who, + func(accountData *primitives.AccountData, isNew bool) (sc.Encodable, error) { + return m.withdraw(who, value, accountData, reasons, liveness) + }, + ) + + if err != nil { + return primitives.Balance{}, err + } + + return result.(primitives.Balance), nil +} + +func (m module) deposit(who primitives.AccountId, account *primitives.AccountData, isNew bool, value sc.U128) (sc.Encodable, error) { + if isNew { + return nil, primitives.NewDispatchErrorModule(primitives.CustomModuleError{ + Index: m.Index, + Err: sc.U32(ErrorDeadAccount), + Message: sc.NewOption[sc.Str](nil), + }) + } + + free, err := sc.CheckedAddU128(account.Free, value) + if err != nil { + return nil, primitives.NewDispatchErrorArithmetic(primitives.NewArithmeticErrorOverflow()) + } + account.Free = free + + m.Config.StoredMap.DepositEvent(newEventDeposit(m.Index, who, value)) + + return value, nil +} - return result.(primitives.Balance), err +func (m module) withdraw(who primitives.AccountId, value sc.U128, account *primitives.AccountData, reasons sc.U8, liveness primitives.ExistenceRequirement) (sc.Encodable, error) { + newFreeAccount, err := sc.CheckedSubU128(account.Free, value) + if err != nil { + return nil, primitives.NewDispatchErrorModule(primitives.CustomModuleError{ + Index: m.Index, + Err: sc.U32(ErrorInsufficientBalance), + Message: sc.NewOption[sc.Str](nil), + }) + } + + existentialDeposit := m.constants.ExistentialDeposit + + wouldBeDead := newFreeAccount.Lt(existentialDeposit) + wouldKill := wouldBeDead && account.Free.Gte(existentialDeposit) + if !(liveness == primitives.ExistenceRequirementAllowDeath || !wouldKill) { + return nil, primitives.NewDispatchErrorModule(primitives.CustomModuleError{ + Index: m.Index, + Err: sc.U32(ErrorExpendability), + Message: sc.NewOption[sc.Str](nil), + }) + } + + if err := m.ensureCanWithdraw(who, value, primitives.Reasons(reasons), newFreeAccount); err != nil { + return nil, err + } + + account.Free = newFreeAccount + m.Config.StoredMap.DepositEvent(newEventWithdraw(m.Index, who, value)) + return value, nil } // ensureCanWithdraw checks that an account can withdraw from their balance given any existing withdraw restrictions. -func (m Module) ensureCanWithdraw(who primitives.AccountId, amount sc.U128, reasons primitives.Reasons, newBalance sc.U128) error { +func (m module) ensureCanWithdraw(who primitives.AccountId, amount sc.U128, _reasons primitives.Reasons, newBalance sc.U128) error { if amount.Eq(constants.Zero) { return nil } @@ -122,7 +203,7 @@ func (m Module) ensureCanWithdraw(who primitives.AccountId, amount sc.U128, reas return primitives.NewDispatchErrorOther(sc.Str(err.Error())) } - minBalance := accountInfo.Frozen(reasons) + minBalance := accountInfo.Data.Frozen if minBalance.Gt(newBalance) { return primitives.NewDispatchErrorModule(primitives.CustomModuleError{ Index: m.Index, @@ -134,29 +215,262 @@ func (m Module) ensureCanWithdraw(who primitives.AccountId, amount sc.U128, reas return nil } -// tryMutateAccount mutates an account based on argument `f`. Does not change total issuance. -// Does not do anything if `f` returns an error. -func (m Module) tryMutateAccount(who primitives.AccountId, f func(who *primitives.AccountData, bool bool) (sc.Encodable, error)) (sc.Encodable, error) { - result, err := m.tryMutateAccountWithDust(who, f) +func (m module) ensureUpgraded(who primitives.AccountId) (bool, error) { + acc, err := m.Config.StoredMap.Get(who) + if err != nil { + return false, err + } + + if acc.Data.Flags.IsNewLogic() { + return false, nil + } + acc.Data.Flags = acc.Data.Flags.SetNewLogic() + if !acc.Data.Reserved.Eq(constants.Zero) && acc.Data.Frozen.Eq(constants.Zero) { + if acc.Providers == 0 { + m.logger.Warnf("account with a non-zero reserve balance has no provider refs, acc_id [%s]", hex.EncodeToString(who.Bytes())) + acc.Data.Free = sc.Max128(acc.Data.Free, m.constants.ExistentialDeposit) + _, err := m.Config.StoredMap.IncProviders(who) + if err != nil { + return false, err + } + } + + err := m.Config.StoredMap.IncConsumersWithoutLimit(who) + if err != nil { + return false, err + } + } + _, err = m.Config.StoredMap.TryMutateExists(who, func(target *primitives.AccountData) (sc.Encodable, error) { + updateAccount(target, acc.Data) + return nil, nil + }) + if err != nil { + return false, err + } + + m.Config.StoredMap.DepositEvent(newEventUpgraded(m.Index, who)) + + return true, nil +} + +func (m module) transfer(from primitives.AccountId, to primitives.AccountId, value sc.U128, preservation types.Preservation) error { + withdrawalConsequence, err := m.canWithdraw(from, value) + if err != nil { + return err + } + _, err = withdrawalConsequence.IntoResult(preservation != types.PreservationExpendable) + if err != nil { + return err + } + depositConsequence, err := m.canDeposit(to, value, false) + if err != nil { + return err + } + err = depositConsequence.IntoResult() + if err != nil { + return err + } + + if reflect.DeepEqual(from, to) { + return nil + } + + _, err = m.decreaseBalance(from, value, types.PrecisionBestEffort, preservation, types.FortitudePolite) + if err != nil { + return err + } + + // This should never fail as we checked `can_deposit` earlier. But we do a best-effort + // anyway. + _, err = m.increaseBalance(to, value, types.PrecisionBestEffort) + if err != nil { + return err + } + + m.Config.StoredMap.DepositEvent(newEventTransfer(m.Index, from, to, value)) + + return nil +} + +func (m module) increaseBalance(who primitives.AccountId, amount sc.U128, precision types.Precision) (sc.U128, error) { + acc, err := m.Config.StoredMap.Get(who) + if err != nil { + return sc.U128{}, primitives.NewDispatchErrorOther(sc.Str(err.Error())) + } + oldBalance := acc.Data.Free + + var newBalance sc.U128 + if precision == types.PrecisionBestEffort { + newBalance = sc.SaturatingAddU128(oldBalance, amount) + } else { + newBalance, err = sc.CheckedAddU128(oldBalance, amount) + if err != nil { + return sc.U128{}, primitives.NewDispatchErrorArithmetic(primitives.NewArithmeticErrorOverflow()) + } + } + + if newBalance.Lt(m.constants.ExistentialDeposit) { + if precision == types.PrecisionBestEffort { + return constants.Zero, nil + } else { + return sc.U128{}, primitives.NewDispatchErrorToken(primitives.NewTokenErrorBelowMinimum()) + } + } + + if newBalance.Eq(oldBalance) { + return constants.Zero, nil + } + + dust, err := m.writeBalance(who, newBalance) + if err != nil { + return sc.U128{}, err + } + + if dust.HasValue { + err := m.handleDust(dust.Value) + if err != nil { + return sc.U128{}, err + } + } + + return sc.SaturatingSubU128(newBalance, oldBalance), nil +} + +func (m module) decreaseBalance(who primitives.AccountId, value sc.U128, precision types.Precision, preservation types.Preservation, fortitude types.Fortitude) (sc.U128, error) { + acc, err := m.Config.StoredMap.Get(who) + if err != nil { + return sc.U128{}, primitives.NewDispatchErrorOther(sc.Str(err.Error())) + } + oldBalance := acc.Data.Free + + reducible, err := m.reducibleBalance(who, preservation, fortitude) + if err != nil { + return sc.U128{}, err + } + if precision == types.PrecisionBestEffort { + value = sc.Min128(value, reducible) + } else if precision == types.PrecisionExact { + if value.Gt(reducible) { + return sc.U128{}, primitives.NewDispatchErrorToken(primitives.NewTokenErrorFundsUnavailable()) + } + } + + newBalance, err := sc.CheckedSubU128(oldBalance, value) + if err != nil { + return sc.U128{}, primitives.NewDispatchErrorToken(primitives.NewTokenErrorFundsUnavailable()) + } + + maybeDust, err := m.writeBalance(who, newBalance) + if err != nil { + return sc.U128{}, err + } + if maybeDust.HasValue { + err := m.handleDust(maybeDust.Value) + if err != nil { + return sc.U128{}, err + } + } + + return sc.SaturatingSubU128(oldBalance, newBalance), nil + +} + +// handleRawDust creates some dust and handle it with [`Unbalanced::handle_dust`]. This is an unbalanced +// +// operation, so it must only be used when an account is modified in a raw fashion, outside +// +// the entire fungibles API. The `amount` is capped at [`Inspect::minimum_balance()`] - 1`. +// +// This should not be reimplemented. +func (m module) handleRawDust(dust sc.U128) error { + return m.handleDust(sc.Min128(dust, sc.SaturatingSubU128(m.Config.ExistentialDeposit, constants.One))) +} + +func (m module) handleDust(dust sc.U128) error { + // TODO: handle dust + return nil +} + +func (m module) writeBalance(who primitives.AccountId, amount sc.U128) (sc.Option[sc.U128], error) { + maxReduction, err := m.reducibleBalance(who, types.PreservationExpendable, types.FortitudeForce) + if err != nil { + return sc.Option[sc.U128]{}, err + } + + result, err := m.tryMutateAccount(who, func(accountData *primitives.AccountData, bool bool) (sc.Encodable, error) { + reduction := sc.SaturatingSubU128(accountData.Free, amount) + if reduction.Gt(maxReduction) { + return nil, primitives.NewDispatchErrorModule( + primitives.CustomModuleError{ + Index: m.Index, + Err: sc.U32(ErrorInsufficientBalance), + Message: sc.NewOption[sc.Str](nil), + }) + } + accountData.Free = amount + return nil, nil + }) + if err != nil { + return sc.Option[sc.U128]{}, err + } + + resultValue := result.(sc.VaryingData) + return resultValue[1].(sc.Option[sc.U128]), nil +} + +func (m module) tryMutateAccountHandlingDust(who primitives.AccountId, f func(who *primitives.AccountData, bool bool) (sc.Encodable, error)) (sc.Encodable, error) { + result, err := m.tryMutateAccount(who, f) if err != nil { return result, err } - r := result.(sc.VaryingData) + resultValue := result.(sc.VaryingData) + maybeDust, ok := resultValue[1].(sc.Option[sc.U128]) + if !ok { + return nil, primitives.NewDispatchErrorOther("could not cast dust in mutateAccountHandlingDust") + } - dustCleaner := r[1].(dustCleaner) - dustCleaner.Drop() + if maybeDust.HasValue { + err := m.handleRawDust(maybeDust.Value) + if err != nil { + return nil, err + } + } - return r[0].(sc.Encodable), nil + return resultValue[0], nil } -func (m Module) tryMutateAccountWithDust(who primitives.AccountId, f func(who *primitives.AccountData, _ bool) (sc.Encodable, error)) (sc.Encodable, error) { - result, err := m.Config.StoredMap.TryMutateExists( - who, - func(maybeAccount *primitives.AccountData) (sc.Encodable, error) { - return m.mutateAccount(maybeAccount, f) - }, - ) +func (m module) MutateAccountHandlingDust(who primitives.AccountId, f func(who *primitives.AccountData, bool bool) (sc.Encodable, error)) (sc.Encodable, error) { + result, err := m.tryMutateAccount(who, f) + if err != nil { + return result, err + } + + resultValue := result.(sc.VaryingData) + maybeDust, ok := resultValue[1].(sc.Option[sc.U128]) + if !ok { + return nil, primitives.NewDispatchErrorOther("could not cast dust in mutateAccountHandlingDust") + } + + if maybeDust.HasValue { + err := m.handleRawDust(maybeDust.Value) + if err != nil { + return nil, err + } + } + + return resultValue[0], nil +} + +func (m module) tryMutateAccount(who primitives.AccountId, f func(who *primitives.AccountData, bool bool) (sc.Encodable, error)) (sc.Encodable, error) { + _, err := m.ensureUpgraded(who) + if err != nil { + return nil, err + } + + result, err := m.Config.StoredMap.TryMutateExists(who, func(maybeAccount *primitives.AccountData) (sc.Encodable, error) { + return m.mutateAccount(who, maybeAccount, f) + }) if err != nil { return result, err } @@ -167,338 +481,294 @@ func (m Module) tryMutateAccountWithDust(who primitives.AccountId, f func(who *p m.Config.StoredMap.DepositEvent(newEventEndowed(m.Index, who, maybeEndowed.Value)) } - maybeDust := resultValue[1].(sc.Option[negativeImbalance]) - dustCleaner := newDustCleaner(m.Index, who, maybeDust, m.Config.StoredMap) + maybeDust := resultValue[1].(sc.Option[primitives.Balance]) + if maybeDust.HasValue { + m.Config.StoredMap.DepositEvent(newEventDustLost(m.Index, who, maybeDust.Value)) + } - r := sc.NewVaryingData(resultValue[2], dustCleaner) - return r, nil + return sc.NewVaryingData(resultValue[2], maybeDust), nil } -func (m Module) mutateAccount(maybeAccount *primitives.AccountData, f func(who *primitives.AccountData, _ bool) (sc.Encodable, error)) (sc.Encodable, error) { - account := &primitives.AccountData{} +func (m module) mutateAccount(who primitives.AccountId, maybeAccount *primitives.AccountData, f func(who *primitives.AccountData, _ bool) (sc.Encodable, error)) (sc.Encodable, error) { + data := primitives.DefaultAccountData() + account := &data isNew := true - if !reflect.DeepEqual(*maybeAccount, primitives.AccountData{}) { + if !reflect.DeepEqual(*maybeAccount, primitives.DefaultAccountData()) { account = maybeAccount isNew = false } + acc, err := m.Config.StoredMap.Get(who) + if err != nil { + return primitives.Balance{}, primitives.NewDispatchErrorOther(sc.Str(err.Error())) + } + + didProvide := account.Free.Gte(m.constants.ExistentialDeposit) && acc.Providers > 0 + didConsume := !isNew && (!account.Reserved.Eq(constants.Zero) || !account.Frozen.Eq(constants.Zero)) + result, err := f(account, isNew) if err != nil { return result, err } + doesProvide := account.Free.Gte(m.constants.ExistentialDeposit) + doesConsume := !account.Reserved.Eq(constants.Zero) || !account.Frozen.Eq(constants.Zero) + + if !didProvide && doesProvide { + _, err = m.Config.StoredMap.IncProviders(who) + if err != nil { + return nil, err + } + } + if didConsume && !doesConsume { + err = m.Config.StoredMap.DecConsumers(who) + if err != nil { + return nil, err + } + } + if !didConsume && doesConsume { + err = m.Config.StoredMap.IncConsumers(who) + if err != nil { + return nil, err + } + } + if didProvide && !doesProvide { + // This could reap the account so must go last. + _, err = m.Config.StoredMap.DecProviders(who) + if err != nil { + if didConsume && !doesConsume { + err := m.Config.StoredMap.IncConsumers(who) + if err != nil { + m.logger.Criticalf("defensive: [%s]", err.Error()) + } + } + if !didConsume && doesConsume { + err := m.Config.StoredMap.DecConsumers(who) + if err != nil { + return nil, err + } + } + return nil, err + } + } + maybeEndowed := sc.NewOption[primitives.Balance](nil) if isNew { maybeEndowed = sc.NewOption[primitives.Balance](account.Free) } - maybeAccountWithDust, imbalance := m.postMutation(*account) - if !maybeAccountWithDust.HasValue { - maybeAccount = &primitives.AccountData{} + + maybeDust := sc.NewOption[primitives.Balance](nil) + if account.Free.Lt(m.constants.ExistentialDeposit) && account.Reserved.Eq(constants.Zero) { + if !account.Free.Eq(constants.Zero) { + maybeDust = sc.NewOption[primitives.Balance](account.Free) + } } else { - maybeAccount.Free = maybeAccountWithDust.Value.Free - maybeAccount.MiscFrozen = maybeAccountWithDust.Value.MiscFrozen - maybeAccount.FeeFrozen = maybeAccountWithDust.Value.FeeFrozen - maybeAccount.Reserved = maybeAccountWithDust.Value.Reserved + if !(account.Free.Eq(constants.Zero) || account.Free.Gte(m.constants.ExistentialDeposit) || account.Reserved.Eq(constants.Zero)) { + m.logger.Criticalf("failed to assert maybe dust") + } + maybeAccount.Free = account.Free + maybeAccount.Reserved = account.Reserved + maybeAccount.Frozen = account.Frozen + maybeAccount.Flags = account.Flags } - r := sc.NewVaryingData(maybeEndowed, imbalance, result) - - return r, nil + return sc.NewVaryingData(maybeEndowed, maybeDust, result), nil } -func (m Module) postMutation(new primitives.AccountData) (sc.Option[primitives.AccountData], sc.Option[negativeImbalance]) { - total := new.Total() +func (m module) canWithdraw(who primitives.AccountId, value sc.U128) (types.WithdrawalConsequence, error) { + if value.Eq(constants.Zero) { + return types.NewWithdrawalConsequenceSuccess(), nil + } + + totalIssuance, err := m.storage.TotalIssuance.Get() + if err != nil { + return types.WithdrawalConsequence{}, primitives.NewDispatchErrorOther(sc.Str(err.Error())) + } + + if _, err := sc.CheckedSubU128(totalIssuance, value); err != nil { + return types.NewWithdrawalConsequenceUnderflow(), nil + } + + acc, err := m.Config.StoredMap.Get(who) + if err != nil { + return types.WithdrawalConsequence{}, primitives.NewDispatchErrorOther(sc.Str(err.Error())) + } + + newFreeBalance, err := sc.CheckedSubU128(acc.Data.Free, value) + if err != nil { + return types.NewWithdrawalConsequenceBalanceLow(), nil + } + + liquid, err := m.reducibleBalance(who, types.PreservationExpendable, types.FortitudePolite) + if err != nil { + return types.WithdrawalConsequence{}, err + } + + if value.Gt(liquid) { + return types.NewWithdrawalConsequenceFrozen(), nil + } + + // Provider restriction - total account balance cannot be reduced to zero if it cannot + // sustain the loss of a provider reference. + // NOTE: This assumes that the pallet is a provider (which is true). Is this ever changes, + // then this will need to adapt accordingly. - if total.Lt(m.constants.ExistentialDeposit) { - if total.Eq(constants.Zero) { - return sc.NewOption[primitives.AccountData](nil), sc.NewOption[negativeImbalance](nil) + canDecProviders, err := m.Config.StoredMap.CanDecProviders(who) + if err != nil { + return types.WithdrawalConsequence{}, primitives.NewDispatchErrorOther(sc.Str(err.Error())) + } + + var success types.WithdrawalConsequence + if newFreeBalance.Lt(m.constants.ExistentialDeposit) { + if canDecProviders { + success = types.NewWithdrawalConsequenceReducedToZero(newFreeBalance) } else { - return sc.NewOption[primitives.AccountData](nil), sc.NewOption[negativeImbalance](newNegativeImbalance(total, m.storage.TotalIssuance)) + return types.NewWithdrawalConsequenceWouldDie(), nil } + } else { + success = types.NewWithdrawalConsequenceSuccess() } - return sc.NewOption[primitives.AccountData](new), sc.NewOption[negativeImbalance](nil) + newTotalBalance := sc.SaturatingAddU128(newFreeBalance, acc.Data.Reserved) + if newTotalBalance.Lt(acc.Data.Frozen) { + return types.NewWithdrawalConsequenceFrozen(), nil + } + + return success, nil } -func (m Module) withdraw(who primitives.AccountId, value sc.U128, account *primitives.AccountData, reasons sc.U8, liveness primitives.ExistenceRequirement) (sc.Encodable, error) { - newFreeAccount, err := sc.CheckedSubU128(account.Free, value) +// Returns `true` if the balance of `who` may be increased by `amount`. +// +// - `who`: The account of which the balance should be increased by `amount`. +// - `amount`: How much should the balance be increased? +// - `provenance`: Will `amount` be minted to deposit it into `account` or is it already in the system? +func (m module) canDeposit(who primitives.AccountId, amount primitives.Balance, minted bool) (types.DepositConsequence, error) { + if amount.Eq(constants.Zero) { + return types.NewDepositConsequenceSuccess(), nil + } + + if minted { + if totalIssuance, err := m.storage.TotalIssuance.Get(); err != nil { + return types.DepositConsequence{}, primitives.NewDispatchErrorOther(sc.Str(err.Error())) + } else if _, err := sc.CheckedAddU128(totalIssuance, amount); err != nil { + return types.NewDepositConsequenceOverflow(), nil + } + } + + acc, err := m.Config.StoredMap.Get(who) if err != nil { - return nil, primitives.NewDispatchErrorModule(primitives.CustomModuleError{ - Index: m.Index, - Err: sc.U32(ErrorInsufficientBalance), - Message: sc.NewOption[sc.Str](nil), - }) + return types.DepositConsequence{}, primitives.NewDispatchErrorOther(sc.Str(err.Error())) } - existentialDeposit := m.constants.ExistentialDeposit + newFree, err := sc.CheckedAddU128(acc.Data.Free, amount) + if err != nil { + return types.NewDepositConsequenceOverflow(), nil + } + if newFree.Lt(m.constants.ExistentialDeposit) { + return types.NewDepositConsequenceBelowMinimum(), nil + } - wouldBeDead := (newFreeAccount.Add(account.Reserved)).Lt(existentialDeposit) - wouldKill := wouldBeDead && ((account.Free.Add(account.Reserved)).Gte(existentialDeposit)) + if _, err := sc.CheckedAddU128(acc.Data.Reserved, newFree); err != nil { + return types.NewDepositConsequenceOverflow(), nil + } - if !(liveness == primitives.ExistenceRequirementAllowDeath || !wouldKill) { - return nil, primitives.NewDispatchErrorModule(primitives.CustomModuleError{ - Index: m.Index, - Err: sc.U32(ErrorKeepAlive), - Message: sc.NewOption[sc.Str](nil), - }) + // NOTE: We assume that we are a provider, so don't need to do any checks in the + // case of account creation. + return types.NewDepositConsequenceSuccess(), nil +} + +// Get the maximum amount that `who` can withdraw/transfer successfully based on whether the +// account should be kept alive (`preservation`) or whether we are willing to force the +// reduction and potentially go below user-level restrictions on the minimum amount of the account. +// +// Always less than or equal to [`Inspect::balance`]. +func (m module) reducibleBalance(who primitives.AccountId, preservation types.Preservation, force types.Fortitude) (primitives.Balance, error) { + acc, err := m.Config.StoredMap.Get(who) + if err != nil { + return primitives.Balance{}, primitives.NewDispatchErrorOther(sc.Str(err.Error())) } - if err := m.ensureCanWithdraw(who, value, primitives.Reasons(reasons), newFreeAccount); err != nil { - return nil, err + untouchable := sc.NewU128(0) + if force == types.FortitudePolite { + // Frozen balance applies to total. Anything on hold therefore gets discounted from the limit given by the freezes. + untouchable = sc.SaturatingSubU128(acc.Data.Frozen, acc.Data.Reserved) } - account.Free = newFreeAccount + canDecProviders, err := m.Config.StoredMap.CanDecProviders(who) + if err != nil { + return primitives.Balance{}, primitives.NewDispatchErrorOther(sc.Str(err.Error())) + } - m.Config.StoredMap.DepositEvent(newEventWithdraw(m.Index, who, value)) - return value, nil + // If we want to keep our provider ref + if preservation == types.PreservationPreserve || + // ..or we don't want the account to die and our provider ref is needed for it to live.. + (preservation == types.PreservationProtect && !acc.Data.Free.Eq(constants.Zero) && acc.Providers == 1) || + // ..or we don't care about the account dying but our provider ref is required.. + (preservation == types.PreservationExpendable && !acc.Data.Free.Eq(constants.Zero) && !canDecProviders) { + // ..then the ED needed.. + untouchable = sc.Max128(untouchable, m.Config.ExistentialDeposit) + } + + // Liquid balance is what is neither on hold nor frozen/required for provider. + return sc.SaturatingSubU128(acc.Data.Free, untouchable), nil } -func (m Module) deposit(who primitives.AccountId, account *primitives.AccountData, isNew bool, value sc.U128) (sc.Encodable, error) { - if isNew { - return nil, primitives.NewDispatchErrorModule(primitives.CustomModuleError{ - Index: m.Index, - Err: sc.U32(ErrorDeadAccount), - Message: sc.NewOption[sc.Str](nil), - }) +func (m module) Unreserve(who primitives.AccountId, value sc.U128) (sc.U128, error) { + if value.Eq(constants.Zero) { + return constants.Zero, nil } - free, err := sc.CheckedAddU128(account.Free, value) + account, err := m.Config.StoredMap.Get(who) if err != nil { - return nil, primitives.NewDispatchErrorArithmetic(primitives.NewArithmeticErrorOverflow()) + return sc.U128{}, primitives.NewDispatchErrorOther(sc.Str(err.Error())) } - account.Free = free - m.Config.StoredMap.DepositEvent(newEventDeposit(m.Index, who, value)) + totalBalance := account.Data.Total() + if totalBalance.Eq(constants.Zero) { + return value, nil + } - return value, nil + result, err := m.MutateAccountHandlingDust(who, func(accountData *primitives.AccountData, bool bool) (sc.Encodable, error) { + return removeReserveAndFree(accountData, value), nil + }) + if err != nil { + return sc.U128{}, err + } + actual := result.(primitives.Balance) + m.Config.StoredMap.DepositEvent(newEventUnreserved(m.Index, who, actual)) + + return value.Sub(actual), nil } -func (m Module) Metadata() primitives.MetadataModule { - metadataIdBalancesCalls := m.mdGenerator.BuildCallsMetadata("Balances", m.functions, &sc.Sequence[primitives.MetadataTypeParameter]{ - primitives.NewMetadataEmptyTypeParameter("T"), - primitives.NewMetadataEmptyTypeParameter("I")}) - - mdConstants := metadataConstants{ - ExistentialDeposit: primitives.ExistentialDeposit{U128: m.constants.ExistentialDeposit}, - MaxLocks: primitives.MaxLocks{U32: m.constants.MaxLocks}, - MaxReserves: primitives.MaxReserves{U32: m.constants.MaxReserves}, - } - - moduleMdConstants := m.mdGenerator.BuildModuleConstants(reflect.ValueOf(mdConstants)) - - dataV14 := primitives.MetadataModuleV14{ - Name: m.name(), - Storage: m.metadataStorage(), - Call: sc.NewOption[sc.Compact](sc.ToCompact(metadataIdBalancesCalls)), - CallDef: sc.NewOption[primitives.MetadataDefinitionVariant]( - primitives.NewMetadataDefinitionVariantStr( - m.name(), - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithName(metadataIdBalancesCalls, "self::sp_api_hidden_includes_construct_runtime::hidden_include::dispatch\n::CallableCallFor"), - }, - m.Index, - "Call.Balances"), - ), - Event: sc.NewOption[sc.Compact](sc.ToCompact(metadata.TypesBalancesEvent)), - EventDef: sc.NewOption[primitives.MetadataDefinitionVariant]( - primitives.NewMetadataDefinitionVariantStr( - m.name(), - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithName(metadata.TypesBalancesEvent, "pallet_balances::Event"), - }, - m.Index, - "Events.Balances"), - ), - Constants: moduleMdConstants, - Error: sc.NewOption[sc.Compact](sc.ToCompact(metadata.TypesBalancesErrors)), - ErrorDef: sc.NewOption[primitives.MetadataDefinitionVariant]( - primitives.NewMetadataDefinitionVariantStr( - m.name(), - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionField(metadata.TypesBalancesErrors), - }, - m.Index, - "Errors.Balances"), - ), - Index: m.Index, - } - - m.mdGenerator.AppendMetadataTypes(m.metadataTypes()) - - return primitives.MetadataModule{ - Version: primitives.ModuleVersion14, - ModuleV14: dataV14, - } -} - -func (m Module) metadataTypes() sc.Sequence[primitives.MetadataType] { - return sc.Sequence[primitives.MetadataType]{ - primitives.NewMetadataTypeWithPath(metadata.TypesBalancesEvent, "pallet_balances pallet Event", sc.Sequence[sc.Str]{"pallet_balances", "pallet", "Event"}, primitives.NewMetadataTypeDefinitionVariant( - sc.Sequence[primitives.MetadataDefinitionVariant]{ - primitives.NewMetadataDefinitionVariant( - "Endowed", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "account", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "free_balance", "T::Balance"), - }, - EventEndowed, - "Event.Endowed"), - primitives.NewMetadataDefinitionVariant( - "DustLost", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "account", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - }, - EventDustLost, - "Events.DustLost"), - primitives.NewMetadataDefinitionVariant( - "Transfer", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "from", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "to", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - }, - EventTransfer, - "Events.Transfer"), - primitives.NewMetadataDefinitionVariant( - "BalanceSet", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "free", "T::Balance"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "reserved", "T::Balance"), - }, - EventBalanceSet, - "Events.BalanceSet"), - primitives.NewMetadataDefinitionVariant( - "Reserved", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - }, - EventReserved, - "Events.Reserved"), - primitives.NewMetadataDefinitionVariant( - "Unreserved", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - }, - EventUnreserved, - "Events.Unreserved"), - primitives.NewMetadataDefinitionVariant( - "ReserveRepatriated", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "from", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "to", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesBalanceStatus, "destination_status", "Status"), - }, - EventReserveRepatriated, - "Events.ReserveRepatriated"), - primitives.NewMetadataDefinitionVariant( - "Deposit", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - }, - EventDeposit, - "Event.Deposit"), - primitives.NewMetadataDefinitionVariant( - "Withdraw", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - }, - EventWithdraw, - "Event.Withdraw"), - primitives.NewMetadataDefinitionVariant( - "Slashed", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - }, - EventSlashed, - "Event.Slashed"), - }, - )), - primitives.NewMetadataTypeWithPath(metadata.TypesBalanceStatus, - "BalanceStatus", - sc.Sequence[sc.Str]{"frame_support", "traits", "tokens", "misc", "BalanceStatus"}, primitives.NewMetadataTypeDefinitionVariant( - sc.Sequence[primitives.MetadataDefinitionVariant]{ - primitives.NewMetadataDefinitionVariant( - "Free", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - types.BalanceStatusFree, - "BalanceStatus.Free"), - primitives.NewMetadataDefinitionVariant( - "Reserved", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - types.BalanceStatusReserved, - "BalanceStatus.Reserved"), - })), - - primitives.NewMetadataTypeWithParams(metadata.TypesBalancesErrors, - "pallet_balances pallet Error", - sc.Sequence[sc.Str]{"pallet_balances", "pallet", "Error"}, - primitives.NewMetadataTypeDefinitionVariant( - sc.Sequence[primitives.MetadataDefinitionVariant]{ - primitives.NewMetadataDefinitionVariant( - "VestingBalance", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorVestingBalance, - "Vesting balance too high to send value"), - primitives.NewMetadataDefinitionVariant( - "LiquidityRestrictions", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorLiquidityRestrictions, - "Account liquidity restrictions prevent withdrawal"), - primitives.NewMetadataDefinitionVariant( - "InsufficientBalance", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorInsufficientBalance, - "Balance too low to send value."), - primitives.NewMetadataDefinitionVariant( - "ExistentialDeposit", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorExistentialDeposit, - "Value too low to create account due to existential deposit"), - primitives.NewMetadataDefinitionVariant( - "KeepAlive", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorKeepAlive, - "Transfer/payment would kill account"), - primitives.NewMetadataDefinitionVariant( - "ExistingVestingSchedule", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorExistingVestingSchedule, - "A vesting schedule already exists for this account"), - primitives.NewMetadataDefinitionVariant( - "DeadAccount", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorDeadAccount, - "Beneficiary account must pre-exist"), - primitives.NewMetadataDefinitionVariant( - "TooManyReserves", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorTooManyReserves, - "Number of named reserves exceed MaxReserves"), - }), - sc.Sequence[primitives.MetadataTypeParameter]{ - primitives.NewMetadataEmptyTypeParameter("T"), - primitives.NewMetadataEmptyTypeParameter("I"), - }), - } -} - -func (m Module) metadataStorage() sc.Option[primitives.MetadataModuleStorage] { - return sc.NewOption[primitives.MetadataModuleStorage](primitives.MetadataModuleStorage{ - Prefix: m.name(), - Items: sc.Sequence[primitives.MetadataModuleStorageEntry]{ - primitives.NewMetadataModuleStorageEntry( - "TotalIssuance", - primitives.MetadataModuleStorageEntryModifierDefault, - primitives.NewMetadataModuleStorageEntryDefinitionPlain(sc.ToCompact(metadata.PrimitiveTypesU128)), - "The total units issued in the system."), - }, - }) +// removeReserveAndFree frees reserved value from the account. +func removeReserveAndFree(account *primitives.AccountData, value sc.U128) primitives.Balance { + actual := sc.Min128(account.Reserved, value) + account.Reserved = account.Reserved.Sub(actual) + + account.Free = sc.SaturatingAddU128(account.Free, actual) + + return actual +} + +func updateAccount(account *primitives.AccountData, data primitives.AccountData) { + account.Free = data.Free + account.Reserved = data.Reserved + account.Frozen = data.Frozen + account.Flags = data.Flags +} + +func (m module) TotalIssuance() support.StorageValue[goscale.U128] { + return m.storage.TotalIssuance +} + +func (m module) DbWeight() primitives.RuntimeDbWeight { + return m.constants.DbWeight +} + +func (m module) DepositEvent(event primitives.Event) { + m.Config.StoredMap.DepositEvent(event) +} + +func (m module) ExistentialDeposit() sc.U128 { + return m.Config.ExistentialDeposit } diff --git a/frame/balances/module_mock_test.go b/frame/balances/module_mock_test.go new file mode 100644 index 00000000..b9c648ff --- /dev/null +++ b/frame/balances/module_mock_test.go @@ -0,0 +1,151 @@ +package balances + +import ( + "github.com/LimeChain/goscale" + sc "github.com/LimeChain/goscale" + "github.com/LimeChain/gosemble/frame/support" + primitives "github.com/LimeChain/gosemble/primitives/types" + "github.com/stretchr/testify/mock" +) + +type MockModule struct { + mock.Mock +} + +func (m *MockModule) GetIndex() sc.U8 { + args := m.Called() + return args.Get(0).(sc.U8) +} + +func (m *MockModule) Functions() map[sc.U8]primitives.Call { + args := m.Called() + return args.Get(0).(map[sc.U8]primitives.Call) +} + +func (m *MockModule) PreDispatch(call primitives.Call) (sc.Empty, error) { + args := m.Called(call) + return args.Get(0).(sc.Empty), args.Get(1).(error) +} + +func (m *MockModule) ValidateUnsigned(source primitives.TransactionSource, call primitives.Call) (primitives.ValidTransaction, error) { + args := m.Called(source, call) + return args.Get(0).(primitives.ValidTransaction), args.Get(1).(error) +} + +func (m *MockModule) Metadata() primitives.MetadataModule { + args := m.Called() + return args.Get(0).(primitives.MetadataModule) +} + +func (m *MockModule) CreateInherent(inherent primitives.InherentData) (sc.Option[primitives.Call], error) { + args := m.Called(inherent) + + if args.Get(1) == nil { + return args.Get(0).(sc.Option[primitives.Call]), nil + } + + return args.Get(0).(sc.Option[primitives.Call]), args.Get(1).(error) +} + +func (m *MockModule) CheckInherent(call primitives.Call, data primitives.InherentData) error { + args := m.Called(call, data) + return args.Get(0).(error) +} + +func (m *MockModule) InherentIdentifier() [8]byte { + args := m.Called() + return args.Get(0).([8]byte) +} + +func (m *MockModule) IsInherent(call primitives.Call) bool { + args := m.Called(call) + return args.Get(0).(bool) +} + +func (m *MockModule) OnInitialize(n sc.U64) (primitives.Weight, error) { + args := m.Called(n) + + if args.Get(1) == nil { + return args.Get(0).(primitives.Weight), nil + } + + return args.Get(0).(primitives.Weight), args.Get(1).(error) +} + +func (m *MockModule) OnRuntimeUpgrade() primitives.Weight { + args := m.Called() + return args.Get(0).(primitives.Weight) +} + +func (m *MockModule) OnFinalize(n sc.U64) error { + args := m.Called(n) + return args.Get(0).(error) +} + +func (m *MockModule) OnIdle(n sc.U64, remainingWeight primitives.Weight) primitives.Weight { + args := m.Called(n, remainingWeight) + return args.Get(0).(primitives.Weight) +} + +func (m *MockModule) OffchainWorker(n sc.U64) { + m.Called(n) +} + +func (m *MockModule) Unreserve(who primitives.AccountId, value sc.U128) (sc.U128, error) { + args := m.Called(who, value) + + if args.Get(1) == nil { + return args.Get(0).(sc.U128), nil + } + + return args.Get(0).(sc.U128), args.Get(1).(error) +} + +func (m *MockModule) DbWeight() primitives.RuntimeDbWeight { + args := m.Called() + return args.Get(0).(primitives.RuntimeDbWeight) +} + +func (m *MockModule) ExistentialDeposit() sc.U128 { + args := m.Called() + return args.Get(0).(sc.U128) +} + +func (m *MockModule) MutateAccountHandlingDust(who primitives.AccountId, f func(who *primitives.AccountData, bool bool) (sc.Encodable, error)) (sc.Encodable, error) { + args := m.Called(who, f) + + if args.Get(1) == nil { + return args.Get(0).(sc.Encodable), nil + } + + return args.Get(0).(sc.Encodable), args.Get(1).(error) +} + +func (m *MockModule) TotalIssuance() support.StorageValue[goscale.U128] { + args := m.Called() + return args.Get(0).(support.StorageValue[goscale.U128]) +} + +func (m *MockModule) DepositEvent(event primitives.Event) { + m.Called(event) +} + +func (m *MockModule) DepositIntoExisting(who primitives.AccountId, value sc.U128) (primitives.Balance, error) { + args := m.Called(who, value) + + if args.Get(1) == nil { + return args.Get(0).(primitives.Balance), nil + } + + return args.Get(0).(primitives.Balance), args.Get(1).(error) +} + +func (m *MockModule) Withdraw(who primitives.AccountId, value sc.U128, reasons sc.U8, liveness primitives.ExistenceRequirement) (primitives.Balance, error) { + args := m.Called(who, value, reasons, liveness) + + if args.Get(1) == nil { + return args.Get(0).(primitives.Balance), nil + } + + return args.Get(0).(primitives.Balance), args.Get(1).(error) +} diff --git a/frame/balances/module_test.go b/frame/balances/module_test.go index b7245fdd..054c2983 100644 --- a/frame/balances/module_test.go +++ b/frame/balances/module_test.go @@ -4,195 +4,220 @@ import ( "testing" sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/constants/metadata" - "github.com/LimeChain/gosemble/frame/balances/types" + "github.com/LimeChain/gosemble/constants" "github.com/LimeChain/gosemble/mocks" "github.com/LimeChain/gosemble/primitives/log" + "github.com/LimeChain/gosemble/primitives/types" primitives "github.com/LimeChain/gosemble/primitives/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) +const ( + moduleId = sc.U8(3) +) + var ( + maxLocks = sc.U32(5) + maxReserves = sc.U32(6) + existentialDeposit = sc.NewU128(1) + dbWeight = primitives.RuntimeDbWeight{ + Read: 1, + Write: 2, + } + baseWeight = primitives.WeightFromParts(124, 123) mdGenerator = primitives.NewMetadataTypeGenerator() + logger = log.NewLogger() + accountInfo = primitives.AccountInfo{ + Data: primitives.AccountData{ + Free: sc.NewU128(4), + Reserved: primitives.Balance{}, + Frozen: primitives.Balance{}, + // Flags: primitives.DefaultExtraFlags, + }, + } + fromAddress = constants.OneAccountId + toAddress = constants.TwoAccountId + targetAddress = constants.ZeroAccountId + targetMultiAddress = primitives.NewMultiAddressId(targetAddress) + targetValue = sc.NewU128(5) + + newFree = sc.NewU128(5) + newReserved = sc.NewU128(6) + oldFree = sc.NewU128(4) + oldReserved = sc.NewU128(3) ) var ( - unknownTransactionNoUnsignedValidator = primitives.NewTransactionValidityError(primitives.NewUnknownTransactionNoUnsignedValidator()) + expectedErr = primitives.NewDispatchErrorCannotLookup() ) var ( - mockStorage *mocks.IoStorage - mockTypeMutateAccountData = mock.AnythingOfType("func(*types.AccountData) (goscale.Encodable, error)") - logger = log.NewLogger() + mockStorage *mocks.IoStorage + mockStoredMap *mocks.StoredMap + mockTotalIssuance *mocks.StorageValue[sc.U128] + mockCall = new(mocks.Call) + mockTypeMutateAccountData = mock.AnythingOfType("func(*types.AccountData) (goscale.Encodable, error)") + mockTypeMutateAccountDataBool = mock.AnythingOfType("func(*types.AccountData, bool) (goscale.Encodable, error)") ) +var ( + target module +) + +func setupModule() module { + mockStorage = new(mocks.IoStorage) + mockStoredMap = new(mocks.StoredMap) + mockTotalIssuance = new(mocks.StorageValue[sc.U128]) + + config := NewConfig(mockStorage, dbWeight, maxLocks, maxReserves, existentialDeposit, mockStoredMap) + target = New(moduleId, config, mdGenerator, logger).(module) + target.storage.TotalIssuance = mockTotalIssuance + + return target +} + func Test_Module_GetIndex(t *testing.T) { - assert.Equal(t, sc.U8(moduleId), setupModule().GetIndex()) + target = setupModule() + + assert.Equal(t, sc.U8(moduleId), target.GetIndex()) } func Test_Module_Functions(t *testing.T) { - target := setupModule() - functions := target.Functions() + target = setupModule() - assert.Equal(t, 6, len(functions)) + assert.Equal(t, 8, len(target.Functions())) } func Test_Module_PreDispatch(t *testing.T) { - target := setupModule() + target = setupModule() - result, err := target.PreDispatch(setupCallTransfer()) + result, err := target.PreDispatch(mockCall) assert.Nil(t, err) assert.Equal(t, sc.Empty{}, result) } func Test_Module_ValidateUnsigned(t *testing.T) { - target := setupModule() + target = setupModule() - result, err := target.ValidateUnsigned(primitives.TransactionSource{}, setupCallTransfer()) + result, err := target.ValidateUnsigned(primitives.TransactionSource{}, mockCall) - assert.Equal(t, unknownTransactionNoUnsignedValidator, err) + assert.Equal(t, primitives.NewTransactionValidityError(primitives.NewUnknownTransactionNoUnsignedValidator()), err) assert.Equal(t, primitives.ValidTransaction{}, result) } func Test_Module_DepositIntoExisting_Success(t *testing.T) { - target := setupModule() - mockTotalIssuance := new(mocks.StorageValue[sc.U128]) - target.storage.TotalIssuance = mockTotalIssuance - - tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[negativeImbalance](nil), targetValue) - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) + target = setupModule() - mockStoredMap.On("TryMutateExists", fromAddressId, mockTypeMutateAccountData).Return(tryMutateResult, nil) + mockStoredMap.On("Get", fromAddress).Return(accountInfo, nil) + tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[sc.U128](nil), targetValue) + mockStoredMap.On("TryMutateExists", fromAddress, mockTypeMutateAccountData).Return(tryMutateResult, nil) + mockStoredMap.On("DepositEvent", newEventUpgraded(moduleId, fromAddress)) - result, errDeposit := target.DepositIntoExisting(fromAddressId, targetValue) - assert.Nil(t, errDeposit) + result, err := target.DepositIntoExisting(fromAddress, targetValue) - assert.Equal(t, targetValue, result) assert.Nil(t, err) - mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddressId, mockTypeMutateAccountData) - mockTotalIssuance.AssertNotCalled(t, "Get") - mockTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) + assert.Equal(t, targetValue, result) + + mockStoredMap.AssertCalled(t, "Get", fromAddress) + mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddress, mockTypeMutateAccountData) + mockStoredMap.AssertCalled(t, "DepositEvent", newEventUpgraded(moduleId, fromAddress)) } func Test_Module_DepositIntoExisting_ZeroValue(t *testing.T) { - target := setupModule() + target = setupModule() - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - result, errDeposit := target.DepositIntoExisting(fromAddressId, sc.NewU128(0)) - assert.Nil(t, errDeposit) + result, err := target.DepositIntoExisting(fromAddress, sc.NewU128(0)) - assert.Equal(t, sc.NewU128(0), result) assert.Nil(t, err) + assert.Equal(t, sc.NewU128(0), result) mockStoredMap.AssertNotCalled(t, "TryMutateExists", mock.Anything, mock.Anything) mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) } func Test_Module_DepositIntoExisting_TryMutateAccount_Fails(t *testing.T) { - target := setupModule() + target = setupModule() - expectedResult := sc.NewU128(1) - expectedErr := primitives.NewDispatchErrorCannotLookup() + mockStoredMap.On("Get", fromAddress).Return(accountInfo, nil) + tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[sc.U128](nil), targetValue) + mockStoredMap.On("TryMutateExists", fromAddress, mockTypeMutateAccountData).Return(tryMutateResult, expectedErr) - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - mockStoredMap.On("TryMutateExists", fromAddressId, mockTypeMutateAccountData).Return(expectedResult, expectedErr) - - _, errDeposit := target.DepositIntoExisting(fromAddressId, targetValue) + _, errDeposit := target.DepositIntoExisting(fromAddress, targetValue) assert.Equal(t, expectedErr, errDeposit) - mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddressId, mockTypeMutateAccountData) + mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddress, mockTypeMutateAccountData) mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) } func Test_Module_Withdraw_Success(t *testing.T) { - target := setupModule() - mockTotalIssuance := new(mocks.StorageValue[sc.U128]) - target.storage.TotalIssuance = mockTotalIssuance - - tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[negativeImbalance](nil), targetValue) - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) + target = setupModule() - mockStoredMap.On("TryMutateExists", fromAddressId, mockTypeMutateAccountData).Return(tryMutateResult, nil) + mockStoredMap.On("Get", fromAddress).Return(accountInfo, nil) + tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[sc.U128](nil), targetValue) + mockStoredMap.On("TryMutateExists", fromAddress, mockTypeMutateAccountData).Return(tryMutateResult, nil) + mockStoredMap.On("DepositEvent", newEventUpgraded(moduleId, fromAddress)) - result, errWithdraw := target.Withdraw(fromAddressId, targetValue, sc.U8(primitives.ReasonsFee), primitives.ExistenceRequirementKeepAlive) - assert.Nil(t, errWithdraw) + result, err := target.Withdraw(fromAddress, targetValue, sc.U8(primitives.ReasonsFee), primitives.ExistenceRequirementKeepAlive) - assert.Equal(t, targetValue, result) assert.Nil(t, err) - mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddressId, mockTypeMutateAccountData) + assert.Equal(t, targetValue, result) + + mockStoredMap.AssertCalled(t, "Get", fromAddress) + mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddress, mockTypeMutateAccountData) + mockStoredMap.AssertCalled(t, "DepositEvent", newEventUpgraded(moduleId, fromAddress)) mockTotalIssuance.AssertNotCalled(t, "Get") mockTotalIssuance.AssertNotCalled(t, "Put", mock.Anything) } func Test_Module_Withdraw_ZeroValue(t *testing.T) { - target := setupModule() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) + target = setupModule() - result, errWithdraw := target.Withdraw(fromAddressId, sc.NewU128(0), sc.U8(primitives.ReasonsFee), primitives.ExistenceRequirementKeepAlive) - assert.Nil(t, errWithdraw) + result, err := target.Withdraw(fromAddress, sc.NewU128(0), sc.U8(primitives.ReasonsFee), primitives.ExistenceRequirementKeepAlive) - assert.Equal(t, sc.NewU128(0), result) assert.Nil(t, err) + assert.Equal(t, sc.NewU128(0), result) mockStoredMap.AssertNotCalled(t, "TryMutateExists", mock.Anything, mock.Anything) mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) } func Test_Module_Withdraw_TryMutateAccount_Fails(t *testing.T) { - target := setupModule() - - expectedErr := primitives.NewDispatchErrorCannotLookup() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) + target = setupModule() - mockStoredMap.On("TryMutateExists", fromAddressId, mockTypeMutateAccountData).Return(sc.NewU128(1), expectedErr) + mockStoredMap.On("Get", fromAddress).Return(accountInfo, nil) + tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[sc.U128](nil), targetValue) + mockStoredMap.On("TryMutateExists", fromAddress, mockTypeMutateAccountData).Return(tryMutateResult, expectedErr) - _, errWithdraw := target.Withdraw(fromAddressId, targetValue, sc.U8(primitives.ReasonsFee), primitives.ExistenceRequirementKeepAlive) + _, errWithdraw := target.Withdraw(fromAddress, targetValue, sc.U8(primitives.ReasonsFee), primitives.ExistenceRequirementKeepAlive) assert.Equal(t, expectedErr, errWithdraw) - mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddressId, mockTypeMutateAccountData) + mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddress, mockTypeMutateAccountData) mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) } func Test_Module_ensureCanWithdraw_Success(t *testing.T) { - target := setupModule() + target = setupModule() - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - mockStoredMap.On("Get", fromAddressId).Return(accountInfo, nil) + mockStoredMap.On("Get", fromAddress).Return(accountInfo, nil) - result := target.ensureCanWithdraw(fromAddressId, targetValue, primitives.ReasonsFee, sc.NewU128(5)) + result := target.ensureCanWithdraw(fromAddress, targetValue, primitives.ReasonsFee, sc.NewU128(5)) assert.Nil(t, result) - mockStoredMap.AssertCalled(t, "Get", fromAddressId) + mockStoredMap.AssertCalled(t, "Get", fromAddress) } func Test_Module_ensureCanWithdraw_ZeroAmount(t *testing.T) { - target := setupModule() + target = setupModule() - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - result := target.ensureCanWithdraw(fromAddressId, sc.NewU128(0), primitives.ReasonsFee, sc.NewU128(5)) + result := target.ensureCanWithdraw(fromAddress, sc.NewU128(0), primitives.ReasonsFee, sc.NewU128(5)) assert.Nil(t, result) - mockStoredMap.AssertNotCalled(t, "Get", fromAddressId) + mockStoredMap.AssertNotCalled(t, "Get", fromAddress) } func Test_Module_ensureCanWithdraw_LiquidityRestrictions(t *testing.T) { - target := setupModule() + target = setupModule() + expected := primitives.NewDispatchErrorModule(primitives.CustomModuleError{ Index: moduleId, Err: sc.U32(ErrorLiquidityRestrictions), @@ -200,321 +225,287 @@ func Test_Module_ensureCanWithdraw_LiquidityRestrictions(t *testing.T) { }) frozenAccountInfo := primitives.AccountInfo{ Data: primitives.AccountData{ - MiscFrozen: sc.NewU128(10), - FeeFrozen: sc.NewU128(11), + Frozen: sc.NewU128(10), }, } - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - mockStoredMap.On("Get", fromAddressId).Return(frozenAccountInfo, nil) + mockStoredMap.On("Get", fromAddress).Return(frozenAccountInfo, nil) - result := target.ensureCanWithdraw(fromAddressId, targetValue, primitives.ReasonsFee, sc.NewU128(5)) + result := target.ensureCanWithdraw(fromAddress, targetValue, primitives.ReasonsFee, sc.NewU128(5)) assert.Equal(t, expected, result) - mockStoredMap.AssertCalled(t, "Get", fromAddressId) + mockStoredMap.AssertCalled(t, "Get", fromAddress) } func Test_Module_tryMutateAccount_Success(t *testing.T) { - target := setupModule() - mockTotalIssuance := new(mocks.StorageValue[sc.U128]) - target.storage.TotalIssuance = mockTotalIssuance - - tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[negativeImbalance](nil), sc.U128{}) - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) + target = setupModule() - mockStoredMap.On("TryMutateExists", fromAddressId, mockTypeMutateAccountData).Return(tryMutateResult, nil) + mockStoredMap.On("Get", fromAddress).Return(accountInfo, nil) + tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[sc.U128](nil), sc.U128{}) + mockStoredMap.On("TryMutateExists", fromAddress, mockTypeMutateAccountData).Return(tryMutateResult, nil) + mockStoredMap.On("DepositEvent", newEventUpgraded(moduleId, fromAddress)) - _, err = target.tryMutateAccount(fromAddressId, func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { return nil, nil }) + _, err := target.tryMutateAccount(fromAddress, func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { return nil, nil }) assert.NoError(t, err) - mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddressId, mockTypeMutateAccountData) + mockStoredMap.AssertCalled(t, "Get", fromAddress) + mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddress, mockTypeMutateAccountData) + mockStoredMap.AssertCalled(t, "DepositEvent", newEventUpgraded(moduleId, fromAddress)) } func Test_Module_tryMutateAccount_TryMutateAccountWithDust_Fails(t *testing.T) { - target := setupModule() - expectedErr := primitives.NewDispatchErrorCannotLookup() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) + target = setupModule() - mockStoredMap.On("TryMutateExists", fromAddressId, mockTypeMutateAccountData).Return(sc.NewU128(0), expectedErr) + mockStoredMap.On("Get", fromAddress).Return(accountInfo, nil) + tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[sc.U128](nil), targetValue) + mockStoredMap.On("TryMutateExists", fromAddress, mockTypeMutateAccountData).Return(tryMutateResult, expectedErr) - _, err = target.tryMutateAccount(fromAddressId, func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { return nil, nil }) + _, err := target.tryMutateAccount(fromAddress, func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { return nil, nil }) assert.Equal(t, expectedErr, err) - mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddressId, mockTypeMutateAccountData) + mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddress, mockTypeMutateAccountData) mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) } -func Test_Module_tryMutateAccountWithDust_Success(t *testing.T) { - target := setupModule() - mockTotalIssuance := new(mocks.StorageValue[sc.U128]) - target.storage.TotalIssuance = mockTotalIssuance - - tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[negativeImbalance](nil), sc.NewOption[sc.U128](nil)) +// func Test_Module_tryMutateAccountHandlingDust_Success(t *testing.T) { +// target = setupModule() - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) +// tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[negativeImbalance](nil), sc.NewOption[sc.U128](nil)) +// expectedResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), newDustCleaner(moduleId, fromAddress, sc.NewOption[negativeImbalance](nil), mockStoredMap)) - expectedResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), newDustCleaner(moduleId, fromAddressId, sc.NewOption[negativeImbalance](nil), mockStoredMap)) +// mockStoredMap.On("TryMutateExists", fromAddress, mockTypeMutateAccountData).Return(tryMutateResult, nil) - mockStoredMap.On("TryMutateExists", fromAddressId, mockTypeMutateAccountData).Return(tryMutateResult, nil) +// result, err := target.tryMutateAccountHandlingDust(fromAddress, func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { return nil, nil }) - result, err := target.tryMutateAccountWithDust(fromAddressId, func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { return nil, nil }) +// assert.NoError(t, err) +// assert.Equal(t, expectedResult, result) +// mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddress, mockTypeMutateAccountData) +// } - assert.NoError(t, err) - assert.Equal(t, expectedResult, result) - mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddressId, mockTypeMutateAccountData) -} +// func Test_Module_tryMutateAccountHandlingDust_Success_Endowed(t *testing.T) { +// target = setupModule() -func Test_Module_tryMutateAccountWithDust_Success_Endowed(t *testing.T) { - target := setupModule() - mockTotalIssuance := new(mocks.StorageValue[sc.U128]) - target.storage.TotalIssuance = mockTotalIssuance +// tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](targetValue), sc.NewOption[negativeImbalance](nil), sc.NewOption[sc.U128](targetValue)) +// expectedResult := sc.NewVaryingData(sc.NewOption[sc.U128](targetValue), newDustCleaner(moduleId, fromAddress, sc.NewOption[negativeImbalance](nil), mockStoredMap)) - tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](targetValue), sc.NewOption[negativeImbalance](nil), sc.NewOption[sc.U128](targetValue)) +// mockStoredMap.On("TryMutateExists", fromAddress, mockTypeMutateAccountData).Return(tryMutateResult, nil) +// mockStoredMap.On("DepositEvent", newEventEndowed(moduleId, fromAddress, targetValue)) - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) +// result, err := target.tryMutateAccountHandlingDust(fromAddress, func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { return nil, nil }) - expectedResult := sc.NewVaryingData(sc.NewOption[sc.U128](targetValue), newDustCleaner(moduleId, fromAddressId, sc.NewOption[negativeImbalance](nil), mockStoredMap)) +// assert.NoError(t, err) +// assert.Equal(t, expectedResult, result) +// mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddress, mockTypeMutateAccountData) +// mockStoredMap.AssertCalled(t, "DepositEvent", newEventEndowed(moduleId, fromAddress, targetValue)) +// } - mockStoredMap.On("TryMutateExists", fromAddressId, mockTypeMutateAccountData).Return(tryMutateResult, nil) - mockStoredMap.On("DepositEvent", newEventEndowed(moduleId, fromAddressId, targetValue)) +func Test_Module_tryMutateAccountHandlingDust_TryMutateExists_Fail(t *testing.T) { + target = setupModule() - result, err := target.tryMutateAccountWithDust(fromAddressId, func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { return nil, nil }) + mockStoredMap.On("Get", fromAddress).Return(accountInfo, nil) + tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[sc.U128](nil), targetValue) + mockStoredMap.On("TryMutateExists", fromAddress, mockTypeMutateAccountData).Return(tryMutateResult, expectedErr) - assert.NoError(t, err) - assert.Equal(t, expectedResult, result) - mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddressId, mockTypeMutateAccountData) - mockStoredMap.AssertCalled(t, "DepositEvent", newEventEndowed(moduleId, fromAddressId, targetValue)) -} - -func Test_Module_tryMutateAccountWithDust_TryMutateExists_Fail(t *testing.T) { - target := setupModule() - expectedErr := primitives.NewDispatchErrorCannotLookup() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - mockStoredMap.On("TryMutateExists", fromAddressId, mockTypeMutateAccountData).Return(sc.NewU128(1), expectedErr) - - _, err = target.tryMutateAccountWithDust(fromAddressId, func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { return nil, nil }) + _, err := target.tryMutateAccountHandlingDust(fromAddress, func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { return nil, nil }) assert.Equal(t, expectedErr, err) - mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddressId, mockTypeMutateAccountData) + mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddress, mockTypeMutateAccountData) mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) } func Test_Module_mutateAccount_Success(t *testing.T) { - target := setupModule() - target.storage.TotalIssuance = new(mocks.StorageValue[sc.U128]) + target = setupModule() + maybeAccount := &primitives.AccountData{} - expectedResult := sc.NewVaryingData(sc.NewOption[sc.U128](sc.NewU128(0)), sc.NewOption[negativeImbalance](nil), sc.U128{}) + expectedResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[sc.U128](nil), sc.U128{}) + + mockStoredMap.On("Get", fromAddress).Return(accountInfo, nil) - result, err := target. - mutateAccount( - maybeAccount, - func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { - return sc.U128{}, nil - }, - ) + result, err := target.mutateAccount( + fromAddress, + maybeAccount, + func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { + return sc.U128{}, nil + }, + ) assert.NoError(t, err) assert.Equal(t, expectedResult, result) + mockStoredMap.AssertCalled(t, "Get", fromAddress) } func Test_Module_mutateAccount_f_result(t *testing.T) { - target := setupModule() - target.storage.TotalIssuance = new(mocks.StorageValue[sc.U128]) + target = setupModule() + maybeAccount := &primitives.AccountData{ Free: sc.NewU128(2), } expectedErr := primitives.NewDispatchErrorBadOrigin() - _, err := target. - mutateAccount( - maybeAccount, - func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { - return nil, expectedErr - }, - ) + mockStoredMap.On("Get", fromAddress).Return(accountInfo, nil) + + result, err := target.mutateAccount( + fromAddress, + maybeAccount, + func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { + return nil, expectedErr + }, + ) assert.Equal(t, expectedErr, err) + assert.Equal(t, nil, result) + mockStoredMap.AssertCalled(t, "Get", fromAddress) } func Test_Module_mutateAccount_Success_NotNewAccount(t *testing.T) { - target := setupModule() - target.storage.TotalIssuance = new(mocks.StorageValue[sc.U128]) + target = setupModule() + maybeAccount := &primitives.AccountData{ Free: sc.NewU128(2), } - expectedResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[negativeImbalance](nil), sc.U128{}) + expectedResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[sc.U128](nil), sc.U128{}) - result, err := target. - mutateAccount( - maybeAccount, - func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { - return sc.U128{}, nil - }, - ) + mockStoredMap.On("Get", fromAddress).Return(accountInfo, nil) + mockStoredMap.On("IncProviders", fromAddress).Return(types.IncRefStatus(0), nil) + + result, err := target.mutateAccount( + fromAddress, + maybeAccount, + func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { + return sc.U128{}, nil + }, + ) assert.NoError(t, err) assert.Equal(t, expectedResult, result) + mockStoredMap.AssertCalled(t, "Get", fromAddress) + mockStoredMap.AssertCalled(t, "IncProviders", fromAddress) } -func Test_Module_postMutation_Success(t *testing.T) { - target := setupModule() - - accOption, imbalance := target.postMutation(*fromAccountData) - - assert.Equal(t, sc.NewOption[primitives.AccountData](*fromAccountData), accOption) - assert.Equal(t, sc.NewOption[negativeImbalance](nil), imbalance) -} - -func Test_Module_postMutation_ZeroTotal(t *testing.T) { - target := setupModule() - - fromAccountData.Free = sc.NewU128(0) - - accOption, imbalance := target.postMutation(*fromAccountData) - - assert.Equal(t, sc.NewOption[primitives.AccountData](nil), accOption) - assert.Equal(t, sc.NewOption[negativeImbalance](nil), imbalance) -} - -func Test_Module_postMutation_LessExistentialDeposit(t *testing.T) { - target := setupModule() - mockTotalIssuance := new(mocks.StorageValue[sc.U128]) - target.storage.TotalIssuance = mockTotalIssuance - target.constants.ExistentialDeposit = sc.NewU128(6) - - accOption, imbalance := target.postMutation(*fromAccountData) +func Test_Module_withdraw_Success(t *testing.T) { + target = setupModule() - assert.Equal(t, sc.NewOption[primitives.AccountData](nil), accOption) - assert.Equal(t, sc.NewOption[negativeImbalance](newNegativeImbalance(fromAccountData.Total(), target.storage.TotalIssuance)), imbalance) -} + fromAccountData := &primitives.AccountData{ + Free: sc.NewU128(5), + } -func Test_Module_withdraw_Success(t *testing.T) { - target := setupModule() value := sc.NewU128(3) - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) + mockStoredMap.On("Get", fromAddress).Return(accountInfo, nil) + mockStoredMap.On("DepositEvent", newEventWithdraw(moduleId, fromAddress, value)) - mockStoredMap.On("Get", fromAddressId).Return(accountInfo, nil) - mockStoredMap.On("DepositEvent", newEventWithdraw(moduleId, fromAddressId, value)) - - result, err := target.withdraw(fromAddressId, value, fromAccountData, sc.U8(primitives.ReasonsFee), primitives.ExistenceRequirementKeepAlive) + result, err := target.withdraw(fromAddress, value, fromAccountData, sc.U8(primitives.ReasonsFee), primitives.ExistenceRequirementKeepAlive) assert.NoError(t, err) assert.Equal(t, value, result) - mockStoredMap.AssertCalled(t, "Get", fromAddressId) assert.Equal(t, sc.NewU128(2), fromAccountData.Free) - mockStoredMap.AssertCalled(t, "DepositEvent", newEventWithdraw(moduleId, fromAddressId, value)) + + mockStoredMap.AssertCalled(t, "Get", fromAddress) + mockStoredMap.AssertCalled(t, "DepositEvent", newEventWithdraw(moduleId, fromAddress, value)) } func Test_Module_withdraw_InsufficientBalance(t *testing.T) { - target := setupModule() + target = setupModule() + + fromAccountData := &primitives.AccountData{ + Free: sc.NewU128(5), + } expectedErr := primitives.NewDispatchErrorModule(primitives.CustomModuleError{ Index: moduleId, Err: sc.U32(ErrorInsufficientBalance), Message: sc.NewOption[sc.Str](nil), }) - value := sc.NewU128(10) - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - _, err = target.withdraw(fromAddressId, value, fromAccountData, sc.U8(primitives.ReasonsFee), primitives.ExistenceRequirementKeepAlive) + _, err := target.withdraw(fromAddress, sc.NewU128(10), fromAccountData, sc.U8(primitives.ReasonsFee), primitives.ExistenceRequirementKeepAlive) assert.Equal(t, expectedErr, err) - mockStoredMap.AssertNotCalled(t, "Get", mock.Anything) assert.Equal(t, sc.NewU128(5), fromAccountData.Free) + + mockStoredMap.AssertNotCalled(t, "Get", mock.Anything) mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) } func Test_Module_withdraw_KeepAlive(t *testing.T) { - target := setupModule() + target = setupModule() + + fromAccountData := &primitives.AccountData{ + Free: sc.NewU128(5), + } expectedErr := primitives.NewDispatchErrorModule(primitives.CustomModuleError{ Index: moduleId, - Err: sc.U32(ErrorKeepAlive), + Err: sc.U32(ErrorExpendability), Message: sc.NewOption[sc.Str](nil), }) - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - _, err = target.withdraw(fromAddressId, targetValue, fromAccountData, sc.U8(primitives.ReasonsFee), primitives.ExistenceRequirementKeepAlive) + _, err := target.withdraw(fromAddress, targetValue, fromAccountData, sc.U8(primitives.ReasonsFee), primitives.ExistenceRequirementKeepAlive) assert.Equal(t, expectedErr, err) - mockStoredMap.AssertNotCalled(t, "Get", mock.Anything) assert.Equal(t, sc.NewU128(5), fromAccountData.Free) + mockStoredMap.AssertNotCalled(t, "Get", mock.Anything) mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) } func Test_Module_withdraw_CannotWithdraw(t *testing.T) { - target := setupModule() - expectedErr := primitives.NewDispatchErrorModule(primitives.CustomModuleError{ - Index: moduleId, - Err: sc.U32(ErrorLiquidityRestrictions), - Message: sc.NewOption[sc.Str](nil), - }) + target = setupModule() + + fromAccountData := &primitives.AccountData{ + Free: sc.NewU128(5), + } + value := sc.NewU128(3) frozenAccountInfo := primitives.AccountInfo{ Data: primitives.AccountData{ - MiscFrozen: sc.NewU128(10), - FeeFrozen: sc.NewU128(11), + Frozen: sc.NewU128(10), }, } + expectedErr := primitives.NewDispatchErrorModule(primitives.CustomModuleError{ + Index: moduleId, + Err: sc.U32(ErrorLiquidityRestrictions), + Message: sc.NewOption[sc.Str](nil), + }) - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - mockStoredMap.On("Get", fromAddressId).Return(frozenAccountInfo, nil) + mockStoredMap.On("Get", fromAddress).Return(frozenAccountInfo, nil) - _, err = target.withdraw(fromAddressId, value, fromAccountData, sc.U8(primitives.ReasonsFee), primitives.ExistenceRequirementKeepAlive) + _, err := target.withdraw(fromAddress, value, fromAccountData, sc.U8(primitives.ReasonsFee), primitives.ExistenceRequirementKeepAlive) assert.Equal(t, expectedErr, err) - mockStoredMap.AssertCalled(t, "Get", fromAddressId) assert.Equal(t, sc.NewU128(5), fromAccountData.Free) + mockStoredMap.AssertCalled(t, "Get", fromAddress) mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) } func Test_Module_deposit_Success(t *testing.T) { - target := setupModule() + target = setupModule() + toAccountData := &primitives.AccountData{ + Free: sc.NewU128(1), + } expectedResult := targetValue - toAddressId, err := toAddress.AsAccountId() - assert.Nil(t, err) - mockStoredMap.On("DepositEvent", newEventDeposit(moduleId, toAddressId, targetValue)) + mockStoredMap.On("DepositEvent", newEventDeposit(moduleId, toAddress, targetValue)) - result, err := target.deposit(toAddressId, toAccountData, false, targetValue) + result, err := target.deposit(toAddress, toAccountData, false, targetValue) assert.NoError(t, err) assert.Equal(t, expectedResult, result) assert.Equal(t, sc.NewU128(6), toAccountData.Free) - mockStoredMap.AssertCalled(t, "DepositEvent", newEventDeposit(moduleId, toAddressId, targetValue)) + mockStoredMap.AssertCalled(t, "DepositEvent", newEventDeposit(moduleId, toAddress, targetValue)) } func Test_Module_deposit_DeadAccount(t *testing.T) { - target := setupModule() + target = setupModule() + + toAccountData := &primitives.AccountData{ + Free: sc.NewU128(1), + } expectedErr := primitives.NewDispatchErrorModule(primitives.CustomModuleError{ Index: moduleId, Err: sc.U32(ErrorDeadAccount), Message: sc.NewOption[sc.Str](nil), }) - toAddressId, err := toAddress.AsAccountId() - assert.Nil(t, err) - - _, err = target.deposit(toAddressId, toAccountData, true, targetValue) + _, err := target.deposit(toAddress, toAccountData, true, targetValue) assert.Equal(t, expectedErr, err) assert.Equal(t, sc.NewU128(1), toAccountData.Free) @@ -522,331 +513,42 @@ func Test_Module_deposit_DeadAccount(t *testing.T) { } func Test_Module_deposit_ArithmeticOverflow(t *testing.T) { - target := setupModule() - expectedErr := primitives.NewDispatchErrorArithmetic(primitives.NewArithmeticErrorOverflow()) - toAccountData.Free = sc.MaxU128() + target = setupModule() - toAddressId, err := toAddress.AsAccountId() - assert.Nil(t, err) + toAccountData := &primitives.AccountData{ + Free: sc.MaxU128(), + } + expectedErr := primitives.NewDispatchErrorArithmetic(primitives.NewArithmeticErrorOverflow()) - _, err = target.deposit(toAddressId, toAccountData, false, targetValue) + _, err := target.deposit(toAddress, toAccountData, false, targetValue) assert.Equal(t, expectedErr, err) assert.Equal(t, sc.MaxU128(), toAccountData.Free) mockStoredMap.AssertNotCalled(t, "DepositEvent", mock.Anything) } -func Test_Module_Metadata(t *testing.T) { - target := setupModule() - - expectedBalancesCallsMetadataId := mdGenerator.GetLastAvailableIndex() + 1 - - expectedCompactU128TypeId := expectedBalancesCallsMetadataId + 1 - - expectMetadataTypes := sc.Sequence[primitives.MetadataType]{ - primitives.NewMetadataType(expectedCompactU128TypeId, "CompactU128", primitives.NewMetadataTypeDefinitionCompact(sc.ToCompact(metadata.PrimitiveTypesU128))), - primitives.NewMetadataTypeWithParams(expectedBalancesCallsMetadataId, "Balances calls", sc.Sequence[sc.Str]{"pallet_balances", "pallet", "Call"}, primitives.NewMetadataTypeDefinitionVariant( - sc.Sequence[primitives.MetadataDefinitionVariant]{ - primitives.NewMetadataDefinitionVariant( - "transfer", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionField(metadata.TypesMultiAddress), - primitives.NewMetadataTypeDefinitionField(expectedCompactU128TypeId), - }, - functionTransferIndex, - "Transfer some liquid free balance to another account."), - primitives.NewMetadataDefinitionVariant( - "set_balance", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionField(metadata.TypesMultiAddress), - primitives.NewMetadataTypeDefinitionField(expectedCompactU128TypeId), - primitives.NewMetadataTypeDefinitionField(expectedCompactU128TypeId), - }, - functionSetBalanceIndex, - "Set the balances of a given account."), - primitives.NewMetadataDefinitionVariant( - "force_transfer", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionField(metadata.TypesMultiAddress), - primitives.NewMetadataTypeDefinitionField(metadata.TypesMultiAddress), - primitives.NewMetadataTypeDefinitionField(expectedCompactU128TypeId), - }, - functionForceTransferIndex, - "Exactly as `transfer`, except the origin must be root and the source account may be specified."), - primitives.NewMetadataDefinitionVariant( - "transfer_keep_alive", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionField(metadata.TypesMultiAddress), - primitives.NewMetadataTypeDefinitionField(expectedCompactU128TypeId), - }, - functionTransferKeepAliveIndex, - "Same as the [`transfer`] call, but with a check that the transfer will not kill the origin account."), - primitives.NewMetadataDefinitionVariant( - "transfer_all", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionField(metadata.TypesMultiAddress), - primitives.NewMetadataTypeDefinitionField(metadata.PrimitiveTypesBool), - }, - functionTransferAllIndex, - "Transfer the entire transferable balance from the caller account."), - primitives.NewMetadataDefinitionVariant( - "force_free", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionField(metadata.TypesMultiAddress), - primitives.NewMetadataTypeDefinitionField(metadata.PrimitiveTypesU128), - }, - functionForceFreeIndex, - "Unreserve some balance from a user by force."), - }), - sc.Sequence[primitives.MetadataTypeParameter]{ - primitives.NewMetadataEmptyTypeParameter("T"), - primitives.NewMetadataEmptyTypeParameter("I"), - }), - - primitives.NewMetadataTypeWithPath(metadata.TypesBalancesEvent, "pallet_balances pallet Event", sc.Sequence[sc.Str]{"pallet_balances", "pallet", "Event"}, primitives.NewMetadataTypeDefinitionVariant( - sc.Sequence[primitives.MetadataDefinitionVariant]{ - primitives.NewMetadataDefinitionVariant( - "Endowed", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "account", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "free_balance", "T::Balance"), - }, - EventEndowed, - "Event.Endowed"), - primitives.NewMetadataDefinitionVariant( - "DustLost", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "account", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - }, - EventDustLost, - "Events.DustLost"), - primitives.NewMetadataDefinitionVariant( - "Transfer", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "from", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "to", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - }, - EventTransfer, - "Events.Transfer"), - primitives.NewMetadataDefinitionVariant( - "BalanceSet", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "free", "T::Balance"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "reserved", "T::Balance"), - }, - EventBalanceSet, - "Events.BalanceSet"), - primitives.NewMetadataDefinitionVariant( - "Reserved", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - }, - EventReserved, - "Events.Reserved"), - primitives.NewMetadataDefinitionVariant( - "Unreserved", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - }, - EventUnreserved, - "Events.Unreserved"), - primitives.NewMetadataDefinitionVariant( - "ReserveRepatriated", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "from", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "to", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesBalanceStatus, "destination_status", "Status"), - }, - EventReserveRepatriated, - "Events.ReserveRepatriated"), - primitives.NewMetadataDefinitionVariant( - "Deposit", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - }, - EventDeposit, - "Event.Deposit"), - primitives.NewMetadataDefinitionVariant( - "Withdraw", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - }, - EventWithdraw, - "Event.Withdraw"), - primitives.NewMetadataDefinitionVariant( - "Slashed", - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.TypesAddress32, "who", "T::AccountId"), - primitives.NewMetadataTypeDefinitionFieldWithNames(metadata.PrimitiveTypesU128, "amount", "T::Balance"), - }, - EventSlashed, - "Event.Slashed"), - }, - )), - primitives.NewMetadataTypeWithPath(metadata.TypesBalanceStatus, - "BalanceStatus", - sc.Sequence[sc.Str]{"frame_support", "traits", "tokens", "misc", "BalanceStatus"}, primitives.NewMetadataTypeDefinitionVariant( - sc.Sequence[primitives.MetadataDefinitionVariant]{ - primitives.NewMetadataDefinitionVariant( - "Free", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - types.BalanceStatusFree, - "BalanceStatus.Free"), - primitives.NewMetadataDefinitionVariant( - "Reserved", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - types.BalanceStatusReserved, - "BalanceStatus.Reserved"), - })), - - primitives.NewMetadataTypeWithParams(metadata.TypesBalancesErrors, - "pallet_balances pallet Error", - sc.Sequence[sc.Str]{"pallet_balances", "pallet", "Error"}, - primitives.NewMetadataTypeDefinitionVariant( - sc.Sequence[primitives.MetadataDefinitionVariant]{ - primitives.NewMetadataDefinitionVariant( - "VestingBalance", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorVestingBalance, - "Vesting balance too high to send value"), - primitives.NewMetadataDefinitionVariant( - "LiquidityRestrictions", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorLiquidityRestrictions, - "Account liquidity restrictions prevent withdrawal"), - primitives.NewMetadataDefinitionVariant( - "InsufficientBalance", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorInsufficientBalance, - "Balance too low to send value."), - primitives.NewMetadataDefinitionVariant( - "ExistentialDeposit", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorExistentialDeposit, - "Value too low to create account due to existential deposit"), - primitives.NewMetadataDefinitionVariant( - "KeepAlive", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorKeepAlive, - "Transfer/payment would kill account"), - primitives.NewMetadataDefinitionVariant( - "ExistingVestingSchedule", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorExistingVestingSchedule, - "A vesting schedule already exists for this account"), - primitives.NewMetadataDefinitionVariant( - "DeadAccount", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorDeadAccount, - "Beneficiary account must pre-exist"), - primitives.NewMetadataDefinitionVariant( - "TooManyReserves", - sc.Sequence[primitives.MetadataTypeDefinitionField]{}, - ErrorTooManyReserves, - "Number of named reserves exceed MaxReserves"), - }), - sc.Sequence[primitives.MetadataTypeParameter]{ - primitives.NewMetadataEmptyTypeParameter("T"), - primitives.NewMetadataEmptyTypeParameter("I"), - }), - } - moduleV14 := primitives.MetadataModuleV14{ - Name: name, - Storage: sc.NewOption[primitives.MetadataModuleStorage](primitives.MetadataModuleStorage{ - Prefix: name, - Items: sc.Sequence[primitives.MetadataModuleStorageEntry]{ - primitives.NewMetadataModuleStorageEntry( - "TotalIssuance", - primitives.MetadataModuleStorageEntryModifierDefault, - primitives.NewMetadataModuleStorageEntryDefinitionPlain(sc.ToCompact(metadata.PrimitiveTypesU128)), - "The total units issued in the system."), - }, - }), - Call: sc.NewOption[sc.Compact](sc.ToCompact(expectedBalancesCallsMetadataId)), - CallDef: sc.NewOption[primitives.MetadataDefinitionVariant]( - primitives.NewMetadataDefinitionVariantStr( - name, - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithName(expectedBalancesCallsMetadataId, "self::sp_api_hidden_includes_construct_runtime::hidden_include::dispatch\n::CallableCallFor"), - }, - moduleId, - "Call.Balances"), - ), - Event: sc.NewOption[sc.Compact](sc.ToCompact(metadata.TypesBalancesEvent)), - EventDef: sc.NewOption[primitives.MetadataDefinitionVariant]( - primitives.NewMetadataDefinitionVariantStr( - name, - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionFieldWithName(metadata.TypesBalancesEvent, "pallet_balances::Event"), - }, - moduleId, - "Events.Balances"), - ), - Constants: sc.Sequence[primitives.MetadataModuleConstant]{ - primitives.NewMetadataModuleConstant( - "ExistentialDeposit", - sc.ToCompact(metadata.PrimitiveTypesU128), - sc.BytesToSequenceU8(existentialDeposit.Bytes()), - "The minimum amount required to keep an account open. MUST BE GREATER THAN ZERO!", - ), - primitives.NewMetadataModuleConstant( - "MaxLocks", - sc.ToCompact(metadata.PrimitiveTypesU32), - sc.BytesToSequenceU8(maxLocks.Bytes()), - "The maximum number of locks that should exist on an account. Not strictly enforced, but used for weight estimation.", - ), - primitives.NewMetadataModuleConstant( - "MaxReserves", - sc.ToCompact(metadata.PrimitiveTypesU32), - sc.BytesToSequenceU8(maxReserves.Bytes()), - "The maximum number of named reserves that can exist on an account.", - ), - }, - Error: sc.NewOption[sc.Compact](sc.ToCompact(metadata.TypesBalancesErrors)), - ErrorDef: sc.NewOption[primitives.MetadataDefinitionVariant]( - primitives.NewMetadataDefinitionVariantStr( - name, - sc.Sequence[primitives.MetadataTypeDefinitionField]{ - primitives.NewMetadataTypeDefinitionField(metadata.TypesBalancesErrors), - }, - moduleId, - "Errors.Balances"), - ), - Index: moduleId, - } - - expectMetadataModule := primitives.MetadataModule{ - Version: primitives.ModuleVersion14, - ModuleV14: moduleV14, - } - - resultMetadataModule := target.Metadata() - resultTypes := mdGenerator.GetMetadataTypes() - - assert.Equal(t, expectMetadataTypes, resultTypes) - assert.Equal(t, expectMetadataModule, resultMetadataModule) -} - -func setupModule() Module { - mockStorage = new(mocks.IoStorage) - mockStoredMap = new(mocks.StoredMap) - config := NewConfig(mockStorage, dbWeight, maxLocks, maxReserves, existentialDeposit, mockStoredMap) - - fromAccountData = &primitives.AccountData{ - Free: sc.NewU128(5), - } - - toAccountData = &primitives.AccountData{ - Free: sc.NewU128(1), - } - - return New(moduleId, config, logger, mdGenerator) -} +// func Test_Module_updateAccount(t *testing.T) { +// expectedOldFree := sc.NewU128(1) +// expectedOldReserved := sc.NewU128(2) +// newFree := sc.NewU128(5) +// newReserved := sc.NewU128(6) + +// account := &primitives.AccountData{ +// Free: expectedOldFree, +// Reserved: expectedOldReserved, +// MiscFrozen: sc.NewU128(3), +// FeeFrozen: sc.NewU128(4), +// } +// expectAccount := &primitives.AccountData{ +// Free: newFree, +// Reserved: newReserved, +// MiscFrozen: sc.NewU128(3), +// FeeFrozen: sc.NewU128(4), +// } + +// updateAccount(account, newFree) + +// assert.Equal(t, expectedOldFree, oldFree) +// assert.Equal(t, expectedOldReserved, oldReserved) +// assert.Equal(t, expectAccount, account) +// } diff --git a/frame/balances/storage.go b/frame/balances/storage.go index b36b19c3..1248a11e 100644 --- a/frame/balances/storage.go +++ b/frame/balances/storage.go @@ -7,16 +7,19 @@ import ( ) var ( - keyBalances = []byte("Balances") - keyTotalIssuance = []byte("TotalIssuance") + keyBalances = []byte("Balances") + keyInactiveIssuance = []byte("InactiveIssuance") + keyTotalIssuance = []byte("TotalIssuance") ) type storage struct { - TotalIssuance support.StorageValue[sc.U128] + InactiveIssuance support.StorageValue[sc.U128] + TotalIssuance support.StorageValue[sc.U128] } func newStorage(s io.Storage) *storage { return &storage{ - TotalIssuance: support.NewHashStorageValue(s, keyBalances, keyTotalIssuance, sc.DecodeU128), + InactiveIssuance: support.NewHashStorageValue(s, keyBalances, keyInactiveIssuance, sc.DecodeU128), + TotalIssuance: support.NewHashStorageValue(s, keyBalances, keyTotalIssuance, sc.DecodeU128), } } diff --git a/frame/balances/types.go b/frame/balances/types.go index fd41fd01..a14e7446 100644 --- a/frame/balances/types.go +++ b/frame/balances/types.go @@ -1,19 +1,11 @@ package balances import ( - "bytes" - sc "github.com/LimeChain/goscale" "github.com/LimeChain/gosemble/frame/support" "github.com/LimeChain/gosemble/primitives/types" ) -type accountMutator interface { - ensureCanWithdraw(who types.AccountId, amount sc.U128, reasons types.Reasons, newBalance sc.U128) error - tryMutateAccountWithDust(who types.AccountId, f func(who *types.AccountData, bool bool) (sc.Encodable, error)) (sc.Encodable, error) - tryMutateAccount(who types.AccountId, f func(who *types.AccountData, bool bool) (sc.Encodable, error)) (sc.Encodable, error) -} - type negativeImbalance struct { types.Balance totalIssuance support.StorageValue[sc.U128] @@ -53,39 +45,3 @@ func (pi positiveImbalance) Drop() error { pi.totalIssuance.Put(add) return nil } - -type dustCleaner struct { - moduleIndex sc.U8 - accountId types.AccountId - negativeImbalance sc.Option[negativeImbalance] - eventDepositor types.EventDepositor -} - -func newDustCleaner(moduleId sc.U8, accountId types.AccountId, negativeImbalance sc.Option[negativeImbalance], eventDepositor types.EventDepositor) dustCleaner { - return dustCleaner{ - moduleIndex: moduleId, - accountId: accountId, - negativeImbalance: negativeImbalance, - eventDepositor: eventDepositor, - } -} - -func (dcv dustCleaner) Encode(buffer *bytes.Buffer) error { - return sc.EncodeEach(buffer, - dcv.accountId, - dcv.negativeImbalance, - ) -} - -func (dcv dustCleaner) Bytes() []byte { - return sc.EncodedBytes(dcv) -} - -func (dcv dustCleaner) Drop() error { - if dcv.negativeImbalance.HasValue { - dcv.eventDepositor.DepositEvent(newEventDustLost(dcv.moduleIndex, dcv.accountId, dcv.negativeImbalance.Value.Balance)) - return dcv.negativeImbalance.Value.Drop() - } - - return nil -} diff --git a/frame/balances/types/adjust_direction.go b/frame/balances/types/adjust_direction.go new file mode 100644 index 00000000..b44c8ebe --- /dev/null +++ b/frame/balances/types/adjust_direction.go @@ -0,0 +1,52 @@ +package types + +import ( + "bytes" + "errors" + + sc "github.com/LimeChain/goscale" +) + +const ( + AdjustDirectionIncrease sc.U8 = iota + AdjustDirectionDecrease +) + +type AdjustDirection struct { + sc.VaryingData +} + +var ( + errInvalidAdjustDirectionType = errors.New("invalid adjust direction type") +) + +func NewAdjustDirectionIncrease() AdjustDirection { + return AdjustDirection{sc.NewVaryingData(AdjustDirectionIncrease)} +} + +func NewAdjustDirectionDecrease() AdjustDirection { + return AdjustDirection{sc.NewVaryingData(AdjustDirectionDecrease)} +} + +func DecodeAdjustDirection(buffer *bytes.Buffer) (AdjustDirection, error) { + value, err := sc.DecodeU8(buffer) + if err != nil { + return AdjustDirection{}, err + } + switch value { + case AdjustDirectionIncrease: + return NewAdjustDirectionIncrease(), nil + case AdjustDirectionDecrease: + return NewAdjustDirectionDecrease(), nil + default: + return AdjustDirection{}, errInvalidAdjustDirectionType + } +} + +func (ad AdjustDirection) IsIncrease() bool { + return ad.VaryingData[0] == AdjustDirectionIncrease +} + +func (ad AdjustDirection) IsDecrease() bool { + return ad.VaryingData[0] == AdjustDirectionDecrease +} diff --git a/frame/balances/types/balance_status_test.go b/frame/balances/types/balance_status_test.go deleted file mode 100644 index a1198d36..00000000 --- a/frame/balances/types/balance_status_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package types - -import ( - "bytes" - "testing" - - sc "github.com/LimeChain/goscale" - "github.com/stretchr/testify/assert" -) - -func Test_DecodeBalanceStatus(t *testing.T) { - var testExamples = []struct { - label string - input []byte - expectation sc.U8 - }{ - { - label: "BalanceStatusFree", - input: []byte{0x00}, - expectation: BalanceStatusFree, - }, - { - label: "BalanceStatusReserved", - input: []byte{0x01}, - expectation: BalanceStatusReserved, - }, - } - - for _, testExample := range testExamples { - t.Run(testExample.label, func(t *testing.T) { - result, err := DecodeBalanceStatus(bytes.NewBuffer(testExample.input)) - assert.NoError(t, err) - - assert.Equal(t, testExample.expectation, result) - }) - } -} - -func Test_DecodeBalanceStatus_Error(t *testing.T) { - _, err := DecodeBalanceStatus(bytes.NewBuffer([]byte{0x02})) - assert.Equal(t, errInvalidBalanceStatusType, err) -} diff --git a/frame/balances/types/deposit_consequence.go b/frame/balances/types/deposit_consequence.go new file mode 100644 index 00000000..d9b0c5ac --- /dev/null +++ b/frame/balances/types/deposit_consequence.go @@ -0,0 +1,62 @@ +package types + +import ( + sc "github.com/LimeChain/goscale" + primitives "github.com/LimeChain/gosemble/primitives/types" +) + +type DepositConsequence struct { + sc.VaryingData +} + +const ( + DepositConsequenceBelowMinimum sc.U8 = iota + DepositConsequenceCannotCreate + DepositConsequenceUnknownAsset + DepositConsequenceOverflow + DepositConsequenceSuccess + DepositConsequenceBlocked +) + +func NewDepositConsequenceBelowMinimum() DepositConsequence { + return DepositConsequence{sc.NewVaryingData(DepositConsequenceBelowMinimum)} +} + +func NewDepositConsequenceCannotCreate() DepositConsequence { + return DepositConsequence{sc.NewVaryingData(DepositConsequenceCannotCreate)} +} + +func NewDepositConsequenceUnknownAsset() DepositConsequence { + return DepositConsequence{sc.NewVaryingData(DepositConsequenceUnknownAsset)} +} + +func NewDepositConsequenceOverflow() DepositConsequence { + return DepositConsequence{sc.NewVaryingData(DepositConsequenceOverflow)} +} + +func NewDepositConsequenceSuccess() DepositConsequence { + return DepositConsequence{sc.NewVaryingData(DepositConsequenceSuccess)} +} + +func NewDepositConsequenceBlocked() DepositConsequence { + return DepositConsequence{sc.NewVaryingData(DepositConsequenceBlocked)} +} + +func (wc DepositConsequence) IntoResult() error { + switch wc.VaryingData[0] { + case DepositConsequenceBelowMinimum: + return primitives.NewDispatchErrorToken(primitives.NewTokenErrorBelowMinimum()) + case DepositConsequenceCannotCreate: + return primitives.NewDispatchErrorToken(primitives.NewTokenErrorCannotCreate()) + case DepositConsequenceUnknownAsset: + return primitives.NewDispatchErrorToken(primitives.NewTokenErrorUnknownAsset()) + case DepositConsequenceOverflow: + return primitives.NewDispatchErrorArithmetic(primitives.NewArithmeticErrorOverflow()) + case DepositConsequenceBlocked: + return primitives.NewDispatchErrorToken(primitives.NewTokenErrorBlocked()) + case DepositConsequenceSuccess: + return nil + default: + return primitives.NewDispatchErrorOther("invalid DepositConsequence type") + } +} diff --git a/frame/balances/types/fortitude.go b/frame/balances/types/fortitude.go new file mode 100644 index 00000000..82394ec3 --- /dev/null +++ b/frame/balances/types/fortitude.go @@ -0,0 +1,10 @@ +package types + +import sc "github.com/LimeChain/goscale" + +type Fortitude sc.U8 + +const ( + FortitudePolite Fortitude = iota + FortitudeForce +) diff --git a/frame/balances/types/precision.go b/frame/balances/types/precision.go new file mode 100644 index 00000000..9066520c --- /dev/null +++ b/frame/balances/types/precision.go @@ -0,0 +1,10 @@ +package types + +import sc "github.com/LimeChain/goscale" + +type Precision sc.U8 + +const ( + PrecisionExact Precision = iota + PrecisionBestEffort +) diff --git a/frame/balances/types/preservation.go b/frame/balances/types/preservation.go new file mode 100644 index 00000000..5f4df908 --- /dev/null +++ b/frame/balances/types/preservation.go @@ -0,0 +1,11 @@ +package types + +import sc "github.com/LimeChain/goscale" + +type Preservation sc.U8 + +const ( + PreservationExpendable Preservation = iota + PreservationProtect + PreservationPreserve +) diff --git a/frame/balances/types/withdrawal_consequence.go b/frame/balances/types/withdrawal_consequence.go new file mode 100644 index 00000000..25edfc2e --- /dev/null +++ b/frame/balances/types/withdrawal_consequence.go @@ -0,0 +1,79 @@ +package types + +import ( + sc "github.com/LimeChain/goscale" + primitives "github.com/LimeChain/gosemble/primitives/types" +) + +type WithdrawalConsequence struct { + sc.VaryingData +} + +const ( + WithdrawalConsequenceBalanceLow sc.U8 = iota + WithdrawalConsequenceWouldDie + WithdrawalConsequenceUnknownAsset + WithdrawalConsequenceUnderflow + WithdrawalConsequenceOverflow + WithdrawalConsequenceFrozen + WithdrawalConsequenceReducedToZero + WithdrawalConsequenceSuccess +) + +func NewWithdrawalConsequenceBalanceLow() WithdrawalConsequence { + return WithdrawalConsequence{sc.NewVaryingData(WithdrawalConsequenceBalanceLow)} +} + +func NewWithdrawalConsequenceWouldDie() WithdrawalConsequence { + return WithdrawalConsequence{sc.NewVaryingData(WithdrawalConsequenceWouldDie)} +} + +func NewWithdrawalConsequenceUnknownAsset() WithdrawalConsequence { + return WithdrawalConsequence{sc.NewVaryingData(WithdrawalConsequenceUnknownAsset)} +} + +func NewWithdrawalConsequenceUnderflow() WithdrawalConsequence { + return WithdrawalConsequence{sc.NewVaryingData(WithdrawalConsequenceUnderflow)} +} + +func NewWithdrawalConsequenceOverflow() WithdrawalConsequence { + return WithdrawalConsequence{sc.NewVaryingData(WithdrawalConsequenceOverflow)} +} + +func NewWithdrawalConsequenceFrozen() WithdrawalConsequence { + return WithdrawalConsequence{sc.NewVaryingData(WithdrawalConsequenceFrozen)} +} + +func NewWithdrawalConsequenceReducedToZero(balance sc.U128) WithdrawalConsequence { + return WithdrawalConsequence{sc.NewVaryingData(WithdrawalConsequenceReducedToZero, balance)} +} + +func NewWithdrawalConsequenceSuccess() WithdrawalConsequence { + return WithdrawalConsequence{sc.NewVaryingData(WithdrawalConsequenceSuccess)} +} + +func (wc WithdrawalConsequence) IntoResult(keepNonZero bool) (sc.U128, error) { + switch wc.VaryingData[0] { + case WithdrawalConsequenceBalanceLow: + return sc.U128{}, primitives.NewDispatchErrorToken(primitives.NewTokenErrorFundsUnavailable()) + case WithdrawalConsequenceWouldDie: + return sc.U128{}, primitives.NewDispatchErrorToken(primitives.NewTokenErrorOnlyProvider()) + case WithdrawalConsequenceUnknownAsset: + return sc.U128{}, primitives.NewDispatchErrorToken(primitives.NewTokenErrorUnknownAsset()) + case WithdrawalConsequenceUnderflow: + return sc.U128{}, primitives.NewDispatchErrorArithmetic(primitives.NewArithmeticErrorUnderflow()) + case WithdrawalConsequenceOverflow: + return sc.U128{}, primitives.NewDispatchErrorArithmetic(primitives.NewArithmeticErrorOverflow()) + case WithdrawalConsequenceFrozen: + return sc.U128{}, primitives.NewDispatchErrorToken(primitives.NewTokenErrorFrozen()) + case WithdrawalConsequenceReducedToZero: + if keepNonZero { + return sc.U128{}, primitives.NewDispatchErrorToken(primitives.NewTokenErrorNotExpendable()) + } + return wc.VaryingData[1].(sc.U128), nil + case WithdrawalConsequenceSuccess: + return sc.U128{}, nil + default: + return sc.U128{}, primitives.NewDispatchErrorOther("invalid WithdrawalConsequence type") + } +} diff --git a/frame/balances/types_test.go b/frame/balances/types_test.go index 96e596bc..b9bb0fbf 100644 --- a/frame/balances/types_test.go +++ b/frame/balances/types_test.go @@ -1,30 +1,33 @@ package balances import ( - "bytes" "testing" sc "github.com/LimeChain/goscale" - "github.com/LimeChain/gosemble/constants" "github.com/LimeChain/gosemble/mocks" "github.com/stretchr/testify/assert" ) var ( - dustCleanerAccount = constants.ZeroAccountId - expectedDustCleaner = dustCleaner{ - accountId: dustCleanerAccount, - negativeImbalance: sc.NewOption[negativeImbalance](negativeImbalance{ - Balance: issuanceBalance, - }), - eventDepositor: nil, - } issuanceBalance = sc.NewU128(123) +) +var ( mockStorageTotalIssuance *mocks.StorageValue[sc.U128] - mockEventDepositor *mocks.EventDepositor ) +func setupNegativeImbalance() negativeImbalance { + mockStorageTotalIssuance = new(mocks.StorageValue[sc.U128]) + + return newNegativeImbalance(issuanceBalance, mockStorageTotalIssuance) +} + +func setupPositiveImbalance() positiveImbalance { + mockStorageTotalIssuance = new(mocks.StorageValue[sc.U128]) + + return newPositiveImbalance(issuanceBalance, mockStorageTotalIssuance) +} + func Test_NegativeImbalance_New(t *testing.T) { target := setupNegativeImbalance() @@ -33,6 +36,7 @@ func Test_NegativeImbalance_New(t *testing.T) { func Test_NegativeImbalance_Drop(t *testing.T) { target := setupNegativeImbalance() + mockStorageTotalIssuance.On("Get").Return(sc.NewU128(5), nil) mockStorageTotalIssuance.On("Put", sc.NewU128(0)).Return() @@ -50,6 +54,7 @@ func Test_PositiveImbalance_New(t *testing.T) { func Test_PositiveImbalance_Drop(t *testing.T) { target := setupPositiveImbalance() + mockStorageTotalIssuance.On("Get").Return(sc.NewU128(5), nil) mockStorageTotalIssuance.On("Put", sc.NewU128(128)).Return() @@ -58,63 +63,3 @@ func Test_PositiveImbalance_Drop(t *testing.T) { mockStorageTotalIssuance.AssertCalled(t, "Get") mockStorageTotalIssuance.AssertCalled(t, "Put", sc.NewU128(128)) } - -func Test_DustCleanerValue_New(t *testing.T) { - target := setupDustCleanerValue() - expected := dustCleaner{ - moduleIndex: moduleId, - accountId: constants.ZeroAccountId, - negativeImbalance: sc.NewOption[negativeImbalance](negativeImbalance{ - Balance: issuanceBalance, - totalIssuance: mockStorageTotalIssuance, - }), - eventDepositor: mockEventDepositor, - } - - assert.Equal(t, expected, target) -} - -func Test_DustCleanerValue_Encode(t *testing.T) { - target := setupDustCleanerValue() - buffer := &bytes.Buffer{} - - err := target.Encode(buffer) - - assert.NoError(t, err) - assert.Equal(t, expectedDustCleaner.Bytes(), buffer.Bytes()) -} - -func Test_DustCleanerValue_Bytes(t *testing.T) { - target := setupDustCleanerValue() - - assert.Equal(t, expectedDustCleaner.Bytes(), target.Bytes()) -} - -func Test_DustCleanerValue_Drop(t *testing.T) { - expectedEvent := newEventDustLost(moduleId, dustCleanerAccount, issuanceBalance) - target := setupDustCleanerValue() - mockEventDepositor.On("DepositEvent", expectedEvent).Return() - mockStorageTotalIssuance.On("Get").Return(sc.NewU128(5), nil) - mockStorageTotalIssuance.On("Put", sc.NewU128(0)) - - target.Drop() - - mockEventDepositor.AssertCalled(t, "DepositEvent", expectedEvent) - mockStorageTotalIssuance.AssertCalled(t, "Get") - mockStorageTotalIssuance.AssertCalled(t, "Put", sc.NewU128(0)) -} - -func setupNegativeImbalance() negativeImbalance { - mockStorageTotalIssuance = new(mocks.StorageValue[sc.U128]) - return newNegativeImbalance(issuanceBalance, mockStorageTotalIssuance) -} - -func setupPositiveImbalance() positiveImbalance { - mockStorageTotalIssuance = new(mocks.StorageValue[sc.U128]) - return newPositiveImbalance(issuanceBalance, mockStorageTotalIssuance) -} - -func setupDustCleanerValue() dustCleaner { - mockEventDepositor = new(mocks.EventDepositor) - return newDustCleaner(moduleId, dustCleanerAccount, sc.NewOption[negativeImbalance](setupNegativeImbalance()), mockEventDepositor) -} diff --git a/frame/grandpa/call_note_stalled_weight.go b/frame/grandpa/call_note_stalled_weight.go index ffa514b3..59bd9134 100644 --- a/frame/grandpa/call_note_stalled_weight.go +++ b/frame/grandpa/call_note_stalled_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-04-29 22:01:01.470495 +0300 EEST m=+1.966673542`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:15.272285 +0300 EEST m=+2.327889751`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 96100000, BaseReads: 0, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 96100, MinReads: 0, MinWrites: 1 +// BaseExtrinsicTime: 100150000, BaseReads: 0, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 100150, MinReads: 0, MinWrites: 1 package grandpa @@ -11,7 +11,7 @@ import ( ) func callNoteStalledWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(96100000, 0). + return primitives.WeightFromParts(100150000, 0). SaturatingAdd(dbWeight.Reads(0)). SaturatingAdd(dbWeight.Writes(1)) } diff --git a/frame/session/call_purge_keys_weight.go b/frame/session/call_purge_keys_weight.go index fcf846ae..8a5baf76 100644 --- a/frame/session/call_purge_keys_weight.go +++ b/frame/session/call_purge_keys_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-04-02 12:57:50.640013 +0300 EEST m=+0.280270126`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: ``, CPU: `Apple M2 Pro(10 cores, 3504 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:16.419 +0300 EEST m=+3.474602376`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 573750000, BaseReads: 1, BaseWrites: 2, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 573750, MinReads: 1, MinWrites: 2 +// BaseExtrinsicTime: 312900000, BaseReads: 1, BaseWrites: 2, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 312900, MinReads: 1, MinWrites: 2 package session @@ -11,7 +11,7 @@ import ( ) func callPurgeKeysWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(573750000, 0). + return primitives.WeightFromParts(312900000, 0). SaturatingAdd(dbWeight.Reads(1)). SaturatingAdd(dbWeight.Writes(2)) } diff --git a/frame/session/call_set_keys_weight.go b/frame/session/call_set_keys_weight.go index 032808d3..5283d8e6 100644 --- a/frame/session/call_set_keys_weight.go +++ b/frame/session/call_set_keys_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-04-02 12:57:39.567397 +0300 EEST m=+0.288732126`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: ``, CPU: `Apple M2 Pro(10 cores, 3504 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:16.659198 +0300 EEST m=+3.714800209`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 1095550000, BaseReads: 2, BaseWrites: 2, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 1095550, MinReads: 2, MinWrites: 2 +// BaseExtrinsicTime: 473850000, BaseReads: 2, BaseWrites: 2, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 473850, MinReads: 2, MinWrites: 2 package session @@ -11,7 +11,7 @@ import ( ) func callSetKeysWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(1095550000, 0). + return primitives.WeightFromParts(473850000, 0). SaturatingAdd(dbWeight.Reads(2)). SaturatingAdd(dbWeight.Writes(2)) } diff --git a/frame/sudo/call_remove_key_weight.go b/frame/sudo/call_remove_key_weight.go index 50d2a086..112ea2a4 100644 --- a/frame/sudo/call_remove_key_weight.go +++ b/frame/sudo/call_remove_key_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-04-10 12:57:43.946518 +0300 EEST m=+0.294647501`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: ``, CPU: `Apple M2 Pro(10 cores, 3504 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:17.606693 +0300 EEST m=+4.662293501`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 536700000, BaseReads: 1, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 536700, MinReads: 1, MinWrites: 1 +// BaseExtrinsicTime: 264650000, BaseReads: 1, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 264650, MinReads: 1, MinWrites: 1 package sudo @@ -11,7 +11,7 @@ import ( ) func callRemoveKeyWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(536700000, 0). + return primitives.WeightFromParts(264650000, 0). SaturatingAdd(dbWeight.Reads(1)). SaturatingAdd(dbWeight.Writes(1)) } diff --git a/frame/sudo/call_set_key_weight.go b/frame/sudo/call_set_key_weight.go index 7f28d4e5..d64b485d 100644 --- a/frame/sudo/call_set_key_weight.go +++ b/frame/sudo/call_set_key_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-04-10 12:57:01.945926 +0300 EEST m=+0.301102001`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: ``, CPU: `Apple M2 Pro(10 cores, 3504 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:16.897363 +0300 EEST m=+3.952964501`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 845850000, BaseReads: 1, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 845850, MinReads: 1, MinWrites: 1 +// BaseExtrinsicTime: 316200000, BaseReads: 1, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 316200, MinReads: 1, MinWrites: 1 package sudo @@ -11,7 +11,7 @@ import ( ) func callSetKeyWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(845850000, 0). + return primitives.WeightFromParts(316200000, 0). SaturatingAdd(dbWeight.Reads(1)). SaturatingAdd(dbWeight.Writes(1)) } diff --git a/frame/sudo/call_sudo_as_weight.go b/frame/sudo/call_sudo_as_weight.go index cb1a945c..c261e1a6 100644 --- a/frame/sudo/call_sudo_as_weight.go +++ b/frame/sudo/call_sudo_as_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-04-10 12:57:56.78372 +0300 EEST m=+0.309308584`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: ``, CPU: `Apple M2 Pro(10 cores, 3504 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:17.132353 +0300 EEST m=+4.187953917`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 519500000, BaseReads: 1, BaseWrites: 0, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 519500, MinReads: 1, MinWrites: 0 +// BaseExtrinsicTime: 269250000, BaseReads: 1, BaseWrites: 0, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 269250, MinReads: 1, MinWrites: 0 package sudo @@ -11,7 +11,7 @@ import ( ) func callSudoAsWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(519500000, 0). + return primitives.WeightFromParts(269250000, 0). SaturatingAdd(dbWeight.Reads(1)). SaturatingAdd(dbWeight.Writes(0)) } diff --git a/frame/sudo/call_sudo_weight.go b/frame/sudo/call_sudo_weight.go index dd17463b..9dec5594 100644 --- a/frame/sudo/call_sudo_weight.go +++ b/frame/sudo/call_sudo_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-04-10 12:57:47.616238 +0300 EEST m=+0.293206876`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: ``, CPU: `Apple M2 Pro(10 cores, 3504 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:17.372134 +0300 EEST m=+4.427734334`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 503800000, BaseReads: 1, BaseWrites: 0, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 503800, MinReads: 1, MinWrites: 0 +// BaseExtrinsicTime: 264900000, BaseReads: 1, BaseWrites: 0, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 264900, MinReads: 1, MinWrites: 0 package sudo @@ -11,7 +11,7 @@ import ( ) func callSudoWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(503800000, 0). + return primitives.WeightFromParts(264900000, 0). SaturatingAdd(dbWeight.Reads(1)). SaturatingAdd(dbWeight.Writes(0)) } diff --git a/frame/support/hash_storage_map.go b/frame/support/hash_storage_map.go index c45aff01..2e09725c 100644 --- a/frame/support/hash_storage_map.go +++ b/frame/support/hash_storage_map.go @@ -18,8 +18,12 @@ type HashStorageMap[K, V sc.Encodable] struct { } func NewHashStorageMap[K, V sc.Encodable](storage io.Storage, prefix []byte, name []byte, keyHashFunc func([]byte) []byte, decodeFunc func(buffer *bytes.Buffer) (V, error)) StorageMap[K, V] { + return NewHashStorageMapWithDefault[K, V](storage, prefix, name, keyHashFunc, decodeFunc, nil) +} + +func NewHashStorageMapWithDefault[K, V sc.Encodable](storage io.Storage, prefix []byte, name []byte, keyHashFunc func([]byte) []byte, decodeFunc func(buffer *bytes.Buffer) (V, error), defaultValue *V) StorageMap[K, V] { return HashStorageMap[K, V]{ - newBaseStorage[V](storage, decodeFunc, nil), + newBaseStorage[V](storage, decodeFunc, defaultValue), prefix, name, keyHashFunc, @@ -29,7 +33,7 @@ func NewHashStorageMap[K, V sc.Encodable](storage io.Storage, prefix []byte, nam } func (hsm HashStorageMap[K, V]) Get(k K) (V, error) { - return hsm.baseStorage.getDecode(hsm.key(k)) + return hsm.baseStorage.get(hsm.key(k)) } func (hsm HashStorageMap[K, V]) Exists(k K) bool { diff --git a/frame/system/call_apply_authorized_upgrade_weight.go b/frame/system/call_apply_authorized_upgrade_weight.go index e9a5176e..e8a78f7e 100644 --- a/frame/system/call_apply_authorized_upgrade_weight.go +++ b/frame/system/call_apply_authorized_upgrade_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:29:50.92382 +0200 EET m=+4.929834959`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:20.509067 +0300 EEST m=+7.564663334`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 107619400000, BaseReads: 2, BaseWrites: 3, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 107619400, MinReads: 2, MinWrites: 3 +// BaseExtrinsicTime: 116793550000, BaseReads: 2, BaseWrites: 3, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 116793550, MinReads: 2, MinWrites: 3 package system @@ -11,7 +11,7 @@ import ( ) func callApplyAuthorizedUpgradeWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(107619400000, 0). + return primitives.WeightFromParts(116793550000, 0). SaturatingAdd(dbWeight.Reads(2)). SaturatingAdd(dbWeight.Writes(3)) } diff --git a/frame/system/call_authorize_upgrade_weight.go b/frame/system/call_authorize_upgrade_weight.go index 1830b64c..a1045bcb 100644 --- a/frame/system/call_authorize_upgrade_weight.go +++ b/frame/system/call_authorize_upgrade_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:29:51.113442 +0200 EET m=+5.119458376`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:20.74655 +0300 EEST m=+7.802146251`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 225800000, BaseReads: 0, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 225800, MinReads: 0, MinWrites: 1 +// BaseExtrinsicTime: 208350000, BaseReads: 0, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 208350, MinReads: 0, MinWrites: 1 package system @@ -11,7 +11,7 @@ import ( ) func callAuthorizeUpgradeWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(225800000, 0). + return primitives.WeightFromParts(208350000, 0). SaturatingAdd(dbWeight.Reads(0)). SaturatingAdd(dbWeight.Writes(1)) } diff --git a/frame/system/call_authorize_upgrade_without_checks_weight.go b/frame/system/call_authorize_upgrade_without_checks_weight.go index 3d03796a..8f49b557 100644 --- a/frame/system/call_authorize_upgrade_without_checks_weight.go +++ b/frame/system/call_authorize_upgrade_without_checks_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:29:51.304115 +0200 EET m=+5.310132709`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:20.982069 +0300 EEST m=+8.037665292`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 212450000, BaseReads: 0, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 212450, MinReads: 0, MinWrites: 1 +// BaseExtrinsicTime: 208950000, BaseReads: 0, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 208950, MinReads: 0, MinWrites: 1 package system @@ -11,7 +11,7 @@ import ( ) func callAuthorizeUpgradeWithoutChecksWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(212450000, 0). + return primitives.WeightFromParts(208950000, 0). SaturatingAdd(dbWeight.Reads(0)). SaturatingAdd(dbWeight.Writes(1)) } diff --git a/frame/system/call_kill_prefix_weight.go b/frame/system/call_kill_prefix_weight.go index 691556ce..21d804ec 100644 --- a/frame/system/call_kill_prefix_weight.go +++ b/frame/system/call_kill_prefix_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-12 14:48:02.707458 +0200 EET m=+17.287341042`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:34.391686 +0300 EEST m=+21.447280042`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 143582293, BaseReads: 0, BaseWrites: 0, SlopesExtrinsicTime: [3480066], SlopesReads: [1], SlopesWrites: [1], MinExtrinsicTime: 103750, MinReads: 1, MinWrites: 1 +// BaseExtrinsicTime: 115594308, BaseReads: 0, BaseWrites: 0, SlopesExtrinsicTime: [3436991], SlopesReads: [1], SlopesWrites: [1], MinExtrinsicTime: 86950, MinReads: 1, MinWrites: 1 package system @@ -11,8 +11,8 @@ import (sc "github.com/LimeChain/goscale" ) func callKillPrefixWeight(dbWeight primitives.RuntimeDbWeight, size sc.U64) primitives.Weight { - return primitives.WeightFromParts(143582293, 0). - SaturatingAdd(primitives.WeightFromParts(3480066, 0).SaturatingMul(size)). + return primitives.WeightFromParts(115594308, 0). + SaturatingAdd(primitives.WeightFromParts(3436991, 0).SaturatingMul(size)). SaturatingAdd(dbWeight.Reads(0)). SaturatingAdd(dbWeight.Reads(1).SaturatingMul(size)). SaturatingAdd(dbWeight.Writes(0)). diff --git a/frame/system/call_kill_storage_weight.go b/frame/system/call_kill_storage_weight.go index 8d77ec48..9c27a6a9 100644 --- a/frame/system/call_kill_storage_weight.go +++ b/frame/system/call_kill_storage_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:30:16.88032 +0200 EET m=+30.886501876`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:03:50.630109 +0300 EEST m=+37.685715792`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 73285788, BaseReads: 0, BaseWrites: 0, SlopesExtrinsicTime: [8733462], SlopesReads: [0], SlopesWrites: [1], MinExtrinsicTime: 78100, MinReads: 0, MinWrites: 0 +// BaseExtrinsicTime: 0, BaseReads: 0, BaseWrites: 0, SlopesExtrinsicTime: [8137534], SlopesReads: [0], SlopesWrites: [1], MinExtrinsicTime: 79600, MinReads: 0, MinWrites: 0 package system @@ -13,7 +13,7 @@ import ( func callKillStorageWeight(dbWeight primitives.RuntimeDbWeight, size sc.U64) primitives.Weight { return primitives.WeightFromParts(73285788, 0). - SaturatingAdd(primitives.WeightFromParts(8733462, 0).SaturatingMul(size)). + SaturatingAdd(primitives.WeightFromParts(8137534, 0).SaturatingMul(size)). SaturatingAdd(dbWeight.Reads(0)). SaturatingAdd(dbWeight.Writes(0)). SaturatingAdd(dbWeight.Writes(1).SaturatingMul(size)) diff --git a/frame/system/call_remark_weight.go b/frame/system/call_remark_weight.go index abd37e9b..fe98a4a5 100644 --- a/frame/system/call_remark_weight.go +++ b/frame/system/call_remark_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:30:51.763287 +0200 EET m=+65.769693251`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:04:26.364946 +0300 EEST m=+73.420601751`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 68363334, BaseReads: 0, BaseWrites: 0, SlopesExtrinsicTime: [10], SlopesReads: [0], SlopesWrites: [0], MinExtrinsicTime: 76200, MinReads: 0, MinWrites: 0 +// BaseExtrinsicTime: 92589999, BaseReads: 0, BaseWrites: 0, SlopesExtrinsicTime: [0], SlopesReads: [0], SlopesWrites: [0], MinExtrinsicTime: 72200, MinReads: 0, MinWrites: 0 package system @@ -12,7 +12,7 @@ import ( ) func callRemarkWeight(dbWeight primitives.RuntimeDbWeight, size sc.U64) primitives.Weight { - return primitives.WeightFromParts(68363334, 0). + return primitives.WeightFromParts(92589999, 0). SaturatingAdd(primitives.WeightFromParts(10, 0).SaturatingMul(size)). SaturatingAdd(dbWeight.Reads(0)). SaturatingAdd(dbWeight.Writes(0)) diff --git a/frame/system/call_remark_with_event_weight.go b/frame/system/call_remark_with_event_weight.go index 091dd221..1a0d3170 100644 --- a/frame/system/call_remark_with_event_weight.go +++ b/frame/system/call_remark_with_event_weight.go @@ -1,19 +1,18 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:31:37.548875 +0200 EET m=+111.555576042`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:05:09.789194 +0300 EEST m=+116.844913751`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 1157040131, BaseReads: 0, BaseWrites: 0, SlopesExtrinsicTime: [4780], SlopesReads: [0], SlopesWrites: [0], MinExtrinsicTime: 200200, MinReads: 0, MinWrites: 0 +// BaseExtrinsicTime: 169868579, BaseReads: 0, BaseWrites: 0, SlopesExtrinsicTime: [3709], SlopesReads: [0], SlopesWrites: [0], MinExtrinsicTime: 204950, MinReads: 0, MinWrites: 0 package system -import ( - sc "github.com/LimeChain/goscale" +import (sc "github.com/LimeChain/goscale" primitives "github.com/LimeChain/gosemble/primitives/types" ) func callRemarkWithEventWeight(dbWeight primitives.RuntimeDbWeight, size sc.U64) primitives.Weight { - return primitives.WeightFromParts(1157040131, 0). - SaturatingAdd(primitives.WeightFromParts(4780, 0).SaturatingMul(size)). + return primitives.WeightFromParts(169868579, 0). + SaturatingAdd(primitives.WeightFromParts(3709, 0).SaturatingMul(size)). SaturatingAdd(dbWeight.Reads(0)). SaturatingAdd(dbWeight.Writes(0)) } diff --git a/frame/system/call_set_code_weight.go b/frame/system/call_set_code_weight.go index 9e284d7e..6a223562 100644 --- a/frame/system/call_set_code_weight.go +++ b/frame/system/call_set_code_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:31:39.820327 +0200 EET m=+113.827041959`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:05:12.320724 +0300 EEST m=+119.376447959`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 89003550000, BaseReads: 1, BaseWrites: 2, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 89003550, MinReads: 1, MinWrites: 2 +// BaseExtrinsicTime: 97109800000, BaseReads: 1, BaseWrites: 2, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 97109800, MinReads: 1, MinWrites: 2 package system @@ -11,7 +11,7 @@ import ( ) func callSetCodeWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(89003550000, 0). + return primitives.WeightFromParts(97109800000, 0). SaturatingAdd(dbWeight.Reads(1)). SaturatingAdd(dbWeight.Writes(2)) } diff --git a/frame/system/call_set_code_without_checks_weight.go b/frame/system/call_set_code_without_checks_weight.go index 1b573df0..a97dff5a 100644 --- a/frame/system/call_set_code_without_checks_weight.go +++ b/frame/system/call_set_code_without_checks_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:31:42.269941 +0200 EET m=+116.276671959`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:05:14.449622 +0300 EEST m=+121.505348834`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 29150650000, BaseReads: 1, BaseWrites: 2, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 29150650, MinReads: 1, MinWrites: 2 +// BaseExtrinsicTime: 17858650000, BaseReads: 1, BaseWrites: 2, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 17858650, MinReads: 1, MinWrites: 2 package system @@ -11,7 +11,7 @@ import ( ) func callSetCodeWithoutChecksWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(29150650000, 0). + return primitives.WeightFromParts(17858650000, 0). SaturatingAdd(dbWeight.Reads(1)). SaturatingAdd(dbWeight.Writes(2)) } diff --git a/frame/system/call_set_heap_pages_weight.go b/frame/system/call_set_heap_pages_weight.go index 325da104..3650ecc5 100644 --- a/frame/system/call_set_heap_pages_weight.go +++ b/frame/system/call_set_heap_pages_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:31:42.489809 +0200 EET m=+116.496541626`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:05:14.698223 +0300 EEST m=+121.753949751`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 152750000, BaseReads: 1, BaseWrites: 2, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 152750, MinReads: 1, MinWrites: 2 +// BaseExtrinsicTime: 108700000, BaseReads: 1, BaseWrites: 2, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 108700, MinReads: 1, MinWrites: 2 package system @@ -11,7 +11,7 @@ import ( ) func callSetHeapPagesWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(152750000, 0). + return primitives.WeightFromParts(108700000, 0). SaturatingAdd(dbWeight.Reads(1)). SaturatingAdd(dbWeight.Writes(2)) } diff --git a/frame/system/call_set_storage_weight.go b/frame/system/call_set_storage_weight.go index 51fd3f5a..82a5ef43 100644 --- a/frame/system/call_set_storage_weight.go +++ b/frame/system/call_set_storage_weight.go @@ -1,20 +1,19 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:31:56.904116 +0200 EET m=+130.910941001`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:05:30.644281 +0300 EEST m=+137.700031542`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 14944233, BaseReads: 0, BaseWrites: 0, SlopesExtrinsicTime: [7674802], SlopesReads: [0], SlopesWrites: [1], MinExtrinsicTime: 76550, MinReads: 0, MinWrites: 0 +// BaseExtrinsicTime: 0, BaseReads: 0, BaseWrites: 0, SlopesExtrinsicTime: [7367302], SlopesReads: [0], SlopesWrites: [1], MinExtrinsicTime: 76200, MinReads: 0, MinWrites: 0 package system -import ( - sc "github.com/LimeChain/goscale" +import (sc "github.com/LimeChain/goscale" primitives "github.com/LimeChain/gosemble/primitives/types" ) func callSetStorageWeight(dbWeight primitives.RuntimeDbWeight, size sc.U64) primitives.Weight { - return primitives.WeightFromParts(14944233, 0). - SaturatingAdd(primitives.WeightFromParts(7674802, 0).SaturatingMul(size)). + return primitives.WeightFromParts(0, 0). + SaturatingAdd(primitives.WeightFromParts(7367302, 0).SaturatingMul(size)). SaturatingAdd(dbWeight.Reads(0)). SaturatingAdd(dbWeight.Writes(0)). - SaturatingAdd(dbWeight.Writes(1).SaturatingMul(size)) + SaturatingAdd(dbWeight.Writes(1).SaturatingMul(size)) } diff --git a/frame/system/module.go b/frame/system/module.go index 6f1b2197..033f1e91 100644 --- a/frame/system/module.go +++ b/frame/system/module.go @@ -54,9 +54,11 @@ type Module interface { CanDecProviders(who primitives.AccountId) (bool, error) CanIncConsumer(who primitives.AccountId) (bool, error) DecConsumers(who primitives.AccountId) error + DecProviders(who primitives.AccountId) (primitives.DecRefStatus, error) IncConsumers(who primitives.AccountId) error IncConsumersWithoutLimit(who primitives.AccountId) error IncProviders(who primitives.AccountId) (primitives.IncRefStatus, error) + Insert(who primitives.AccountId, data primitives.AccountData) (sc.Encodable, error) UpdateCodeInStorage(code sc.Sequence[sc.U8]) TryMutateExists(who primitives.AccountId, f func(who *primitives.AccountData) (sc.Encodable, error)) (sc.Encodable, error) @@ -479,13 +481,11 @@ func (m module) TryMutateExists(who primitives.AccountId, f func(*primitives.Acc if err != nil { return nil, err } - wasProviding := false - if !reflect.DeepEqual(account.Data, primitives.AccountData{}) { - wasProviding = true - } - someData := &primitives.AccountData{} - if wasProviding { + defaultData := primitives.DefaultAccountData() + isDefault := reflect.DeepEqual(account.Data, defaultData) + someData := &defaultData + if !isDefault { someData = &account.Data } @@ -494,31 +494,21 @@ func (m module) TryMutateExists(who primitives.AccountId, f func(*primitives.Acc return result, err } - isProviding := !reflect.DeepEqual(*someData, primitives.AccountData{}) + latest, err := m.Get(who) + if err != nil { + return nil, err + } - if !wasProviding && isProviding { - _, err := m.IncProviders(who) - if err != nil { - return nil, err - } - } else if wasProviding && !isProviding { - status, err := m.decProviders(who) + if latest.Providers > 0 || latest.Sufficients > 0 { + _, err = m.storage.Account.Mutate(who, func(a *primitives.AccountInfo) (sc.Encodable, error) { + mutateAccount(a, someData) + return nil, nil + }) if err != nil { - return nil, err - } - if status == primitives.DecRefStatusExists { - return result, nil + return nil, nil } - } else if !wasProviding && !isProviding { - return result, nil - } - - _, err = m.storage.Account.Mutate(who, func(a *primitives.AccountInfo) (sc.Encodable, error) { - mutateAccount(a, someData) - return nil, nil - }) - if err != nil { - return nil, err + } else { + m.storage.Account.Remove(who) } return result, nil @@ -589,6 +579,20 @@ func (m module) IncProviders(who primitives.AccountId) (primitives.IncRefStatus, return result.(primitives.IncRefStatus), err } +func (m module) Insert(who primitives.AccountId, data primitives.AccountData) (sc.Encodable, error) { + return m.TryMutateExists(who, func(a *primitives.AccountData) (sc.Encodable, error) { + updateAccount(a, data) + return nil, nil + }) +} + +func updateAccount(account *types.AccountData, data primitives.AccountData) { + account.Free = data.Free + account.Reserved = data.Reserved + account.Frozen = data.Frozen + account.Flags = data.Flags +} + // UpdateCodeInStorage writes code to the storage and emit related events and digest items. // // Note this function almost never should be used directly. It is exposed @@ -641,7 +645,7 @@ func (m module) incrementProviders(who primitives.AccountId, account *primitives } } -func (m module) decProviders(who primitives.AccountId) (primitives.DecRefStatus, error) { +func (m module) DecProviders(who primitives.AccountId) (primitives.DecRefStatus, error) { result, err := m.storage.Account.TryMutateExists(who, func(maybeAccount *sc.Option[primitives.AccountInfo]) (sc.Encodable, error) { return m.decrementProviders(who, maybeAccount) }) @@ -1098,7 +1102,7 @@ func mutateAccount(account *primitives.AccountInfo, data *primitives.AccountData if data != nil { account.Data = *data } else { - account.Data = primitives.AccountData{} + account.Data = primitives.DefaultAccountData() } } diff --git a/frame/system/module_test.go b/frame/system/module_test.go index 9ca57f50..9a7f2af8 100644 --- a/frame/system/module_test.go +++ b/frame/system/module_test.go @@ -33,10 +33,10 @@ var ( Providers: 3, Sufficients: 4, Data: primitives.AccountData{ - Free: sc.NewU128(5), - Reserved: sc.NewU128(6), - MiscFrozen: sc.NewU128(7), - FeeFrozen: sc.NewU128(8), + Free: sc.NewU128(5), + Reserved: sc.NewU128(6), + Frozen: sc.NewU128(7), + Flags: primitives.ExtraFlags{sc.NewU128(8)}, }, } blockHashCount = sc.U64(5) @@ -812,6 +812,7 @@ func Test_Module_TryMutateExists_NoProviding(t *testing.T) { } mockStorageAccount.On("Get", targetAccountId).Return(accountInfo, nil) + mockStorageAccount.On("Remove", targetAccountId).Return(nil) result, err := target.TryMutateExists(targetAccountId, f) assert.Nil(t, err) @@ -819,157 +820,8 @@ func Test_Module_TryMutateExists_NoProviding(t *testing.T) { assert.Equal(t, expectedResult, result) mockStorageAccount.AssertCalled(t, "Get", targetAccountId) - mockStorageAccount.AssertNotCalled(t, - "Mutate", - targetAccountId, - mockTypeMutateAccountInfo) -} - -func Test_Module_TryMutateExists_WasProviding_NoLongerProviding_DecRefStatus_Success(t *testing.T) { - target := setupModule() - expectedResult := sc.NewU128(5) - - accountInfo := primitives.AccountInfo{ - Data: primitives.AccountData{ - Free: sc.NewU128(1), - }, - } - f := func(account *primitives.AccountData) (sc.Encodable, error) { - account.Free = primitives.Balance{} - return expectedResult, nil - } - - mockStorageAccount.On("Get", targetAccountId).Return(accountInfo, nil) - mockStorageAccount. - On( - "TryMutateExists", - targetAccountId, - mockTypeMutateOptionAccountInfo). - Return(primitives.DecRefStatusExists, nil) - - result, err := target.TryMutateExists(targetAccountId, f) - assert.Nil(t, err) - - assert.Equal(t, expectedResult, result) - - mockStorageAccount.AssertCalled(t, "Get", targetAccountId) - mockStorageAccount. - AssertCalled(t, - "TryMutateExists", - targetAccountId, - mockTypeMutateOptionAccountInfo) - mockStorageAccount.AssertNotCalled(t, - "Mutate", - targetAccountId, - mockTypeMutateAccountInfo) -} - -func Test_Module_TryMutateExists_WasProviding_NoLongerProviding_Error(t *testing.T) { - target := setupModule() - expectedErr := primitives.NewDispatchErrorCannotLookup() - - accountInfo := primitives.AccountInfo{ - Data: primitives.AccountData{ - Free: sc.NewU128(1), - }, - } - f := func(account *primitives.AccountData) (sc.Encodable, error) { - account.Free = primitives.Balance{} - return sc.Empty{}, nil - } - - mockStorageAccount.On("Get", targetAccountId).Return(accountInfo, nil) - mockStorageAccount. - On( - "TryMutateExists", - targetAccountId, - mockTypeMutateOptionAccountInfo). - Return(sc.Empty{}, expectedErr) - - _, err := target.TryMutateExists(targetAccountId, f) - - assert.Equal(t, expectedErr, err) - - mockStorageAccount.AssertCalled(t, "Get", targetAccountId) - mockStorageAccount. - AssertCalled(t, - "TryMutateExists", - targetAccountId, - mockTypeMutateOptionAccountInfo) - mockStorageAccount.AssertNotCalled(t, - "Mutate", - targetAccountId, - mockTypeMutateAccountInfo) -} - -func Test_Module_TryMutateExists_WasNotProviding_IsProviding(t *testing.T) { - target := setupModule() - - expectedResult := sc.NewU128(5) - accountInfo := primitives.AccountInfo{ - Data: primitives.AccountData{}, - } - f := func(account *primitives.AccountData) (sc.Encodable, error) { - account.Free = sc.NewU128(5) - return expectedResult, nil - } - - mockStorageAccount.On("Get", targetAccountId).Return(accountInfo, nil) - mockStorageAccount.On( - "Mutate", - targetAccountId, - mockTypeMutateAccountInfo). - Return(primitives.IncRefStatusExisted, nil).Once() - mockStorageAccount.On( - "Mutate", - targetAccountId, - mockTypeMutateAccountInfo). - Return(sc.NewU128(2), nil).Once() - - result, err := target.TryMutateExists(targetAccountId, f) - assert.Nil(t, err) - - assert.Equal(t, expectedResult, result) - - mockStorageAccount.AssertCalled(t, "Get", targetAccountId) - mockStorageAccount.AssertNumberOfCalls(t, "Mutate", 2) - mockStorageAccount.AssertCalled(t, - "Mutate", - targetAccountId, - mockTypeMutateAccountInfo) -} - -func Test_Module_TryMutateExists_WasProviding_IsProviding_Success(t *testing.T) { - target := setupModule() - - expectedResult := sc.NewU128(5) - accountInfo := primitives.AccountInfo{ - Data: primitives.AccountData{ - Free: sc.NewU128(1), - }, - } - f := func(*primitives.AccountData) (sc.Encodable, error) { - return expectedResult, nil - } - - mockStorageAccount.On("Get", targetAccountId).Return(accountInfo, nil) - mockStorageAccount.On( - "Mutate", - targetAccountId, - mockTypeMutateAccountInfo). - Return(sc.Empty{}, nil) - - result, err := target.TryMutateExists(targetAccountId, f) - assert.Nil(t, err) - - assert.Equal(t, expectedResult, result) - - mockStorageAccount.AssertCalled(t, "Get", targetAccountId) - mockStorageAccount.AssertNumberOfCalls(t, "Mutate", 1) - mockStorageAccount.AssertCalled(t, - "Mutate", - targetAccountId, - mockTypeMutateAccountInfo) + mockStorageAccount.AssertCalled(t, "Remove", targetAccountId) + mockStorageAccount.AssertNotCalled(t, "Mutate", targetAccountId, mockTypeMutateAccountInfo) } func Test_Module_TryMutateExists_GetAccount_Error(t *testing.T) { @@ -993,71 +845,6 @@ func Test_Module_TryMutateExists_GetAccount_Error(t *testing.T) { mockTypeMutateAccountInfo) } -func Test_Module_TryMutateExists_incProviders_Error(t *testing.T) { - target := setupModule() - - expectedErr := errors.New("err") - expectedResult := sc.NewU128(5) - accountInfo := primitives.AccountInfo{ - Data: primitives.AccountData{}, - } - f := func(account *primitives.AccountData) (sc.Encodable, error) { - account.Free = sc.NewU128(5) - return expectedResult, nil - } - - mockStorageAccount.On("Get", targetAccountId).Return(accountInfo, nil) - mockStorageAccount.On( - "Mutate", - targetAccountId, - mockTypeMutateAccountInfo). - Return(primitives.IncRefStatusExisted, expectedErr) - - _, err := target.TryMutateExists(targetAccountId, f) - - assert.Equal(t, expectedErr, err) - - mockStorageAccount.AssertCalled(t, "Get", targetAccountId) - mockStorageAccount.AssertCalled(t, "Mutate", targetAccountId, mockTypeMutateAccountInfo) -} - -func Test_Module_TryMutateExists_AccountMutate_Error(t *testing.T) { - target := setupModule() - - expectedErr := errors.New("err") - expectedResult := sc.NewU128(5) - accountInfo := primitives.AccountInfo{ - Data: primitives.AccountData{}, - } - f := func(account *primitives.AccountData) (sc.Encodable, error) { - account.Free = sc.NewU128(5) - return expectedResult, nil - } - - mockStorageAccount.On("Get", targetAccountId).Return(accountInfo, nil) - mockStorageAccount.On( - "Mutate", - targetAccountId, - mockTypeMutateAccountInfo). - Return(primitives.IncRefStatusExisted, nil).Once() - mockStorageAccount.On( - "Mutate", - targetAccountId, - mockTypeMutateAccountInfo). - Return(sc.NewU128(2), expectedErr).Once() - - _, err := target.TryMutateExists(targetAccountId, f) - - assert.Equal(t, expectedErr, err) - - mockStorageAccount.AssertCalled(t, "Get", targetAccountId) - mockStorageAccount.AssertNumberOfCalls(t, "Mutate", 2) - mockStorageAccount.AssertCalled(t, - "Mutate", - targetAccountId, - mockTypeMutateAccountInfo) -} - func Test_Module_CanIncConsumer_True(t *testing.T) { target := setupModule() @@ -1380,17 +1167,17 @@ func Test_Module_mutateAccount(t *testing.T) { Providers: 3, Sufficients: 4, Data: primitives.AccountData{ - Free: sc.NewU128(1), - Reserved: sc.NewU128(2), - MiscFrozen: sc.NewU128(3), - FeeFrozen: sc.NewU128(4), + Free: sc.NewU128(1), + Reserved: sc.NewU128(2), + Frozen: sc.NewU128(3), + Flags: primitives.ExtraFlags{sc.NewU128(4)}, }, } accountData := primitives.AccountData{ - Free: sc.NewU128(5), - Reserved: sc.NewU128(6), - MiscFrozen: sc.NewU128(7), - FeeFrozen: sc.NewU128(8), + Free: sc.NewU128(5), + Reserved: sc.NewU128(6), + Frozen: sc.NewU128(7), + Flags: primitives.ExtraFlags{sc.NewU128(8)}, } expectAccountInfo := &primitives.AccountInfo{ Nonce: 1, @@ -1418,10 +1205,10 @@ func Test_Module_mutateAccount_NilData(t *testing.T) { Providers: 3, Sufficients: 4, Data: primitives.AccountData{ - Free: sc.NewU128(1), - Reserved: sc.NewU128(2), - MiscFrozen: sc.NewU128(3), - FeeFrozen: sc.NewU128(4), + Free: sc.NewU128(1), + Reserved: sc.NewU128(2), + Frozen: sc.NewU128(3), + Flags: primitives.ExtraFlags{sc.NewU128(4)}, }, } expectAccountInfo := &primitives.AccountInfo{ @@ -1429,7 +1216,9 @@ func Test_Module_mutateAccount_NilData(t *testing.T) { Consumers: 2, Providers: 3, Sufficients: 4, - Data: primitives.AccountData{}, + Data: primitives.AccountData{ + Flags: primitives.DefaultExtraFlags, + }, } mutateAccount(accountInfo, nil) diff --git a/frame/system/storage.go b/frame/system/storage.go index f8604003..caec3d0c 100644 --- a/frame/system/storage.go +++ b/frame/system/storage.go @@ -54,9 +54,10 @@ type storage struct { func newStorage(s io.Storage) *storage { hashing := io.NewHashing() + defaultAccountInfo := types.DefaultAccountInfo() return &storage{ - Account: support.NewHashStorageMap[types.AccountId](s, keySystem, keyAccount, hashing.Blake128, types.DecodeAccountInfo), + Account: support.NewHashStorageMapWithDefault[types.AccountId](s, keySystem, keyAccount, hashing.Blake128, types.DecodeAccountInfo, &defaultAccountInfo), BlockWeight: support.NewHashStorageValue(s, keySystem, keyBlockWeight, types.DecodeConsumedWeight), BlockHash: support.NewHashStorageMap[sc.U64, types.Blake2bHash](s, keySystem, keyBlockHash, hashing.Twox64, types.DecodeBlake2bHash), BlockNumber: support.NewHashStorageValue(s, keySystem, keyNumber, sc.DecodeU64), diff --git a/frame/timestamp/call_set_weight.go b/frame/timestamp/call_set_weight.go index a7077ff0..51ab3ba7 100644 --- a/frame/timestamp/call_set_weight.go +++ b/frame/timestamp/call_set_weight.go @@ -1,8 +1,8 @@ // THIS FILE WAS GENERATED USING GOSEMBLE BENCHMARKING PACKAGE -// DATE: `2024-03-11 12:31:57.118419 +0200 EET m=+131.125246042`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` +// DATE: `2024-06-12 10:05:30.902314 +0300 EEST m=+137.958065292`, STEPS: `50`, REPEAT: `20`, DBCACHE: `1024`, HEAPPAGES: `4096`, HOSTNAME: `Rados-MBP.lan`, CPU: `Apple M1 Pro(8 cores, 3228 mhz)`, GC: ``, TINYGO VERSION: ``, TARGET: `` // Summary: -// BaseExtrinsicTime: 151600000, BaseReads: 2, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 151600, MinReads: 2, MinWrites: 1 +// BaseExtrinsicTime: 144650000, BaseReads: 2, BaseWrites: 1, SlopesExtrinsicTime: [], SlopesReads: [], SlopesWrites: [], MinExtrinsicTime: 144650, MinReads: 2, MinWrites: 1 package timestamp @@ -11,7 +11,7 @@ import ( ) func callSetWeight(dbWeight primitives.RuntimeDbWeight) primitives.Weight { - return primitives.WeightFromParts(151600000, 0). + return primitives.WeightFromParts(144650000, 0). SaturatingAdd(dbWeight.Reads(2)). SaturatingAdd(dbWeight.Writes(1)) } diff --git a/mocks/stored_map.go b/mocks/stored_map.go index cf4ca73b..0f3600c9 100644 --- a/mocks/stored_map.go +++ b/mocks/stored_map.go @@ -48,10 +48,41 @@ func (m *StoredMap) TryMutateExists(who types.AccountId, f func(who *types.Accou return args.Get(0).(sc.Encodable), args.Get(1).(error) } -func (m *StoredMap) incProviders(who types.AccountId) (types.IncRefStatus, error) { +func (m *StoredMap) DecConsumers(who types.AccountId) error { + args := m.Called(who) + return args.Get(0).(error) +} + +func (m *StoredMap) DecProviders(who types.AccountId) (types.DecRefStatus, error) { + args := m.Called(who) + if args.Get(1) == nil { + return args.Get(0).(types.DecRefStatus), nil + } + return args.Get(0).(types.DecRefStatus), args.Get(1).(error) +} + +func (m *StoredMap) IncConsumers(who types.AccountId) error { + args := m.Called(who) + return args.Get(0).(error) +} + +func (m *StoredMap) IncConsumersWithoutLimit(who types.AccountId) error { + args := m.Called(who) + return args.Get(0).(error) +} + +func (m *StoredMap) IncProviders(who types.AccountId) (types.IncRefStatus, error) { args := m.Called(who) if args.Get(1) == nil { return args.Get(0).(types.IncRefStatus), nil } return args.Get(0).(types.IncRefStatus), args.Get(1).(error) } + +func (m *StoredMap) Insert(who types.AccountId, data types.AccountData) (sc.Encodable, error) { + args := m.Called(who, data) + if args.Get(1) == nil { + return args.Get(0).(sc.Encodable), nil + } + return args.Get(0).(sc.Encodable), args.Get(1).(error) +} diff --git a/mocks/system.go b/mocks/system.go index f58c2a8b..14d3943f 100644 --- a/mocks/system.go +++ b/mocks/system.go @@ -202,6 +202,15 @@ func (m *SystemModule) DecConsumers(who primitives.AccountId) error { return args[0].(error) } +func (m *SystemModule) DecProviders(who primitives.AccountId) (primitives.DecRefStatus, error) { + args := m.Called(who) + if args[1] == nil { + return args[0].(primitives.DecRefStatus), nil + } + + return args[0].(primitives.DecRefStatus), args[1].(error) +} + func (m *SystemModule) IncConsumers(who primitives.AccountId) error { args := m.Called(who) if args[0] == nil { @@ -229,6 +238,15 @@ func (m *SystemModule) IncProviders(who primitives.AccountId) (primitives.IncRef return args[0].(primitives.IncRefStatus), args[1].(error) } +func (m *SystemModule) Insert(who primitives.AccountId, data primitives.AccountData) (sc.Encodable, error) { + args := m.Called(who, data) + if args.Get(1) == nil { + return args.Get(0).(sc.Encodable), nil + } + + return args.Get(0).(sc.Encodable), args.Get(1).(error) +} + func (m *SystemModule) UpdateCodeInStorage(code sc.Sequence[sc.U8]) { m.Called(code) } diff --git a/primitives/types/account_data.go b/primitives/types/account_data.go index 514cc543..094506a5 100644 --- a/primitives/types/account_data.go +++ b/primitives/types/account_data.go @@ -2,25 +2,33 @@ package types import ( "bytes" - sc "github.com/LimeChain/goscale" ) type Balance = sc.U128 +func DefaultAccountData() AccountData { + return AccountData{ + Free: Balance{}, + Reserved: Balance{}, + Frozen: Balance{}, + Flags: DefaultExtraFlags, + } +} + type AccountData struct { - Free Balance - Reserved Balance - MiscFrozen Balance - FeeFrozen Balance + Free Balance + Reserved Balance + Frozen Balance + Flags ExtraFlags } func (ad AccountData) Encode(buffer *bytes.Buffer) error { return sc.EncodeEach(buffer, ad.Free, ad.Reserved, - ad.MiscFrozen, - ad.FeeFrozen, + ad.Frozen, + ad.Flags, ) } @@ -37,22 +45,22 @@ func DecodeAccountData(buffer *bytes.Buffer) (AccountData, error) { if err != nil { return AccountData{}, err } - misc, err := sc.DecodeU128(buffer) + frozen, err := sc.DecodeU128(buffer) if err != nil { return AccountData{}, err } - fee, err := sc.DecodeU128(buffer) + flags, err := sc.DecodeU128(buffer) if err != nil { return AccountData{}, err } return AccountData{ - Free: free, - Reserved: reserved, - MiscFrozen: misc, - FeeFrozen: fee, + Free: free, + Reserved: reserved, + Frozen: frozen, + Flags: ExtraFlags{flags}, }, nil } func (ad AccountData) Total() sc.U128 { - return ad.Free.Add(ad.Reserved) + return sc.SaturatingAddU128(ad.Free, ad.Reserved) } diff --git a/primitives/types/account_data_test.go b/primitives/types/account_data_test.go index 1b856101..71983afd 100644 --- a/primitives/types/account_data_test.go +++ b/primitives/types/account_data_test.go @@ -18,10 +18,10 @@ var ( var ( targetAccountData = AccountData{ - Free: sc.NewU128(1), - Reserved: sc.NewU128(2), - MiscFrozen: sc.NewU128(3), - FeeFrozen: sc.NewU128(4), + Free: sc.NewU128(1), + Reserved: sc.NewU128(2), + Frozen: sc.NewU128(3), + Flags: ExtraFlags{sc.NewU128(4)}, } ) diff --git a/primitives/types/account_info.go b/primitives/types/account_info.go index 2b9c1f2d..1f5185f9 100644 --- a/primitives/types/account_info.go +++ b/primitives/types/account_info.go @@ -8,6 +8,14 @@ import ( type RefCount = sc.U32 +func DefaultAccountInfo() AccountInfo { + return AccountInfo{ + Data: AccountData{ + Flags: DefaultExtraFlags, + }, + } +} + type AccountInfo struct { Nonce AccountIndex Consumers RefCount @@ -59,19 +67,3 @@ func DecodeAccountInfo(buffer *bytes.Buffer) (AccountInfo, error) { Data: data, }, nil } - -func (ai AccountInfo) Frozen(reasons Reasons) sc.U128 { - switch reasons { - case ReasonsAll: - if ai.Data.MiscFrozen.Gt(ai.Data.FeeFrozen) { - return ai.Data.MiscFrozen - } - return ai.Data.FeeFrozen - case ReasonsMisc: - return ai.Data.MiscFrozen - case ReasonsFee: - return ai.Data.MiscFrozen - } - - return sc.NewU128(0) -} diff --git a/primitives/types/account_info_test.go b/primitives/types/account_info_test.go index b08caebf..b5fcfeac 100644 --- a/primitives/types/account_info_test.go +++ b/primitives/types/account_info_test.go @@ -22,10 +22,10 @@ var ( Providers: RefCount(3), Sufficients: RefCount(4), Data: AccountData{ - Free: sc.NewU128(5), - Reserved: sc.NewU128(6), - MiscFrozen: sc.NewU128(7), - FeeFrozen: sc.NewU128(8), + Free: sc.NewU128(5), + Reserved: sc.NewU128(6), + Frozen: sc.NewU128(7), + Flags: ExtraFlags{sc.NewU128(8)}, }, } ) @@ -51,18 +51,3 @@ func Test_DecodeAccountInfo(t *testing.T) { assert.Equal(t, targetAccountInfo, result) } - -func Test_AccountInfo_Frozen(t *testing.T) { - assert.Equal(t, sc.NewU128(8), targetAccountInfo.Frozen(ReasonsAll)) - assert.Equal(t, sc.NewU128(7), targetAccountInfo.Frozen(ReasonsMisc)) - assert.Equal(t, sc.NewU128(7), targetAccountInfo.Frozen(ReasonsFee)) - assert.Equal(t, sc.NewU128(0), targetAccountInfo.Frozen(3)) -} - -func Test_AccountInfo_Frozen_WithGreaterMiscFrozen(t *testing.T) { - targetAccountInfo = AccountInfo{} - targetAccountInfo.Data.MiscFrozen = sc.NewU128(9) - targetAccountInfo.Data.FeeFrozen = sc.NewU128(8) - - assert.Equal(t, sc.NewU128(9), targetAccountInfo.Frozen(ReasonsAll)) -} diff --git a/primitives/types/dispatch_errors_test.go b/primitives/types/dispatch_errors_test.go index 22619941..1f6846a1 100644 --- a/primitives/types/dispatch_errors_test.go +++ b/primitives/types/dispatch_errors_test.go @@ -20,7 +20,7 @@ func Test_EncodeDispatchError(t *testing.T) { {label: "Encode(DispatchErrorConsumerRemaining)", input: NewDispatchErrorConsumerRemaining(), expectation: []byte{0x04}}, {label: "Encode(DispatchErrorNoProviders)", input: NewDispatchErrorNoProviders(), expectation: []byte{0x05}}, {label: "Encode(DispatchErrorTooManyConsumers)", input: NewDispatchErrorTooManyConsumers(), expectation: []byte{0x06}}, - {label: "Encode(DispatchErrorToken)", input: NewDispatchErrorToken(NewTokenErrorNoFunds()), expectation: []byte{0x07, 0x00}}, + {label: "Encode(DispatchErrorToken)", input: NewDispatchErrorToken(NewTokenErrorFundsUnavailable()), expectation: []byte{0x07, 0x00}}, {label: "Encode(DispatchErrorArithmetic)", input: NewDispatchErrorArithmetic(NewArithmeticErrorUnderflow()), expectation: []byte{0x08, 0x00}}, {label: "Encode(DispatchErrorTransactional)", input: NewDispatchErrorTransactional(NewTransactionalErrorLimitReached()), expectation: []byte{0x09, 0x00}}, {label: "Encode(DispatchErrorExhausted)", input: NewDispatchErrorExhausted(), expectation: []byte{0xa}}, @@ -54,7 +54,7 @@ func Test_DecodeDispatchError(t *testing.T) { {label: "DecodeDispatchError(DispatchErrorConsumerRemaining)", input: []byte{0x04}, expectation: NewDispatchErrorConsumerRemaining()}, {label: "DecodeDispatchError(DispatchErrorNoProviders)", input: []byte{0x05}, expectation: NewDispatchErrorNoProviders()}, {label: "DecodeDispatchError(DispatchErrorTooManyConsumers)", input: []byte{0x06}, expectation: NewDispatchErrorTooManyConsumers()}, - {label: "DecodeDispatchError(DispatchErrorToken)", input: []byte{0x07, 0x00}, expectation: NewDispatchErrorToken(NewTokenErrorNoFunds())}, + {label: "DecodeDispatchError(DispatchErrorToken)", input: []byte{0x07, 0x00}, expectation: NewDispatchErrorToken(NewTokenErrorFundsUnavailable())}, {label: "DecodeDispatchError(DispatchErrorArithmetic)", input: []byte{0x08, 0x00}, expectation: NewDispatchErrorArithmetic(NewArithmeticErrorUnderflow())}, {label: "DecodeDispatchError(DispatchErrorTransactional)", input: []byte{0x09, 0x00}, expectation: NewDispatchErrorTransactional(NewTransactionalErrorLimitReached())}, {label: "DecodeDispatchError(DispatchErrorExhausted)", input: []byte{0xa}, expectation: NewDispatchErrorExhausted()}, diff --git a/primitives/types/flags.go b/primitives/types/flags.go new file mode 100644 index 00000000..c5f3bb41 --- /dev/null +++ b/primitives/types/flags.go @@ -0,0 +1,41 @@ +package types + +import ( + "bytes" + "math/big" + + sc "github.com/LimeChain/goscale" +) + +var ( + FlagsNewLogic, _ = new(big.Int).SetString("80000000000000000000000000000000", 16) + DefaultExtraFlags = ExtraFlags{sc.NewU128(FlagsNewLogic)} +) + +type ExtraFlags struct { + sc.U128 +} + +func (ef ExtraFlags) Encode(buffer *bytes.Buffer) error { + return ef.U128.Encode(buffer) +} + +func (ef ExtraFlags) Bytes() []byte { + return ef.U128.Bytes() +} + +func (ef ExtraFlags) OldLogic() ExtraFlags { + return ef +} + +func (ef ExtraFlags) SetNewLogic() ExtraFlags { + currentEf := ef.ToBigInt() + newEf := currentEf.Or(currentEf, FlagsNewLogic) + return ExtraFlags{sc.NewU128(newEf)} +} + +func (ef ExtraFlags) IsNewLogic() bool { + currentEf := ef.ToBigInt() + currentEf = currentEf.And(currentEf, FlagsNewLogic) + return currentEf.Cmp(FlagsNewLogic) == 0 +} diff --git a/primitives/types/metadata_generator.go b/primitives/types/metadata_generator.go index 93982a82..57b74465 100644 --- a/primitives/types/metadata_generator.go +++ b/primitives/types/metadata_generator.go @@ -69,6 +69,8 @@ func BuildMetadataTypesIdsMap() map[string]int { "CodeUpgradeAuthorization": metadata.TypesCodeUpgradeAuthorization, "RuntimeVersion": metadata.TypesRuntimeVersion, "Weight": metadata.TypesWeight, + "AdjustedDirection": metadata.TypesBalancesAdjustDirection, + "SequenceAddress32": metadata.TypesSequenceAddress32, } } diff --git a/primitives/types/stored_map.go b/primitives/types/stored_map.go index e37fba7d..081b6254 100644 --- a/primitives/types/stored_map.go +++ b/primitives/types/stored_map.go @@ -8,5 +8,11 @@ type StoredMap interface { EventDepositor Get(key AccountId) (AccountInfo, error) CanDecProviders(who AccountId) (bool, error) + DecConsumers(who AccountId) error + DecProviders(who AccountId) (DecRefStatus, error) + IncConsumers(who AccountId) error + IncConsumersWithoutLimit(who AccountId) error + IncProviders(who AccountId) (IncRefStatus, error) + Insert(who AccountId, data AccountData) (sc.Encodable, error) TryMutateExists(who AccountId, f func(who *AccountData) (sc.Encodable, error)) (sc.Encodable, error) } diff --git a/primitives/types/token_error.go b/primitives/types/token_error.go index ae437cd9..a20a76f5 100644 --- a/primitives/types/token_error.go +++ b/primitives/types/token_error.go @@ -7,23 +7,26 @@ import ( ) const ( - TokenErrorNoFunds sc.U8 = iota - TokenErrorWouldDie + TokenErrorFundsUnavailable sc.U8 = iota + TokenErrorOnlyProvider TokenErrorBelowMinimum TokenErrorCannotCreate TokenErrorUnknownAsset TokenErrorFrozen TokenErrorUnsupported + TokenErrorCannotCreateHold + TokenErrorNotExpendable + TokenErrorBlocked ) type TokenError sc.VaryingData -func NewTokenErrorNoFunds() TokenError { - return TokenError(sc.NewVaryingData(TokenErrorNoFunds)) +func NewTokenErrorFundsUnavailable() TokenError { + return TokenError(sc.NewVaryingData(TokenErrorFundsUnavailable)) } -func NewTokenErrorWouldDie() TokenError { - return TokenError(sc.NewVaryingData(TokenErrorWouldDie)) +func NewTokenErrorOnlyProvider() TokenError { + return TokenError(sc.NewVaryingData(TokenErrorOnlyProvider)) } func NewTokenErrorBelowMinimum() TokenError { @@ -46,6 +49,18 @@ func NewTokenErrorUnsupported() TokenError { return TokenError(sc.NewVaryingData(TokenErrorUnsupported)) } +func NewTokenErrorCannotCreateHold() TokenError { + return TokenError(sc.NewVaryingData(TokenErrorCannotCreateHold)) +} + +func NewTokenErrorNotExpendable() TokenError { + return TokenError(sc.NewVaryingData(TokenErrorNotExpendable)) +} + +func NewTokenErrorBlocked() TokenError { + return TokenError(sc.NewVaryingData(TokenErrorBlocked)) +} + func (err TokenError) Encode(buffer *bytes.Buffer) error { return err[0].Encode(buffer) } @@ -56,9 +71,9 @@ func (err TokenError) Error() string { } switch err[0] { - case TokenErrorNoFunds: + case TokenErrorFundsUnavailable: return "Funds are unavailable" - case TokenErrorWouldDie: + case TokenErrorOnlyProvider: return "Account that must exist would die" case TokenErrorBelowMinimum: return "Account cannot exist with the funds that would be given" @@ -70,6 +85,12 @@ func (err TokenError) Error() string { return "Funds exist but are frozen" case TokenErrorUnsupported: return "Operation is not supported by the asset" + case TokenErrorCannotCreateHold: + return "Account cannot be created for recording amount on hold" + case TokenErrorNotExpendable: + return "Account that is desired to remain would die" + case TokenErrorBlocked: + return "Account cannot receive the assets" default: return newTypeError("TokenError").Error() } @@ -82,10 +103,10 @@ func DecodeTokenError(buffer *bytes.Buffer) (TokenError, error) { } switch b { - case TokenErrorNoFunds: - return NewTokenErrorNoFunds(), nil - case TokenErrorWouldDie: - return NewTokenErrorWouldDie(), nil + case TokenErrorFundsUnavailable: + return NewTokenErrorFundsUnavailable(), nil + case TokenErrorOnlyProvider: + return NewTokenErrorOnlyProvider(), nil case TokenErrorBelowMinimum: return NewTokenErrorBelowMinimum(), nil case TokenErrorCannotCreate: @@ -96,6 +117,12 @@ func DecodeTokenError(buffer *bytes.Buffer) (TokenError, error) { return NewTokenErrorFrozen(), nil case TokenErrorUnsupported: return NewTokenErrorUnsupported(), nil + case TokenErrorCannotCreateHold: + return NewTokenErrorCannotCreateHold(), nil + case TokenErrorNotExpendable: + return NewTokenErrorNotExpendable(), nil + case TokenErrorBlocked: + return NewTokenErrorBlocked(), nil default: return TokenError{}, newTypeError("TokenError") } diff --git a/primitives/types/token_error_test.go b/primitives/types/token_error_test.go index 07b07b5e..b15d5c13 100644 --- a/primitives/types/token_error_test.go +++ b/primitives/types/token_error_test.go @@ -17,14 +17,14 @@ func Test_TokenError(t *testing.T) { }{ { name: "TokenErrorNoFunds", - newErr: NewTokenErrorNoFunds(), - wantErr: TokenError(sc.NewVaryingData(TokenErrorNoFunds)), + newErr: NewTokenErrorFundsUnavailable(), + wantErr: TokenError(sc.NewVaryingData(TokenErrorFundsUnavailable)), wantErrMsg: "Funds are unavailable", }, { name: "TokenErrorWouldDie", - newErr: NewTokenErrorWouldDie(), - wantErr: TokenError(sc.NewVaryingData(TokenErrorWouldDie)), + newErr: NewTokenErrorOnlyProvider(), + wantErr: TokenError(sc.NewVaryingData(TokenErrorOnlyProvider)), wantErrMsg: "Account that must exist would die", }, { @@ -57,6 +57,24 @@ func Test_TokenError(t *testing.T) { wantErr: TokenError(sc.NewVaryingData(TokenErrorUnsupported)), wantErrMsg: "Operation is not supported by the asset", }, + { + name: "TokenErrorNotExpendable", + newErr: NewTokenErrorCannotCreateHold(), + wantErr: TokenError(sc.NewVaryingData(TokenErrorCannotCreateHold)), + wantErrMsg: "Account cannot be created for recording amount on hold", + }, + { + name: "TokenErrorCannotCreateHold", + newErr: NewTokenErrorNotExpendable(), + wantErr: TokenError(sc.NewVaryingData(TokenErrorNotExpendable)), + wantErrMsg: "Account that is desired to remain would die", + }, + { + name: "TokenErrorBlocked", + newErr: NewTokenErrorBlocked(), + wantErr: TokenError(sc.NewVaryingData(TokenErrorBlocked)), + wantErrMsg: "Account cannot receive the assets", + }, } { t.Run(tt.name, func(t *testing.T) { buffer := &bytes.Buffer{} @@ -79,7 +97,7 @@ func Test_DecodeTokenError_TypeError(t *testing.T) { }{ { name: "invalid type", - errType: sc.U8(7), + errType: sc.U8(10), }, { name: "nil", diff --git a/runtime/templates/parachain/runtime.go b/runtime/templates/parachain/runtime.go index 6e305434..b8a03a13 100644 --- a/runtime/templates/parachain/runtime.go +++ b/runtime/templates/parachain/runtime.go @@ -219,8 +219,8 @@ func initializeModules(storage io.Storage) []primitives.Module { balancesModule := balances.New( BalancesIndex, balances.NewConfig(storage, DbWeight, BalancesMaxLocks, BalancesMaxReserves, BalancesExistentialDeposit, systemModule), - logger, mdGenerator, + logger, ) tpmModule := transaction_payment.New( diff --git a/runtime/templates/poa/balances_force_adjust_total_issuance_test.go b/runtime/templates/poa/balances_force_adjust_total_issuance_test.go new file mode 100644 index 00000000..21bace61 --- /dev/null +++ b/runtime/templates/poa/balances_force_adjust_total_issuance_test.go @@ -0,0 +1,66 @@ +package main + +import ( + "bytes" + gossamertypes "github.com/ChainSafe/gossamer/dot/types" + "github.com/ChainSafe/gossamer/pkg/scale" + "github.com/LimeChain/gosemble/constants" + "github.com/LimeChain/gosemble/testhelpers" + cscale "github.com/centrifuge/go-substrate-rpc-client/v4/scale" + "github.com/centrifuge/go-substrate-rpc-client/v4/signature" + ctypes "github.com/centrifuge/go-substrate-rpc-client/v4/types" + "github.com/stretchr/testify/assert" + "math/big" + "testing" +) + +func Test_Balances_ForceAdjustTotalIssuance_BadOrigin(t *testing.T) { + rt, storage := testhelpers.NewRuntimeInstance(t) + runtimeVersion, err := rt.Version() + assert.NoError(t, err) + + metadata := testhelpers.RuntimeMetadata(t, rt) + + issuance := big.NewInt(0).SetUint64(constants.Dollar) + call, err := ctypes.NewCall(metadata, "Balances.force_adjust_total_issuance", uint8(0), ctypes.NewUCompact(issuance)) + assert.NoError(t, err) + + // Create the extrinsic + ext := ctypes.NewExtrinsic(call) + o := ctypes.SignatureOptions{ + BlockHash: ctypes.Hash(testhelpers.ParentHash), + Era: ctypes.ExtrinsicEra{IsImmortalEra: true}, + GenesisHash: ctypes.Hash(testhelpers.ParentHash), + Nonce: ctypes.NewUCompactFromUInt(0), + SpecVersion: ctypes.U32(runtimeVersion.SpecVersion), + Tip: ctypes.NewUCompactFromUInt(0), + TransactionVersion: ctypes.U32(runtimeVersion.TransactionVersion), + } + + // Set Account Info + balance, ok := big.NewInt(0).SetString("500000000000000", 10) + assert.True(t, ok) + + testhelpers.SetStorageAccountInfo(t, storage, signature.TestKeyringPairAlice.PublicKey, balance, 0) + + // Sign the transaction using Alice's default account + err = ext.Sign(signature.TestKeyringPairAlice, o) + assert.NoError(t, err) + + extEnc := bytes.Buffer{} + encoder := cscale.NewEncoder(&extEnc) + err = ext.Encode(*encoder) + assert.NoError(t, err) + + header := gossamertypes.NewHeader(testhelpers.ParentHash, testhelpers.StateRoot, testhelpers.ExtrinsicsRoot, uint(testhelpers.BlockNumber), gossamertypes.NewDigest()) + encodedHeader, err := scale.Marshal(*header) + assert.NoError(t, err) + + _, err = rt.Exec("Core_initialize_block", encodedHeader) + assert.NoError(t, err) + + res, err := rt.Exec("BlockBuilder_apply_extrinsic", extEnc.Bytes()) + assert.NoError(t, err) + + assert.Equal(t, testhelpers.ApplyExtrinsicResultBadOriginErr.Bytes(), res) +} diff --git a/runtime/templates/poa/balances_force_free_test.go b/runtime/templates/poa/balances_force_free_test.go index ce8d4cbd..e9b06f96 100644 --- a/runtime/templates/poa/balances_force_free_test.go +++ b/runtime/templates/poa/balances_force_free_test.go @@ -23,7 +23,7 @@ func Test_Balances_ForceFree_BadOrigin(t *testing.T) { alice, err := ctypes.NewMultiAddressFromAccountID(signature.TestKeyringPairAlice.PublicKey) - call, err := ctypes.NewCall(metadata, "Balances.force_free", alice, ctypes.NewU128(*big.NewInt(10000000000))) + call, err := ctypes.NewCall(metadata, "Balances.force_unreserve", alice, ctypes.NewU128(*big.NewInt(10000000000))) assert.NoError(t, err) // Create the extrinsic diff --git a/runtime/templates/poa/balances_set_balance_test.go b/runtime/templates/poa/balances_force_set_balance_test.go similarity index 91% rename from runtime/templates/poa/balances_set_balance_test.go rename to runtime/templates/poa/balances_force_set_balance_test.go index b5929d22..85c740e8 100644 --- a/runtime/templates/poa/balances_set_balance_test.go +++ b/runtime/templates/poa/balances_force_set_balance_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/assert" ) -func Test_Balances_SetBalance_BadOrigin(t *testing.T) { +func Test_Balances_ForceSetBalance_BadOrigin(t *testing.T) { rt, storage := testhelpers.NewRuntimeInstance(t) runtimeVersion, err := rt.Version() assert.NoError(t, err) @@ -25,7 +25,7 @@ func Test_Balances_SetBalance_BadOrigin(t *testing.T) { "0x90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22") assert.NoError(t, err) - call, err := ctypes.NewCall(metadata, "Balances.set_balance", bob, ctypes.NewUCompactFromUInt(10000000000), ctypes.NewUCompactFromUInt(10000000000)) + call, err := ctypes.NewCall(metadata, "Balances.force_set_balance", bob, ctypes.NewUCompactFromUInt(10000000000)) assert.NoError(t, err) // Create the extrinsic diff --git a/runtime/templates/poa/balances_transfer_all_test.go b/runtime/templates/poa/balances_transfer_all_test.go index 3480f0b3..ff2a44ff 100644 --- a/runtime/templates/poa/balances_transfer_all_test.go +++ b/runtime/templates/poa/balances_transfer_all_test.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "github.com/LimeChain/gosemble/primitives/types" "math/big" "testing" @@ -84,7 +85,7 @@ func Test_Balances_TransferAll_Success_AllowDeath(t *testing.T) { Free: scale.MustNewUint128(big.NewInt(0).Sub(balance, queryInfo.PartialFee.ToBigInt())), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), }, } @@ -104,7 +105,7 @@ func Test_Balances_TransferAll_Success_AllowDeath(t *testing.T) { Free: scale.MustNewUint128(big.NewInt(0)), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), }, } @@ -145,7 +146,7 @@ func Test_Balances_TransferAll_Success_KeepAlive(t *testing.T) { balance, ok := big.NewInt(0).SetString("500000000000000", 10) assert.True(t, ok) - testhelpers.SetStorageAccountInfo(t, storage, signature.TestKeyringPairAlice.PublicKey, balance, 0) + keyStorageAccountAlice, aliceAccountInfo := testhelpers.SetStorageAccountInfo(t, storage, signature.TestKeyringPairAlice.PublicKey, balance, 0) // Sign the transaction using Alice's default account err = ext.Sign(signature.TestKeyringPairAlice, o) @@ -163,61 +164,60 @@ func Test_Balances_TransferAll_Success_KeepAlive(t *testing.T) { _, err = rt.Exec("Core_initialize_block", encodedHeader) assert.NoError(t, err) + queryInfo := testhelpers.GetQueryInfo(t, rt, extEnc.Bytes()) + res, err := rt.Exec("BlockBuilder_apply_extrinsic", extEnc.Bytes()) assert.NoError(t, err) - // TODO: remove once tx payments are implemented - assert.Equal(t, testhelpers.ApplyExtrinsicResultKeepAliveErr.Bytes(), res) - - // TODO: Uncomment once tx payments are implemented, this will be successfully executed, - // for now it fails due to nothing reserved in account executor - //assert.Equal(t, - // primitives.NewApplyExtrinsicResult(primitives.NewDispatchOutcome(nil)).Bytes(), - // res, - //) - - //bobHash, _ := common.Blake2b128(bob.AsID[:]) - //keyStorageAccountBob := append(keySystemHash, keyAccountHash...) - //keyStorageAccountBob = append(keyStorageAccountBob, bobHash...) - //keyStorageAccountBob = append(keyStorageAccountBob, bob.AsID[:]...) - //bytesStorageBob := storage.Get(keyStorageAccountBob) - // - //expectedBobAccountInfo := gossamertypes.AccountInfo{ - // Nonce: 0, - // Consumers: 0, - // Producers: 1, - // Sufficients: 0, - // Data: gossamertypes.AccountData{ - // Free: scale.MustNewUint128(mockBalance), - // Reserved: scale.MustNewUint128(big.NewInt(0)), - // MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - // FreeFrozen: scale.MustNewUint128(big.NewInt(0)), - // }, - //} - // - //bobAccountInfo := gossamertypes.AccountInfo{} - // - //err = scale.Unmarshal(bytesStorageBob, &bobAccountInfo) - //assert.NoError(t, err) - // - //assert.Equal(t, expectedBobAccountInfo, bobAccountInfo) - // - //expectedAliceAccountInfo := gossamertypes.AccountInfo{ - // Nonce: 1, - // Consumers: 0, - // Producers: 0, - // Sufficients: 0, - // Data: gossamertypes.AccountData{ - // Free: scale.MustNewUint128(big.NewInt(0)), - // Reserved: scale.MustNewUint128(big.NewInt(0)), - // MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - // FreeFrozen: scale.MustNewUint128(big.NewInt(0)), - // }, - //} - // - //bytesAliceStorage := storage.Get(keyStorageAccountAlice) - //err = scale.Unmarshal(bytesAliceStorage, &aliceAccountInfo) - //assert.NoError(t, err) - // - //assert.Equal(t, expectedAliceAccountInfo, aliceAccountInfo) + assert.Equal(t, + testhelpers.ApplyExtrinsicResultOutcome.Bytes(), + res, + ) + + bobHash, _ := common.Blake2b128(bob.AsID[:]) + keyStorageAccountBob := append(testhelpers.KeySystemHash, testhelpers.KeyAccountHash...) + keyStorageAccountBob = append(keyStorageAccountBob, bobHash...) + keyStorageAccountBob = append(keyStorageAccountBob, bob.AsID[:]...) + bytesStorageBob := (*storage).Get(keyStorageAccountBob) + + transferDiff := new(big.Int).Sub(balance, queryInfo.PartialFee.ToBigInt()) + expectedBobBalance := new(big.Int).Sub(transferDiff, BalancesExistentialDeposit.ToBigInt()) + expectedBobAccountInfo := gossamertypes.AccountInfo{ + Nonce: 0, + Consumers: 0, + Producers: 1, + Sufficients: 0, + Data: gossamertypes.AccountData{ + Free: scale.MustNewUint128(expectedBobBalance), + Reserved: scale.MustNewUint128(big.NewInt(0)), + MiscFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), + }, + } + + bobAccountInfo := gossamertypes.AccountInfo{} + + err = scale.Unmarshal(bytesStorageBob, &bobAccountInfo) + assert.NoError(t, err) + + assert.Equal(t, expectedBobAccountInfo, bobAccountInfo) + + expectedAliceAccountInfo := gossamertypes.AccountInfo{ + Nonce: 1, + Consumers: 0, + Producers: 1, + Sufficients: 0, + Data: gossamertypes.AccountData{ + Free: scale.MustNewUint128(BalancesExistentialDeposit.ToBigInt()), + Reserved: scale.MustNewUint128(big.NewInt(0)), + MiscFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), + }, + } + + bytesAliceStorage := (*storage).Get(keyStorageAccountAlice) + err = scale.Unmarshal(bytesAliceStorage, &aliceAccountInfo) + assert.NoError(t, err) + + assert.Equal(t, expectedAliceAccountInfo, aliceAccountInfo) } diff --git a/runtime/templates/poa/balances_transfer_test.go b/runtime/templates/poa/balances_transfer_allow_death_test.go similarity index 89% rename from runtime/templates/poa/balances_transfer_test.go rename to runtime/templates/poa/balances_transfer_allow_death_test.go index 4e45c1c6..82a01b60 100644 --- a/runtime/templates/poa/balances_transfer_test.go +++ b/runtime/templates/poa/balances_transfer_allow_death_test.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "github.com/LimeChain/gosemble/primitives/types" "math/big" "testing" @@ -18,7 +19,7 @@ import ( "golang.org/x/crypto/blake2b" ) -func Test_Balances_Transfer_Success(t *testing.T) { +func Test_Balances_TransferAllowDeath_Success(t *testing.T) { rt, storage := testhelpers.NewRuntimeInstance(t) runtimeVersion, err := rt.Version() assert.NoError(t, err) @@ -31,7 +32,7 @@ func Test_Balances_Transfer_Success(t *testing.T) { transferAmount := big.NewInt(0).SetUint64(constants.Dollar) - call, err := ctypes.NewCall(metadata, "Balances.transfer", bob, ctypes.NewUCompact(transferAmount)) + call, err := ctypes.NewCall(metadata, "Balances.transfer_allow_death", bob, ctypes.NewUCompact(transferAmount)) assert.NoError(t, err) // Create the extrinsic @@ -89,7 +90,7 @@ func Test_Balances_Transfer_Success(t *testing.T) { Free: scale.MustNewUint128(transferAmount), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), }, } @@ -113,7 +114,7 @@ func Test_Balances_Transfer_Success(t *testing.T) { Free: scale.MustNewUint128(expectedAliceFreeBalance), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), }, } @@ -124,7 +125,7 @@ func Test_Balances_Transfer_Success(t *testing.T) { assert.Equal(t, expectedAliceAccountInfo, aliceAccountInfo) } -func Test_Balances_Transfer_Invalid_InsufficientBalance(t *testing.T) { +func Test_Balances_TransferAllowDeath_Invalid_InsufficientBalance(t *testing.T) { rt, storage := testhelpers.NewRuntimeInstance(t) runtimeVersion, err := rt.Version() assert.NoError(t, err) @@ -135,9 +136,10 @@ func Test_Balances_Transfer_Invalid_InsufficientBalance(t *testing.T) { "0x90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22") assert.NoError(t, err) - transferAmount := big.NewInt(0).SetUint64(constants.Dollar) + transferAmount, e := big.NewInt(0).SetString("500000000000000", 10) + assert.True(t, e) - call, err := ctypes.NewCall(metadata, "Balances.transfer", bob, ctypes.NewUCompact(transferAmount)) + call, err := ctypes.NewCall(metadata, "Balances.transfer_allow_death", bob, ctypes.NewUCompact(transferAmount)) assert.NoError(t, err) // Create the extrinsic @@ -153,7 +155,8 @@ func Test_Balances_Transfer_Invalid_InsufficientBalance(t *testing.T) { } // Set Account Info - balance := big.NewInt(0).Sub(transferAmount, big.NewInt(1)) + balance, e := big.NewInt(0).SetString("500000000000000", 10) + assert.True(t, e) testhelpers.SetStorageAccountInfo(t, storage, signature.TestKeyringPairAlice.PublicKey, balance, 0) // Sign the transaction using Alice's default account @@ -173,10 +176,10 @@ func Test_Balances_Transfer_Invalid_InsufficientBalance(t *testing.T) { assert.NoError(t, err) res, err := rt.Exec("BlockBuilder_apply_extrinsic", extEnc.Bytes()) - assert.Equal(t, testhelpers.ApplyExtrinsicResultCustomModuleErr.Bytes(), res) + assert.Equal(t, testhelpers.ApplyExtrinsicResultTokenErrorFundsUnavailable.Bytes(), res) } -func Test_Balances_Transfer_Invalid_ExistentialDeposit(t *testing.T) { +func Test_Balances_TransferAllowDeath_Invalid_ExistentialDeposit(t *testing.T) { rt, storage := testhelpers.NewRuntimeInstance(t) runtimeVersion, err := rt.Version() assert.NoError(t, err) @@ -187,7 +190,7 @@ func Test_Balances_Transfer_Invalid_ExistentialDeposit(t *testing.T) { "0x90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22") assert.NoError(t, err) - call, err := ctypes.NewCall(metadata, "Balances.transfer", bob, ctypes.NewUCompactFromUInt(1)) + call, err := ctypes.NewCall(metadata, "Balances.transfer_allow_death", bob, ctypes.NewUCompactFromUInt(1)) assert.NoError(t, err) // Create the extrinsic @@ -230,7 +233,7 @@ func Test_Balances_Transfer_Invalid_ExistentialDeposit(t *testing.T) { assert.Equal(t, testhelpers.ApplyExtrinsicResultExistentialDepositErr.Bytes(), res) } -func Test_Balances_Transfer_Ecdsa_Signature(t *testing.T) { +func Test_Balances_TransferAllowDeath_Ecdsa_Signature(t *testing.T) { rt, storage := testhelpers.NewRuntimeInstance(t) runtimeVersion, err := rt.Version() assert.NoError(t, err) @@ -249,7 +252,7 @@ func Test_Balances_Transfer_Ecdsa_Signature(t *testing.T) { transferAmount := big.NewInt(0).SetUint64(constants.Dollar) - call, err := ctypes.NewCall(metadata, "Balances.transfer", bob, ctypes.NewUCompact(transferAmount)) + call, err := ctypes.NewCall(metadata, "Balances.transfer_allow_death", bob, ctypes.NewUCompact(transferAmount)) assert.NoError(t, err) // Create the extrinsic @@ -308,7 +311,7 @@ func Test_Balances_Transfer_Ecdsa_Signature(t *testing.T) { Free: scale.MustNewUint128(transferAmount), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), }, } @@ -332,7 +335,7 @@ func Test_Balances_Transfer_Ecdsa_Signature(t *testing.T) { Free: scale.MustNewUint128(expectedAliceFreeBalance), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), }, } diff --git a/runtime/templates/poa/balances_transfer_keep_alive_test.go b/runtime/templates/poa/balances_transfer_keep_alive_test.go index ff057de7..c4e9c835 100644 --- a/runtime/templates/poa/balances_transfer_keep_alive_test.go +++ b/runtime/templates/poa/balances_transfer_keep_alive_test.go @@ -2,11 +2,12 @@ package main import ( "bytes" + "github.com/ChainSafe/gossamer/lib/common" + "github.com/LimeChain/gosemble/primitives/types" "math/big" "testing" gossamertypes "github.com/ChainSafe/gossamer/dot/types" - "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/pkg/scale" "github.com/LimeChain/gosemble/constants" "github.com/LimeChain/gosemble/testhelpers" @@ -88,7 +89,7 @@ func Test_Balances_TransferKeepAlive_Success(t *testing.T) { Free: scale.MustNewUint128(transferAmount), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), }, } @@ -112,7 +113,7 @@ func Test_Balances_TransferKeepAlive_Success(t *testing.T) { Free: scale.MustNewUint128(expectedAliceFreeBalance), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), }, } diff --git a/runtime/templates/poa/balances_upgrade_accounts_test.go b/runtime/templates/poa/balances_upgrade_accounts_test.go new file mode 100644 index 00000000..b1109f64 --- /dev/null +++ b/runtime/templates/poa/balances_upgrade_accounts_test.go @@ -0,0 +1,100 @@ +package main + +import ( + "bytes" + gossamertypes "github.com/ChainSafe/gossamer/dot/types" + "github.com/ChainSafe/gossamer/lib/common" + "github.com/ChainSafe/gossamer/pkg/scale" + "github.com/LimeChain/gosemble/primitives/types" + "github.com/LimeChain/gosemble/testhelpers" + cscale "github.com/centrifuge/go-substrate-rpc-client/v4/scale" + "github.com/centrifuge/go-substrate-rpc-client/v4/signature" + ctypes "github.com/centrifuge/go-substrate-rpc-client/v4/types" + "github.com/stretchr/testify/assert" + "math/big" + "testing" +) + +func Test_Balances_UpgradeAccounts_NoUpgrades_Success(t *testing.T) { + rt, storage := testhelpers.NewRuntimeInstance(t) + runtimeVersion, err := rt.Version() + assert.NoError(t, err) + + metadata := testhelpers.RuntimeMetadata(t, rt) + + bob, err := ctypes.NewMultiAddressFromHexAccountID( + "0x90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22") + assert.NoError(t, err) + + call, err := ctypes.NewCall(metadata, "Balances.upgrade_accounts", []ctypes.AccountID{bob.AsID}) + assert.NoError(t, err) + + // Create the extrinsic + ext := ctypes.NewExtrinsic(call) + o := ctypes.SignatureOptions{ + BlockHash: ctypes.Hash(testhelpers.ParentHash), + Era: ctypes.ExtrinsicEra{IsImmortalEra: true}, + GenesisHash: ctypes.Hash(testhelpers.ParentHash), + Nonce: ctypes.NewUCompactFromUInt(0), + SpecVersion: ctypes.U32(runtimeVersion.SpecVersion), + Tip: ctypes.NewUCompactFromUInt(0), + TransactionVersion: ctypes.U32(runtimeVersion.TransactionVersion), + } + + // Set Account Info + balance, e := big.NewInt(0).SetString("500000000000000", 10) + assert.True(t, e) + + keyStorageAccountAlice, aliceAccountInfo := testhelpers.SetStorageAccountInfo(t, storage, signature.TestKeyringPairAlice.PublicKey, balance, 0) + + // Sign the transaction using Alice's default account + err = ext.Sign(signature.TestKeyringPairAlice, o) + assert.NoError(t, err) + + extEnc := bytes.Buffer{} + encoder := cscale.NewEncoder(&extEnc) + err = ext.Encode(*encoder) + assert.NoError(t, err) + + header := gossamertypes.NewHeader(testhelpers.ParentHash, testhelpers.StateRoot, testhelpers.ExtrinsicsRoot, uint(testhelpers.BlockNumber), gossamertypes.NewDigest()) + encodedHeader, err := scale.Marshal(*header) + assert.NoError(t, err) + + _, err = rt.Exec("Core_initialize_block", encodedHeader) + assert.NoError(t, err) + + queryInfo := testhelpers.GetQueryInfo(t, rt, extEnc.Bytes()) + + res, err := rt.Exec("BlockBuilder_apply_extrinsic", extEnc.Bytes()) + assert.NoError(t, err) + assert.Equal(t, testhelpers.ApplyExtrinsicResultOutcome.Bytes(), res) + + bobHash, _ := common.Blake2b128(bob.AsID[:]) + keyStorageAccountBob := append(testhelpers.KeySystemHash, testhelpers.KeyAccountHash...) + keyStorageAccountBob = append(keyStorageAccountBob, bobHash...) + keyStorageAccountBob = append(keyStorageAccountBob, bob.AsID[:]...) + + bytesStorageBob := (*storage).Get(keyStorageAccountBob) + assert.Nil(t, bytesStorageBob) + + expectedAliceFreeBalance := big.NewInt(0).Sub( + balance, queryInfo.PartialFee.ToBigInt()) + expectedAliceAccountInfo := gossamertypes.AccountInfo{ + Nonce: 1, + Consumers: 0, + Producers: 1, + Sufficients: 0, + Data: gossamertypes.AccountData{ + Free: scale.MustNewUint128(expectedAliceFreeBalance), + Reserved: scale.MustNewUint128(big.NewInt(0)), + MiscFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), + }, + } + + bytesAliceStorage := (*storage).Get(keyStorageAccountAlice) + err = scale.Unmarshal(bytesAliceStorage, &aliceAccountInfo) + assert.NoError(t, err) + + assert.Equal(t, expectedAliceAccountInfo, aliceAccountInfo) +} diff --git a/runtime/templates/poa/benchmark_balances_force_free_test.go b/runtime/templates/poa/benchmark_balances_force_free_test.go index 9dc4c95a..c79f37c5 100644 --- a/runtime/templates/poa/benchmark_balances_force_free_test.go +++ b/runtime/templates/poa/benchmark_balances_force_free_test.go @@ -13,11 +13,11 @@ import ( ) func BenchmarkBalancesForceFree(b *testing.B) { - benchmarking.RunDispatchCall(b, "../../../frame/balances/call_force_free_weight.go", func(i *benchmarking.Instance) { + benchmarking.RunDispatchCall(b, "../../../frame/balances/call_force_unreserve_weight.go", func(i *benchmarking.Instance) { accountInfo := gossamertypes.AccountInfo{ Nonce: 0, Consumers: 0, - Producers: 0, + Producers: 1, Sufficients: 0, Data: gossamertypes.AccountData{ Free: scale.MustNewUint128(big.NewInt(existentialAmount)), @@ -31,7 +31,7 @@ func BenchmarkBalancesForceFree(b *testing.B) { assert.NoError(b, err) err = i.ExecuteExtrinsic( - "Balances.force_free", + "Balances.force_unreserve", types.NewRawOriginRoot(), aliceAddress, ctypes.NewU128(*big.NewInt(2 * existentialAmount)), diff --git a/runtime/templates/poa/benchmark_balances_force_transfer_test.go b/runtime/templates/poa/benchmark_balances_force_transfer_test.go index 5f99dc50..a798d632 100644 --- a/runtime/templates/poa/benchmark_balances_force_transfer_test.go +++ b/runtime/templates/poa/benchmark_balances_force_transfer_test.go @@ -6,8 +6,11 @@ import ( gossamertypes "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/pkg/scale" + sc "github.com/LimeChain/goscale" "github.com/LimeChain/gosemble/benchmarking" "github.com/LimeChain/gosemble/primitives/types" + primitives "github.com/LimeChain/gosemble/primitives/types" + "github.com/LimeChain/gosemble/testhelpers" ctypes "github.com/centrifuge/go-substrate-rpc-client/v4/types" "github.com/stretchr/testify/assert" ) @@ -23,19 +26,23 @@ func BenchmarkBalancesForceTransfer(b *testing.B) { accountInfo := gossamertypes.AccountInfo{ Nonce: 0, Consumers: 0, - Producers: 0, + Producers: 1, Sufficients: 0, Data: gossamertypes.AccountData{ Free: scale.MustNewUint128(big.NewInt(balance)), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(primitives.FlagsNewLogic), }, } err := i.SetAccountInfo(aliceAccountIdBytes, accountInfo) assert.NoError(b, err) + keyTotalIssuance := append(testhelpers.KeyBalancesHash, testhelpers.KeyTotalIssuanceHash...) + err = (*i.Storage()).Put(keyTotalIssuance, sc.NewU128(balance).Bytes()) + assert.NoError(b, err) + err = i.ExecuteExtrinsic( "Balances.force_transfer", types.NewRawOriginRoot(), diff --git a/runtime/templates/poa/benchmark_balances_set_balance_test.go b/runtime/templates/poa/benchmark_balances_set_balance_test.go index 2429d3ca..08ecb9d8 100644 --- a/runtime/templates/poa/benchmark_balances_set_balance_test.go +++ b/runtime/templates/poa/benchmark_balances_set_balance_test.go @@ -16,11 +16,11 @@ var value = uint64(existentialMultiplier * existentialAmount) // Coming from ROOT account. This always creates an account. func BenchmarkBalancesSetBalanceCreating(b *testing.B) { - benchmarkBalancesSetBalance(b, "../../../frame/balances/call_set_balance_creating_weight.go", value, value) + benchmarkBalancesSetBalance(b, "../../../frame/balances/call_force_set_balance_creating_weight.go", value, value) } func BenchmarkBalancesSetBalanceKilling(b *testing.B) { - benchmarkBalancesSetBalance(b, "../../../frame/balances/call_set_balance_killing_weight.go", value, 0) + benchmarkBalancesSetBalance(b, "../../../frame/balances/call_force_set_balance_killing_weight.go", value, 0) } func benchmarkBalancesSetBalance(b *testing.B, outputPath string, balance, amount uint64) { @@ -41,11 +41,10 @@ func benchmarkBalancesSetBalance(b *testing.B, outputPath string, balance, amoun assert.NoError(b, err) err = i.ExecuteExtrinsic( - "Balances.set_balance", + "Balances.force_set_balance", types.NewRawOriginRoot(), aliceAddress, ctypes.NewUCompactFromUInt(amount), - ctypes.NewUCompactFromUInt(amount), ) assert.NoError(b, err) diff --git a/runtime/templates/poa/benchmark_balances_transfer_all_test.go b/runtime/templates/poa/benchmark_balances_transfer_all_test.go index ea732092..736747d4 100644 --- a/runtime/templates/poa/benchmark_balances_transfer_all_test.go +++ b/runtime/templates/poa/benchmark_balances_transfer_all_test.go @@ -6,8 +6,10 @@ import ( gossamertypes "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/pkg/scale" + sc "github.com/LimeChain/goscale" "github.com/LimeChain/gosemble/benchmarking" "github.com/LimeChain/gosemble/primitives/types" + "github.com/LimeChain/gosemble/testhelpers" ctypes "github.com/centrifuge/go-substrate-rpc-client/v4/types" "github.com/stretchr/testify/assert" ) @@ -35,6 +37,10 @@ func BenchmarkBalancesTransferAllAllowDeath(b *testing.B) { err := i.SetAccountInfo(aliceAccountIdBytes, accountInfo) assert.NoError(b, err) + keyTotalIssuance := append(testhelpers.KeyBalancesHash, testhelpers.KeyTotalIssuanceHash...) + err = (*i.Storage()).Put(keyTotalIssuance, sc.NewU128(balance).Bytes()) + assert.NoError(b, err) + err = i.ExecuteExtrinsic( "Balances.transfer_all", types.NewRawOriginSigned(aliceAccountId), diff --git a/runtime/templates/poa/benchmark_balances_transfer_keep_alive_test.go b/runtime/templates/poa/benchmark_balances_transfer_keep_alive_test.go index 97727af4..b4d79b98 100644 --- a/runtime/templates/poa/benchmark_balances_transfer_keep_alive_test.go +++ b/runtime/templates/poa/benchmark_balances_transfer_keep_alive_test.go @@ -8,6 +8,7 @@ import ( "github.com/ChainSafe/gossamer/pkg/scale" "github.com/LimeChain/gosemble/benchmarking" "github.com/LimeChain/gosemble/primitives/types" + "github.com/LimeChain/gosemble/testhelpers" ctypes "github.com/centrifuge/go-substrate-rpc-client/v4/types" "github.com/stretchr/testify/assert" ) @@ -17,7 +18,7 @@ func BenchmarkBalancesTransferKeepAlive(b *testing.B) { accountInfo := gossamertypes.AccountInfo{ Nonce: 0, Consumers: 0, - Producers: 0, + Producers: 1, Sufficients: 0, Data: gossamertypes.AccountData{ Free: scale.MaxUint128, @@ -30,6 +31,10 @@ func BenchmarkBalancesTransferKeepAlive(b *testing.B) { err := i.SetAccountInfo(aliceAccountIdBytes, accountInfo) assert.NoError(b, err) + keyTotalIssuance := append(testhelpers.KeyBalancesHash, testhelpers.KeyTotalIssuanceHash...) + err = (*i.Storage()).Put(keyTotalIssuance, scale.MaxUint128.Bytes()) + assert.NoError(b, err) + transferAmount := existentialMultiplier * existentialAmount err = i.ExecuteExtrinsic( diff --git a/runtime/templates/poa/benchmark_balances_transfer_test.go b/runtime/templates/poa/benchmark_balances_transfer_test.go index df97b991..6af10bbe 100644 --- a/runtime/templates/poa/benchmark_balances_transfer_test.go +++ b/runtime/templates/poa/benchmark_balances_transfer_test.go @@ -6,8 +6,10 @@ import ( gossamertypes "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/pkg/scale" + sc "github.com/LimeChain/goscale" "github.com/LimeChain/gosemble/benchmarking" "github.com/LimeChain/gosemble/primitives/types" + "github.com/LimeChain/gosemble/testhelpers" ctypes "github.com/centrifuge/go-substrate-rpc-client/v4/types" "github.com/stretchr/testify/assert" ) @@ -16,14 +18,14 @@ import ( // * Transfer will kill the sender account. // * Transfer will create the recipient account. func BenchmarkBalancesTransferAllowDeath(b *testing.B) { - benchmarking.RunDispatchCall(b, "../../../frame/balances/call_transfer_weight.go", func(i *benchmarking.Instance) { + benchmarking.RunDispatchCall(b, "../../../frame/balances/call_transfer_allow_death_weight.go", func(i *benchmarking.Instance) { balance := existentialMultiplier * existentialAmount transferAmount := existentialAmount*(existentialMultiplier-1) + 1 accountInfo := gossamertypes.AccountInfo{ Nonce: 0, Consumers: 0, - Producers: 0, + Producers: 1, Sufficients: 0, Data: gossamertypes.AccountData{ Free: scale.MustNewUint128(big.NewInt(balance)), @@ -36,8 +38,12 @@ func BenchmarkBalancesTransferAllowDeath(b *testing.B) { err := i.SetAccountInfo(aliceAccountIdBytes, accountInfo) assert.NoError(b, err) + keyTotalIssuance := append(testhelpers.KeyBalancesHash, testhelpers.KeyTotalIssuanceHash...) + err = (*i.Storage()).Put(keyTotalIssuance, sc.NewU128(balance).Bytes()) + assert.NoError(b, err) + err = i.ExecuteExtrinsic( - "Balances.transfer", + "Balances.transfer_allow_death", types.NewRawOriginSigned(aliceAccountId), bobAddress, ctypes.NewUCompact(big.NewInt(transferAmount)), diff --git a/runtime/templates/poa/core_execute_block_test.go b/runtime/templates/poa/core_execute_block_test.go index 2114a688..290170bd 100644 --- a/runtime/templates/poa/core_execute_block_test.go +++ b/runtime/templates/poa/core_execute_block_test.go @@ -22,7 +22,7 @@ import ( var ( dateTime = time.Date(2023, time.January, 2, 3, 4, 5, 6, time.UTC) - storageRoot = common.MustHexToHash("0xd940e147feef433028c8ca2db9ef6c7c51bf6e9538b81301fff3ff24950fa056") // Depends on date + storageRoot = common.MustHexToHash("0x104a0c104217efdf4c8a6adb259ed24ed581fdf6afb61fc5189b4c1162244955") // Depends on date ) func Test_BlockExecution(t *testing.T) { diff --git a/runtime/templates/poa/genesis_builder_test.go b/runtime/templates/poa/genesis_builder_test.go index 429d4ab4..0e751f39 100644 --- a/runtime/templates/poa/genesis_builder_test.go +++ b/runtime/templates/poa/genesis_builder_test.go @@ -77,7 +77,7 @@ func Test_BuildConfig(t *testing.T) { keyStorageAccount = append(keyStorageAccount, accId.Bytes()...) accInfo := (*storage).Get(keyStorageAccount) expectedBalance := sc.NewU128(uint64(1000000000000000000)) - expectedAccInfo := types.AccountInfo{Data: types.AccountData{Free: expectedBalance}, Providers: 1} + expectedAccInfo := types.AccountInfo{Data: types.AccountData{Free: expectedBalance, Flags: types.DefaultExtraFlags}, Providers: 1} assert.Equal(t, expectedAccInfo.Bytes(), accInfo) // assert total issuance diff --git a/runtime/templates/poa/runtime.go b/runtime/templates/poa/runtime.go index 47b8fb0d..5ea7e465 100644 --- a/runtime/templates/poa/runtime.go +++ b/runtime/templates/poa/runtime.go @@ -199,8 +199,8 @@ func initializeModules(storage io.Storage, transactionBroker io.TransactionBroke balancesModule := balances.New( BalancesIndex, balances.NewConfig(storage, DbWeight, BalancesMaxLocks, BalancesMaxReserves, BalancesExistentialDeposit, systemModule), - logger, mdGenerator, + logger, ) tpmModule := transaction_payment.New( diff --git a/runtime/templates/poa/sudo_call_sudo_as_test.go b/runtime/templates/poa/sudo_call_sudo_as_test.go index 4bb225d2..d36c1c0b 100644 --- a/runtime/templates/poa/sudo_call_sudo_as_test.go +++ b/runtime/templates/poa/sudo_call_sudo_as_test.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "github.com/LimeChain/gosemble/primitives/types" "math/big" "testing" @@ -91,7 +92,7 @@ func Test_Sudo_SudoAs_Success(t *testing.T) { Free: scale.MustNewUint128(transferAmount), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), }, } @@ -115,7 +116,7 @@ func Test_Sudo_SudoAs_Success(t *testing.T) { Free: scale.MustNewUint128(expectedAliceFreeBalance), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), }, } diff --git a/runtime/templates/poa/sudo_call_sudo_test.go b/runtime/templates/poa/sudo_call_sudo_test.go index 25de702a..1f9ea921 100644 --- a/runtime/templates/poa/sudo_call_sudo_test.go +++ b/runtime/templates/poa/sudo_call_sudo_test.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "github.com/LimeChain/gosemble/primitives/types" "math/big" "testing" @@ -91,7 +92,7 @@ func Test_Sudo_Sudo_Success(t *testing.T) { Free: scale.MustNewUint128(transferAmount), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), }, } @@ -115,7 +116,7 @@ func Test_Sudo_Sudo_Success(t *testing.T) { Free: scale.MustNewUint128(expectedAliceFreeBalance), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), }, } diff --git a/runtime/templates/poa/sudo_call_sudo_unchecked_weight_test.go b/runtime/templates/poa/sudo_call_sudo_unchecked_weight_test.go index b491940c..596b4af8 100644 --- a/runtime/templates/poa/sudo_call_sudo_unchecked_weight_test.go +++ b/runtime/templates/poa/sudo_call_sudo_unchecked_weight_test.go @@ -5,6 +5,8 @@ import ( "math/big" "testing" + "github.com/LimeChain/gosemble/primitives/types" + gossamertypes "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/pkg/scale" @@ -96,7 +98,7 @@ func Test_Sudo_SudoUncheckedWeight_Success(t *testing.T) { Free: scale.MustNewUint128(transferAmount), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), }, } @@ -120,7 +122,7 @@ func Test_Sudo_SudoUncheckedWeight_Success(t *testing.T) { Free: scale.MustNewUint128(expectedAliceFreeBalance), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(types.FlagsNewLogic), }, } diff --git a/runtime/templates/poa/transaction_payment_test.go b/runtime/templates/poa/transaction_payment_test.go index a6afda6a..8f41f60b 100644 --- a/runtime/templates/poa/transaction_payment_test.go +++ b/runtime/templates/poa/transaction_payment_test.go @@ -62,7 +62,7 @@ func Test_TransactionPaymentApi_QueryInfo_Signed_Success(t *testing.T) { assert.Nil(t, err) expectedRdi := primitives.RuntimeDispatchInfo{ - Weight: primitives.WeightFromParts(68_363_334, 0), + Weight: primitives.WeightFromParts(92_589_999, 0), Class: primitives.NewDispatchClassNormal(), PartialFee: sc.NewU128(4_288_948_107), } @@ -98,7 +98,7 @@ func Test_TransactionPaymentApi_QueryInfo_Unsigned_Success(t *testing.T) { assert.Nil(t, err) expectedRdi := primitives.RuntimeDispatchInfo{ - Weight: primitives.WeightFromParts(68_363_334, 0), + Weight: primitives.WeightFromParts(92_589_999, 0), Class: primitives.NewDispatchClassNormal(), PartialFee: sc.NewU128(0), } @@ -223,7 +223,7 @@ func Test_TransactionPaymentCallApi_QueryCallInfo_Success(t *testing.T) { assert.Nil(t, err) expectedRdi := primitives.RuntimeDispatchInfo{ - Weight: primitives.WeightFromParts(68_363_334, 0), + Weight: primitives.WeightFromParts(92_589_999, 0), Class: primitives.NewDispatchClassNormal(), PartialFee: sc.NewU128(4_288_948_003), } diff --git a/runtime/templates/poa/validate_transaction_test.go b/runtime/templates/poa/validate_transaction_test.go index c16de4ae..d435895f 100644 --- a/runtime/templates/poa/validate_transaction_test.go +++ b/runtime/templates/poa/validate_transaction_test.go @@ -360,12 +360,12 @@ func Test_ValidateTransaction_NoUnsignedValidator(t *testing.T) { args: []any{[]byte{}}, }, { - callName: "Balances.transfer", + callName: "Balances.transfer_allow_death", args: []any{alice, amount}, }, { - callName: "Balances.set_balance", - args: []any{alice, amount, amount}, + callName: "Balances.force_set_balance", + args: []any{alice, amount}, }, { callName: "Balances.force_transfer", @@ -380,7 +380,7 @@ func Test_ValidateTransaction_NoUnsignedValidator(t *testing.T) { args: []any{alice, ctypes.NewBool(false)}, }, { - callName: "Balances.force_free", + callName: "Balances.force_unreserve", args: []any{alice, ctypes.NewU128(*big.NewInt(amount.Int64()))}, }, } diff --git a/runtime/templates/pos/runtime.go b/runtime/templates/pos/runtime.go index 5add075c..21e62e8a 100644 --- a/runtime/templates/pos/runtime.go +++ b/runtime/templates/pos/runtime.go @@ -262,8 +262,8 @@ func initializeModules(storage io.Storage, transactionBroker io.TransactionBroke balancesModule := balances.New( BalancesIndex, balances.NewConfig(storage, DbWeight, BalancesMaxLocks, BalancesMaxReserves, BalancesExistentialDeposit, systemModule), - logger, mdGenerator, + logger, ) tpmModule := transaction_payment.New( diff --git a/testhelpers/testhelpers.go b/testhelpers/testhelpers.go index d6a7e637..153da5c7 100644 --- a/testhelpers/testhelpers.go +++ b/testhelpers/testhelpers.go @@ -146,26 +146,10 @@ var ( dispatchOutcome, _ = primitives.NewDispatchOutcome(nil) dispatchOutcomeBadOriginErr, _ = primitives.NewDispatchOutcome(primitives.NewDispatchErrorBadOrigin()) - dispatchOutcomeCustomModuleErr, _ = primitives.NewDispatchOutcome( - primitives.NewDispatchErrorModule( - primitives.CustomModuleError{ - Index: BalancesIndex, - Err: sc.U32(balances.ErrorInsufficientBalance), - })) - - dispatchOutcomeExistentialDepositErr, _ = primitives.NewDispatchOutcome( - primitives.NewDispatchErrorModule( - primitives.CustomModuleError{ - Index: BalancesIndex, - Err: sc.U32(balances.ErrorExistentialDeposit), - })) - - dispatchOutcomeKeepAliveErr, _ = primitives.NewDispatchOutcome( - primitives.NewDispatchErrorModule( - primitives.CustomModuleError{ - Index: BalancesIndex, - Err: sc.U32(balances.ErrorKeepAlive), - })) + dispatchOutcomeTokenErrorFundsUnavailable, _ = primitives.NewDispatchOutcome( + primitives.NewDispatchErrorToken(primitives.NewTokenErrorFundsUnavailable())) + dispatchOutcomeTokenErrorBelowMinimum, _ = primitives.NewDispatchOutcome( + primitives.NewDispatchErrorToken(primitives.NewTokenErrorBelowMinimum())) dispatchOutcomeSessionNoKeysErr, _ = primitives.NewDispatchOutcome( primitives.NewDispatchErrorModule( @@ -181,15 +165,14 @@ var ( Err: sc.U32(sudo.ErrorRequireSudo), })) - ApplyExtrinsicResultOutcome, _ = primitives.NewApplyExtrinsicResult(dispatchOutcome) - ApplyExtrinsicResultExhaustsResourcesErr, _ = primitives.NewApplyExtrinsicResult(invalidTransactionExhaustsResourcesErr.(primitives.TransactionValidityError)) - ApplyExtrinsicResultBadOriginErr, _ = primitives.NewApplyExtrinsicResult(dispatchOutcomeBadOriginErr) - ApplyExtrinsicResultBadProofErr, _ = primitives.NewApplyExtrinsicResult(invalidTransactionBadProofErr.(primitives.TransactionValidityError)) - ApplyExtrinsicResultCustomModuleErr, _ = primitives.NewApplyExtrinsicResult(dispatchOutcomeCustomModuleErr) - ApplyExtrinsicResultExistentialDepositErr, _ = primitives.NewApplyExtrinsicResult(dispatchOutcomeExistentialDepositErr) - ApplyExtrinsicResultKeepAliveErr, _ = primitives.NewApplyExtrinsicResult(dispatchOutcomeKeepAliveErr) - ApplyExtrinsicResultSessionNoKeysErr, _ = primitives.NewApplyExtrinsicResult(dispatchOutcomeSessionNoKeysErr) - ApplyExtrinsicResultSudoRequireSudoErr, _ = primitives.NewApplyExtrinsicResult(dispatchOutcomeSudoRequireSudoErr) + ApplyExtrinsicResultOutcome, _ = primitives.NewApplyExtrinsicResult(dispatchOutcome) + ApplyExtrinsicResultExhaustsResourcesErr, _ = primitives.NewApplyExtrinsicResult(invalidTransactionExhaustsResourcesErr.(primitives.TransactionValidityError)) + ApplyExtrinsicResultBadOriginErr, _ = primitives.NewApplyExtrinsicResult(dispatchOutcomeBadOriginErr) + ApplyExtrinsicResultBadProofErr, _ = primitives.NewApplyExtrinsicResult(invalidTransactionBadProofErr.(primitives.TransactionValidityError)) + ApplyExtrinsicResultTokenErrorFundsUnavailable, _ = primitives.NewApplyExtrinsicResult(dispatchOutcomeTokenErrorFundsUnavailable) + ApplyExtrinsicResultExistentialDepositErr, _ = primitives.NewApplyExtrinsicResult(dispatchOutcomeTokenErrorBelowMinimum) + ApplyExtrinsicResultSessionNoKeysErr, _ = primitives.NewApplyExtrinsicResult(dispatchOutcomeSessionNoKeysErr) + ApplyExtrinsicResultSudoRequireSudoErr, _ = primitives.NewApplyExtrinsicResult(dispatchOutcomeSudoRequireSudoErr) ) var ( @@ -322,7 +305,7 @@ func SetStorageAccountInfo(t *testing.T, storage *runtime.Storage, account []byt Free: scale.MustNewUint128(freeBalance), Reserved: scale.MustNewUint128(big.NewInt(0)), MiscFrozen: scale.MustNewUint128(big.NewInt(0)), - FreeFrozen: scale.MustNewUint128(big.NewInt(0)), + FreeFrozen: scale.MustNewUint128(primitives.FlagsNewLogic), }, } @@ -337,6 +320,12 @@ func SetStorageAccountInfo(t *testing.T, storage *runtime.Storage, account []byt err = (*storage).Put(keyStorageAccount, bytesStorage) assert.NoError(t, err) + // Set TotalIssuance as well + keyTotalIssuance := append(KeyBalancesHash, KeyTotalIssuanceHash...) + + err = (*storage).Put(keyTotalIssuance, sc.NewU128(freeBalance).Bytes()) + assert.NoError(t, err) + return keyStorageAccount, accountInfo }