mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-21 03:30:30 +00:00
b483c38593
We make it explicit in the appropriate Block/Transaction structures, not via a singleton as C# node does. I think this approach has a bit more potential and allows better packages reuse for different purposes.
174 lines
5 KiB
Go
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 := make(keys.PublicKeys, len(pubs))
|
|
copy(pubsCopy, pubs)
|
|
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.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
|
|
}
|