Merge pull request #2298 from nspcc-dev/test-signer
Improve signers handling in test framework
This commit is contained in:
commit
e6f64b7e3d
3 changed files with 118 additions and 35 deletions
|
@ -72,40 +72,36 @@ func init() {
|
||||||
standByCommittee[4] = hex.EncodeToString(pubs[4].Bytes())
|
standByCommittee[4] = hex.EncodeToString(pubs[4].Bytes())
|
||||||
standByCommittee[5] = hex.EncodeToString(pubs[5].Bytes())
|
standByCommittee[5] = hex.EncodeToString(pubs[5].Bytes())
|
||||||
|
|
||||||
multiValidatorAcc = make([]*wallet.Account, mv)
|
multiValidatorAcc = make([]*wallet.Account, 4)
|
||||||
sort.Sort(pubs[:4])
|
sort.Sort(pubs[:4])
|
||||||
|
|
||||||
vloop:
|
sort.Slice(accs[:4], func(i, j int) bool {
|
||||||
for i := 0; i < mv; i++ {
|
p1 := accs[i].PrivateKey().PublicKey()
|
||||||
for j := range accs {
|
p2 := accs[j].PrivateKey().PublicKey()
|
||||||
if accs[j].PrivateKey().PublicKey().Equal(pubs[i]) {
|
return p1.Cmp(p2) == -1
|
||||||
multiValidatorAcc[i] = wallet.NewAccountFromPrivateKey(accs[j].PrivateKey())
|
})
|
||||||
err := multiValidatorAcc[i].ConvertMultisig(mv, pubs[:4])
|
for i := range multiValidatorAcc {
|
||||||
if err != nil {
|
multiValidatorAcc[i] = wallet.NewAccountFromPrivateKey(accs[i].PrivateKey())
|
||||||
panic(err)
|
err := multiValidatorAcc[i].ConvertMultisig(mv, pubs[:4])
|
||||||
}
|
if err != nil {
|
||||||
continue vloop
|
panic(err)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
panic("invalid committee WIFs")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
multiCommitteeAcc = make([]*wallet.Account, mc)
|
multiCommitteeAcc = make([]*wallet.Account, len(committeeWIFs))
|
||||||
sort.Sort(pubs)
|
sort.Sort(pubs)
|
||||||
|
|
||||||
cloop:
|
sort.Slice(accs, func(i, j int) bool {
|
||||||
for i := 0; i < mc; i++ {
|
p1 := accs[i].PrivateKey().PublicKey()
|
||||||
for j := range accs {
|
p2 := accs[j].PrivateKey().PublicKey()
|
||||||
if accs[j].PrivateKey().PublicKey().Equal(pubs[i]) {
|
return p1.Cmp(p2) == -1
|
||||||
multiCommitteeAcc[i] = wallet.NewAccountFromPrivateKey(accs[j].PrivateKey())
|
})
|
||||||
err := multiCommitteeAcc[i].ConvertMultisig(mc, pubs)
|
for i := range multiCommitteeAcc {
|
||||||
if err != nil {
|
multiCommitteeAcc[i] = wallet.NewAccountFromPrivateKey(accs[i].PrivateKey())
|
||||||
panic(err)
|
err := multiCommitteeAcc[i].ConvertMultisig(mc, pubs)
|
||||||
}
|
if err != nil {
|
||||||
continue cloop
|
panic(err)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
panic("invalid committee WIFs")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package neotest
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
|
@ -27,15 +28,33 @@ type Signer interface {
|
||||||
SignTx(netmode.Magic, *transaction.Transaction) error
|
SignTx(netmode.Magic, *transaction.Transaction) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SingleSigner is a generic interface for simple one-signature signer.
|
||||||
|
type SingleSigner interface {
|
||||||
|
Signer
|
||||||
|
// Account returns underlying account which can be used to
|
||||||
|
// get public key and/or sign arbitrary things.
|
||||||
|
Account() *wallet.Account
|
||||||
|
}
|
||||||
|
|
||||||
|
// MultiSigner is the interface for multisignature signing account.
|
||||||
|
type MultiSigner interface {
|
||||||
|
Signer
|
||||||
|
// Single returns simple-signature signer for n-th account in list.
|
||||||
|
Single(n int) SingleSigner
|
||||||
|
}
|
||||||
|
|
||||||
// signer represents simple-signature signer.
|
// signer represents simple-signature signer.
|
||||||
type signer wallet.Account
|
type signer wallet.Account
|
||||||
|
|
||||||
// multiSigner represents single multi-signature signer consisting of provided accounts.
|
// multiSigner represents single multi-signature signer consisting of provided accounts.
|
||||||
type multiSigner []*wallet.Account
|
type multiSigner struct {
|
||||||
|
accounts []*wallet.Account
|
||||||
|
m int
|
||||||
|
}
|
||||||
|
|
||||||
// NewSingleSigner returns multi-signature signer for the provided account.
|
// NewSingleSigner returns multi-signature signer for the provided account.
|
||||||
// It must contain exactly as many accounts as needed to sign the script.
|
// It must contain exactly as many accounts as needed to sign the script.
|
||||||
func NewSingleSigner(acc *wallet.Account) Signer {
|
func NewSingleSigner(acc *wallet.Account) SingleSigner {
|
||||||
if !vm.IsSignatureContract(acc.Contract.Script) {
|
if !vm.IsSignatureContract(acc.Contract.Script) {
|
||||||
panic("account must have simple-signature verification script")
|
panic("account must have simple-signature verification script")
|
||||||
}
|
}
|
||||||
|
@ -63,9 +82,14 @@ func (s *signer) SignTx(magic netmode.Magic, tx *transaction.Transaction) error
|
||||||
return (*wallet.Account)(s).SignTx(magic, tx)
|
return (*wallet.Account)(s).SignTx(magic, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Account implements SingleSigner interface.
|
||||||
|
func (s *signer) Account() *wallet.Account {
|
||||||
|
return (*wallet.Account)(s)
|
||||||
|
}
|
||||||
|
|
||||||
// NewMultiSigner returns multi-signature signer for the provided account.
|
// NewMultiSigner returns multi-signature signer for the provided account.
|
||||||
// It must contain at least as many accounts as needed to sign the script.
|
// It must contain at least as many accounts as needed to sign the script.
|
||||||
func NewMultiSigner(accs ...*wallet.Account) Signer {
|
func NewMultiSigner(accs ...*wallet.Account) MultiSigner {
|
||||||
if len(accs) == 0 {
|
if len(accs) == 0 {
|
||||||
panic("empty account list")
|
panic("empty account list")
|
||||||
}
|
}
|
||||||
|
@ -78,30 +102,35 @@ func NewMultiSigner(accs ...*wallet.Account) Signer {
|
||||||
panic(fmt.Sprintf("verification script requires %d signatures, "+
|
panic(fmt.Sprintf("verification script requires %d signatures, "+
|
||||||
"but only %d accounts were provided", m, len(accs)))
|
"but only %d accounts were provided", m, len(accs)))
|
||||||
}
|
}
|
||||||
|
sort.Slice(accs, func(i, j int) bool {
|
||||||
|
p1 := accs[i].PrivateKey().PublicKey()
|
||||||
|
p2 := accs[j].PrivateKey().PublicKey()
|
||||||
|
return p1.Cmp(p2) == -1
|
||||||
|
})
|
||||||
for _, acc := range accs {
|
for _, acc := range accs {
|
||||||
if !bytes.Equal(script, acc.Contract.Script) {
|
if !bytes.Equal(script, acc.Contract.Script) {
|
||||||
panic("all accounts must have equal verification script")
|
panic("all accounts must have equal verification script")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return multiSigner(accs[:m])
|
return multiSigner{accounts: accs, m: m}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScriptHash implements Signer interface.
|
// ScriptHash implements Signer interface.
|
||||||
func (m multiSigner) ScriptHash() util.Uint160 {
|
func (m multiSigner) ScriptHash() util.Uint160 {
|
||||||
return m[0].Contract.ScriptHash()
|
return m.accounts[0].Contract.ScriptHash()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Script implements Signer interface.
|
// Script implements Signer interface.
|
||||||
func (m multiSigner) Script() []byte {
|
func (m multiSigner) Script() []byte {
|
||||||
return m[0].Contract.Script
|
return m.accounts[0].Contract.Script
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignHashable implements Signer interface.
|
// SignHashable implements Signer interface.
|
||||||
func (m multiSigner) SignHashable(magic uint32, item hash.Hashable) []byte {
|
func (m multiSigner) SignHashable(magic uint32, item hash.Hashable) []byte {
|
||||||
var script []byte
|
var script []byte
|
||||||
for _, acc := range m {
|
for i := 0; i < m.m; i++ {
|
||||||
sign := acc.PrivateKey().SignHashable(magic, item)
|
sign := m.accounts[i].PrivateKey().SignHashable(magic, item)
|
||||||
script = append(script, byte(opcode.PUSHDATA1), 64)
|
script = append(script, byte(opcode.PUSHDATA1), 64)
|
||||||
script = append(script, sign...)
|
script = append(script, sign...)
|
||||||
}
|
}
|
||||||
|
@ -125,9 +154,19 @@ func (m multiSigner) SignTx(magic netmode.Magic, tx *transaction.Transaction) er
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Single implements MultiSigner interface.
|
||||||
|
func (m multiSigner) Single(n int) SingleSigner {
|
||||||
|
if len(m.accounts) <= n {
|
||||||
|
panic("invalid index")
|
||||||
|
}
|
||||||
|
return NewSingleSigner(wallet.NewAccountFromPrivateKey(m.accounts[n].PrivateKey()))
|
||||||
|
}
|
||||||
|
|
||||||
func checkMultiSigner(t *testing.T, s Signer) {
|
func checkMultiSigner(t *testing.T, s Signer) {
|
||||||
accs, ok := s.(multiSigner)
|
ms, ok := s.(multiSigner)
|
||||||
require.True(t, ok, "expected to be a multi-signer")
|
require.True(t, ok, "expected to be a multi-signer")
|
||||||
|
|
||||||
|
accs := ms.accounts
|
||||||
require.True(t, len(accs) > 0, "empty multi-signer")
|
require.True(t, len(accs) > 0, "empty multi-signer")
|
||||||
|
|
||||||
m := len(accs[0].Contract.Parameters)
|
m := len(accs[0].Contract.Parameters)
|
||||||
|
|
48
pkg/neotest/signer_test.go
Normal file
48
pkg/neotest/signer_test.go
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
package neotest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSingleSigner(t *testing.T) {
|
||||||
|
a, err := wallet.NewAccount()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
s := NewSingleSigner(a)
|
||||||
|
require.Equal(t, s.ScriptHash(), s.Account().Contract.ScriptHash())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMultiSigner(t *testing.T) {
|
||||||
|
const size = 4
|
||||||
|
|
||||||
|
pubs := make(keys.PublicKeys, size)
|
||||||
|
accs := make([]*wallet.Account, size)
|
||||||
|
for i := range accs {
|
||||||
|
a, err := wallet.NewAccount()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
accs[i] = a
|
||||||
|
pubs[i] = a.PrivateKey().PublicKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(pubs)
|
||||||
|
m := smartcontract.GetDefaultHonestNodeCount(size)
|
||||||
|
for i := range accs {
|
||||||
|
require.NoError(t, accs[i].ConvertMultisig(m, pubs))
|
||||||
|
}
|
||||||
|
|
||||||
|
s := NewMultiSigner(accs...)
|
||||||
|
for i := range pubs {
|
||||||
|
for j := range accs {
|
||||||
|
if pub := accs[j].PrivateKey().PublicKey(); pub.Equal(pubs[i]) {
|
||||||
|
require.Equal(t, pub, s.Single(i).Account().PrivateKey().PublicKey())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue