Merge pull request #2181 from nspcc-dev/states-diff_testnet_289026

core: fix NEO balance state handler
This commit is contained in:
Roman Khimov 2021-09-21 15:39:37 +03:00 committed by GitHub
commit 4743d5aacf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 82 additions and 4 deletions

View file

@ -28,6 +28,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
@ -395,6 +396,7 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
},
}
require.NoError(t, addNetworkFee(bc, transferTx, acc0))
transferTx.SystemFee += 1000000
require.NoError(t, acc0.SignTx(testchain.Network(), transferTx))
b = bc.newBlock(initTx, transferTx)
@ -415,6 +417,7 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
},
}
require.NoError(t, addNetworkFee(bc, transferTx, acc0))
transferTx.SystemFee += 1000000
require.NoError(t, acc0.SignTx(testchain.Network(), transferTx))
b = bc.newBlock(transferTx)
@ -603,14 +606,20 @@ func prepareContractMethodInvokeGeneric(chain *Blockchain, sysfee int64,
func signTxWithAccounts(chain *Blockchain, tx *transaction.Transaction, accs ...*wallet.Account) {
scope := transaction.CalledByEntry
for _, acc := range accs {
accH, _ := address.StringToUint160(acc.Address)
tx.Signers = append(tx.Signers, transaction.Signer{
Account: acc.PrivateKey().GetScriptHash(),
Account: accH,
Scopes: scope,
})
scope = transaction.Global
}
size := io.GetVarSize(tx)
for _, acc := range accs {
if acc.Contract.Deployed {
// don't need precise calculation for tests
tx.NetworkFee += 1000_0000
continue
}
netFee, sizeDelta := fee.Calculate(chain.GetBaseExecFee(), acc.Contract.Script)
size += sizeDelta
tx.NetworkFee += netFee

View file

@ -442,6 +442,15 @@ func (n *NEO) distributeGas(ic *interop.Context, h util.Uint160, acc *state.NEOB
return err
}
acc.BalanceHeight = ic.Block.Index
// Must store acc before GAS distribution to fix acc's BalanceHeight value in the storage for
// further acc's queries from `onNEP17Payment` if so, see https://github.com/nspcc-dev/neo-go/pull/2181.
key := makeAccountKey(h)
err = ic.DAO.PutStorageItem(n.ID, key, acc.Bytes())
if err != nil {
return fmt.Errorf("failed to store acc before gas distribution: %w", err)
}
n.GAS.mint(ic, h, gen, true)
return nil
}

View file

@ -195,6 +195,39 @@ func TestNEO_Vote(t *testing.T) {
}
}
// TestNEO_RecursiveDistribution is a test for https://github.com/nspcc-dev/neo-go/pull/2181.
func TestNEO_RecursiveGASMint(t *testing.T) {
bc := newTestChain(t)
initBasicChain(t, bc)
contractHash, err := bc.GetContractScriptHash(1) // deployed rpc/server/testdata/test_contract.go contract
require.NoError(t, err)
tx := transferTokenFromMultisigAccount(t, bc, contractHash, bc.contracts.GAS.Hash, 2_0000_0000)
checkTxHalt(t, bc, tx.Hash())
// Transfer 10 NEO to test contract, the contract should earn some GAS by owning this NEO.
tx = transferTokenFromMultisigAccount(t, bc, contractHash, bc.contracts.NEO.Hash, 10)
res, err := bc.GetAppExecResults(tx.Hash(), trigger.Application)
require.NoError(t, err)
require.Equal(t, vm.HaltState, res[0].VMState)
// Add blocks to be able to trigger NEO transfer from contract address to owner
// address inside onNEP17Payment (the contract starts NEO transfers from chain height = 100).
for i := bc.BlockHeight(); i < 100; i++ {
require.NoError(t, bc.AddBlock(bc.newBlock()))
}
// Transfer 1 more NEO to the contract. Transfer will trigger onNEP17Payment. OnNEP17Payment will
// trigger transfer of 11 NEO to the contract owner (based on the contract code). 11 NEO Transfer will
// trigger GAS distribution. GAS transfer will trigger OnNEP17Payment one more time. The recursion
// shouldn't occur here, because contract's balance LastUpdated height has already been updated in
// this block.
tx = transferTokenFromMultisigAccount(t, bc, contractHash, bc.contracts.NEO.Hash, 1)
res, err = bc.GetAppExecResults(tx.Hash(), trigger.Application)
require.NoError(t, err)
require.Equal(t, vm.HaltState, res[0].VMState, res[0].FaultException)
}
func TestNEO_SetGasPerBlock(t *testing.T) {
bc := newTestChain(t)

View file

@ -54,8 +54,8 @@ type rpcTestCase struct {
check func(t *testing.T, e *executor, result interface{})
}
const testContractHash = "bb6a679438ce0fc6cb0ed1aa85ce83cf96cd3aeb"
const deploymentTxHash = "4c631654b04f6a3b25af45082d260b555de4d0eeba6b7697e3a0f18b3f96434f"
const testContractHash = "5c9e40a12055c6b9e3f72271c9779958c842135d"
const deploymentTxHash = "fefc10d2f7e323282cb50838174b68979b1794c1e5131f2b4737acbc5dde5932"
const genesisBlockHash = "0f8fb4e17d2ab9f3097af75ca7fd16064160fb8043db94909e00dd4e257b9dc4"
const verifyContractHash = "f68822e4ecd93de334bdf1f7c409eda3431bcbd0"
@ -1650,7 +1650,7 @@ func checkNep17Balances(t *testing.T, e *executor, acc interface{}) {
},
{
Asset: e.chain.UtilityTokenHash(),
Amount: "57900879260",
Amount: "57898138260",
LastUpdated: 15,
}},
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),

View file

@ -3,9 +3,12 @@ package testdata
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
"github.com/nspcc-dev/neo-go/pkg/interop/native/neo"
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
"github.com/nspcc-dev/neo-go/pkg/interop/util"
)
const (
@ -13,6 +16,8 @@ const (
decimals = 2
)
var owner = util.FromAddress("NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB")
func Init() bool {
ctx := storage.GetContext()
h := runtime.GetExecutingScriptHash()
@ -22,6 +27,26 @@ func Init() bool {
return true
}
func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) {
curr := runtime.GetExecutingScriptHash()
balance := neo.BalanceOf(curr)
if ledger.CurrentIndex() >= 100 {
ok := neo.Transfer(curr, owner, balance, nil)
if !ok {
panic("owner transfer failed")
}
ok = neo.Transfer(curr, owner, 0, nil)
if !ok {
panic("owner transfer failed")
}
}
}
// Verify always returns true and is aimed to serve the TestNEO_RecursiveGASMint.
func Verify() bool {
return true
}
func Transfer(from, to interop.Hash160, amount int, data interface{}) bool {
ctx := storage.GetContext()
if len(from) != 20 {

View file

@ -11,4 +11,6 @@ events:
- name: amount
type: Integer
permissions:
- hash: ef4073a0f2b305a38ec4050e4d3d28bc40ea63f5
methods: ["transfer"]
- methods: ["onNEP17Payment"]

Binary file not shown.