github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/signer/core/api.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2018 Go Ethereum作者
    10  //此文件是Go以太坊的一部分。
    11  //
    12  //Go以太坊是免费软件:您可以重新发布和/或修改它
    13  //根据GNU通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊的分布希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU通用公共许可证了解更多详细信息。
    21  //
    22  //你应该已经收到一份GNU通用公共许可证的副本
    23  //一起去以太坊吧。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package core
    26  
    27  import (
    28  	"context"
    29  	"encoding/json"
    30  	"errors"
    31  	"fmt"
    32  	"io/ioutil"
    33  	"math/big"
    34  	"reflect"
    35  
    36  	"github.com/ethereum/go-ethereum/accounts"
    37  	"github.com/ethereum/go-ethereum/accounts/keystore"
    38  	"github.com/ethereum/go-ethereum/accounts/usbwallet"
    39  	"github.com/ethereum/go-ethereum/common"
    40  	"github.com/ethereum/go-ethereum/common/hexutil"
    41  	"github.com/ethereum/go-ethereum/crypto"
    42  	"github.com/ethereum/go-ethereum/internal/ethapi"
    43  	"github.com/ethereum/go-ethereum/log"
    44  	"github.com/ethereum/go-ethereum/rlp"
    45  )
    46  
    47  //ExternalAPI定义用于发出签名请求的外部API。
    48  type ExternalAPI interface {
    49  //列出可用帐户
    50  	List(ctx context.Context) (Accounts, error)
    51  //创建新帐户的新请求
    52  	New(ctx context.Context) (accounts.Account, error)
    53  //SignTransaction请求签署指定的事务
    54  	SignTransaction(ctx context.Context, args SendTxArgs, methodSelector *string) (*ethapi.SignTransactionResult, error)
    55  //签名-请求对给定数据进行签名(加前缀)
    56  	Sign(ctx context.Context, addr common.MixedcaseAddress, data hexutil.Bytes) (hexutil.Bytes, error)
    57  //ecrecover-请求执行ecrecover
    58  	EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error)
    59  //导出-请求导出帐户
    60  	Export(ctx context.Context, addr common.Address) (json.RawMessage, error)
    61  //导入-请求导入帐户
    62  	Import(ctx context.Context, keyJSON json.RawMessage) (Account, error)
    63  }
    64  
    65  //SignerRui指定UI需要实现什么方法才能用作签名者的UI
    66  type SignerUI interface {
    67  //approvetx提示用户确认请求签署交易
    68  	ApproveTx(request *SignTxRequest) (SignTxResponse, error)
    69  //ApproveSignData提示用户确认请求签署数据
    70  	ApproveSignData(request *SignDataRequest) (SignDataResponse, error)
    71  //approveexport提示用户确认导出加密帐户json
    72  	ApproveExport(request *ExportRequest) (ExportResponse, error)
    73  //approveImport提示用户确认导入账号json
    74  	ApproveImport(request *ImportRequest) (ImportResponse, error)
    75  //批准提示用户确认列出帐户
    76  //用户界面可以修改要列出的科目列表
    77  	ApproveListing(request *ListRequest) (ListResponse, error)
    78  //ApproveWaccount提示用户确认创建新帐户,并显示给调用方
    79  	ApproveNewAccount(request *NewAccountRequest) (NewAccountResponse, error)
    80  //ShowError向用户显示错误消息
    81  	ShowError(message string)
    82  //ShowInfo向用户显示信息消息
    83  	ShowInfo(message string)
    84  //OnApprovedTX通知用户界面一个事务已成功签名。
    85  //用户界面可以使用此方法跟踪发送给特定收件人的邮件数量。
    86  	OnApprovedTx(tx ethapi.SignTransactionResult)
    87  //当签名者启动时调用OnSignerStartup,并告诉用户界面有关外部API位置和版本的信息。
    88  //信息
    89  	OnSignerStartup(info StartupInfo)
    90  }
    91  
    92  //signerapi定义了externalAPI的实际实现
    93  type SignerAPI struct {
    94  	chainID   *big.Int
    95  	am        *accounts.Manager
    96  	UI        SignerUI
    97  	validator *Validator
    98  }
    99  
   100  //有关请求的元数据
   101  type Metadata struct {
   102  	Remote string `json:"remote"`
   103  	Local  string `json:"local"`
   104  	Scheme string `json:"scheme"`
   105  }
   106  
   107  //MetadataFromContext从给定的Context.Context中提取元数据
   108  func MetadataFromContext(ctx context.Context) Metadata {
   109  m := Metadata{"NA", "NA", "NA"} //蝙蝠侠
   110  
   111  	if v := ctx.Value("remote"); v != nil {
   112  		m.Remote = v.(string)
   113  	}
   114  	if v := ctx.Value("scheme"); v != nil {
   115  		m.Scheme = v.(string)
   116  	}
   117  	if v := ctx.Value("local"); v != nil {
   118  		m.Local = v.(string)
   119  	}
   120  	return m
   121  }
   122  
   123  //字符串实现字符串接口
   124  func (m Metadata) String() string {
   125  	s, err := json.Marshal(m)
   126  	if err == nil {
   127  		return string(s)
   128  	}
   129  	return err.Error()
   130  }
   131  
   132  //签名者和用户界面之间的请求/响应类型的类型
   133  type (
   134  //signtxrequest包含要签名的事务的信息
   135  	SignTxRequest struct {
   136  		Transaction SendTxArgs       `json:"transaction"`
   137  		Callinfo    []ValidationInfo `json:"call_info"`
   138  		Meta        Metadata         `json:"meta"`
   139  	}
   140  //SigntxRequest的SigntxResponse结果
   141  	SignTxResponse struct {
   142  //用户界面可以更改Tx
   143  		Transaction SendTxArgs `json:"transaction"`
   144  		Approved    bool       `json:"approved"`
   145  		Password    string     `json:"password"`
   146  	}
   147  //将有关查询的信息导出到导出帐户
   148  	ExportRequest struct {
   149  		Address common.Address `json:"address"`
   150  		Meta    Metadata       `json:"meta"`
   151  	}
   152  //导出响应对导出请求的响应
   153  	ExportResponse struct {
   154  		Approved bool `json:"approved"`
   155  	}
   156  //导入请求有关导入帐户请求的信息
   157  	ImportRequest struct {
   158  		Meta Metadata `json:"meta"`
   159  	}
   160  	ImportResponse struct {
   161  		Approved    bool   `json:"approved"`
   162  		OldPassword string `json:"old_password"`
   163  		NewPassword string `json:"new_password"`
   164  	}
   165  	SignDataRequest struct {
   166  		Address common.MixedcaseAddress `json:"address"`
   167  		Rawdata hexutil.Bytes           `json:"raw_data"`
   168  		Message string                  `json:"message"`
   169  		Hash    hexutil.Bytes           `json:"hash"`
   170  		Meta    Metadata                `json:"meta"`
   171  	}
   172  	SignDataResponse struct {
   173  		Approved bool `json:"approved"`
   174  		Password string
   175  	}
   176  	NewAccountRequest struct {
   177  		Meta Metadata `json:"meta"`
   178  	}
   179  	NewAccountResponse struct {
   180  		Approved bool   `json:"approved"`
   181  		Password string `json:"password"`
   182  	}
   183  	ListRequest struct {
   184  		Accounts []Account `json:"accounts"`
   185  		Meta     Metadata  `json:"meta"`
   186  	}
   187  	ListResponse struct {
   188  		Accounts []Account `json:"accounts"`
   189  	}
   190  	Message struct {
   191  		Text string `json:"text"`
   192  	}
   193  	StartupInfo struct {
   194  		Info map[string]interface{} `json:"info"`
   195  	}
   196  )
   197  
   198  var ErrRequestDenied = errors.New("Request denied")
   199  
   200  //NewSignerAPI创建了一个新的可用于帐户管理的API。
   201  //kslocation指定存储受密码保护的private的目录
   202  //创建新帐户时生成的键。
   203  //nousb禁用支持硬件设备所需的USB支持,如
   204  //Ledger和Trezor。
   205  func NewSignerAPI(chainID int64, ksLocation string, noUSB bool, ui SignerUI, abidb *AbiDb, lightKDF bool) *SignerAPI {
   206  	var (
   207  		backends []accounts.Backend
   208  		n, p     = keystore.StandardScryptN, keystore.StandardScryptP
   209  	)
   210  	if lightKDF {
   211  		n, p = keystore.LightScryptN, keystore.LightScryptP
   212  	}
   213  //支持基于密码的帐户
   214  	if len(ksLocation) > 0 {
   215  		backends = append(backends, keystore.NewKeyStore(ksLocation, n, p))
   216  	}
   217  	if !noUSB {
   218  //启动用于分类帐硬件钱包的USB集线器
   219  		if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil {
   220  			log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err))
   221  		} else {
   222  			backends = append(backends, ledgerhub)
   223  			log.Debug("Ledger support enabled")
   224  		}
   225  //启动Trezor硬件钱包的USB集线器
   226  		if trezorhub, err := usbwallet.NewTrezorHub(); err != nil {
   227  			log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err))
   228  		} else {
   229  			backends = append(backends, trezorhub)
   230  			log.Debug("Trezor support enabled")
   231  		}
   232  	}
   233  	return &SignerAPI{big.NewInt(chainID), accounts.NewManager(backends...), ui, NewValidator(abidb)}
   234  }
   235  
   236  //list返回签名者管理的钱包集。每个钱包都可以包含
   237  //多个帐户。
   238  func (api *SignerAPI) List(ctx context.Context) (Accounts, error) {
   239  	var accs []Account
   240  	for _, wallet := range api.am.Wallets() {
   241  		for _, acc := range wallet.Accounts() {
   242  			acc := Account{Typ: "Account", URL: wallet.URL(), Address: acc.Address}
   243  			accs = append(accs, acc)
   244  		}
   245  	}
   246  	result, err := api.UI.ApproveListing(&ListRequest{Accounts: accs, Meta: MetadataFromContext(ctx)})
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  	if result.Accounts == nil {
   251  		return nil, ErrRequestDenied
   252  
   253  	}
   254  	return result.Accounts, nil
   255  }
   256  
   257  //新建创建新的密码保护帐户。私钥受保护
   258  //给定的密码。用户负责备份存储的私钥
   259  //在密钥库位置中,创建此API时指定了THA。
   260  func (api *SignerAPI) New(ctx context.Context) (accounts.Account, error) {
   261  	be := api.am.Backends(keystore.KeyStoreType)
   262  	if len(be) == 0 {
   263  		return accounts.Account{}, errors.New("password based accounts not supported")
   264  	}
   265  	resp, err := api.UI.ApproveNewAccount(&NewAccountRequest{MetadataFromContext(ctx)})
   266  
   267  	if err != nil {
   268  		return accounts.Account{}, err
   269  	}
   270  	if !resp.Approved {
   271  		return accounts.Account{}, ErrRequestDenied
   272  	}
   273  	return be[0].(*keystore.KeyStore).NewAccount(resp.Password)
   274  }
   275  
   276  //logdiff记录传入(原始)事务和从签名者返回的事务之间的差异。
   277  //如果修改了事务,它还返回“true”,以便可以将签名者配置为不允许
   278  //请求的用户界面修改
   279  func logDiff(original *SignTxRequest, new *SignTxResponse) bool {
   280  	modified := false
   281  	if f0, f1 := original.Transaction.From, new.Transaction.From; !reflect.DeepEqual(f0, f1) {
   282  		log.Info("Sender-account changed by UI", "was", f0, "is", f1)
   283  		modified = true
   284  	}
   285  	if t0, t1 := original.Transaction.To, new.Transaction.To; !reflect.DeepEqual(t0, t1) {
   286  		log.Info("Recipient-account changed by UI", "was", t0, "is", t1)
   287  		modified = true
   288  	}
   289  	if g0, g1 := original.Transaction.Gas, new.Transaction.Gas; g0 != g1 {
   290  		modified = true
   291  		log.Info("Gas changed by UI", "was", g0, "is", g1)
   292  	}
   293  	if g0, g1 := big.Int(original.Transaction.GasPrice), big.Int(new.Transaction.GasPrice); g0.Cmp(&g1) != 0 {
   294  		modified = true
   295  		log.Info("GasPrice changed by UI", "was", g0, "is", g1)
   296  	}
   297  	if v0, v1 := big.Int(original.Transaction.Value), big.Int(new.Transaction.Value); v0.Cmp(&v1) != 0 {
   298  		modified = true
   299  		log.Info("Value changed by UI", "was", v0, "is", v1)
   300  	}
   301  	if d0, d1 := original.Transaction.Data, new.Transaction.Data; d0 != d1 {
   302  		d0s := ""
   303  		d1s := ""
   304  		if d0 != nil {
   305  			d0s = common.ToHex(*d0)
   306  		}
   307  		if d1 != nil {
   308  			d1s = common.ToHex(*d1)
   309  		}
   310  		if d1s != d0s {
   311  			modified = true
   312  			log.Info("Data changed by UI", "was", d0s, "is", d1s)
   313  		}
   314  	}
   315  	if n0, n1 := original.Transaction.Nonce, new.Transaction.Nonce; n0 != n1 {
   316  		modified = true
   317  		log.Info("Nonce changed by UI", "was", n0, "is", n1)
   318  	}
   319  	return modified
   320  }
   321  
   322  //signTransaction对给定的事务进行签名,并将其作为json和rlp编码的形式返回
   323  func (api *SignerAPI) SignTransaction(ctx context.Context, args SendTxArgs, methodSelector *string) (*ethapi.SignTransactionResult, error) {
   324  	var (
   325  		err    error
   326  		result SignTxResponse
   327  	)
   328  	msgs, err := api.validator.ValidateTransaction(&args, methodSelector)
   329  	if err != nil {
   330  		return nil, err
   331  	}
   332  
   333  	req := SignTxRequest{
   334  		Transaction: args,
   335  		Meta:        MetadataFromContext(ctx),
   336  		Callinfo:    msgs.Messages,
   337  	}
   338  //工艺批准
   339  	result, err = api.UI.ApproveTx(&req)
   340  	if err != nil {
   341  		return nil, err
   342  	}
   343  	if !result.Approved {
   344  		return nil, ErrRequestDenied
   345  	}
   346  //记录用户界面对签名请求所做的更改
   347  	logDiff(&req, &result)
   348  	var (
   349  		acc    accounts.Account
   350  		wallet accounts.Wallet
   351  	)
   352  	acc = accounts.Account{Address: result.Transaction.From.Address()}
   353  	wallet, err = api.am.Find(acc)
   354  	if err != nil {
   355  		return nil, err
   356  	}
   357  //将字段转换为实际事务
   358  	var unsignedTx = result.Transaction.toTransaction()
   359  
   360  //要签名的是从UI返回的那个
   361  	signedTx, err := wallet.SignTxWithPassphrase(acc, result.Password, unsignedTx, api.chainID)
   362  	if err != nil {
   363  		api.UI.ShowError(err.Error())
   364  		return nil, err
   365  	}
   366  
   367  	rlpdata, err := rlp.EncodeToBytes(signedTx)
   368  	response := ethapi.SignTransactionResult{Raw: rlpdata, Tx: signedTx}
   369  
   370  //最后,将签名的Tx发送到UI
   371  	api.UI.OnApprovedTx(response)
   372  //…和外部呼叫者
   373  	return &response, nil
   374  
   375  }
   376  
   377  //sign计算以太坊ECDSA签名:
   378  //keccack256(“\x19ethereum签名消息:\n”+len(消息)+消息)
   379  //
   380  //注:生成的签名符合secp256k1曲线r、s和v值,
   381  //由于遗产原因,V值将为27或28。
   382  //
   383  //用于计算签名的密钥用给定的密码解密。
   384  //
   385  //https://github.com/ethereum/go-ethereum/wiki/management-apis个人签名
   386  func (api *SignerAPI) Sign(ctx context.Context, addr common.MixedcaseAddress, data hexutil.Bytes) (hexutil.Bytes, error) {
   387  	sighash, msg := SignHash(data)
   388  //我们在查询是否有账户之前提出请求,以防止
   389  //通过API进行帐户枚举
   390  	req := &SignDataRequest{Address: addr, Rawdata: data, Message: msg, Hash: sighash, Meta: MetadataFromContext(ctx)}
   391  	res, err := api.UI.ApproveSignData(req)
   392  
   393  	if err != nil {
   394  		return nil, err
   395  	}
   396  	if !res.Approved {
   397  		return nil, ErrRequestDenied
   398  	}
   399  //查找包含请求签名者的钱包
   400  	account := accounts.Account{Address: addr.Address()}
   401  	wallet, err := api.am.Find(account)
   402  	if err != nil {
   403  		return nil, err
   404  	}
   405  //集合用钱包签名数据
   406  	signature, err := wallet.SignHashWithPassphrase(account, res.Password, sighash)
   407  	if err != nil {
   408  		api.UI.ShowError(err.Error())
   409  		return nil, err
   410  	}
   411  signature[64] += 27 //根据黄纸将V从0/1转换为27/28
   412  	return signature, nil
   413  }
   414  
   415  //ecrecover返回用于创建签名的帐户的地址。
   416  //注意,此功能与ETH标志和个人标志兼容。因此,它恢复了
   417  //地址:
   418  //hash=keccak256(“\x19ethereum签名消息:\n”$消息长度$消息)
   419  //addr=ecrecover(哈希,签名)
   420  //
   421  //注意,签名必须符合secp256k1曲线r、s和v值,其中
   422  //由于遗留原因,V值必须是27或28。
   423  //
   424  //https://github.com/ethereum/go-ethereum/wiki/management-apis个人\u-ecrecover
   425  func (api *SignerAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) {
   426  	if len(sig) != 65 {
   427  		return common.Address{}, fmt.Errorf("signature must be 65 bytes long")
   428  	}
   429  	if sig[64] != 27 && sig[64] != 28 {
   430  		return common.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)")
   431  	}
   432  sig[64] -= 27 //将黄纸V从27/28转换为0/1
   433  	hash, _ := SignHash(data)
   434  	rpk, err := crypto.SigToPub(hash, sig)
   435  	if err != nil {
   436  		return common.Address{}, err
   437  	}
   438  	return crypto.PubkeyToAddress(*rpk), nil
   439  }
   440  
   441  //signhash是一个帮助函数,用于计算给定消息的哈希
   442  //安全地用于计算签名。
   443  //
   444  //哈希计算为
   445  //keccak256(“\x19ethereum签名消息:\n”$消息长度$消息)。
   446  //
   447  //这将为已签名的消息提供上下文,并防止对事务进行签名。
   448  func SignHash(data []byte) ([]byte, string) {
   449  	msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data)
   450  	return crypto.Keccak256([]byte(msg)), msg
   451  }
   452  
   453  //export以Web3密钥库格式返回与给定地址关联的加密私钥。
   454  func (api *SignerAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) {
   455  	res, err := api.UI.ApproveExport(&ExportRequest{Address: addr, Meta: MetadataFromContext(ctx)})
   456  
   457  	if err != nil {
   458  		return nil, err
   459  	}
   460  	if !res.Approved {
   461  		return nil, ErrRequestDenied
   462  	}
   463  //查找包含请求签名者的钱包
   464  	wallet, err := api.am.Find(accounts.Account{Address: addr})
   465  	if err != nil {
   466  		return nil, err
   467  	}
   468  	if wallet.URL().Scheme != keystore.KeyStoreScheme {
   469  		return nil, fmt.Errorf("Account is not a keystore-account")
   470  	}
   471  	return ioutil.ReadFile(wallet.URL().Path)
   472  }
   473  
   474  //import尝试在本地密钥库中导入给定的keyjson。keyjson数据应为
   475  //以Web3密钥库格式。它将使用给定的密码短语解密keyjson,并在成功时
   476  //解密它将使用给定的新密码短语加密密钥,并将其存储在密钥库中。
   477  func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage) (Account, error) {
   478  	be := api.am.Backends(keystore.KeyStoreType)
   479  
   480  	if len(be) == 0 {
   481  		return Account{}, errors.New("password based accounts not supported")
   482  	}
   483  	res, err := api.UI.ApproveImport(&ImportRequest{Meta: MetadataFromContext(ctx)})
   484  
   485  	if err != nil {
   486  		return Account{}, err
   487  	}
   488  	if !res.Approved {
   489  		return Account{}, ErrRequestDenied
   490  	}
   491  	acc, err := be[0].(*keystore.KeyStore).Import(keyJSON, res.OldPassword, res.NewPassword)
   492  	if err != nil {
   493  		api.UI.ShowError(err.Error())
   494  		return Account{}, err
   495  	}
   496  	return Account{Typ: "Account", URL: acc.URL, Address: acc.Address}, nil
   497  }