neo-go/pkg/services/notary/notary_test.go
Roman Khimov 608df7fb21
Merge pull request #1747 from nspcc-dev/default-notary-config
notary: usability improvements
2021-02-17 14:21:47 +03:00

410 lines
12 KiB
Go

package notary
import (
"testing"
"github.com/nspcc-dev/neo-go/internal/fakechain"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/mempool"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
)
func TestWallet(t *testing.T) {
bc := fakechain.NewFakeChain()
mainCfg := config.P2PNotary{Enabled: true}
cfg := Config{
MainCfg: mainCfg,
Chain: bc,
Log: zaptest.NewLogger(t),
}
t.Run("unexisting wallet", func(t *testing.T) {
cfg.MainCfg.UnlockWallet.Path = "./testdata/does_not_exists.json"
_, err := NewNotary(cfg, mempool.New(1, 1, true), nil)
require.Error(t, err)
})
t.Run("bad password", func(t *testing.T) {
cfg.MainCfg.UnlockWallet.Path = "./testdata/notary1.json"
cfg.MainCfg.UnlockWallet.Password = "invalid"
_, err := NewNotary(cfg, mempool.New(1, 1, true), nil)
require.Error(t, err)
})
t.Run("good", func(t *testing.T) {
cfg.MainCfg.UnlockWallet.Path = "./testdata/notary1.json"
cfg.MainCfg.UnlockWallet.Password = "one"
_, err := NewNotary(cfg, mempool.New(1, 1, true), nil)
require.NoError(t, err)
})
}
func TestVerifyIncompleteRequest(t *testing.T) {
bc := fakechain.NewFakeChain()
notaryContractHash := util.Uint160{1, 2, 3}
bc.NotaryContractScriptHash = notaryContractHash
_, ntr, _ := getTestNotary(t, bc, "./testdata/notary1.json", "one")
sig := append([]byte{byte(opcode.PUSHDATA1), 64}, make([]byte, 64)...) // we're not interested in signature correctness
acc1, _ := keys.NewPrivateKey()
acc2, _ := keys.NewPrivateKey()
acc3, _ := keys.NewPrivateKey()
sigScript1 := acc1.PublicKey().GetVerificationScript()
sigScript2 := acc2.PublicKey().GetVerificationScript()
sigScript3 := acc3.PublicKey().GetVerificationScript()
multisigScript1, err := smartcontract.CreateMultiSigRedeemScript(1, keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()})
require.NoError(t, err)
multisigScriptHash1 := hash.Hash160(multisigScript1)
multisigScript2, err := smartcontract.CreateMultiSigRedeemScript(2, keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()})
require.NoError(t, err)
multisigScriptHash2 := hash.Hash160(multisigScript2)
checkErr := func(t *testing.T, tx *transaction.Transaction, nKeys uint8) {
typ, nSigs, pubs, err := ntr.verifyIncompleteWitnesses(tx, nKeys)
require.Error(t, err)
require.Equal(t, Unknown, typ)
require.Equal(t, uint8(0), nSigs)
require.Nil(t, pubs)
}
errCases := map[string]struct {
tx *transaction.Transaction
nKeys uint8
}{
"not enough signers": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: notaryContractHash}},
Scripts: []transaction.Witness{{}},
},
},
"missing Notary witness": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: acc1.GetScriptHash()}, {Account: acc2.GetScriptHash()}},
Scripts: []transaction.Witness{{}, {}},
},
},
"unknown witness type": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: acc1.PublicKey().GetScriptHash()}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{},
{},
},
},
},
"bad verification script": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: acc1.PublicKey().GetScriptHash()}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: []byte{},
VerificationScript: []byte{1, 2, 3},
},
{},
},
},
},
"several multisig witnesses": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: multisigScriptHash2}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: sig,
VerificationScript: multisigScript1,
},
{
InvocationScript: sig,
VerificationScript: multisigScript2,
},
{},
},
},
nKeys: 2,
},
"multisig + sig": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: acc1.PublicKey().GetScriptHash()}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: sig,
VerificationScript: multisigScript1,
},
{
InvocationScript: sig,
VerificationScript: sigScript1,
},
{},
},
},
nKeys: 2,
},
"sig + multisig": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: acc1.PublicKey().GetScriptHash()}, {Account: multisigScriptHash1}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: sig,
VerificationScript: sigScript1,
},
{
InvocationScript: sig,
VerificationScript: multisigScript1,
},
{},
},
},
nKeys: 2,
},
"empty multisig + sig": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: acc1.PublicKey().GetScriptHash()}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: []byte{},
VerificationScript: multisigScript1,
},
{
InvocationScript: sig,
VerificationScript: sigScript1,
},
{},
},
},
nKeys: 2,
},
"sig + empty multisig": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: acc1.PublicKey().GetScriptHash()}, {Account: multisigScriptHash1}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: sig,
VerificationScript: sigScript1,
},
{
InvocationScript: []byte{},
VerificationScript: multisigScript1,
},
{},
},
},
nKeys: 2,
},
"multisig + empty sig": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: acc1.PublicKey().GetScriptHash()}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: sig,
VerificationScript: multisigScript1,
},
{
InvocationScript: []byte{},
VerificationScript: sigScript1,
},
{},
},
},
nKeys: 2,
},
"empty sig + multisig": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: acc1.PublicKey().GetScriptHash()}, {Account: multisigScriptHash1}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: []byte{},
VerificationScript: sigScript1,
},
{
InvocationScript: sig,
VerificationScript: multisigScript1,
},
{},
},
},
nKeys: 2,
},
"sig: bad nKeys": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: acc1.PublicKey().GetScriptHash()}, {Account: acc2.PublicKey().GetScriptHash()}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: sig,
VerificationScript: sigScript1,
},
{
InvocationScript: sig,
VerificationScript: sigScript2,
},
{},
},
},
nKeys: 3,
},
"multisig: bad witnesses count": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: sig,
VerificationScript: multisigScript1,
},
},
},
nKeys: 2,
},
"multisig: bad nKeys": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: sig,
VerificationScript: multisigScript1,
},
{},
},
},
nKeys: 2,
},
}
for name, errCase := range errCases {
t.Run(name, func(t *testing.T) {
checkErr(t, errCase.tx, errCase.nKeys)
})
}
testCases := map[string]struct {
tx *transaction.Transaction
nKeys uint8
expectedType RequestType
expectedNSigs uint8
expectedPubs keys.PublicKeys
}{
"single sig": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: acc1.GetScriptHash()}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: sig,
VerificationScript: sigScript1,
},
{},
},
},
nKeys: 1,
expectedType: Signature,
expectedNSigs: 1,
},
"multiple sig": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: acc1.GetScriptHash()}, {Account: acc2.GetScriptHash()}, {Account: acc3.GetScriptHash()}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: sig,
VerificationScript: sigScript1,
},
{
InvocationScript: []byte{},
VerificationScript: []byte{},
},
{
InvocationScript: sig,
VerificationScript: sigScript3,
},
{},
},
},
nKeys: 3,
expectedType: Signature,
expectedNSigs: 3,
},
"multisig 1 out of 3": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: sig,
VerificationScript: multisigScript1,
},
{},
},
},
nKeys: 3,
expectedType: MultiSignature,
expectedNSigs: 1,
expectedPubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()},
},
"multisig 2 out of 3": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: multisigScriptHash2}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: sig,
VerificationScript: multisigScript2,
},
{},
},
},
nKeys: 3,
expectedType: MultiSignature,
expectedNSigs: 2,
expectedPubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()},
},
"empty + multisig": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: acc1.PublicKey().GetScriptHash()}, {Account: multisigScriptHash1}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: []byte{},
VerificationScript: []byte{},
},
{
InvocationScript: sig,
VerificationScript: multisigScript1,
},
{},
},
},
nKeys: 3,
expectedType: MultiSignature,
expectedNSigs: 1,
expectedPubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()},
},
"multisig + empty": {
tx: &transaction.Transaction{
Signers: []transaction.Signer{{Account: multisigScriptHash1}, {Account: acc1.PublicKey().GetScriptHash()}, {Account: notaryContractHash}},
Scripts: []transaction.Witness{
{
InvocationScript: sig,
VerificationScript: multisigScript1,
},
{
InvocationScript: []byte{},
VerificationScript: []byte{},
},
{},
},
},
nKeys: 3,
expectedType: MultiSignature,
expectedNSigs: 1,
expectedPubs: keys.PublicKeys{acc1.PublicKey(), acc2.PublicKey(), acc3.PublicKey()},
},
}
for name, testCase := range testCases {
t.Run(name, func(t *testing.T) {
typ, nSigs, pubs, err := ntr.verifyIncompleteWitnesses(testCase.tx, testCase.nKeys)
require.NoError(t, err)
assert.Equal(t, testCase.expectedType, typ)
assert.Equal(t, testCase.expectedNSigs, nSigs)
assert.ElementsMatch(t, testCase.expectedPubs, pubs)
})
}
}