8c6de35ec2
Close #2310.
149 lines
6 KiB
Go
149 lines
6 KiB
Go
package core
|
|
|
|
import (
|
|
"math/big"
|
|
"testing"
|
|
|
|
"github.com/nspcc-dev/neo-go/internal/testchain"
|
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
|
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
|
"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/smartcontract/trigger"
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestGAS_Roundtrip(t *testing.T) {
|
|
bc := newTestChain(t)
|
|
|
|
getUtilityTokenBalance := func(bc *Blockchain, acc util.Uint160) (*big.Int, uint32) {
|
|
lub, err := bc.GetTokenLastUpdated(acc)
|
|
require.NoError(t, err)
|
|
return bc.GetUtilityTokenBalance(acc), lub[bc.contracts.GAS.ID]
|
|
}
|
|
|
|
initialBalance, _ := getUtilityTokenBalance(bc, neoOwner)
|
|
require.NotNil(t, initialBalance)
|
|
|
|
t.Run("bad: amount > initial balance", func(t *testing.T) {
|
|
tx := transferTokenFromMultisigAccountWithAssert(t, bc, neoOwner, bc.contracts.GAS.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 := getUtilityTokenBalance(bc, neoOwner)
|
|
initialBalance.Sub(initialBalance, big.NewInt(tx.SystemFee+tx.NetworkFee))
|
|
require.Equal(t, initialBalance, updatedBalance)
|
|
require.Equal(t, bc.BlockHeight(), updatedHeight)
|
|
})
|
|
|
|
t.Run("good: amount < initial balance", func(t *testing.T) {
|
|
amount := initialBalance.Int64() - 10_00000000
|
|
tx := transferTokenFromMultisigAccountWithAssert(t, bc, neoOwner, bc.contracts.GAS.Hash, amount, 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, 1) // roundtrip
|
|
// check balance wasn't changed and height was updated
|
|
updatedBalance, updatedHeight := getUtilityTokenBalance(bc, neoOwner)
|
|
initialBalance.Sub(initialBalance, big.NewInt(tx.SystemFee+tx.NetworkFee))
|
|
require.Equal(t, initialBalance, updatedBalance)
|
|
require.Equal(t, bc.BlockHeight(), updatedHeight)
|
|
})
|
|
}
|
|
|
|
func TestGAS_RewardWithP2PSigExtensionsEnabled(t *testing.T) {
|
|
chain := newTestChain(t)
|
|
notaryHash := chain.contracts.Notary.Hash
|
|
gasHash := chain.contracts.GAS.Hash
|
|
signer := testchain.MultisigScriptHash()
|
|
var err error
|
|
|
|
const (
|
|
nNotaries = 2
|
|
nKeys = 4
|
|
)
|
|
|
|
// set Notary nodes and check their balance
|
|
notaryNodes := make([]*keys.PrivateKey, nNotaries)
|
|
notaryNodesPublicKeys := make(keys.PublicKeys, nNotaries)
|
|
for i := range notaryNodes {
|
|
notaryNodes[i], err = keys.NewPrivateKey()
|
|
require.NoError(t, err)
|
|
notaryNodesPublicKeys[i] = notaryNodes[i].PublicKey()
|
|
}
|
|
chain.setNodesByRole(t, true, noderoles.P2PNotary, notaryNodesPublicKeys)
|
|
for _, notaryNode := range notaryNodesPublicKeys {
|
|
checkBalanceOf(t, chain, notaryNode.GetScriptHash(), 0)
|
|
}
|
|
// deposit GAS for `signer` with lock until the next block
|
|
depositAmount := 100_0000 + (2+int64(nKeys))*transaction.NotaryServiceFeePerKey // sysfee + netfee of the next transaction
|
|
transferTx := transferTokenFromMultisigAccount(t, chain, notaryHash, gasHash, depositAmount, signer, int64(chain.BlockHeight()+1))
|
|
res, err := chain.GetAppExecResults(transferTx.Hash(), trigger.Application)
|
|
require.NoError(t, err)
|
|
require.Equal(t, vm.HaltState, res[0].VMState)
|
|
require.Equal(t, 0, len(res[0].Stack))
|
|
|
|
// save initial validators balance
|
|
balances := make(map[int]int64, testchain.ValidatorsCount)
|
|
for i := 0; i < testchain.ValidatorsCount; i++ {
|
|
balances[i] = chain.GetUtilityTokenBalance(testchain.PrivateKeyByID(i).GetScriptHash()).Int64()
|
|
}
|
|
ic := interop.NewContext(trigger.Application, chain, chain.dao, nil, nil, nil, nil, chain.log)
|
|
tsInitial := chain.contracts.GAS.TotalSupply(ic, nil).Value().(*big.Int).Int64()
|
|
|
|
// send transaction with Notary contract as a sender
|
|
tx := chain.newTestTx(util.Uint160{}, []byte{byte(opcode.PUSH1)})
|
|
tx.Attributes = append(tx.Attributes, transaction.Attribute{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: uint8(nKeys)}})
|
|
tx.NetworkFee = (2 + int64(nKeys)) * transaction.NotaryServiceFeePerKey
|
|
tx.Signers = []transaction.Signer{
|
|
{
|
|
Account: notaryHash,
|
|
Scopes: transaction.None,
|
|
},
|
|
{
|
|
Account: signer,
|
|
Scopes: transaction.None,
|
|
},
|
|
}
|
|
tx.Scripts = []transaction.Witness{
|
|
{
|
|
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, notaryNodes[0].SignHashable(uint32(testchain.Network()), tx)...),
|
|
},
|
|
{
|
|
InvocationScript: testchain.Sign(tx),
|
|
VerificationScript: testchain.MultisigVerificationScript(),
|
|
},
|
|
}
|
|
b := chain.newBlock(tx)
|
|
require.NoError(t, chain.AddBlock(b))
|
|
checkBalanceOf(t, chain, notaryHash, int(depositAmount-tx.SystemFee-tx.NetworkFee))
|
|
singleReward := transaction.NotaryServiceFeePerKey * (nKeys + 1) / nNotaries
|
|
for _, notaryNode := range notaryNodesPublicKeys {
|
|
checkBalanceOf(t, chain, notaryNode.GetScriptHash(), singleReward)
|
|
}
|
|
for i := 0; i < testchain.ValidatorsCount; i++ {
|
|
newBalance := chain.GetUtilityTokenBalance(testchain.PrivateKeyByID(i).GetScriptHash()).Int64()
|
|
expectedBalance := balances[i]
|
|
if i == int(b.Index)%testchain.CommitteeSize() {
|
|
// committee reward
|
|
expectedBalance += 5000_0000
|
|
}
|
|
if testchain.IDToOrder(i) == int(b.PrimaryIndex) {
|
|
// primary reward
|
|
expectedBalance += tx.NetworkFee - int64(singleReward*nNotaries)
|
|
}
|
|
assert.Equal(t, expectedBalance, newBalance, i)
|
|
}
|
|
tsUpdated := chain.contracts.GAS.TotalSupply(ic, nil).Value().(*big.Int).Int64()
|
|
tsExpected := tsInitial + 5000_0000 - tx.SystemFee
|
|
require.Equal(t, tsExpected, tsUpdated)
|
|
}
|