2020-08-03 13:24:22 +00:00
|
|
|
package core
|
|
|
|
|
|
|
|
import (
|
2021-03-05 11:17:58 +00:00
|
|
|
"math"
|
2020-08-03 13:24:22 +00:00
|
|
|
"math/big"
|
2020-08-10 16:16:54 +00:00
|
|
|
"sort"
|
2020-08-03 13:24:22 +00:00
|
|
|
"testing"
|
|
|
|
|
2020-11-23 11:09:00 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/internal/testchain"
|
2020-08-03 13:24:22 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
2020-08-26 10:06:19 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
2020-08-03 13:24:22 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
2020-11-03 15:08:58 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
2020-12-29 10:44:07 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
2020-08-03 13:24:22 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2020-11-03 15:08:58 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
2020-08-26 13:16:57 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
2020-11-19 15:01:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
2020-11-03 15:08:58 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
2020-08-03 13:24:22 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func setSigner(tx *transaction.Transaction, h util.Uint160) {
|
|
|
|
tx.Signers = []transaction.Signer{{
|
|
|
|
Account: h,
|
|
|
|
Scopes: transaction.Global,
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:08:58 +00:00
|
|
|
func checkTxHalt(t *testing.T, bc *Blockchain, h util.Uint256) {
|
2020-11-11 15:43:28 +00:00
|
|
|
aer, err := bc.GetAppExecResults(h, trigger.Application)
|
2020-11-03 15:08:58 +00:00
|
|
|
require.NoError(t, err)
|
2020-11-11 15:43:28 +00:00
|
|
|
require.Equal(t, 1, len(aer))
|
|
|
|
require.Equal(t, vm.HaltState, aer[0].VMState, aer[0].FaultException)
|
2020-11-03 15:08:58 +00:00
|
|
|
}
|
|
|
|
|
2020-08-03 13:24:22 +00:00
|
|
|
func TestNEO_Vote(t *testing.T) {
|
|
|
|
bc := newTestChain(t)
|
|
|
|
|
|
|
|
neo := bc.contracts.NEO
|
2021-03-25 16:18:01 +00:00
|
|
|
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
|
2020-10-29 16:14:49 +00:00
|
|
|
ic := bc.newInteropContext(trigger.Application, bc.dao, nil, tx)
|
2020-10-29 16:10:28 +00:00
|
|
|
ic.SpawnVM()
|
2020-08-26 13:16:57 +00:00
|
|
|
ic.Block = bc.newBlock(tx)
|
2020-08-03 13:24:22 +00:00
|
|
|
|
2020-09-22 10:03:34 +00:00
|
|
|
freq := testchain.ValidatorsCount + testchain.CommitteeSize()
|
|
|
|
advanceChain := func(t *testing.T) {
|
|
|
|
for i := 0; i < freq; i++ {
|
2020-11-03 15:08:58 +00:00
|
|
|
require.NoError(t, bc.AddBlock(bc.newBlock()))
|
2020-09-22 10:03:34 +00:00
|
|
|
ic.Block.Index++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-10 16:16:54 +00:00
|
|
|
standBySorted := bc.GetStandByValidators()
|
|
|
|
sort.Sort(standBySorted)
|
2020-09-22 09:53:44 +00:00
|
|
|
pubs, err := neo.ComputeNextBlockValidators(bc, ic.DAO)
|
2020-08-03 13:24:22 +00:00
|
|
|
require.NoError(t, err)
|
2020-08-10 16:16:54 +00:00
|
|
|
require.Equal(t, standBySorted, pubs)
|
2020-08-03 13:24:22 +00:00
|
|
|
|
2020-11-03 15:08:58 +00:00
|
|
|
sz := testchain.CommitteeSize()
|
|
|
|
accs := make([]*wallet.Account, sz)
|
2020-08-03 13:24:22 +00:00
|
|
|
candidates := make(keys.PublicKeys, sz)
|
2020-11-03 15:08:58 +00:00
|
|
|
txs := make([]*transaction.Transaction, 0, len(accs))
|
2020-08-03 13:24:22 +00:00
|
|
|
for i := 0; i < sz; i++ {
|
|
|
|
priv, err := keys.NewPrivateKey()
|
|
|
|
require.NoError(t, err)
|
|
|
|
candidates[i] = priv.PublicKey()
|
2020-11-03 15:08:58 +00:00
|
|
|
accs[i], err = wallet.NewAccount()
|
|
|
|
require.NoError(t, err)
|
2020-08-03 13:24:22 +00:00
|
|
|
if i > 0 {
|
|
|
|
require.NoError(t, neo.RegisterCandidateInternal(ic, candidates[i]))
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:08:58 +00:00
|
|
|
to := accs[i].Contract.ScriptHash()
|
|
|
|
w := io.NewBufBinWriter()
|
2020-12-29 10:44:07 +00:00
|
|
|
emit.AppCall(w.BinWriter, bc.contracts.NEO.Hash, "transfer", callflag.All,
|
2020-11-03 15:08:58 +00:00
|
|
|
neoOwner.BytesBE(), to.BytesBE(),
|
2020-11-19 15:01:42 +00:00
|
|
|
big.NewInt(int64(sz-i)*1000000).Int64(), nil)
|
2020-11-03 15:08:58 +00:00
|
|
|
emit.Opcodes(w.BinWriter, opcode.ASSERT)
|
2020-12-29 10:44:07 +00:00
|
|
|
emit.AppCall(w.BinWriter, bc.contracts.GAS.Hash, "transfer", callflag.All,
|
2020-11-03 15:08:58 +00:00
|
|
|
neoOwner.BytesBE(), to.BytesBE(),
|
2020-11-19 15:01:42 +00:00
|
|
|
int64(1_000_000_000), nil)
|
2020-11-03 15:08:58 +00:00
|
|
|
emit.Opcodes(w.BinWriter, opcode.ASSERT)
|
|
|
|
require.NoError(t, w.Err)
|
2021-03-25 16:18:01 +00:00
|
|
|
tx := transaction.New(w.Bytes(), 1000_000_000)
|
2020-11-03 15:08:58 +00:00
|
|
|
tx.ValidUntilBlock = bc.BlockHeight() + 1
|
|
|
|
setSigner(tx, testchain.MultisigScriptHash())
|
2020-11-23 11:09:45 +00:00
|
|
|
require.NoError(t, testchain.SignTx(bc, tx))
|
2020-11-03 15:08:58 +00:00
|
|
|
txs = append(txs, tx)
|
|
|
|
}
|
|
|
|
require.NoError(t, bc.AddBlock(bc.newBlock(txs...)))
|
|
|
|
for _, tx := range txs {
|
|
|
|
checkTxHalt(t, bc, tx.Hash())
|
2020-08-03 13:24:22 +00:00
|
|
|
}
|
2020-11-03 15:08:58 +00:00
|
|
|
transferBlock := bc.BlockHeight()
|
2020-08-03 13:24:22 +00:00
|
|
|
|
|
|
|
for i := 1; i < sz; i++ {
|
2020-11-03 15:08:58 +00:00
|
|
|
priv := accs[i].PrivateKey()
|
2020-08-10 06:20:21 +00:00
|
|
|
h := priv.GetScriptHash()
|
2020-08-03 13:24:22 +00:00
|
|
|
setSigner(tx, h)
|
2020-08-10 06:20:21 +00:00
|
|
|
ic.VM.Load(priv.PublicKey().GetVerificationScript())
|
2020-08-03 13:24:22 +00:00
|
|
|
require.NoError(t, neo.VoteInternal(ic, h, candidates[i]))
|
|
|
|
}
|
|
|
|
|
2020-08-10 14:51:46 +00:00
|
|
|
// We still haven't voted enough validators in.
|
2020-09-22 09:53:44 +00:00
|
|
|
pubs, err = neo.ComputeNextBlockValidators(bc, ic.DAO)
|
2020-08-03 13:24:22 +00:00
|
|
|
require.NoError(t, err)
|
2020-08-10 16:16:54 +00:00
|
|
|
require.Equal(t, standBySorted, pubs)
|
2020-08-03 13:24:22 +00:00
|
|
|
|
2020-09-22 10:03:34 +00:00
|
|
|
advanceChain(t)
|
2020-08-28 07:24:54 +00:00
|
|
|
pubs = neo.GetNextBlockValidatorsInternal()
|
2020-08-20 15:49:01 +00:00
|
|
|
require.EqualValues(t, standBySorted, pubs)
|
|
|
|
|
2020-08-03 13:24:22 +00:00
|
|
|
// Register and give some value to the last validator.
|
|
|
|
require.NoError(t, neo.RegisterCandidateInternal(ic, candidates[0]))
|
2020-11-03 15:08:58 +00:00
|
|
|
priv := accs[0].PrivateKey()
|
2020-08-10 06:20:21 +00:00
|
|
|
h := priv.GetScriptHash()
|
2020-08-03 13:24:22 +00:00
|
|
|
setSigner(tx, h)
|
2020-08-10 06:20:21 +00:00
|
|
|
ic.VM.Load(priv.PublicKey().GetVerificationScript())
|
2020-08-03 13:24:22 +00:00
|
|
|
require.NoError(t, neo.VoteInternal(ic, h, candidates[0]))
|
|
|
|
|
2021-05-12 18:34:07 +00:00
|
|
|
_, err = ic.DAO.Persist()
|
|
|
|
require.NoError(t, err)
|
2020-09-22 10:03:34 +00:00
|
|
|
advanceChain(t)
|
2020-09-22 09:53:44 +00:00
|
|
|
pubs, err = neo.ComputeNextBlockValidators(bc, ic.DAO)
|
2020-08-03 13:24:22 +00:00
|
|
|
require.NoError(t, err)
|
2020-11-03 15:08:58 +00:00
|
|
|
sortedCandidates := candidates.Copy()[:testchain.Size()]
|
2020-08-10 16:16:54 +00:00
|
|
|
sort.Sort(sortedCandidates)
|
|
|
|
require.EqualValues(t, sortedCandidates, pubs)
|
2020-08-06 11:57:10 +00:00
|
|
|
|
2020-08-28 07:24:54 +00:00
|
|
|
pubs = neo.GetNextBlockValidatorsInternal()
|
2020-08-20 15:49:01 +00:00
|
|
|
require.EqualValues(t, sortedCandidates, pubs)
|
|
|
|
|
2020-11-03 15:08:58 +00:00
|
|
|
t.Run("check voter rewards", func(t *testing.T) {
|
|
|
|
gasBalance := make([]*big.Int, len(accs))
|
|
|
|
neoBalance := make([]*big.Int, len(accs))
|
|
|
|
txs := make([]*transaction.Transaction, 0, len(accs))
|
|
|
|
for i := range accs {
|
|
|
|
w := io.NewBufBinWriter()
|
|
|
|
h := accs[i].PrivateKey().GetScriptHash()
|
|
|
|
gasBalance[i] = bc.GetUtilityTokenBalance(h)
|
|
|
|
neoBalance[i], _ = bc.GetGoverningTokenBalance(h)
|
2020-12-29 10:44:07 +00:00
|
|
|
emit.AppCall(w.BinWriter, bc.contracts.NEO.Hash, "transfer", callflag.All,
|
2020-11-19 15:01:42 +00:00
|
|
|
h.BytesBE(), h.BytesBE(), int64(1), nil)
|
2020-11-03 15:08:58 +00:00
|
|
|
emit.Opcodes(w.BinWriter, opcode.ASSERT)
|
|
|
|
require.NoError(t, w.Err)
|
2021-03-25 16:18:01 +00:00
|
|
|
tx := transaction.New(w.Bytes(), 0)
|
2020-11-03 15:08:58 +00:00
|
|
|
tx.ValidUntilBlock = bc.BlockHeight() + 1
|
|
|
|
tx.NetworkFee = 2_000_000
|
2020-12-15 09:04:08 +00:00
|
|
|
tx.SystemFee = 11_000_000
|
2020-11-03 15:08:58 +00:00
|
|
|
setSigner(tx, h)
|
2021-03-25 16:18:01 +00:00
|
|
|
require.NoError(t, accs[i].SignTx(netmode.UnitTestNet, tx))
|
2020-11-03 15:08:58 +00:00
|
|
|
txs = append(txs, tx)
|
|
|
|
}
|
|
|
|
require.NoError(t, bc.AddBlock(bc.newBlock(txs...)))
|
|
|
|
for _, tx := range txs {
|
|
|
|
checkTxHalt(t, bc, tx.Hash())
|
|
|
|
}
|
|
|
|
|
|
|
|
// GAS increase consists of 2 parts: NEO holding + voting for committee nodes.
|
|
|
|
// Here we check that 2-nd part exists and is proportional to the amount of NEO given.
|
|
|
|
for i := range accs {
|
|
|
|
newGAS := bc.GetUtilityTokenBalance(accs[i].Contract.ScriptHash())
|
|
|
|
newGAS.Sub(newGAS, gasBalance[i])
|
|
|
|
|
2020-11-06 09:27:05 +00:00
|
|
|
gasForHold, err := bc.contracts.NEO.CalculateNEOHolderReward(bc.dao, neoBalance[i], transferBlock, bc.BlockHeight())
|
|
|
|
require.NoError(t, err)
|
2020-11-03 15:08:58 +00:00
|
|
|
newGAS.Sub(newGAS, gasForHold)
|
|
|
|
require.True(t, newGAS.Sign() > 0)
|
|
|
|
gasBalance[i] = newGAS
|
|
|
|
}
|
|
|
|
// First account voted later than the others.
|
|
|
|
require.Equal(t, -1, gasBalance[0].Cmp(gasBalance[1]))
|
|
|
|
for i := 2; i < testchain.ValidatorsCount; i++ {
|
|
|
|
require.Equal(t, 0, gasBalance[i].Cmp(gasBalance[1]))
|
|
|
|
}
|
|
|
|
require.Equal(t, 1, gasBalance[1].Cmp(gasBalance[testchain.ValidatorsCount]))
|
|
|
|
for i := testchain.ValidatorsCount; i < testchain.CommitteeSize(); i++ {
|
|
|
|
require.Equal(t, 0, gasBalance[i].Cmp(gasBalance[testchain.ValidatorsCount]))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2020-08-06 11:57:10 +00:00
|
|
|
require.NoError(t, neo.UnregisterCandidateInternal(ic, candidates[0]))
|
|
|
|
require.Error(t, neo.VoteInternal(ic, h, candidates[0]))
|
2020-09-22 10:03:34 +00:00
|
|
|
advanceChain(t)
|
2020-08-06 11:57:10 +00:00
|
|
|
|
2020-09-22 09:53:44 +00:00
|
|
|
pubs, err = neo.ComputeNextBlockValidators(bc, ic.DAO)
|
2020-08-06 11:57:10 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
for i := range pubs {
|
|
|
|
require.NotEqual(t, candidates[0], pubs[i])
|
|
|
|
}
|
2020-08-03 13:24:22 +00:00
|
|
|
}
|
2020-08-26 09:07:30 +00:00
|
|
|
|
2020-08-26 10:06:19 +00:00
|
|
|
func TestNEO_SetGasPerBlock(t *testing.T) {
|
|
|
|
bc := newTestChain(t)
|
|
|
|
|
2021-01-28 15:01:30 +00:00
|
|
|
testGetSet(t, bc, bc.contracts.NEO.Hash, "GasPerBlock",
|
|
|
|
5*native.GASFactor, 0, 10*native.GASFactor)
|
2020-08-26 10:06:19 +00:00
|
|
|
}
|
|
|
|
|
2020-08-26 09:07:30 +00:00
|
|
|
func TestNEO_CalculateBonus(t *testing.T) {
|
|
|
|
bc := newTestChain(t)
|
|
|
|
|
|
|
|
neo := bc.contracts.NEO
|
2021-03-25 16:18:01 +00:00
|
|
|
tx := transaction.New([]byte{}, 0)
|
2020-10-29 16:14:49 +00:00
|
|
|
ic := bc.newInteropContext(trigger.Application, bc.dao, nil, tx)
|
2020-09-29 06:56:19 +00:00
|
|
|
ic.SpawnVM()
|
|
|
|
ic.VM.LoadScript([]byte{byte(opcode.RET)})
|
2020-08-26 09:07:30 +00:00
|
|
|
t.Run("Invalid", func(t *testing.T) {
|
2020-11-06 09:27:05 +00:00
|
|
|
_, err := neo.CalculateNEOHolderReward(ic.DAO, new(big.Int).SetInt64(-1), 0, 1)
|
2020-08-26 09:07:30 +00:00
|
|
|
require.Error(t, err)
|
|
|
|
})
|
|
|
|
t.Run("Zero", func(t *testing.T) {
|
2020-11-06 09:27:05 +00:00
|
|
|
res, err := neo.CalculateNEOHolderReward(ic.DAO, big.NewInt(0), 0, 100)
|
2020-08-26 09:07:30 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.EqualValues(t, 0, res.Int64())
|
|
|
|
})
|
2020-08-26 10:06:19 +00:00
|
|
|
t.Run("ManyBlocks", func(t *testing.T) {
|
2020-09-24 12:36:14 +00:00
|
|
|
setSigner(tx, neo.GetCommitteeAddress())
|
2021-01-28 15:01:30 +00:00
|
|
|
err := neo.SetGASPerBlock(ic, 10, big.NewInt(1*native.GASFactor))
|
2020-08-26 10:06:19 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-11-06 09:27:05 +00:00
|
|
|
res, err := neo.CalculateNEOHolderReward(ic.DAO, big.NewInt(100), 5, 15)
|
2020-08-26 10:06:19 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.EqualValues(t, (100*5*5/10)+(100*5*1/10), res.Int64())
|
|
|
|
})
|
2020-08-26 09:07:30 +00:00
|
|
|
}
|
2020-08-26 13:16:57 +00:00
|
|
|
|
2021-05-25 14:54:57 +00:00
|
|
|
func TestNEO_GetAccountState(t *testing.T) {
|
|
|
|
bc := newTestChain(t)
|
|
|
|
|
|
|
|
acc, err := wallet.NewAccount()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
h := acc.Contract.ScriptHash()
|
|
|
|
t.Run("empty", func(t *testing.T) {
|
|
|
|
res, err := invokeContractMethod(bc, 1_0000000, bc.contracts.NEO.Hash, "getAccountState", h)
|
|
|
|
require.NoError(t, err)
|
|
|
|
checkResult(t, res, stackitem.Null{})
|
|
|
|
})
|
|
|
|
|
|
|
|
const amount = 123
|
|
|
|
transferTokenFromMultisigAccountCheckOK(t, bc, h, bc.GoverningTokenHash(), int64(amount))
|
|
|
|
|
|
|
|
t.Run("with funds", func(t *testing.T) {
|
|
|
|
bs := stackitem.NewStruct([]stackitem.Item{
|
|
|
|
stackitem.Make(123),
|
|
|
|
stackitem.Make(bc.BlockHeight()),
|
|
|
|
stackitem.Null{},
|
|
|
|
})
|
|
|
|
res, err := invokeContractMethod(bc, 1_0000000, bc.contracts.NEO.Hash, "getAccountState", h)
|
|
|
|
require.NoError(t, err)
|
|
|
|
checkResult(t, res, bs)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-08-26 13:16:57 +00:00
|
|
|
func TestNEO_CommitteeBountyOnPersist(t *testing.T) {
|
|
|
|
bc := newTestChain(t)
|
|
|
|
|
|
|
|
hs := make([]util.Uint160, testchain.CommitteeSize())
|
|
|
|
for i := range hs {
|
|
|
|
hs[i] = testchain.PrivateKeyByID(i).GetScriptHash()
|
|
|
|
}
|
|
|
|
|
2020-11-06 07:50:45 +00:00
|
|
|
const singleBounty = 50000000
|
2020-09-23 08:48:31 +00:00
|
|
|
bs := map[int]int64{0: singleBounty}
|
2020-08-26 13:16:57 +00:00
|
|
|
checkBalances := func() {
|
|
|
|
for i := 0; i < testchain.CommitteeSize(); i++ {
|
2020-09-23 08:48:31 +00:00
|
|
|
require.EqualValues(t, bs[i], bc.GetUtilityTokenBalance(hs[i]).Int64(), i)
|
2020-08-26 13:16:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for i := 0; i < testchain.CommitteeSize()*2; i++ {
|
|
|
|
require.NoError(t, bc.AddBlock(bc.newBlock()))
|
2020-09-23 08:48:31 +00:00
|
|
|
bs[(i+1)%testchain.CommitteeSize()] += singleBounty
|
2020-08-26 13:16:57 +00:00
|
|
|
checkBalances()
|
|
|
|
}
|
|
|
|
}
|
2020-11-19 15:01:42 +00:00
|
|
|
|
|
|
|
func TestNEO_TransferOnPayment(t *testing.T) {
|
|
|
|
bc := newTestChain(t)
|
|
|
|
|
2020-12-13 15:26:35 +00:00
|
|
|
cs, _ := getTestContractState(bc)
|
|
|
|
require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs))
|
2020-11-19 15:01:42 +00:00
|
|
|
|
|
|
|
const amount = 2
|
2020-11-18 20:10:48 +00:00
|
|
|
tx := transferTokenFromMultisigAccount(t, bc, cs.Hash, bc.contracts.NEO.Hash, amount)
|
2020-11-19 15:01:42 +00:00
|
|
|
aer, err := bc.GetAppExecResults(tx.Hash(), trigger.Application)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, vm.HaltState, aer[0].VMState)
|
2020-12-10 13:52:16 +00:00
|
|
|
require.Len(t, aer[0].Events, 3) // transfer + GAS claim for sender + onPayment
|
2020-11-19 15:01:42 +00:00
|
|
|
|
|
|
|
e := aer[0].Events[2]
|
|
|
|
require.Equal(t, "LastPayment", e.Name)
|
|
|
|
arr := e.Item.Value().([]stackitem.Item)
|
2020-12-10 13:52:16 +00:00
|
|
|
require.Equal(t, bc.contracts.NEO.Hash.BytesBE(), arr[0].Value())
|
|
|
|
require.Equal(t, neoOwner.BytesBE(), arr[1].Value())
|
|
|
|
require.Equal(t, big.NewInt(amount), arr[2].Value())
|
|
|
|
|
|
|
|
tx = transferTokenFromMultisigAccount(t, bc, cs.Hash, bc.contracts.NEO.Hash, amount)
|
|
|
|
aer, err = bc.GetAppExecResults(tx.Hash(), trigger.Application)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, vm.HaltState, aer[0].VMState)
|
|
|
|
// Now we must also have GAS claim for contract and corresponding `onPayment`.
|
|
|
|
require.Len(t, aer[0].Events, 5)
|
|
|
|
|
|
|
|
e = aer[0].Events[2] // onPayment for GAS claim
|
|
|
|
require.Equal(t, "LastPayment", e.Name)
|
|
|
|
arr = e.Item.Value().([]stackitem.Item)
|
|
|
|
require.Equal(t, stackitem.Null{}, arr[1])
|
|
|
|
require.Equal(t, bc.contracts.GAS.Hash.BytesBE(), arr[0].Value())
|
|
|
|
|
|
|
|
e = aer[0].Events[4] // onPayment for NEO transfer
|
|
|
|
require.Equal(t, "LastPayment", e.Name)
|
|
|
|
arr = e.Item.Value().([]stackitem.Item)
|
|
|
|
require.Equal(t, bc.contracts.NEO.Hash.BytesBE(), arr[0].Value())
|
|
|
|
require.Equal(t, neoOwner.BytesBE(), arr[1].Value())
|
|
|
|
require.Equal(t, big.NewInt(amount), arr[2].Value())
|
2020-11-19 15:01:42 +00:00
|
|
|
}
|
2021-03-05 11:17:58 +00:00
|
|
|
|
|
|
|
func TestRegisterPrice(t *testing.T) {
|
|
|
|
bc := newTestChain(t)
|
|
|
|
testGetSet(t, bc, bc.contracts.NEO.Hash, "RegisterPrice",
|
|
|
|
native.DefaultRegisterPrice, 1, math.MaxInt64)
|
|
|
|
}
|
core: do not allow NEP17 roundtrip in case of insufficient funds
NEP17 roundtrip is prohibited if from account doesn't have enough funds.
This commit fixes states diff in block 92057 where account
NfuwpaQ1A2xaeVbxWe8FRtaRgaMa8yF3YM initiates two NEO roundtrips with
amount exceeding the account's balance:
block 92057: value mismatch for key +////xTbYWBH3r5qhRKZAPFPHabKfb2vhQ==: QQMhAkwBIQOZZwEA vs QQMhAkwBIQN/ZwEA
block 92057: value mismatch for key +v///ws=: kqlddcitCg== vs tphddcitCg==
block 92057: value mismatch for key +v///xTbYWBH3r5qhRKZAPFPHabKfb2vhQ==: QQEhBUWyDu0W vs QQEhBWmhDu0W
C#'s applog (contains False and False on stack for both transfers):
```
{
"id" : 1,
"jsonrpc" : "2.0",
"result" : {
"executions" : [
{
"gasconsumed" : "11955500",
"exception" : null,
"stack" : [
{
"value" : false,
"type" : "Boolean"
},
{
"value" : false,
"type" : "Boolean"
}
],
"vmstate" : "HALT",
"trigger" : "Application",
"notifications" : []
}
],
"txid" : "0x8e73a7e9a566a514813907272ad65fc965002c3b098eacc5bdda529af19d7688"
}
}
```
Go's applog (both transfers succeeded and GAS minted):
```
{
"result" : {
"executions" : [
{
"gasconsumed" : "11955500",
"trigger" : "Application",
"stack" : [
{
"type" : "Boolean",
"value" : true
},
{
"type" : "Boolean",
"value" : true
}
],
"vmstate" : "HALT",
"notifications" : [
{
"eventname" : "Transfer",
"contract" : "0xd2a4cff31913016155e38e474a2c06d08be276cf",
"state" : {
"value" : [
{
"type" : "Any"
},
{
"value" : "22FgR96+aoUSmQDxTx2myn29r4U=",
"type" : "ByteString"
},
{
"value" : "4316",
"type" : "Integer"
}
],
"type" : "Array"
}
},
{
"state" : {
"type" : "Array",
"value" : [
{
"value" : "22FgR96+aoUSmQDxTx2myn29r4U=",
"type" : "ByteString"
},
{
"type" : "ByteString",
"value" : "22FgR96+aoUSmQDxTx2myn29r4U="
},
{
"type" : "Integer",
"value" : "1111111111"
}
]
},
"contract" : "0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5",
"eventname" : "Transfer"
},
{
"contract" : "0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5",
"state" : {
"type" : "Array",
"value" : [
{
"value" : "22FgR96+aoUSmQDxTx2myn29r4U=",
"type" : "ByteString"
},
{
"type" : "ByteString",
"value" : "22FgR96+aoUSmQDxTx2myn29r4U="
},
{
"type" : "Integer",
"value" : "1111111"
}
]
},
"eventname" : "Transfer"
}
]
}
],
"txid" : "0x8e73a7e9a566a514813907272ad65fc965002c3b098eacc5bdda529af19d7688"
},
"id" : 1,
"jsonrpc" : "2.0"
}
```
2021-06-09 08:58:58 +00:00
|
|
|
|
|
|
|
func TestNEO_Roundtrip(t *testing.T) {
|
|
|
|
bc := newTestChain(t)
|
|
|
|
initialBalance, initialHeight := bc.GetGoverningTokenBalance(neoOwner)
|
|
|
|
require.NotNil(t, initialBalance)
|
|
|
|
|
|
|
|
t.Run("bad: amount > initial balance", func(t *testing.T) {
|
|
|
|
tx := transferTokenFromMultisigAccountWithAssert(t, bc, neoOwner, bc.contracts.NEO.Hash, initialBalance.Int64()+1, false)
|
|
|
|
aer, err := bc.GetAppExecResults(tx.Hash(), trigger.Application)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, vm.HaltState, aer[0].VMState, aer[0].FaultException) // transfer without assert => HALT state
|
|
|
|
checkResult(t, &aer[0], stackitem.NewBool(false))
|
|
|
|
require.Len(t, aer[0].Events, 0) // failed transfer => no events
|
|
|
|
// check balance and height were not changed
|
|
|
|
updatedBalance, updatedHeight := bc.GetGoverningTokenBalance(neoOwner)
|
|
|
|
require.Equal(t, initialBalance, updatedBalance)
|
|
|
|
require.Equal(t, initialHeight, updatedHeight)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("good: amount == initial balance", func(t *testing.T) {
|
|
|
|
tx := transferTokenFromMultisigAccountWithAssert(t, bc, neoOwner, bc.contracts.NEO.Hash, initialBalance.Int64(), false)
|
|
|
|
aer, err := bc.GetAppExecResults(tx.Hash(), trigger.Application)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, vm.HaltState, aer[0].VMState, aer[0].FaultException)
|
|
|
|
checkResult(t, &aer[0], stackitem.NewBool(true))
|
|
|
|
require.Len(t, aer[0].Events, 2) // roundtrip + GAS claim
|
|
|
|
// check balance wasn't changed and height was updated
|
|
|
|
updatedBalance, updatedHeight := bc.GetGoverningTokenBalance(neoOwner)
|
|
|
|
require.Equal(t, initialBalance, updatedBalance)
|
|
|
|
require.Equal(t, bc.BlockHeight(), updatedHeight)
|
|
|
|
})
|
|
|
|
}
|