forked from TrueCloudLab/neoneo-go
7589733017
And include some node-specific configurations there with backwards compatibility. Note that in the future we'll remove Ledger's fields from the ProtocolConfiguration and it'll be possible to access them in Blockchain directly (not via .Ledger). The other option tried was using two configuration types separately, but that incurs more changes to the codebase, single structure that behaves almost like the old one is better for backwards compatibility. Fixes #2676.
140 lines
5.4 KiB
Go
140 lines
5.4 KiB
Go
package native_test
|
|
|
|
import (
|
|
"math/big"
|
|
"testing"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
|
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
|
"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/neotest"
|
|
"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func newGasClient(t *testing.T) *neotest.ContractInvoker {
|
|
return newNativeClient(t, nativenames.Gas)
|
|
}
|
|
|
|
func TestGAS_Roundtrip(t *testing.T) {
|
|
c := newGasClient(t)
|
|
e := c.Executor
|
|
gasInvoker := c.WithSigners(c.NewAccount(t))
|
|
owner := gasInvoker.Signers[0].ScriptHash()
|
|
|
|
getUtilityTokenBalance := func(acc util.Uint160) (*big.Int, uint32) {
|
|
lub, err := e.Chain.GetTokenLastUpdated(acc)
|
|
require.NoError(t, err)
|
|
return e.Chain.GetUtilityTokenBalance(acc), lub[e.NativeID(t, nativenames.Gas)]
|
|
}
|
|
|
|
initialBalance, _ := getUtilityTokenBalance(owner)
|
|
require.NotNil(t, initialBalance)
|
|
|
|
t.Run("bad: amount > initial balance", func(t *testing.T) {
|
|
h := gasInvoker.Invoke(t, false, "transfer", owner, owner, initialBalance.Int64()+1, nil)
|
|
tx, height := e.GetTransaction(t, h)
|
|
require.Equal(t, 0, len(e.GetTxExecResult(t, h).Events)) // no events (failed transfer)
|
|
// check balance and height were not changed
|
|
updatedBalance, updatedHeight := getUtilityTokenBalance(owner)
|
|
initialBalance.Sub(initialBalance, big.NewInt(tx.SystemFee+tx.NetworkFee))
|
|
require.Equal(t, initialBalance, updatedBalance)
|
|
require.Equal(t, height, updatedHeight)
|
|
})
|
|
|
|
t.Run("good: amount < initial balance", func(t *testing.T) {
|
|
h := gasInvoker.Invoke(t, true, "transfer", owner, owner, initialBalance.Int64()-1_0000_0000, nil)
|
|
tx, height := e.GetTransaction(t, h)
|
|
require.Equal(t, 1, len(e.GetTxExecResult(t, h).Events)) // roundtrip
|
|
// check balance wasn't changed and height was updated
|
|
updatedBalance, updatedHeight := getUtilityTokenBalance(owner)
|
|
initialBalance.Sub(initialBalance, big.NewInt(tx.SystemFee+tx.NetworkFee))
|
|
require.Equal(t, initialBalance, updatedBalance)
|
|
require.Equal(t, height, updatedHeight)
|
|
})
|
|
}
|
|
|
|
func TestGAS_RewardWithP2PSigExtensionsEnabled(t *testing.T) {
|
|
const (
|
|
nNotaries = 2
|
|
nKeys = 4
|
|
)
|
|
|
|
bc, validator, committee := chain.NewMultiWithCustomConfig(t, func(cfg *config.Blockchain) {
|
|
cfg.P2PSigExtensions = true
|
|
})
|
|
e := neotest.NewExecutor(t, bc, validator, committee)
|
|
gasCommitteeInvoker := e.CommitteeInvoker(e.NativeHash(t, nativenames.Gas))
|
|
notaryHash := e.NativeHash(t, nativenames.Notary)
|
|
notaryServiceFeePerKey := e.Chain.GetNotaryServiceFeePerKey()
|
|
|
|
// transfer funds to committee
|
|
e.ValidatorInvoker(e.NativeHash(t, nativenames.Gas)).Invoke(t, true, "transfer", e.Validator.ScriptHash(), e.CommitteeHash, 1000_0000_0000, nil)
|
|
|
|
// set Notary nodes and check their balance
|
|
notaryNodes := make([]*keys.PrivateKey, nNotaries)
|
|
notaryNodesPublicKeys := make([]interface{}, nNotaries)
|
|
var err error
|
|
for i := range notaryNodes {
|
|
notaryNodes[i], err = keys.NewPrivateKey()
|
|
require.NoError(t, err)
|
|
notaryNodesPublicKeys[i] = notaryNodes[i].PublicKey().Bytes()
|
|
}
|
|
e.CommitteeInvoker(e.NativeHash(t, nativenames.Designation)).Invoke(t, stackitem.Null{}, "designateAsRole", int(noderoles.P2PNotary), notaryNodesPublicKeys)
|
|
for _, notaryNode := range notaryNodes {
|
|
e.CheckGASBalance(t, notaryNode.GetScriptHash(), big.NewInt(0))
|
|
}
|
|
|
|
// deposit GAS for `signer` with lock until the next block
|
|
depositAmount := 100_0000 + (2+int64(nKeys))*notaryServiceFeePerKey // sysfee + netfee of the next transaction
|
|
gasCommitteeInvoker.Invoke(t, true, "transfer", e.CommitteeHash, notaryHash, depositAmount, []interface{}{e.CommitteeHash, e.Chain.BlockHeight() + 1})
|
|
|
|
// save initial GAS total supply
|
|
getGASTS := func(t *testing.T) int64 {
|
|
stack, err := gasCommitteeInvoker.TestInvoke(t, "totalSupply")
|
|
require.NoError(t, err)
|
|
return stack.Pop().Value().(*big.Int).Int64()
|
|
}
|
|
tsInitial := getGASTS(t)
|
|
|
|
// send transaction with Notary contract as a sender
|
|
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 1_000_000)
|
|
tx.Nonce = neotest.Nonce()
|
|
tx.ValidUntilBlock = e.Chain.BlockHeight() + 1
|
|
tx.Attributes = append(tx.Attributes, transaction.Attribute{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: uint8(nKeys)}})
|
|
tx.NetworkFee = (2 + int64(nKeys)) * notaryServiceFeePerKey
|
|
tx.Signers = []transaction.Signer{
|
|
{
|
|
Account: notaryHash,
|
|
Scopes: transaction.None,
|
|
},
|
|
{
|
|
Account: e.CommitteeHash,
|
|
Scopes: transaction.None,
|
|
},
|
|
}
|
|
tx.Scripts = []transaction.Witness{
|
|
{
|
|
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, notaryNodes[0].SignHashable(uint32(e.Chain.GetConfig().Magic), tx)...),
|
|
},
|
|
{
|
|
InvocationScript: e.Committee.SignHashable(uint32(e.Chain.GetConfig().Magic), tx),
|
|
VerificationScript: e.Committee.Script(),
|
|
},
|
|
}
|
|
e.AddNewBlock(t, tx)
|
|
|
|
// check balance of notaries
|
|
e.CheckGASBalance(t, notaryHash, big.NewInt(int64(depositAmount-tx.SystemFee-tx.NetworkFee)))
|
|
for _, notaryNode := range notaryNodes {
|
|
e.CheckGASBalance(t, notaryNode.GetScriptHash(), big.NewInt(notaryServiceFeePerKey*(nKeys+1)/nNotaries))
|
|
}
|
|
tsUpdated := getGASTS(t)
|
|
tsExpected := tsInitial + 5000_0000 - tx.SystemFee
|
|
require.Equal(t, tsExpected, tsUpdated)
|
|
}
|