From 354e59cf9e1a3b7601a1837747d0da94a386e85b Mon Sep 17 00:00:00 2001 From: siovanus Date: Thu, 12 Oct 2023 10:51:23 +0800 Subject: [PATCH] add p2p keystore (#126) --- accounts/keystore/keystore.go | 14 +-- .../governance/node_manager/external.go | 2 +- node/config.go | 99 +++++++++++++++++++ 3 files changed, 107 insertions(+), 8 deletions(-) diff --git a/accounts/keystore/keystore.go b/accounts/keystore/keystore.go index 88dcfbeb..64b34504 100644 --- a/accounts/keystore/keystore.go +++ b/accounts/keystore/keystore.go @@ -240,7 +240,7 @@ func (ks *KeyStore) Delete(a accounts.Account, passphrase string) error { // Decrypting the key isn't really necessary, but we do // it anyway to check the password and zero out the key // immediately afterwards. - a, key, err := ks.getDecryptedKey(a, passphrase) + a, key, err := ks.GetDecryptedKey(a, passphrase) if key != nil { zeroKey(key.PrivateKey) } @@ -292,7 +292,7 @@ func (ks *KeyStore) SignTx(a accounts.Account, tx *types.Transaction, chainID *b // can be decrypted with the given passphrase. The produced signature is in the // [R || S || V] format where V is 0 or 1. func (ks *KeyStore) SignHashWithPassphrase(a accounts.Account, passphrase string, hash []byte) (signature []byte, err error) { - _, key, err := ks.getDecryptedKey(a, passphrase) + _, key, err := ks.GetDecryptedKey(a, passphrase) if err != nil { return nil, err } @@ -303,7 +303,7 @@ func (ks *KeyStore) SignHashWithPassphrase(a accounts.Account, passphrase string // SignTxWithPassphrase signs the transaction if the private key matching the // given address can be decrypted with the given passphrase. func (ks *KeyStore) SignTxWithPassphrase(a accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { - _, key, err := ks.getDecryptedKey(a, passphrase) + _, key, err := ks.GetDecryptedKey(a, passphrase) if err != nil { return nil, err } @@ -338,7 +338,7 @@ func (ks *KeyStore) Lock(addr common.Address) error { // shortens the active unlock timeout. If the address was previously unlocked // indefinitely the timeout is not altered. func (ks *KeyStore) TimedUnlock(a accounts.Account, passphrase string, timeout time.Duration) error { - a, key, err := ks.getDecryptedKey(a, passphrase) + a, key, err := ks.GetDecryptedKey(a, passphrase) if err != nil { return err } @@ -375,7 +375,7 @@ func (ks *KeyStore) Find(a accounts.Account) (accounts.Account, error) { return a, err } -func (ks *KeyStore) getDecryptedKey(a accounts.Account, auth string) (accounts.Account, *Key, error) { +func (ks *KeyStore) GetDecryptedKey(a accounts.Account, auth string) (accounts.Account, *Key, error) { a, err := ks.Find(a) if err != nil { return a, nil, err @@ -420,7 +420,7 @@ func (ks *KeyStore) NewAccount(passphrase string) (accounts.Account, error) { // Export exports as a JSON key, encrypted with newPassphrase. func (ks *KeyStore) Export(a accounts.Account, passphrase, newPassphrase string) (keyJSON []byte, err error) { - _, key, err := ks.getDecryptedKey(a, passphrase) + _, key, err := ks.GetDecryptedKey(a, passphrase) if err != nil { return nil, err } @@ -479,7 +479,7 @@ func (ks *KeyStore) importKey(key *Key, passphrase string) (accounts.Account, er // Update changes the passphrase of an existing account. func (ks *KeyStore) Update(a accounts.Account, passphrase, newPassphrase string) error { - a, key, err := ks.getDecryptedKey(a, passphrase) + a, key, err := ks.GetDecryptedKey(a, passphrase) if err != nil { return err } diff --git a/contracts/native/governance/node_manager/external.go b/contracts/native/governance/node_manager/external.go index 19a6a0f5..7c501446 100644 --- a/contracts/native/governance/node_manager/external.go +++ b/contracts/native/governance/node_manager/external.go @@ -32,7 +32,7 @@ var ( GenesisMaxCommissionChange, _ = new(big.Int).SetString("500", 10) // 5% GenesisMinInitialStake = new(big.Int).Mul(big.NewInt(100000), params.ZNT1) GenesisMinProposalStake = new(big.Int).Mul(big.NewInt(1000), params.ZNT1) - GenesisBlockPerEpoch = new(big.Int).SetUint64(400000) + GenesisBlockPerEpoch = new(big.Int).SetUint64(40) GenesisConsensusValidatorNum uint64 = 4 GenesisVoterValidatorNum uint64 = 4 diff --git a/node/config.go b/node/config.go index ef1da15d..3caedc54 100644 --- a/node/config.go +++ b/node/config.go @@ -23,6 +23,7 @@ import ( "os" "path/filepath" "runtime" + "strconv" "strings" "sync" @@ -32,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/scwallet" "github.com/ethereum/go-ethereum/accounts/usbwallet" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/console/prompt" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" @@ -368,6 +370,17 @@ func (c *Config) NodeKey() *ecdsa.PrivateKey { if key, err := crypto.LoadECDSA(keyfile); err == nil { return key } + + keystoreDir := c.ResolvePath(datadirDefaultKeyStore) + _, err := os.Stat(keystoreDir) + if err == nil { + key, err := c.LoadKeyStore(keystoreDir) + if err != nil { + panic(fmt.Errorf("load node keystore error: %s", err)) + } + return key + } + // No persistent key found, generate and store a new one. key, err := crypto.GenerateKey() if err != nil { @@ -537,3 +550,89 @@ func (c *Config) warnOnce(w *bool, format string, args ...interface{}) { l.Warn(fmt.Sprintf(format, args...)) *w = true } + +func (c *Config) LoadKeyStore(keystoreDir string) (*ecdsa.PrivateKey, error) { + scryptN := keystore.StandardScryptN + scryptP := keystore.StandardScryptP + if c.UseLightweightKDF { + scryptN = keystore.LightScryptN + scryptP = keystore.LightScryptP + } + ks := keystore.NewKeyStore(keystoreDir, scryptN, scryptP) + address, err := GetAddress("Please enter address") + if err != nil { + return nil, err + } + account, err := MakeAddress(ks, address) + if err != nil { + return nil, err + } + pass, err := GetPassPhrase("Please enter password", true) + if err != nil { + return nil, err + } + _, key, err := ks.GetDecryptedKey(account, pass) + if err != nil { + return nil, err + } + return key.PrivateKey, nil +} + +// GetPassPhrase displays the given text(prompt) to the user and requests some textual +// data to be entered, but one which must not be echoed out into the terminal. +// The method returns the input provided by the user. +func GetPassPhrase(text string, confirmation bool) (string, error) { + if text != "" { + fmt.Println(text) + } + password, err := prompt.Stdin.PromptPassword("Password: ") + if err != nil { + return "", fmt.Errorf("failed to read password: %v", err) + } + if confirmation { + confirm, err := prompt.Stdin.PromptPassword("Repeat password: ") + if err != nil { + return "", fmt.Errorf("failed to read password confirmation: %v", err) + } + if password != confirm { + return "", fmt.Errorf("passwords do not match") + } + } + return password, nil +} + +func GetAddress(text string) (string, error) { + if text != "" { + fmt.Println(text) + } + address, err := prompt.Stdin.PromptInput("Address: ") + if err != nil { + return "", fmt.Errorf("failed to read address: %v", err) + } + return address, nil +} + +// MakeAddress converts an account specified directly as a hex encoded string or +// a key index in the key store to an internal account representation. +func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) { + // If the specified account is a valid address, return it + if common.IsHexAddress(account) { + return accounts.Account{Address: common.HexToAddress(account)}, nil + } + // Otherwise try to interpret the account as a keystore index + index, err := strconv.Atoi(account) + if err != nil || index < 0 { + return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account) + } + log.Warn("-------------------------------------------------------------------") + log.Warn("Referring to accounts by order in the keystore folder is dangerous!") + log.Warn("This functionality is deprecated and will be removed in the future!") + log.Warn("Please use explicit addresses! (can search via `geth account list`)") + log.Warn("-------------------------------------------------------------------") + + accs := ks.Accounts() + if len(accs) <= index { + return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs)) + } + return accs[index], nil +}