forked from TrueCloudLab/neoneo-go
wallet: support creating multisig accounts
(*Account).ConvertMultisig() will convert an existing account into a multisig one.
This commit is contained in:
parent
baa68e1d46
commit
25ffb56982
2 changed files with 76 additions and 0 deletions
|
@ -1,6 +1,7 @@
|
|||
package wallet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
@ -8,6 +9,7 @@ import (
|
|||
|
||||
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
||||
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
||||
"github.com/CityOfZion/neo-go/pkg/encoding/address"
|
||||
"github.com/CityOfZion/neo-go/pkg/smartcontract"
|
||||
"github.com/CityOfZion/neo-go/pkg/util"
|
||||
)
|
||||
|
@ -177,6 +179,34 @@ func NewAccountFromEncryptedWIF(wif string, pass string) (*Account, error) {
|
|||
return a, nil
|
||||
}
|
||||
|
||||
// ConvertMultisig sets a's contract to multisig contract with m sufficient signatures.
|
||||
func (a *Account) ConvertMultisig(m int, pubs []*keys.PublicKey) error {
|
||||
var found bool
|
||||
for i := range pubs {
|
||||
if bytes.Equal(a.publicKey, pubs[i].Bytes()) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return errors.New("own public key was not found among multisig keys")
|
||||
}
|
||||
|
||||
script, err := smartcontract.CreateMultiSigRedeemScript(m, pubs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.Address = address.Uint160ToString(hash.Hash160(script))
|
||||
a.Contract = &Contract{
|
||||
Script: script,
|
||||
Parameters: getContractParams(m),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// newAccountFromPrivateKey creates a wallet from the given PrivateKey.
|
||||
func newAccountFromPrivateKey(p *keys.PrivateKey) *Account {
|
||||
pubKey := p.PublicKey()
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
||||
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
||||
"github.com/CityOfZion/neo-go/pkg/internal/keytestcases"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -87,6 +88,51 @@ func TestContract_ScriptHash(t *testing.T) {
|
|||
require.Equal(t, hash.Hash160(script), c.ScriptHash())
|
||||
}
|
||||
|
||||
func TestAccount_ConvertMultisig(t *testing.T) {
|
||||
// test is based on a wallet1_solo.json accounts from neo-local
|
||||
a, err := NewAccountFromEncryptedWIF("6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y", "one")
|
||||
require.NoError(t, err)
|
||||
|
||||
hexs := []string{
|
||||
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2", // <- this is our key
|
||||
"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e",
|
||||
"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62",
|
||||
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
||||
}
|
||||
|
||||
t.Run("invalid number of signatures", func(t *testing.T) {
|
||||
pubs := convertPubs(t, hexs)
|
||||
require.Error(t, a.ConvertMultisig(0, pubs))
|
||||
})
|
||||
|
||||
t.Run("account key is missing from multisig", func(t *testing.T) {
|
||||
pubs := convertPubs(t, hexs[1:])
|
||||
require.Error(t, a.ConvertMultisig(1, pubs))
|
||||
})
|
||||
|
||||
t.Run("1/1 multisig", func(t *testing.T) {
|
||||
pubs := convertPubs(t, hexs[:1])
|
||||
require.NoError(t, a.ConvertMultisig(1, pubs))
|
||||
require.Equal(t, "AbU69m8WUZJSWanfr1Cy66cpEcsmMcX7BR", a.Address)
|
||||
})
|
||||
|
||||
t.Run("3/4 multisig", func(t *testing.T) {
|
||||
pubs := convertPubs(t, hexs)
|
||||
require.NoError(t, a.ConvertMultisig(3, pubs))
|
||||
require.Equal(t, "AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU", a.Address)
|
||||
})
|
||||
}
|
||||
|
||||
func convertPubs(t *testing.T, hexKeys []string) []*keys.PublicKey {
|
||||
pubs := make([]*keys.PublicKey, len(hexKeys))
|
||||
for i := range pubs {
|
||||
var err error
|
||||
pubs[i], err = keys.NewPublicKeyFromString(hexKeys[i])
|
||||
require.NoError(t, err)
|
||||
}
|
||||
return pubs
|
||||
}
|
||||
|
||||
func compareFields(t *testing.T, tk keytestcases.Ktype, acc *Account) {
|
||||
if want, have := tk.Address, acc.Address; want != have {
|
||||
t.Fatalf("expected %s got %s", want, have)
|
||||
|
|
Loading…
Reference in a new issue