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 }