[#45] balance: Fix inconsistent fee of transfer operations

Signed-off-by: Alex Vanin <a.vanin@yadro.com>
This commit is contained in:
Alexey Vanin 2023-10-24 13:41:54 +03:00
parent 5124555f05
commit e834a66117
2 changed files with 31 additions and 25 deletions

View file

@ -31,6 +31,13 @@ type (
// account wasn't burnt. // account wasn't burnt.
Parent []byte Parent []byte
} }
// account is a stored view of Account with fixed int size
account struct {
Balance []byte
Until []byte
Parent []byte
}
) )
const ( const (
@ -173,7 +180,7 @@ func Lock(txDetails []byte, from, to interop.Hash160, amount, until int) {
Parent: from, Parent: from,
} }
common.SetSerialized(ctx, to, lockAccount) setAccount(ctx, to, lockAccount)
result := token.transfer(ctx, from, to, amount, true, details) result := token.transfer(ctx, from, to, amount, true, details)
if !result { if !result {
@ -310,14 +317,14 @@ func (t Token) transfer(ctx storage.Context, from, to interop.Hash160, amount in
storage.Delete(ctx, from) storage.Delete(ctx, from)
} else { } else {
amountFrom.Balance = amountFrom.Balance - amount // neo-go#953 amountFrom.Balance = amountFrom.Balance - amount // neo-go#953
common.SetSerialized(ctx, from, amountFrom) setAccount(ctx, from, amountFrom)
} }
} }
if len(to) == 20 { if len(to) == 20 {
amountTo := getAccount(ctx, to) amountTo := getAccount(ctx, to)
amountTo.Balance = amountTo.Balance + amount // neo-go#953 amountTo.Balance = amountTo.Balance + amount // neo-go#953
common.SetSerialized(ctx, to, amountTo) setAccount(ctx, to, amountTo)
} }
runtime.Notify("Transfer", from, to, amount) runtime.Notify("Transfer", from, to, amount)
@ -371,8 +378,21 @@ func isUsableAddress(addr interop.Hash160) bool {
func getAccount(ctx storage.Context, key interface{}) Account { func getAccount(ctx storage.Context, key interface{}) Account {
data := storage.Get(ctx, key) data := storage.Get(ctx, key)
if data != nil { 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{} 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,
})
}

View file

@ -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) 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) { func setContainerOwner(c []byte, acc neotest.Signer) {
copy(c[6:], signerToOwner(acc)) 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) { t.Run("gas costs are the same for all containers in block", func(t *testing.T) {
c, _, _ := newFreeContainerInvoker(t) const (
const containerPerBlock = 512 containerPerBlock = 512
totalContainers = containerPerBlock + 1
totalPrice = containerFee + containerAliasFee
)
acc := c.NewAccount(t) acc := c.NewAccount(t)
balanceMint(t, cBal, acc, totalPrice*totalContainers, []byte{})
cnt := dummyContainer(acc) cnt := dummyContainer(acc)
putArgs := []interface{}{cnt.value, cnt.sig, cnt.pub, cnt.token, "precreated", ""} putArgs := []interface{}{cnt.value, cnt.sig, cnt.pub, cnt.token, "precreated", ""}
c.Invoke(t, stackitem.Null{}, "putNamed", putArgs...) c.Invoke(t, stackitem.Null{}, "putNamed", putArgs...)