diff --git a/Makefile b/Makefile index ddc23c44..fa083dae 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 + # gossamer node configuration CHAIN_SPEC_PLAIN = ../testdata/chain-spec/plain.json CHAIN_SPEC_UPDATED = ../testdata/chain-spec/plain-updated.json diff --git a/api/benchmarking/module.go b/api/benchmarking/module.go index 68319344..40def768 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 d9f4b766..a774b88b 100644 --- a/api/metadata/module.go +++ b/api/metadata/module.go @@ -281,6 +281,14 @@ func (m Module) basicTypes() sc.Sequence[primitives.MetadataType] { primitives.NewMetadataTypeDefinitionComposite(sc.Sequence[primitives.MetadataTypeDefinitionField]{ primitives.NewMetadataTypeDefinitionField(metadata.TypesFixedSequence32U8)})), + 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]")}, )), @@ -337,8 +345,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( @@ -591,17 +599,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"), @@ -625,6 +633,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/runtime-benchmarks.wasm b/build/runtime-benchmarks.wasm index a6a1ff51..91ad43ea 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 07d6c436..d9bddcf7 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 3070e2fb..1af8d37b 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/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 3526902e..70ad53bd 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() - 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 6dc2cff5..581fb127 100644 --- a/frame/balances/module_test.go +++ b/frame/balances/module_test.go @@ -4,194 +4,218 @@ 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 ( - mockTypeMutateAccountData = mock.AnythingOfType("func(*types.AccountData) (goscale.Encodable, error)") - logger = log.NewLogger() + 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 { + mockStoredMap = new(mocks.StoredMap) + mockTotalIssuance = new(mocks.StorageValue[sc.U128]) + + config := NewConfig(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, err := target.DepositIntoExisting(fromAddress, sc.NewU128(0)) - result, errDeposit := target.DepositIntoExisting(fromAddressId, sc.NewU128(0)) - assert.Nil(t, errDeposit) - - 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() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) + 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) - 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() + target = setupModule() - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - 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", fromAddress).Return(accountInfo, nil) - mockStoredMap.On("Get", fromAddressId).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() - - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) + target = setupModule() - 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), @@ -199,321 +223,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", fromAddress).Return(frozenAccountInfo, nil) - mockStoredMap.On("Get", fromAddressId).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() + target = setupModule() - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - 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 +// func Test_Module_tryMutateAccountHandlingDust_Success(t *testing.T) { +// target = setupModule() - tryMutateResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), sc.NewOption[negativeImbalance](nil), sc.NewOption[sc.U128](nil)) +// 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)) - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) +// mockStoredMap.On("TryMutateExists", fromAddress, mockTypeMutateAccountData).Return(tryMutateResult, nil) - expectedResult := sc.NewVaryingData(sc.NewOption[sc.U128](nil), newDustCleaner(moduleId, fromAddressId, sc.NewOption[negativeImbalance](nil), mockStoredMap)) +// result, err := target.tryMutateAccountHandlingDust(fromAddress, func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { return nil, nil }) - mockStoredMap.On("TryMutateExists", fromAddressId, mockTypeMutateAccountData).Return(tryMutateResult, nil) +// assert.NoError(t, err) +// assert.Equal(t, expectedResult, result) +// mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddress, mockTypeMutateAccountData) +// } - result, err := target.tryMutateAccountWithDust(fromAddressId, func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { return nil, nil }) +// func Test_Module_tryMutateAccountHandlingDust_Success_Endowed(t *testing.T) { +// target = setupModule() - assert.NoError(t, err) - assert.Equal(t, expectedResult, result) - mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddressId, mockTypeMutateAccountData) -} - -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)) +// 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)) - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) - - expectedResult := sc.NewVaryingData(sc.NewOption[sc.U128](targetValue), newDustCleaner(moduleId, fromAddressId, sc.NewOption[negativeImbalance](nil), mockStoredMap)) - - mockStoredMap.On("TryMutateExists", fromAddressId, mockTypeMutateAccountData).Return(tryMutateResult, nil) - mockStoredMap.On("DepositEvent", newEventEndowed(moduleId, fromAddressId, targetValue)) +// mockStoredMap.On("TryMutateExists", fromAddress, mockTypeMutateAccountData).Return(tryMutateResult, nil) +// mockStoredMap.On("DepositEvent", newEventEndowed(moduleId, fromAddress, targetValue)) - 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", fromAddressId, mockTypeMutateAccountData) - mockStoredMap.AssertCalled(t, "DepositEvent", newEventEndowed(moduleId, fromAddressId, targetValue)) -} +// result, err := target.tryMutateAccountHandlingDust(fromAddress, func(who *primitives.AccountData, _ bool) (sc.Encodable, error) { return nil, nil }) -func Test_Module_tryMutateAccountWithDust_TryMutateExists_Fail(t *testing.T) { - target := setupModule() - expectedErr := primitives.NewDispatchErrorCannotLookup() +// assert.NoError(t, err) +// assert.Equal(t, expectedResult, result) +// mockStoredMap.AssertCalled(t, "TryMutateExists", fromAddress, mockTypeMutateAccountData) +// mockStoredMap.AssertCalled(t, "DepositEvent", newEventEndowed(moduleId, fromAddress, targetValue)) +// } - fromAddressId, err := fromAddress.AsAccountId() - assert.Nil(t, err) +func Test_Module_tryMutateAccountHandlingDust_TryMutateExists_Fail(t *testing.T) { + 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) - _, 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) @@ -521,330 +511,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 { - mockStoredMap = new(mocks.StoredMap) - config := NewConfig(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 4b602d24..d3623188 100644 --- a/frame/balances/storage.go +++ b/frame/balances/storage.go @@ -6,16 +6,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() *storage { return &storage{ - TotalIssuance: support.NewHashStorageValue(keyBalances, keyTotalIssuance, sc.DecodeU128), + InactiveIssuance: support.NewHashStorageValue(keyBalances, keyInactiveIssuance, sc.DecodeU128), + TotalIssuance: support.NewHashStorageValue(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 592491d2..5394ef2c 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](prefix []byte, name []byte, keyHashFunc func([]byte) []byte, decodeFunc func(buffer *bytes.Buffer) (V, error)) StorageMap[K, V] { + return NewHashStorageMapWithDefault[K, V](prefix, name, keyHashFunc, decodeFunc, nil) +} + +func NewHashStorageMapWithDefault[K, V sc.Encodable](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](decodeFunc, nil), + newBaseStorage[V](decodeFunc, defaultValue), prefix, name, keyHashFunc, @@ -29,7 +33,7 @@ func NewHashStorageMap[K, V sc.Encodable](prefix []byte, name []byte, keyHashFun } 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 0ea51704..19a09fe2 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) TryMutateExists(who primitives.AccountId, f func(who *primitives.AccountData) (sc.Encodable, error)) (sc.Encodable, error) Metadata() primitives.MetadataModule @@ -473,13 +475,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 } @@ -488,31 +488,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 @@ -583,6 +573,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 +} + func (m module) decrementProviders(who primitives.AccountId, maybeAccount *sc.Option[primitives.AccountInfo]) (sc.Encodable, error) { if maybeAccount.HasValue { account := &maybeAccount.Value @@ -624,7 +628,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) }) @@ -1081,7 +1085,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 6f3b85d6..4edb60a2 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) @@ -811,6 +811,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) @@ -818,157 +819,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) { @@ -992,71 +844,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() @@ -1379,17 +1166,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, @@ -1417,10 +1204,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{ @@ -1428,7 +1215,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 acb56471..13a7ebc4 100644 --- a/frame/system/storage.go +++ b/frame/system/storage.go @@ -54,9 +54,10 @@ type storage struct { func newStorage() *storage { hashing := io.NewHashing() + defaultAccountInfo := types.DefaultAccountInfo() return &storage{ - Account: support.NewHashStorageMap[types.AccountId](keySystem, keyAccount, hashing.Blake128, types.DecodeAccountInfo), + Account: support.NewHashStorageMapWithDefault[types.AccountId](keySystem, keyAccount, hashing.Blake128, types.DecodeAccountInfo, &defaultAccountInfo), BlockWeight: support.NewHashStorageValue(keySystem, keyBlockWeight, types.DecodeConsumedWeight), BlockHash: support.NewHashStorageMap[sc.U64, types.Blake2bHash](keySystem, keyBlockHash, hashing.Twox64, types.DecodeBlake2bHash), BlockNumber: support.NewHashStorageValue(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 24947b19..a027789f 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) Metadata() primitives.MetadataModule { args := m.Called() return args.Get(0).(primitives.MetadataModule) 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 f5e3244b..f49e95c2 100644 --- a/primitives/types/metadata_generator.go +++ b/primitives/types/metadata_generator.go @@ -11,7 +11,7 @@ import ( ) const ( - lastAvailableIndex = 148 + 22 + 5 // the last enum id from constants/metadata.go + lastAvailableIndex = 180 // the last enum id from constants/metadata.go ) const ( @@ -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/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 3d5b8d58..40f05e8d 100644 --- a/runtime/templates/poa/runtime.go +++ b/runtime/templates/poa/runtime.go @@ -194,8 +194,8 @@ func initializeModules() []primitives.Module { balancesModule := balances.New( BalancesIndex, balances.NewConfig(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 36dcca74..5d63e10e 100644 --- a/runtime/templates/pos/runtime.go +++ b/runtime/templates/pos/runtime.go @@ -254,8 +254,8 @@ func initializeModules() []primitives.Module { balancesModule := balances.New( BalancesIndex, balances.NewConfig(DbWeight, BalancesMaxLocks, BalancesMaxReserves, BalancesExistentialDeposit, systemModule), - logger, mdGenerator, + logger, ) tpmModule := transaction_payment.New( diff --git a/testhelpers/testhelpers.go b/testhelpers/testhelpers.go index 5b92480a..22387753 100644 --- a/testhelpers/testhelpers.go +++ b/testhelpers/testhelpers.go @@ -7,8 +7,6 @@ import ( "math/big" "testing" - "github.com/LimeChain/gosemble/frame/sudo" - gossamertypes "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/crypto/secp256k1" @@ -19,6 +17,7 @@ import ( sc "github.com/LimeChain/goscale" "github.com/LimeChain/gosemble/frame/balances" "github.com/LimeChain/gosemble/frame/session" + "github.com/LimeChain/gosemble/frame/sudo" "github.com/LimeChain/gosemble/frame/system" "github.com/LimeChain/gosemble/frame/transaction_payment" babetypes "github.com/LimeChain/gosemble/primitives/babe" @@ -145,26 +144,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( @@ -180,15 +163,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 ( @@ -310,7 +292,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), }, } @@ -325,6 +307,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 }