forked from TrueCloudLab/neoneo-go
Merge pull request #2672 from nspcc-dev/private-key-cleanup
Private key cleanup
This commit is contained in:
commit
3da8b98fc3
52 changed files with 337 additions and 234 deletions
|
@ -199,10 +199,7 @@ func ParseParams(args []string, calledFromMain bool) (int, []smartcontract.Param
|
||||||
// accounts from the provided wallet.
|
// accounts from the provided wallet.
|
||||||
func GetSignersAccounts(senderAcc *wallet.Account, wall *wallet.Wallet, signers []transaction.Signer, accScope transaction.WitnessScope) ([]actor.SignerAccount, error) {
|
func GetSignersAccounts(senderAcc *wallet.Account, wall *wallet.Wallet, signers []transaction.Signer, accScope transaction.WitnessScope) ([]actor.SignerAccount, error) {
|
||||||
signersAccounts := make([]actor.SignerAccount, 0, len(signers)+1)
|
signersAccounts := make([]actor.SignerAccount, 0, len(signers)+1)
|
||||||
sender, err := address.StringToUint160(senderAcc.Address)
|
sender := senderAcc.ScriptHash()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
signersAccounts = append(signersAccounts, actor.SignerAccount{
|
signersAccounts = append(signersAccounts, actor.SignerAccount{
|
||||||
Signer: transaction.Signer{
|
Signer: transaction.Signer{
|
||||||
Account: sender,
|
Account: sender,
|
||||||
|
|
|
@ -802,7 +802,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pk, err := keys.NewPrivateKey()
|
pk, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = acc.ConvertMultisig(2, keys.PublicKeys{acc.PrivateKey().PublicKey(), pk.PublicKey()})
|
err = acc.ConvertMultisig(2, keys.PublicKeys{acc.PublicKey(), pk.PublicKey()})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("cosigner is multisig account", func(t *testing.T) {
|
t.Run("cosigner is multisig account", func(t *testing.T) {
|
||||||
|
|
|
@ -162,8 +162,7 @@ func TestNEP17Transfer(t *testing.T) {
|
||||||
e.checkNextLine(t, `^Total fee:\s*(\d|\.)+`)
|
e.checkNextLine(t, `^Total fee:\s*(\d|\.)+`)
|
||||||
e.checkTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
sh, err := address.StringToUint160(w.Accounts[0].Address)
|
sh := w.Accounts[0].ScriptHash()
|
||||||
require.NoError(t, err)
|
|
||||||
b, _ := e.Chain.GetGoverningTokenBalance(sh)
|
b, _ := e.Chain.GetGoverningTokenBalance(sh)
|
||||||
require.Equal(t, big.NewInt(1), b)
|
require.Equal(t, big.NewInt(1), b)
|
||||||
|
|
||||||
|
@ -172,8 +171,6 @@ func TestNEP17Transfer(t *testing.T) {
|
||||||
e.Run(t, append(args, "--force")...)
|
e.Run(t, append(args, "--force")...)
|
||||||
e.checkTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
sh, err := address.StringToUint160(w.Accounts[0].Address)
|
|
||||||
require.NoError(t, err)
|
|
||||||
b, _ := e.Chain.GetGoverningTokenBalance(sh)
|
b, _ := e.Chain.GetGoverningTokenBalance(sh)
|
||||||
require.Equal(t, big.NewInt(2), b)
|
require.Equal(t, big.NewInt(2), b)
|
||||||
})
|
})
|
||||||
|
@ -198,8 +195,6 @@ func TestNEP17Transfer(t *testing.T) {
|
||||||
e.Run(t, args...)
|
e.Run(t, args...)
|
||||||
e.checkTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
sh, err := address.StringToUint160(w.Accounts[0].Address)
|
|
||||||
require.NoError(t, err)
|
|
||||||
b, _ := e.Chain.GetGoverningTokenBalance(sh)
|
b, _ := e.Chain.GetGoverningTokenBalance(sh)
|
||||||
require.Equal(t, big.NewInt(3), b)
|
require.Equal(t, big.NewInt(3), b)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/context"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/context"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
)
|
)
|
||||||
|
@ -18,14 +17,8 @@ import (
|
||||||
func InitAndSave(net netmode.Magic, tx *transaction.Transaction, acc *wallet.Account, filename string) error {
|
func InitAndSave(net netmode.Magic, tx *transaction.Transaction, acc *wallet.Account, filename string) error {
|
||||||
scCtx := context.NewParameterContext("Neo.Network.P2P.Payloads.Transaction", net, tx)
|
scCtx := context.NewParameterContext("Neo.Network.P2P.Payloads.Transaction", net, tx)
|
||||||
if acc != nil && acc.CanSign() {
|
if acc != nil && acc.CanSign() {
|
||||||
priv := acc.PrivateKey()
|
sign := acc.SignHashable(net, tx)
|
||||||
pub := priv.PublicKey()
|
if err := scCtx.AddSignature(acc.ScriptHash(), acc.Contract, acc.PublicKey(), sign); err != nil {
|
||||||
sign := priv.SignHashable(uint32(net), tx)
|
|
||||||
h, err := address.StringToUint160(acc.Address)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("invalid address: %s", acc.Address)
|
|
||||||
}
|
|
||||||
if err := scCtx.AddSignature(h, acc.Contract, pub, sign); err != nil {
|
|
||||||
return fmt.Errorf("can't add signature: %w", err)
|
return fmt.Errorf("can't add signature: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,15 +37,16 @@ func manifestAddGroup(ctx *cli.Context) error {
|
||||||
|
|
||||||
h := state.CreateContractHash(sender, nf.Checksum, m.Name)
|
h := state.CreateContractHash(sender, nf.Checksum, m.Name)
|
||||||
|
|
||||||
gAcc, _, err := getAccFromContext(ctx)
|
gAcc, w, err := getAccFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("can't get account to sign group with: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't get account to sign group with: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
var found bool
|
var found bool
|
||||||
|
|
||||||
sig := gAcc.PrivateKey().Sign(h.BytesBE())
|
sig := gAcc.PrivateKey().Sign(h.BytesBE())
|
||||||
pub := gAcc.PrivateKey().PublicKey()
|
pub := gAcc.PublicKey()
|
||||||
for i := range m.Groups {
|
for i := range m.Groups {
|
||||||
if m.Groups[i].PublicKey.Equal(pub) {
|
if m.Groups[i].PublicKey.Equal(pub) {
|
||||||
m.Groups[i].Signature = sig
|
m.Groups[i].Signature = sig
|
||||||
|
|
|
@ -650,6 +650,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer w.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = invokeWithArgs(ctx, acc, w, script, operation, params, cosigners)
|
_, err = invokeWithArgs(ctx, acc, w, script, operation, params, cosigners)
|
||||||
|
@ -892,7 +893,7 @@ func getUnlockedAccount(wall *wallet.Wallet, addr util.Uint160, pass *string) (*
|
||||||
return nil, fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr))
|
return nil, fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr))
|
||||||
}
|
}
|
||||||
|
|
||||||
if acc.PrivateKey() != nil {
|
if acc.CanSign() {
|
||||||
return acc, nil
|
return acc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -949,6 +950,7 @@ func contractDeploy(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
cosigners, sgnErr := cmdargs.GetSignersFromContext(ctx, signOffset)
|
cosigners, sgnErr := cmdargs.GetSignersFromContext(ctx, signOffset)
|
||||||
if sgnErr != nil {
|
if sgnErr != nil {
|
||||||
|
|
|
@ -25,6 +25,7 @@ func signStoredTransaction(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
pc, err := paramcontext.Read(ctx.String("in"))
|
pc, err := paramcontext.Read(ctx.String("in"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -58,9 +59,8 @@ func signStoredTransaction(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if acc.CanSign() {
|
if acc.CanSign() {
|
||||||
priv := acc.PrivateKey()
|
sign := acc.SignHashable(pc.Network, pc.Verifiable)
|
||||||
sign := priv.SignHashable(uint32(pc.Network), pc.Verifiable)
|
if err := pc.AddSignature(ch, acc.Contract, acc.PublicKey(), sign); err != nil {
|
||||||
if err := pc.AddSignature(ch, acc.Contract, priv.PublicKey(), sign); err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("can't add signature: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't add signature: %w", err), 1)
|
||||||
}
|
}
|
||||||
} else if rpcNode == "" {
|
} else if rpcNode == "" {
|
||||||
|
|
|
@ -222,6 +222,7 @@ func getNEPBalance(ctx *cli.Context, standard string, accHandler func(*cli.Conte
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("bad wallet: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("bad wallet: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
addrFlag := ctx.Generic("address").(*flags.Address)
|
addrFlag := ctx.Generic("address").(*flags.Address)
|
||||||
if addrFlag.IsSet {
|
if addrFlag.IsSet {
|
||||||
|
@ -286,17 +287,12 @@ func getNEPBalance(ctx *cli.Context, standard string, accHandler func(*cli.Conte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for k, acc := range accounts {
|
for k, acc := range accounts {
|
||||||
addrHash, err := address.StringToUint160(acc.Address)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("invalid account address: %w", err), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if k != 0 {
|
if k != 0 {
|
||||||
fmt.Fprintln(ctx.App.Writer)
|
fmt.Fprintln(ctx.App.Writer)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(ctx.App.Writer, "Account %s\n", acc.Address)
|
fmt.Fprintf(ctx.App.Writer, "Account %s\n", acc.Address)
|
||||||
|
|
||||||
err = accHandler(ctx, c, addrHash, name, token, tokenID)
|
err = accHandler(ctx, c, acc.ScriptHash(), name, token, tokenID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -392,6 +388,7 @@ func importNEPToken(ctx *cli.Context, standard string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
tokenHashFlag := ctx.Generic("token").(*flags.Address)
|
tokenHashFlag := ctx.Generic("token").(*flags.Address)
|
||||||
if !tokenHashFlag.IsSet {
|
if !tokenHashFlag.IsSet {
|
||||||
|
@ -460,6 +457,7 @@ func printNEPInfo(ctx *cli.Context, standard string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
if name := ctx.String("token"); name != "" {
|
if name := ctx.String("token"); name != "" {
|
||||||
token, err := getMatchingToken(ctx, wall, name, standard)
|
token, err := getMatchingToken(ctx, wall, name, standard)
|
||||||
|
@ -495,6 +493,7 @@ func removeNEPToken(ctx *cli.Context, standard string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
token, err := getMatchingToken(ctx, wall, ctx.String("token"), standard)
|
token, err := getMatchingToken(ctx, wall, ctx.String("token"), standard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -518,6 +517,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
fromFlag := ctx.Generic("from").(*flags.Address)
|
fromFlag := ctx.Generic("from").(*flags.Address)
|
||||||
from, err := getDefaultAddress(fromFlag, wall)
|
from, err := getDefaultAddress(fromFlag, wall)
|
||||||
|
@ -613,6 +613,7 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
fromFlag := ctx.Generic("from").(*flags.Address)
|
fromFlag := ctx.Generic("from").(*flags.Address)
|
||||||
from, err := getDefaultAddress(fromFlag, wall)
|
from, err := getDefaultAddress(fromFlag, wall)
|
||||||
|
|
|
@ -76,13 +76,13 @@ func newValidatorCommands() []cli.Command {
|
||||||
|
|
||||||
func handleRegister(ctx *cli.Context) error {
|
func handleRegister(ctx *cli.Context) error {
|
||||||
return handleNeoAction(ctx, func(contract *neo.Contract, _ util.Uint160, acc *wallet.Account) (*transaction.Transaction, error) {
|
return handleNeoAction(ctx, func(contract *neo.Contract, _ util.Uint160, acc *wallet.Account) (*transaction.Transaction, error) {
|
||||||
return contract.RegisterCandidateUnsigned(acc.PrivateKey().PublicKey())
|
return contract.RegisterCandidateUnsigned(acc.PublicKey())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleUnregister(ctx *cli.Context) error {
|
func handleUnregister(ctx *cli.Context) error {
|
||||||
return handleNeoAction(ctx, func(contract *neo.Contract, _ util.Uint160, acc *wallet.Account) (*transaction.Transaction, error) {
|
return handleNeoAction(ctx, func(contract *neo.Contract, _ util.Uint160, acc *wallet.Account) (*transaction.Transaction, error) {
|
||||||
return contract.UnregisterCandidateUnsigned(acc.PrivateKey().PublicKey())
|
return contract.UnregisterCandidateUnsigned(acc.PublicKey())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +94,7 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
addrFlag := ctx.Generic("address").(*flags.Address)
|
addrFlag := ctx.Generic("address").(*flags.Address)
|
||||||
if !addrFlag.IsSet {
|
if !addrFlag.IsSet {
|
||||||
|
|
|
@ -173,7 +173,12 @@ func NewCommands() []cli.Command {
|
||||||
Name: "dump",
|
Name: "dump",
|
||||||
Usage: "check and dump an existing NEO wallet",
|
Usage: "check and dump an existing NEO wallet",
|
||||||
UsageText: "neo-go wallet dump -w wallet [--wallet-config path] [-d]",
|
UsageText: "neo-go wallet dump -w wallet [--wallet-config path] [-d]",
|
||||||
Action: dumpWallet,
|
Description: `Prints the given wallet (via -w option or via wallet configuration file) in JSON
|
||||||
|
format to the standard output. If -d is given, private keys are unencrypted and
|
||||||
|
displayed in clear text on the console! Be very careful with this option and
|
||||||
|
don't use it unless you know what you're doing.
|
||||||
|
`,
|
||||||
|
Action: dumpWallet,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
|
@ -198,7 +203,13 @@ func NewCommands() []cli.Command {
|
||||||
Name: "export",
|
Name: "export",
|
||||||
Usage: "export keys for address",
|
Usage: "export keys for address",
|
||||||
UsageText: "export -w wallet [--wallet-config path] [--decrypt] [<address>]",
|
UsageText: "export -w wallet [--wallet-config path] [--decrypt] [<address>]",
|
||||||
Action: exportKeys,
|
Description: `Prints the key for the given account to the standard output. It uses NEP-2
|
||||||
|
encrypted format by default (the way NEP-6 wallets store it) or WIF format if
|
||||||
|
-d option is given. In the latter case the key can be displayed in clear text
|
||||||
|
on the console, so be extremely careful with this option and don't use unless
|
||||||
|
you really need it and know what you're doing.
|
||||||
|
`,
|
||||||
|
Action: exportKeys,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
|
@ -336,6 +347,7 @@ func claimGas(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
addrFlag := ctx.Generic("address").(*flags.Address)
|
addrFlag := ctx.Generic("address").(*flags.Address)
|
||||||
if !addrFlag.IsSet {
|
if !addrFlag.IsSet {
|
||||||
|
@ -377,6 +389,7 @@ func changePassword(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
if len(wall.Accounts) == 0 {
|
if len(wall.Accounts) == 0 {
|
||||||
return cli.NewExitError("wallet has no accounts", 1)
|
return cli.NewExitError("wallet has no accounts", 1)
|
||||||
}
|
}
|
||||||
|
@ -472,6 +485,7 @@ func addAccount(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
if err := createAccount(wall, pass); err != nil {
|
if err := createAccount(wall, pass); err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
|
@ -485,6 +499,7 @@ func exportKeys(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
var addr string
|
var addr string
|
||||||
|
|
||||||
|
@ -546,6 +561,7 @@ func importMultisig(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
m := ctx.Int("min")
|
m := ctx.Int("min")
|
||||||
if ctx.NArg() < m {
|
if ctx.NArg() < m {
|
||||||
|
@ -589,6 +605,7 @@ func importDeployed(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
rawHash := ctx.Generic("contract").(*flags.Address)
|
rawHash := ctx.Generic("contract").(*flags.Address)
|
||||||
if !rawHash.IsSet {
|
if !rawHash.IsSet {
|
||||||
|
@ -645,6 +662,7 @@ func importWallet(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt)
|
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -677,6 +695,7 @@ func removeAccount(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
|
|
||||||
addr := ctx.Generic("address").(*flags.Address)
|
addr := ctx.Generic("address").(*flags.Address)
|
||||||
if !addr.IsSet {
|
if !addr.IsSet {
|
||||||
|
@ -723,6 +742,7 @@ func dumpWallet(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
if ctx.Bool("decrypt") {
|
if ctx.Bool("decrypt") {
|
||||||
if pass == nil {
|
if pass == nil {
|
||||||
password, err := input.ReadPassword(EnterPasswordPrompt)
|
password, err := input.ReadPassword(EnterPasswordPrompt)
|
||||||
|
@ -751,6 +771,7 @@ func dumpKeys(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
accounts := wall.Accounts
|
accounts := wall.Accounts
|
||||||
|
|
||||||
addrFlag := ctx.Generic("address").(*flags.Address)
|
addrFlag := ctx.Generic("address").(*flags.Address)
|
||||||
|
@ -801,6 +822,7 @@ func stripKeys(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
if !ctx.Bool("force") {
|
if !ctx.Bool("force") {
|
||||||
fmt.Fprintln(ctx.App.Writer, "All private keys for all accounts will be removed from the wallet. This action is irreversible.")
|
fmt.Fprintln(ctx.App.Writer, "All private keys for all accounts will be removed from the wallet. This action is irreversible.")
|
||||||
if ok := askForConsent(ctx.App.Writer); !ok {
|
if ok := askForConsent(ctx.App.Writer); !ok {
|
||||||
|
@ -850,6 +872,7 @@ func createWallet(ctx *cli.Context) error {
|
||||||
if err := createAccount(wall, pass); err != nil {
|
if err := createAccount(wall, pass); err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
defer wall.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
fmtPrintWallet(ctx.App.Writer, wall)
|
fmtPrintWallet(ctx.App.Writer, wall)
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -11,7 +11,7 @@ require (
|
||||||
github.com/holiman/uint256 v1.2.0
|
github.com/holiman/uint256 v1.2.0
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||||
github.com/mr-tron/base58 v1.2.0
|
github.com/mr-tron/base58 v1.2.0
|
||||||
github.com/nspcc-dev/dbft v0.0.0-20220629112714-fd49ca59d354
|
github.com/nspcc-dev/dbft v0.0.0-20220902113116-58a5e763e647
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22
|
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22
|
||||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220809123759-3094d3e0c14b
|
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220809123759-3094d3e0c14b
|
||||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659
|
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659
|
||||||
|
@ -42,7 +42,7 @@ require (
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
github.com/nspcc-dev/hrw v1.0.9 // indirect
|
github.com/nspcc-dev/hrw v1.0.9 // indirect
|
||||||
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1 // indirect
|
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1 // indirect
|
||||||
github.com/nspcc-dev/neofs-crypto v0.3.0 // indirect
|
github.com/nspcc-dev/neofs-crypto v0.4.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/prometheus/client_model v0.2.0 // indirect
|
github.com/prometheus/client_model v0.2.0 // indirect
|
||||||
github.com/prometheus/common v0.37.0 // indirect
|
github.com/prometheus/common v0.37.0 // indirect
|
||||||
|
|
7
go.sum
7
go.sum
|
@ -251,8 +251,8 @@ github.com/nspcc-dev/dbft v0.0.0-20191209120240-0d6b7568d9ae/go.mod h1:3FjXOoHmA
|
||||||
github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a/go.mod h1:/YFK+XOxxg0Bfm6P92lY5eDSLYfp06XOdL8KAVgXjVk=
|
github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a/go.mod h1:/YFK+XOxxg0Bfm6P92lY5eDSLYfp06XOdL8KAVgXjVk=
|
||||||
github.com/nspcc-dev/dbft v0.0.0-20200219114139-199d286ed6c1/go.mod h1:O0qtn62prQSqizzoagHmuuKoz8QMkU3SzBoKdEvm3aQ=
|
github.com/nspcc-dev/dbft v0.0.0-20200219114139-199d286ed6c1/go.mod h1:O0qtn62prQSqizzoagHmuuKoz8QMkU3SzBoKdEvm3aQ=
|
||||||
github.com/nspcc-dev/dbft v0.0.0-20210721160347-1b03241391ac/go.mod h1:U8MSnEShH+o5hexfWJdze6uMFJteP0ko7J2frO7Yu1Y=
|
github.com/nspcc-dev/dbft v0.0.0-20210721160347-1b03241391ac/go.mod h1:U8MSnEShH+o5hexfWJdze6uMFJteP0ko7J2frO7Yu1Y=
|
||||||
github.com/nspcc-dev/dbft v0.0.0-20220629112714-fd49ca59d354 h1:/NYQJ9dmeOajNuS0b8x8SMt0b4mEYwUWOpMXuLQ1qwM=
|
github.com/nspcc-dev/dbft v0.0.0-20220902113116-58a5e763e647 h1:handGBjqVzRx7HD6152zsP8ZRxw083zCMbN0IlUaPQk=
|
||||||
github.com/nspcc-dev/dbft v0.0.0-20220629112714-fd49ca59d354/go.mod h1:U8MSnEShH+o5hexfWJdze6uMFJteP0ko7J2frO7Yu1Y=
|
github.com/nspcc-dev/dbft v0.0.0-20220902113116-58a5e763e647/go.mod h1:g9xisXmX9NP9MjioaTe862n9SlZTrP+6PVUWLBYOr98=
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20210915112629-e1b6cce73d02/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U=
|
github.com/nspcc-dev/go-ordered-json v0.0.0-20210915112629-e1b6cce73d02/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U=
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 h1:n4ZaFCKt1pQJd7PXoMJabZWK9ejjbLOVrkl/lOUmshg=
|
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 h1:n4ZaFCKt1pQJd7PXoMJabZWK9ejjbLOVrkl/lOUmshg=
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U=
|
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U=
|
||||||
|
@ -267,8 +267,9 @@ github.com/nspcc-dev/neofs-api-go/v2 v2.11.1 h1:SVqc523pZsSaS9vnPS1mm3VV6b6xY0gv
|
||||||
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
|
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
|
||||||
github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA=
|
github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA=
|
||||||
github.com/nspcc-dev/neofs-crypto v0.2.3/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
|
github.com/nspcc-dev/neofs-crypto v0.2.3/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
|
||||||
github.com/nspcc-dev/neofs-crypto v0.3.0 h1:zlr3pgoxuzrmGCxc5W8dGVfA9Rro8diFvVnBg0L4ifM=
|
|
||||||
github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
|
github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
|
||||||
|
github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4=
|
||||||
|
github.com/nspcc-dev/neofs-crypto v0.4.0/go.mod h1:6XJ8kbXgOfevbI2WMruOtI+qUJXNwSGM/E9eClXxPHs=
|
||||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211201182451-a5b61c4f6477/go.mod h1:dfMtQWmBHYpl9Dez23TGtIUKiFvCIxUZq/CkSIhEpz4=
|
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211201182451-a5b61c4f6477/go.mod h1:dfMtQWmBHYpl9Dez23TGtIUKiFvCIxUZq/CkSIhEpz4=
|
||||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659 h1:rpMCoRa7expLc9gMiOP724gz6YSykZzmMALR/CmiwnU=
|
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659 h1:rpMCoRa7expLc9gMiOP724gz6YSykZzmMALR/CmiwnU=
|
||||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659/go.mod h1:/jay1lr3w7NQd/VDBkEhkJmDmyPNsu4W+QV2obsUV40=
|
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659/go.mod h1:/jay1lr3w7NQd/VDBkEhkJmDmyPNsu4W+QV2obsUV40=
|
||||||
|
|
|
@ -144,8 +144,8 @@ func Init(t *testing.T, rootpath string, e *neotest.Executor) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, ntr.Accounts[0].Decrypt("one", ntr.Scrypt))
|
require.NoError(t, ntr.Accounts[0].Decrypt("one", ntr.Scrypt))
|
||||||
designateSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
|
designateSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
|
||||||
int64(noderoles.P2PNotary), []interface{}{ntr.Accounts[0].PrivateKey().PublicKey().Bytes()})
|
int64(noderoles.P2PNotary), []interface{}{ntr.Accounts[0].PublicKey().Bytes()})
|
||||||
t.Logf("Designated Notary node: %s", hex.EncodeToString(ntr.Accounts[0].PrivateKey().PublicKey().Bytes()))
|
t.Logf("Designated Notary node: %s", hex.EncodeToString(ntr.Accounts[0].PublicKey().Bytes()))
|
||||||
|
|
||||||
// Block #10: push verification contract with arguments into the chain.
|
// Block #10: push verification contract with arguments into the chain.
|
||||||
verifyPath = filepath.Join(testDataPrefix, "verify_args", "verification_with_args_contract.go")
|
verifyPath = filepath.Join(testDataPrefix, "verify_args", "verification_with_args_contract.go")
|
||||||
|
|
|
@ -74,7 +74,7 @@ func generateManagementHelperContracts(t *testing.T, saveState bool) {
|
||||||
stdHash := e.NativeHash(t, nativenames.StdLib)
|
stdHash := e.NativeHash(t, nativenames.StdLib)
|
||||||
neoHash := e.NativeHash(t, nativenames.Neo)
|
neoHash := e.NativeHash(t, nativenames.Neo)
|
||||||
singleChainValidatorAcc := e.Validator.(neotest.MultiSigner).Single(2).Account() // priv0
|
singleChainValidatorAcc := e.Validator.(neotest.MultiSigner).Single(2).Account() // priv0
|
||||||
require.NoError(t, singleChainValidatorAcc.ConvertMultisig(1, keys.PublicKeys{singleChainValidatorAcc.PrivateKey().PublicKey()}))
|
require.NoError(t, singleChainValidatorAcc.ConvertMultisig(1, keys.PublicKeys{singleChainValidatorAcc.PublicKey()}))
|
||||||
singleChainValidatorHash := singleChainValidatorAcc.Contract.ScriptHash()
|
singleChainValidatorHash := singleChainValidatorAcc.Contract.ScriptHash()
|
||||||
|
|
||||||
w := io.NewBufBinWriter()
|
w := io.NewBufBinWriter()
|
||||||
|
|
|
@ -276,6 +276,7 @@ func (s *service) Shutdown() {
|
||||||
s.log.Info("stopping consensus service")
|
s.log.Info("stopping consensus service")
|
||||||
close(s.quit)
|
close(s.quit)
|
||||||
<-s.finished
|
<-s.finished
|
||||||
|
s.wallet.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,17 +378,15 @@ func (s *service) getKeyPair(pubs []crypto.PublicKey) (int, crypto.PrivateKey, c
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
key := acc.PrivateKey()
|
if !acc.CanSign() {
|
||||||
if acc.PrivateKey() == nil {
|
|
||||||
err := acc.Decrypt(s.Config.Wallet.Password, s.wallet.Scrypt)
|
err := acc.Decrypt(s.Config.Wallet.Password, s.wallet.Scrypt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Fatal("can't unlock account", zap.String("address", address.Uint160ToString(sh)))
|
s.log.Fatal("can't unlock account", zap.String("address", address.Uint160ToString(sh)))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
key = acc.PrivateKey()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return i, &privateKey{PrivateKey: key}, &publicKey{PublicKey: key.PublicKey()}
|
return i, &privateKey{PrivateKey: acc.PrivateKey()}, &publicKey{PublicKey: acc.PublicKey()}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, nil, nil
|
return -1, nil, nil
|
||||||
|
|
|
@ -115,7 +115,7 @@ func initServiceNextConsensus(t *testing.T, newAcc *wallet.Account, offset uint3
|
||||||
func TestService_NextConsensus(t *testing.T) {
|
func TestService_NextConsensus(t *testing.T) {
|
||||||
newAcc, err := wallet.NewAccount()
|
newAcc, err := wallet.NewAccount()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
script, err := smartcontract.CreateMajorityMultiSigRedeemScript(keys.PublicKeys{newAcc.PrivateKey().PublicKey()})
|
script, err := smartcontract.CreateMajorityMultiSigRedeemScript(keys.PublicKeys{newAcc.PublicKey()})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
checkNextConsensus := func(t *testing.T, bc *core.Blockchain, height uint32, h util.Uint160) {
|
checkNextConsensus := func(t *testing.T, bc *core.Blockchain, height uint32, h util.Uint160) {
|
||||||
|
|
|
@ -13,17 +13,6 @@ type privateKey struct {
|
||||||
*keys.PrivateKey
|
*keys.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalBinary implements the encoding.BinaryMarshaler interface.
|
|
||||||
func (p privateKey) MarshalBinary() (data []byte, err error) {
|
|
||||||
return p.PrivateKey.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
|
|
||||||
func (p *privateKey) UnmarshalBinary(data []byte) (err error) {
|
|
||||||
p.PrivateKey, err = keys.NewPrivateKeyFromBytes(data)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign implements the dbft's crypto.PrivateKey interface.
|
// Sign implements the dbft's crypto.PrivateKey interface.
|
||||||
func (p *privateKey) Sign(data []byte) ([]byte, error) {
|
func (p *privateKey) Sign(data []byte) ([]byte, error) {
|
||||||
return p.PrivateKey.Sign(data), nil
|
return p.PrivateKey.Sign(data), nil
|
||||||
|
|
|
@ -12,19 +12,12 @@ func TestCrypt(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
priv := privateKey{key}
|
priv := privateKey{key}
|
||||||
data, err := priv.MarshalBinary()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
key1, err := keys.NewPrivateKey()
|
key1, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
priv1 := privateKey{key1}
|
|
||||||
require.NotEqual(t, priv, priv1)
|
|
||||||
require.NoError(t, priv1.UnmarshalBinary(data))
|
|
||||||
require.Equal(t, priv, priv1)
|
|
||||||
|
|
||||||
pub := publicKey{key.PublicKey()}
|
pub := publicKey{key.PublicKey()}
|
||||||
data, err = pub.MarshalBinary()
|
data, err := pub.MarshalBinary()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pub1 := publicKey{key1.PublicKey()}
|
pub1 := publicKey{key1.PublicKey()}
|
||||||
|
|
|
@ -1060,7 +1060,7 @@ func TestBlockchain_VerifyTx(t *testing.T) {
|
||||||
notaryServiceFeePerKey := bc.GetNotaryServiceFeePerKey()
|
notaryServiceFeePerKey := bc.GetNotaryServiceFeePerKey()
|
||||||
|
|
||||||
oracleAcc := accs[2]
|
oracleAcc := accs[2]
|
||||||
oraclePubs := keys.PublicKeys{oracleAcc.PrivateKey().PublicKey()}
|
oraclePubs := keys.PublicKeys{oracleAcc.PublicKey()}
|
||||||
require.NoError(t, oracleAcc.ConvertMultisig(1, oraclePubs))
|
require.NoError(t, oracleAcc.ConvertMultisig(1, oraclePubs))
|
||||||
|
|
||||||
neoHash := e.NativeHash(t, nativenames.Neo)
|
neoHash := e.NativeHash(t, nativenames.Neo)
|
||||||
|
@ -1179,7 +1179,7 @@ func TestBlockchain_VerifyTx(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("CalculateNetworkFee, multisignature script", func(t *testing.T) {
|
t.Run("CalculateNetworkFee, multisignature script", func(t *testing.T) {
|
||||||
multisigAcc := accs[4]
|
multisigAcc := accs[4]
|
||||||
pKeys := keys.PublicKeys{multisigAcc.PrivateKey().PublicKey()}
|
pKeys := keys.PublicKeys{multisigAcc.PublicKey()}
|
||||||
require.NoError(t, multisigAcc.ConvertMultisig(1, pKeys))
|
require.NoError(t, multisigAcc.ConvertMultisig(1, pKeys))
|
||||||
multisigHash := hash.Hash160(multisigAcc.Contract.Script)
|
multisigHash := hash.Hash160(multisigAcc.Contract.Script)
|
||||||
tx := newTestTx(t, multisigHash, testScript)
|
tx := newTestTx(t, multisigHash, testScript)
|
||||||
|
@ -1594,7 +1594,7 @@ func TestBlockchain_VerifyTx(t *testing.T) {
|
||||||
notary, err := wallet.NewAccount()
|
notary, err := wallet.NewAccount()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
designateSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
|
designateSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
|
||||||
int64(noderoles.P2PNotary), []interface{}{notary.PrivateKey().PublicKey().Bytes()})
|
int64(noderoles.P2PNotary), []interface{}{notary.PublicKey().Bytes()})
|
||||||
txSetNotary := transaction.New([]byte{byte(opcode.RET)}, 0)
|
txSetNotary := transaction.New([]byte{byte(opcode.RET)}, 0)
|
||||||
txSetNotary.Signers = []transaction.Signer{
|
txSetNotary.Signers = []transaction.Signer{
|
||||||
{
|
{
|
||||||
|
|
|
@ -65,7 +65,7 @@ func TestNEO_CandidateEvents(t *testing.T) {
|
||||||
singleSigner := c.Signers[0].(neotest.MultiSigner).Single(0)
|
singleSigner := c.Signers[0].(neotest.MultiSigner).Single(0)
|
||||||
cc := c.WithSigners(c.Signers[0], singleSigner)
|
cc := c.WithSigners(c.Signers[0], singleSigner)
|
||||||
e := c.Executor
|
e := c.Executor
|
||||||
pkb := singleSigner.Account().PrivateKey().PublicKey().Bytes()
|
pkb := singleSigner.Account().PublicKey().Bytes()
|
||||||
|
|
||||||
// Register 1 -> event
|
// Register 1 -> event
|
||||||
tx := cc.Invoke(t, true, "registerCandidate", pkb)
|
tx := cc.Invoke(t, true, "registerCandidate", pkb)
|
||||||
|
@ -160,13 +160,13 @@ func TestNEO_Vote(t *testing.T) {
|
||||||
transferTx = neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), referenceAccounts[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(committeeSize+1-i)*1000000, nil)
|
transferTx = neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), referenceAccounts[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(committeeSize+1-i)*1000000, nil)
|
||||||
txes = append(txes, transferTx)
|
txes = append(txes, transferTx)
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
registerTx := neoValidatorsInvoker.WithSigners(candidates[i]).PrepareInvoke(t, "registerCandidate", candidates[i].(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes())
|
registerTx := neoValidatorsInvoker.WithSigners(candidates[i]).PrepareInvoke(t, "registerCandidate", candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
|
||||||
txes = append(txes, registerTx)
|
txes = append(txes, registerTx)
|
||||||
voteTx := neoValidatorsInvoker.WithSigners(voters[i]).PrepareInvoke(t, "vote", voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[i].(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes())
|
voteTx := neoValidatorsInvoker.WithSigners(voters[i]).PrepareInvoke(t, "vote", voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
|
||||||
txes = append(txes, voteTx)
|
txes = append(txes, voteTx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
txes = append(txes, policyInvoker.PrepareInvoke(t, "blockAccount", candidates[len(candidates)-1].(neotest.SingleSigner).Account().PrivateKey().PublicKey().GetScriptHash()))
|
txes = append(txes, policyInvoker.PrepareInvoke(t, "blockAccount", candidates[len(candidates)-1].(neotest.SingleSigner).Account().ScriptHash()))
|
||||||
neoValidatorsInvoker.AddNewBlock(t, txes...)
|
neoValidatorsInvoker.AddNewBlock(t, txes...)
|
||||||
for _, tx := range txes {
|
for _, tx := range txes {
|
||||||
e.CheckHalt(t, tx.Hash(), stackitem.Make(true)) // luckily, both `transfer`, `registerCandidate` and `vote` return boolean values
|
e.CheckHalt(t, tx.Hash(), stackitem.Make(true)) // luckily, both `transfer`, `registerCandidate` and `vote` return boolean values
|
||||||
|
@ -184,9 +184,9 @@ func TestNEO_Vote(t *testing.T) {
|
||||||
|
|
||||||
// Register and give some value to the last validator.
|
// Register and give some value to the last validator.
|
||||||
txes = txes[:0]
|
txes = txes[:0]
|
||||||
registerTx := neoValidatorsInvoker.WithSigners(candidates[0]).PrepareInvoke(t, "registerCandidate", candidates[0].(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes())
|
registerTx := neoValidatorsInvoker.WithSigners(candidates[0]).PrepareInvoke(t, "registerCandidate", candidates[0].(neotest.SingleSigner).Account().PublicKey().Bytes())
|
||||||
txes = append(txes, registerTx)
|
txes = append(txes, registerTx)
|
||||||
voteTx := neoValidatorsInvoker.WithSigners(voters[0]).PrepareInvoke(t, "vote", voters[0].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[0].(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes())
|
voteTx := neoValidatorsInvoker.WithSigners(voters[0]).PrepareInvoke(t, "vote", voters[0].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[0].(neotest.SingleSigner).Account().PublicKey().Bytes())
|
||||||
txes = append(txes, voteTx)
|
txes = append(txes, voteTx)
|
||||||
neoValidatorsInvoker.AddNewBlock(t, txes...)
|
neoValidatorsInvoker.AddNewBlock(t, txes...)
|
||||||
for _, tx := range txes {
|
for _, tx := range txes {
|
||||||
|
@ -198,7 +198,7 @@ func TestNEO_Vote(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
sortedCandidates := make(keys.PublicKeys, validatorsCount)
|
sortedCandidates := make(keys.PublicKeys, validatorsCount)
|
||||||
for i := range candidates[:validatorsCount] {
|
for i := range candidates[:validatorsCount] {
|
||||||
sortedCandidates[i] = candidates[i].(neotest.SingleSigner).Account().PrivateKey().PublicKey()
|
sortedCandidates[i] = candidates[i].(neotest.SingleSigner).Account().PublicKey()
|
||||||
}
|
}
|
||||||
sort.Sort(sortedCandidates)
|
sort.Sort(sortedCandidates)
|
||||||
require.EqualValues(t, sortedCandidates, keys.PublicKeys(pubs))
|
require.EqualValues(t, sortedCandidates, keys.PublicKeys(pubs))
|
||||||
|
@ -259,8 +259,8 @@ func TestNEO_Vote(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
neoCommitteeInvoker.WithSigners(candidates[0]).Invoke(t, true, "unregisterCandidate", candidates[0].(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes())
|
neoCommitteeInvoker.WithSigners(candidates[0]).Invoke(t, true, "unregisterCandidate", candidates[0].(neotest.SingleSigner).Account().PublicKey().Bytes())
|
||||||
neoCommitteeInvoker.WithSigners(voters[0]).Invoke(t, false, "vote", voters[0].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[0].(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes())
|
neoCommitteeInvoker.WithSigners(voters[0]).Invoke(t, false, "vote", voters[0].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[0].(neotest.SingleSigner).Account().PublicKey().Bytes())
|
||||||
|
|
||||||
advanceChain(t)
|
advanceChain(t)
|
||||||
|
|
||||||
|
@ -564,9 +564,9 @@ func TestNEO_GetCandidates(t *testing.T) {
|
||||||
for i := 0; i < candidatesCount; i++ {
|
for i := 0; i < candidatesCount; i++ {
|
||||||
transferTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(candidatesCount+1-i)*1000000, nil)
|
transferTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(candidatesCount+1-i)*1000000, nil)
|
||||||
txes = append(txes, transferTx)
|
txes = append(txes, transferTx)
|
||||||
registerTx := neoValidatorsInvoker.WithSigners(candidates[i]).PrepareInvoke(t, "registerCandidate", candidates[i].(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes())
|
registerTx := neoValidatorsInvoker.WithSigners(candidates[i]).PrepareInvoke(t, "registerCandidate", candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
|
||||||
txes = append(txes, registerTx)
|
txes = append(txes, registerTx)
|
||||||
voteTx := neoValidatorsInvoker.WithSigners(voters[i]).PrepareInvoke(t, "vote", voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[i].(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes())
|
voteTx := neoValidatorsInvoker.WithSigners(voters[i]).PrepareInvoke(t, "vote", voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
|
||||||
txes = append(txes, voteTx)
|
txes = append(txes, voteTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,7 +576,7 @@ func TestNEO_GetCandidates(t *testing.T) {
|
||||||
}
|
}
|
||||||
expected := make([]stackitem.Item, candidatesCount)
|
expected := make([]stackitem.Item, candidatesCount)
|
||||||
for i := range expected {
|
for i := range expected {
|
||||||
pub := candidates[i].(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes()
|
pub := candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes()
|
||||||
v := stackitem.NewBigInteger(big.NewInt(int64(candidatesCount-i+1) * 1000000))
|
v := stackitem.NewBigInteger(big.NewInt(int64(candidatesCount-i+1) * 1000000))
|
||||||
expected[i] = stackitem.NewStruct([]stackitem.Item{
|
expected[i] = stackitem.NewStruct([]stackitem.Item{
|
||||||
stackitem.NewByteArray(pub),
|
stackitem.NewByteArray(pub),
|
||||||
|
@ -613,7 +613,7 @@ func TestNEO_GetCandidates(t *testing.T) {
|
||||||
checkGetAllCandidates(t, expected)
|
checkGetAllCandidates(t, expected)
|
||||||
|
|
||||||
// Block candidate and check it won't be returned from getCandidates and getAllCandidates.
|
// Block candidate and check it won't be returned from getCandidates and getAllCandidates.
|
||||||
unlucky := candidates[len(candidates)-1].(neotest.SingleSigner).Account().PrivateKey().PublicKey()
|
unlucky := candidates[len(candidates)-1].(neotest.SingleSigner).Account().PublicKey()
|
||||||
policyInvoker.Invoke(t, true, "blockAccount", unlucky.GetScriptHash())
|
policyInvoker.Invoke(t, true, "blockAccount", unlucky.GetScriptHash())
|
||||||
for i := range expected {
|
for i := range expected {
|
||||||
if bytes.Equal(expected[i].Value().([]stackitem.Item)[0].Value().([]byte), unlucky.Bytes()) {
|
if bytes.Equal(expected[i].Value().([]stackitem.Item)[0].Value().([]byte), unlucky.Bytes()) {
|
||||||
|
|
|
@ -71,8 +71,8 @@ func TestOracle_Request(t *testing.T) {
|
||||||
|
|
||||||
// Designate single Oracle node.
|
// Designate single Oracle node.
|
||||||
oracleNode := e.NewAccount(t)
|
oracleNode := e.NewAccount(t)
|
||||||
designationCommitteeInvoker.Invoke(t, stackitem.Null{}, "designateAsRole", int(noderoles.Oracle), []interface{}{oracleNode.(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes()})
|
designationCommitteeInvoker.Invoke(t, stackitem.Null{}, "designateAsRole", int(noderoles.Oracle), []interface{}{oracleNode.(neotest.SingleSigner).Account().PublicKey().Bytes()})
|
||||||
err = oracleNode.(neotest.SingleSigner).Account().ConvertMultisig(1, []*keys.PublicKey{oracleNode.(neotest.SingleSigner).Account().PrivateKey().PublicKey()})
|
err = oracleNode.(neotest.SingleSigner).Account().ConvertMultisig(1, []*keys.PublicKey{oracleNode.(neotest.SingleSigner).Account().PublicKey()})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
oracleNodeMulti := neotest.NewMultiSigner(oracleNode.(neotest.SingleSigner).Account())
|
oracleNodeMulti := neotest.NewMultiSigner(oracleNode.(neotest.SingleSigner).Account())
|
||||||
gasCommitteeInvoker.Invoke(t, true, "transfer", gasCommitteeInvoker.CommitteeHash, oracleNodeMulti.ScriptHash(), 100_0000_0000, nil)
|
gasCommitteeInvoker.Invoke(t, true, "transfer", gasCommitteeInvoker.CommitteeHash, oracleNodeMulti.ScriptHash(), 100_0000_0000, nil)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/base58"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/base58"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util/slice"
|
||||||
"golang.org/x/crypto/scrypt"
|
"golang.org/x/crypto/scrypt"
|
||||||
"golang.org/x/text/unicode/norm"
|
"golang.org/x/text/unicode/norm"
|
||||||
)
|
)
|
||||||
|
@ -52,10 +53,15 @@ func NEP2Encrypt(priv *PrivateKey, passphrase string, params ScryptParams) (s st
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
|
defer slice.Clean(derivedKey)
|
||||||
|
|
||||||
derivedKey1 := derivedKey[:32]
|
derivedKey1 := derivedKey[:32]
|
||||||
derivedKey2 := derivedKey[32:]
|
derivedKey2 := derivedKey[32:]
|
||||||
xr := xor(priv.Bytes(), derivedKey1)
|
|
||||||
|
privBytes := priv.Bytes()
|
||||||
|
defer slice.Clean(privBytes)
|
||||||
|
xr := xor(privBytes, derivedKey1)
|
||||||
|
defer slice.Clean(xr)
|
||||||
|
|
||||||
encrypted, err := aesEncrypt(xr, derivedKey2)
|
encrypted, err := aesEncrypt(xr, derivedKey2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -93,6 +99,7 @@ func NEP2Decrypt(key, passphrase string, params ScryptParams) (*PrivateKey, erro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
defer slice.Clean(derivedKey)
|
||||||
|
|
||||||
derivedKey1 := derivedKey[:32]
|
derivedKey1 := derivedKey[:32]
|
||||||
derivedKey2 := derivedKey[32:]
|
derivedKey2 := derivedKey[32:]
|
||||||
|
@ -102,8 +109,10 @@ func NEP2Decrypt(key, passphrase string, params ScryptParams) (*PrivateKey, erro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
defer slice.Clean(decrypted)
|
||||||
|
|
||||||
privBytes := xor(decrypted, derivedKey1)
|
privBytes := xor(decrypted, derivedKey1)
|
||||||
|
defer slice.Clean(privBytes)
|
||||||
|
|
||||||
// Rebuild the private key.
|
// Rebuild the private key.
|
||||||
privKey, err := NewPrivateKeyFromBytes(privBytes)
|
privKey, err := NewPrivateKeyFromBytes(privBytes)
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util/slice"
|
||||||
"github.com/nspcc-dev/rfc6979"
|
"github.com/nspcc-dev/rfc6979"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,6 +49,7 @@ func NewPrivateKeyFromHex(str string) (*PrivateKey, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
defer slice.Clean(b)
|
||||||
return NewPrivateKeyFromBytes(b)
|
return NewPrivateKeyFromBytes(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +110,9 @@ func NewPrivateKeyFromWIF(wif string) (*PrivateKey, error) {
|
||||||
// Good documentation about this process can be found here:
|
// Good documentation about this process can be found here:
|
||||||
// https://en.bitcoin.it/wiki/Wallet_import_format
|
// https://en.bitcoin.it/wiki/Wallet_import_format
|
||||||
func (p *PrivateKey) WIF() string {
|
func (p *PrivateKey) WIF() string {
|
||||||
w, err := WIFEncode(p.Bytes(), WIFVersion, true)
|
pb := p.Bytes()
|
||||||
|
defer slice.Clean(pb)
|
||||||
|
w, err := WIFEncode(pb, WIFVersion, true)
|
||||||
// The only way WIFEncode() can fail is if we're to give it a key of
|
// The only way WIFEncode() can fail is if we're to give it a key of
|
||||||
// wrong size, but we have a proper key here, aren't we?
|
// wrong size, but we have a proper key here, aren't we?
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -117,6 +121,15 @@ func (p *PrivateKey) WIF() string {
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Destroy wipes the contents of the private key from memory. Any operations
|
||||||
|
// with the key after call to Destroy have undefined behavior.
|
||||||
|
func (p *PrivateKey) Destroy() {
|
||||||
|
bits := p.D.Bits()
|
||||||
|
for i := range bits {
|
||||||
|
bits[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Address derives the public NEO address that is coupled with the private key, and
|
// Address derives the public NEO address that is coupled with the private key, and
|
||||||
// returns it as a string.
|
// returns it as a string.
|
||||||
func (p *PrivateKey) Address() string {
|
func (p *PrivateKey) Address() string {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package keys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -27,6 +28,9 @@ func TestPrivateKey(t *testing.T) {
|
||||||
assert.Equal(t, testCase.Wif, wif)
|
assert.Equal(t, testCase.Wif, wif)
|
||||||
pubKey := privKey.PublicKey()
|
pubKey := privKey.PublicKey()
|
||||||
assert.Equal(t, hex.EncodeToString(pubKey.Bytes()), testCase.PublicKey)
|
assert.Equal(t, hex.EncodeToString(pubKey.Bytes()), testCase.PublicKey)
|
||||||
|
oldD := new(big.Int).Set(privKey.D)
|
||||||
|
privKey.Destroy()
|
||||||
|
assert.NotEqual(t, oldD, privKey.D)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/base58"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/base58"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util/slice"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -53,40 +54,36 @@ func WIFDecode(wif string, version byte) (*WIF, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
defer slice.Clean(b)
|
||||||
|
|
||||||
if version == 0x00 {
|
if version == 0x00 {
|
||||||
version = WIFVersion
|
version = WIFVersion
|
||||||
}
|
}
|
||||||
|
w := &WIF{
|
||||||
|
Version: version,
|
||||||
|
S: wif,
|
||||||
|
}
|
||||||
|
switch len(b) {
|
||||||
|
case 33: // OK, uncompressed public key.
|
||||||
|
case 34: // OK, compressed public key.
|
||||||
|
// Check the compression flag.
|
||||||
|
if b[33] != 0x01 {
|
||||||
|
return nil, fmt.Errorf("invalid compression flag %d expecting %d", b[33], 0x01)
|
||||||
|
}
|
||||||
|
w.Compressed = true
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid WIF length %d, expecting 33 or 34", len(b))
|
||||||
|
}
|
||||||
|
|
||||||
if b[0] != version {
|
if b[0] != version {
|
||||||
return nil, fmt.Errorf("invalid WIF version got %d, expected %d", b[0], version)
|
return nil, fmt.Errorf("invalid WIF version got %d, expected %d", b[0], version)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive the PrivateKey.
|
// Derive the PrivateKey.
|
||||||
privKey, err := NewPrivateKeyFromBytes(b[1:33])
|
w.PrivateKey, err = NewPrivateKeyFromBytes(b[1:33])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
w := &WIF{
|
|
||||||
Version: version,
|
|
||||||
PrivateKey: privKey,
|
|
||||||
S: wif,
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is an uncompressed WIF.
|
|
||||||
if len(b) == 33 {
|
|
||||||
w.Compressed = false
|
|
||||||
return w, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(b) != 34 {
|
|
||||||
return nil, fmt.Errorf("invalid WIF length: %d expecting 34", len(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the compression flag.
|
|
||||||
if b[33] != 0x01 {
|
|
||||||
return nil, fmt.Errorf("invalid compression flag %d expecting %d", b[34], 0x01)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Compressed = true
|
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/encoding/base58"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -65,3 +66,35 @@ func TestWIFEncodeDecode(t *testing.T) {
|
||||||
_, err := WIFEncode(wifInv, 0, true)
|
_, err := WIFEncode(wifInv, 0, true)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBadWIFDecode(t *testing.T) {
|
||||||
|
_, err := WIFDecode("garbage", 0)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
s := base58.CheckEncode([]byte{})
|
||||||
|
_, err = WIFDecode(s, 0)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
uncompr := make([]byte, 33)
|
||||||
|
compr := make([]byte, 34)
|
||||||
|
|
||||||
|
s = base58.CheckEncode(compr)
|
||||||
|
_, err = WIFDecode(s, 0)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
s = base58.CheckEncode(uncompr)
|
||||||
|
_, err = WIFDecode(s, 0)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
compr[33] = 1
|
||||||
|
compr[0] = WIFVersion
|
||||||
|
uncompr[0] = WIFVersion
|
||||||
|
|
||||||
|
s = base58.CheckEncode(compr)
|
||||||
|
_, err = WIFDecode(s, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
s = base58.CheckEncode(uncompr)
|
||||||
|
_, err = WIFDecode(s, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ var (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
committeeAcc, _ = wallet.NewAccountFromWIF(singleValidatorWIF)
|
committeeAcc, _ = wallet.NewAccountFromWIF(singleValidatorWIF)
|
||||||
pubs := keys.PublicKeys{committeeAcc.PrivateKey().PublicKey()}
|
pubs := keys.PublicKeys{committeeAcc.PublicKey()}
|
||||||
err := committeeAcc.ConvertMultisig(1, pubs)
|
err := committeeAcc.ConvertMultisig(1, pubs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -70,7 +70,7 @@ func init() {
|
||||||
pubs = make(keys.PublicKeys, len(accs))
|
pubs = make(keys.PublicKeys, len(accs))
|
||||||
for i := range committeeWIFs {
|
for i := range committeeWIFs {
|
||||||
accs[i], _ = wallet.NewAccountFromWIF(committeeWIFs[i])
|
accs[i], _ = wallet.NewAccountFromWIF(committeeWIFs[i])
|
||||||
pubs[i] = accs[i].PrivateKey().PublicKey()
|
pubs[i] = accs[i].PublicKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config entry must contain validators first in a specific order.
|
// Config entry must contain validators first in a specific order.
|
||||||
|
@ -86,8 +86,8 @@ func init() {
|
||||||
sort.Sort(pubs[:4])
|
sort.Sort(pubs[:4])
|
||||||
|
|
||||||
sort.Slice(accs[:4], func(i, j int) bool {
|
sort.Slice(accs[:4], func(i, j int) bool {
|
||||||
p1 := accs[i].PrivateKey().PublicKey()
|
p1 := accs[i].PublicKey()
|
||||||
p2 := accs[j].PrivateKey().PublicKey()
|
p2 := accs[j].PublicKey()
|
||||||
return p1.Cmp(p2) == -1
|
return p1.Cmp(p2) == -1
|
||||||
})
|
})
|
||||||
for i := range multiValidatorAcc {
|
for i := range multiValidatorAcc {
|
||||||
|
@ -102,8 +102,8 @@ func init() {
|
||||||
sort.Sort(pubs)
|
sort.Sort(pubs)
|
||||||
|
|
||||||
sort.Slice(accs, func(i, j int) bool {
|
sort.Slice(accs, func(i, j int) bool {
|
||||||
p1 := accs[i].PrivateKey().PublicKey()
|
p1 := accs[i].PublicKey()
|
||||||
p2 := accs[j].PrivateKey().PublicKey()
|
p2 := accs[j].PublicKey()
|
||||||
return p1.Cmp(p2) == -1
|
return p1.Cmp(p2) == -1
|
||||||
})
|
})
|
||||||
for i := range multiCommitteeAcc {
|
for i := range multiCommitteeAcc {
|
||||||
|
@ -141,7 +141,7 @@ func NewSingleWithCustomConfigAndStore(t testing.TB, f func(cfg *config.Protocol
|
||||||
Magic: netmode.UnitTestNet,
|
Magic: netmode.UnitTestNet,
|
||||||
MaxTraceableBlocks: MaxTraceableBlocks,
|
MaxTraceableBlocks: MaxTraceableBlocks,
|
||||||
SecondsPerBlock: SecondsPerBlock,
|
SecondsPerBlock: SecondsPerBlock,
|
||||||
StandbyCommittee: []string{hex.EncodeToString(committeeAcc.PrivateKey().PublicKey().Bytes())},
|
StandbyCommittee: []string{hex.EncodeToString(committeeAcc.PublicKey().Bytes())},
|
||||||
ValidatorsCount: 1,
|
ValidatorsCount: 1,
|
||||||
VerifyBlocks: true,
|
VerifyBlocks: true,
|
||||||
VerifyTransactions: true,
|
VerifyTransactions: true,
|
||||||
|
|
|
@ -74,7 +74,7 @@ func (s *signer) ScriptHash() util.Uint160 {
|
||||||
// SignHashable implements Signer interface.
|
// SignHashable implements Signer interface.
|
||||||
func (s *signer) SignHashable(magic uint32, item hash.Hashable) []byte {
|
func (s *signer) SignHashable(magic uint32, item hash.Hashable) []byte {
|
||||||
return append([]byte{byte(opcode.PUSHDATA1), 64},
|
return append([]byte{byte(opcode.PUSHDATA1), 64},
|
||||||
(*wallet.Account)(s).PrivateKey().SignHashable(magic, item)...)
|
(*wallet.Account)(s).SignHashable(netmode.Magic(magic), item)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignTx implements Signer interface.
|
// SignTx implements Signer interface.
|
||||||
|
@ -103,8 +103,8 @@ func NewMultiSigner(accs ...*wallet.Account) MultiSigner {
|
||||||
"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 {
|
sort.Slice(accs, func(i, j int) bool {
|
||||||
p1 := accs[i].PrivateKey().PublicKey()
|
p1 := accs[i].PublicKey()
|
||||||
p2 := accs[j].PrivateKey().PublicKey()
|
p2 := accs[j].PublicKey()
|
||||||
return p1.Cmp(p2) == -1
|
return p1.Cmp(p2) == -1
|
||||||
})
|
})
|
||||||
for _, acc := range accs {
|
for _, acc := range accs {
|
||||||
|
@ -130,7 +130,7 @@ func (m multiSigner) Script() []byte {
|
||||||
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 i := 0; i < m.m; i++ {
|
for i := 0; i < m.m; i++ {
|
||||||
sign := m.accounts[i].PrivateKey().SignHashable(magic, item)
|
sign := m.accounts[i].SignHashable(netmode.Magic(magic), item)
|
||||||
script = append(script, byte(opcode.PUSHDATA1), 64)
|
script = append(script, byte(opcode.PUSHDATA1), 64)
|
||||||
script = append(script, sign...)
|
script = append(script, sign...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ func TestMultiSigner(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
accs[i] = a
|
accs[i] = a
|
||||||
pubs[i] = a.PrivateKey().PublicKey()
|
pubs[i] = a.PublicKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(pubs)
|
sort.Sort(pubs)
|
||||||
|
@ -40,8 +40,8 @@ func TestMultiSigner(t *testing.T) {
|
||||||
s := NewMultiSigner(accs...)
|
s := NewMultiSigner(accs...)
|
||||||
for i := range pubs {
|
for i := range pubs {
|
||||||
for j := range accs {
|
for j := range accs {
|
||||||
if pub := accs[j].PrivateKey().PublicKey(); pub.Equal(pubs[i]) {
|
if pub := accs[j].PublicKey(); pub.Equal(pubs[i]) {
|
||||||
require.Equal(t, pub, s.Single(i).Account().PrivateKey().PublicKey())
|
require.Equal(t, pub, s.Single(i).Account().PublicKey())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
@ -276,8 +275,5 @@ func TestSender(t *testing.T) {
|
||||||
client, acc := testRPCAndAccount(t)
|
client, acc := testRPCAndAccount(t)
|
||||||
a, err := NewSimple(client, acc)
|
a, err := NewSimple(client, acc)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, acc.ScriptHash(), a.Sender())
|
||||||
addr, err := address.StringToUint160(acc.Address)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, addr, a.Sender())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
@ -88,13 +87,9 @@ func (c *Client) CreateNEP11TransferTx(acc *wallet.Account, tokenHash util.Uint1
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create NEP-11 transfer script: %w", err)
|
return nil, fmt.Errorf("failed to create NEP-11 transfer script: %w", err)
|
||||||
}
|
}
|
||||||
from, err := address.StringToUint160(acc.Address)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("bad account address: %w", err)
|
|
||||||
}
|
|
||||||
return c.CreateTxFromScript(script, acc, -1, gas, append([]SignerAccount{{
|
return c.CreateTxFromScript(script, acc, -1, gas, append([]SignerAccount{{
|
||||||
Signer: transaction.Signer{
|
Signer: transaction.Signer{
|
||||||
Account: from,
|
Account: acc.ScriptHash(),
|
||||||
Scopes: transaction.CalledByEntry,
|
Scopes: transaction.CalledByEntry,
|
||||||
},
|
},
|
||||||
Account: acc,
|
Account: acc,
|
||||||
|
@ -148,11 +143,7 @@ func (c *Client) NEP11NDOwnerOf(tokenHash util.Uint160, tokenID []byte) (util.Ui
|
||||||
// versions.
|
// versions.
|
||||||
func (c *Client) TransferNEP11D(acc *wallet.Account, to util.Uint160,
|
func (c *Client) TransferNEP11D(acc *wallet.Account, to util.Uint160,
|
||||||
tokenHash util.Uint160, amount int64, tokenID []byte, data interface{}, gas int64, cosigners []SignerAccount) (util.Uint256, error) {
|
tokenHash util.Uint160, amount int64, tokenID []byte, data interface{}, gas int64, cosigners []SignerAccount) (util.Uint256, error) {
|
||||||
from, err := address.StringToUint160(acc.Address)
|
tx, err := c.CreateNEP11TransferTx(acc, tokenHash, gas, cosigners, acc.ScriptHash(), to, amount, tokenID, data)
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, fmt.Errorf("bad account address: %w", err)
|
|
||||||
}
|
|
||||||
tx, err := c.CreateNEP11TransferTx(acc, tokenHash, gas, cosigners, from, to, amount, tokenID, data)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.Uint256{}, err
|
return util.Uint256{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
@ -96,10 +95,7 @@ func (c *Client) CreateNEP17TransferTx(acc *wallet.Account, to util.Uint160,
|
||||||
// be removed in future versions.
|
// be removed in future versions.
|
||||||
func (c *Client) CreateNEP17MultiTransferTx(acc *wallet.Account, gas int64,
|
func (c *Client) CreateNEP17MultiTransferTx(acc *wallet.Account, gas int64,
|
||||||
recipients []TransferTarget, cosigners []SignerAccount) (*transaction.Transaction, error) {
|
recipients []TransferTarget, cosigners []SignerAccount) (*transaction.Transaction, error) {
|
||||||
from, err := address.StringToUint160(acc.Address)
|
from := acc.ScriptHash()
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("bad account address: %w", err)
|
|
||||||
}
|
|
||||||
b := smartcontract.NewBuilder()
|
b := smartcontract.NewBuilder()
|
||||||
for i := range recipients {
|
for i := range recipients {
|
||||||
b.InvokeWithAssert(recipients[i].Token, "transfer",
|
b.InvokeWithAssert(recipients[i].Token, "transfer",
|
||||||
|
|
|
@ -300,7 +300,7 @@ func (a *Actor) SendRequestExactly(mainTx *transaction.Transaction, fbTx *transa
|
||||||
FallbackTransaction: fbTx,
|
FallbackTransaction: fbTx,
|
||||||
}
|
}
|
||||||
req.Witness = transaction.Witness{
|
req.Witness = transaction.Witness{
|
||||||
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, a.sender.PrivateKey().SignHashable(uint32(a.GetNetwork()), req)...),
|
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, a.sender.SignHashable(a.GetNetwork(), req)...),
|
||||||
VerificationScript: a.sender.GetVerificationScript(),
|
VerificationScript: a.sender.GetVerificationScript(),
|
||||||
}
|
}
|
||||||
actualHash, err := a.rpc.SubmitP2PNotaryRequest(req)
|
actualHash, err := a.rpc.SubmitP2PNotaryRequest(req)
|
||||||
|
|
|
@ -827,10 +827,7 @@ func getSigners(sender *wallet.Account, cosigners []SignerAccount) ([]transactio
|
||||||
signers []transaction.Signer
|
signers []transaction.Signer
|
||||||
accounts []*wallet.Account
|
accounts []*wallet.Account
|
||||||
)
|
)
|
||||||
from, err := address.StringToUint160(sender.Address)
|
from := sender.ScriptHash()
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("bad sender account address: %v", err)
|
|
||||||
}
|
|
||||||
s := transaction.Signer{
|
s := transaction.Signer{
|
||||||
Account: from,
|
Account: from,
|
||||||
Scopes: transaction.None,
|
Scopes: transaction.None,
|
||||||
|
@ -875,10 +872,7 @@ func (c *Client) SignAndPushP2PNotaryRequest(mainTx *transaction.Transaction, fa
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get native Notary hash: %w", err)
|
return nil, fmt.Errorf("failed to get native Notary hash: %w", err)
|
||||||
}
|
}
|
||||||
from, err := address.StringToUint160(acc.Address)
|
from := acc.ScriptHash()
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("bad account address: %v", err)
|
|
||||||
}
|
|
||||||
signers := []transaction.Signer{{Account: notaryHash}, {Account: from}}
|
signers := []transaction.Signer{{Account: notaryHash}, {Account: from}}
|
||||||
if fallbackSysFee < 0 {
|
if fallbackSysFee < 0 {
|
||||||
result, err := c.InvokeScript(fallbackScript, signers)
|
result, err := c.InvokeScript(fallbackScript, signers)
|
||||||
|
@ -944,7 +938,7 @@ func (c *Client) SignAndPushP2PNotaryRequest(mainTx *transaction.Transaction, fa
|
||||||
FallbackTransaction: fallbackTx,
|
FallbackTransaction: fallbackTx,
|
||||||
}
|
}
|
||||||
req.Witness = transaction.Witness{
|
req.Witness = transaction.Witness{
|
||||||
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, acc.PrivateKey().SignHashable(uint32(m), req)...),
|
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, acc.SignHashable(m, req)...),
|
||||||
VerificationScript: acc.GetVerificationScript(),
|
VerificationScript: acc.GetVerificationScript(),
|
||||||
}
|
}
|
||||||
actualHash, err := c.SubmitP2PNotaryRequest(req)
|
actualHash, err := c.SubmitP2PNotaryRequest(req)
|
||||||
|
|
|
@ -154,7 +154,7 @@ func TestNotary(t *testing.T) {
|
||||||
mp1.StopSubscriptions()
|
mp1.StopSubscriptions()
|
||||||
})
|
})
|
||||||
|
|
||||||
notaryNodes := []interface{}{acc1.PrivateKey().PublicKey().Bytes(), acc2.PrivateKey().PublicKey().Bytes()}
|
notaryNodes := []interface{}{acc1.PublicKey().Bytes(), acc2.PrivateKey().PublicKey().Bytes()}
|
||||||
designationSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
|
designationSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
|
||||||
int64(noderoles.P2PNotary), notaryNodes)
|
int64(noderoles.P2PNotary), notaryNodes)
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ func TestNotary(t *testing.T) {
|
||||||
Scopes: transaction.None,
|
Scopes: transaction.None,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Account: requester.PrivateKey().PublicKey().GetScriptHash(),
|
Account: requester.ScriptHash(),
|
||||||
Scopes: transaction.None,
|
Scopes: transaction.None,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -222,12 +222,12 @@ func TestNotary(t *testing.T) {
|
||||||
var script []byte
|
var script []byte
|
||||||
switch requesters[i].typ {
|
switch requesters[i].typ {
|
||||||
case notary.Signature:
|
case notary.Signature:
|
||||||
script = requesters[i].accounts[0].PrivateKey().PublicKey().GetVerificationScript()
|
script = requesters[i].accounts[0].PublicKey().GetVerificationScript()
|
||||||
nKeys++
|
nKeys++
|
||||||
case notary.MultiSignature:
|
case notary.MultiSignature:
|
||||||
pubs := make(keys.PublicKeys, len(requesters[i].accounts))
|
pubs := make(keys.PublicKeys, len(requesters[i].accounts))
|
||||||
for j, r := range requesters[i].accounts {
|
for j, r := range requesters[i].accounts {
|
||||||
pubs[j] = r.PrivateKey().PublicKey()
|
pubs[j] = r.PublicKey()
|
||||||
}
|
}
|
||||||
script, err = smartcontract.CreateMultiSigRedeemScript(requesters[i].m, pubs)
|
script, err = smartcontract.CreateMultiSigRedeemScript(requesters[i].m, pubs)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -456,7 +456,7 @@ func TestNotary(t *testing.T) {
|
||||||
r, _ := checkCompleteStandardRequest(t, 1, false)
|
r, _ := checkCompleteStandardRequest(t, 1, false)
|
||||||
checkFallbackTxs(t, r, false)
|
checkFallbackTxs(t, r, false)
|
||||||
// set account back for the next tests
|
// set account back for the next tests
|
||||||
ntr1.UpdateNotaryNodes(keys.PublicKeys{acc1.PrivateKey().PublicKey()})
|
ntr1.UpdateNotaryNodes(keys.PublicKeys{acc1.PublicKey()})
|
||||||
|
|
||||||
// OnNewRequest: signature request
|
// OnNewRequest: signature request
|
||||||
for _, i := range []int{1, 2, 3, 10} {
|
for _, i := range []int{1, 2, 3, 10} {
|
||||||
|
@ -496,7 +496,7 @@ func TestNotary(t *testing.T) {
|
||||||
checkMainTx(t, requesters, r, 1, false)
|
checkMainTx(t, requesters, r, 1, false)
|
||||||
checkFallbackTxs(t, r, false)
|
checkFallbackTxs(t, r, false)
|
||||||
// set account back for the next tests
|
// set account back for the next tests
|
||||||
ntr1.UpdateNotaryNodes(keys.PublicKeys{acc1.PrivateKey().PublicKey()})
|
ntr1.UpdateNotaryNodes(keys.PublicKeys{acc1.PublicKey()})
|
||||||
|
|
||||||
// PostPersist: complete main transaction, signature request
|
// PostPersist: complete main transaction, signature request
|
||||||
setFinalizeWithError(true)
|
setFinalizeWithError(true)
|
||||||
|
@ -634,7 +634,7 @@ func TestNotary(t *testing.T) {
|
||||||
checkMainTx(t, requesters, requests, len(requests), false)
|
checkMainTx(t, requesters, requests, len(requests), false)
|
||||||
checkFallbackTxs(t, requests, false)
|
checkFallbackTxs(t, requests, false)
|
||||||
// set account back for the next tests
|
// set account back for the next tests
|
||||||
ntr1.UpdateNotaryNodes(keys.PublicKeys{acc1.PrivateKey().PublicKey()})
|
ntr1.UpdateNotaryNodes(keys.PublicKeys{acc1.PublicKey()})
|
||||||
|
|
||||||
// OnRequestRemoval: signature request, remove one fallback
|
// OnRequestRemoval: signature request, remove one fallback
|
||||||
// check OnNewRequest with finalization error
|
// check OnNewRequest with finalization error
|
||||||
|
@ -721,9 +721,9 @@ func TestNotary(t *testing.T) {
|
||||||
requester1, _ := wallet.NewAccount()
|
requester1, _ := wallet.NewAccount()
|
||||||
requester2, _ := wallet.NewAccount()
|
requester2, _ := wallet.NewAccount()
|
||||||
amount := int64(100_0000_0000)
|
amount := int64(100_0000_0000)
|
||||||
gasValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), bc.GetNotaryContractScriptHash(), amount, []interface{}{requester1.PrivateKey().PublicKey().GetScriptHash(), int64(bc.BlockHeight() + 50)})
|
gasValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), bc.GetNotaryContractScriptHash(), amount, []interface{}{requester1.ScriptHash(), int64(bc.BlockHeight() + 50)})
|
||||||
e.CheckGASBalance(t, notaryHash, big.NewInt(amount))
|
e.CheckGASBalance(t, notaryHash, big.NewInt(amount))
|
||||||
gasValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), bc.GetNotaryContractScriptHash(), amount, []interface{}{requester2.PrivateKey().PublicKey().GetScriptHash(), int64(bc.BlockHeight() + 50)})
|
gasValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), bc.GetNotaryContractScriptHash(), amount, []interface{}{requester2.ScriptHash(), int64(bc.BlockHeight() + 50)})
|
||||||
e.CheckGASBalance(t, notaryHash, big.NewInt(2*amount))
|
e.CheckGASBalance(t, notaryHash, big.NewInt(2*amount))
|
||||||
|
|
||||||
// create request for 2 standard signatures => main tx should be completed after the second request is added to the pool
|
// create request for 2 standard signatures => main tx should be completed after the second request is added to the pool
|
||||||
|
|
|
@ -15,7 +15,7 @@ func (n *Notary) UpdateNotaryNodes(notaryNodes keys.PublicKeys) {
|
||||||
|
|
||||||
if n.currAccount != nil {
|
if n.currAccount != nil {
|
||||||
for _, node := range notaryNodes {
|
for _, node := range notaryNodes {
|
||||||
if node.Equal(n.currAccount.PrivateKey().PublicKey()) {
|
if node.Equal(n.currAccount.PublicKey()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ func (n *Notary) UpdateNotaryNodes(notaryNodes keys.PublicKeys) {
|
||||||
for _, node := range notaryNodes {
|
for _, node := range notaryNodes {
|
||||||
acc = n.wallet.GetAccount(node.GetScriptHash())
|
acc = n.wallet.GetAccount(node.GetScriptHash())
|
||||||
if acc != nil {
|
if acc != nil {
|
||||||
if acc.PrivateKey() != nil {
|
if acc.CanSign() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
err := acc.Decrypt(n.Config.MainCfg.UnlockWallet.Password, n.wallet.Scrypt)
|
err := acc.Decrypt(n.Config.MainCfg.UnlockWallet.Password, n.wallet.Scrypt)
|
||||||
|
|
|
@ -44,11 +44,11 @@ func TestUpdateNotaryNodes(t *testing.T) {
|
||||||
// currAcc is nil before UpdateNotaryNodes call
|
// currAcc is nil before UpdateNotaryNodes call
|
||||||
require.Nil(t, ntr.currAccount)
|
require.Nil(t, ntr.currAccount)
|
||||||
// set account for the first time
|
// set account for the first time
|
||||||
ntr.UpdateNotaryNodes(keys.PublicKeys{acc.PrivateKey().PublicKey()})
|
ntr.UpdateNotaryNodes(keys.PublicKeys{acc.PublicKey()})
|
||||||
require.Equal(t, acc, ntr.currAccount)
|
require.Equal(t, acc, ntr.currAccount)
|
||||||
|
|
||||||
t.Run("account is already set", func(t *testing.T) {
|
t.Run("account is already set", func(t *testing.T) {
|
||||||
ntr.UpdateNotaryNodes(keys.PublicKeys{acc.PrivateKey().PublicKey(), randomKey.PublicKey()})
|
ntr.UpdateNotaryNodes(keys.PublicKeys{acc.PublicKey(), randomKey.PublicKey()})
|
||||||
require.Equal(t, acc, ntr.currAccount)
|
require.Equal(t, acc, ntr.currAccount)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -57,14 +57,14 @@ func TestUpdateNotaryNodes(t *testing.T) {
|
||||||
w, err := wallet.NewWalletFromFile("./testdata/notary1.json")
|
w, err := wallet.NewWalletFromFile("./testdata/notary1.json")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, w.Accounts[1].Decrypt("one", w.Scrypt))
|
require.NoError(t, w.Accounts[1].Decrypt("one", w.Scrypt))
|
||||||
ntr.UpdateNotaryNodes(keys.PublicKeys{w.Accounts[1].PrivateKey().PublicKey()})
|
ntr.UpdateNotaryNodes(keys.PublicKeys{w.Accounts[1].PublicKey()})
|
||||||
require.Equal(t, w.Accounts[1], ntr.currAccount)
|
require.Equal(t, w.Accounts[1], ntr.currAccount)
|
||||||
})
|
})
|
||||||
t.Run("bad config password", func(t *testing.T) {
|
t.Run("bad config password", func(t *testing.T) {
|
||||||
w, err := wallet.NewWalletFromFile("./testdata/notary1.json")
|
w, err := wallet.NewWalletFromFile("./testdata/notary1.json")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, w.Accounts[2].Decrypt("four", w.Scrypt))
|
require.NoError(t, w.Accounts[2].Decrypt("four", w.Scrypt))
|
||||||
ntr.UpdateNotaryNodes(keys.PublicKeys{w.Accounts[2].PrivateKey().PublicKey()})
|
ntr.UpdateNotaryNodes(keys.PublicKeys{w.Accounts[2].PublicKey()})
|
||||||
require.Nil(t, ntr.currAccount)
|
require.Nil(t, ntr.currAccount)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -222,6 +222,7 @@ func (n *Notary) Shutdown() {
|
||||||
n.Config.Log.Info("stopping notary service")
|
n.Config.Log.Info("stopping notary service")
|
||||||
close(n.stopCh)
|
close(n.stopCh)
|
||||||
<-n.done
|
<-n.done
|
||||||
|
n.wallet.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnNewRequest is a callback method which is called after a new notary request is added to the notary request pool.
|
// OnNewRequest is a callback method which is called after a new notary request is added to the notary request pool.
|
||||||
|
@ -391,7 +392,7 @@ func (n *Notary) PostPersist() {
|
||||||
// finalize adds missing Notary witnesses to the transaction (main or fallback) and pushes it to the network.
|
// finalize adds missing Notary witnesses to the transaction (main or fallback) and pushes it to the network.
|
||||||
func (n *Notary) finalize(acc *wallet.Account, tx *transaction.Transaction, h util.Uint256) error {
|
func (n *Notary) finalize(acc *wallet.Account, tx *transaction.Transaction, h util.Uint256) error {
|
||||||
notaryWitness := transaction.Witness{
|
notaryWitness := transaction.Witness{
|
||||||
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, acc.PrivateKey().SignHashable(uint32(n.Network), tx)...),
|
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, acc.SignHashable(n.Network, tx)...),
|
||||||
VerificationScript: []byte{},
|
VerificationScript: []byte{},
|
||||||
}
|
}
|
||||||
for i, signer := range tx.Signers {
|
for i, signer := range tx.Signers {
|
||||||
|
|
|
@ -30,7 +30,7 @@ func (o *Oracle) UpdateOracleNodes(oracleNodes keys.PublicKeys) {
|
||||||
for i := range oracleNodes {
|
for i := range oracleNodes {
|
||||||
acc = o.wallet.GetAccount(oracleNodes[i].GetScriptHash())
|
acc = o.wallet.GetAccount(oracleNodes[i].GetScriptHash())
|
||||||
if acc != nil {
|
if acc != nil {
|
||||||
if acc.PrivateKey() != nil {
|
if acc.CanSign() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
err := acc.Decrypt(o.MainCfg.UnlockWallet.Password, o.wallet.Scrypt)
|
err := acc.Decrypt(o.MainCfg.UnlockWallet.Password, o.wallet.Scrypt)
|
||||||
|
|
|
@ -191,6 +191,7 @@ func (o *Oracle) Shutdown() {
|
||||||
close(o.close)
|
close(o.close)
|
||||||
o.ResponseHandler.Shutdown()
|
o.ResponseHandler.Shutdown()
|
||||||
<-o.done
|
<-o.done
|
||||||
|
o.wallet.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start runs the oracle service in a separate goroutine.
|
// Start runs the oracle service in a separate goroutine.
|
||||||
|
|
|
@ -122,7 +122,7 @@ func TestCreateResponseTx(t *testing.T) {
|
||||||
}
|
}
|
||||||
cInvoker.Invoke(t, stackitem.Null{}, "requestURL", req.URL, *req.Filter, req.CallbackMethod, req.UserData, int64(req.GasForResponse))
|
cInvoker.Invoke(t, stackitem.Null{}, "requestURL", req.URL, *req.Filter, req.CallbackMethod, req.UserData, int64(req.GasForResponse))
|
||||||
bc.SetOracle(orc)
|
bc.SetOracle(orc)
|
||||||
orc.UpdateOracleNodes(keys.PublicKeys{acc.PrivateKey().PublicKey()})
|
orc.UpdateOracleNodes(keys.PublicKeys{acc.PublicKey()})
|
||||||
tx, err = orc.CreateResponseTx(int64(req.GasForResponse), 1, resp)
|
tx, err = orc.CreateResponseTx(int64(req.GasForResponse), 1, resp)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, 166, tx.Size())
|
assert.Equal(t, 166, tx.Size())
|
||||||
|
@ -150,7 +150,7 @@ func TestOracle(t *testing.T) {
|
||||||
|
|
||||||
acc1, orc1, m1, ch1 := getTestOracle(t, bc, "./testdata/oracle1.json", "one")
|
acc1, orc1, m1, ch1 := getTestOracle(t, bc, "./testdata/oracle1.json", "one")
|
||||||
acc2, orc2, m2, ch2 := getTestOracle(t, bc, "./testdata/oracle2.json", "two")
|
acc2, orc2, m2, ch2 := getTestOracle(t, bc, "./testdata/oracle2.json", "two")
|
||||||
oracleNodes := keys.PublicKeys{acc1.PrivateKey().PublicKey(), acc2.PrivateKey().PublicKey()}
|
oracleNodes := keys.PublicKeys{acc1.PublicKey(), acc2.PrivateKey().PublicKey()}
|
||||||
// Must be set in native contract for tx verification.
|
// Must be set in native contract for tx verification.
|
||||||
designationSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
|
designationSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
|
||||||
int64(roles.Oracle), []interface{}{oracleNodes[0].Bytes(), oracleNodes[1].Bytes()})
|
int64(roles.Oracle), []interface{}{oracleNodes[0].Bytes(), oracleNodes[1].Bytes()})
|
||||||
|
@ -249,10 +249,10 @@ func TestOracle(t *testing.T) {
|
||||||
require.Empty(t, ch2)
|
require.Empty(t, ch2)
|
||||||
|
|
||||||
t.Run("InvalidSignature", func(t *testing.T) {
|
t.Run("InvalidSignature", func(t *testing.T) {
|
||||||
orc1.AddResponse(acc2.PrivateKey().PublicKey(), m2[0].resp.ID, []byte{1, 2, 3})
|
orc1.AddResponse(acc2.PublicKey(), m2[0].resp.ID, []byte{1, 2, 3})
|
||||||
require.Empty(t, ch1)
|
require.Empty(t, ch1)
|
||||||
})
|
})
|
||||||
orc1.AddResponse(acc2.PrivateKey().PublicKey(), m2[0].resp.ID, m2[0].txSig)
|
orc1.AddResponse(acc2.PublicKey(), m2[0].resp.ID, m2[0].txSig)
|
||||||
checkEmitTx(t, ch1)
|
checkEmitTx(t, ch1)
|
||||||
|
|
||||||
t.Run("FirstOtherThenMe", func(t *testing.T) {
|
t.Run("FirstOtherThenMe", func(t *testing.T) {
|
||||||
|
@ -264,7 +264,7 @@ func TestOracle(t *testing.T) {
|
||||||
Result: []byte{1, 2, 3, 4},
|
Result: []byte{1, 2, 3, 4},
|
||||||
}
|
}
|
||||||
req := checkResp(t, reqID, resp)
|
req := checkResp(t, reqID, resp)
|
||||||
orc2.AddResponse(acc1.PrivateKey().PublicKey(), reqID, m1[reqID].txSig)
|
orc2.AddResponse(acc1.PublicKey(), reqID, m1[reqID].txSig)
|
||||||
require.Empty(t, ch2)
|
require.Empty(t, ch2)
|
||||||
|
|
||||||
reqs := map[uint64]*state.OracleRequest{reqID: req}
|
reqs := map[uint64]*state.OracleRequest{reqID: req}
|
||||||
|
@ -357,7 +357,7 @@ func TestOracleFull(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
designationSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
|
designationSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
|
||||||
int64(roles.Oracle), []interface{}{acc.PrivateKey().PublicKey().Bytes()})
|
int64(roles.Oracle), []interface{}{acc.PublicKey().Bytes()})
|
||||||
|
|
||||||
cs := contracts.GetOracleContractState(t, pathToInternalContracts, validator.ScriptHash(), 0)
|
cs := contracts.GetOracleContractState(t, pathToInternalContracts, validator.ScriptHash(), 0)
|
||||||
e.DeployContract(t, &neotest.Contract{
|
e.DeployContract(t, &neotest.Contract{
|
||||||
|
@ -391,7 +391,7 @@ func TestNotYetRunningOracle(t *testing.T) {
|
||||||
t.Cleanup(bc.Close)
|
t.Cleanup(bc.Close)
|
||||||
|
|
||||||
designationSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
|
designationSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
|
||||||
int64(roles.Oracle), []interface{}{acc.PrivateKey().PublicKey().Bytes()})
|
int64(roles.Oracle), []interface{}{acc.PublicKey().Bytes()})
|
||||||
|
|
||||||
var req state.OracleRequest
|
var req state.OracleRequest
|
||||||
var reqs = make(map[uint64]*state.OracleRequest)
|
var reqs = make(map[uint64]*state.OracleRequest)
|
||||||
|
|
|
@ -1033,11 +1033,6 @@ func TestSignAndPushP2PNotaryRequest(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
require.NoError(t, c.Init())
|
require.NoError(t, c.Init())
|
||||||
t.Run("bad account address", func(t *testing.T) {
|
|
||||||
_, err := c.SignAndPushP2PNotaryRequest(nil, nil, 0, 0, 0, &wallet.Account{Address: "not-an-addr"}) //nolint:staticcheck // SA1019: c.SignAndPushP2PNotaryRequest is deprecated
|
|
||||||
require.NotNil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("bad fallback script", func(t *testing.T) {
|
t.Run("bad fallback script", func(t *testing.T) {
|
||||||
_, err := c.SignAndPushP2PNotaryRequest(nil, []byte{byte(opcode.ASSERT)}, -1, 0, 0, acc) //nolint:staticcheck // SA1019: c.SignAndPushP2PNotaryRequest is deprecated
|
_, err := c.SignAndPushP2PNotaryRequest(nil, []byte{byte(opcode.ASSERT)}, -1, 0, 0, acc) //nolint:staticcheck // SA1019: c.SignAndPushP2PNotaryRequest is deprecated
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
|
|
|
@ -90,7 +90,6 @@ func (s *service) trySendRoot(ir *incompleteRoot, acc *wallet.Account) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) sendValidatedRoot(r *state.MPTRoot, acc *wallet.Account) {
|
func (s *service) sendValidatedRoot(r *state.MPTRoot, acc *wallet.Account) {
|
||||||
priv := acc.PrivateKey()
|
|
||||||
w := io.NewBufBinWriter()
|
w := io.NewBufBinWriter()
|
||||||
m := NewMessage(RootT, r)
|
m := NewMessage(RootT, r)
|
||||||
m.EncodeBinary(w.BinWriter)
|
m.EncodeBinary(w.BinWriter)
|
||||||
|
@ -98,13 +97,13 @@ func (s *service) sendValidatedRoot(r *state.MPTRoot, acc *wallet.Account) {
|
||||||
Category: Category,
|
Category: Category,
|
||||||
ValidBlockStart: r.Index,
|
ValidBlockStart: r.Index,
|
||||||
ValidBlockEnd: r.Index + rootValidEndInc,
|
ValidBlockEnd: r.Index + rootValidEndInc,
|
||||||
Sender: priv.GetScriptHash(),
|
Sender: acc.ScriptHash(),
|
||||||
Data: w.Bytes(),
|
Data: w.Bytes(),
|
||||||
Witness: transaction.Witness{
|
Witness: transaction.Witness{
|
||||||
VerificationScript: acc.GetVerificationScript(),
|
VerificationScript: acc.GetVerificationScript(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
sig := priv.SignHashable(uint32(s.Network), ep)
|
sig := acc.SignHashable(s.Network, ep)
|
||||||
buf := io.NewBufBinWriter()
|
buf := io.NewBufBinWriter()
|
||||||
emit.Bytes(buf.BinWriter, sig)
|
emit.Bytes(buf.BinWriter, sig)
|
||||||
ep.Witness.InvocationScript = buf.Bytes()
|
ep.Witness.InvocationScript = buf.Bytes()
|
||||||
|
|
|
@ -65,13 +65,13 @@ func newMajorityMultisigWithGAS(t *testing.T, n int) (util.Uint160, keys.PublicK
|
||||||
accs[i] = acc
|
accs[i] = acc
|
||||||
}
|
}
|
||||||
sort.Slice(accs, func(i, j int) bool {
|
sort.Slice(accs, func(i, j int) bool {
|
||||||
pi := accs[i].PrivateKey().PublicKey()
|
pi := accs[i].PublicKey()
|
||||||
pj := accs[j].PrivateKey().PublicKey()
|
pj := accs[j].PublicKey()
|
||||||
return pi.Cmp(pj) == -1
|
return pi.Cmp(pj) == -1
|
||||||
})
|
})
|
||||||
pubs := make(keys.PublicKeys, n)
|
pubs := make(keys.PublicKeys, n)
|
||||||
for i := range pubs {
|
for i := range pubs {
|
||||||
pubs[i] = accs[i].PrivateKey().PublicKey()
|
pubs[i] = accs[i].PublicKey()
|
||||||
}
|
}
|
||||||
script, err := smartcontract.CreateMajorityMultiSigRedeemScript(pubs)
|
script, err := smartcontract.CreateMajorityMultiSigRedeemScript(pubs)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -126,7 +126,7 @@ func TestStateRoot(t *testing.T) {
|
||||||
t.Run("invalid signer", func(t *testing.T) {
|
t.Run("invalid signer", func(t *testing.T) {
|
||||||
accInv, err := wallet.NewAccount()
|
accInv, err := wallet.NewAccount()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pubs := keys.PublicKeys{accInv.PrivateKey().PublicKey()}
|
pubs := keys.PublicKeys{accInv.PublicKey()}
|
||||||
require.NoError(t, accInv.ConvertMultisig(1, pubs))
|
require.NoError(t, accInv.ConvertMultisig(1, pubs))
|
||||||
gasValidatorInvoker.Invoke(t, true, "transfer", validator.ScriptHash(), accInv.Contract.ScriptHash(), 1_0000_0000, nil)
|
gasValidatorInvoker.Invoke(t, true, "transfer", validator.ScriptHash(), accInv.Contract.ScriptHash(), 1_0000_0000, nil)
|
||||||
r, err := bc.GetStateModule().GetStateRoot(1)
|
r, err := bc.GetStateModule().GetStateRoot(1)
|
||||||
|
|
|
@ -74,6 +74,7 @@ func (s *service) Shutdown() {
|
||||||
s.log.Info("stopping state validation service")
|
s.log.Info("stopping state validation service")
|
||||||
close(s.stopCh)
|
close(s.stopCh)
|
||||||
<-s.done
|
<-s.done
|
||||||
|
s.wallet.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) signAndSend(r *state.MPTRoot) error {
|
func (s *service) signAndSend(r *state.MPTRoot) error {
|
||||||
|
@ -86,12 +87,12 @@ func (s *service) signAndSend(r *state.MPTRoot) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sig := acc.PrivateKey().SignHashable(uint32(s.Network), r)
|
sig := acc.SignHashable(s.Network, r)
|
||||||
incRoot := s.getIncompleteRoot(r.Index, myIndex)
|
incRoot := s.getIncompleteRoot(r.Index, myIndex)
|
||||||
incRoot.Lock()
|
incRoot.Lock()
|
||||||
defer incRoot.Unlock()
|
defer incRoot.Unlock()
|
||||||
incRoot.root = r
|
incRoot.root = r
|
||||||
incRoot.addSignature(acc.PrivateKey().PublicKey(), sig)
|
incRoot.addSignature(acc.PublicKey(), sig)
|
||||||
incRoot.reverify(s.Network)
|
incRoot.reverify(s.Network)
|
||||||
s.trySendRoot(incRoot, acc)
|
s.trySendRoot(incRoot, acc)
|
||||||
|
|
||||||
|
@ -110,13 +111,13 @@ func (s *service) signAndSend(r *state.MPTRoot) error {
|
||||||
Category: Category,
|
Category: Category,
|
||||||
ValidBlockStart: r.Index,
|
ValidBlockStart: r.Index,
|
||||||
ValidBlockEnd: r.Index + voteValidEndInc,
|
ValidBlockEnd: r.Index + voteValidEndInc,
|
||||||
Sender: acc.PrivateKey().GetScriptHash(),
|
Sender: acc.ScriptHash(),
|
||||||
Data: w.Bytes(),
|
Data: w.Bytes(),
|
||||||
Witness: transaction.Witness{
|
Witness: transaction.Witness{
|
||||||
VerificationScript: acc.GetVerificationScript(),
|
VerificationScript: acc.GetVerificationScript(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
sig = acc.PrivateKey().SignHashable(uint32(s.Network), e)
|
sig = acc.SignHashable(s.Network, e)
|
||||||
buf := io.NewBufBinWriter()
|
buf := io.NewBufBinWriter()
|
||||||
emit.Bytes(buf.BinWriter, sig)
|
emit.Bytes(buf.BinWriter, sig)
|
||||||
e.Witness.InvocationScript = buf.Bytes()
|
e.Witness.InvocationScript = buf.Bytes()
|
||||||
|
|
|
@ -33,6 +33,7 @@ func ExampleBuilder() {
|
||||||
b.Reset() // Copy the old script above if you need it!
|
b.Reset() // Copy the old script above if you need it!
|
||||||
|
|
||||||
w, _ := wallet.NewWalletFromFile("somewhere")
|
w, _ := wallet.NewWalletFromFile("somewhere")
|
||||||
|
defer w.Close()
|
||||||
// Assuming there is one Account inside
|
// Assuming there is one Account inside
|
||||||
a, _ := actor.NewSimple(c, w.Accounts[0])
|
a, _ := actor.NewSimple(c, w.Accounts[0])
|
||||||
from := w.Accounts[0].Contract.ScriptHash() // Assuming Contract is present.
|
from := w.Accounts[0].Contract.ScriptHash() // Assuming Contract is present.
|
||||||
|
|
|
@ -28,3 +28,10 @@ func Copy(b []byte) []byte {
|
||||||
copy(d, b)
|
copy(d, b)
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean wipes the data in b by filling it with zeros.
|
||||||
|
func Clean(b []byte) {
|
||||||
|
for i := range b {
|
||||||
|
b[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -49,3 +49,11 @@ func TestCopyReverse(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClean(t *testing.T) {
|
||||||
|
for _, tc := range testCases[1:] { // Empty one will be equal.
|
||||||
|
cp := Copy(tc.arr)
|
||||||
|
Clean(cp)
|
||||||
|
require.NotEqual(t, tc.arr, cp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package wallet
|
package wallet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
@ -21,11 +20,8 @@ type Account struct {
|
||||||
// NEO private key.
|
// NEO private key.
|
||||||
privateKey *keys.PrivateKey
|
privateKey *keys.PrivateKey
|
||||||
|
|
||||||
// NEO public key.
|
// Script hash corresponding to the Address.
|
||||||
publicKey []byte
|
scriptHash util.Uint160
|
||||||
|
|
||||||
// Account import file.
|
|
||||||
wif string
|
|
||||||
|
|
||||||
// NEO public address.
|
// NEO public address.
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
|
@ -87,8 +83,6 @@ func (a *Account) SignTx(net netmode.Magic, t *transaction.Transaction) error {
|
||||||
var (
|
var (
|
||||||
haveAcc bool
|
haveAcc bool
|
||||||
pos int
|
pos int
|
||||||
accHash util.Uint160
|
|
||||||
err error
|
|
||||||
)
|
)
|
||||||
if a.Locked {
|
if a.Locked {
|
||||||
return errors.New("account is locked")
|
return errors.New("account is locked")
|
||||||
|
@ -96,12 +90,8 @@ func (a *Account) SignTx(net netmode.Magic, t *transaction.Transaction) error {
|
||||||
if a.Contract == nil {
|
if a.Contract == nil {
|
||||||
return errors.New("account has no contract")
|
return errors.New("account has no contract")
|
||||||
}
|
}
|
||||||
accHash, err = address.StringToUint160(a.Address)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for i := range t.Signers {
|
for i := range t.Signers {
|
||||||
if t.Signers[i].Account.Equals(accHash) {
|
if t.Signers[i].Account.Equals(a.ScriptHash()) {
|
||||||
haveAcc = true
|
haveAcc = true
|
||||||
pos = i
|
pos = i
|
||||||
break
|
break
|
||||||
|
@ -136,6 +126,15 @@ func (a *Account) SignTx(net netmode.Magic, t *transaction.Transaction) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignHashable signs the given Hashable item and returns the signature. If this
|
||||||
|
// account can't sign (CanSign() returns false) nil is returned.
|
||||||
|
func (a *Account) SignHashable(net netmode.Magic, item hash.Hashable) []byte {
|
||||||
|
if !a.CanSign() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return a.privateKey.SignHashable(uint32(net), item)
|
||||||
|
}
|
||||||
|
|
||||||
// CanSign returns true when account is not locked and has a decrypted private
|
// CanSign returns true when account is not locked and has a decrypted private
|
||||||
// key inside, so it's ready to create real signatures.
|
// key inside, so it's ready to create real signatures.
|
||||||
func (a *Account) CanSign() bool {
|
func (a *Account) CanSign() bool {
|
||||||
|
@ -147,11 +146,13 @@ func (a *Account) GetVerificationScript() []byte {
|
||||||
if a.Contract != nil {
|
if a.Contract != nil {
|
||||||
return a.Contract.Script
|
return a.Contract.Script
|
||||||
}
|
}
|
||||||
return a.PrivateKey().PublicKey().GetVerificationScript()
|
return a.privateKey.PublicKey().GetVerificationScript()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt decrypts the EncryptedWIF with the given passphrase returning error
|
// Decrypt decrypts the EncryptedWIF with the given passphrase returning error
|
||||||
// if anything goes wrong.
|
// if anything goes wrong. After the decryption Account can be used to sign
|
||||||
|
// things unless it's locked. Don't decrypt the key unless you want to sign
|
||||||
|
// something and don't forget to call Close after use for maximum safety.
|
||||||
func (a *Account) Decrypt(passphrase string, scrypt keys.ScryptParams) error {
|
func (a *Account) Decrypt(passphrase string, scrypt keys.ScryptParams) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -163,9 +164,6 @@ func (a *Account) Decrypt(passphrase string, scrypt keys.ScryptParams) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
a.publicKey = a.privateKey.PublicKey().Bytes()
|
|
||||||
a.wif = a.privateKey.WIF()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,11 +178,45 @@ func (a *Account) Encrypt(passphrase string, scrypt keys.ScryptParams) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrivateKey returns private key corresponding to the account.
|
// PrivateKey returns private key corresponding to the account if it's unlocked.
|
||||||
|
// Please be very careful when using it, do not copy its contents and do not
|
||||||
|
// keep a pointer to it unless you absolutely need to. Most of the time you can
|
||||||
|
// use other methods (PublicKey, ScriptHash, SignHashable) depending on your
|
||||||
|
// needs and it'll be safer this way.
|
||||||
func (a *Account) PrivateKey() *keys.PrivateKey {
|
func (a *Account) PrivateKey() *keys.PrivateKey {
|
||||||
return a.privateKey
|
return a.privateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PublicKey returns the public key associated with the private key corresponding to
|
||||||
|
// the account. It can return nil if account is locked (use CanSign to check).
|
||||||
|
func (a *Account) PublicKey() *keys.PublicKey {
|
||||||
|
if !a.CanSign() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return a.privateKey.PublicKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScriptHash returns the script hash (account) that the Account.Address is
|
||||||
|
// derived from. It never returns an error, so if this Account has an invalid
|
||||||
|
// Address you'll just get a zero script hash.
|
||||||
|
func (a *Account) ScriptHash() util.Uint160 {
|
||||||
|
if a.scriptHash.Equals(util.Uint160{}) {
|
||||||
|
a.scriptHash, _ = address.StringToUint160(a.Address)
|
||||||
|
}
|
||||||
|
return a.scriptHash
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close cleans up the private key used by Account and disassociates it from
|
||||||
|
// Account. The Account can no longer sign anything after this call, but Decrypt
|
||||||
|
// can make it usable again.
|
||||||
|
func (a *Account) Close() {
|
||||||
|
if a.privateKey == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
a.privateKey.Destroy()
|
||||||
|
a.privateKey = nil
|
||||||
|
}
|
||||||
|
|
||||||
// NewAccountFromWIF creates a new Account from the given WIF.
|
// NewAccountFromWIF creates a new Account from the given WIF.
|
||||||
func NewAccountFromWIF(wif string) (*Account, error) {
|
func NewAccountFromWIF(wif string) (*Account, error) {
|
||||||
privKey, err := keys.NewPrivateKeyFromWIF(wif)
|
privKey, err := keys.NewPrivateKeyFromWIF(wif)
|
||||||
|
@ -209,9 +241,16 @@ func NewAccountFromEncryptedWIF(wif string, pass string, scrypt keys.ScryptParam
|
||||||
|
|
||||||
// ConvertMultisig sets a's contract to multisig contract with m sufficient signatures.
|
// ConvertMultisig sets a's contract to multisig contract with m sufficient signatures.
|
||||||
func (a *Account) ConvertMultisig(m int, pubs []*keys.PublicKey) error {
|
func (a *Account) ConvertMultisig(m int, pubs []*keys.PublicKey) error {
|
||||||
|
if a.Locked {
|
||||||
|
return errors.New("account is locked")
|
||||||
|
}
|
||||||
|
if a.privateKey == nil {
|
||||||
|
return errors.New("account key is not available (need to decrypt?)")
|
||||||
|
}
|
||||||
var found bool
|
var found bool
|
||||||
|
accKey := a.privateKey.PublicKey()
|
||||||
for i := range pubs {
|
for i := range pubs {
|
||||||
if bytes.Equal(a.publicKey, pubs[i].Bytes()) {
|
if accKey.Equal(pubs[i]) {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -226,7 +265,8 @@ func (a *Account) ConvertMultisig(m int, pubs []*keys.PublicKey) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
a.Address = address.Uint160ToString(hash.Hash160(script))
|
a.scriptHash = hash.Hash160(script)
|
||||||
|
a.Address = address.Uint160ToString(a.scriptHash)
|
||||||
a.Contract = &Contract{
|
a.Contract = &Contract{
|
||||||
Script: script,
|
Script: script,
|
||||||
Parameters: getContractParams(m),
|
Parameters: getContractParams(m),
|
||||||
|
@ -238,14 +278,11 @@ func (a *Account) ConvertMultisig(m int, pubs []*keys.PublicKey) error {
|
||||||
// NewAccountFromPrivateKey creates a wallet from the given PrivateKey.
|
// NewAccountFromPrivateKey creates a wallet from the given PrivateKey.
|
||||||
func NewAccountFromPrivateKey(p *keys.PrivateKey) *Account {
|
func NewAccountFromPrivateKey(p *keys.PrivateKey) *Account {
|
||||||
pubKey := p.PublicKey()
|
pubKey := p.PublicKey()
|
||||||
pubAddr := p.Address()
|
|
||||||
wif := p.WIF()
|
|
||||||
|
|
||||||
a := &Account{
|
a := &Account{
|
||||||
publicKey: pubKey.Bytes(),
|
|
||||||
privateKey: p,
|
privateKey: p,
|
||||||
Address: pubAddr,
|
scriptHash: p.GetScriptHash(),
|
||||||
wif: wif,
|
Address: p.Address(),
|
||||||
Contract: &Contract{
|
Contract: &Contract{
|
||||||
Script: pubKey.GetVerificationScript(),
|
Script: pubKey.GetVerificationScript(),
|
||||||
Parameters: getContractParams(1),
|
Parameters: getContractParams(1),
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"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/hash"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -18,6 +19,7 @@ func TestNewAccount(t *testing.T) {
|
||||||
acc, err := NewAccount()
|
acc, err := NewAccount()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, acc)
|
require.NotNil(t, acc)
|
||||||
|
require.Equal(t, acc.Address, address.Uint160ToString(acc.ScriptHash()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDecryptAccount(t *testing.T) {
|
func TestDecryptAccount(t *testing.T) {
|
||||||
|
@ -105,7 +107,7 @@ func TestContractSignTx(t *testing.T) {
|
||||||
|
|
||||||
require.Error(t, acc2.SignTx(0, tx))
|
require.Error(t, acc2.SignTx(0, tx))
|
||||||
|
|
||||||
pubs := keys.PublicKeys{acc.privateKey.PublicKey(), acc2.privateKey.PublicKey()}
|
pubs := keys.PublicKeys{acc.PublicKey(), acc2.PublicKey()}
|
||||||
multiS, err := smartcontract.CreateDefaultMultiSigRedeemScript(pubs)
|
multiS, err := smartcontract.CreateDefaultMultiSigRedeemScript(pubs)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
multiAcc := NewAccountFromPrivateKey(acc.privateKey)
|
multiAcc := NewAccountFromPrivateKey(acc.privateKey)
|
||||||
|
@ -138,18 +140,23 @@ func TestContractSignTx(t *testing.T) {
|
||||||
|
|
||||||
acc2.Locked = true
|
acc2.Locked = true
|
||||||
require.False(t, acc2.CanSign())
|
require.False(t, acc2.CanSign())
|
||||||
require.Error(t, acc2.SignTx(0, tx)) // Locked account.
|
require.Error(t, acc2.SignTx(0, tx)) // Locked account.
|
||||||
|
require.Nil(t, acc2.PublicKey()) // Locked account.
|
||||||
|
require.Nil(t, acc2.SignHashable(0, tx)) // Locked account.
|
||||||
|
|
||||||
acc2.Locked = false
|
acc2.Locked = false
|
||||||
acc2.privateKey = nil
|
acc2.Close()
|
||||||
require.False(t, acc2.CanSign())
|
require.False(t, acc2.CanSign())
|
||||||
require.Error(t, acc2.SignTx(0, tx)) // No private key.
|
require.Error(t, acc2.SignTx(0, tx)) // No private key.
|
||||||
|
acc2.Close() // No-op.
|
||||||
|
require.False(t, acc2.CanSign())
|
||||||
|
|
||||||
tx.Scripts = append(tx.Scripts, transaction.Witness{
|
tx.Scripts = append(tx.Scripts, transaction.Witness{
|
||||||
VerificationScript: acc.Contract.Script,
|
VerificationScript: acc.Contract.Script,
|
||||||
})
|
})
|
||||||
require.NoError(t, acc.SignTx(0, tx)) // Add invocation script for existing witness.
|
require.NoError(t, acc.SignTx(0, tx)) // Add invocation script for existing witness.
|
||||||
require.Equal(t, 66, len(tx.Scripts[1].InvocationScript))
|
require.Equal(t, 66, len(tx.Scripts[1].InvocationScript))
|
||||||
|
require.NotNil(t, acc.SignHashable(0, tx)) // Works via Hashable too.
|
||||||
|
|
||||||
require.NoError(t, multiAcc.SignTx(0, tx))
|
require.NoError(t, multiAcc.SignTx(0, tx))
|
||||||
require.Equal(t, 3, len(tx.Scripts))
|
require.Equal(t, 3, len(tx.Scripts))
|
||||||
|
@ -179,6 +186,19 @@ func TestAccount_ConvertMultisig(t *testing.T) {
|
||||||
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.Run("locked", func(t *testing.T) {
|
||||||
|
a.Locked = true
|
||||||
|
pubs := convertPubs(t, hexs)
|
||||||
|
require.Error(t, a.ConvertMultisig(1, pubs))
|
||||||
|
a.Locked = false
|
||||||
|
})
|
||||||
|
t.Run("no private key", func(t *testing.T) {
|
||||||
|
pk := a.privateKey
|
||||||
|
a.privateKey = nil
|
||||||
|
pubs := convertPubs(t, hexs)
|
||||||
|
require.Error(t, a.ConvertMultisig(0, pubs))
|
||||||
|
a.privateKey = pk
|
||||||
|
})
|
||||||
t.Run("invalid number of signatures", func(t *testing.T) {
|
t.Run("invalid number of signatures", func(t *testing.T) {
|
||||||
pubs := convertPubs(t, hexs)
|
pubs := convertPubs(t, hexs)
|
||||||
require.Error(t, a.ConvertMultisig(0, pubs))
|
require.Error(t, a.ConvertMultisig(0, pubs))
|
||||||
|
@ -215,9 +235,9 @@ func convertPubs(t *testing.T, hexKeys []string) []*keys.PublicKey {
|
||||||
func compareFields(t *testing.T, tk keytestcases.Ktype, acc *Account) {
|
func compareFields(t *testing.T, tk keytestcases.Ktype, acc *Account) {
|
||||||
want, have := tk.Address, acc.Address
|
want, have := tk.Address, acc.Address
|
||||||
require.Equalf(t, want, have, "expected address %s got %s", want, have)
|
require.Equalf(t, want, have, "expected address %s got %s", want, have)
|
||||||
want, have = tk.Wif, acc.wif
|
want, have = tk.Wif, acc.privateKey.WIF()
|
||||||
require.Equalf(t, want, have, "expected wif %s got %s", want, have)
|
require.Equalf(t, want, have, "expected wif %s got %s", want, have)
|
||||||
want, have = tk.PublicKey, hex.EncodeToString(acc.publicKey)
|
want, have = tk.PublicKey, hex.EncodeToString(acc.PublicKey().Bytes())
|
||||||
require.Equalf(t, want, have, "expected pub key %s got %s", want, have)
|
require.Equalf(t, want, have, "expected pub key %s got %s", want, have)
|
||||||
want, have = tk.PrivateKey, acc.privateKey.String()
|
want, have = tk.PrivateKey, acc.privateKey.String()
|
||||||
require.Equalf(t, want, have, "expected priv key %s got %s", want, have)
|
require.Equalf(t, want, have, "expected priv key %s got %s", want, have)
|
||||||
|
|
|
@ -168,9 +168,14 @@ func (w *Wallet) JSON() ([]byte, error) {
|
||||||
return json.MarshalIndent(w, " ", " ")
|
return json.MarshalIndent(w, " ", " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: Close is deprecated.
|
// Close closes all Wallet accounts making them incapable of signing anything
|
||||||
// Close performs nothing and is left for backwards compatibility.
|
// (unless they're decrypted again). It's not doing anything to the underlying
|
||||||
func (w *Wallet) Close() {}
|
// wallet file.
|
||||||
|
func (w *Wallet) Close() {
|
||||||
|
for _, acc := range w.Accounts {
|
||||||
|
acc.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetAccount returns an account corresponding to the provided scripthash.
|
// GetAccount returns an account corresponding to the provided scripthash.
|
||||||
func (w *Wallet) GetAccount(h util.Uint160) *Account {
|
func (w *Wallet) GetAccount(h util.Uint160) *Account {
|
||||||
|
|
|
@ -34,13 +34,16 @@ func TestNewWalletFromFile_Negative_NoFile(t *testing.T) {
|
||||||
require.Errorf(t, err, "open testWallet: no such file or directory")
|
require.Errorf(t, err, "open testWallet: no such file or directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateAccount(t *testing.T) {
|
func TestCreateAccountAndClose(t *testing.T) {
|
||||||
wallet := checkWalletConstructor(t)
|
wallet := checkWalletConstructor(t)
|
||||||
|
|
||||||
errAcc := wallet.CreateAccount("testName", "testPass")
|
errAcc := wallet.CreateAccount("testName", "testPass")
|
||||||
require.NoError(t, errAcc)
|
require.NoError(t, errAcc)
|
||||||
accounts := wallet.Accounts
|
accounts := wallet.Accounts
|
||||||
require.Len(t, accounts, 1)
|
require.Len(t, accounts, 1)
|
||||||
|
require.True(t, wallet.Accounts[0].CanSign())
|
||||||
|
wallet.Close()
|
||||||
|
require.False(t, wallet.Accounts[0].CanSign())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddAccount(t *testing.T) {
|
func TestAddAccount(t *testing.T) {
|
||||||
|
@ -48,8 +51,6 @@ func TestAddAccount(t *testing.T) {
|
||||||
|
|
||||||
wallet.AddAccount(&Account{
|
wallet.AddAccount(&Account{
|
||||||
privateKey: nil,
|
privateKey: nil,
|
||||||
publicKey: nil,
|
|
||||||
wif: "",
|
|
||||||
Address: "real",
|
Address: "real",
|
||||||
EncryptedWIF: "",
|
EncryptedWIF: "",
|
||||||
Label: "",
|
Label: "",
|
||||||
|
@ -78,8 +79,6 @@ func TestSave(t *testing.T) {
|
||||||
|
|
||||||
wallet.AddAccount(&Account{
|
wallet.AddAccount(&Account{
|
||||||
privateKey: nil,
|
privateKey: nil,
|
||||||
publicKey: nil,
|
|
||||||
wif: "",
|
|
||||||
Address: "",
|
Address: "",
|
||||||
EncryptedWIF: "",
|
EncryptedWIF: "",
|
||||||
Label: "",
|
Label: "",
|
||||||
|
@ -103,6 +102,7 @@ func TestSave(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 2, len(w2.Accounts))
|
require.Equal(t, 2, len(w2.Accounts))
|
||||||
require.NoError(t, w2.Accounts[1].Decrypt("pass", w2.Scrypt))
|
require.NoError(t, w2.Accounts[1].Decrypt("pass", w2.Scrypt))
|
||||||
|
_ = w2.Accounts[1].ScriptHash() // openedWallet has it for acc 1.
|
||||||
require.Equal(t, openedWallet.Accounts, w2.Accounts)
|
require.Equal(t, openedWallet.Accounts, w2.Accounts)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue