github.com/turingchain2020/turingchain@v1.1.21/wallet/wallet_proc.go (about) 1 // Copyright Turing Corp. 2018 All Rights Reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package wallet 6 7 import ( 8 "encoding/hex" 9 "fmt" 10 "io/ioutil" 11 "os" 12 "strings" 13 "sync/atomic" 14 "time" 15 "unicode" 16 17 "github.com/turingchain2020/turingchain/account" 18 "github.com/turingchain2020/turingchain/common" 19 "github.com/turingchain2020/turingchain/common/address" 20 "github.com/turingchain2020/turingchain/common/crypto" 21 dbm "github.com/turingchain2020/turingchain/common/db" 22 cty "github.com/turingchain2020/turingchain/system/dapp/coins/types" 23 "github.com/turingchain2020/turingchain/types" 24 "github.com/turingchain2020/turingchain/wallet/bipwallet" 25 wcom "github.com/turingchain2020/turingchain/wallet/common" 26 "github.com/golang/protobuf/proto" 27 ) 28 29 // ProcSignRawTx 用钱包对交易进行签名 30 //input: 31 //type ReqSignRawTx struct { 32 // Addr string 33 // Privkey string 34 // TxHex string 35 // Expire string 36 //} 37 //output: 38 //string 39 //签名交易 40 func (wallet *Wallet) ProcSignRawTx(unsigned *types.ReqSignRawTx) (string, error) { 41 wallet.mtx.Lock() 42 defer wallet.mtx.Unlock() 43 index := unsigned.Index 44 45 //Privacy交易功能,需要在隐私plugin里面检查,而不是所有交易签名都检查,在隐私启动scan时候会导致其他交易签名失败,同时这里在scaning时候, 46 //需要返回一个错误,而不是nil 47 //if ok, err := wallet.IsRescanUtxosFlagScaning(); ok || err != nil { 48 // return "", err types.ErrNotSupport 49 //} 50 51 var key crypto.PrivKey 52 if unsigned.GetAddr() != "" { 53 ok, err := wallet.checkWalletStatus() 54 if !ok { 55 return "", err 56 } 57 key, err = wallet.getPrivKeyByAddr(unsigned.GetAddr()) 58 if err != nil { 59 return "", err 60 } 61 } else if unsigned.GetPrivkey() != "" { 62 keyByte, err := common.FromHex(unsigned.GetPrivkey()) 63 if err != nil { 64 return "", err 65 } 66 if len(keyByte) == 0 { 67 return "", types.ErrPrivateKeyLen 68 } 69 cr, err := crypto.New(types.GetSignName("", wallet.SignType)) 70 if err != nil { 71 return "", err 72 } 73 key, err = cr.PrivKeyFromBytes(keyByte) 74 if err != nil { 75 return "", err 76 } 77 } else { 78 return "", types.ErrNoPrivKeyOrAddr 79 } 80 81 txByteData, err := common.FromHex(unsigned.GetTxHex()) 82 if err != nil { 83 return "", err 84 } 85 var tx types.Transaction 86 err = types.Decode(txByteData, &tx) 87 if err != nil { 88 return "", err 89 } 90 91 if unsigned.NewToAddr != "" { 92 tx.To = unsigned.NewToAddr 93 } 94 if unsigned.Fee != 0 { 95 tx.Fee = unsigned.Fee 96 } else { 97 //get proper fee if not set 98 proper, err := wallet.api.GetProperFee(nil) 99 if err != nil { 100 return "", err 101 } 102 fee, err := tx.GetRealFee(proper.ProperFee) 103 if err != nil { 104 return "", err 105 } 106 tx.Fee = fee 107 } 108 109 expire, err := types.ParseExpire(unsigned.GetExpire()) 110 if err != nil { 111 return "", err 112 } 113 types.AssertConfig(wallet.client) 114 cfg := wallet.client.GetConfig() 115 tx.SetExpire(cfg, time.Duration(expire)) 116 if policy, ok := wcom.PolicyContainer[string(cfg.GetParaExec(tx.Execer))]; ok { 117 // 尝试让策略自己去完成签名 118 needSysSign, signtx, err := policy.SignTransaction(key, unsigned) 119 if !needSysSign { 120 return signtx, err 121 } 122 } 123 124 group, err := tx.GetTxGroup() 125 if err != nil { 126 return "", err 127 } 128 if group == nil { 129 tx.Sign(int32(wallet.SignType), key) 130 txHex := types.Encode(&tx) 131 signedTx := hex.EncodeToString(txHex) 132 return signedTx, nil 133 } 134 if int(index) > len(group.GetTxs()) { 135 return "", types.ErrIndex 136 } 137 if index <= 0 { 138 //设置过期需要重构 139 group.SetExpire(cfg, 0, time.Duration(expire)) 140 group.RebuiltGroup() 141 for i := range group.Txs { 142 err := group.SignN(i, int32(wallet.SignType), key) 143 if err != nil { 144 return "", err 145 } 146 } 147 grouptx := group.Tx() 148 txHex := types.Encode(grouptx) 149 signedTx := hex.EncodeToString(txHex) 150 return signedTx, nil 151 } 152 index-- 153 err = group.SignN(int(index), int32(wallet.SignType), key) 154 if err != nil { 155 return "", err 156 } 157 grouptx := group.Tx() 158 txHex := types.Encode(grouptx) 159 signedTx := hex.EncodeToString(txHex) 160 return signedTx, nil 161 } 162 163 // ProcGetAccount 通过地址标签获取账户地址 164 func (wallet *Wallet) ProcGetAccount(req *types.ReqGetAccount) (*types.WalletAccount, error) { 165 wallet.mtx.Lock() 166 defer wallet.mtx.Unlock() 167 accStore, err := wallet.walletStore.GetAccountByLabel(req.GetLabel()) 168 if err != nil { 169 return nil, err 170 } 171 172 accs, err := wallet.accountdb.LoadAccounts(wallet.api, []string{accStore.GetAddr()}) 173 if err != nil { 174 return nil, err 175 } 176 return &types.WalletAccount{Label: accStore.GetLabel(), Acc: accs[0]}, nil 177 178 } 179 180 // ProcGetAccountList 获取钱包账号列表 181 //output: 182 //type WalletAccounts struct { 183 // Wallets []*WalletAccount 184 //type WalletAccount struct { 185 // Acc *Account 186 // Label string 187 //获取钱包的地址列表 188 func (wallet *Wallet) ProcGetAccountList(req *types.ReqAccountList) (*types.WalletAccounts, error) { 189 wallet.mtx.Lock() 190 defer wallet.mtx.Unlock() 191 192 //通过Account前缀查找获取钱包中的所有账户信息 193 WalletAccStores, err := wallet.walletStore.GetAccountByPrefix("Account") 194 if err != nil || len(WalletAccStores) == 0 { 195 walletlog.Info("ProcGetAccountList", "GetAccountByPrefix:err", err) 196 return nil, err 197 } 198 if req.WithoutBalance { 199 return makeAccountWithoutBalance(WalletAccStores) 200 } 201 202 addrs := make([]string, len(WalletAccStores)) 203 for index, AccStore := range WalletAccStores { 204 if len(AccStore.Addr) != 0 { 205 addrs[index] = AccStore.Addr 206 } 207 } 208 //获取所有地址对应的账户详细信息从account模块 209 accounts, err := wallet.accountdb.LoadAccounts(wallet.api, addrs) 210 if err != nil || len(accounts) == 0 { 211 walletlog.Error("ProcGetAccountList", "LoadAccounts:err", err) 212 return nil, err 213 } 214 215 //异常打印信息 216 if len(WalletAccStores) != len(accounts) { 217 walletlog.Error("ProcGetAccountList err!", "AccStores)", len(WalletAccStores), "accounts", len(accounts)) 218 } 219 220 var WalletAccounts types.WalletAccounts 221 WalletAccounts.Wallets = make([]*types.WalletAccount, len(WalletAccStores)) 222 223 for index, Account := range accounts { 224 var WalletAccount types.WalletAccount 225 //此账户还没有参与交易所在account模块没有记录 226 if len(Account.Addr) == 0 { 227 Account.Addr = addrs[index] 228 } 229 WalletAccount.Acc = Account 230 WalletAccount.Label = WalletAccStores[index].GetLabel() 231 WalletAccounts.Wallets[index] = &WalletAccount 232 } 233 return &WalletAccounts, nil 234 } 235 236 func makeAccountWithoutBalance(accountStores []*types.WalletAccountStore) (*types.WalletAccounts, error) { 237 var WalletAccounts types.WalletAccounts 238 WalletAccounts.Wallets = make([]*types.WalletAccount, len(accountStores)) 239 240 for index, account := range accountStores { 241 var WalletAccount types.WalletAccount 242 //此账户还没有参与交易所在account模块没有记录 243 if len(account.Addr) == 0 { 244 continue 245 } 246 WalletAccount.Acc = &types.Account{Addr: account.Addr} 247 WalletAccount.Label = account.GetLabel() 248 WalletAccounts.Wallets[index] = &WalletAccount 249 } 250 return &WalletAccounts, nil 251 } 252 253 // ProcCreateNewAccount 处理创建新账号 254 //input: 255 //type ReqNewAccount struct { 256 // Label string 257 //output: 258 //type WalletAccount struct { 259 // Acc *Account 260 // Label string 261 //type Account struct { 262 // Currency int32 263 // Balance int64 264 // Frozen int64 265 // Addr string 266 //创建一个新的账户 267 func (wallet *Wallet) ProcCreateNewAccount(Label *types.ReqNewAccount) (*types.WalletAccount, error) { 268 wallet.mtx.Lock() 269 defer wallet.mtx.Unlock() 270 271 ok, err := wallet.checkWalletStatus() 272 if !ok { 273 return nil, err 274 } 275 276 if Label == nil || len(Label.GetLabel()) == 0 { 277 walletlog.Error("ProcCreateNewAccount Label is nil") 278 return nil, types.ErrInvalidParam 279 } 280 281 //首先校验label是否已被使用 282 WalletAccStores, err := wallet.walletStore.GetAccountByLabel(Label.GetLabel()) 283 if WalletAccStores != nil && err == nil { 284 walletlog.Error("ProcCreateNewAccount Label is exist in wallet!") 285 return nil, types.ErrLabelHasUsed 286 } 287 288 var Account types.Account 289 var walletAccount types.WalletAccount 290 var WalletAccStore types.WalletAccountStore 291 var addr string 292 var privkeybyte []byte 293 294 cointype := wallet.GetCoinType() 295 //通过seed获取私钥, 首先通过钱包密码解锁seed然后通过seed生成私钥 296 seed, err := wallet.getSeed(wallet.Password) 297 if err != nil { 298 walletlog.Error("ProcCreateNewAccount", "getSeed err", err) 299 return nil, err 300 } 301 302 for { 303 privkeyhex, err := GetPrivkeyBySeed(wallet.walletStore.GetDB(), seed, 0, wallet.SignType, wallet.CoinType) 304 if err != nil { 305 walletlog.Error("ProcCreateNewAccount", "GetPrivkeyBySeed err", err) 306 return nil, err 307 } 308 privkeybyte, err = common.FromHex(privkeyhex) 309 if err != nil || len(privkeybyte) == 0 { 310 walletlog.Error("ProcCreateNewAccount", "FromHex err", err) 311 return nil, err 312 } 313 314 pub, err := bipwallet.PrivkeyToPub(cointype, uint32(wallet.SignType), privkeybyte) 315 if err != nil { 316 seedlog.Error("ProcCreateNewAccount PrivkeyToPub", "err", err) 317 return nil, types.ErrPrivkeyToPub 318 } 319 addr, err = bipwallet.PubToAddress(pub) 320 if err != nil { 321 seedlog.Error("ProcCreateNewAccount PubToAddress", "err", err) 322 return nil, types.ErrPrivkeyToPub 323 } 324 //通过新生成的账户地址查询钱包数据库,如果查询返回的账户信息是空, 325 //说明新生成的账户没有被使用,否则继续使用下一个index生成私钥对 326 account, err := wallet.walletStore.GetAccountByAddr(addr) 327 if account == nil || err != nil { 328 break 329 } 330 } 331 332 Account.Addr = addr 333 Account.Currency = 0 334 Account.Balance = 0 335 Account.Frozen = 0 336 337 walletAccount.Acc = &Account 338 walletAccount.Label = Label.GetLabel() 339 340 //使用钱包的password对私钥加密 aes cbc 341 Encrypted := wcom.CBCEncrypterPrivkey([]byte(wallet.Password), privkeybyte) 342 WalletAccStore.Privkey = common.ToHex(Encrypted) 343 WalletAccStore.Label = Label.GetLabel() 344 WalletAccStore.Addr = addr 345 346 //存储账户信息到wallet数据库中 347 err = wallet.walletStore.SetWalletAccount(false, Account.Addr, &WalletAccStore) 348 if err != nil { 349 return nil, err 350 } 351 352 //获取地址对应的账户信息从account模块 353 addrs := make([]string, 1) 354 addrs[0] = addr 355 accounts, err := wallet.accountdb.LoadAccounts(wallet.api, addrs) 356 if err != nil { 357 walletlog.Error("ProcCreateNewAccount", "LoadAccounts err", err) 358 return nil, err 359 } 360 // 本账户是首次创建 361 if len(accounts[0].Addr) == 0 { 362 accounts[0].Addr = addr 363 } 364 walletAccount.Acc = accounts[0] 365 366 //从blockchain模块同步Account.Addr对应的所有交易详细信息 367 for _, policy := range wcom.PolicyContainer { 368 policy.OnCreateNewAccount(walletAccount.Acc) 369 } 370 371 return &walletAccount, nil 372 } 373 374 // ProcWalletTxList 处理获取钱包交易列表 375 //input: 376 //type ReqWalletTransactionList struct { 377 // FromTx []byte 378 // Count int32 379 //output: 380 //type WalletTxDetails struct { 381 // TxDetails []*WalletTxDetail 382 //type WalletTxDetail struct { 383 // Tx *Transaction 384 // Receipt *ReceiptData 385 // Height int64 386 // Index int64 387 //获取所有钱包的交易记录 388 func (wallet *Wallet) ProcWalletTxList(TxList *types.ReqWalletTransactionList) (*types.WalletTxDetails, error) { 389 wallet.mtx.Lock() 390 defer wallet.mtx.Unlock() 391 392 if TxList == nil { 393 walletlog.Error("ProcWalletTxList TxList is nil!") 394 return nil, types.ErrInvalidParam 395 } 396 if TxList.GetDirection() != 0 && TxList.GetDirection() != 1 { 397 walletlog.Error("ProcWalletTxList Direction err!") 398 return nil, types.ErrInvalidParam 399 } 400 //默认取10笔交易数据 401 if TxList.Count == 0 { 402 TxList.Count = 10 403 } 404 if int64(TxList.Count) > types.MaxBlockCountPerTime { 405 return nil, types.ErrMaxCountPerTime 406 } 407 408 WalletTxDetails, err := wallet.walletStore.GetTxDetailByIter(TxList) 409 if err != nil { 410 walletlog.Error("ProcWalletTxList", "GetTxDetailByIter err", err) 411 return nil, err 412 } 413 return WalletTxDetails, nil 414 } 415 416 // ProcImportPrivKey 处理导入私钥 417 //input: 418 //type ReqWalletImportPrivKey struct { 419 // Privkey string 420 // Label string 421 //output: 422 //type WalletAccount struct { 423 // Acc *Account 424 // Label string 425 //导入私钥,并且同时会导入交易 426 func (wallet *Wallet) ProcImportPrivKey(PrivKey *types.ReqWalletImportPrivkey) (*types.WalletAccount, error) { 427 wallet.mtx.Lock() 428 defer wallet.mtx.Unlock() 429 walletaccount, err := wallet.procImportPrivKey(PrivKey) 430 return walletaccount, err 431 } 432 433 func (wallet *Wallet) procImportPrivKey(PrivKey *types.ReqWalletImportPrivkey) (*types.WalletAccount, error) { 434 ok, err := wallet.checkWalletStatus() 435 if !ok { 436 return nil, err 437 } 438 439 if PrivKey == nil || len(PrivKey.GetLabel()) == 0 || len(PrivKey.GetPrivkey()) == 0 { 440 walletlog.Error("ProcImportPrivKey input parameter is nil!") 441 return nil, types.ErrInvalidParam 442 } 443 444 //校验label是否已经被使用 445 Account, err := wallet.walletStore.GetAccountByLabel(PrivKey.GetLabel()) 446 if Account != nil && err == nil { 447 walletlog.Error("ProcImportPrivKey Label is exist in wallet!") 448 return nil, types.ErrLabelHasUsed 449 } 450 451 cointype := wallet.GetCoinType() 452 453 privkeybyte, err := common.FromHex(PrivKey.Privkey) 454 if err != nil || len(privkeybyte) == 0 { 455 walletlog.Error("ProcImportPrivKey", "FromHex err", err) 456 return nil, types.ErrFromHex 457 } 458 459 pub, err := bipwallet.PrivkeyToPub(cointype, uint32(wallet.SignType), privkeybyte) 460 if err != nil { 461 seedlog.Error("ProcImportPrivKey PrivkeyToPub", "err", err) 462 return nil, types.ErrPrivkeyToPub 463 } 464 465 addr, err := bipwallet.PubToAddress(pub) 466 if err != nil { 467 seedlog.Error("ProcImportPrivKey PrivkeyToPub", "err", err) 468 return nil, types.ErrPrivkeyToPub 469 } 470 471 //对私钥加密 472 Encryptered := wcom.CBCEncrypterPrivkey([]byte(wallet.Password), privkeybyte) 473 Encrypteredstr := common.ToHex(Encryptered) 474 //校验PrivKey对应的addr是否已经存在钱包中 475 Account, err = wallet.walletStore.GetAccountByAddr(addr) 476 if Account != nil && err == nil { 477 if Account.Privkey == Encrypteredstr { 478 walletlog.Error("ProcImportPrivKey Privkey is exist in wallet!") 479 return nil, types.ErrPrivkeyExist 480 } 481 walletlog.Error("ProcImportPrivKey!", "Account.Privkey", Account.Privkey, "input Privkey", PrivKey.Privkey) 482 return nil, types.ErrPrivkey 483 } 484 485 var walletaccount types.WalletAccount 486 var WalletAccStore types.WalletAccountStore 487 WalletAccStore.Privkey = Encrypteredstr //存储加密后的私钥 488 WalletAccStore.Label = PrivKey.GetLabel() 489 WalletAccStore.Addr = addr 490 //存储Addr:label+privkey+addr到数据库 491 err = wallet.walletStore.SetWalletAccount(false, addr, &WalletAccStore) 492 if err != nil { 493 walletlog.Error("ProcImportPrivKey", "SetWalletAccount err", err) 494 return nil, err 495 } 496 497 //获取地址对应的账户信息从account模块 498 addrs := make([]string, 1) 499 addrs[0] = addr 500 accounts, err := wallet.accountdb.LoadAccounts(wallet.api, addrs) 501 if err != nil { 502 walletlog.Error("ProcImportPrivKey", "LoadAccounts err", err) 503 return nil, err 504 } 505 // 本账户是首次创建 506 if len(accounts[0].Addr) == 0 { 507 accounts[0].Addr = addr 508 } 509 walletaccount.Acc = accounts[0] 510 walletaccount.Label = PrivKey.Label 511 512 for _, policy := range wcom.PolicyContainer { 513 policy.OnImportPrivateKey(accounts[0]) 514 } 515 return &walletaccount, nil 516 } 517 518 // ProcSendToAddress 响应发送到地址 519 //input: 520 //type ReqWalletSendToAddress struct { 521 // From string 522 // To string 523 // Amount int64 524 // Note string 525 //output: 526 //type ReplyHash struct { 527 // Hashe []byte 528 //发送一笔交易给对方地址,返回交易hash 529 func (wallet *Wallet) ProcSendToAddress(SendToAddress *types.ReqWalletSendToAddress) (*types.ReplyHash, error) { 530 wallet.mtx.Lock() 531 defer wallet.mtx.Unlock() 532 533 if SendToAddress == nil { 534 walletlog.Error("ProcSendToAddress input para is nil") 535 return nil, types.ErrInvalidParam 536 } 537 if len(SendToAddress.From) == 0 || len(SendToAddress.To) == 0 { 538 walletlog.Error("ProcSendToAddress input para From or To is nil!") 539 return nil, types.ErrInvalidParam 540 } 541 542 ok, err := wallet.isTransfer(SendToAddress.GetTo()) 543 if !ok { 544 return nil, err 545 } 546 547 //获取from账户的余额从account模块,校验余额是否充足 548 addrs := make([]string, 1) 549 addrs[0] = SendToAddress.GetFrom() 550 var accounts []*types.Account 551 var tokenAccounts []*types.Account 552 accounts, err = wallet.accountdb.LoadAccounts(wallet.api, addrs) 553 if err != nil || len(accounts) == 0 { 554 walletlog.Error("ProcSendToAddress", "LoadAccounts err", err) 555 return nil, err 556 } 557 Balance := accounts[0].Balance 558 amount := SendToAddress.GetAmount() 559 //amount必须大于等于0 560 if amount < 0 { 561 return nil, types.ErrAmount 562 } 563 if !SendToAddress.IsToken { 564 if Balance-amount < wallet.FeeAmount { 565 return nil, types.ErrInsufficientBalance 566 } 567 } else { 568 //如果是token转账,一方面需要保证coin的余额满足fee,另一方面则需要保证token的余额满足转账操作 569 if Balance < wallet.FeeAmount { 570 return nil, types.ErrInsufficientBalance 571 } 572 if nil == wallet.accTokenMap[SendToAddress.TokenSymbol] { 573 tokenAccDB, err := account.NewAccountDB(wallet.api.GetConfig(), "token", SendToAddress.TokenSymbol, nil) 574 if err != nil { 575 return nil, err 576 } 577 wallet.accTokenMap[SendToAddress.TokenSymbol] = tokenAccDB 578 } 579 tokenAccDB := wallet.accTokenMap[SendToAddress.TokenSymbol] 580 tokenAccounts, err = tokenAccDB.LoadAccounts(wallet.api, addrs) 581 if err != nil || len(tokenAccounts) == 0 { 582 walletlog.Error("ProcSendToAddress", "Load Token Accounts err", err) 583 return nil, err 584 } 585 tokenBalance := tokenAccounts[0].Balance 586 if tokenBalance < amount { 587 return nil, types.ErrInsufficientTokenBal 588 } 589 } 590 addrto := SendToAddress.GetTo() 591 note := SendToAddress.GetNote() 592 priv, err := wallet.getPrivKeyByAddr(addrs[0]) 593 if err != nil { 594 return nil, err 595 } 596 return wallet.sendToAddress(priv, addrto, amount, note, SendToAddress.IsToken, SendToAddress.TokenSymbol) 597 } 598 599 // ProcWalletSetFee 处理设置手续费 600 //type ReqWalletSetFee struct { 601 // Amount int64 602 //设置钱包默认的手续费 603 func (wallet *Wallet) ProcWalletSetFee(WalletSetFee *types.ReqWalletSetFee) error { 604 if WalletSetFee.Amount < wallet.minFee { 605 walletlog.Error("ProcWalletSetFee err!", "Amount", WalletSetFee.Amount, "MinFee", wallet.minFee) 606 return types.ErrInvalidParam 607 } 608 err := wallet.walletStore.SetFeeAmount(WalletSetFee.Amount) 609 if err == nil { 610 walletlog.Debug("ProcWalletSetFee success!") 611 wallet.mtx.Lock() 612 wallet.FeeAmount = WalletSetFee.Amount 613 wallet.mtx.Unlock() 614 } 615 return err 616 } 617 618 // ProcWalletSetLabel 处理设置账号标签 619 //input: 620 //type ReqWalletSetLabel struct { 621 // Addr string 622 // Label string 623 //output: 624 //type WalletAccount struct { 625 // Acc *Account 626 // Label string 627 //设置某个账户的标签 628 func (wallet *Wallet) ProcWalletSetLabel(SetLabel *types.ReqWalletSetLabel) (*types.WalletAccount, error) { 629 wallet.mtx.Lock() 630 defer wallet.mtx.Unlock() 631 632 if SetLabel == nil || len(SetLabel.Addr) == 0 || len(SetLabel.Label) == 0 { 633 walletlog.Error("ProcWalletSetLabel input parameter is nil!") 634 return nil, types.ErrInvalidParam 635 } 636 //校验label是否已经被使用 637 Account, err := wallet.walletStore.GetAccountByLabel(SetLabel.GetLabel()) 638 if Account != nil && err == nil { 639 walletlog.Error("ProcWalletSetLabel Label is exist in wallet!") 640 return nil, types.ErrLabelHasUsed 641 } 642 //获取地址对应的账户信息从钱包中,然后修改label 643 Account, err = wallet.walletStore.GetAccountByAddr(SetLabel.Addr) 644 if err == nil && Account != nil { 645 oldLabel := Account.Label 646 Account.Label = SetLabel.GetLabel() 647 err := wallet.walletStore.SetWalletAccount(true, SetLabel.Addr, Account) 648 if err == nil { 649 //新的label设置成功之后需要删除旧的label在db的数据 650 wallet.walletStore.DelAccountByLabel(oldLabel) 651 652 //获取地址对应的账户详细信息从account模块 653 addrs := make([]string, 1) 654 addrs[0] = SetLabel.Addr 655 accounts, err := wallet.accountdb.LoadAccounts(wallet.api, addrs) 656 if err != nil || len(accounts) == 0 { 657 walletlog.Error("ProcWalletSetLabel", "LoadAccounts err", err) 658 return nil, err 659 } 660 var walletAccount types.WalletAccount 661 walletAccount.Acc = accounts[0] 662 walletAccount.Label = SetLabel.GetLabel() 663 return &walletAccount, err 664 } 665 } 666 return nil, err 667 } 668 669 // ProcMergeBalance 处理 670 //input: 671 //type ReqWalletMergeBalance struct { 672 // To string 673 //output: 674 //type ReplyHashes struct { 675 // Hashes [][]byte 676 //合并所有的balance 到一个地址 677 func (wallet *Wallet) ProcMergeBalance(MergeBalance *types.ReqWalletMergeBalance) (*types.ReplyHashes, error) { 678 wallet.mtx.Lock() 679 defer wallet.mtx.Unlock() 680 681 ok, err := wallet.checkWalletStatus() 682 if !ok { 683 return nil, err 684 } 685 686 if len(MergeBalance.GetTo()) == 0 { 687 walletlog.Error("ProcMergeBalance input para is nil!") 688 return nil, types.ErrInvalidParam 689 } 690 691 //获取钱包上的所有账户信息 692 WalletAccStores, err := wallet.walletStore.GetAccountByPrefix("Account") 693 if err != nil || len(WalletAccStores) == 0 { 694 walletlog.Error("ProcMergeBalance", "GetAccountByPrefix err", err) 695 return nil, err 696 } 697 698 addrs := make([]string, len(WalletAccStores)) 699 for index, AccStore := range WalletAccStores { 700 if len(AccStore.Addr) != 0 { 701 addrs[index] = AccStore.Addr 702 } 703 } 704 //获取所有地址对应的账户信息从account模块 705 accounts, err := wallet.accountdb.LoadAccounts(wallet.api, addrs) 706 if err != nil || len(accounts) == 0 { 707 walletlog.Error("ProcMergeBalance", "LoadAccounts err", err) 708 return nil, err 709 } 710 711 //异常信息记录 712 if len(WalletAccStores) != len(accounts) { 713 walletlog.Error("ProcMergeBalance", "AccStores", len(WalletAccStores), "accounts", len(accounts)) 714 } 715 //通过privkey生成一个pubkey然后换算成对应的addr 716 cr, err := crypto.New(types.GetSignName("", wallet.SignType)) 717 if err != nil { 718 walletlog.Error("ProcMergeBalance", "err", err) 719 return nil, err 720 } 721 722 addrto := MergeBalance.GetTo() 723 note := "MergeBalance" 724 725 var ReplyHashes types.ReplyHashes 726 727 types.AssertConfig(wallet.client) 728 cfg := wallet.client.GetConfig() 729 for index, Account := range accounts { 730 Privkey := WalletAccStores[index].Privkey 731 //解密存储的私钥 732 prikeybyte, err := common.FromHex(Privkey) 733 if err != nil || len(prikeybyte) == 0 { 734 walletlog.Error("ProcMergeBalance", "FromHex err", err, "index", index) 735 continue 736 } 737 738 privkey := wcom.CBCDecrypterPrivkey([]byte(wallet.Password), prikeybyte) 739 priv, err := cr.PrivKeyFromBytes(privkey) 740 if err != nil { 741 walletlog.Error("ProcMergeBalance", "PrivKeyFromBytes err", err, "index", index) 742 continue 743 } 744 //过滤掉to地址 745 if Account.Addr == addrto { 746 continue 747 } 748 //获取账户的余额,过滤掉余额不足的地址 749 amount := Account.GetBalance() 750 if amount < wallet.FeeAmount { 751 continue 752 } 753 amount = amount - wallet.FeeAmount 754 v := &cty.CoinsAction_Transfer{ 755 Transfer: &types.AssetsTransfer{Amount: amount, Note: []byte(note)}, 756 } 757 if cfg.IsPara() { 758 v.Transfer.To = MergeBalance.GetTo() 759 } 760 transfer := &cty.CoinsAction{Value: v, Ty: cty.CoinsActionTransfer} 761 //初始化随机数 762 exec := []byte("coins") 763 toAddr := addrto 764 if cfg.IsPara() { 765 exec = []byte(cfg.GetTitle() + "coins") 766 toAddr = address.ExecAddress(string(exec)) 767 } 768 tx := &types.Transaction{Execer: exec, Payload: types.Encode(transfer), Fee: wallet.FeeAmount, To: toAddr, Nonce: wallet.random.Int63()} 769 tx.ChainID = cfg.GetChainID() 770 771 tx.SetExpire(cfg, time.Second*120) 772 tx.Sign(int32(wallet.SignType), priv) 773 //walletlog.Info("ProcMergeBalance", "tx.Nonce", tx.Nonce, "tx", tx, "index", index) 774 775 //发送交易信息给mempool模块 776 msg := wallet.client.NewMessage("mempool", types.EventTx, tx) 777 err = wallet.client.Send(msg, true) 778 if err != nil { 779 walletlog.Error("ProcMergeBalance", "Send tx err", err, "index", index) 780 continue 781 } 782 resp, err := wallet.client.Wait(msg) 783 if err != nil { 784 walletlog.Error("ProcMergeBalance", "Send tx err", err, "index", index) 785 continue 786 } 787 //如果交易在mempool校验失败,不记录此交易 788 reply := resp.GetData().(*types.Reply) 789 if !reply.GetIsOk() { 790 walletlog.Error("ProcMergeBalance", "Send tx err", string(reply.GetMsg()), "index", index) 791 continue 792 } 793 ReplyHashes.Hashes = append(ReplyHashes.Hashes, tx.Hash()) 794 } 795 return &ReplyHashes, nil 796 } 797 798 // ProcWalletSetPasswd 处理钱包的保存密码 799 //input: 800 //type ReqWalletSetPasswd struct { 801 // Oldpass string 802 // Newpass string 803 //设置或者修改密码 804 func (wallet *Wallet) ProcWalletSetPasswd(Passwd *types.ReqWalletSetPasswd) error { 805 wallet.mtx.Lock() 806 defer wallet.mtx.Unlock() 807 808 isok, err := wallet.checkWalletStatus() 809 if !isok && err == types.ErrSaveSeedFirst { 810 return err 811 } 812 // 新密码合法性校验 813 if !isValidPassWord(Passwd.NewPass) { 814 return types.ErrInvalidPassWord 815 } 816 //保存钱包的锁状态,需要暂时的解锁,函数退出时再恢复回去 817 tempislock := atomic.LoadInt32(&wallet.isWalletLocked) 818 //wallet.isWalletLocked = false 819 atomic.CompareAndSwapInt32(&wallet.isWalletLocked, 1, 0) 820 821 defer func() { 822 //wallet.isWalletLocked = tempislock 823 atomic.CompareAndSwapInt32(&wallet.isWalletLocked, 0, tempislock) 824 }() 825 826 // 钱包已经加密需要验证oldpass的正确性 827 if len(wallet.Password) == 0 && wallet.EncryptFlag == 1 { 828 isok := wallet.walletStore.VerifyPasswordHash(Passwd.OldPass) 829 if !isok { 830 walletlog.Error("ProcWalletSetPasswd Verify Oldpasswd fail!") 831 return types.ErrVerifyOldpasswdFail 832 } 833 } 834 835 if len(wallet.Password) != 0 && Passwd.OldPass != wallet.Password { 836 walletlog.Error("ProcWalletSetPasswd Oldpass err!") 837 return types.ErrVerifyOldpasswdFail 838 } 839 840 //使用新的密码生成passwdhash用于下次密码的验证 841 newBatch := wallet.walletStore.NewBatch(true) 842 err = wallet.walletStore.SetPasswordHash(Passwd.NewPass, newBatch) 843 if err != nil { 844 walletlog.Error("ProcWalletSetPasswd", "SetPasswordHash err", err) 845 return err 846 } 847 //设置钱包加密标志位 848 err = wallet.walletStore.SetEncryptionFlag(newBatch) 849 if err != nil { 850 walletlog.Error("ProcWalletSetPasswd", "SetEncryptionFlag err", err) 851 return err 852 } 853 //使用old密码解密seed然后用新的钱包密码重新加密seed 854 seed, err := wallet.getSeed(Passwd.OldPass) 855 if err != nil { 856 walletlog.Error("ProcWalletSetPasswd", "getSeed err", err) 857 return err 858 } 859 ok, err := SaveSeedInBatch(wallet.walletStore.GetDB(), seed, Passwd.NewPass, newBatch) 860 if !ok { 861 walletlog.Error("ProcWalletSetPasswd", "SaveSeed err", err) 862 return err 863 } 864 865 //对所有存储的私钥重新使用新的密码加密,通过Account前缀查找获取钱包中的所有账户信息 866 WalletAccStores, err := wallet.walletStore.GetAccountByPrefix("Account") 867 if err != nil || len(WalletAccStores) == 0 { 868 walletlog.Error("ProcWalletSetPasswd", "GetAccountByPrefix:err", err) 869 } 870 871 for _, AccStore := range WalletAccStores { 872 //使用old Password解密存储的私钥 873 storekey, err := common.FromHex(AccStore.GetPrivkey()) 874 if err != nil || len(storekey) == 0 { 875 walletlog.Info("ProcWalletSetPasswd", "addr", AccStore.Addr, "FromHex err", err) 876 continue 877 } 878 Decrypter := wcom.CBCDecrypterPrivkey([]byte(Passwd.OldPass), storekey) 879 880 //使用新的密码重新加密私钥 881 Encrypter := wcom.CBCEncrypterPrivkey([]byte(Passwd.NewPass), Decrypter) 882 AccStore.Privkey = common.ToHex(Encrypter) 883 err = wallet.walletStore.SetWalletAccountInBatch(true, AccStore.Addr, AccStore, newBatch) 884 if err != nil { 885 walletlog.Info("ProcWalletSetPasswd", "addr", AccStore.Addr, "SetWalletAccount err", err) 886 } 887 } 888 889 err = newBatch.Write() 890 if err != nil { 891 walletlog.Error("ProcWalletSetPasswd newBatch.Write", "err", err) 892 return err 893 } 894 wallet.Password = Passwd.NewPass 895 wallet.EncryptFlag = 1 896 return nil 897 } 898 899 //ProcWalletLock 锁定钱包 900 func (wallet *Wallet) ProcWalletLock() error { 901 //判断钱包是否已保存seed 902 has, err := wallet.walletStore.HasSeed() 903 if !has || err != nil { 904 return types.ErrSaveSeedFirst 905 } 906 907 atomic.CompareAndSwapInt32(&wallet.isWalletLocked, 0, 1) 908 for _, policy := range wcom.PolicyContainer { 909 policy.OnWalletLocked() 910 } 911 return nil 912 } 913 914 // ProcWalletUnLock 处理钱包解锁 915 //input: 916 //type WalletUnLock struct { 917 // Passwd string 918 // Timeout int64 919 //解锁钱包Timeout时间,超时后继续锁住 920 func (wallet *Wallet) ProcWalletUnLock(WalletUnLock *types.WalletUnLock) error { 921 wallet.mtx.Lock() 922 defer wallet.mtx.Unlock() 923 924 //判断钱包是否已保存seed 925 has, err := wallet.walletStore.HasSeed() 926 if !has || err != nil { 927 return types.ErrSaveSeedFirst 928 } 929 // 钱包已经加密需要验证passwd的正确性 930 if len(wallet.Password) == 0 && wallet.EncryptFlag == 1 { 931 isok := wallet.walletStore.VerifyPasswordHash(WalletUnLock.Passwd) 932 if !isok { 933 walletlog.Error("ProcWalletUnLock Verify Oldpasswd fail!") 934 return types.ErrVerifyOldpasswdFail 935 } 936 } 937 //内存中已经记录password时的校验 938 if len(wallet.Password) != 0 && WalletUnLock.Passwd != wallet.Password { 939 return types.ErrInputPassword 940 } 941 //本钱包没有设置密码加密过,只需要解锁不需要记录解锁密码 942 wallet.Password = WalletUnLock.Passwd 943 //只解锁挖矿转账 944 if !WalletUnLock.WalletOrTicket { 945 //wallet.isTicketLocked = false 946 atomic.CompareAndSwapInt32(&wallet.isWalletLocked, 1, 0) 947 if WalletUnLock.Timeout != 0 { 948 wallet.resetTimeout(WalletUnLock.Timeout) 949 } 950 } 951 for _, policy := range wcom.PolicyContainer { 952 policy.OnWalletUnlocked(WalletUnLock) 953 } 954 return nil 955 956 } 957 958 //解锁超时处理,需要区分整个钱包的解锁或者只挖矿的解锁 959 func (wallet *Wallet) resetTimeout(Timeout int64) { 960 if wallet.timeout == nil { 961 wallet.timeout = time.AfterFunc(time.Second*time.Duration(Timeout), func() { 962 //wallet.isWalletLocked = true 963 atomic.CompareAndSwapInt32(&wallet.isWalletLocked, 0, 1) 964 }) 965 } else { 966 wallet.timeout.Reset(time.Second * time.Duration(Timeout)) 967 } 968 } 969 970 //ProcWalletAddBlock wallet模块收到blockchain广播的addblock消息,需要解析钱包相关的tx并存储到db中 971 func (wallet *Wallet) ProcWalletAddBlock(block *types.BlockDetail) { 972 if block == nil { 973 walletlog.Error("ProcWalletAddBlock input para is nil!") 974 return 975 } 976 //walletlog.Error("ProcWalletAddBlock", "height", block.GetBlock().GetHeight()) 977 types.AssertConfig(wallet.client) 978 cfg := wallet.client.GetConfig() 979 txlen := len(block.Block.GetTxs()) 980 newbatch := wallet.walletStore.GetBlockBatch(true) 981 defer wallet.walletStore.FreeBlockBatch() 982 for index := 0; index < txlen; index++ { 983 tx := block.Block.Txs[index] 984 execer := string(cfg.GetParaExec(tx.Execer)) 985 // 执行钱包业务逻辑策略 986 if policy, ok := wcom.PolicyContainer[execer]; ok { 987 wtxdetail := policy.OnAddBlockTx(block, tx, int32(index), newbatch) 988 if wtxdetail == nil { 989 continue 990 } 991 if len(wtxdetail.Fromaddr) > 0 { 992 txdetailbyte, err := proto.Marshal(wtxdetail) 993 if err != nil { 994 walletlog.Error("ProcWalletAddBlock", "Marshal txdetail error", err, "Height", block.Block.Height, "index", index) 995 continue 996 } 997 blockheight := block.Block.Height*maxTxNumPerBlock + int64(index) 998 heightstr := fmt.Sprintf("%018d", blockheight) 999 key := wcom.CalcTxKey(heightstr) 1000 newbatch.Set(key, txdetailbyte) 1001 } 1002 1003 } else { // 默认的执行器类型处理 1004 // TODO: 钱包基础功能模块,将会重新建立一个处理策略,将钱包变成一个容器 1005 //获取from地址 1006 pubkey := block.Block.Txs[index].Signature.GetPubkey() 1007 addr := address.PubKeyToAddress(pubkey) 1008 param := &buildStoreWalletTxDetailParam{ 1009 tokenname: "", 1010 block: block, 1011 tx: tx, 1012 index: index, 1013 newbatch: newbatch, 1014 isprivacy: false, 1015 addDelType: AddTx, 1016 //utxos: nil, 1017 } 1018 //from addr 1019 fromaddress := addr.String() 1020 param.senderRecver = fromaddress 1021 if len(fromaddress) != 0 && wallet.AddrInWallet(fromaddress) { 1022 param.sendRecvFlag = sendTx 1023 wallet.buildAndStoreWalletTxDetail(param) 1024 walletlog.Debug("ProcWalletAddBlock", "fromaddress", fromaddress) 1025 continue 1026 } 1027 //toaddr获取交易中真实的接收地址,主要是针对para 1028 toaddr := tx.GetRealToAddr() 1029 if len(toaddr) != 0 && wallet.AddrInWallet(toaddr) { 1030 param.sendRecvFlag = recvTx 1031 wallet.buildAndStoreWalletTxDetail(param) 1032 walletlog.Debug("ProcWalletAddBlock", "toaddr", toaddr) 1033 continue 1034 } 1035 } 1036 } 1037 err := newbatch.Write() 1038 if err != nil { 1039 walletlog.Error("ProcWalletAddBlock newbatch.Write", "err", err) 1040 atomic.CompareAndSwapInt32(&wallet.fatalFailureFlag, 0, 1) 1041 } 1042 1043 for _, policy := range wcom.PolicyContainer { 1044 policy.OnAddBlockFinish(block) 1045 } 1046 } 1047 1048 // 1049 type buildStoreWalletTxDetailParam struct { 1050 tokenname string 1051 block *types.BlockDetail 1052 tx *types.Transaction 1053 index int 1054 newbatch dbm.Batch 1055 senderRecver string 1056 isprivacy bool 1057 addDelType int32 1058 sendRecvFlag int32 1059 //utxos []*types.UTXO 1060 } 1061 1062 func (wallet *Wallet) buildAndStoreWalletTxDetail(param *buildStoreWalletTxDetailParam) { 1063 blockheight := param.block.Block.Height*maxTxNumPerBlock + int64(param.index) 1064 heightstr := fmt.Sprintf("%018d", blockheight) 1065 walletlog.Debug("buildAndStoreWalletTxDetail", "heightstr", heightstr, "addDelType", param.addDelType) 1066 if AddTx == param.addDelType { 1067 var txdetail types.WalletTxDetail 1068 var Err error 1069 key := wcom.CalcTxKey(heightstr) 1070 txdetail.Tx = param.tx 1071 txdetail.Height = param.block.Block.Height 1072 txdetail.Index = int64(param.index) 1073 txdetail.Receipt = param.block.Receipts[param.index] 1074 txdetail.Blocktime = param.block.Block.BlockTime 1075 txdetail.Txhash = param.tx.Hash() 1076 txdetail.ActionName = txdetail.Tx.ActionName() 1077 txdetail.Amount, Err = param.tx.Amount() 1078 if Err != nil { 1079 walletlog.Error("buildAndStoreWalletTxDetail Amount err", "Height", param.block.Block.Height, "index", param.index) 1080 } 1081 txdetail.Fromaddr = param.senderRecver 1082 //txdetail.Spendrecv = param.utxos 1083 1084 txdetailbyte, err := proto.Marshal(&txdetail) 1085 if err != nil { 1086 walletlog.Error("buildAndStoreWalletTxDetail Marshal txdetail err", "Height", param.block.Block.Height, "index", param.index) 1087 return 1088 } 1089 param.newbatch.Set(key, txdetailbyte) 1090 } else { 1091 param.newbatch.Delete(wcom.CalcTxKey(heightstr)) 1092 } 1093 } 1094 1095 //ProcWalletDelBlock wallet模块收到blockchain广播的delblock消息,需要解析钱包相关的tx并存db中删除 1096 func (wallet *Wallet) ProcWalletDelBlock(block *types.BlockDetail) { 1097 if block == nil { 1098 walletlog.Error("ProcWalletDelBlock input para is nil!") 1099 return 1100 } 1101 //walletlog.Error("ProcWalletDelBlock", "height", block.GetBlock().GetHeight()) 1102 types.AssertConfig(wallet.client) 1103 cfg := wallet.client.GetConfig() 1104 txlen := len(block.Block.GetTxs()) 1105 newbatch := wallet.walletStore.GetBlockBatch(true) 1106 defer wallet.walletStore.FreeBlockBatch() 1107 for index := txlen - 1; index >= 0; index-- { 1108 blockheight := block.Block.Height*maxTxNumPerBlock + int64(index) 1109 heightstr := fmt.Sprintf("%018d", blockheight) 1110 tx := block.Block.Txs[index] 1111 1112 execer := string(cfg.GetParaExec(tx.Execer)) 1113 // 执行钱包业务逻辑策略 1114 if policy, ok := wcom.PolicyContainer[execer]; ok { 1115 wtxdetail := policy.OnDeleteBlockTx(block, tx, int32(index), newbatch) 1116 if wtxdetail == nil { 1117 continue 1118 } 1119 if len(wtxdetail.Fromaddr) > 0 { 1120 newbatch.Delete(wcom.CalcTxKey(heightstr)) 1121 } 1122 1123 } else { // 默认的合约处理流程 1124 // TODO:将钱包基础功能移动到专属钱包基础业务的模块中,将钱包模块变成容器 1125 //获取from地址 1126 pubkey := tx.Signature.GetPubkey() 1127 addr := address.PubKeyToAddress(pubkey) 1128 fromaddress := addr.String() 1129 if len(fromaddress) != 0 && wallet.AddrInWallet(fromaddress) { 1130 newbatch.Delete(wcom.CalcTxKey(heightstr)) 1131 continue 1132 } 1133 //toaddr 1134 toaddr := tx.GetRealToAddr() 1135 if len(toaddr) != 0 && wallet.AddrInWallet(toaddr) { 1136 newbatch.Delete(wcom.CalcTxKey(heightstr)) 1137 } 1138 } 1139 } 1140 err := newbatch.Write() 1141 if err != nil { 1142 walletlog.Error("ProcWalletDelBlock newbatch.Write", "err", err) 1143 } 1144 for _, policy := range wcom.PolicyContainer { 1145 policy.OnDeleteBlockFinish(block) 1146 } 1147 } 1148 1149 // GetTxDetailByHashs 根据交易哈希获取对应的交易详情 1150 func (wallet *Wallet) GetTxDetailByHashs(ReqHashes *types.ReqHashes) { 1151 //通过txhashs获取对应的txdetail 1152 msg := wallet.client.NewMessage("blockchain", types.EventGetTransactionByHash, ReqHashes) 1153 err := wallet.client.Send(msg, true) 1154 if err != nil { 1155 walletlog.Error("GetTxDetailByHashs Send EventGetTransactionByHash", "err", err) 1156 return 1157 } 1158 resp, err := wallet.client.Wait(msg) 1159 if err != nil { 1160 walletlog.Error("GetTxDetailByHashs EventGetTransactionByHash", "err", err) 1161 return 1162 } 1163 TxDetails := resp.GetData().(*types.TransactionDetails) 1164 if TxDetails == nil { 1165 walletlog.Info("GetTxDetailByHashs TransactionDetails is nil") 1166 return 1167 } 1168 1169 //批量存储地址对应的所有交易的详细信息到wallet db中 1170 newbatch := wallet.walletStore.NewBatch(true) 1171 for _, txdetal := range TxDetails.Txs { 1172 height := txdetal.GetHeight() 1173 txindex := txdetal.GetIndex() 1174 1175 blockheight := height*maxTxNumPerBlock + txindex 1176 heightstr := fmt.Sprintf("%018d", blockheight) 1177 var txdetail types.WalletTxDetail 1178 txdetail.Tx = txdetal.GetTx() 1179 txdetail.Height = txdetal.GetHeight() 1180 txdetail.Index = txdetal.GetIndex() 1181 txdetail.Receipt = txdetal.GetReceipt() 1182 txdetail.Blocktime = txdetal.GetBlocktime() 1183 txdetail.Amount = txdetal.GetAmount() 1184 txdetail.Fromaddr = txdetal.GetFromaddr() 1185 txdetail.ActionName = txdetal.GetTx().ActionName() 1186 1187 txdetailbyte, err := proto.Marshal(&txdetail) 1188 if err != nil { 1189 walletlog.Error("GetTxDetailByHashs Marshal txdetail err", "Height", height, "index", txindex) 1190 return 1191 } 1192 newbatch.Set(wcom.CalcTxKey(heightstr), txdetailbyte) 1193 } 1194 err = newbatch.Write() 1195 if err != nil { 1196 walletlog.Error("GetTxDetailByHashs newbatch.Write", "err", err) 1197 } 1198 } 1199 1200 //生成一个随机的seed种子, 目前支持英文单词和简体中文 1201 func (wallet *Wallet) genSeed(lang int32) (*types.ReplySeed, error) { 1202 seed, err := CreateSeed("", lang) 1203 if err != nil { 1204 walletlog.Error("genSeed", "CreateSeed err", err) 1205 return nil, err 1206 } 1207 var ReplySeed types.ReplySeed 1208 ReplySeed.Seed = seed 1209 return &ReplySeed, nil 1210 } 1211 1212 // GenSeed 获取随机种子 1213 func (wallet *Wallet) GenSeed(lang int32) (*types.ReplySeed, error) { 1214 return wallet.genSeed(lang) 1215 } 1216 1217 //GetSeed 获取seed种子, 通过钱包密码 1218 func (wallet *Wallet) GetSeed(password string) (string, error) { 1219 wallet.mtx.Lock() 1220 defer wallet.mtx.Unlock() 1221 1222 return wallet.getSeed(password) 1223 } 1224 1225 //获取seed种子, 通过钱包密码 1226 func (wallet *Wallet) getSeed(password string) (string, error) { 1227 ok, err := wallet.checkWalletStatus() 1228 if !ok { 1229 return "", err 1230 } 1231 1232 seed, err := GetSeed(wallet.walletStore.GetDB(), password) 1233 if err != nil { 1234 walletlog.Error("getSeed", "GetSeed err", err) 1235 return "", err 1236 } 1237 return seed, nil 1238 } 1239 1240 // SaveSeed 保存种子 1241 func (wallet *Wallet) SaveSeed(password string, seed string) (bool, error) { 1242 return wallet.saveSeed(password, seed) 1243 } 1244 1245 //保存seed种子到数据库中, 并通过钱包密码加密, 钱包起来首先要设置seed 1246 func (wallet *Wallet) saveSeed(password string, seed string) (bool, error) { 1247 wallet.mtx.Lock() 1248 defer wallet.mtx.Unlock() 1249 1250 //首先需要判断钱包是否已经设置seed,如果已经设置提示不需要再设置,一个钱包只能保存一个seed 1251 exit, err := wallet.walletStore.HasSeed() 1252 if exit && err == nil { 1253 return false, types.ErrSeedExist 1254 } 1255 //入参数校验,seed必须是大于等于12个单词或者汉字 1256 if len(password) == 0 || len(seed) == 0 { 1257 return false, types.ErrInvalidParam 1258 } 1259 1260 // 密码合法性校验 1261 if !isValidPassWord(password) { 1262 return false, types.ErrInvalidPassWord 1263 } 1264 1265 seedarry := strings.Fields(seed) 1266 curseedlen := len(seedarry) 1267 if curseedlen < SaveSeedLong { 1268 walletlog.Error("saveSeed VeriySeedwordnum", "curseedlen", curseedlen, "SaveSeedLong", SaveSeedLong) 1269 return false, types.ErrSeedWordNum 1270 } 1271 1272 var newseed string 1273 for index, seedstr := range seedarry { 1274 if index != curseedlen-1 { 1275 newseed += seedstr + " " 1276 } else { 1277 newseed += seedstr 1278 } 1279 } 1280 1281 //校验seed是否能生成钱包结构类型,从而来校验seed的正确性 1282 have, err := VerifySeed(newseed, wallet.SignType, wallet.CoinType) 1283 if !have { 1284 walletlog.Error("saveSeed VerifySeed", "err", err) 1285 return false, types.ErrSeedWord 1286 } 1287 //批量处理seed和password的存储 1288 newBatch := wallet.walletStore.NewBatch(true) 1289 err = wallet.walletStore.SetPasswordHash(password, newBatch) 1290 if err != nil { 1291 walletlog.Error("saveSeed", "SetPasswordHash err", err) 1292 return false, err 1293 } 1294 //设置钱包加密标志位 1295 err = wallet.walletStore.SetEncryptionFlag(newBatch) 1296 if err != nil { 1297 walletlog.Error("saveSeed", "SetEncryptionFlag err", err) 1298 return false, err 1299 } 1300 1301 ok, err := SaveSeedInBatch(wallet.walletStore.GetDB(), newseed, password, newBatch) 1302 if !ok { 1303 walletlog.Error("saveSeed", "SaveSeed err", err) 1304 return false, err 1305 } 1306 1307 err = newBatch.Write() 1308 if err != nil { 1309 walletlog.Error("saveSeed newBatch.Write", "err", err) 1310 return false, err 1311 } 1312 wallet.Password = password 1313 wallet.EncryptFlag = 1 1314 return true, nil 1315 } 1316 1317 //ProcDumpPrivkey 获取地址对应的私钥 1318 func (wallet *Wallet) ProcDumpPrivkey(addr string) (string, error) { 1319 wallet.mtx.Lock() 1320 defer wallet.mtx.Unlock() 1321 1322 ok, err := wallet.checkWalletStatus() 1323 if !ok { 1324 return "", err 1325 } 1326 if len(addr) == 0 { 1327 walletlog.Error("ProcDumpPrivkey input para is nil!") 1328 return "", types.ErrInvalidParam 1329 } 1330 1331 priv, err := wallet.getPrivKeyByAddr(addr) 1332 if err != nil { 1333 return "", err 1334 } 1335 return common.ToHex(priv.Bytes()), nil 1336 //return strings.ToUpper(common.ToHex(priv.Bytes())), nil 1337 } 1338 1339 //收到其他模块上报的系统有致命性故障,需要通知前端 1340 func (wallet *Wallet) setFatalFailure(reportErrEvent *types.ReportErrEvent) { 1341 1342 walletlog.Error("setFatalFailure", "reportErrEvent", reportErrEvent.String()) 1343 if reportErrEvent.Error == "ErrDataBaseDamage" { 1344 atomic.StoreInt32(&wallet.fatalFailureFlag, 1) 1345 } 1346 } 1347 1348 func (wallet *Wallet) getFatalFailure() int32 { 1349 return atomic.LoadInt32(&wallet.fatalFailureFlag) 1350 } 1351 1352 //密码合法性校验,密码长度在8-30位之间。必须是数字+字母的组合 1353 func isValidPassWord(password string) bool { 1354 pwLen := len(password) 1355 if pwLen < 8 || pwLen > 30 { 1356 return false 1357 } 1358 1359 var char bool 1360 var digit bool 1361 for _, s := range password { 1362 if unicode.IsLetter(s) { 1363 char = true 1364 } else if unicode.IsDigit(s) { 1365 digit = true 1366 } else { 1367 return false 1368 } 1369 } 1370 return char && digit 1371 } 1372 1373 // CreateNewAccountByIndex 指定index创建公私钥对,主要用于空投地址。目前暂定一千万 1374 func (wallet *Wallet) createNewAccountByIndex(index uint32) (string, error) { 1375 wallet.mtx.Lock() 1376 defer wallet.mtx.Unlock() 1377 1378 ok, err := wallet.checkWalletStatus() 1379 if !ok { 1380 return "", err 1381 } 1382 1383 if !isValidIndex(index) { 1384 walletlog.Error("createNewAccountByIndex index err", "index", index) 1385 return "", types.ErrInvalidParam 1386 } 1387 1388 //空投地址是否已经存在,存在就直接返回存储的值即可 1389 airDropAddr, err := wallet.walletStore.GetAirDropIndex() 1390 if airDropAddr != "" && err == nil { 1391 priv, err := wallet.getPrivKeyByAddr(airDropAddr) 1392 if err != nil { 1393 return "", err 1394 } 1395 return common.ToHex(priv.Bytes()), nil 1396 } 1397 1398 var addr string 1399 var privkeybyte []byte 1400 var HexPubkey string 1401 var isUsed bool 1402 1403 cointype := wallet.GetCoinType() 1404 1405 //通过seed获取私钥, 首先通过钱包密码解锁seed然后通过seed生成私钥 1406 seed, err := wallet.getSeed(wallet.Password) 1407 if err != nil { 1408 walletlog.Error("createNewAccountByIndex", "getSeed err", err) 1409 return "", err 1410 } 1411 1412 // 通过指定index生成公私钥对,并存入数据库中,如果账户已经存在就直接返回账户信息即可 1413 privkeyhex, err := GetPrivkeyBySeed(wallet.walletStore.GetDB(), seed, index, wallet.SignType, wallet.CoinType) 1414 if err != nil { 1415 walletlog.Error("createNewAccountByIndex", "GetPrivkeyBySeed err", err) 1416 return "", err 1417 } 1418 privkeybyte, err = common.FromHex(privkeyhex) 1419 if err != nil || len(privkeybyte) == 0 { 1420 walletlog.Error("createNewAccountByIndex", "FromHex err", err) 1421 return "", err 1422 } 1423 1424 pub, err := bipwallet.PrivkeyToPub(cointype, uint32(wallet.SignType), privkeybyte) 1425 if err != nil { 1426 seedlog.Error("createNewAccountByIndex PrivkeyToPub", "err", err) 1427 return "", types.ErrPrivkeyToPub 1428 } 1429 1430 HexPubkey = hex.EncodeToString(pub) 1431 1432 addr, err = bipwallet.PubToAddress(pub) 1433 if err != nil { 1434 seedlog.Error("createNewAccountByIndex PubToAddress", "err", err) 1435 return "", types.ErrPrivkeyToPub 1436 } 1437 //通过新生成的账户地址查询钱包数据库,如果查询返回的账户信息不为空, 1438 //说明此账户已经被使用,不需要再次存储账户信息 1439 account, err := wallet.walletStore.GetAccountByAddr(addr) 1440 if account != nil && err == nil { 1441 isUsed = true 1442 } 1443 1444 //第一次创建此账户 1445 if !isUsed { 1446 Account := types.Account{ 1447 Addr: addr, 1448 Currency: 0, 1449 Balance: 0, 1450 Frozen: 0, 1451 } 1452 //首先校验label是否已被使用 1453 Label := "airdropaddr" 1454 for { 1455 i := 0 1456 WalletAccStores, err := wallet.walletStore.GetAccountByLabel(Label) 1457 if WalletAccStores != nil && err == nil { 1458 walletlog.Debug("createNewAccountByIndex Label is exist in wallet!", "WalletAccStores", WalletAccStores) 1459 i++ 1460 Label = Label + fmt.Sprintf("%d", i) 1461 } else { 1462 break 1463 } 1464 } 1465 1466 walletAccount := types.WalletAccount{ 1467 Acc: &Account, 1468 Label: Label, 1469 } 1470 1471 //使用钱包的password对私钥加密 aes cbc 1472 Encrypted := wcom.CBCEncrypterPrivkey([]byte(wallet.Password), privkeybyte) 1473 1474 var WalletAccStore types.WalletAccountStore 1475 WalletAccStore.Privkey = common.ToHex(Encrypted) 1476 WalletAccStore.Label = Label 1477 WalletAccStore.Addr = addr 1478 1479 //存储账户信息到wallet数据库中 1480 err = wallet.walletStore.SetWalletAccount(false, Account.Addr, &WalletAccStore) 1481 if err != nil { 1482 return "", err 1483 } 1484 1485 //获取地址对应的账户信息从account模块 1486 addrs := make([]string, 1) 1487 addrs[0] = addr 1488 accounts, err := wallet.accountdb.LoadAccounts(wallet.api, addrs) 1489 if err != nil { 1490 walletlog.Error("createNewAccountByIndex", "LoadAccounts err", err) 1491 return "", err 1492 } 1493 // 本账户是首次创建 1494 if len(accounts[0].Addr) == 0 { 1495 accounts[0].Addr = addr 1496 } 1497 walletAccount.Acc = accounts[0] 1498 1499 //从blockchain模块同步Account.Addr对应的所有交易详细信息 1500 for _, policy := range wcom.PolicyContainer { 1501 policy.OnCreateNewAccount(walletAccount.Acc) 1502 } 1503 } 1504 //存贮空投地址的信息 1505 airfrop := &wcom.AddrInfo{ 1506 Index: index, 1507 Addr: addr, 1508 Pubkey: HexPubkey, 1509 } 1510 err = wallet.walletStore.SetAirDropIndex(airfrop) 1511 if err != nil { 1512 walletlog.Error("createNewAccountByIndex", "SetAirDropIndex err", err) 1513 } 1514 return privkeyhex, nil 1515 } 1516 1517 //isValidIndex校验index的合法性 1518 func isValidIndex(index uint32) bool { 1519 if types.AirDropMinIndex <= index && index <= types.AirDropMaxIndex { 1520 return true 1521 } 1522 return false 1523 } 1524 1525 //ProcDumpPrivkeysFile 获取全部私钥保存到文件 1526 func (wallet *Wallet) ProcDumpPrivkeysFile(fileName, passwd string) error { 1527 _, err := os.Stat(fileName) 1528 if err == nil { 1529 walletlog.Error("ProcDumpPrivkeysFile file already exists!", "fileName", fileName) 1530 return types.ErrFileExists 1531 } 1532 1533 wallet.mtx.Lock() 1534 defer wallet.mtx.Unlock() 1535 1536 ok, err := wallet.checkWalletStatus() 1537 if !ok { 1538 return err 1539 } 1540 1541 f, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666) 1542 if err != nil { 1543 walletlog.Error("ProcDumpPrivkeysFile create file error!", "fileName", fileName, "err", err) 1544 return err 1545 } 1546 defer f.Close() 1547 1548 accounts, err := wallet.walletStore.GetAccountByPrefix("Account") 1549 if err != nil || len(accounts) == 0 { 1550 walletlog.Info("ProcDumpPrivkeysFile GetWalletAccounts", "GetAccountByPrefix:err", err) 1551 return err 1552 } 1553 1554 for i, acc := range accounts { 1555 priv, err := wallet.getPrivKeyByAddr(acc.Addr) 1556 if err != nil { 1557 walletlog.Info("getPrivKeyByAddr", acc.Addr, err) 1558 continue 1559 } 1560 1561 privkey := common.ToHex(priv.Bytes()) 1562 content := privkey + "& *.prickey.+.label.* &" + acc.Label 1563 1564 Encrypter, err := AesgcmEncrypter([]byte(passwd), []byte(content)) 1565 if err != nil { 1566 walletlog.Error("ProcDumpPrivkeysFile AesgcmEncrypter fileContent error!", "fileName", fileName, "err", err) 1567 continue 1568 } 1569 1570 f.WriteString(string(Encrypter)) 1571 1572 if i < len(accounts)-1 { 1573 f.WriteString("&ffzm.&**&") 1574 } 1575 } 1576 1577 return nil 1578 } 1579 1580 // ProcImportPrivkeysFile 处理导入私钥 1581 //input: 1582 //type struct { 1583 // fileName string 1584 // passwd string 1585 //导入私钥,并且同时会导入交易 1586 func (wallet *Wallet) ProcImportPrivkeysFile(fileName, passwd string) error { 1587 if _, err := os.Stat(fileName); os.IsNotExist(err) { 1588 walletlog.Error("ProcImportPrivkeysFile file is not exist!", "fileName", fileName) 1589 return err 1590 } 1591 1592 wallet.mtx.Lock() 1593 defer wallet.mtx.Unlock() 1594 1595 ok, err := wallet.checkWalletStatus() 1596 if !ok { 1597 return err 1598 } 1599 1600 f, err := os.Open(fileName) 1601 if err != nil { 1602 walletlog.Error("ProcImportPrivkeysFile Open file error", "fileName", fileName, "err", err) 1603 return err 1604 } 1605 defer f.Close() 1606 1607 fileContent, err := ioutil.ReadAll(f) 1608 if err != nil { 1609 walletlog.Error("ProcImportPrivkeysFile read file error", "fileName", fileName, "err", err) 1610 return err 1611 } 1612 accounts := strings.Split(string(fileContent), "&ffzm.&**&") 1613 for _, value := range accounts { 1614 Decrypter, err := AesgcmDecrypter([]byte(passwd), []byte(value)) 1615 if err != nil { 1616 walletlog.Error("ProcImportPrivkeysFile AesgcmDecrypter fileContent error", "fileName", fileName, "err", err) 1617 return types.ErrVerifyOldpasswdFail 1618 } 1619 1620 acc := strings.Split(string(Decrypter), "& *.prickey.+.label.* &") 1621 if len(acc) != 2 { 1622 walletlog.Error("ProcImportPrivkeysFile len(acc) != 2, File format error.", "Decrypter", string(Decrypter), "len", len(acc)) 1623 continue 1624 } 1625 privKey := acc[0] 1626 label := acc[1] 1627 1628 //校验label是否已经被使用 1629 Account, err := wallet.walletStore.GetAccountByLabel(label) 1630 if Account != nil && err == nil { 1631 walletlog.Info("ProcImportPrivKey Label is exist in wallet, label = label + _2!") 1632 label = label + "_2" 1633 } 1634 1635 PrivKey := &types.ReqWalletImportPrivkey{ 1636 Privkey: privKey, 1637 Label: label, 1638 } 1639 1640 _, err = wallet.procImportPrivKey(PrivKey) 1641 if err == types.ErrPrivkeyExist { 1642 // 修改标签名称 是否需要? 1643 // wallet.ProcWalletSetLabel() 1644 } else if err != nil { 1645 walletlog.Info("ProcImportPrivKey procImportPrivKey error") 1646 return err 1647 } 1648 } 1649 1650 return nil 1651 }