github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/signer/core/api.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:42</date>
    10  //</624450110293544960>
    11  
    12  
    13  package core
    14  
    15  import (
    16  	"context"
    17  	"encoding/json"
    18  	"errors"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"math/big"
    22  	"reflect"
    23  
    24  	"github.com/ethereum/go-ethereum/accounts"
    25  	"github.com/ethereum/go-ethereum/accounts/keystore"
    26  	"github.com/ethereum/go-ethereum/accounts/usbwallet"
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/common/hexutil"
    29  	"github.com/ethereum/go-ethereum/crypto"
    30  	"github.com/ethereum/go-ethereum/internal/ethapi"
    31  	"github.com/ethereum/go-ethereum/log"
    32  	"github.com/ethereum/go-ethereum/rlp"
    33  )
    34  
    35  //number of accounts to derive用于硬件钱包,要派生的帐户数
    36  const numberOfAccountsToDerive = 10
    37  
    38  //ExternalAPI定义用于发出签名请求的外部API。
    39  type ExternalAPI interface {
    40  //列出可用帐户
    41  	List(ctx context.Context) ([]common.Address, error)
    42  //创建新帐户的新请求
    43  	New(ctx context.Context) (accounts.Account, error)
    44  //SignTransaction请求签署指定的事务
    45  	SignTransaction(ctx context.Context, args SendTxArgs, methodSelector *string) (*ethapi.SignTransactionResult, error)
    46  //签名-请求对给定数据进行签名(加前缀)
    47  	Sign(ctx context.Context, addr common.MixedcaseAddress, data hexutil.Bytes) (hexutil.Bytes, error)
    48  //导出-请求导出帐户
    49  	Export(ctx context.Context, addr common.Address) (json.RawMessage, error)
    50  //导入-请求导入帐户
    51  //在下一阶段,当我们
    52  //双向通信
    53  //导入(ctx context.context,keyjson json.rawmessage)(account,error)
    54  }
    55  
    56  //SignerRui指定UI需要实现什么方法才能用作签名者的UI
    57  type SignerUI interface {
    58  //approvetx提示用户确认请求签署交易
    59  	ApproveTx(request *SignTxRequest) (SignTxResponse, error)
    60  //ApproveSignData提示用户确认请求签署数据
    61  	ApproveSignData(request *SignDataRequest) (SignDataResponse, error)
    62  //approveexport提示用户确认导出加密帐户json
    63  	ApproveExport(request *ExportRequest) (ExportResponse, error)
    64  //approveImport提示用户确认导入账号json
    65  	ApproveImport(request *ImportRequest) (ImportResponse, error)
    66  //批准提示用户确认列出帐户
    67  //用户界面可以修改要列出的科目列表
    68  	ApproveListing(request *ListRequest) (ListResponse, error)
    69  //ApproveWaccount提示用户确认创建新帐户,并显示给调用方
    70  	ApproveNewAccount(request *NewAccountRequest) (NewAccountResponse, error)
    71  //ShowError向用户显示错误消息
    72  	ShowError(message string)
    73  //ShowInfo向用户显示信息消息
    74  	ShowInfo(message string)
    75  //OnApprovedTX通知用户界面一个事务已成功签名。
    76  //用户界面可以使用此方法跟踪发送给特定收件人的邮件数量。
    77  	OnApprovedTx(tx ethapi.SignTransactionResult)
    78  //当签名者启动时调用OnSignerStartup,并告诉用户界面有关外部API位置和版本的信息。
    79  //信息
    80  	OnSignerStartup(info StartupInfo)
    81  //当CLEF需要用户输入时,调用OnInputRequired,例如主密码或
    82  //解锁硬件钱包的PIN码
    83  	OnInputRequired(info UserInputRequest) (UserInputResponse, error)
    84  }
    85  
    86  //signerapi定义了externalAPI的实际实现
    87  type SignerAPI struct {
    88  	chainID    *big.Int
    89  	am         *accounts.Manager
    90  	UI         SignerUI
    91  	validator  *Validator
    92  	rejectMode bool
    93  }
    94  
    95  //有关请求的元数据
    96  type Metadata struct {
    97  	Remote    string `json:"remote"`
    98  	Local     string `json:"local"`
    99  	Scheme    string `json:"scheme"`
   100  	UserAgent string `json:"User-Agent"`
   101  	Origin    string `json:"Origin"`
   102  }
   103  
   104  //MetadataFromContext从给定的Context.Context中提取元数据
   105  func MetadataFromContext(ctx context.Context) Metadata {
   106  m := Metadata{"NA", "NA", "NA", "", ""} //蝙蝠侠
   107  
   108  	if v := ctx.Value("remote"); v != nil {
   109  		m.Remote = v.(string)
   110  	}
   111  	if v := ctx.Value("scheme"); v != nil {
   112  		m.Scheme = v.(string)
   113  	}
   114  	if v := ctx.Value("local"); v != nil {
   115  		m.Local = v.(string)
   116  	}
   117  	if v := ctx.Value("Origin"); v != nil {
   118  		m.Origin = v.(string)
   119  	}
   120  	if v := ctx.Value("User-Agent"); v != nil {
   121  		m.UserAgent = v.(string)
   122  	}
   123  	return m
   124  }
   125  
   126  //字符串实现字符串接口
   127  func (m Metadata) String() string {
   128  	s, err := json.Marshal(m)
   129  	if err == nil {
   130  		return string(s)
   131  	}
   132  	return err.Error()
   133  }
   134  
   135  //签名者和用户界面之间的请求/响应类型的类型
   136  type (
   137  //signtxrequest包含要签名的事务的信息
   138  	SignTxRequest struct {
   139  		Transaction SendTxArgs       `json:"transaction"`
   140  		Callinfo    []ValidationInfo `json:"call_info"`
   141  		Meta        Metadata         `json:"meta"`
   142  	}
   143  //SigntxRequest的SigntxResponse结果
   144  	SignTxResponse struct {
   145  //用户界面可以更改Tx
   146  		Transaction SendTxArgs `json:"transaction"`
   147  		Approved    bool       `json:"approved"`
   148  		Password    string     `json:"password"`
   149  	}
   150  //将有关查询的信息导出到导出帐户
   151  	ExportRequest struct {
   152  		Address common.Address `json:"address"`
   153  		Meta    Metadata       `json:"meta"`
   154  	}
   155  //导出响应对导出请求的响应
   156  	ExportResponse struct {
   157  		Approved bool `json:"approved"`
   158  	}
   159  //导入请求有关导入帐户请求的信息
   160  	ImportRequest struct {
   161  		Meta Metadata `json:"meta"`
   162  	}
   163  	ImportResponse struct {
   164  		Approved    bool   `json:"approved"`
   165  		OldPassword string `json:"old_password"`
   166  		NewPassword string `json:"new_password"`
   167  	}
   168  	SignDataRequest struct {
   169  		Address common.MixedcaseAddress `json:"address"`
   170  		Rawdata hexutil.Bytes           `json:"raw_data"`
   171  		Message string                  `json:"message"`
   172  		Hash    hexutil.Bytes           `json:"hash"`
   173  		Meta    Metadata                `json:"meta"`
   174  	}
   175  	SignDataResponse struct {
   176  		Approved bool `json:"approved"`
   177  		Password string
   178  	}
   179  	NewAccountRequest struct {
   180  		Meta Metadata `json:"meta"`
   181  	}
   182  	NewAccountResponse struct {
   183  		Approved bool   `json:"approved"`
   184  		Password string `json:"password"`
   185  	}
   186  	ListRequest struct {
   187  		Accounts []Account `json:"accounts"`
   188  		Meta     Metadata  `json:"meta"`
   189  	}
   190  	ListResponse struct {
   191  		Accounts []Account `json:"accounts"`
   192  	}
   193  	Message struct {
   194  		Text string `json:"text"`
   195  	}
   196  	PasswordRequest struct {
   197  		Prompt string `json:"prompt"`
   198  	}
   199  	PasswordResponse struct {
   200  		Password string `json:"password"`
   201  	}
   202  	StartupInfo struct {
   203  		Info map[string]interface{} `json:"info"`
   204  	}
   205  	UserInputRequest struct {
   206  		Prompt     string `json:"prompt"`
   207  		Title      string `json:"title"`
   208  		IsPassword bool   `json:"isPassword"`
   209  	}
   210  	UserInputResponse struct {
   211  		Text string `json:"text"`
   212  	}
   213  )
   214  
   215  var ErrRequestDenied = errors.New("Request denied")
   216  
   217  //NewSignerAPI创建了一个新的可用于帐户管理的API。
   218  //kslocation指定存储受密码保护的private的目录
   219  //创建新帐户时生成的键。
   220  //nousb禁用支持硬件设备所需的USB支持,如
   221  //Ledger和Trezor。
   222  func NewSignerAPI(chainID int64, ksLocation string, noUSB bool, ui SignerUI, abidb *AbiDb, lightKDF bool, advancedMode bool) *SignerAPI {
   223  	var (
   224  		backends []accounts.Backend
   225  		n, p     = keystore.StandardScryptN, keystore.StandardScryptP
   226  	)
   227  	if lightKDF {
   228  		n, p = keystore.LightScryptN, keystore.LightScryptP
   229  	}
   230  //支持基于密码的帐户
   231  	if len(ksLocation) > 0 {
   232  		backends = append(backends, keystore.NewKeyStore(ksLocation, n, p))
   233  	}
   234  	if advancedMode {
   235  		log.Info("Clef is in advanced mode: will warn instead of reject")
   236  	}
   237  	if !noUSB {
   238  //启动用于分类帐硬件钱包的USB集线器
   239  		if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil {
   240  			log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err))
   241  		} else {
   242  			backends = append(backends, ledgerhub)
   243  			log.Debug("Ledger support enabled")
   244  		}
   245  //启动Trezor硬件钱包的USB集线器
   246  		if trezorhub, err := usbwallet.NewTrezorHub(); err != nil {
   247  			log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err))
   248  		} else {
   249  			backends = append(backends, trezorhub)
   250  			log.Debug("Trezor support enabled")
   251  		}
   252  	}
   253  	signer := &SignerAPI{big.NewInt(chainID), accounts.NewManager(backends...), ui, NewValidator(abidb), !advancedMode}
   254  	if !noUSB {
   255  		signer.startUSBListener()
   256  	}
   257  	return signer
   258  }
   259  func (api *SignerAPI) openTrezor(url accounts.URL) {
   260  	resp, err := api.UI.OnInputRequired(UserInputRequest{
   261  		Prompt: "Pin required to open Trezor wallet\n" +
   262  			"Look at the device for number positions\n\n" +
   263  			"7 | 8 | 9\n" +
   264  			"--+---+--\n" +
   265  			"4 | 5 | 6\n" +
   266  			"--+---+--\n" +
   267  			"1 | 2 | 3\n\n",
   268  		IsPassword: true,
   269  		Title:      "Trezor unlock",
   270  	})
   271  	if err != nil {
   272  		log.Warn("failed getting trezor pin", "err", err)
   273  		return
   274  	}
   275  //我们使用的是URL而不是指向
   276  //钱包——也许它已经不存在了
   277  	w, err := api.am.Wallet(url.String())
   278  	if err != nil {
   279  		log.Warn("wallet unavailable", "url", url)
   280  		return
   281  	}
   282  	err = w.Open(resp.Text)
   283  	if err != nil {
   284  		log.Warn("failed to open wallet", "wallet", url, "err", err)
   285  		return
   286  	}
   287  
   288  }
   289  
   290  //StartusBlistener为USB事件启动监听器,用于硬件钱包交互
   291  func (api *SignerAPI) startUSBListener() {
   292  	events := make(chan accounts.WalletEvent, 16)
   293  	am := api.am
   294  	am.Subscribe(events)
   295  	go func() {
   296  
   297  //打开所有已连接的钱包
   298  		for _, wallet := range am.Wallets() {
   299  			if err := wallet.Open(""); err != nil {
   300  				log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
   301  				if err == usbwallet.ErrTrezorPINNeeded {
   302  					go api.openTrezor(wallet.URL())
   303  				}
   304  			}
   305  		}
   306  //听钱包事件直到终止
   307  		for event := range events {
   308  			switch event.Kind {
   309  			case accounts.WalletArrived:
   310  				if err := event.Wallet.Open(""); err != nil {
   311  					log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
   312  					if err == usbwallet.ErrTrezorPINNeeded {
   313  						go api.openTrezor(event.Wallet.URL())
   314  					}
   315  				}
   316  			case accounts.WalletOpened:
   317  				status, _ := event.Wallet.Status()
   318  				log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)
   319  
   320  				derivationPath := accounts.DefaultBaseDerivationPath
   321  				if event.Wallet.URL().Scheme == "ledger" {
   322  					derivationPath = accounts.DefaultLedgerBaseDerivationPath
   323  				}
   324  				var nextPath = derivationPath
   325  //导出前n个帐户,目前已硬编码
   326  				for i := 0; i < numberOfAccountsToDerive; i++ {
   327  					acc, err := event.Wallet.Derive(nextPath, true)
   328  					if err != nil {
   329  						log.Warn("account derivation failed", "error", err)
   330  					} else {
   331  						log.Info("derived account", "address", acc.Address)
   332  					}
   333  					nextPath[len(nextPath)-1]++
   334  				}
   335  			case accounts.WalletDropped:
   336  				log.Info("Old wallet dropped", "url", event.Wallet.URL())
   337  				event.Wallet.Close()
   338  			}
   339  		}
   340  	}()
   341  }
   342  
   343  //list返回签名者管理的钱包集。每个钱包都可以包含
   344  //多个帐户。
   345  func (api *SignerAPI) List(ctx context.Context) ([]common.Address, error) {
   346  	var accs []Account
   347  	for _, wallet := range api.am.Wallets() {
   348  		for _, acc := range wallet.Accounts() {
   349  			acc := Account{Typ: "Account", URL: wallet.URL(), Address: acc.Address}
   350  			accs = append(accs, acc)
   351  		}
   352  	}
   353  	result, err := api.UI.ApproveListing(&ListRequest{Accounts: accs, Meta: MetadataFromContext(ctx)})
   354  	if err != nil {
   355  		return nil, err
   356  	}
   357  	if result.Accounts == nil {
   358  		return nil, ErrRequestDenied
   359  
   360  	}
   361  
   362  	addresses := make([]common.Address, 0)
   363  	for _, acc := range result.Accounts {
   364  		addresses = append(addresses, acc.Address)
   365  	}
   366  
   367  	return addresses, nil
   368  }
   369  
   370  //新建创建新的密码保护帐户。私钥受保护
   371  //给定的密码。用户负责备份存储的私钥
   372  //在密钥库位置中,创建此API时指定了THA。
   373  func (api *SignerAPI) New(ctx context.Context) (accounts.Account, error) {
   374  	be := api.am.Backends(keystore.KeyStoreType)
   375  	if len(be) == 0 {
   376  		return accounts.Account{}, errors.New("password based accounts not supported")
   377  	}
   378  	var (
   379  		resp NewAccountResponse
   380  		err  error
   381  	)
   382  //三次重试以获取有效密码
   383  	for i := 0; i < 3; i++ {
   384  		resp, err = api.UI.ApproveNewAccount(&NewAccountRequest{MetadataFromContext(ctx)})
   385  		if err != nil {
   386  			return accounts.Account{}, err
   387  		}
   388  		if !resp.Approved {
   389  			return accounts.Account{}, ErrRequestDenied
   390  		}
   391  		if pwErr := ValidatePasswordFormat(resp.Password); pwErr != nil {
   392  			api.UI.ShowError(fmt.Sprintf("Account creation attempt #%d failed due to password requirements: %v", (i + 1), pwErr))
   393  		} else {
   394  //无误差
   395  			return be[0].(*keystore.KeyStore).NewAccount(resp.Password)
   396  		}
   397  	}
   398  //否则将失败,并显示一般错误消息
   399  	return accounts.Account{}, errors.New("account creation failed")
   400  }
   401  
   402  //logdiff记录传入(原始)事务和从签名者返回的事务之间的差异。
   403  //如果修改了事务,它还返回“true”,以便可以将签名者配置为不允许
   404  //请求的用户界面修改
   405  func logDiff(original *SignTxRequest, new *SignTxResponse) bool {
   406  	modified := false
   407  	if f0, f1 := original.Transaction.From, new.Transaction.From; !reflect.DeepEqual(f0, f1) {
   408  		log.Info("Sender-account changed by UI", "was", f0, "is", f1)
   409  		modified = true
   410  	}
   411  	if t0, t1 := original.Transaction.To, new.Transaction.To; !reflect.DeepEqual(t0, t1) {
   412  		log.Info("Recipient-account changed by UI", "was", t0, "is", t1)
   413  		modified = true
   414  	}
   415  	if g0, g1 := original.Transaction.Gas, new.Transaction.Gas; g0 != g1 {
   416  		modified = true
   417  		log.Info("Gas changed by UI", "was", g0, "is", g1)
   418  	}
   419  	if g0, g1 := big.Int(original.Transaction.GasPrice), big.Int(new.Transaction.GasPrice); g0.Cmp(&g1) != 0 {
   420  		modified = true
   421  		log.Info("GasPrice changed by UI", "was", g0, "is", g1)
   422  	}
   423  	if v0, v1 := big.Int(original.Transaction.Value), big.Int(new.Transaction.Value); v0.Cmp(&v1) != 0 {
   424  		modified = true
   425  		log.Info("Value changed by UI", "was", v0, "is", v1)
   426  	}
   427  	if d0, d1 := original.Transaction.Data, new.Transaction.Data; d0 != d1 {
   428  		d0s := ""
   429  		d1s := ""
   430  		if d0 != nil {
   431  			d0s = hexutil.Encode(*d0)
   432  		}
   433  		if d1 != nil {
   434  			d1s = hexutil.Encode(*d1)
   435  		}
   436  		if d1s != d0s {
   437  			modified = true
   438  			log.Info("Data changed by UI", "was", d0s, "is", d1s)
   439  		}
   440  	}
   441  	if n0, n1 := original.Transaction.Nonce, new.Transaction.Nonce; n0 != n1 {
   442  		modified = true
   443  		log.Info("Nonce changed by UI", "was", n0, "is", n1)
   444  	}
   445  	return modified
   446  }
   447  
   448  //signTransaction对给定的事务进行签名,并将其作为json和rlp编码的形式返回
   449  func (api *SignerAPI) SignTransaction(ctx context.Context, args SendTxArgs, methodSelector *string) (*ethapi.SignTransactionResult, error) {
   450  	var (
   451  		err    error
   452  		result SignTxResponse
   453  	)
   454  	msgs, err := api.validator.ValidateTransaction(&args, methodSelector)
   455  	if err != nil {
   456  		return nil, err
   457  	}
   458  //如果我们处于“拒绝模式”,则拒绝而不是显示用户警告
   459  	if api.rejectMode {
   460  		if err := msgs.getWarnings(); err != nil {
   461  			return nil, err
   462  		}
   463  	}
   464  
   465  	req := SignTxRequest{
   466  		Transaction: args,
   467  		Meta:        MetadataFromContext(ctx),
   468  		Callinfo:    msgs.Messages,
   469  	}
   470  //工艺批准
   471  	result, err = api.UI.ApproveTx(&req)
   472  	if err != nil {
   473  		return nil, err
   474  	}
   475  	if !result.Approved {
   476  		return nil, ErrRequestDenied
   477  	}
   478  //记录用户界面对签名请求所做的更改
   479  	logDiff(&req, &result)
   480  	var (
   481  		acc    accounts.Account
   482  		wallet accounts.Wallet
   483  	)
   484  	acc = accounts.Account{Address: result.Transaction.From.Address()}
   485  	wallet, err = api.am.Find(acc)
   486  	if err != nil {
   487  		return nil, err
   488  	}
   489  //将字段转换为实际事务
   490  	var unsignedTx = result.Transaction.toTransaction()
   491  
   492  //要签名的是从UI返回的那个
   493  	signedTx, err := wallet.SignTxWithPassphrase(acc, result.Password, unsignedTx, api.chainID)
   494  	if err != nil {
   495  		api.UI.ShowError(err.Error())
   496  		return nil, err
   497  	}
   498  
   499  	rlpdata, err := rlp.EncodeToBytes(signedTx)
   500  	response := ethapi.SignTransactionResult{Raw: rlpdata, Tx: signedTx}
   501  
   502  //最后,将签名的Tx发送到UI
   503  	api.UI.OnApprovedTx(response)
   504  //…和外部呼叫者
   505  	return &response, nil
   506  
   507  }
   508  
   509  //sign计算以太坊ECDSA签名:
   510  //keccack256(“\x19ethereum签名消息:\n”+len(消息)+消息)
   511  //
   512  //注:生成的签名符合secp256k1曲线r、s和v值,
   513  //由于遗产原因,V值将为27或28。
   514  //
   515  //用于计算签名的密钥用给定的密码解密。
   516  //
   517  //https://github.com/ethereum/go-ethereum/wiki/management-apis个人签名
   518  func (api *SignerAPI) Sign(ctx context.Context, addr common.MixedcaseAddress, data hexutil.Bytes) (hexutil.Bytes, error) {
   519  	sighash, msg := SignHash(data)
   520  //我们在查询是否有账户之前提出请求,以防止
   521  //通过API进行帐户枚举
   522  	req := &SignDataRequest{Address: addr, Rawdata: data, Message: msg, Hash: sighash, Meta: MetadataFromContext(ctx)}
   523  	res, err := api.UI.ApproveSignData(req)
   524  
   525  	if err != nil {
   526  		return nil, err
   527  	}
   528  	if !res.Approved {
   529  		return nil, ErrRequestDenied
   530  	}
   531  //查找包含请求签名者的钱包
   532  	account := accounts.Account{Address: addr.Address()}
   533  	wallet, err := api.am.Find(account)
   534  	if err != nil {
   535  		return nil, err
   536  	}
   537  //集合用钱包签名数据
   538  	signature, err := wallet.SignHashWithPassphrase(account, res.Password, sighash)
   539  	if err != nil {
   540  		api.UI.ShowError(err.Error())
   541  		return nil, err
   542  	}
   543  signature[64] += 27 //根据黄纸将V从0/1转换为27/28
   544  	return signature, nil
   545  }
   546  
   547  //signhash是一个帮助函数,用于计算给定消息的哈希
   548  //安全地用于计算签名。
   549  //
   550  //哈希计算为
   551  //keccak256(“\x19ethereum签名消息:\n”$消息长度$消息)。
   552  //
   553  //这将为已签名的消息提供上下文,并防止对事务进行签名。
   554  func SignHash(data []byte) ([]byte, string) {
   555  	msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data)
   556  	return crypto.Keccak256([]byte(msg)), msg
   557  }
   558  
   559  //export以Web3密钥库格式返回与给定地址关联的加密私钥。
   560  func (api *SignerAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) {
   561  	res, err := api.UI.ApproveExport(&ExportRequest{Address: addr, Meta: MetadataFromContext(ctx)})
   562  
   563  	if err != nil {
   564  		return nil, err
   565  	}
   566  	if !res.Approved {
   567  		return nil, ErrRequestDenied
   568  	}
   569  //查找包含请求签名者的钱包
   570  	wallet, err := api.am.Find(accounts.Account{Address: addr})
   571  	if err != nil {
   572  		return nil, err
   573  	}
   574  	if wallet.URL().Scheme != keystore.KeyStoreScheme {
   575  		return nil, fmt.Errorf("Account is not a keystore-account")
   576  	}
   577  	return ioutil.ReadFile(wallet.URL().Path)
   578  }
   579  
   580  //import尝试在本地密钥库中导入给定的keyjson。keyjson数据应为
   581  //以Web3密钥库格式。它将使用给定的密码短语解密keyjson,并在成功时
   582  //解密它将使用给定的新密码短语加密密钥,并将其存储在密钥库中。
   583  //OBS!此方法已从公共API中删除。不应在外部API上公开
   584  //有几个原因:
   585  //1。即使它是加密的,它仍然应该被视为敏感数据。
   586  //2。它可以用于dos clef,通过使用恶意数据,例如超大
   587  //kdfarams的值。
   588  func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage) (Account, error) {
   589  	be := api.am.Backends(keystore.KeyStoreType)
   590  
   591  	if len(be) == 0 {
   592  		return Account{}, errors.New("password based accounts not supported")
   593  	}
   594  	res, err := api.UI.ApproveImport(&ImportRequest{Meta: MetadataFromContext(ctx)})
   595  
   596  	if err != nil {
   597  		return Account{}, err
   598  	}
   599  	if !res.Approved {
   600  		return Account{}, ErrRequestDenied
   601  	}
   602  	acc, err := be[0].(*keystore.KeyStore).Import(keyJSON, res.OldPassword, res.NewPassword)
   603  	if err != nil {
   604  		api.UI.ShowError(err.Error())
   605  		return Account{}, err
   606  	}
   607  	return Account{Typ: "Account", URL: acc.URL, Address: acc.Address}, nil
   608  }
   609