github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/signer/rules/rules_test.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 rules 26 27 import ( 28 "fmt" 29 "math/big" 30 "strings" 31 "testing" 32 33 "github.com/ethereum/go-ethereum/accounts" 34 "github.com/ethereum/go-ethereum/common" 35 "github.com/ethereum/go-ethereum/common/hexutil" 36 "github.com/ethereum/go-ethereum/core/types" 37 "github.com/ethereum/go-ethereum/internal/ethapi" 38 "github.com/ethereum/go-ethereum/signer/core" 39 "github.com/ethereum/go-ethereum/signer/storage" 40 ) 41 42 const JS = ` 43 /* 44 这是一个JavaScript规则文件的示例实现。 45 46 当签名者通过外部API接收到请求时,将计算相应的方法。 47 可能发生三件事: 48 49 1。方法返回“批准”。这意味着操作是允许的。 50 2。方法返回“reject”。这意味着操作被拒绝。 51 三。其他任何内容;其他返回值[*],方法未实现或在处理过程中发生异常。这意味着 52 操作将继续通过用户选择的常规UI方法进行手动处理。 53 54 [*]注意:未来版本的规则集可能会使用更复杂的基于JSON的返回值,因此可能不会 55 只响应批准/拒绝/手动,但也修改响应。例如,选择只列出一个,而不是全部 56 列表请求中的帐户。以上几点将继续适用于非基于JSON的响应(“批准”/“拒绝”)。 57 58 */ 59 60 61 function ApproveListing(request){ 62 console.log("In js approve listing"); 63 console.log(request.accounts[3].Address) 64 console.log(request.meta.Remote) 65 return "Approve" 66 } 67 68 function ApproveTx(request){ 69 console.log("test"); 70 console.log("from"); 71 return "Reject"; 72 } 73 74 function test(thing){ 75 console.log(thing.String()) 76 } 77 78 ` 79 80 func mixAddr(a string) (*common.MixedcaseAddress, error) { 81 return common.NewMixedcaseAddressFromString(a) 82 } 83 84 type alwaysDenyUI struct{} 85 86 func (alwaysDenyUI) OnSignerStartup(info core.StartupInfo) { 87 } 88 89 func (alwaysDenyUI) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) { 90 return core.SignTxResponse{Transaction: request.Transaction, Approved: false, Password: ""}, nil 91 } 92 93 func (alwaysDenyUI) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) { 94 return core.SignDataResponse{Approved: false, Password: ""}, nil 95 } 96 97 func (alwaysDenyUI) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) { 98 return core.ExportResponse{Approved: false}, nil 99 } 100 101 func (alwaysDenyUI) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) { 102 return core.ImportResponse{Approved: false, OldPassword: "", NewPassword: ""}, nil 103 } 104 105 func (alwaysDenyUI) ApproveListing(request *core.ListRequest) (core.ListResponse, error) { 106 return core.ListResponse{Accounts: nil}, nil 107 } 108 109 func (alwaysDenyUI) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) { 110 return core.NewAccountResponse{Approved: false, Password: ""}, nil 111 } 112 113 func (alwaysDenyUI) ShowError(message string) { 114 panic("implement me") 115 } 116 117 func (alwaysDenyUI) ShowInfo(message string) { 118 panic("implement me") 119 } 120 121 func (alwaysDenyUI) OnApprovedTx(tx ethapi.SignTransactionResult) { 122 panic("implement me") 123 } 124 125 func initRuleEngine(js string) (*rulesetUI, error) { 126 r, err := NewRuleEvaluator(&alwaysDenyUI{}, storage.NewEphemeralStorage(), storage.NewEphemeralStorage()) 127 if err != nil { 128 return nil, fmt.Errorf("failed to create js engine: %v", err) 129 } 130 if err = r.Init(js); err != nil { 131 return nil, fmt.Errorf("failed to load bootstrap js: %v", err) 132 } 133 return r, nil 134 } 135 136 func TestListRequest(t *testing.T) { 137 accs := make([]core.Account, 5) 138 139 for i := range accs { 140 addr := fmt.Sprintf("000000000000000000000000000000000000000%x", i) 141 acc := core.Account{ 142 Address: common.BytesToAddress(common.Hex2Bytes(addr)), 143 URL: accounts.URL{Scheme: "test", Path: fmt.Sprintf("acc-%d", i)}, 144 } 145 accs[i] = acc 146 } 147 148 js := `function ApproveListing(){ return "Approve" }` 149 150 r, err := initRuleEngine(js) 151 if err != nil { 152 t.Errorf("Couldn't create evaluator %v", err) 153 return 154 } 155 resp, err := r.ApproveListing(&core.ListRequest{ 156 Accounts: accs, 157 Meta: core.Metadata{Remote: "remoteip", Local: "localip", Scheme: "inproc"}, 158 }) 159 if len(resp.Accounts) != len(accs) { 160 t.Errorf("Expected check to resolve to 'Approve'") 161 } 162 } 163 164 func TestSignTxRequest(t *testing.T) { 165 166 js := ` 167 function ApproveTx(r){ 168 console.log("transaction.from", r.transaction.from); 169 console.log("transaction.to", r.transaction.to); 170 console.log("transaction.value", r.transaction.value); 171 console.log("transaction.nonce", r.transaction.nonce); 172 if(r.transaction.from.toLowerCase()=="0x0000000000000000000000000000000000001337"){ return "Approve"} 173 if(r.transaction.from.toLowerCase()=="0x000000000000000000000000000000000000dead"){ return "Reject"} 174 }` 175 176 r, err := initRuleEngine(js) 177 if err != nil { 178 t.Errorf("Couldn't create evaluator %v", err) 179 return 180 } 181 to, err := mixAddr("000000000000000000000000000000000000dead") 182 if err != nil { 183 t.Error(err) 184 return 185 } 186 from, err := mixAddr("0000000000000000000000000000000000001337") 187 188 if err != nil { 189 t.Error(err) 190 return 191 } 192 fmt.Printf("to %v", to.Address().String()) 193 resp, err := r.ApproveTx(&core.SignTxRequest{ 194 Transaction: core.SendTxArgs{ 195 From: *from, 196 To: to}, 197 Callinfo: nil, 198 Meta: core.Metadata{Remote: "remoteip", Local: "localip", Scheme: "inproc"}, 199 }) 200 if err != nil { 201 t.Errorf("Unexpected error %v", err) 202 } 203 if !resp.Approved { 204 t.Errorf("Expected check to resolve to 'Approve'") 205 } 206 } 207 208 type dummyUI struct { 209 calls []string 210 } 211 212 func (d *dummyUI) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) { 213 d.calls = append(d.calls, "ApproveTx") 214 return core.SignTxResponse{}, core.ErrRequestDenied 215 } 216 217 func (d *dummyUI) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) { 218 d.calls = append(d.calls, "ApproveSignData") 219 return core.SignDataResponse{}, core.ErrRequestDenied 220 } 221 222 func (d *dummyUI) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) { 223 d.calls = append(d.calls, "ApproveExport") 224 return core.ExportResponse{}, core.ErrRequestDenied 225 } 226 227 func (d *dummyUI) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) { 228 d.calls = append(d.calls, "ApproveImport") 229 return core.ImportResponse{}, core.ErrRequestDenied 230 } 231 232 func (d *dummyUI) ApproveListing(request *core.ListRequest) (core.ListResponse, error) { 233 d.calls = append(d.calls, "ApproveListing") 234 return core.ListResponse{}, core.ErrRequestDenied 235 } 236 237 func (d *dummyUI) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) { 238 d.calls = append(d.calls, "ApproveNewAccount") 239 return core.NewAccountResponse{}, core.ErrRequestDenied 240 } 241 242 func (d *dummyUI) ShowError(message string) { 243 d.calls = append(d.calls, "ShowError") 244 } 245 246 func (d *dummyUI) ShowInfo(message string) { 247 d.calls = append(d.calls, "ShowInfo") 248 } 249 250 func (d *dummyUI) OnApprovedTx(tx ethapi.SignTransactionResult) { 251 d.calls = append(d.calls, "OnApprovedTx") 252 } 253 func (d *dummyUI) OnSignerStartup(info core.StartupInfo) { 254 } 255 256 //TestForwarding测试规则引擎是否正确地将请求分派给下一个调用方 257 func TestForwarding(t *testing.T) { 258 259 js := "" 260 ui := &dummyUI{make([]string, 0)} 261 jsBackend := storage.NewEphemeralStorage() 262 credBackend := storage.NewEphemeralStorage() 263 r, err := NewRuleEvaluator(ui, jsBackend, credBackend) 264 if err != nil { 265 t.Fatalf("Failed to create js engine: %v", err) 266 } 267 if err = r.Init(js); err != nil { 268 t.Fatalf("Failed to load bootstrap js: %v", err) 269 } 270 r.ApproveSignData(nil) 271 r.ApproveTx(nil) 272 r.ApproveImport(nil) 273 r.ApproveNewAccount(nil) 274 r.ApproveListing(nil) 275 r.ApproveExport(nil) 276 r.ShowError("test") 277 r.ShowInfo("test") 278 279 //这个没有转发 280 r.OnApprovedTx(ethapi.SignTransactionResult{}) 281 282 expCalls := 8 283 if len(ui.calls) != expCalls { 284 285 t.Errorf("Expected %d forwarded calls, got %d: %s", expCalls, len(ui.calls), strings.Join(ui.calls, ",")) 286 287 } 288 289 } 290 291 func TestMissingFunc(t *testing.T) { 292 r, err := initRuleEngine(JS) 293 if err != nil { 294 t.Errorf("Couldn't create evaluator %v", err) 295 return 296 } 297 298 _, err = r.execute("MissingMethod", "test") 299 300 if err == nil { 301 t.Error("Expected error") 302 } 303 304 approved, err := r.checkApproval("MissingMethod", nil, nil) 305 if err == nil { 306 t.Errorf("Expected missing method to yield error'") 307 } 308 if approved { 309 t.Errorf("Expected missing method to cause non-approval") 310 } 311 fmt.Printf("Err %v", err) 312 313 } 314 func TestStorage(t *testing.T) { 315 316 js := ` 317 function testStorage(){ 318 storage.Put("mykey", "myvalue") 319 a = storage.Get("mykey") 320 321 storage.Put("mykey", ["a", "list"]) //应生成“a,list” 322 a += storage.Get("mykey") 323 324 325 storage.Put("mykey", {"an": "object"}) //应导致“[对象对象]” 326 a += storage.Get("mykey") 327 328 329 storage.Put("mykey", JSON.stringify({"an": "object"})) //应导致“”an“:”对象“” 330 a += storage.Get("mykey") 331 332 a += storage.Get("missingkey") //缺少键应导致空字符串 333 storage.Put("","missing key==noop") //无法使用0长度密钥存储 334 a += storage.Get("") //应导致“”。 335 336 var b = new BigNumber(2) 337 var c = new BigNumber(16)//“0xF0”,16) 338 var d = b.plus(c) 339 console.log(d) 340 return a 341 } 342 ` 343 r, err := initRuleEngine(js) 344 if err != nil { 345 t.Errorf("Couldn't create evaluator %v", err) 346 return 347 } 348 349 v, err := r.execute("testStorage", nil) 350 351 if err != nil { 352 t.Errorf("Unexpected error %v", err) 353 } 354 355 retval, err := v.ToString() 356 357 if err != nil { 358 t.Errorf("Unexpected error %v", err) 359 } 360 exp := `myvaluea,list[object Object]{"an":"object"}` 361 if retval != exp { 362 t.Errorf("Unexpected data, expected '%v', got '%v'", exp, retval) 363 } 364 fmt.Printf("Err %v", err) 365 366 } 367 368 const ExampleTxWindow = ` 369 function big(str){ 370 if(str.slice(0,2) == "0x"){ return new BigNumber(str.slice(2),16)} 371 return new BigNumber(str) 372 } 373 374 //时间窗口:1周 375 var window = 1000* 3600*24*7; 376 377 //极限:1醚 378 var limit = new BigNumber("1e18"); 379 380 function isLimitOk(transaction){ 381 var value = big(transaction.value) 382 //启动窗口功能 383 var windowstart = new Date().getTime() - window; 384 385 var txs = []; 386 var stored = storage.Get('txs'); 387 388 if(stored != ""){ 389 txs = JSON.parse(stored) 390 } 391 //首先,删除时间窗口之外的所有内容 392 var newtxs = txs.filter(function(tx){return tx.tstamp > windowstart}); 393 console.log(txs, newtxs.length); 394 395 //第二,合计当前总额 396 sum = new BigNumber(0) 397 398 sum = newtxs.reduce(function(agg, tx){ return big(tx.value).plus(agg)}, sum); 399 console.log("ApproveTx > Sum so far", sum); 400 console.log("ApproveTx > Requested", value.toNumber()); 401 402 //我们会超过每周限额吗? 403 return sum.plus(value).lt(limit) 404 405 } 406 function ApproveTx(r){ 407 console.log(r) 408 console.log(typeof(r)) 409 if (isLimitOk(r.transaction)){ 410 return "Approve" 411 } 412 return "Nope" 413 } 414 415 /* 416 *OnApprovedTx(str)在交易被批准和签署后调用。参数 417 *“response_str”包含将发送给外部调用方的返回值。 418 *此方法的返回值为ignore-进行此回调的原因是允许 419 *用于跟踪已批准交易的规则集。 420 * 421 *在执行速率限制规则时,应使用此回调。 422 *如果规则的响应既不包含“批准”也不包含“拒绝”,则发送将进入手动处理。如果用户 423 *然后接受事务,将调用此方法。 424 * 425 *tldr;使用此方法跟踪已签名的事务,而不是使用approvetx中的数据。 426 **/ 427 428 function OnApprovedTx(resp){ 429 var value = big(resp.tx.value) 430 var txs = [] 431 //加载存储的事务 432 var stored = storage.Get('txs'); 433 if(stored != ""){ 434 txs = JSON.parse(stored) 435 } 436 //将此添加到存储 437 txs.push({tstamp: new Date().getTime(), value: value}); 438 storage.Put("txs", JSON.stringify(txs)); 439 } 440 441 ` 442 443 func dummyTx(value hexutil.Big) *core.SignTxRequest { 444 445 to, _ := mixAddr("000000000000000000000000000000000000dead") 446 from, _ := mixAddr("000000000000000000000000000000000000dead") 447 n := hexutil.Uint64(3) 448 gas := hexutil.Uint64(21000) 449 gasPrice := hexutil.Big(*big.NewInt(2000000)) 450 451 return &core.SignTxRequest{ 452 Transaction: core.SendTxArgs{ 453 From: *from, 454 To: to, 455 Value: value, 456 Nonce: n, 457 GasPrice: gasPrice, 458 Gas: gas, 459 }, 460 Callinfo: []core.ValidationInfo{ 461 {Typ: "Warning", Message: "All your base are bellong to us"}, 462 }, 463 Meta: core.Metadata{Remote: "remoteip", Local: "localip", Scheme: "inproc"}, 464 } 465 } 466 func dummyTxWithV(value uint64) *core.SignTxRequest { 467 468 v := big.NewInt(0).SetUint64(value) 469 h := hexutil.Big(*v) 470 return dummyTx(h) 471 } 472 func dummySigned(value *big.Int) *types.Transaction { 473 to := common.HexToAddress("000000000000000000000000000000000000dead") 474 gas := uint64(21000) 475 gasPrice := big.NewInt(2000000) 476 data := make([]byte, 0) 477 return types.NewTransaction(3, to, value, gas, gasPrice, data) 478 479 } 480 func TestLimitWindow(t *testing.T) { 481 482 r, err := initRuleEngine(ExampleTxWindow) 483 if err != nil { 484 t.Errorf("Couldn't create evaluator %v", err) 485 return 486 } 487 488 //0.3乙醚:429D069189E0000 wei 489 v := big.NewInt(0).SetBytes(common.Hex2Bytes("0429D069189E0000")) 490 h := hexutil.Big(*v) 491 //前三个应该成功 492 for i := 0; i < 3; i++ { 493 unsigned := dummyTx(h) 494 resp, err := r.ApproveTx(unsigned) 495 if err != nil { 496 t.Errorf("Unexpected error %v", err) 497 } 498 if !resp.Approved { 499 t.Errorf("Expected check to resolve to 'Approve'") 500 } 501 //创建虚拟签名事务 502 503 response := ethapi.SignTransactionResult{ 504 Tx: dummySigned(v), 505 Raw: common.Hex2Bytes("deadbeef"), 506 } 507 r.OnApprovedTx(response) 508 } 509 //第四个应该失败 510 resp, err := r.ApproveTx(dummyTx(h)) 511 if resp.Approved { 512 t.Errorf("Expected check to resolve to 'Reject'") 513 } 514 515 } 516 517 //dontcallme用作不希望调用的下一个处理程序-它调用测试失败 518 type dontCallMe struct { 519 t *testing.T 520 } 521 522 func (d *dontCallMe) OnSignerStartup(info core.StartupInfo) { 523 } 524 525 func (d *dontCallMe) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) { 526 d.t.Fatalf("Did not expect next-handler to be called") 527 return core.SignTxResponse{}, core.ErrRequestDenied 528 } 529 530 func (d *dontCallMe) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) { 531 d.t.Fatalf("Did not expect next-handler to be called") 532 return core.SignDataResponse{}, core.ErrRequestDenied 533 } 534 535 func (d *dontCallMe) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) { 536 d.t.Fatalf("Did not expect next-handler to be called") 537 return core.ExportResponse{}, core.ErrRequestDenied 538 } 539 540 func (d *dontCallMe) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) { 541 d.t.Fatalf("Did not expect next-handler to be called") 542 return core.ImportResponse{}, core.ErrRequestDenied 543 } 544 545 func (d *dontCallMe) ApproveListing(request *core.ListRequest) (core.ListResponse, error) { 546 d.t.Fatalf("Did not expect next-handler to be called") 547 return core.ListResponse{}, core.ErrRequestDenied 548 } 549 550 func (d *dontCallMe) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) { 551 d.t.Fatalf("Did not expect next-handler to be called") 552 return core.NewAccountResponse{}, core.ErrRequestDenied 553 } 554 555 func (d *dontCallMe) ShowError(message string) { 556 d.t.Fatalf("Did not expect next-handler to be called") 557 } 558 559 func (d *dontCallMe) ShowInfo(message string) { 560 d.t.Fatalf("Did not expect next-handler to be called") 561 } 562 563 func (d *dontCallMe) OnApprovedTx(tx ethapi.SignTransactionResult) { 564 d.t.Fatalf("Did not expect next-handler to be called") 565 } 566 567 //testcontext清除了规则引擎不在多个请求上保留变量的测试。 568 //如果是这样,那就不好了,因为开发人员可能会依赖它来存储数据, 569 //而不是使用基于磁盘的数据存储 570 func TestContextIsCleared(t *testing.T) { 571 572 js := ` 573 function ApproveTx(){ 574 if (typeof foobar == 'undefined') { 575 foobar = "Approve" 576 } 577 console.log(foobar) 578 if (foobar == "Approve"){ 579 foobar = "Reject" 580 }else{ 581 foobar = "Approve" 582 } 583 return foobar 584 } 585 ` 586 ui := &dontCallMe{t} 587 r, err := NewRuleEvaluator(ui, storage.NewEphemeralStorage(), storage.NewEphemeralStorage()) 588 if err != nil { 589 t.Fatalf("Failed to create js engine: %v", err) 590 } 591 if err = r.Init(js); err != nil { 592 t.Fatalf("Failed to load bootstrap js: %v", err) 593 } 594 tx := dummyTxWithV(0) 595 r1, err := r.ApproveTx(tx) 596 r2, err := r.ApproveTx(tx) 597 if r1.Approved != r2.Approved { 598 t.Errorf("Expected execution context to be cleared between executions") 599 } 600 } 601 602 func TestSignData(t *testing.T) { 603 604 js := `function ApproveListing(){ 605 return "Approve" 606 } 607 function ApproveSignData(r){ 608 if( r.address.toLowerCase() == "0x694267f14675d7e1b9494fd8d72fefe1755710fa") 609 { 610 if(r.message.indexOf("bazonk") >= 0){ 611 return "Approve" 612 } 613 return "Reject" 614 } 615 //否则进入手动处理 616 }` 617 r, err := initRuleEngine(js) 618 if err != nil { 619 t.Errorf("Couldn't create evaluator %v", err) 620 return 621 } 622 message := []byte("baz bazonk foo") 623 hash, msg := core.SignHash(message) 624 raw := hexutil.Bytes(message) 625 addr, _ := mixAddr("0x694267f14675d7e1b9494fd8d72fefe1755710fa") 626 627 fmt.Printf("address %v %v\n", addr.String(), addr.Original()) 628 resp, err := r.ApproveSignData(&core.SignDataRequest{ 629 Address: *addr, 630 Message: msg, 631 Hash: hash, 632 Meta: core.Metadata{Remote: "remoteip", Local: "localip", Scheme: "inproc"}, 633 Rawdata: raw, 634 }) 635 if err != nil { 636 t.Fatalf("Unexpected error %v", err) 637 } 638 if !resp.Approved { 639 t.Fatalf("Expected approved") 640 } 641 }