mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
clique, signer: implement clique signing for clef
This commit is contained in:
parent
8e0bc14235
commit
9e3f27fc18
8 changed files with 69 additions and 45 deletions
|
|
@ -39,7 +39,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
"github.com/hashicorp/golang-lru"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -136,9 +136,9 @@ var (
|
||||||
errRecentlySigned = errors.New("recently signed")
|
errRecentlySigned = errors.New("recently signed")
|
||||||
)
|
)
|
||||||
|
|
||||||
// SignerFn is a signer callback function to request a hash to be signed by a
|
// SignerFn is a signer callback function to request a block header to be signed by a
|
||||||
// backing account.
|
// backing account.
|
||||||
type SignerFn func(accounts.Account, []byte) ([]byte, error)
|
type SignerFn func(accounts.Account, *types.Header) ([]byte, error)
|
||||||
|
|
||||||
// sigHash returns the hash which is used as input for the proof-of-authority
|
// sigHash returns the hash which is used as input for the proof-of-authority
|
||||||
// signing. It is the hash of the entire header apart from the 65 byte signature
|
// signing. It is the hash of the entire header apart from the 65 byte signature
|
||||||
|
|
@ -646,7 +646,7 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, results c
|
||||||
log.Trace("Out-of-turn signing requested", "wiggle", common.PrettyDuration(wiggle))
|
log.Trace("Out-of-turn signing requested", "wiggle", common.PrettyDuration(wiggle))
|
||||||
}
|
}
|
||||||
// Sign all the things!
|
// Sign all the things!
|
||||||
sighash, err := signFn(accounts.Account{Address: signer}, sigHash(header).Bytes())
|
sighash, err := signFn(accounts.Account{Address: signer}, header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma
|
||||||
go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests)
|
go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (b *EthAPIBackend) ExternalSigner() *ethapi.ExternalSignerAPI {
|
func (b *EthAPIBackend) ExternalSigner() *ethapi.ExternalSignerClient {
|
||||||
return b.eth.externalSigner
|
return b.eth.externalSigner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ package eth
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"math/big"
|
"math/big"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
@ -76,7 +77,7 @@ type Ethereum struct {
|
||||||
|
|
||||||
eventMux *event.TypeMux
|
eventMux *event.TypeMux
|
||||||
engine consensus.Engine
|
engine consensus.Engine
|
||||||
externalSigner *ethapi.ExternalSignerAPI
|
externalSigner *ethapi.ExternalSignerClient
|
||||||
|
|
||||||
bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
|
bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
|
||||||
bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports
|
bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports
|
||||||
|
|
@ -100,7 +101,7 @@ func (s *Ethereum) AddLesServer(ls LesServer) {
|
||||||
|
|
||||||
// New creates a new Ethereum object (including the
|
// New creates a new Ethereum object (including the
|
||||||
// initialisation of the common Ethereum object)
|
// initialisation of the common Ethereum object)
|
||||||
func New(ctx *node.ServiceContext, config *Config, api *ethapi.ExternalSignerAPI) (*Ethereum, error) {
|
func New(ctx *node.ServiceContext, config *Config, api *ethapi.ExternalSignerClient) (*Ethereum, error) {
|
||||||
// Ensure configuration values are compatible and sane
|
// Ensure configuration values are compatible and sane
|
||||||
if config.SyncMode == downloader.LightSync {
|
if config.SyncMode == downloader.LightSync {
|
||||||
return nil, errors.New("can't run eth.Ethereum in light sync mode, use les.LightEthereum")
|
return nil, errors.New("can't run eth.Ethereum in light sync mode, use les.LightEthereum")
|
||||||
|
|
@ -413,10 +414,19 @@ func (s *Ethereum) StartMining(threads int) error {
|
||||||
log.Error("Cannot start mining without etherbase", "err", err)
|
log.Error("Cannot start mining without etherbase", "err", err)
|
||||||
return fmt.Errorf("etherbase missing: %v", err)
|
return fmt.Errorf("etherbase missing: %v", err)
|
||||||
}
|
}
|
||||||
if _, ok := s.engine.(*clique.Clique); ok {
|
if clique, ok := s.engine.(*clique.Clique); ok {
|
||||||
//TODO @holiman
|
if s.ExternalSigner() != nil {
|
||||||
log.Error("Etherbase account unavailable locally", "err", err)
|
signerFn := func(a accounts.Account, header *types.Header) ([]byte, error) {
|
||||||
return fmt.Errorf("signer not configured: %v", err)
|
rlpHeader, err := rlp.EncodeToBytes(header)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s.ExternalSigner().SignCliqueBlock(a.Address, rlpHeader)
|
||||||
|
}
|
||||||
|
clique.Authorize(eb, signerFn)
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("external signer not configured")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// If mining is started, we can disable the transaction rejection mechanism
|
// If mining is started, we can disable the transaction rejection mechanism
|
||||||
// introduced to speed sync times.
|
// introduced to speed sync times.
|
||||||
|
|
@ -453,7 +463,7 @@ func (s *Ethereum) IsListening() bool { return true } //
|
||||||
func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) }
|
func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) }
|
||||||
func (s *Ethereum) NetVersion() uint64 { return s.networkID }
|
func (s *Ethereum) NetVersion() uint64 { return s.networkID }
|
||||||
func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
|
func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
|
||||||
func (s *Ethereum) ExternalSigner() *ethapi.ExternalSignerAPI { return s.externalSigner }
|
func (s *Ethereum) ExternalSigner() *ethapi.ExternalSignerClient { return s.externalSigner }
|
||||||
|
|
||||||
// Protocols implements node.Service, returning all the currently configured
|
// Protocols implements node.Service, returning all the currently configured
|
||||||
// network protocols to start.
|
// network protocols to start.
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ func (s *PublicTxPoolAPI) Inspect() map[string]map[string]map[string]string {
|
||||||
type PrivateAccountAPI struct {
|
type PrivateAccountAPI struct {
|
||||||
nonceLock *AddrLocker
|
nonceLock *AddrLocker
|
||||||
b Backend
|
b Backend
|
||||||
extapi *ExternalSignerAPI // external signer, nil if not used
|
extapi *ExternalSignerClient // external signer, nil if not used
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPrivateAccountAPI create a new PrivateAccountAPI.
|
// NewPrivateAccountAPI create a new PrivateAccountAPI.
|
||||||
|
|
@ -200,7 +200,7 @@ func NewPrivateAccountAPI(b Backend, nonceLock *AddrLocker) *PrivateAccountAPI {
|
||||||
func (s *PrivateAccountAPI) ListAccounts() []common.Address {
|
func (s *PrivateAccountAPI) ListAccounts() []common.Address {
|
||||||
addresses := make([]common.Address, 0) // return [] instead of nil if empty
|
addresses := make([]common.Address, 0) // return [] instead of nil if empty
|
||||||
if s.extapi != nil {
|
if s.extapi != nil {
|
||||||
if accounts, err := s.extapi.listAccounts(); err == nil {
|
if accounts, err := s.extapi.ListAccounts(); err == nil {
|
||||||
return accounts
|
return accounts
|
||||||
}
|
}
|
||||||
return addresses
|
return addresses
|
||||||
|
|
@ -219,7 +219,7 @@ type rawWallet struct {
|
||||||
|
|
||||||
// NewAccount will create a new account and returns the address for the new account.
|
// NewAccount will create a new account and returns the address for the new account.
|
||||||
func (s *PrivateAccountAPI) NewAccount(password string) (common.Address, error) {
|
func (s *PrivateAccountAPI) NewAccount(password string) (common.Address, error) {
|
||||||
return s.extapi.newAccount()
|
return s.extapi.NewAccount()
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchKeystore retrives the encrypted keystore from the account manager.
|
// fetchKeystore retrives the encrypted keystore from the account manager.
|
||||||
|
|
@ -253,7 +253,7 @@ func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args SendTxArgs
|
||||||
if err := args.setDefaults(ctx, s.b); err != nil {
|
if err := args.setDefaults(ctx, s.b); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return s.extapi.signTransaction(ctx, args)
|
return s.extapi.SignTransaction(ctx, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendTransaction will create a transaction from the given arguments and
|
// SendTransaction will create a transaction from the given arguments and
|
||||||
|
|
@ -806,7 +806,7 @@ func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransa
|
||||||
type PublicTransactionPoolAPI struct {
|
type PublicTransactionPoolAPI struct {
|
||||||
b Backend
|
b Backend
|
||||||
nonceLock *AddrLocker
|
nonceLock *AddrLocker
|
||||||
extapi *ExternalSignerAPI // external signer, nil if not used
|
extapi *ExternalSignerClient // external signer, nil if not used
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
|
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
|
||||||
|
|
@ -1057,7 +1057,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
|
||||||
if err := args.setDefaults(ctx, s.b); err != nil {
|
if err := args.setDefaults(ctx, s.b); err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
signed, err := s.extapi.signTransaction(ctx, args)
|
signed, err := s.extapi.SignTransaction(ctx, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -1114,7 +1114,7 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sen
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
tx, err = s.extapi.signTransaction(ctx, args)
|
tx, err = s.extapi.SignTransaction(ctx, args)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -1166,7 +1166,7 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
|
||||||
if gasLimit != nil && *gasLimit != 0 {
|
if gasLimit != nil && *gasLimit != 0 {
|
||||||
sendArgs.Gas = gasLimit
|
sendArgs.Gas = gasLimit
|
||||||
}
|
}
|
||||||
signedTx, err = s.extapi.signTransaction(ctx, sendArgs)
|
signedTx, err = s.extapi.SignTransaction(ctx, sendArgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -1300,24 +1300,24 @@ func (s *PublicNetAPI) Version() string {
|
||||||
return fmt.Sprintf("%d", s.networkVersion)
|
return fmt.Sprintf("%d", s.networkVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExternalSignerAPI provides an API to interact with an external signer (clef)
|
// ExternalSignerClient provides an API to interact with an external signer (clef)
|
||||||
// It proxies request to the external signer while forwarding relevant
|
// It proxies request to the external signer while forwarding relevant
|
||||||
// request headers
|
// request headers
|
||||||
type ExternalSignerAPI struct {
|
type ExternalSignerClient struct {
|
||||||
client *rpc.Client
|
client *rpc.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewExternalSigner(endpoint string) (*ExternalSignerAPI, error) {
|
func NewExternalSigner(endpoint string) (*ExternalSignerClient, error) {
|
||||||
client, err := rpc.DialHTTP(endpoint)
|
client, err := rpc.DialHTTP(endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &ExternalSignerAPI{
|
return &ExternalSignerClient{
|
||||||
client: client,
|
client: client,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ExternalSignerAPI) signTransaction(ctx context.Context, args SendTxArgs) (*types.Transaction, error) {
|
func (api *ExternalSignerClient) SignTransaction(ctx context.Context, args SendTxArgs) (*types.Transaction, error) {
|
||||||
if api == nil{
|
if api == nil{
|
||||||
return nil, errors.New("External API not initialized")
|
return nil, errors.New("External API not initialized")
|
||||||
}
|
}
|
||||||
|
|
@ -1327,7 +1327,7 @@ func (api *ExternalSignerAPI) signTransaction(ctx context.Context, args SendTxAr
|
||||||
}
|
}
|
||||||
return res.Tx, nil
|
return res.Tx, nil
|
||||||
}
|
}
|
||||||
func (api *ExternalSignerAPI) listAccounts() ([]common.Address, error) {
|
func (api *ExternalSignerClient) ListAccounts() ([]common.Address, error) {
|
||||||
if api == nil{
|
if api == nil{
|
||||||
return []common.Address{}, errors.New("External API not initialized")
|
return []common.Address{}, errors.New("External API not initialized")
|
||||||
}
|
}
|
||||||
|
|
@ -1337,15 +1337,29 @@ func (api *ExternalSignerAPI) listAccounts() ([]common.Address, error) {
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
func (api *ExternalSignerAPI) newAccount() (common.Address, error) {
|
func (api *ExternalSignerClient) NewAccount() (common.Address, error) {
|
||||||
if api == nil{
|
if api == nil{
|
||||||
return common.Address{}, errors.New("External API not initialized")
|
return common.Address{}, errors.New("External API not initialized")
|
||||||
}
|
}
|
||||||
var res accounts.Account
|
var res accounts.Account
|
||||||
|
|
||||||
if err := api.client.Call(&res, "account_new"); err != nil {
|
if err := api.client.Call(&res, "account_new"); err != nil {
|
||||||
|
return common.Address{}, err
|
||||||
|
}
|
||||||
return res.Address, nil
|
return res.Address, nil
|
||||||
}
|
}
|
||||||
return common.Address{}, nil
|
func (api *ExternalSignerClient) SignCliqueBlock(a common.Address, rlpBlock hexutil.Bytes) (hexutil.Bytes, error) {
|
||||||
|
if api == nil{
|
||||||
|
return nil, errors.New("External API not initialized")
|
||||||
|
}
|
||||||
|
var sig hexutil.Bytes
|
||||||
|
if err := api.client.Call(&sig, "account_signData", "application/clique", a, rlpBlock); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if sig[64] != 27 && sig[64] != 28 {
|
||||||
|
return nil, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)")
|
||||||
|
}
|
||||||
|
sig[64] -= 27 // Transform V from 27/28 to 0/1 for Clique use
|
||||||
|
|
||||||
|
return sig, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ type Backend interface {
|
||||||
SuggestPrice(ctx context.Context) (*big.Int, error)
|
SuggestPrice(ctx context.Context) (*big.Int, error)
|
||||||
ChainDb() ethdb.Database
|
ChainDb() ethdb.Database
|
||||||
EventMux() *event.TypeMux
|
EventMux() *event.TypeMux
|
||||||
ExternalSigner() *ExternalSignerAPI
|
ExternalSigner() *ExternalSignerClient
|
||||||
|
|
||||||
// BlockChain API
|
// BlockChain API
|
||||||
SetHead(number uint64)
|
SetHead(number uint64)
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ func (b *LesApiBackend) EventMux() *event.TypeMux {
|
||||||
return b.eth.eventMux
|
return b.eth.eventMux
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) ExternalSigner() *ethapi.ExternalSignerAPI{
|
func (b *LesApiBackend) ExternalSigner() *ethapi.ExternalSignerClient {
|
||||||
return b.eth.externalSigner
|
return b.eth.externalSigner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ type LightEthereum struct {
|
||||||
|
|
||||||
eventMux *event.TypeMux
|
eventMux *event.TypeMux
|
||||||
engine consensus.Engine
|
engine consensus.Engine
|
||||||
externalSigner *ethapi.ExternalSignerAPI
|
externalSigner *ethapi.ExternalSignerClient
|
||||||
|
|
||||||
networkId uint64
|
networkId uint64
|
||||||
netRPCService *ethapi.PublicNetAPI
|
netRPCService *ethapi.PublicNetAPI
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ import (
|
||||||
type Node struct {
|
type Node struct {
|
||||||
eventmux *event.TypeMux // Event multiplexer used between the services of a stack
|
eventmux *event.TypeMux // Event multiplexer used between the services of a stack
|
||||||
config *Config
|
config *Config
|
||||||
extapi *ethapi.ExternalSignerAPI// If non-empty, the ipc-path or http(s)-url to an external signer
|
extapi *ethapi.ExternalSignerClient // If non-empty, the ipc-path or http(s)-url to an external signer
|
||||||
|
|
||||||
instanceDirLock flock.Releaser // prevents concurrent use of instance directory
|
instanceDirLock flock.Releaser // prevents concurrent use of instance directory
|
||||||
|
|
||||||
|
|
@ -554,11 +554,11 @@ func (n *Node) ResolvePath(x string) string {
|
||||||
return n.config.ResolvePath(x)
|
return n.config.ResolvePath(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) SetExternalAPI(api *ethapi.ExternalSignerAPI){
|
func (n *Node) SetExternalAPI(api *ethapi.ExternalSignerClient){
|
||||||
n.extapi = api
|
n.extapi = api
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) ExternalSignerAPI() *ethapi.ExternalSignerAPI{
|
func (n *Node) ExternalSignerAPI() *ethapi.ExternalSignerClient {
|
||||||
return n.extapi
|
return n.extapi
|
||||||
}
|
}
|
||||||
// apis returns the collection of RPC descriptors this node offers.
|
// apis returns the collection of RPC descriptors this node offers.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue