mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
signer,clef: implement timeout for external api
This commit is contained in:
parent
1ff152f3a4
commit
a043ed2ff6
3 changed files with 157 additions and 10 deletions
|
|
@ -49,12 +49,6 @@ import (
|
|||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
// ExternalAPIVersion -- see extapi_changelog.md
|
||||
const ExternalAPIVersion = "4.0.0"
|
||||
|
||||
// InternalAPIVersion -- see intapi_changelog.md
|
||||
const InternalAPIVersion = "3.0.0"
|
||||
|
||||
const legalWarning = `
|
||||
WARNING!
|
||||
|
||||
|
|
@ -110,6 +104,11 @@ var (
|
|||
Usage: "File used to emit audit logs. Set to \"\" to disable",
|
||||
Value: "audit.log",
|
||||
}
|
||||
timeoutFlag = cli.DurationFlag{
|
||||
Name: "timeout",
|
||||
Usage: "Specify a timeout, so external callers get a response within a certain time (default 0 = no timeout)",
|
||||
Value: 0,
|
||||
}
|
||||
ruleFlag = cli.StringFlag{
|
||||
Name: "rules",
|
||||
Usage: "Enable rule-engine",
|
||||
|
|
@ -194,6 +193,7 @@ func init() {
|
|||
dBFlag,
|
||||
customDBFlag,
|
||||
auditLogFlag,
|
||||
timeoutFlag,
|
||||
ruleFlag,
|
||||
stdiouiFlag,
|
||||
testFlag,
|
||||
|
|
@ -414,6 +414,12 @@ func signer(c *cli.Context) error {
|
|||
c.GlobalBool(utils.LightKDFFlag.Name),
|
||||
c.GlobalBool(advancedMode.Name))
|
||||
api = apiImpl
|
||||
|
||||
// Timeout
|
||||
if timeout := c.GlobalDuration(timeoutFlag.Name); timeout > 0 {
|
||||
log.Info("extapi timeout set", "time", timeout)
|
||||
api = core.NewTimedExternalAPI(api, timeout)
|
||||
}
|
||||
// Audit logging
|
||||
if logfile := c.GlobalString(auditLogFlag.Name); logfile != "" {
|
||||
api, err = core.NewAuditLogger(logfile, api)
|
||||
|
|
@ -479,8 +485,8 @@ func signer(c *cli.Context) error {
|
|||
}
|
||||
ui.OnSignerStartup(core.StartupInfo{
|
||||
Info: map[string]interface{}{
|
||||
"extapi_version": ExternalAPIVersion,
|
||||
"intapi_version": InternalAPIVersion,
|
||||
"extapi_version": core.ExternalAPIVersion,
|
||||
"intapi_version": core.InternalAPIVersion,
|
||||
"extapi_http": extapiURL,
|
||||
"extapi_ipc": ipcapiURL,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -36,8 +36,14 @@ import (
|
|||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
const(
|
||||
// numberOfAccountsToDerive For hardware wallets, the number of accounts to derive
|
||||
const numberOfAccountsToDerive = 10
|
||||
numberOfAccountsToDerive = 10
|
||||
// ExternalAPIVersion -- see extapi_changelog.md
|
||||
ExternalAPIVersion = "4.0.0"
|
||||
// InternalAPIVersion -- see intapi_changelog.md
|
||||
InternalAPIVersion = "3.0.0"
|
||||
)
|
||||
|
||||
// ExternalAPI defines the external API through which signing requests are made.
|
||||
type ExternalAPI interface {
|
||||
|
|
|
|||
135
signer/core/timeout.go
Normal file
135
signer/core/timeout.go
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The TimedExternalAPI implements ExternalAPI, but can be configured to time out after a specified interval.
|
||||
// This can be used to ensure that callers get a response within reasonable time,
|
||||
// even if the user is unresponsive.
|
||||
type TimedExternalAPI struct {
|
||||
timeout time.Duration
|
||||
next ExternalAPI
|
||||
}
|
||||
|
||||
func NewTimedExternalAPI(next ExternalAPI, timeout time.Duration) ExternalAPI {
|
||||
return &TimedExternalAPI{timeout, next}
|
||||
}
|
||||
|
||||
var (
|
||||
ErrTimeout = fmt.Errorf("timeout occurred")
|
||||
)
|
||||
|
||||
func (t *TimedExternalAPI) List(ctx context.Context) ([]common.Address, error) {
|
||||
type response struct {
|
||||
addr []common.Address
|
||||
err error
|
||||
}
|
||||
ch := make(chan response)
|
||||
go func() {
|
||||
addr, err := t.next.List(ctx)
|
||||
ch <- response{addr, err}
|
||||
}()
|
||||
|
||||
select {
|
||||
case r := <-ch:
|
||||
return r.addr, r.err
|
||||
case <-time.After(t.timeout):
|
||||
log.Info("timeout", "op", "list")
|
||||
go func() { <-ch }()
|
||||
return []common.Address{}, ErrTimeout
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TimedExternalAPI) New(ctx context.Context) (accounts.Account, error) {
|
||||
type response struct {
|
||||
acc accounts.Account
|
||||
err error
|
||||
}
|
||||
ch := make(chan response)
|
||||
go func() {
|
||||
acc, err := t.next.New(ctx)
|
||||
ch <- response{acc, err}
|
||||
}()
|
||||
|
||||
select {
|
||||
case r := <-ch:
|
||||
return r.acc, r.err
|
||||
case <-time.After(t.timeout):
|
||||
log.Info("timeout", "op", "list")
|
||||
go func() { <-ch }()
|
||||
return accounts.Account{}, ErrTimeout
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TimedExternalAPI) SignTransaction(ctx context.Context, args SendTxArgs, methodSelector *string) (*ethapi.SignTransactionResult, error) {
|
||||
type response struct {
|
||||
res *ethapi.SignTransactionResult
|
||||
err error
|
||||
}
|
||||
ch := make(chan response)
|
||||
go func() {
|
||||
res, err := t.next.SignTransaction(ctx, args, methodSelector)
|
||||
ch <- response{res, err}
|
||||
}()
|
||||
select {
|
||||
case r := <-ch:
|
||||
return r.res, r.err
|
||||
case <-time.After(t.timeout):
|
||||
log.Info("timeout", "op", "signTransaction")
|
||||
go func() { <-ch }()
|
||||
return nil, ErrTimeout
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TimedExternalAPI) Sign(ctx context.Context, addr common.MixedcaseAddress, data hexutil.Bytes) (hexutil.Bytes, error) {
|
||||
type response struct {
|
||||
res hexutil.Bytes
|
||||
err error
|
||||
}
|
||||
ch := make(chan response)
|
||||
go func() {
|
||||
res, err := t.next.Sign(ctx, addr, data)
|
||||
ch <- response{res, err}
|
||||
}()
|
||||
select {
|
||||
case r := <-ch:
|
||||
return r.res, r.err
|
||||
case <-time.After(t.timeout):
|
||||
log.Info("timeout", "op", "sign")
|
||||
go func() { <-ch }()
|
||||
return nil, ErrTimeout
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TimedExternalAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) {
|
||||
type response struct {
|
||||
res json.RawMessage
|
||||
err error
|
||||
}
|
||||
ch := make(chan response)
|
||||
go func() {
|
||||
res, err := t.next.Export(ctx, addr)
|
||||
ch <- response{res, err}
|
||||
}()
|
||||
select {
|
||||
case r := <-ch:
|
||||
return r.res, r.err
|
||||
case <-time.After(t.timeout):
|
||||
log.Info("timeout", "op", "sign")
|
||||
go func() { <-ch }()
|
||||
return json.RawMessage{}, ErrTimeout
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TimedExternalAPI) Version(ctx context.Context) (string, error) {
|
||||
return ExternalAPIVersion, nil
|
||||
}
|
||||
Loading…
Reference in a new issue