From e834a661179135f478c91abad6743fcaa8ef3e5c Mon Sep 17 00:00:00 2001 From: Alex Vanin Date: Tue, 24 Oct 2023 13:41:54 +0300 Subject: [PATCH] [#45] balance: Fix inconsistent fee of transfer operations Signed-off-by: Alex Vanin --- balance/balance_contract.go | 30 +++++++++++++++++++++++++----- tests/container_test.go | 26 ++++++-------------------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/balance/balance_contract.go b/balance/balance_contract.go index 39118e7..2c5e9aa 100644 --- a/balance/balance_contract.go +++ b/balance/balance_contract.go @@ -31,6 +31,13 @@ type ( // account wasn't burnt. Parent []byte } + + // account is a stored view of Account with fixed int size + account struct { + Balance []byte + Until []byte + Parent []byte + } ) const ( @@ -69,7 +76,7 @@ func _deploy(data interface{}, isUpdate bool) { } args := data.(struct { - //TODO(@acid-ant): #9 remove notaryDisabled in future version + // TODO(@acid-ant): #9 remove notaryDisabled in future version notaryDisabled bool addrNetmap interop.Hash160 addrContainer interop.Hash160 @@ -173,7 +180,7 @@ func Lock(txDetails []byte, from, to interop.Hash160, amount, until int) { Parent: from, } - common.SetSerialized(ctx, to, lockAccount) + setAccount(ctx, to, lockAccount) result := token.transfer(ctx, from, to, amount, true, details) if !result { @@ -310,14 +317,14 @@ func (t Token) transfer(ctx storage.Context, from, to interop.Hash160, amount in storage.Delete(ctx, from) } else { amountFrom.Balance = amountFrom.Balance - amount // neo-go#953 - common.SetSerialized(ctx, from, amountFrom) + setAccount(ctx, from, amountFrom) } } if len(to) == 20 { amountTo := getAccount(ctx, to) amountTo.Balance = amountTo.Balance + amount // neo-go#953 - common.SetSerialized(ctx, to, amountTo) + setAccount(ctx, to, amountTo) } runtime.Notify("Transfer", from, to, amount) @@ -371,8 +378,21 @@ func isUsableAddress(addr interop.Hash160) bool { func getAccount(ctx storage.Context, key interface{}) Account { data := storage.Get(ctx, key) if data != nil { - return std.Deserialize(data.([]byte)).(Account) + acc := std.Deserialize(data.([]byte)).(account) + return Account{ + Balance: common.FromFixedWidth64(acc.Balance), + Until: common.FromFixedWidth64(acc.Until), + Parent: acc.Parent, + } } return Account{} } + +func setAccount(ctx storage.Context, key interface{}, acc Account) { + common.SetSerialized(ctx, key, account{ + Balance: common.ToFixedWidth64(acc.Balance), + Until: common.ToFixedWidth64(acc.Until), + Parent: acc.Parent, + }) +} diff --git a/tests/container_test.go b/tests/container_test.go index 5c115c3..9950db6 100644 --- a/tests/container_test.go +++ b/tests/container_test.go @@ -59,24 +59,6 @@ func newContainerInvoker(t *testing.T) (*neotest.ContractInvoker, *neotest.Contr return e.CommitteeInvoker(ctrContainer.Hash), e.CommitteeInvoker(ctrBalance.Hash), e.CommitteeInvoker(ctrNetmap.Hash) } -// TODO(alexvanin): remove this after fix of inconsistent tx cost in balance contract -func newFreeContainerInvoker(t *testing.T) (*neotest.ContractInvoker, *neotest.ContractInvoker, *neotest.ContractInvoker) { - e := newExecutor(t) - - ctrNNS := neotest.CompileFile(t, e.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml")) - ctrNetmap := neotest.CompileFile(t, e.CommitteeHash, netmapPath, path.Join(netmapPath, "config.yml")) - ctrBalance := neotest.CompileFile(t, e.CommitteeHash, balancePath, path.Join(balancePath, "config.yml")) - ctrContainer := neotest.CompileFile(t, e.CommitteeHash, containerPath, path.Join(containerPath, "config.yml")) - - e.DeployContract(t, ctrNNS, nil) - deployNetmapContract(t, e, ctrBalance.Hash, ctrContainer.Hash, - container.RegistrationFeeKey, int64(0), - container.AliasFeeKey, int64(0)) - deployBalanceContract(t, e, ctrNetmap.Hash, ctrContainer.Hash) - deployContainerContract(t, e, ctrNetmap.Hash, ctrBalance.Hash, ctrNNS.Hash) - return e.CommitteeInvoker(ctrContainer.Hash), e.CommitteeInvoker(ctrBalance.Hash), e.CommitteeInvoker(ctrNetmap.Hash) -} - func setContainerOwner(c []byte, acc neotest.Signer) { copy(c[6:], signerToOwner(acc)) } @@ -253,10 +235,14 @@ func TestContainerPut(t *testing.T) { }) t.Run("gas costs are the same for all containers in block", func(t *testing.T) { - c, _, _ := newFreeContainerInvoker(t) - const containerPerBlock = 512 + const ( + containerPerBlock = 512 + totalContainers = containerPerBlock + 1 + totalPrice = containerFee + containerAliasFee + ) acc := c.NewAccount(t) + balanceMint(t, cBal, acc, totalPrice*totalContainers, []byte{}) cnt := dummyContainer(acc) putArgs := []interface{}{cnt.value, cnt.sig, cnt.pub, cnt.token, "precreated", ""} c.Invoke(t, stackitem.Null{}, "putNamed", putArgs...)