github.com/turingchain2020/turingchain@v1.1.21/wallet/wallet.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 wallet turingchain钱包功能实现 6 package wallet 7 8 import ( 9 "errors" 10 "math/rand" 11 "reflect" 12 "sync" 13 "sync/atomic" 14 "time" 15 16 "github.com/turingchain2020/turingchain/account" 17 "github.com/turingchain2020/turingchain/client" 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 clog "github.com/turingchain2020/turingchain/common/log" 23 log "github.com/turingchain2020/turingchain/common/log/log15" 24 "github.com/turingchain2020/turingchain/queue" 25 "github.com/turingchain2020/turingchain/types" 26 "github.com/turingchain2020/turingchain/wallet/bipwallet" 27 wcom "github.com/turingchain2020/turingchain/wallet/common" 28 ) 29 30 var ( 31 //minFee int64 32 maxTxNumPerBlock int64 = types.MaxTxsPerBlock 33 // MaxTxHashsPerTime 每次处理的最大交易哈希数量 34 MaxTxHashsPerTime int64 = 100 35 walletlog = log.New("module", "wallet") 36 //accountdb *account.DB 37 //accTokenMap = make(map[string]*account.DB) 38 ) 39 40 func init() { 41 wcom.QueryData.Register("wallet", &Wallet{}) 42 } 43 44 const ( 45 // AddTx 添加交易操作 46 AddTx int32 = 20001 47 // DelTx 删除交易操作 48 DelTx int32 = 20002 49 // 交易收发方向 50 sendTx int32 = 30001 51 recvTx int32 = 30002 52 ) 53 54 // Wallet 钱包功能的实现类 55 type Wallet struct { 56 client queue.Client 57 // 模块间通信的操作接口,建议用api代替client调用 58 api client.QueueProtocolAPI 59 mtx sync.Mutex 60 timeout *time.Timer 61 mineStatusReporter wcom.MineStatusReport 62 isclosed int32 63 isWalletLocked int32 64 fatalFailureFlag int32 65 Password string 66 FeeAmount int64 67 EncryptFlag int64 68 wg *sync.WaitGroup 69 walletStore *walletStore 70 random *rand.Rand 71 cfg *types.Wallet 72 done chan struct{} 73 rescanwg *sync.WaitGroup 74 lastHeader *types.Header 75 initFlag uint32 // 钱包模块是否初始化完毕的标记,默认为0,表示未初始化 76 SignType int // SignType 签名类型 1;secp256k1,2:ed25519,3:sm2 77 CoinType uint32 // CoinType 币种类型 trc:0x80003333,ycc:0x80003334 78 79 minFee int64 80 accountdb *account.DB 81 accTokenMap map[string]*account.DB 82 } 83 84 // SetLogLevel 设置日志登记 85 func SetLogLevel(level string) { 86 clog.SetLogLevel(level) 87 } 88 89 // DisableLog 禁用日志 90 func DisableLog() { 91 walletlog.SetHandler(log.DiscardHandler()) 92 storelog.SetHandler(log.DiscardHandler()) 93 } 94 95 // New 创建一个钱包对象 96 func New(cfg *types.TuringchainConfig) *Wallet { 97 mcfg := cfg.GetModuleConfig().Wallet 98 //walletStore 99 //accountdb = account.NewCoinsAccount() 100 walletStoreDB := dbm.NewDB("wallet", mcfg.Driver, mcfg.DbPath, mcfg.DbCache) 101 //walletStore := NewStore(walletStoreDB) 102 walletStore := newStore(walletStoreDB) 103 //minFee = cfg.MinFee 104 signType := types.GetSignType("", mcfg.SignType) 105 if signType <= 0 { 106 signType = types.SECP256K1 107 } 108 109 wallet := &Wallet{ 110 walletStore: walletStore, 111 isWalletLocked: 1, 112 fatalFailureFlag: 0, 113 wg: &sync.WaitGroup{}, 114 FeeAmount: walletStore.GetFeeAmount(mcfg.MinFee), 115 EncryptFlag: walletStore.GetEncryptionFlag(), 116 done: make(chan struct{}), 117 cfg: mcfg, 118 rescanwg: &sync.WaitGroup{}, 119 initFlag: 0, 120 SignType: signType, 121 CoinType: bipwallet.GetSLIP0044CoinType(mcfg.CoinType), 122 minFee: mcfg.MinFee, 123 accountdb: account.NewCoinsAccount(cfg), 124 accTokenMap: make(map[string]*account.DB), 125 } 126 wallet.random = rand.New(rand.NewSource(types.Now().UnixNano())) 127 wcom.QueryData.SetThis("wallet", reflect.ValueOf(wallet)) 128 return wallet 129 } 130 131 //Wait for wallet ready 132 func (wallet *Wallet) Wait() {} 133 134 // RegisterMineStatusReporter 向钱包注册状态回报 135 func (wallet *Wallet) RegisterMineStatusReporter(reporter wcom.MineStatusReport) error { 136 if reporter == nil { 137 return types.ErrInvalidParam 138 } 139 if wallet.mineStatusReporter != nil { 140 return errors.New("ReporterIsExisted") 141 } 142 consensus := wallet.client.GetConfig().GetModuleConfig().Consensus.Name 143 144 if !isConflict(consensus, reporter.PolicyName()) { 145 wallet.mineStatusReporter = reporter 146 } 147 return nil 148 } 149 150 //检测当policy和Consensus有冲突时,不挂接对应的reporter 151 func isConflict(curConsensus string, policy string) bool { 152 walletlog.Info("isConflict", "curConsensus", curConsensus, "policy", policy) 153 154 return curConsensus != policy 155 } 156 157 // GetConfig 获取钱包配置 158 func (wallet *Wallet) GetConfig() *types.Wallet { 159 return wallet.cfg 160 } 161 162 // GetAPI 获取操作API 163 func (wallet *Wallet) GetAPI() client.QueueProtocolAPI { 164 return wallet.api 165 } 166 167 // GetDBStore 获取数据库存储对象操作接口 168 func (wallet *Wallet) GetDBStore() dbm.DB { 169 return wallet.walletStore.GetDB() 170 } 171 172 // GetSignType 获取签名类型 173 func (wallet *Wallet) GetSignType() int { 174 return wallet.SignType 175 } 176 177 // GetCoinType 获取币种类型 178 func (wallet *Wallet) GetCoinType() uint32 { 179 return wallet.CoinType 180 } 181 182 // GetPassword 获取密码 183 func (wallet *Wallet) GetPassword() string { 184 wallet.mtx.Lock() 185 defer wallet.mtx.Unlock() 186 187 return wallet.Password 188 } 189 190 // Nonce 获取随机值 191 func (wallet *Wallet) Nonce() int64 { 192 return wallet.random.Int63() 193 } 194 195 // AddWaitGroup 添加一个分组等待事件 196 func (wallet *Wallet) AddWaitGroup(delta int) { 197 wallet.wg.Add(delta) 198 } 199 200 // WaitGroupDone 完成分组事件 201 func (wallet *Wallet) WaitGroupDone() { 202 wallet.wg.Done() 203 } 204 205 // GetBlockHeight 获取区块高度 206 func (wallet *Wallet) GetBlockHeight() int64 { 207 return wallet.GetHeight() 208 } 209 210 // GetRandom 获取随机值 211 func (wallet *Wallet) GetRandom() *rand.Rand { 212 return wallet.random 213 } 214 215 // GetWalletDone 是否结束的通道 216 func (wallet *Wallet) GetWalletDone() chan struct{} { 217 return wallet.done 218 } 219 220 // GetLastHeader 获取最新高度信息 221 func (wallet *Wallet) GetLastHeader() *types.Header { 222 wallet.mtx.Lock() 223 defer wallet.mtx.Unlock() 224 return wallet.lastHeader 225 } 226 227 // GetWaitGroup 获取等待互斥量 228 func (wallet *Wallet) GetWaitGroup() *sync.WaitGroup { 229 return wallet.wg 230 } 231 232 // GetAccountByLabel 根据标签获取账号 233 func (wallet *Wallet) GetAccountByLabel(label string) (*types.WalletAccountStore, error) { 234 return wallet.walletStore.GetAccountByLabel(label) 235 } 236 237 // IsRescanUtxosFlagScaning 是否处于扫描UTXO状态 238 func (wallet *Wallet) IsRescanUtxosFlagScaning() (bool, error) { 239 in := &types.ReqNil{} 240 flag := false 241 for _, policy := range wcom.PolicyContainer { 242 out, err := policy.Call("GetUTXOScaningFlag", in) 243 if err != nil { 244 if err.Error() == types.ErrNotSupport.Error() { 245 continue 246 } 247 return flag, err 248 } 249 reply, ok := out.(*types.Reply) 250 if !ok { 251 err = types.ErrTypeAsset 252 return flag, err 253 } 254 flag = reply.IsOk 255 return flag, err 256 } 257 258 return flag, nil 259 } 260 261 // Close 关闭钱包 262 func (wallet *Wallet) Close() { 263 //等待所有的子线程退出 264 //set close flag to isclosed == 1 265 atomic.StoreInt32(&wallet.isclosed, 1) 266 for _, policy := range wcom.PolicyContainer { 267 policy.OnClose() 268 } 269 close(wallet.done) 270 wallet.client.Close() 271 wallet.wg.Wait() 272 //关闭数据库 273 wallet.walletStore.Close() 274 walletlog.Info("wallet module closed") 275 } 276 277 // IsClose 检查是否处于关闭状态 278 func (wallet *Wallet) IsClose() bool { 279 return atomic.LoadInt32(&wallet.isclosed) == 1 280 } 281 282 // IsWalletLocked 返回钱包锁的状态 283 func (wallet *Wallet) IsWalletLocked() bool { 284 return atomic.LoadInt32(&wallet.isWalletLocked) != 0 285 } 286 287 // SetQueueClient 初始化客户端消息队列 288 func (wallet *Wallet) SetQueueClient(cli queue.Client) { 289 var err error 290 wallet.client = cli 291 wallet.client.Sub("wallet") 292 wallet.api, err = client.New(cli, nil) 293 if err != nil { 294 panic("SetQueueClient client.New err") 295 } 296 sub := cli.GetConfig().GetSubConfig().Wallet 297 // 置完client之后才做Init 298 wcom.Init(wallet, sub) 299 wallet.wg.Add(1) 300 go wallet.ProcRecvMsg() 301 for _, policy := range wcom.PolicyContainer { 302 policy.OnSetQueueClient() 303 } 304 wallet.setInited(true) 305 } 306 307 // GetAccountByAddr 根据地址获取账户 308 func (wallet *Wallet) GetAccountByAddr(addr string) (*types.WalletAccountStore, error) { 309 return wallet.walletStore.GetAccountByAddr(addr) 310 } 311 312 // SetWalletAccount 设置钱包账户 313 func (wallet *Wallet) SetWalletAccount(update bool, addr string, account *types.WalletAccountStore) error { 314 return wallet.walletStore.SetWalletAccount(update, addr, account) 315 } 316 317 // GetPrivKeyByAddr 根据地址获取私钥 318 func (wallet *Wallet) GetPrivKeyByAddr(addr string) (crypto.PrivKey, error) { 319 if !wallet.isInited() { 320 return nil, types.ErrNotInited 321 } 322 wallet.mtx.Lock() 323 defer wallet.mtx.Unlock() 324 325 return wallet.getPrivKeyByAddr(addr) 326 } 327 328 func (wallet *Wallet) getPrivKeyByAddr(addr string) (crypto.PrivKey, error) { 329 //获取指定地址在钱包里的账户信息 330 Accountstor, err := wallet.walletStore.GetAccountByAddr(addr) 331 if err != nil { 332 walletlog.Error("getPrivKeyByAddr", "GetAccountByAddr err:", err) 333 return nil, err 334 } 335 336 //通过password解密存储的私钥 337 prikeybyte, err := common.FromHex(Accountstor.GetPrivkey()) 338 if err != nil || len(prikeybyte) == 0 { 339 walletlog.Error("getPrivKeyByAddr", "FromHex err", err) 340 return nil, err 341 } 342 343 privkey := wcom.CBCDecrypterPrivkey([]byte(wallet.Password), prikeybyte) 344 //通过privkey生成一个pubkey然后换算成对应的addr 345 cr, err := crypto.New(types.GetSignName("", wallet.SignType)) 346 if err != nil { 347 walletlog.Error("getPrivKeyByAddr", "err", err) 348 return nil, err 349 } 350 priv, err := cr.PrivKeyFromBytes(privkey) 351 if err != nil { 352 walletlog.Error("getPrivKeyByAddr", "PrivKeyFromBytes err", err) 353 return nil, err 354 } 355 return priv, nil 356 } 357 358 // AddrInWallet 地址对应的账户是否属于本钱包 359 func (wallet *Wallet) AddrInWallet(addr string) bool { 360 if !wallet.isInited() { 361 return false 362 } 363 if len(addr) == 0 { 364 return false 365 } 366 acc, err := wallet.walletStore.GetAccountByAddr(addr) 367 if err == nil && acc != nil { 368 return true 369 } 370 return false 371 } 372 373 //IsTransfer 检测钱包是否允许转账到指定地址,判断钱包锁和是否有seed以及挖矿锁 374 func (wallet *Wallet) IsTransfer(addr string) (bool, error) { 375 wallet.mtx.Lock() 376 defer wallet.mtx.Unlock() 377 378 return wallet.isTransfer(addr) 379 } 380 381 //isTransfer 检测钱包是否允许转账到指定地址,判断钱包锁和是否有seed以及挖矿锁 382 func (wallet *Wallet) isTransfer(addr string) (bool, error) { 383 384 ok, err := wallet.checkWalletStatus() 385 //钱包已经解锁或者错误是ErrSaveSeedFirst直接返回 386 if ok || err == types.ErrSaveSeedFirst { 387 return ok, err 388 } 389 //钱包已经锁定,挖矿锁已经解锁,需要判断addr是否是挖矿合约地址 390 //这里依赖了ticket 挖矿合约 391 if !wallet.isTicketLocked() { 392 consensus := wallet.client.GetConfig().GetModuleConfig().Consensus.Name 393 394 if addr == address.ExecAddress(consensus) { 395 return true, nil 396 } 397 } 398 return ok, err 399 } 400 401 //CheckWalletStatus 钱包状态检测函数,解锁状态,seed是否已保存 402 func (wallet *Wallet) CheckWalletStatus() (bool, error) { 403 if !wallet.isInited() { 404 return false, types.ErrNotInited 405 } 406 407 wallet.mtx.Lock() 408 defer wallet.mtx.Unlock() 409 410 return wallet.checkWalletStatus() 411 } 412 413 //CheckWalletStatus 钱包状态检测函数,解锁状态,seed是否已保存 414 func (wallet *Wallet) checkWalletStatus() (bool, error) { 415 // 钱包锁定,ticket已经解锁,返回只解锁了ticket的错误 416 if wallet.IsWalletLocked() && !wallet.isTicketLocked() { 417 return false, types.ErrOnlyTicketUnLocked 418 } else if wallet.IsWalletLocked() { 419 return false, types.ErrWalletIsLocked 420 } 421 422 //判断钱包是否已保存seed 423 has, err := wallet.walletStore.HasSeed() 424 if !has || err != nil { 425 return false, types.ErrSaveSeedFirst 426 } 427 return true, nil 428 } 429 430 func (wallet *Wallet) isTicketLocked() bool { 431 locked := true 432 if wallet.mineStatusReporter != nil { 433 locked = wallet.mineStatusReporter.IsTicketLocked() 434 } 435 return locked 436 } 437 438 func (wallet *Wallet) isAutoMinning() bool { 439 autoMining := false 440 if wallet.mineStatusReporter != nil { 441 autoMining = wallet.mineStatusReporter.IsAutoMining() 442 } 443 return autoMining 444 } 445 446 // GetWalletStatus 获取钱包状态 447 func (wallet *Wallet) GetWalletStatus() *types.WalletStatus { 448 var err error 449 s := &types.WalletStatus{} 450 s.IsWalletLock = wallet.IsWalletLocked() 451 s.IsHasSeed, err = wallet.walletStore.HasSeed() 452 s.IsAutoMining = wallet.isAutoMinning() 453 s.IsTicketLock = wallet.isTicketLocked() 454 if err != nil { 455 walletlog.Debug("GetWalletStatus HasSeed ", "err", err) 456 } 457 walletlog.Debug("GetWalletStatus", "walletstatus", s) 458 return s 459 } 460 461 // GetWalletAccounts 获取账号列表 462 //output: 463 //type WalletAccountStore struct { 464 // Privkey string //加密后的私钥hex值 465 // Label string 466 // Addr string 467 // TimeStamp string 468 //获取钱包的所有账户地址列表, 469 func (wallet *Wallet) getWalletAccounts() ([]*types.WalletAccountStore, error) { 470 if !wallet.isInited() { 471 return nil, types.ErrNotInited 472 } 473 474 //通过Account前缀查找获取钱包中的所有账户信息 475 WalletAccStores, err := wallet.walletStore.GetAccountByPrefix("Account") 476 if err != nil || len(WalletAccStores) == 0 { 477 walletlog.Info("GetWalletAccounts", "GetAccountByPrefix:err", err) 478 return nil, err 479 } 480 return WalletAccStores, err 481 } 482 483 //GetWalletAccounts 获取账号列表 484 func (wallet *Wallet) GetWalletAccounts() ([]*types.WalletAccountStore, error) { 485 if !wallet.isInited() { 486 return nil, types.ErrNotInited 487 } 488 wallet.mtx.Lock() 489 defer wallet.mtx.Unlock() 490 491 return wallet.getWalletAccounts() 492 } 493 494 func (wallet *Wallet) updateLastHeader(block *types.BlockDetail, mode int) error { 495 wallet.mtx.Lock() 496 defer wallet.mtx.Unlock() 497 header, err := wallet.api.GetLastHeader() 498 if err != nil { 499 return err 500 } 501 if block != nil { 502 if mode == 1 && block.Block.Height > header.Height { 503 wallet.lastHeader = &types.Header{ 504 BlockTime: block.Block.BlockTime, 505 Height: block.Block.Height, 506 StateHash: block.Block.StateHash, 507 } 508 } else if mode == -1 && wallet.lastHeader != nil && wallet.lastHeader.Height == block.Block.Height { 509 wallet.lastHeader = header 510 } 511 } 512 if block == nil || wallet.lastHeader == nil { 513 wallet.lastHeader = header 514 } 515 return nil 516 } 517 518 func (wallet *Wallet) setInited(flag bool) { 519 if flag && !wallet.isInited() { 520 atomic.StoreUint32(&wallet.initFlag, 1) 521 } 522 } 523 524 func (wallet *Wallet) isInited() bool { 525 return atomic.LoadUint32(&wallet.initFlag) != 0 526 }