neo-go/pkg/smartcontract/context/context_test.go
Roman Khimov db027ad9c5 vm: zero GAS means no GAS, use fee data to properly limit execution
We were accepting transactions with zero system fee, but we shouldn't do
that. Also, transaction's verification execution has to be limited by network
fee.
2020-07-14 08:37:29 +03:00

174 lines
5 KiB
Go

package context
import (
"encoding/hex"
"testing"
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/interop/crypto"
"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/internal/testserdes"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"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/wallet"
"github.com/stretchr/testify/require"
)
func TestParameterContext_AddSignatureSimpleContract(t *testing.T) {
tx := getContractTx()
priv, err := keys.NewPrivateKey()
require.NoError(t, err)
pub := priv.PublicKey()
sig := priv.Sign(tx.GetSignedPart())
t.Run("invalid contract", func(t *testing.T) {
c := NewParameterContext("Neo.Core.ContractTransaction", tx)
ctr := &wallet.Contract{
Script: pub.GetVerificationScript(),
Parameters: []wallet.ContractParam{
newParam(smartcontract.SignatureType, "parameter0"),
newParam(smartcontract.SignatureType, "parameter1"),
},
}
require.Error(t, c.AddSignature(ctr, pub, sig))
if item := c.Items[ctr.ScriptHash()]; item != nil {
require.Nil(t, item.Parameters[0].Value)
}
ctr.Parameters = ctr.Parameters[:0]
require.Error(t, c.AddSignature(ctr, pub, sig))
if item := c.Items[ctr.ScriptHash()]; item != nil {
require.Nil(t, item.Parameters[0].Value)
}
})
c := NewParameterContext("Neo.Core.ContractTransaction", tx)
ctr := &wallet.Contract{
Script: pub.GetVerificationScript(),
Parameters: []wallet.ContractParam{newParam(smartcontract.SignatureType, "parameter0")},
}
require.NoError(t, c.AddSignature(ctr, pub, sig))
item := c.Items[ctr.ScriptHash()]
require.NotNil(t, item)
require.Equal(t, sig, item.Parameters[0].Value)
t.Run("GetWitness", func(t *testing.T) {
w, err := c.GetWitness(ctr)
require.NoError(t, err)
v := newTestVM(w, tx)
require.NoError(t, v.Run())
require.Equal(t, 1, v.Estack().Len())
require.Equal(t, true, v.Estack().Pop().Value())
})
}
func TestParameterContext_AddSignatureMultisig(t *testing.T) {
tx := getContractTx()
c := NewParameterContext("Neo.Core.ContractTransaction", tx)
privs, pubs := getPrivateKeys(t, 4)
pubsCopy := keys.PublicKeys(pubs).Copy()
script, err := smartcontract.CreateMultiSigRedeemScript(3, pubsCopy)
require.NoError(t, err)
ctr := &wallet.Contract{
Script: script,
Parameters: []wallet.ContractParam{
newParam(smartcontract.SignatureType, "parameter0"),
newParam(smartcontract.SignatureType, "parameter1"),
newParam(smartcontract.SignatureType, "parameter2"),
},
}
data := tx.GetSignedPart()
priv, err := keys.NewPrivateKey()
require.NoError(t, err)
sig := priv.Sign(data)
require.Error(t, c.AddSignature(ctr, priv.PublicKey(), sig))
indices := []int{2, 3, 0} // random order
for _, i := range indices {
sig := privs[i].Sign(data)
require.NoError(t, c.AddSignature(ctr, pubs[i], sig))
require.Error(t, c.AddSignature(ctr, pubs[i], sig))
item := c.Items[ctr.ScriptHash()]
require.NotNil(t, item)
require.Equal(t, sig, item.GetSignature(pubs[i]))
}
t.Run("GetWitness", func(t *testing.T) {
w, err := c.GetWitness(ctr)
require.NoError(t, err)
v := newTestVM(w, tx)
require.NoError(t, v.Run())
require.Equal(t, 1, v.Estack().Len())
require.Equal(t, true, v.Estack().Pop().Value())
})
}
func newTestVM(w *transaction.Witness, tx *transaction.Transaction) *vm.VM {
v := vm.New()
v.GasLimit = -1
v.RegisterInteropGetter(crypto.GetInterop(&interop.Context{Container: tx}))
v.LoadScript(w.VerificationScript)
v.LoadScript(w.InvocationScript)
return v
}
func TestParameterContext_MarshalJSON(t *testing.T) {
priv, err := keys.NewPrivateKey()
require.NoError(t, err)
tx := getContractTx()
data := tx.GetSignedPart()
sign := priv.Sign(data)
expected := &ParameterContext{
Type: "Neo.Core.ContractTransaction",
Verifiable: tx,
Items: map[util.Uint160]*Item{
priv.GetScriptHash(): {
Script: priv.GetScriptHash(),
Parameters: []smartcontract.Parameter{{
Type: smartcontract.SignatureType,
Value: sign,
}},
Signatures: map[string][]byte{
hex.EncodeToString(priv.PublicKey().Bytes()): sign,
},
},
},
}
testserdes.MarshalUnmarshalJSON(t, expected, new(ParameterContext))
}
func getPrivateKeys(t *testing.T, n int) ([]*keys.PrivateKey, []*keys.PublicKey) {
privs := make([]*keys.PrivateKey, n)
pubs := make([]*keys.PublicKey, n)
for i := range privs {
var err error
privs[i], err = keys.NewPrivateKey()
require.NoError(t, err)
pubs[i] = privs[i].PublicKey()
}
return privs, pubs
}
func newParam(typ smartcontract.ParamType, name string) wallet.ContractParam {
return wallet.ContractParam{
Name: name,
Type: typ,
}
}
func getContractTx() *transaction.Transaction {
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx.Attributes = make([]transaction.Attribute, 0)
tx.Scripts = make([]transaction.Witness, 0)
tx.Hash()
return tx
}