github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/contracts/statute/service.go (about) 1 package statute 2 3 import ( 4 "context" 5 "encoding/hex" 6 "errors" 7 "fmt" 8 "math/big" 9 "time" 10 11 chieflib "github.com/SmartMeshFoundation/Spectrum/contracts/chief/lib" 12 13 "github.com/SmartMeshFoundation/Spectrum/accounts" 14 "github.com/SmartMeshFoundation/Spectrum/accounts/abi/bind" 15 "github.com/SmartMeshFoundation/Spectrum/common" 16 "github.com/SmartMeshFoundation/Spectrum/contracts" 17 "github.com/SmartMeshFoundation/Spectrum/contracts/statute/anmaplib" 18 "github.com/SmartMeshFoundation/Spectrum/contracts/statute/meshboxlib" 19 "github.com/SmartMeshFoundation/Spectrum/core/types" 20 "github.com/SmartMeshFoundation/Spectrum/eth" 21 "github.com/SmartMeshFoundation/Spectrum/log" 22 "github.com/SmartMeshFoundation/Spectrum/node" 23 "github.com/SmartMeshFoundation/Spectrum/p2p" 24 "github.com/SmartMeshFoundation/Spectrum/params" 25 "github.com/SmartMeshFoundation/Spectrum/rpc" 26 ) 27 28 type AnmapService interface { 29 BindInfo(addr common.Address, blockNumber *big.Int, blockHash *common.Hash) (from common.Address, nodeids []common.Address, err error) 30 Bind(from, nodeAddr common.Address, sigHex string) (common.Hash, error) 31 Unbind(from, nodeAddr common.Address, sigHex string) (common.Hash, error) 32 } 33 34 type MeshboxService interface { 35 ExistAddress(addr common.Address) (*big.Int, error) 36 } 37 38 type StatuteService struct { 39 accman *accounts.Manager 40 anmap_0_0_1 *anmaplib.Anmap 41 meshbox_0_0_1 *meshboxlib.MeshBox 42 meshbox_0_0_2 *meshboxlib.MeshBox_0_0_2 43 poc_1 *chieflib.POC_1_0_0 44 ipcpath string 45 server *p2p.Server // peers and nodekey ... 46 quit chan int 47 ethereum *eth.Ethereum 48 } 49 50 var statuteService *StatuteService 51 52 func NewStatuteService(ctx *node.ServiceContext) (node.Service, error) { 53 var ethereum *eth.Ethereum 54 err := ctx.Service(ðereum) 55 if err != nil { 56 log.Error("NewStatuteService", "err", err) 57 } 58 ipcpath := params.GetIPCPath() 59 statuteService = &StatuteService{ 60 accman: ctx.AccountManager, 61 quit: make(chan int), 62 ipcpath: ipcpath, 63 ethereum: ethereum, 64 } 65 go statuteService.loop() 66 return statuteService, nil 67 } 68 69 func (self *StatuteService) startMeshbox(vsn string, backend *eth.ContractBackend) { 70 defer func() { 71 if r := recover(); r != nil { 72 log.Warn("ignore_this_err", r) 73 } 74 }() 75 var period = params.TribePeriod() 76 for { 77 var cn = self.ethereum.BlockChain().CurrentBlock().Number() 78 if params.IsReadyMeshbox(cn) { 79 mn, maddr := params.MeshboxInfo(cn, vsn) 80 if maddr != common.HexToAddress("") { 81 switch vsn { 82 case "0.0.1": 83 contract, err := meshboxlib.NewMeshBox(maddr, backend) 84 if err != nil { 85 panic(err) 86 } 87 statuteService.meshbox_0_0_1 = contract 88 case "0.0.2": 89 contract, err := meshboxlib.NewMeshBox_0_0_2(maddr, backend) 90 if err != nil { 91 panic(err) 92 } 93 statuteService.meshbox_0_0_2 = contract 94 } 95 close(params.InitMeshbox) 96 log.Info("<<Meshbox.Start>> success ", "period", period, "vsn", vsn, "cn", cn.Int64(), "tn", mn.Int64()) 97 return 98 } else { 99 //} else if cn.Cmp(mn) >= 0 { 100 log.Info("<<Meshbox.Start>> cancel ", "period", period, "vsn", vsn, "cn", cn, "tn", mn) 101 return 102 } 103 } 104 <-time.After(time.Duration(period) * time.Second) 105 } 106 } 107 108 func (self *StatuteService) startAnmap(vsn string, backend *eth.ContractBackend) { 109 defer func() { 110 if r := recover(); r != nil { 111 log.Warn("ignore_this_err", r) 112 } 113 }() 114 var period = params.TribePeriod() 115 for { 116 var cn = self.ethereum.BlockChain().CurrentBlock().Number() 117 if params.IsReadyAnmap(cn) { 118 mn, maddr := params.AnmapInfo(cn, vsn) 119 if maddr != common.HexToAddress("") { 120 switch vsn { 121 case "0.0.1": 122 contract, err := anmaplib.NewAnmap(maddr, backend) 123 if err != nil { 124 panic(err) 125 } 126 statuteService.anmap_0_0_1 = contract 127 } 128 close(params.InitAnmap) 129 log.Info("<<Anmap.Start>> success ", "period", period, "vsn", vsn, "cn", cn.Int64(), "tn", mn.Int64()) 130 return 131 } else if cn.Cmp(mn) >= 0 { 132 log.Info("<<Anmap.Start>> cancel ", "period", period, "vsn", vsn, "cn", cn.Int64(), "tn", mn.Int64()) 133 return 134 } 135 } 136 <-time.After(time.Duration(period) * time.Second) 137 } 138 } 139 140 func (self *StatuteService) Protocols() []p2p.Protocol { return nil } 141 func (self *StatuteService) APIs() []rpc.API { return nil } 142 func (self *StatuteService) Start(server *p2p.Server) error { 143 var be = eth.NewContractBackend(self.ethereum.ApiBackend) 144 go self.startMeshbox("0.0.1", be) 145 go self.startMeshbox("0.0.2", be) 146 go self.startAnmap("0.0.1", be) 147 if true { 148 //poc contract service 149 var err error 150 self.poc_1, err = chieflib.NewPOC_1_0_0(params.POCInfo(), be) 151 if err != nil { 152 panic(err) 153 } 154 } 155 156 self.server = server 157 return nil 158 } 159 160 func (self *StatuteService) Stop() error { 161 close(self.quit) 162 return nil 163 } 164 165 // =============================================================================== 166 // biz functions 167 // =============================================================================== 168 169 func GetAnmapService() (AnmapService, error) { 170 log.Debug("<<GetAnmapService>>") 171 select { 172 case <-params.InitMeshbox: 173 return statuteService, nil 174 default: 175 return nil, errors.New("anmap wait init") 176 } 177 } 178 179 func GetMeshboxService() (MeshboxService, error) { 180 log.Debug("<<GetMeshboxService>>") 181 select { 182 case <-params.InitMeshbox: 183 return statuteService, nil 184 default: 185 return nil, errors.New("meshbox wait init") 186 } 187 } 188 189 func sigSplit(sigHex string) (R, S [32]byte, V uint8) { 190 bR, err := hex.DecodeString(sigHex[:64]) 191 bS, err := hex.DecodeString(sigHex[64:128]) 192 if err != nil { 193 log.Error("sigSplit ", "sigHex", sigHex, "err", err) 194 } 195 copy(R[:], bR) 196 copy(S[:], bS) 197 V = 27 198 switch sigHex[128:] { 199 case "01": 200 V = 28 201 } 202 return 203 } 204 205 func (self *StatuteService) BindInfo(addr common.Address, blockNumber *big.Int, blockHash *common.Hash) (from common.Address, nodeids []common.Address, err error) { 206 chash := self.ethereum.BlockChain().CurrentBlock().Hash() 207 ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) 208 defer cancel() 209 opts := new(bind.CallOptsWithNumber) 210 opts.Context = ctx 211 if blockHash != nil { 212 opts.Hash = blockHash 213 } 214 215 if blockNumber != nil { 216 opts.Number = blockNumber 217 } 218 if blockNumber == nil && blockHash == nil { 219 opts.Hash = &chash 220 } 221 vo, err := self.anmap_0_0_1.BindInfo(opts, addr) 222 223 // anmap.sol bindInfo func has a problum , an/na return diff nodeids so query again 224 if err == nil && len(vo.Nids) == 1 && vo.From != addr { 225 vo, err = self.anmap_0_0_1.BindInfo(opts, vo.From) 226 } 227 228 from = vo.From 229 nodeids = vo.Nids 230 231 return 232 } 233 234 func (self *StatuteService) Bind(from, nodeAddr common.Address, sigHex string) (common.Hash, error) { 235 a := accounts.Account{Address: from} 236 w, err := self.accman.Find(a) 237 if err != nil { 238 return common.Hash{}, err 239 } 240 opts := &bind.TransactOpts{ 241 From: from, 242 Signer: func(signer types.Signer, address common.Address, tx *types.Transaction) (*types.Transaction, error) { 243 return w.SignTx(a, tx, params.ChainID()) 244 }, 245 } 246 //client *ethclient.Client 247 client, err := contracts.GetEthclientInstance() 248 if err != nil { 249 return common.Hash{}, err 250 } 251 //if params.ChiefTxNonce > 0 { 252 pnonce, perr := client.PendingNonceAt(context.Background(), from) 253 if perr != nil { 254 log.Debug("<<StatuteService_Bind>> === nonce_err", "err", perr) 255 } else { 256 log.Debug("<<StatuteService_Bind>> === nonce", "nonce", pnonce) 257 opts.Nonce = new(big.Int).SetUint64(pnonce) 258 } 259 260 r, s, v := sigSplit(sigHex) 261 tx, err := self.anmap_0_0_1.Bind(opts, nodeAddr, v, r, s) 262 log.Info("<<StatuteService.Bind>>", "err", err, "tx", tx) 263 if err != nil { 264 return common.HexToHash("0x"), err 265 } 266 return tx.Hash(), nil 267 } 268 269 func (self *StatuteService) Unbind(from, nodeAddr common.Address, sigHex string) (common.Hash, error) { 270 a := accounts.Account{Address: from} 271 w, err := self.accman.Find(a) 272 if err != nil { 273 log.Error("Unbindb find", "err", err) 274 } 275 opts := &bind.TransactOpts{ 276 From: from, 277 Signer: func(signer types.Signer, address common.Address, tx *types.Transaction) (*types.Transaction, error) { 278 return w.SignTx(a, tx, params.ChainID()) 279 }, 280 } 281 //client *ethclient.Client 282 client, err := contracts.GetEthclientInstance() 283 if err != nil { 284 return common.Hash{}, err 285 } 286 //if params.ChiefTxNonce > 0 { 287 pnonce, perr := client.PendingNonceAt(context.Background(), from) 288 if perr != nil { 289 log.Debug("<<StatuteService_Bind>> === nonce_err", "err", perr) 290 } else { 291 log.Debug("<<StatuteService_Bind>> === nonce", "nonce", pnonce) 292 opts.Nonce = new(big.Int).SetUint64(pnonce) 293 } 294 295 r, s, v := sigSplit(sigHex) 296 tx, err := self.anmap_0_0_1.UnbindBySig(opts, nodeAddr, v, r, s) 297 log.Info("<<StatuteService.Unbind>>", "err", err, "tx", tx) 298 if err != nil { 299 return common.HexToHash("0x"), err 300 } 301 return tx.Hash(), nil 302 } 303 304 func (self *StatuteService) getBalance(mbox params.Mbox) { 305 success := params.MBoxSuccess{Success: true} 306 addr := mbox.Params["addr"].(common.Address) 307 sdb, err := self.ethereum.BlockChain().State() 308 if err != nil { 309 log.Error("BlockChain().State()", "err", err) 310 } 311 success.Entity = map[string]interface{}{"addr": addr, "balance": sdb.GetBalance(addr)} 312 mbox.Rtn <- success 313 } 314 315 /* 316 args: 317 addr 318 hash : blockHash 319 */ 320 func (self *StatuteService) bindInfo(mbox params.Mbox) { 321 success := params.MBoxSuccess{Success: true} 322 var ( 323 addr common.Address 324 blockHash *common.Hash 325 blockNumber *big.Int 326 ) 327 addr = mbox.Params["addr"].(common.Address) 328 // hash and number can not nil 329 if h, ok := mbox.Params["hash"]; ok { 330 bh := h.(common.Hash) 331 blockHash = &bh 332 _block := self.ethereum.BlockChain().GetBlockByHash(*blockHash) 333 log.Debug("<<StatuteService_bindInfo>>", "hash", blockHash.Hex()) 334 if _block == nil { 335 blockHash = nil 336 } 337 } 338 if n, ok := mbox.Params["number"]; ok { 339 blockNumber = n.(*big.Int) 340 } 341 f, n, err := self.BindInfo(addr, blockNumber, blockHash) 342 if err != nil { 343 success.Success = false 344 success.Entity = err 345 } else { 346 success.Entity = map[string]interface{}{"from": f, "nodeids": n} 347 } 348 mbox.Rtn <- success 349 } 350 351 /* 352 args: 353 from 354 nodeid 355 sigHex 356 */ 357 func (self *StatuteService) bind(mbox params.Mbox) { 358 success := params.MBoxSuccess{Success: true} 359 var ( 360 from, nodeid common.Address 361 sigHex string 362 ) 363 from = mbox.Params["from"].(common.Address) 364 nodeid = mbox.Params["nodeid"].(common.Address) 365 sigHex = mbox.Params["sigHex"].(string) 366 log.Info("mbox.params", "from", from.Hex(), "nodeid", nodeid, "sigHex", sigHex) 367 txHash, err := self.Bind(from, nodeid, sigHex) 368 if err != nil { 369 success.Success = false 370 success.Entity = err 371 } else { 372 success.Entity = txHash.Hex() 373 } 374 mbox.Rtn <- success 375 } 376 377 /* 378 from common.Address, sigHex string 379 */ 380 func (self *StatuteService) pocDeposit(mbox params.Mbox) { 381 success := params.MBoxSuccess{Success: true} 382 var ( 383 from common.Address 384 sigHex string 385 err error 386 tx *types.Transaction 387 ) 388 defer func() { 389 if err != nil { 390 success.Success = false 391 success.Entity = err 392 } else { 393 success.Entity = tx.Hash().String() 394 } 395 mbox.Rtn <- success 396 }() 397 from = mbox.Params["from"].(common.Address) 398 sigHex = mbox.Params["sigHex"].(string) 399 log.Info("mbox.params", "from", from.Hex(), "sigHex", sigHex, "pocaddr", params.POCInfo()) 400 401 a := accounts.Account{Address: from} 402 w, err := self.accman.Find(a) 403 if err != nil { 404 return 405 } 406 //client *ethclient.Client 407 client, err := contracts.GetEthclientInstance() 408 if err != nil { 409 return 410 } 411 poc, err := chieflib.NewPOC_1_0_0(params.POCInfo(), client) 412 if err != nil { 413 return 414 } 415 //质押最小金额 416 min, err := poc.MinDepositAmount(nil) 417 if err != nil { 418 log.Error(fmt.Sprintf("query min deposit err %s,poc addr=%s", err, params.POCInfo().String())) 419 return 420 } 421 sdb, err := self.ethereum.BlockChain().State() 422 if err != nil { 423 return 424 } 425 balance := sdb.GetBalance(from) 426 if balance.Cmp(min) <= 0 { 427 err = fmt.Errorf("addr %s doesn't have enough balance, need=%s, have=%s", from.String(), min, balance) 428 } 429 opts := &bind.TransactOpts{ 430 From: from, 431 Signer: func(signer types.Signer, address common.Address, tx *types.Transaction) (*types.Transaction, error) { 432 return w.SignTx(a, tx, params.ChainID()) 433 }, 434 Value: min, 435 } 436 //if params.ChiefTxNonce > 0 { 437 pnonce, perr := client.PendingNonceAt(context.Background(), from) 438 if perr != nil { 439 log.Debug("<<StatuteService_PocDeposit>> === nonce_err", "err", perr) 440 } else { 441 log.Debug("<<StatuteService_PocDeposit>> === nonce", "nonce", pnonce) 442 opts.Nonce = new(big.Int).SetUint64(pnonce) 443 } 444 445 r, s, v := sigSplit(sigHex) 446 tx, err = poc.Deposit(opts, r, s, v) 447 log.Info("<<StatuteService.PocDeposit>>", "err", err, "tx", tx) 448 return 449 } 450 451 func (self *StatuteService) pocStartAndStopAndWithdrawAndWithdrawSurplus(mbox params.Mbox, method string) { 452 success := params.MBoxSuccess{Success: true} 453 var ( 454 from common.Address 455 nodeID common.Address 456 err error 457 tx *types.Transaction 458 ) 459 defer func() { 460 if err != nil { 461 success.Success = false 462 success.Entity = err 463 } else { 464 success.Entity = tx.Hash().String() 465 } 466 mbox.Rtn <- success 467 }() 468 from = mbox.Params["from"].(common.Address) 469 nodeID = mbox.Params["nodeid"].(common.Address) 470 log.Info("mbox.params", "from", from.Hex(), "nodeid", nodeID, "pocaddr", params.POCInfo()) 471 472 a := accounts.Account{Address: from} 473 w, err := self.accman.Find(a) 474 if err != nil { 475 return 476 } 477 opts := &bind.TransactOpts{ 478 From: from, 479 Signer: func(signer types.Signer, address common.Address, tx *types.Transaction) (*types.Transaction, error) { 480 return w.SignTx(a, tx, params.ChainID()) 481 }, 482 } 483 //client *ethclient.Client 484 client, err := contracts.GetEthclientInstance() 485 if err != nil { 486 return 487 } 488 //if params.ChiefTxNonce > 0 { 489 pnonce, perr := client.PendingNonceAt(context.Background(), from) 490 if perr != nil { 491 log.Debug("<<StatuteService_pocStartAndStopAndWithdrawAndWithdrawSurplus>> === nonce_err", "err", perr) 492 } else { 493 log.Debug("<<StatuteService_pocStartAndStopAndWithdrawAndWithdrawSurplus>> === nonce", "nonce", pnonce) 494 opts.Nonce = new(big.Int).SetUint64(pnonce) 495 } 496 switch method { 497 case params.POC_METHOD_START: 498 tx, err = self.poc_1.Start(opts, nodeID) 499 case params.POC_METHOD_STOP: 500 tx, err = self.poc_1.Stop(opts, nodeID) 501 case params.POC_METHOD_WITHDRAW: 502 tx, err = self.poc_1.Withdraw(opts, nodeID) 503 case params.POC_METHOD_WITHDRAW_SURPLUS: 504 tx, err = self.poc_1.WithdrawSurplus(opts, nodeID) 505 default: 506 panic(method) 507 } 508 log.Info("<<StatuteService>>", "method", method, "err", err, "tx", tx) 509 return 510 } 511 512 func (self *StatuteService) pocGetAll(mbox params.Mbox) { 513 var ( 514 blockNumber *big.Int = nil 515 blockHash *common.Hash = nil 516 ) 517 // hash and number can not nil 518 if h, ok := mbox.Params["hash"]; ok { 519 bh := h.(common.Hash) 520 blockHash = &bh 521 } 522 if n, ok := mbox.Params["number"]; ok { 523 blockNumber = n.(*big.Int) 524 } 525 log.Debug("=>TribeService.pocGetAll", "blockNumber", blockNumber, "blockHash", blockHash.Hex()) 526 success := params.MBoxSuccess{Success: true} 527 var ( 528 err error 529 ps *params.PocStatus 530 ) 531 defer func() { 532 if err != nil { 533 success.Success = false 534 success.Entity = err 535 } else { 536 success.Entity = ps 537 } 538 mbox.Rtn <- success 539 }() 540 ctx, cancel := context.WithTimeout(context.Background(), time.Second*60) 541 defer cancel() 542 opts := &bind.CallOptsWithNumber{} 543 opts.Context = ctx 544 opts.Hash = blockHash 545 minerList, amountList, blockList, ownerList, blackStatusList, err := self.poc_1.GetAll(opts) 546 if err != nil { 547 return 548 } 549 ps = ¶ms.PocStatus{ 550 MinerList: minerList, 551 AmountList: amountList, 552 BlockList: blockList, 553 OwnerList: ownerList, 554 BlackStatusList: blackStatusList, 555 } 556 log.Debug("<<StatuteService.pocGetAll>>") 557 return 558 } 559 560 /* 561 args: 562 from 563 nodeid 564 sigHex 565 */ 566 func (self *StatuteService) unbind(mbox params.Mbox) { 567 success := params.MBoxSuccess{Success: true} 568 var ( 569 from, nodeid common.Address 570 sigHex string 571 ) 572 from = mbox.Params["from"].(common.Address) 573 nodeid = mbox.Params["nodeid"].(common.Address) 574 sigHex = mbox.Params["sigHex"].(string) 575 log.Info("mbox.params", "from", from.Hex(), "nodeid", nodeid, "sigHex", sigHex) 576 txHash, err := self.Unbind(from, nodeid, sigHex) 577 if err != nil { 578 success.Success = false 579 success.Entity = err 580 } else { 581 success.Entity = txHash.Hex() 582 } 583 mbox.Rtn <- success 584 } 585 586 func (self *StatuteService) ExistAddress(addr common.Address) (*big.Int, error) { 587 log.Debug("<<StatuteService.ExistAddress>>") 588 select { 589 case <-params.InitMeshbox: 590 var ( 591 num = self.ethereum.BlockChain().CurrentHeader().Number 592 ctx = context.Background() 593 opts = new(bind.CallOptsWithNumber) 594 i *big.Int 595 ) 596 vsn, err := params.MeshboxVsn(num) 597 if err != nil { 598 return nil, err 599 } 600 ctx, cancel := context.WithTimeout(ctx, 3*time.Second) 601 defer cancel() 602 opts.Context = ctx 603 switch vsn { 604 case "0.0.1": 605 i, err = self.meshbox_0_0_1.ExistAddress(opts, addr) 606 case "0.0.2": 607 i, err = self.meshbox_0_0_2.ExistAddress(opts, addr) 608 } 609 log.Debug("<<StatuteService.ExistAddress>>", "r", i, "err", err) 610 return i, err 611 default: 612 return nil, errors.New("wait init") 613 } 614 } 615 616 func (self *StatuteService) GetMeshboxList() ([]common.Address, error) { 617 log.Debug("<<StatuteService.GetMeshboxList>>") 618 select { 619 case <-params.InitMeshbox: 620 var ( 621 num = self.ethereum.BlockChain().CurrentHeader().Number 622 ctx = context.Background() 623 opts = new(bind.CallOptsWithNumber) 624 mbs []common.Address 625 ) 626 vsn, err := params.MeshboxVsn(num) 627 if err != nil { 628 return nil, err 629 } 630 ctx, cancel := context.WithTimeout(ctx, 3*time.Second) 631 defer cancel() 632 opts.Context = ctx 633 switch vsn { 634 case "0.0.2": 635 mbs, err = self.meshbox_0_0_2.GetMeshboxList(opts) 636 } 637 log.Debug("<<StatuteService.GetMeshboxList>>", "err", err) 638 return mbs, err 639 default: 640 return nil, errors.New("wait init") 641 } 642 } 643 644 func (self *StatuteService) existAddress(mbox params.Mbox) { 645 success := params.MBoxSuccess{Success: true} 646 var addr common.Address 647 addr = mbox.Params["addr"].(common.Address) 648 log.Debug("mbox.params", "addr", addr.Hex()) 649 i, err := self.ExistAddress(addr) 650 if err != nil { 651 success.Success = false 652 success.Entity = err 653 } else { 654 success.Entity = i.Int64() 655 } 656 mbox.Rtn <- success 657 } 658 659 func (self *StatuteService) loop() { 660 for { 661 select { 662 case <-self.quit: 663 break 664 case mbox := <-params.StatuteService: 665 switch mbox.Method { 666 case "getBalance": 667 self.getBalance(mbox) 668 case "bindInfo": 669 self.bindInfo(mbox) 670 case "bind": 671 self.bind(mbox) 672 case "unbind": 673 self.unbind(mbox) 674 case "existAddress": 675 self.existAddress(mbox) 676 case params.POC_METHOD_DEPOSIT: 677 self.pocDeposit(mbox) 678 case params.POC_METHOD_START: 679 fallthrough 680 case params.POC_METHOD_STOP: 681 fallthrough 682 case params.POC_METHOD_WITHDRAW: 683 fallthrough 684 case params.POC_METHOD_WITHDRAW_SURPLUS: 685 self.pocStartAndStopAndWithdrawAndWithdrawSurplus(mbox, mbox.Method) 686 case params.POC_METHOD_GET_STATUS: 687 self.pocGetAll(mbox) 688 } 689 } 690 } 691 }