Merge pull request #2181 from nspcc-dev/states-diff_testnet_289026
core: fix NEO balance state handler
This commit is contained in:
commit
4743d5aacf
7 changed files with 82 additions and 4 deletions
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
"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/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"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/encoding/fixedn"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"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))
|
require.NoError(t, addNetworkFee(bc, transferTx, acc0))
|
||||||
|
transferTx.SystemFee += 1000000
|
||||||
require.NoError(t, acc0.SignTx(testchain.Network(), transferTx))
|
require.NoError(t, acc0.SignTx(testchain.Network(), transferTx))
|
||||||
|
|
||||||
b = bc.newBlock(initTx, transferTx)
|
b = bc.newBlock(initTx, transferTx)
|
||||||
|
@ -415,6 +417,7 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
require.NoError(t, addNetworkFee(bc, transferTx, acc0))
|
require.NoError(t, addNetworkFee(bc, transferTx, acc0))
|
||||||
|
transferTx.SystemFee += 1000000
|
||||||
require.NoError(t, acc0.SignTx(testchain.Network(), transferTx))
|
require.NoError(t, acc0.SignTx(testchain.Network(), transferTx))
|
||||||
|
|
||||||
b = bc.newBlock(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) {
|
func signTxWithAccounts(chain *Blockchain, tx *transaction.Transaction, accs ...*wallet.Account) {
|
||||||
scope := transaction.CalledByEntry
|
scope := transaction.CalledByEntry
|
||||||
for _, acc := range accs {
|
for _, acc := range accs {
|
||||||
|
accH, _ := address.StringToUint160(acc.Address)
|
||||||
tx.Signers = append(tx.Signers, transaction.Signer{
|
tx.Signers = append(tx.Signers, transaction.Signer{
|
||||||
Account: acc.PrivateKey().GetScriptHash(),
|
Account: accH,
|
||||||
Scopes: scope,
|
Scopes: scope,
|
||||||
})
|
})
|
||||||
scope = transaction.Global
|
scope = transaction.Global
|
||||||
}
|
}
|
||||||
size := io.GetVarSize(tx)
|
size := io.GetVarSize(tx)
|
||||||
for _, acc := range accs {
|
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)
|
netFee, sizeDelta := fee.Calculate(chain.GetBaseExecFee(), acc.Contract.Script)
|
||||||
size += sizeDelta
|
size += sizeDelta
|
||||||
tx.NetworkFee += netFee
|
tx.NetworkFee += netFee
|
||||||
|
|
|
@ -442,6 +442,15 @@ func (n *NEO) distributeGas(ic *interop.Context, h util.Uint160, acc *state.NEOB
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
acc.BalanceHeight = ic.Block.Index
|
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)
|
n.GAS.mint(ic, h, gen, true)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
func TestNEO_SetGasPerBlock(t *testing.T) {
|
||||||
bc := newTestChain(t)
|
bc := newTestChain(t)
|
||||||
|
|
||||||
|
|
|
@ -54,8 +54,8 @@ type rpcTestCase struct {
|
||||||
check func(t *testing.T, e *executor, result interface{})
|
check func(t *testing.T, e *executor, result interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
const testContractHash = "bb6a679438ce0fc6cb0ed1aa85ce83cf96cd3aeb"
|
const testContractHash = "5c9e40a12055c6b9e3f72271c9779958c842135d"
|
||||||
const deploymentTxHash = "4c631654b04f6a3b25af45082d260b555de4d0eeba6b7697e3a0f18b3f96434f"
|
const deploymentTxHash = "fefc10d2f7e323282cb50838174b68979b1794c1e5131f2b4737acbc5dde5932"
|
||||||
const genesisBlockHash = "0f8fb4e17d2ab9f3097af75ca7fd16064160fb8043db94909e00dd4e257b9dc4"
|
const genesisBlockHash = "0f8fb4e17d2ab9f3097af75ca7fd16064160fb8043db94909e00dd4e257b9dc4"
|
||||||
|
|
||||||
const verifyContractHash = "f68822e4ecd93de334bdf1f7c409eda3431bcbd0"
|
const verifyContractHash = "f68822e4ecd93de334bdf1f7c409eda3431bcbd0"
|
||||||
|
@ -1650,7 +1650,7 @@ func checkNep17Balances(t *testing.T, e *executor, acc interface{}) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Asset: e.chain.UtilityTokenHash(),
|
Asset: e.chain.UtilityTokenHash(),
|
||||||
Amount: "57900879260",
|
Amount: "57898138260",
|
||||||
LastUpdated: 15,
|
LastUpdated: 15,
|
||||||
}},
|
}},
|
||||||
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),
|
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),
|
||||||
|
|
25
pkg/rpc/server/testdata/test_contract.go
vendored
25
pkg/rpc/server/testdata/test_contract.go
vendored
|
@ -3,9 +3,12 @@ package testdata
|
||||||
import (
|
import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
"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/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/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/runtime"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -13,6 +16,8 @@ const (
|
||||||
decimals = 2
|
decimals = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var owner = util.FromAddress("NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB")
|
||||||
|
|
||||||
func Init() bool {
|
func Init() bool {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
h := runtime.GetExecutingScriptHash()
|
h := runtime.GetExecutingScriptHash()
|
||||||
|
@ -22,6 +27,26 @@ func Init() bool {
|
||||||
return true
|
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 {
|
func Transfer(from, to interop.Hash160, amount int, data interface{}) bool {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
if len(from) != 20 {
|
if len(from) != 20 {
|
||||||
|
|
2
pkg/rpc/server/testdata/test_contract.yml
vendored
2
pkg/rpc/server/testdata/test_contract.yml
vendored
|
@ -11,4 +11,6 @@ events:
|
||||||
- name: amount
|
- name: amount
|
||||||
type: Integer
|
type: Integer
|
||||||
permissions:
|
permissions:
|
||||||
|
- hash: ef4073a0f2b305a38ec4050e4d3d28bc40ea63f5
|
||||||
|
methods: ["transfer"]
|
||||||
- methods: ["onNEP17Payment"]
|
- methods: ["onNEP17Payment"]
|
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
Binary file not shown.
Loading…
Reference in a new issue