Merge pull request #2672 from nspcc-dev/private-key-cleanup

Private key cleanup
This commit is contained in:
Roman Khimov 2022-09-02 16:20:39 +03:00 committed by GitHub
commit 3da8b98fc3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 337 additions and 234 deletions

View file

@ -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,

View file

@ -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) {

View file

@ -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)

View file

@ -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)
} }
} }

View file

@ -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

View file

@ -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 {

View file

@ -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 == "" {

View file

@ -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)

View file

@ -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 {

View file

@ -173,6 +173,11 @@ 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]",
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, Action: dumpWallet,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
@ -198,6 +203,12 @@ 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>]",
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, Action: exportKeys,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
@ -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
View file

@ -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
View file

@ -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=

View file

@ -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")

View file

@ -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()

View file

@ -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

View file

@ -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) {

View file

@ -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

View file

@ -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()}

View file

@ -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{
{ {

View file

@ -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()) {

View file

@ -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)

View file

@ -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)

View file

@ -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 {

View file

@ -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)
} }
} }

View file

@ -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
} }

View file

@ -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)
}

View file

@ -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,

View file

@ -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...)
} }

View file

@ -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())
} }
} }
} }

View file

@ -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())
} }

View file

@ -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
} }

View file

@ -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",

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)
}) })
}) })

View file

@ -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 {

View file

@ -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)

View file

@ -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.

View file

@ -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)

View file

@ -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)

View file

@ -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()

View file

@ -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)

View file

@ -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()

View file

@ -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.

View file

@ -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
}
}

View file

@ -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)
}
}

View file

@ -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),

View file

@ -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)
@ -139,17 +141,22 @@ 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)

View file

@ -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 {

View file

@ -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)
}) })
} }