allow multikey unlock (#356)
* allow multikey unlock * fix lint * Update rpc/apis.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
parent
5768706917
commit
b76c36fcdb
@ -3,10 +3,8 @@
|
|||||||
package rpc
|
package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
emintcrypto "github.com/cosmos/ethermint/crypto"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
|
emintcrypto "github.com/cosmos/ethermint/crypto"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,7 +19,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetRPCAPIs returns the list of all APIs
|
// GetRPCAPIs returns the list of all APIs
|
||||||
func GetRPCAPIs(cliCtx context.CLIContext, key emintcrypto.PrivKeySecp256k1) []rpc.API {
|
func GetRPCAPIs(cliCtx context.CLIContext, keys []emintcrypto.PrivKeySecp256k1) []rpc.API {
|
||||||
nonceLock := new(AddrLocker)
|
nonceLock := new(AddrLocker)
|
||||||
backend := NewEthermintBackend(cliCtx)
|
backend := NewEthermintBackend(cliCtx)
|
||||||
return []rpc.API{
|
return []rpc.API{
|
||||||
@ -34,7 +32,7 @@ func GetRPCAPIs(cliCtx context.CLIContext, key emintcrypto.PrivKeySecp256k1) []r
|
|||||||
{
|
{
|
||||||
Namespace: EthNamespace,
|
Namespace: EthNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: NewPublicEthAPI(cliCtx, backend, nonceLock, key),
|
Service: NewPublicEthAPI(cliCtx, backend, nonceLock, keys),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||||
@ -16,7 +17,6 @@ import (
|
|||||||
|
|
||||||
"github.com/cosmos/ethermint/app"
|
"github.com/cosmos/ethermint/app"
|
||||||
emintcrypto "github.com/cosmos/ethermint/crypto"
|
emintcrypto "github.com/cosmos/ethermint/crypto"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -56,8 +56,9 @@ func EmintServeCmd(cdc *codec.Codec) *cobra.Command {
|
|||||||
func registerRoutes(rs *lcd.RestServer) {
|
func registerRoutes(rs *lcd.RestServer) {
|
||||||
s := rpc.NewServer()
|
s := rpc.NewServer()
|
||||||
accountName := viper.GetString(flagUnlockKey)
|
accountName := viper.GetString(flagUnlockKey)
|
||||||
|
accountNames := strings.Split(accountName, ",")
|
||||||
|
|
||||||
var emintKey emintcrypto.PrivKeySecp256k1
|
var emintKeys []emintcrypto.PrivKeySecp256k1
|
||||||
if len(accountName) > 0 {
|
if len(accountName) > 0 {
|
||||||
var err error
|
var err error
|
||||||
inBuf := bufio.NewReader(os.Stdin)
|
inBuf := bufio.NewReader(os.Stdin)
|
||||||
@ -76,13 +77,13 @@ func registerRoutes(rs *lcd.RestServer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emintKey, err = unlockKeyFromNameAndPassphrase(accountName, passphrase)
|
emintKeys, err = unlockKeyFromNameAndPassphrase(accountNames, passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
apis := GetRPCAPIs(rs.CliCtx, emintKey)
|
apis := GetRPCAPIs(rs.CliCtx, emintKeys)
|
||||||
|
|
||||||
// TODO: Allow cli to configure modules https://github.com/ChainSafe/ethermint/issues/74
|
// TODO: Allow cli to configure modules https://github.com/ChainSafe/ethermint/issues/74
|
||||||
whitelist := make(map[string]bool)
|
whitelist := make(map[string]bool)
|
||||||
@ -105,7 +106,7 @@ func registerRoutes(rs *lcd.RestServer) {
|
|||||||
app.ModuleBasics.RegisterRESTRoutes(rs.CliCtx, rs.Mux)
|
app.ModuleBasics.RegisterRESTRoutes(rs.CliCtx, rs.Mux)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unlockKeyFromNameAndPassphrase(accountName, passphrase string) (emintKey emintcrypto.PrivKeySecp256k1, err error) {
|
func unlockKeyFromNameAndPassphrase(accountNames []string, passphrase string) (emintKeys []emintcrypto.PrivKeySecp256k1, err error) {
|
||||||
keybase, err := keyring.NewKeyring(
|
keybase, err := keyring.NewKeyring(
|
||||||
sdk.KeyringServiceName(),
|
sdk.KeyringServiceName(),
|
||||||
viper.GetString(flags.FlagKeyringBackend),
|
viper.GetString(flags.FlagKeyringBackend),
|
||||||
@ -116,16 +117,21 @@ func unlockKeyFromNameAndPassphrase(accountName, passphrase string) (emintKey em
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// With keyring keybase, password is not required as it is pulled from the OS prompt
|
// try the for loop with array []string accountNames
|
||||||
privKey, err := keybase.ExportPrivateKeyObject(accountName, passphrase)
|
// run through the bottom code inside the for loop
|
||||||
if err != nil {
|
for _, acc := range accountNames {
|
||||||
return
|
// With keyring keybase, password is not required as it is pulled from the OS prompt
|
||||||
}
|
privKey, err := keybase.ExportPrivateKeyObject(acc, passphrase)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var ok bool
|
var ok bool
|
||||||
emintKey, ok = privKey.(emintcrypto.PrivKeySecp256k1)
|
emintKey, ok := privKey.(emintcrypto.PrivKeySecp256k1)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("invalid private key type: %T", privKey))
|
panic(fmt.Sprintf("invalid private key type: %T", privKey))
|
||||||
|
}
|
||||||
|
emintKeys = append(emintKeys, emintKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -45,19 +45,19 @@ import (
|
|||||||
type PublicEthAPI struct {
|
type PublicEthAPI struct {
|
||||||
cliCtx context.CLIContext
|
cliCtx context.CLIContext
|
||||||
backend Backend
|
backend Backend
|
||||||
key emintcrypto.PrivKeySecp256k1
|
keys []emintcrypto.PrivKeySecp256k1
|
||||||
nonceLock *AddrLocker
|
nonceLock *AddrLocker
|
||||||
keybaseLock sync.Mutex
|
keybaseLock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPublicEthAPI creates an instance of the public ETH Web3 API.
|
// NewPublicEthAPI creates an instance of the public ETH Web3 API.
|
||||||
func NewPublicEthAPI(cliCtx context.CLIContext, backend Backend, nonceLock *AddrLocker,
|
func NewPublicEthAPI(cliCtx context.CLIContext, backend Backend, nonceLock *AddrLocker,
|
||||||
key emintcrypto.PrivKeySecp256k1) *PublicEthAPI {
|
key []emintcrypto.PrivKeySecp256k1) *PublicEthAPI {
|
||||||
|
|
||||||
return &PublicEthAPI{
|
return &PublicEthAPI{
|
||||||
cliCtx: cliCtx,
|
cliCtx: cliCtx,
|
||||||
backend: backend,
|
backend: backend,
|
||||||
key: key,
|
keys: key,
|
||||||
nonceLock: nonceLock,
|
nonceLock: nonceLock,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,15 +282,28 @@ func (e *PublicEthAPI) ExportAccount(address common.Address, blockNumber BlockNu
|
|||||||
return string(res), nil
|
return string(res), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkKeyInKeyring(keys []emintcrypto.PrivKeySecp256k1, address common.Address) (key emintcrypto.PrivKeySecp256k1, exist bool) {
|
||||||
|
if len(keys) > 0 {
|
||||||
|
for _, key := range keys {
|
||||||
|
if bytes.Equal(key.PubKey().Address().Bytes(), address.Bytes()) {
|
||||||
|
return key, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
// Sign signs the provided data using the private key of address via Geth's signature standard.
|
// Sign signs the provided data using the private key of address via Geth's signature standard.
|
||||||
func (e *PublicEthAPI) Sign(address common.Address, data hexutil.Bytes) (hexutil.Bytes, error) {
|
func (e *PublicEthAPI) Sign(address common.Address, data hexutil.Bytes) (hexutil.Bytes, error) {
|
||||||
// TODO: Change this functionality to find an unlocked account by address
|
// TODO: Change this functionality to find an unlocked account by address
|
||||||
if e.key == nil || !bytes.Equal(e.key.PubKey().Address().Bytes(), address.Bytes()) {
|
|
||||||
|
key, exist := checkKeyInKeyring(e.keys, address)
|
||||||
|
if !exist {
|
||||||
return nil, keystore.ErrLocked
|
return nil, keystore.ErrLocked
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign the requested hash with the wallet
|
// Sign the requested hash with the wallet
|
||||||
signature, err := e.key.Sign(data)
|
signature, err := key.Sign(data)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
|
signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
|
||||||
}
|
}
|
||||||
@ -301,7 +314,9 @@ func (e *PublicEthAPI) Sign(address common.Address, data hexutil.Bytes) (hexutil
|
|||||||
// SendTransaction sends an Ethereum transaction.
|
// SendTransaction sends an Ethereum transaction.
|
||||||
func (e *PublicEthAPI) SendTransaction(args params.SendTxArgs) (common.Hash, error) {
|
func (e *PublicEthAPI) SendTransaction(args params.SendTxArgs) (common.Hash, error) {
|
||||||
// TODO: Change this functionality to find an unlocked account by address
|
// TODO: Change this functionality to find an unlocked account by address
|
||||||
if e.key == nil || !bytes.Equal(e.key.PubKey().Address().Bytes(), args.From.Bytes()) {
|
|
||||||
|
key, exist := checkKeyInKeyring(e.keys, args.From)
|
||||||
|
if !exist {
|
||||||
return common.Hash{}, keystore.ErrLocked
|
return common.Hash{}, keystore.ErrLocked
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +341,7 @@ func (e *PublicEthAPI) SendTransaction(args params.SendTxArgs) (common.Hash, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sign transaction
|
// Sign transaction
|
||||||
if err := tx.Sign(intChainID, e.key.ToECDSA()); err != nil {
|
if err := tx.Sign(intChainID, key.ToECDSA()); err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,9 +444,11 @@ func (e *PublicEthAPI) doCall(
|
|||||||
|
|
||||||
// Set sender address or use a default if none specified
|
// Set sender address or use a default if none specified
|
||||||
var addr common.Address
|
var addr common.Address
|
||||||
|
|
||||||
if args.From == nil {
|
if args.From == nil {
|
||||||
if e.key != nil {
|
key, exist := checkKeyInKeyring(e.keys, *args.From)
|
||||||
addr = common.BytesToAddress(e.key.PubKey().Address().Bytes())
|
if exist {
|
||||||
|
addr = common.BytesToAddress(key.PubKey().Address().Bytes())
|
||||||
}
|
}
|
||||||
// No error handled here intentionally to match geth behaviour
|
// No error handled here intentionally to match geth behaviour
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user