github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/console/bridge.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  //版权所有2016 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package console
    26  
    27  import (
    28  	"encoding/json"
    29  	"fmt"
    30  	"io"
    31  	"strings"
    32  	"time"
    33  
    34  	"github.com/ethereum/go-ethereum/accounts/usbwallet"
    35  	"github.com/ethereum/go-ethereum/log"
    36  	"github.com/ethereum/go-ethereum/rpc"
    37  	"github.com/robertkrimen/otto"
    38  )
    39  
    40  //Bridge是一组javascript实用程序方法,用于连接.js运行时。
    41  //环境和支持远程方法调用的go-rpc连接。
    42  type bridge struct {
    43  client   *rpc.Client  //通过RPC客户端执行以太坊请求
    44  prompter UserPrompter //输入提示以允许交互式用户反馈
    45  printer  io.Writer    //要将任何显示字符串序列化到的输出编写器
    46  }
    47  
    48  //
    49  func newBridge(client *rpc.Client, prompter UserPrompter, printer io.Writer) *bridge {
    50  	return &bridge{
    51  		client:   client,
    52  		prompter: prompter,
    53  		printer:  printer,
    54  	}
    55  }
    56  
    57  //
    58  //不回显密码提示获取密码短语并执行原始密码
    59  //rpc方法(保存在jeth.newaccount中)用于实际执行rpc调用。
    60  func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) {
    61  	var (
    62  		password string
    63  		confirm  string
    64  		err      error
    65  	)
    66  	switch {
    67  //未指定密码,提示用户输入密码
    68  	case len(call.ArgumentList) == 0:
    69  		if password, err = b.prompter.PromptPassword("Passphrase: "); err != nil {
    70  			throwJSException(err.Error())
    71  		}
    72  		if confirm, err = b.prompter.PromptPassword("Repeat passphrase: "); err != nil {
    73  			throwJSException(err.Error())
    74  		}
    75  		if password != confirm {
    76  			throwJSException("passphrases don't match!")
    77  		}
    78  
    79  //指定了单个字符串密码,请使用
    80  	case len(call.ArgumentList) == 1 && call.Argument(0).IsString():
    81  		password, _ = call.Argument(0).ToString()
    82  
    83  //否则会因某些错误而失败
    84  	default:
    85  		throwJSException("expected 0 or 1 string argument")
    86  	}
    87  //获取密码,执行呼叫并返回
    88  	ret, err := call.Otto.Call("jeth.newAccount", nil, password)
    89  	if err != nil {
    90  		throwJSException(err.Error())
    91  	}
    92  	return ret
    93  }
    94  
    95  //openwallet是一个围绕personal.openwallet的包装,它可以解释和
    96  //对某些错误消息作出反应,例如trezor pin matrix请求。
    97  func (b *bridge) OpenWallet(call otto.FunctionCall) (response otto.Value) {
    98  //确保我们有一个指定要打开的钱包
    99  	if !call.Argument(0).IsString() {
   100  		throwJSException("first argument must be the wallet URL to open")
   101  	}
   102  	wallet := call.Argument(0)
   103  
   104  	var passwd otto.Value
   105  	if call.Argument(1).IsUndefined() || call.Argument(1).IsNull() {
   106  		passwd, _ = otto.ToValue("")
   107  	} else {
   108  		passwd = call.Argument(1)
   109  	}
   110  //
   111  	val, err := call.Otto.Call("jeth.openWallet", nil, wallet, passwd)
   112  	if err == nil {
   113  		return val
   114  	}
   115  //钱包打开失败,除非是密码输入,否则报告错误
   116  	if !strings.HasSuffix(err.Error(), usbwallet.ErrTrezorPINNeeded.Error()) {
   117  		throwJSException(err.Error())
   118  	}
   119  //请求Trezor管脚矩阵输入,向用户显示矩阵并获取数据
   120  	fmt.Fprintf(b.printer, "Look at the device for number positions\n\n")
   121  	fmt.Fprintf(b.printer, "7 | 8 | 9\n")
   122  	fmt.Fprintf(b.printer, "--+---+--\n")
   123  	fmt.Fprintf(b.printer, "4 | 5 | 6\n")
   124  	fmt.Fprintf(b.printer, "--+---+--\n")
   125  	fmt.Fprintf(b.printer, "1 | 2 | 3\n\n")
   126  
   127  	if input, err := b.prompter.PromptPassword("Please enter current PIN: "); err != nil {
   128  		throwJSException(err.Error())
   129  	} else {
   130  		passwd, _ = otto.ToValue(input)
   131  	}
   132  	if val, err = call.Otto.Call("jeth.openWallet", nil, wallet, passwd); err != nil {
   133  		throwJSException(err.Error())
   134  	}
   135  	return val
   136  }
   137  
   138  //UnlockAccount是围绕Personal.UnlockAccount RPC方法的包装,
   139  //
   140  //
   141  //RPC调用。
   142  func (b *bridge) UnlockAccount(call otto.FunctionCall) (response otto.Value) {
   143  //
   144  	if !call.Argument(0).IsString() {
   145  		throwJSException("first argument must be the account to unlock")
   146  	}
   147  	account := call.Argument(0)
   148  
   149  //如果未给出密码或是空值,提示用户输入密码。
   150  	var passwd otto.Value
   151  
   152  	if call.Argument(1).IsUndefined() || call.Argument(1).IsNull() {
   153  		fmt.Fprintf(b.printer, "Unlock account %s\n", account)
   154  		if input, err := b.prompter.PromptPassword("Passphrase: "); err != nil {
   155  			throwJSException(err.Error())
   156  		} else {
   157  			passwd, _ = otto.ToValue(input)
   158  		}
   159  	} else {
   160  		if !call.Argument(1).IsString() {
   161  			throwJSException("password must be a string")
   162  		}
   163  		passwd = call.Argument(1)
   164  	}
   165  //第三个参数是帐户必须解锁的持续时间。
   166  	duration := otto.NullValue()
   167  	if call.Argument(2).IsDefined() && !call.Argument(2).IsNull() {
   168  		if !call.Argument(2).IsNumber() {
   169  			throwJSException("unlock duration must be a number")
   170  		}
   171  		duration = call.Argument(2)
   172  	}
   173  //将请求发送到后端并返回
   174  	val, err := call.Otto.Call("jeth.unlockAccount", nil, account, passwd, duration)
   175  	if err != nil {
   176  		throwJSException(err.Error())
   177  	}
   178  	return val
   179  }
   180  
   181  //sign是围绕personal.sign rpc方法的包装,该方法使用非回显密码。
   182  //提示获取密码短语并执行原始RPC方法(保存在
   183  //用它来实际执行RPC调用。
   184  func (b *bridge) Sign(call otto.FunctionCall) (response otto.Value) {
   185  	var (
   186  		message = call.Argument(0)
   187  		account = call.Argument(1)
   188  		passwd  = call.Argument(2)
   189  	)
   190  
   191  	if !message.IsString() {
   192  		throwJSException("first argument must be the message to sign")
   193  	}
   194  	if !account.IsString() {
   195  		throwJSException("second argument must be the account to sign with")
   196  	}
   197  
   198  //如果未提供密码或密码为空,请询问用户并确保密码为字符串
   199  	if passwd.IsUndefined() || passwd.IsNull() {
   200  		fmt.Fprintf(b.printer, "Give password for account %s\n", account)
   201  		if input, err := b.prompter.PromptPassword("Passphrase: "); err != nil {
   202  			throwJSException(err.Error())
   203  		} else {
   204  			passwd, _ = otto.ToValue(input)
   205  		}
   206  	}
   207  	if !passwd.IsString() {
   208  		throwJSException("third argument must be the password to unlock the account")
   209  	}
   210  
   211  //将请求发送到后端并返回
   212  	val, err := call.Otto.Call("jeth.sign", nil, message, account, passwd)
   213  	if err != nil {
   214  		throwJSException(err.Error())
   215  	}
   216  	return val
   217  }
   218  
   219  //睡眠将在指定的秒数内阻止控制台。
   220  func (b *bridge) Sleep(call otto.FunctionCall) (response otto.Value) {
   221  	if call.Argument(0).IsNumber() {
   222  		sleep, _ := call.Argument(0).ToInteger()
   223  		time.Sleep(time.Duration(sleep) * time.Second)
   224  		return otto.TrueValue()
   225  	}
   226  	return throwJSException("usage: sleep(<number of seconds>)")
   227  }
   228  
   229  //SleepBlocks将为指定数量的新块(可选)阻止控制台
   230  //
   231  func (b *bridge) SleepBlocks(call otto.FunctionCall) (response otto.Value) {
   232  	var (
   233  		blocks = int64(0)
   234  sleep  = int64(9999999999999999) //无限期地
   235  	)
   236  //分析睡眠的输入参数
   237  	nArgs := len(call.ArgumentList)
   238  	if nArgs == 0 {
   239  		throwJSException("usage: sleepBlocks(<n blocks>[, max sleep in seconds])")
   240  	}
   241  	if nArgs >= 1 {
   242  		if call.Argument(0).IsNumber() {
   243  			blocks, _ = call.Argument(0).ToInteger()
   244  		} else {
   245  			throwJSException("expected number as first argument")
   246  		}
   247  	}
   248  	if nArgs >= 2 {
   249  		if call.Argument(1).IsNumber() {
   250  			sleep, _ = call.Argument(1).ToInteger()
   251  		} else {
   252  			throwJSException("expected number as second argument")
   253  		}
   254  	}
   255  //通过控制台,这将允许Web3调用适当的
   256  //如果收到延迟的响应或通知,则进行回调。
   257  	blockNumber := func() int64 {
   258  		result, err := call.Otto.Run("eth.blockNumber")
   259  		if err != nil {
   260  			throwJSException(err.Error())
   261  		}
   262  		block, err := result.ToInteger()
   263  		if err != nil {
   264  			throwJSException(err.Error())
   265  		}
   266  		return block
   267  	}
   268  //轮询当前块号,直到超时为止
   269  	targetBlockNr := blockNumber() + blocks
   270  	deadline := time.Now().Add(time.Duration(sleep) * time.Second)
   271  
   272  	for time.Now().Before(deadline) {
   273  		if blockNumber() >= targetBlockNr {
   274  			return otto.TrueValue()
   275  		}
   276  		time.Sleep(time.Second)
   277  	}
   278  	return otto.FalseValue()
   279  }
   280  
   281  type jsonrpcCall struct {
   282  	ID     int64
   283  	Method string
   284  	Params []interface{}
   285  }
   286  
   287  //send实现Web3提供程序“send”方法。
   288  func (b *bridge) Send(call otto.FunctionCall) (response otto.Value) {
   289  //将请求改为go值。
   290  	JSON, _ := call.Otto.Object("JSON")
   291  	reqVal, err := JSON.Call("stringify", call.Argument(0))
   292  	if err != nil {
   293  		throwJSException(err.Error())
   294  	}
   295  	var (
   296  		rawReq = reqVal.String()
   297  		dec    = json.NewDecoder(strings.NewReader(rawReq))
   298  		reqs   []jsonrpcCall
   299  		batch  bool
   300  	)
   301  dec.UseNumber() //避免浮标64
   302  	if rawReq[0] == '[' {
   303  		batch = true
   304  		dec.Decode(&reqs)
   305  	} else {
   306  		batch = false
   307  		reqs = make([]jsonrpcCall, 1)
   308  		dec.Decode(&reqs[0])
   309  	}
   310  
   311  //执行请求。
   312  	resps, _ := call.Otto.Object("new Array()")
   313  	for _, req := range reqs {
   314  		resp, _ := call.Otto.Object(`({"jsonrpc":"2.0"})`)
   315  		resp.Set("id", req.ID)
   316  		var result json.RawMessage
   317  		err = b.client.Call(&result, req.Method, req.Params...)
   318  		switch err := err.(type) {
   319  		case nil:
   320  			if result == nil {
   321  //特殊情况为空,因为它被解码为空
   322  //出于某种原因,原始消息。
   323  				resp.Set("result", otto.NullValue())
   324  			} else {
   325  				resultVal, err := JSON.Call("parse", string(result))
   326  				if err != nil {
   327  					setError(resp, -32603, err.Error())
   328  				} else {
   329  					resp.Set("result", resultVal)
   330  				}
   331  			}
   332  		case rpc.Error:
   333  			setError(resp, err.ErrorCode(), err.Error())
   334  		default:
   335  			setError(resp, -32603, err.Error())
   336  		}
   337  		resps.Call("push", resp)
   338  	}
   339  
   340  //返回对回调的响应(如果提供)
   341  //
   342  	if batch {
   343  		response = resps.Value()
   344  	} else {
   345  		response, _ = resps.Get("0")
   346  	}
   347  	if fn := call.Argument(1); fn.Class() == "Function" {
   348  		fn.Call(otto.NullValue(), otto.NullValue(), response)
   349  		return otto.UndefinedValue()
   350  	}
   351  	return response
   352  }
   353  
   354  func setError(resp *otto.Object, code int, msg string) {
   355  	resp.Set("error", map[string]interface{}{"code": code, "message": msg})
   356  }
   357  
   358  //throwjsException在otto.value上崩溃。奥托虚拟机将从
   359  //惊慌失措,将msg作为一个javascript错误抛出。
   360  func throwJSException(msg interface{}) otto.Value {
   361  	val, err := otto.ToValue(msg)
   362  	if err != nil {
   363  		log.Error("Failed to serialize JavaScript exception", "exception", msg, "err", err)
   364  	}
   365  	panic(val)
   366  }