decred.org/dcrwallet/v3@v3.1.0/wallet/udb/addressdb.go (about) 1 // Copyright (c) 2014 The btcsuite developers 2 // Copyright (c) 2015-2018 The Decred developers 3 // Use of this source code is governed by an ISC 4 // license that can be found in the LICENSE file. 5 6 package udb 7 8 import ( 9 "crypto/sha256" 10 "encoding/binary" 11 "time" 12 13 "decred.org/dcrwallet/v3/errors" 14 "decred.org/dcrwallet/v3/kdf" 15 "decred.org/dcrwallet/v3/wallet/walletdb" 16 ) 17 18 var ( 19 // latestMgrVersion is the most recent manager version as a variable so 20 // the tests can change it to force errors. 21 latestMgrVersion uint32 = 6 22 ) 23 24 // ObtainUserInputFunc is a function that reads a user input and returns it as 25 // a byte stream. It is used to accept data required during upgrades, for e.g. 26 // wallet seed and private passphrase. 27 type ObtainUserInputFunc func() ([]byte, error) 28 29 // addressType represents a type of address stored in the database. 30 type addressType uint8 31 32 // These constants define the various supported address types. 33 // They must remain stable as their values are recorded to the DB. 34 const ( 35 adtChain addressType = iota // seed-derived BIP0044 36 adtImport // individually imported privkey 37 adtScript // individually imported p2sh script 38 ) 39 40 type dbAccount interface { 41 accountType() accountType 42 rowData() []byte 43 } 44 45 // accountType represents a type of address stored in the database. 46 type accountType uint8 47 48 // These constants define the various supported account types. 49 // They must remain stable as their values are recorded to the DB. 50 const ( 51 actBIP0044Legacy accountType = iota 52 actBIP0044 53 importedVoting 54 ) 55 56 // dbAccountRow houses information stored about an account in the database. 57 type dbAccountRow struct { 58 acctType accountType 59 rawData []byte // Varies based on account type field. 60 } 61 62 // dbBIP0044AccountRow houses additional information stored about a BIP0044 63 // account in the database. 64 type dbBIP0044AccountRow struct { 65 dbAccountRow 66 pubKeyEncrypted []byte 67 privKeyEncrypted []byte 68 nextExternalIndex uint32 // Removed by version 2 69 nextInternalIndex uint32 // Removed by version 2 70 lastUsedExternalIndex uint32 // Added in version 2 71 lastUsedInternalIndex uint32 // Added in version 2 72 lastReturnedExternalIndex uint32 // Added in version 5 73 lastReturnedInternalIndex uint32 // Added in version 5 74 name string 75 } 76 77 func (r *dbBIP0044AccountRow) accountType() accountType { return actBIP0044Legacy } 78 func (r *dbBIP0044AccountRow) rowData() []byte { return r.dbAccountRow.rawData } 79 80 // dbBIP0044Account records both the static metadata for a BIP0044 account, as 81 // well as the variables which change over time. 82 type dbBIP0044Account struct { 83 dbAccountRow 84 pubKeyEncrypted []byte 85 privKeyEncrypted []byte 86 87 // variables subbucket is used to record remaining fields 88 lastUsedExternalIndex uint32 89 lastUsedInternalIndex uint32 90 lastReturnedExternalIndex uint32 91 lastReturnedInternalIndex uint32 92 name string 93 uniqueKey *kdf.Argon2idParams 94 } 95 96 func (a *dbBIP0044Account) accountType() accountType { return a.dbAccountRow.acctType } 97 func (a *dbBIP0044Account) rowData() []byte { return a.dbAccountRow.rawData } 98 99 func (a *dbBIP0044Account) serializeRow() []byte { 100 // Format: 101 // <len + encpubkey><len + encprivkey> 102 103 data := make([]byte, 8+len(a.pubKeyEncrypted)+len(a.privKeyEncrypted)) 104 binary.LittleEndian.PutUint32(data, uint32(len(a.pubKeyEncrypted))) 105 off := 4 106 off += copy(data[off:], a.pubKeyEncrypted) 107 binary.LittleEndian.PutUint32(data[off:], uint32(len(a.privKeyEncrypted))) 108 off += 4 109 copy(data[off:], a.privKeyEncrypted) 110 111 a.rawData = data 112 return data 113 } 114 115 func (a *dbBIP0044Account) deserializeRow(v []byte) error { 116 if len(v) < 8 { 117 err := errors.Errorf("BIP0044 account row bad len %d", len(v)) 118 return errors.E(errors.IO, err) 119 } 120 121 encPubLen := binary.LittleEndian.Uint32(v) 122 off := uint32(4) 123 encPub := append([]byte(nil), v[off:off+encPubLen]...) 124 off += encPubLen 125 encPrivLen := binary.LittleEndian.Uint32(v[off:]) 126 off += 4 127 encPriv := append([]byte(nil), v[off:off+encPrivLen]...) 128 off += encPrivLen 129 if int(off) != len(v) { 130 return errors.E(errors.IO, "extra bytes in BIP0044 account row") 131 } 132 133 a.pubKeyEncrypted = encPub 134 a.privKeyEncrypted = encPriv 135 a.rawData = v 136 return nil 137 } 138 139 // dbAddressRow houses common information stored about an address in the 140 // database. 141 type dbAddressRow struct { 142 addrType addressType 143 account uint32 144 addTime uint64 145 rawData []byte // Varies based on address type field. 146 } 147 148 // dbChainAddressRow houses additional information stored about a chained 149 // address in the database. 150 type dbChainAddressRow struct { 151 dbAddressRow 152 branch uint32 153 index uint32 154 } 155 156 // dbImportedAddressRow houses additional information stored about an imported 157 // public key address in the database. 158 type dbImportedAddressRow struct { 159 dbAddressRow 160 encryptedPubKey []byte 161 encryptedPrivKey []byte 162 } 163 164 // dbImportedAddressRow houses additional information stored about a script 165 // address in the database. 166 type dbScriptAddressRow struct { 167 dbAddressRow 168 encryptedHash []byte 169 script []byte 170 } 171 172 // Key names for various database fields. 173 var ( 174 // nullVall is null byte used as a flag value in a bucket entry 175 nullVal = []byte{0} 176 177 // Bucket names. 178 acctBucketName = []byte("acct") 179 acctVarsBucketName = []byte("acctvars") 180 addrBucketName = []byte("addr") 181 182 // addrAcctIdxBucketName is used to index account addresses 183 // Entries in this index may map: 184 // * addr hash => account id 185 // * account bucket -> addr hash => null 186 // To fetch the account of an address, lookup the value using 187 // the address hash. 188 // To fetch all addresses of an account, fetch the account bucket, iterate 189 // over the keys and fetch the address row from the addr bucket. 190 // The index needs to be updated whenever an address is created e.g. 191 // NewAddress 192 addrAcctIdxBucketName = []byte("addracctidx") 193 194 // acctNameIdxBucketName is used to create an index 195 // mapping an account name string to the corresponding 196 // account id. 197 // The index needs to be updated whenever the account name 198 // and id changes e.g. RenameAccount 199 acctNameIdxBucketName = []byte("acctnameidx") 200 201 // acctIDIdxBucketName is used to create an index 202 // mapping an account id to the corresponding 203 // account name string. 204 // The index needs to be updated whenever the account name 205 // and id changes e.g. RenameAccount 206 acctIDIdxBucketName = []byte("acctididx") 207 208 // meta is used to store meta-data about the address manager 209 // e.g. last account number 210 metaBucketName = []byte("meta") 211 212 // addrPoolMetaKeyLen is the byte length of the address pool 213 // prefixes. It is 11 bytes for the prefix and 4 bytes for 214 // the account number. 215 addrPoolMetaKeyLen = 15 216 217 // addrPoolKeyPrefixExt is the prefix for keys mapping the 218 // last used address pool index to a BIP0044 account. The 219 // BIP0044 account is appended to this slice in order to 220 // derive the key. This is the external branch. 221 // e.g. in pseudocode: 222 // key = append([]byte("addrpoolext"), []byte(account)) 223 // 224 // This was removed by database version 2. 225 addrPoolKeyPrefixExt = []byte("addrpoolext") 226 227 // addrPoolKeyPrefixInt is the prefix for keys mapping the 228 // last used address pool index to a BIP0044 account. The 229 // BIP0044 account is appended to this slice in order to 230 // derive the key. This is the internal branch. 231 // 232 // This was removed by database version 2. 233 addrPoolKeyPrefixInt = []byte("addrpoolint") 234 235 // lastAccountName is used to store the metadata - last account 236 // in the manager 237 lastAccountName = []byte("lastaccount") 238 239 // lastImportedAccountName is the metadata key use for the last imported 240 // xpub account. 241 lastImportedAccountName = []byte("lastimportedaccount") 242 243 mainBucketName = []byte("main") 244 245 // Db related key names (main bucket). 246 mgrVersionName = []byte("mgrver") 247 mgrCreateDateName = []byte("mgrcreated") 248 249 // Crypto related key names (main bucket). 250 seedName = []byte("seed") 251 masterPrivKeyName = []byte("mpriv") 252 masterPubKeyName = []byte("mpub") 253 cryptoPrivKeyName = []byte("cpriv") 254 cryptoPubKeyName = []byte("cpub") 255 cryptoScriptKeyName = []byte("cscript") // removed in db v14 256 coinTypeLegacyPrivKeyName = []byte("ctpriv") 257 coinTypeLegacyPubKeyName = []byte("ctpub") 258 coinTypeSLIP0044PrivKeyName = []byte("ctpriv-slip0044") 259 coinTypeSLIP0044PubKeyName = []byte("ctpub-slip0044") 260 watchingOnlyName = []byte("watchonly") 261 slip0044Account0RowName = []byte("slip0044acct0") 262 263 // Used addresses (used bucket). This was removed by database version 2. 264 usedAddrBucketName = []byte("usedaddrs") 265 ) 266 267 // uint32ToBytes converts a 32 bit unsigned integer into a 4-byte slice in 268 // little-endian order: 1 -> [1 0 0 0]. 269 func uint32ToBytes(number uint32) []byte { 270 buf := make([]byte, 4) 271 binary.LittleEndian.PutUint32(buf, number) 272 return buf 273 } 274 275 // stringToBytes converts a string into a variable length byte slice in 276 // little-endian order: "abc" -> [3 0 0 0 61 62 63] 277 func stringToBytes(s string) []byte { 278 // The serialized format is: 279 // <size><string> 280 // 281 // 4 bytes string size + string 282 size := len(s) 283 buf := make([]byte, 4+size) 284 copy(buf[0:4], uint32ToBytes(uint32(size))) 285 copy(buf[4:4+size], s) 286 return buf 287 } 288 289 // fetchManagerVersion fetches the current manager version from the database. 290 // Should only be called on managers in unmigrated DBs. 291 func fetchManagerVersion(ns walletdb.ReadBucket) (uint32, error) { 292 mainBucket := ns.NestedReadBucket(mainBucketName) 293 verBytes := mainBucket.Get(mgrVersionName) 294 if verBytes == nil { 295 return 0, errors.E(errors.IO, "missing address manager version") 296 } 297 version := binary.LittleEndian.Uint32(verBytes) 298 return version, nil 299 } 300 301 // putManagerVersion stores the provided version to the database. Should only 302 // be called on managers in unmigrated DBs. 303 func putManagerVersion(ns walletdb.ReadWriteBucket, version uint32) error { 304 bucket := ns.NestedReadWriteBucket(mainBucketName) 305 306 verBytes := uint32ToBytes(version) 307 err := bucket.Put(mgrVersionName, verBytes) 308 if err != nil { 309 return errors.E(errors.IO, err) 310 } 311 return nil 312 } 313 314 // fetchMasterKeyParams loads the master key parameters needed to derive them 315 // (when given the correct user-supplied passphrase) from the database. Either 316 // returned value can be nil, but in practice only the private key params will 317 // be nil for a watching-only database. 318 func fetchMasterKeyParams(ns walletdb.ReadBucket) ([]byte, []byte, error) { 319 bucket := ns.NestedReadBucket(mainBucketName) 320 321 // Load the master public key parameters. Required. 322 val := bucket.Get(masterPubKeyName) 323 if val == nil { 324 return nil, nil, errors.E(errors.IO, "missing master pubkey params") 325 } 326 pubParams := make([]byte, len(val)) 327 copy(pubParams, val) 328 329 // Load the master private key parameters if they were stored. 330 var privParams []byte 331 val = bucket.Get(masterPrivKeyName) 332 if val != nil { 333 privParams = make([]byte, len(val)) 334 copy(privParams, val) 335 } 336 337 return pubParams, privParams, nil 338 } 339 340 // putMasterKeyParams stores the master key parameters needed to derive them 341 // to the database. Either parameter can be nil in which case no value is 342 // written for the parameter. 343 func putMasterKeyParams(ns walletdb.ReadWriteBucket, pubParams, privParams []byte) error { 344 bucket := ns.NestedReadWriteBucket(mainBucketName) 345 346 if privParams != nil { 347 err := bucket.Put(masterPrivKeyName, privParams) 348 if err != nil { 349 return errors.E(errors.IO, err) 350 } 351 } 352 353 if pubParams != nil { 354 err := bucket.Put(masterPubKeyName, pubParams) 355 if err != nil { 356 return errors.E(errors.IO, err) 357 } 358 } 359 360 return nil 361 } 362 363 // fetchCoinTypeKeys loads the encrypted cointype keys which are in turn used to 364 // derive the extended keys for all accounts. If both the legacy and SLIP0044 365 // coin type keys are saved, the legacy keys are used for backwards 366 // compatibility reasons. 367 func fetchCoinTypeKeys(ns walletdb.ReadBucket) ([]byte, []byte, error) { 368 bucket := ns.NestedReadBucket(mainBucketName) 369 370 var coinTypeSLIP0044 bool 371 372 coinTypePubKeyEnc := bucket.Get(coinTypeLegacyPubKeyName) 373 if coinTypePubKeyEnc == nil { 374 coinTypeSLIP0044 = true 375 coinTypePubKeyEnc = bucket.Get(coinTypeSLIP0044PubKeyName) 376 } 377 if coinTypePubKeyEnc == nil { 378 return nil, nil, errors.E(errors.IO, "missing encrypted cointype pubkey") 379 } 380 381 coinTypePrivKeyName := coinTypeLegacyPrivKeyName 382 if coinTypeSLIP0044 { 383 coinTypePrivKeyName = coinTypeSLIP0044PrivKeyName 384 } 385 coinTypePrivKeyEnc := bucket.Get(coinTypePrivKeyName) 386 if coinTypePrivKeyEnc == nil { 387 return nil, nil, errors.E(errors.IO, "missing encrypted cointype privkey") 388 } 389 390 return coinTypePubKeyEnc, coinTypePrivKeyEnc, nil 391 } 392 393 // putCoinTypeLegacyKeys stores the encrypted legacy cointype keys which are in 394 // turn used to derive the extended keys for all accounts. Either parameter can 395 // be nil in which case no value is written for the parameter. 396 func putCoinTypeLegacyKeys(ns walletdb.ReadWriteBucket, coinTypePubKeyEnc []byte, coinTypePrivKeyEnc []byte) error { 397 bucket := ns.NestedReadWriteBucket(mainBucketName) 398 399 if coinTypePubKeyEnc != nil { 400 err := bucket.Put(coinTypeLegacyPubKeyName, coinTypePubKeyEnc) 401 if err != nil { 402 return errors.E(errors.IO, err) 403 } 404 } 405 406 if coinTypePrivKeyEnc != nil { 407 err := bucket.Put(coinTypeLegacyPrivKeyName, coinTypePrivKeyEnc) 408 if err != nil { 409 return errors.E(errors.IO, err) 410 } 411 } 412 413 return nil 414 } 415 416 // putCoinTypeSLIP0044Keys stores the encrypted SLIP0044 cointype keys which are 417 // in turn used to derive the extended keys for all accounts. Either parameter 418 // can be nil in which case no value is written for the parameter. 419 func putCoinTypeSLIP0044Keys(ns walletdb.ReadWriteBucket, coinTypePubKeyEnc []byte, coinTypePrivKeyEnc []byte) error { 420 bucket := ns.NestedReadWriteBucket(mainBucketName) 421 422 if coinTypePubKeyEnc != nil { 423 err := bucket.Put(coinTypeSLIP0044PubKeyName, coinTypePubKeyEnc) 424 if err != nil { 425 return errors.E(errors.IO, err) 426 } 427 } 428 429 if coinTypePrivKeyEnc != nil { 430 err := bucket.Put(coinTypeSLIP0044PrivKeyName, coinTypePrivKeyEnc) 431 if err != nil { 432 return errors.E(errors.IO, err) 433 } 434 } 435 436 return nil 437 } 438 439 // fetchCryptoKeys loads the encrypted crypto keys which are in turn used to 440 // protect the extended keys and imported keys. Any of the returned values can 441 // be nil, but in practice only the crypto private key will be nil for a 442 // watching-only database. 443 func fetchCryptoKeys(ns walletdb.ReadBucket) ([]byte, []byte, error) { 444 bucket := ns.NestedReadBucket(mainBucketName) 445 446 // Load the crypto public key parameters. Required. 447 val := bucket.Get(cryptoPubKeyName) 448 if val == nil { 449 return nil, nil, errors.E(errors.IO, "missing encrypted crypto pubkey") 450 } 451 pubKey := make([]byte, len(val)) 452 copy(pubKey, val) 453 454 // Load the crypto private key parameters if they were stored. 455 var privKey []byte 456 val = bucket.Get(cryptoPrivKeyName) 457 if val != nil { 458 privKey = make([]byte, len(val)) 459 copy(privKey, val) 460 } 461 462 return pubKey, privKey, nil 463 } 464 465 // putCryptoKeys stores the encrypted crypto keys which are in turn used to 466 // protect the extended and imported keys. Either parameter can be nil in which 467 // case no value is written for the parameter. 468 func putCryptoKeys(ns walletdb.ReadWriteBucket, pubKeyEncrypted, privKeyEncrypted []byte) error { 469 bucket := ns.NestedReadWriteBucket(mainBucketName) 470 471 if pubKeyEncrypted != nil { 472 err := bucket.Put(cryptoPubKeyName, pubKeyEncrypted) 473 if err != nil { 474 return errors.E(errors.IO, err) 475 } 476 } 477 478 if privKeyEncrypted != nil { 479 err := bucket.Put(cryptoPrivKeyName, privKeyEncrypted) 480 if err != nil { 481 return errors.E(errors.IO, err) 482 } 483 } 484 485 return nil 486 } 487 488 // fetchWatchingOnly loads the watching-only flag from the database. 489 func fetchWatchingOnly(ns walletdb.ReadBucket) (bool, error) { 490 bucket := ns.NestedReadBucket(mainBucketName) 491 492 buf := bucket.Get(watchingOnlyName) 493 if len(buf) != 1 { 494 return false, errors.E(errors.IO, errors.Errorf("bad watching-only flag len %d", len(buf))) 495 } 496 497 return buf[0] != 0, nil 498 } 499 500 // putWatchingOnly stores the watching-only flag to the database. 501 func putWatchingOnly(ns walletdb.ReadWriteBucket, watchingOnly bool) error { 502 bucket := ns.NestedReadWriteBucket(mainBucketName) 503 504 var encoded byte 505 if watchingOnly { 506 encoded = 1 507 } 508 509 if err := bucket.Put(watchingOnlyName, []byte{encoded}); err != nil { 510 return errors.E(errors.IO, err) 511 } 512 return nil 513 } 514 515 // deserializeAccountRow deserializes the passed serialized account information. 516 // This is used as a common base for the various account types to deserialize 517 // the common parts. 518 func deserializeAccountRow(accountID []byte, serializedAccount []byte) (*dbAccountRow, error) { 519 // The serialized account format is: 520 // <acctType><rdlen><rawdata> 521 // 522 // 1 byte acctType + 4 bytes raw data length + raw data 523 524 // Given the above, the length of the entry must be at a minimum 525 // the constant value sizes. 526 if len(serializedAccount) < 5 { 527 return nil, errors.E(errors.IO, errors.Errorf("bad account len %d", len(serializedAccount))) 528 } 529 530 row := dbAccountRow{} 531 row.acctType = accountType(serializedAccount[0]) 532 rdlen := binary.LittleEndian.Uint32(serializedAccount[1:5]) 533 row.rawData = make([]byte, rdlen) 534 copy(row.rawData, serializedAccount[5:5+rdlen]) 535 536 return &row, nil 537 } 538 539 // serializeAccountRow returns the serialization of the passed account row. 540 func serializeAccountRow(row *dbAccountRow) []byte { 541 // The serialized account format is: 542 // <acctType><rdlen><rawdata> 543 // 544 // 1 byte acctType + 4 bytes raw data length + raw data 545 rdlen := len(row.rawData) 546 buf := make([]byte, 5+rdlen) 547 buf[0] = byte(row.acctType) 548 binary.LittleEndian.PutUint32(buf[1:5], uint32(rdlen)) 549 copy(buf[5:5+rdlen], row.rawData) 550 return buf 551 } 552 553 // deserializeBIP0044AccountRow deserializes the raw data from the passed 554 // account row as a BIP0044 account. 555 func deserializeBIP0044AccountRow(accountID []byte, row *dbAccountRow, dbVersion uint32) (*dbBIP0044AccountRow, error) { 556 // The serialized BIP0044 account raw data format is: 557 // <encpubkeylen><encpubkey><encprivkeylen><encprivkey><lastusedext> 558 // <lastusedint><lastretext><lastretint><namelen><name> 559 // 560 // 4 bytes encrypted pubkey len + encrypted pubkey + 4 bytes encrypted 561 // privkey len + encrypted privkey + 4 bytes last used external index + 562 // 4 bytes last used internal index + 4 bytes last returned external + 563 // 4 bytes last returned internal + 4 bytes name len + name 564 565 // Given the above, the length of the entry must be at a minimum 566 // the constant value sizes. 567 switch { 568 case dbVersion < 5 && len(row.rawData) < 20, 569 dbVersion >= 5 && len(row.rawData) < 28: 570 return nil, errors.E(errors.IO, errors.Errorf("bip0044 account %x bad len %d", accountID, len(row.rawData))) 571 } 572 573 retRow := dbBIP0044AccountRow{ 574 dbAccountRow: *row, 575 } 576 577 pubLen := binary.LittleEndian.Uint32(row.rawData[0:4]) 578 retRow.pubKeyEncrypted = make([]byte, pubLen) 579 copy(retRow.pubKeyEncrypted, row.rawData[4:4+pubLen]) 580 offset := 4 + pubLen 581 privLen := binary.LittleEndian.Uint32(row.rawData[offset : offset+4]) 582 offset += 4 583 retRow.privKeyEncrypted = make([]byte, privLen) 584 copy(retRow.privKeyEncrypted, row.rawData[offset:offset+privLen]) 585 offset += privLen 586 switch { 587 case dbVersion == 1: 588 retRow.nextExternalIndex = binary.LittleEndian.Uint32(row.rawData[offset : offset+4]) 589 offset += 4 590 retRow.nextInternalIndex = binary.LittleEndian.Uint32(row.rawData[offset : offset+4]) 591 offset += 4 592 case dbVersion >= 2: 593 retRow.lastUsedExternalIndex = binary.LittleEndian.Uint32(row.rawData[offset : offset+4]) 594 retRow.lastUsedInternalIndex = binary.LittleEndian.Uint32(row.rawData[offset+4 : offset+8]) 595 offset += 8 596 } 597 switch { 598 case dbVersion >= 5: 599 retRow.lastReturnedExternalIndex = binary.LittleEndian.Uint32(row.rawData[offset : offset+4]) 600 retRow.lastReturnedInternalIndex = binary.LittleEndian.Uint32(row.rawData[offset+4 : offset+8]) 601 offset += 8 602 } 603 nameLen := binary.LittleEndian.Uint32(row.rawData[offset : offset+4]) 604 offset += 4 605 retRow.name = string(row.rawData[offset : offset+nameLen]) 606 607 return &retRow, nil 608 } 609 610 // serializeBIP0044AccountRow returns the serialization of the raw data field 611 // for a BIP0044 account. 612 func serializeBIP0044AccountRow(row *dbBIP0044AccountRow, dbVersion uint32) []byte { 613 // The serialized BIP0044 account raw data format is: 614 // <encpubkeylen><encpubkey><encprivkeylen><encprivkey><lastusedext> 615 // <lastusedint><lastretext><lastretint><namelen><name> 616 // 617 // 4 bytes encrypted pubkey len + encrypted pubkey + 4 bytes encrypted 618 // privkey len + encrypted privkey + 4 bytes last used external index + 619 // 4 bytes last used internal index + 4 bytes last returned external + 620 // 4 bytes last returned internal + 4 bytes name len + name 621 pubLen := uint32(len(row.pubKeyEncrypted)) 622 privLen := uint32(len(row.privKeyEncrypted)) 623 nameLen := uint32(len(row.name)) 624 rowSize := 28 + pubLen + privLen + nameLen 625 switch { 626 case dbVersion < 5: 627 rowSize -= 8 628 } 629 rawData := make([]byte, rowSize) 630 binary.LittleEndian.PutUint32(rawData[0:4], pubLen) 631 copy(rawData[4:4+pubLen], row.pubKeyEncrypted) 632 offset := 4 + pubLen 633 binary.LittleEndian.PutUint32(rawData[offset:offset+4], privLen) 634 offset += 4 635 copy(rawData[offset:offset+privLen], row.privKeyEncrypted) 636 offset += privLen 637 switch { 638 case dbVersion == 1: 639 binary.LittleEndian.PutUint32(rawData[offset:offset+4], row.nextExternalIndex) 640 offset += 4 641 binary.LittleEndian.PutUint32(rawData[offset:offset+4], row.nextInternalIndex) 642 offset += 4 643 case dbVersion >= 2: 644 binary.LittleEndian.PutUint32(rawData[offset:offset+4], row.lastUsedExternalIndex) 645 binary.LittleEndian.PutUint32(rawData[offset+4:offset+8], row.lastUsedInternalIndex) 646 offset += 8 647 } 648 switch { 649 case dbVersion >= 5: 650 binary.LittleEndian.PutUint32(rawData[offset:offset+4], row.lastReturnedExternalIndex) 651 binary.LittleEndian.PutUint32(rawData[offset+4:offset+8], row.lastReturnedInternalIndex) 652 offset += 8 653 } 654 binary.LittleEndian.PutUint32(rawData[offset:offset+4], nameLen) 655 offset += 4 656 copy(rawData[offset:offset+nameLen], row.name) 657 return rawData 658 } 659 660 func bip0044AccountInfo(pubKeyEnc, privKeyEnc []byte, nextExtIndex, nextIntIndex, 661 lastUsedExtIndex, lastUsedIntIndex, lastRetExtIndex, lastRetIntIndex uint32, 662 name string, dbVersion uint32) *dbBIP0044AccountRow { 663 664 row := &dbBIP0044AccountRow{ 665 dbAccountRow: dbAccountRow{ 666 acctType: actBIP0044Legacy, 667 rawData: nil, 668 }, 669 pubKeyEncrypted: pubKeyEnc, 670 privKeyEncrypted: privKeyEnc, 671 nextExternalIndex: 0, 672 nextInternalIndex: 0, 673 lastUsedExternalIndex: 0, 674 lastUsedInternalIndex: 0, 675 lastReturnedExternalIndex: 0, 676 lastReturnedInternalIndex: 0, 677 name: name, 678 } 679 switch { 680 case dbVersion == 1: 681 row.nextExternalIndex = nextExtIndex 682 row.nextInternalIndex = nextIntIndex 683 case dbVersion >= 2: 684 row.lastUsedExternalIndex = lastUsedExtIndex 685 row.lastUsedInternalIndex = lastUsedIntIndex 686 } 687 switch { 688 case dbVersion >= 5: 689 row.lastReturnedExternalIndex = lastRetExtIndex 690 row.lastReturnedInternalIndex = lastRetIntIndex 691 } 692 row.rawData = serializeBIP0044AccountRow(row, dbVersion) 693 return row 694 } 695 696 // forEachAccount calls the given function with each account stored in 697 // the manager, breaking early on error. 698 func forEachAccount(ns walletdb.ReadBucket, fn func(account uint32) error) error { 699 bucket := ns.NestedReadBucket(acctBucketName) 700 701 return bucket.ForEach(func(k, v []byte) error { 702 // Skip buckets. 703 if v == nil { 704 return nil 705 } 706 return fn(binary.LittleEndian.Uint32(k)) 707 }) 708 } 709 710 // fetchLastAccount retreives the last BIP0044 account from the database. 711 func fetchLastAccount(ns walletdb.ReadBucket) (uint32, error) { 712 bucket := ns.NestedReadBucket(metaBucketName) 713 714 val := bucket.Get(lastAccountName) 715 if len(val) != 4 { 716 return 0, errors.E(errors.IO, errors.Errorf("bad last account len %d", len(val))) 717 } 718 account := binary.LittleEndian.Uint32(val[0:4]) 719 return account, nil 720 } 721 722 // fetchLastAccount retreives the last imported xpub account from the 723 // database. 724 func fetchLastImportedAccount(ns walletdb.ReadBucket) (uint32, error) { 725 bucket := ns.NestedReadBucket(metaBucketName) 726 727 val := bucket.Get(lastImportedAccountName) 728 // TODO: add this, set to old imported account num in db upgrade 729 // TODO: also remove this hack 730 if len(val) == 0 { 731 return ImportedAddrAccount, nil 732 } 733 if len(val) != 4 { 734 return 0, errors.E(errors.IO, errors.Errorf("bad last imported account len %d", len(val))) 735 } 736 account := binary.LittleEndian.Uint32(val[0:4]) 737 if account <= MaxAccountNum { 738 return 0, errors.E(errors.IO, errors.Errorf("bad imported xpub account value %d", account)) 739 } 740 return account, nil 741 } 742 743 // fetchAccountName retreives the account name given an account number from 744 // the database. 745 func fetchAccountName(ns walletdb.ReadBucket, account uint32) (string, error) { 746 bucket := ns.NestedReadBucket(acctIDIdxBucketName) 747 748 val := bucket.Get(uint32ToBytes(account)) 749 if val == nil { 750 return "", errors.E(errors.NotExist, errors.Errorf("no account %d", account)) 751 } 752 offset := uint32(0) 753 nameLen := binary.LittleEndian.Uint32(val[offset : offset+4]) 754 offset += 4 755 acctName := string(val[offset : offset+nameLen]) 756 return acctName, nil 757 } 758 759 // fetchAccountByName retreives the account number given an account name 760 // from the database. 761 func fetchAccountByName(ns walletdb.ReadBucket, name string) (uint32, error) { 762 bucket := ns.NestedReadBucket(acctNameIdxBucketName) 763 764 val := bucket.Get(stringToBytes(name)) 765 if val == nil { 766 return 0, errors.E(errors.NotExist, errors.Errorf("no account %q", name)) 767 } 768 769 return binary.LittleEndian.Uint32(val), nil 770 } 771 772 // fetchAccountRow loads the row serializing details regarding an account. 773 // This function does not perform any further parsing based on the account type. 774 func fetchAccountRow(ns walletdb.ReadBucket, account uint32, dbVersion uint32) (*dbAccountRow, error) { 775 bucket := ns.NestedReadBucket(acctBucketName) 776 777 accountID := uint32ToBytes(account) 778 serializedRow := bucket.Get(accountID) 779 if serializedRow == nil { 780 return nil, errors.E(errors.NotExist, errors.Errorf("no account %d", account)) 781 } 782 783 return deserializeAccountRow(accountID, serializedRow) 784 } 785 786 // fetchAccountInfo loads information about the passed account from the 787 // database. 788 func fetchAccountInfo(ns walletdb.ReadBucket, account uint32, dbVersion uint32) (*dbBIP0044AccountRow, error) { 789 row, err := fetchAccountRow(ns, account, dbVersion) 790 if err != nil { 791 return nil, err 792 } 793 794 accountID := uint32ToBytes(account) 795 switch row.acctType { 796 case actBIP0044Legacy, importedVoting: 797 return deserializeBIP0044AccountRow(accountID, row, dbVersion) 798 } 799 800 return nil, errors.E(errors.IO, errors.Errorf("unknown account type %d", row.acctType)) 801 } 802 803 func fetchDBAccount(ns walletdb.ReadBucket, account uint32, dbVersion uint32) (dbAccount, error) { 804 row, err := fetchAccountRow(ns, account, dbVersion) 805 if err != nil { 806 return nil, err 807 } 808 809 accountID := uint32ToBytes(account) 810 switch row.acctType { 811 case actBIP0044Legacy: 812 if dbVersion >= accountVariablesVersion { 813 err := errors.Errorf("legacy BIP0044 account row unsupported "+ 814 "in db version %v", dbVersion) 815 return nil, errors.E(err) 816 } 817 return deserializeBIP0044AccountRow(accountID, row, dbVersion) 818 case actBIP0044, importedVoting: 819 bucketKey := uint32ToBytes(account) 820 varsBucket := ns.NestedReadBucket(acctVarsBucketName). 821 NestedReadBucket(bucketKey) 822 823 var r accountVarReader 824 lastUsedExt := r.getAccountUint32Var(varsBucket, acctVarLastUsedExternal) 825 lastUsedInt := r.getAccountUint32Var(varsBucket, acctVarLastUsedInternal) 826 lastRetExt := r.getAccountUint32Var(varsBucket, acctVarLastReturnedExternal) 827 lastRetInt := r.getAccountUint32Var(varsBucket, acctVarLastReturnedInternal) 828 name := r.getAccountStringVar(varsBucket, acctVarName) 829 kdfParams := r.getAccountKDFVar(varsBucket, acctVarKDF) 830 if r.err != nil { 831 return nil, errors.E(errors.IO, err) 832 } 833 834 a := new(dbBIP0044Account) 835 a.dbAccountRow = *row 836 err := a.deserializeRow(row.rawData) 837 if err != nil { 838 return nil, err 839 } 840 a.lastUsedExternalIndex = lastUsedExt 841 a.lastUsedInternalIndex = lastUsedInt 842 a.lastReturnedExternalIndex = lastRetExt 843 a.lastReturnedInternalIndex = lastRetInt 844 a.name = name 845 a.uniqueKey = kdfParams 846 847 return a, nil 848 } 849 850 return nil, errors.E(errors.IO, errors.Errorf("unknown account type %d", row.acctType)) 851 } 852 853 func accountVarsBucket(ns walletdb.ReadWriteBucket, account uint32) walletdb.ReadWriteBucket { 854 accountKey := uint32ToBytes(account) 855 return ns.NestedReadWriteBucket(acctVarsBucketName).NestedReadWriteBucket(accountKey) 856 } 857 858 // deleteAccountNameIndex deletes the given key from the account name index of the database. 859 func deleteAccountNameIndex(ns walletdb.ReadWriteBucket, name string) error { 860 bucket := ns.NestedReadWriteBucket(acctNameIdxBucketName) 861 862 // Delete the account name key 863 err := bucket.Delete(stringToBytes(name)) 864 if err != nil { 865 return errors.E(errors.IO, err) 866 } 867 return nil 868 } 869 870 // deleteAccounIdIndex deletes the given key from the account id index of the database. 871 func deleteAccountIDIndex(ns walletdb.ReadWriteBucket, account uint32) error { 872 bucket := ns.NestedReadWriteBucket(acctIDIdxBucketName) 873 874 // Delete the account id key 875 err := bucket.Delete(uint32ToBytes(account)) 876 if err != nil { 877 return errors.E(errors.IO, err) 878 } 879 return nil 880 } 881 882 // putAccountNameIndex stores the given key to the account name index of the database. 883 func putAccountNameIndex(ns walletdb.ReadWriteBucket, account uint32, name string) error { 884 bucket := ns.NestedReadWriteBucket(acctNameIdxBucketName) 885 886 // Write the account number keyed by the account name. 887 err := bucket.Put(stringToBytes(name), uint32ToBytes(account)) 888 if err != nil { 889 return errors.E(errors.IO, err) 890 } 891 return nil 892 } 893 894 // putAccountIDIndex stores the given key to the account id index of the database. 895 func putAccountIDIndex(ns walletdb.ReadWriteBucket, account uint32, name string) error { 896 bucket := ns.NestedReadWriteBucket(acctIDIdxBucketName) 897 898 // Write the account number keyed by the account id. 899 err := bucket.Put(uint32ToBytes(account), stringToBytes(name)) 900 if err != nil { 901 return errors.E(errors.IO, err) 902 } 903 return nil 904 } 905 906 // putAddrAccountIndex stores the given key to the address account index of the database. 907 func putAddrAccountIndex(ns walletdb.ReadWriteBucket, account uint32, addrHash []byte) error { 908 bucket := ns.NestedReadWriteBucket(addrAcctIdxBucketName) 909 910 // Write account keyed by address hash 911 err := bucket.Put(addrHash, uint32ToBytes(account)) 912 if err != nil { 913 return errors.E(errors.IO, err) 914 } 915 916 bucket, err = bucket.CreateBucketIfNotExists(uint32ToBytes(account)) 917 if err != nil { 918 return errors.E(errors.IO, err) 919 } 920 // In account bucket, write a null value keyed by the address hash 921 err = bucket.Put(addrHash, nullVal) 922 if err != nil { 923 return errors.E(errors.IO, err) 924 } 925 return nil 926 } 927 928 // putAccountRow stores the provided account information to the database. This 929 // is used a common base for storing the various account types. 930 func putAccountRow(ns walletdb.ReadWriteBucket, account uint32, row *dbAccountRow) error { 931 bucket := ns.NestedReadWriteBucket(acctBucketName) 932 933 // Write the serialized value keyed by the account number. 934 err := bucket.Put(uint32ToBytes(account), serializeAccountRow(row)) 935 if err != nil { 936 return errors.E(errors.IO, err) 937 } 938 return nil 939 } 940 941 // putBIP0044AccountInfo stores the provided account information to the database. 942 func putBIP0044AccountInfo(ns walletdb.ReadWriteBucket, account uint32, row *dbBIP0044AccountRow) error { 943 if err := putAccountRow(ns, account, &row.dbAccountRow); err != nil { 944 return err 945 } 946 // Update account id index 947 if err := putAccountIDIndex(ns, account, row.name); err != nil { 948 return err 949 } 950 // Update account name index 951 return putAccountNameIndex(ns, account, row.name) 952 } 953 954 // putNewBIP0044Account writes a new account to the database, storing the 955 // account row and all account variables. 956 func putNewBIP0044Account(ns walletdb.ReadWriteBucket, account uint32, a *dbBIP0044Account) error { 957 err := putAccountRow(ns, account, &a.dbAccountRow) 958 if err != nil { 959 return err 960 } 961 // Index the account by name 962 err = putAccountIDIndex(ns, account, a.name) 963 if err != nil { 964 return err 965 } 966 err = putAccountNameIndex(ns, account, a.name) 967 if err != nil { 968 return err 969 } 970 // Create the bucket for this account's variables 971 bucketKey := uint32ToBytes(account) 972 varsBucket, err := ns.NestedReadWriteBucket(acctVarsBucketName). 973 CreateBucketIfNotExists(bucketKey) 974 if err != nil { 975 return err 976 } 977 // Write the account's variables 978 err = putAccountUint32Var(varsBucket, acctVarLastUsedExternal, a.lastUsedExternalIndex) 979 if err != nil { 980 return err 981 } 982 err = putAccountUint32Var(varsBucket, acctVarLastUsedInternal, a.lastUsedInternalIndex) 983 if err != nil { 984 return err 985 } 986 err = putAccountUint32Var(varsBucket, acctVarLastReturnedExternal, a.lastReturnedExternalIndex) 987 if err != nil { 988 return err 989 } 990 err = putAccountUint32Var(varsBucket, acctVarLastReturnedInternal, a.lastReturnedInternalIndex) 991 if err != nil { 992 return err 993 } 994 err = putAccountStringVar(varsBucket, acctVarName, a.name) 995 if err != nil { 996 return err 997 } 998 if a.uniqueKey != nil { 999 err = putAccountKDFVar(varsBucket, acctVarKDF, a.uniqueKey) 1000 if err != nil { 1001 return err 1002 } 1003 } 1004 1005 return nil 1006 } 1007 1008 // putLastAccount stores the provided metadata - last account - to the database. 1009 func putLastAccount(ns walletdb.ReadWriteBucket, account uint32) error { 1010 bucket := ns.NestedReadWriteBucket(metaBucketName) 1011 1012 err := bucket.Put(lastAccountName, uint32ToBytes(account)) 1013 if err != nil { 1014 return errors.E(errors.IO, err) 1015 } 1016 return nil 1017 } 1018 1019 // putLastImportedAccount stores the provided metadata - last account - to the database. 1020 func putLastImportedAccount(ns walletdb.ReadWriteBucket, account uint32) error { 1021 bucket := ns.NestedReadWriteBucket(metaBucketName) 1022 1023 err := bucket.Put(lastImportedAccountName, uint32ToBytes(account)) 1024 if err != nil { 1025 return errors.E(errors.IO, err) 1026 } 1027 return nil 1028 } 1029 1030 // Account variable keys 1031 var ( 1032 acctVarLastUsedExternal = []byte("extused") 1033 acctVarLastUsedInternal = []byte("intused") 1034 acctVarLastReturnedExternal = []byte("extret") 1035 acctVarLastReturnedInternal = []byte("intret") 1036 acctVarName = []byte("name") 1037 acctVarKDF = []byte("kdf-params") 1038 ) 1039 1040 func putAccountUint32Var(varsBucket walletdb.ReadWriteBucket, varName []byte, value uint32) error { 1041 v := make([]byte, 4) 1042 binary.LittleEndian.PutUint32(v, value) 1043 err := varsBucket.Put(varName, v) 1044 if err != nil { 1045 return errors.E(errors.IO, err) 1046 } 1047 return nil 1048 } 1049 1050 func putAccountStringVar(varsBucket walletdb.ReadWriteBucket, varName []byte, value string) error { 1051 err := varsBucket.Put(varName, []byte(value)) 1052 if err != nil { 1053 return errors.E(errors.IO, err) 1054 } 1055 return nil 1056 } 1057 1058 func putAccountKDFVar(varsBucket walletdb.ReadWriteBucket, varName []byte, value *kdf.Argon2idParams) error { 1059 marshaled, err := value.MarshalBinary() 1060 if err != nil { 1061 return err 1062 } 1063 err = varsBucket.Put(varName, marshaled) 1064 if err != nil { 1065 return errors.E(errors.IO, err) 1066 } 1067 return nil 1068 } 1069 1070 type accountVarReader struct { 1071 err error 1072 } 1073 1074 func (r *accountVarReader) getAccountUint32Var(varsBucket walletdb.ReadBucket, varName []byte) uint32 { 1075 if r.err != nil { 1076 return 0 1077 } 1078 value := varsBucket.Get(varName) 1079 if len(value) != 4 { 1080 err := errors.Errorf(`bad len %d for uint32 value "%s"`, len(value), varName) 1081 r.err = errors.E(errors.IO, err) 1082 return 0 1083 } 1084 return binary.LittleEndian.Uint32(value) 1085 } 1086 1087 func (r *accountVarReader) getAccountStringVar(varsBucket walletdb.ReadBucket, varName []byte) string { 1088 if r.err != nil { 1089 return "" 1090 } 1091 value := varsBucket.Get(varName) 1092 return string(value) 1093 } 1094 1095 func (r *accountVarReader) getAccountKDFVar(varsBucket walletdb.ReadBucket, varName []byte) *kdf.Argon2idParams { 1096 if r.err != nil { 1097 return nil 1098 } 1099 value := varsBucket.Get(varName) 1100 if value == nil { 1101 return nil 1102 } 1103 params := new(kdf.Argon2idParams) 1104 r.err = params.UnmarshalBinary(value) 1105 return params 1106 } 1107 1108 // deserializeAddressRow deserializes the passed serialized address information. 1109 // This is used as a common base for the various address types to deserialize 1110 // the common parts. 1111 func deserializeAddressRow(serializedAddress []byte) (*dbAddressRow, error) { 1112 // The serialized address format is: 1113 // <addrType><account><addedTime><syncStatus><rawdata> 1114 // 1115 // 1 byte addrType + 4 bytes account + 8 bytes addTime + 1 byte 1116 // syncStatus + 4 bytes raw data length + raw data 1117 1118 // Given the above, the length of the entry must be at a minimum 1119 // the constant value sizes. 1120 if len(serializedAddress) < 18 { 1121 return nil, errors.E(errors.IO, errors.Errorf("bad address len %d", len(serializedAddress))) 1122 } 1123 1124 row := dbAddressRow{} 1125 row.addrType = addressType(serializedAddress[0]) 1126 row.account = binary.LittleEndian.Uint32(serializedAddress[1:5]) 1127 row.addTime = binary.LittleEndian.Uint64(serializedAddress[5:13]) 1128 rdlen := binary.LittleEndian.Uint32(serializedAddress[14:18]) 1129 row.rawData = make([]byte, rdlen) 1130 copy(row.rawData, serializedAddress[18:18+rdlen]) 1131 1132 return &row, nil 1133 } 1134 1135 // serializeAddressRow returns the serialization of the passed address row. 1136 func serializeAddressRow(row *dbAddressRow) []byte { 1137 // The serialized address format is: 1138 // <addrType><account><addedTime><syncStatus><commentlen><comment> 1139 // <rawdata> 1140 // 1141 // 1 byte addrType + 4 bytes account + 8 bytes addTime + 1 byte 1142 // syncStatus + 4 bytes raw data length + raw data 1143 rdlen := len(row.rawData) 1144 buf := make([]byte, 18+rdlen) 1145 buf[0] = byte(row.addrType) 1146 binary.LittleEndian.PutUint32(buf[1:5], row.account) 1147 binary.LittleEndian.PutUint64(buf[5:13], row.addTime) 1148 buf[13] = 0 // not used 1149 binary.LittleEndian.PutUint32(buf[14:18], uint32(rdlen)) 1150 copy(buf[18:18+rdlen], row.rawData) 1151 return buf 1152 } 1153 1154 // deserializeChainedAddress deserializes the raw data from the passed address 1155 // row as a chained address. 1156 func deserializeChainedAddress(row *dbAddressRow) (*dbChainAddressRow, error) { 1157 // The serialized chain address raw data format is: 1158 // <branch><index> 1159 // 1160 // 4 bytes branch + 4 bytes address index 1161 if len(row.rawData) != 8 { 1162 return nil, errors.E(errors.IO, errors.Errorf("bad chained address len %d", len(row.rawData))) 1163 } 1164 1165 retRow := dbChainAddressRow{ 1166 dbAddressRow: *row, 1167 } 1168 1169 retRow.branch = binary.LittleEndian.Uint32(row.rawData[0:4]) 1170 retRow.index = binary.LittleEndian.Uint32(row.rawData[4:8]) 1171 1172 return &retRow, nil 1173 } 1174 1175 // serializeChainedAddress returns the serialization of the raw data field for 1176 // a chained address. 1177 func serializeChainedAddress(branch, index uint32) []byte { 1178 // The serialized chain address raw data format is: 1179 // <branch><index> 1180 // 1181 // 4 bytes branch + 4 bytes address index 1182 rawData := make([]byte, 8) 1183 binary.LittleEndian.PutUint32(rawData[0:4], branch) 1184 binary.LittleEndian.PutUint32(rawData[4:8], index) 1185 return rawData 1186 } 1187 1188 // deserializeImportedAddress deserializes the raw data from the passed address 1189 // row as an imported address. 1190 func deserializeImportedAddress(row *dbAddressRow) (*dbImportedAddressRow, error) { 1191 // The serialized imported address raw data format is: 1192 // <encpubkeylen><encpubkey><encprivkeylen><encprivkey> 1193 // 1194 // 4 bytes encrypted pubkey len + encrypted pubkey + 4 bytes encrypted 1195 // privkey len + encrypted privkey 1196 1197 // Given the above, the length of the entry must be at a minimum 1198 // the constant value sizes. 1199 if len(row.rawData) < 8 { 1200 return nil, errors.E(errors.IO, errors.Errorf("bad imported address len %d", len(row.rawData))) 1201 } 1202 1203 retRow := dbImportedAddressRow{ 1204 dbAddressRow: *row, 1205 } 1206 1207 pubLen := binary.LittleEndian.Uint32(row.rawData[0:4]) 1208 retRow.encryptedPubKey = make([]byte, pubLen) 1209 copy(retRow.encryptedPubKey, row.rawData[4:4+pubLen]) 1210 offset := 4 + pubLen 1211 privLen := binary.LittleEndian.Uint32(row.rawData[offset : offset+4]) 1212 offset += 4 1213 retRow.encryptedPrivKey = make([]byte, privLen) 1214 copy(retRow.encryptedPrivKey, row.rawData[offset:offset+privLen]) 1215 1216 return &retRow, nil 1217 } 1218 1219 // serializeImportedAddress returns the serialization of the raw data field for 1220 // an imported address. 1221 func serializeImportedAddress(encryptedPubKey, encryptedPrivKey []byte) []byte { 1222 // The serialized imported address raw data format is: 1223 // <encpubkeylen><encpubkey><encprivkeylen><encprivkey> 1224 // 1225 // 4 bytes encrypted pubkey len + encrypted pubkey + 4 bytes encrypted 1226 // privkey len + encrypted privkey 1227 pubLen := uint32(len(encryptedPubKey)) 1228 privLen := uint32(len(encryptedPrivKey)) 1229 rawData := make([]byte, 8+pubLen+privLen) 1230 binary.LittleEndian.PutUint32(rawData[0:4], pubLen) 1231 copy(rawData[4:4+pubLen], encryptedPubKey) 1232 offset := 4 + pubLen 1233 binary.LittleEndian.PutUint32(rawData[offset:offset+4], privLen) 1234 offset += 4 1235 copy(rawData[offset:offset+privLen], encryptedPrivKey) 1236 return rawData 1237 } 1238 1239 // deserializeScriptAddress deserializes the raw data from the passed address 1240 // row as a script address. 1241 func deserializeScriptAddress(row *dbAddressRow) (*dbScriptAddressRow, error) { 1242 // The serialized script address raw data format is: 1243 // <encscripthashlen><encscripthash><scriptlen><script> 1244 // 1245 // 4 bytes encrypted script hash len + encrypted script hash + 4 bytes 1246 // script len + script 1247 1248 // Given the above, the length of the entry must be at a minimum 1249 // the constant value sizes. 1250 if len(row.rawData) < 8 { 1251 return nil, errors.E(errors.IO, errors.Errorf("bad script address len %d", len(row.rawData))) 1252 } 1253 1254 retRow := dbScriptAddressRow{ 1255 dbAddressRow: *row, 1256 } 1257 1258 hashLen := binary.LittleEndian.Uint32(row.rawData[0:4]) 1259 retRow.encryptedHash = make([]byte, hashLen) 1260 copy(retRow.encryptedHash, row.rawData[4:4+hashLen]) 1261 offset := 4 + hashLen 1262 scriptLen := binary.LittleEndian.Uint32(row.rawData[offset : offset+4]) 1263 offset += 4 1264 retRow.script = make([]byte, scriptLen) 1265 copy(retRow.script, row.rawData[offset:offset+scriptLen]) 1266 1267 return &retRow, nil 1268 } 1269 1270 // serializeScriptAddress returns the serialization of the raw data field for 1271 // a script address. 1272 func serializeScriptAddress(encryptedHash, script []byte) []byte { 1273 // The serialized script address raw data format is: 1274 // <encscripthashlen><encscripthash><scriptlen><script> 1275 // 1276 // 4 bytes encrypted script hash len + encrypted script hash + 4 bytes 1277 // script len + script 1278 1279 hashLen := uint32(len(encryptedHash)) 1280 scriptLen := uint32(len(script)) 1281 rawData := make([]byte, 8+hashLen+scriptLen) 1282 binary.LittleEndian.PutUint32(rawData[0:4], hashLen) 1283 copy(rawData[4:4+hashLen], encryptedHash) 1284 offset := 4 + hashLen 1285 binary.LittleEndian.PutUint32(rawData[offset:offset+4], scriptLen) 1286 offset += 4 1287 copy(rawData[offset:offset+scriptLen], script) 1288 return rawData 1289 } 1290 1291 // fetchAddressByHash loads address information for the provided address hash 1292 // from the database. The returned value is one of the address rows for the 1293 // specific address type. The caller should use type assertions to ascertain 1294 // the type. The caller should prefix the error message with the address hash 1295 // which caused the failure. 1296 func fetchAddressByHash(ns walletdb.ReadBucket, addrHash []byte) (interface{}, error) { 1297 bucket := ns.NestedReadBucket(addrBucketName) 1298 1299 serializedRow := bucket.Get(addrHash) 1300 if serializedRow == nil { 1301 return nil, errors.E(errors.NotExist, errors.Errorf("no address with hash %x", addrHash)) 1302 } 1303 1304 row, err := deserializeAddressRow(serializedRow) 1305 if err != nil { 1306 return nil, err 1307 } 1308 1309 switch row.addrType { 1310 case adtChain: 1311 return deserializeChainedAddress(row) 1312 case adtImport: 1313 return deserializeImportedAddress(row) 1314 case adtScript: 1315 return deserializeScriptAddress(row) 1316 } 1317 1318 return nil, errors.E(errors.IO, errors.Errorf("unknown address type %d", row.addrType)) 1319 } 1320 1321 // fetchAddress loads address information for the provided address id from the 1322 // database. The returned value is one of the address rows for the specific 1323 // address type. The caller should use type assertions to ascertain the type. 1324 // The caller should prefix the error message with the address which caused the 1325 // failure. 1326 func fetchAddress(ns walletdb.ReadBucket, addressID []byte) (interface{}, error) { 1327 addrHash := sha256.Sum256(addressID) 1328 addr, err := fetchAddressByHash(ns, addrHash[:]) 1329 if errors.Is(err, errors.NotExist) { 1330 return nil, errors.E(errors.NotExist, errors.Errorf("no address with id %x", addressID)) 1331 } 1332 return addr, err 1333 } 1334 1335 // putAddress stores the provided address information to the database. This 1336 // is used a common base for storing the various address types. 1337 func putAddress(ns walletdb.ReadWriteBucket, addressID []byte, row *dbAddressRow) error { 1338 bucket := ns.NestedReadWriteBucket(addrBucketName) 1339 1340 // Write the serialized value keyed by the hash of the address. The 1341 // additional hash is used to conceal the actual address while still 1342 // allowed keyed lookups. 1343 addrHash := sha256.Sum256(addressID) 1344 err := bucket.Put(addrHash[:], serializeAddressRow(row)) 1345 if err != nil { 1346 return errors.E(errors.IO, err) 1347 } 1348 // Update address account index 1349 return putAddrAccountIndex(ns, row.account, addrHash[:]) 1350 } 1351 1352 // putChainedAddress stores the provided chained address information to the 1353 // database. 1354 func putChainedAddress(ns walletdb.ReadWriteBucket, addressID []byte, account uint32, 1355 branch, index uint32) error { 1356 1357 addrRow := dbAddressRow{ 1358 addrType: adtChain, 1359 account: account, 1360 addTime: uint64(time.Now().Unix()), 1361 rawData: serializeChainedAddress(branch, index), 1362 } 1363 return putAddress(ns, addressID, &addrRow) 1364 } 1365 1366 // putImportedAddress stores the provided imported address information to the 1367 // database. 1368 func putImportedAddress(ns walletdb.ReadWriteBucket, addressID []byte, account uint32, 1369 encryptedPubKey, encryptedPrivKey []byte) error { 1370 1371 rawData := serializeImportedAddress(encryptedPubKey, encryptedPrivKey) 1372 addrRow := dbAddressRow{ 1373 addrType: adtImport, 1374 account: account, 1375 addTime: uint64(time.Now().Unix()), 1376 rawData: rawData, 1377 } 1378 return putAddress(ns, addressID, &addrRow) 1379 } 1380 1381 // putScriptAddress stores the provided script address information to the 1382 // database. 1383 func putScriptAddress(ns walletdb.ReadWriteBucket, addressID []byte, account uint32, 1384 encryptedHash, script []byte) error { 1385 1386 rawData := serializeScriptAddress(encryptedHash, script) 1387 addrRow := dbAddressRow{ 1388 addrType: adtScript, 1389 account: account, 1390 addTime: uint64(time.Now().Unix()), 1391 rawData: rawData, 1392 } 1393 return putAddress(ns, addressID, &addrRow) 1394 } 1395 1396 // existsAddress returns whether or not the address id exists in the database. 1397 func existsAddress(ns walletdb.ReadBucket, addressID []byte) bool { 1398 bucket := ns.NestedReadBucket(addrBucketName) 1399 1400 addrHash := sha256.Sum256(addressID) 1401 return bucket.Get(addrHash[:]) != nil 1402 } 1403 1404 // fetchAddrAccount returns the account to which the given address belongs to. 1405 // It looks up the account using the addracctidx index which maps the address 1406 // hash to its corresponding account id. 1407 func fetchAddrAccount(ns walletdb.ReadBucket, addressID []byte) (uint32, error) { 1408 bucket := ns.NestedReadBucket(addrAcctIdxBucketName) 1409 1410 addrHash := sha256.Sum256(addressID) 1411 val := bucket.Get(addrHash[:]) 1412 if val == nil { 1413 return 0, errors.E(errors.NotExist, errors.Errorf("no address for id %x", addressID)) 1414 } 1415 return binary.LittleEndian.Uint32(val), nil 1416 } 1417 1418 // forEachAccountAddress calls the given function with each address of 1419 // the given account stored in the manager, breaking early on error. 1420 func forEachAccountAddress(ns walletdb.ReadBucket, account uint32, fn func(rowInterface interface{}) error) error { 1421 bucket := ns.NestedReadBucket(addrAcctIdxBucketName). 1422 NestedReadBucket(uint32ToBytes(account)) 1423 // if index bucket is missing the account, there hasn't been any address 1424 // entries yet 1425 if bucket == nil { 1426 return nil 1427 } 1428 1429 c := bucket.ReadCursor() 1430 defer c.Close() 1431 for k, v := c.First(); k != nil; k, v = c.Next() { 1432 // Skip buckets. 1433 if v == nil { 1434 continue 1435 } 1436 addrRow, err := fetchAddressByHash(ns, k) 1437 if err != nil { 1438 return errors.E(errors.IO, err) 1439 } 1440 1441 err = fn(addrRow) 1442 if err != nil { 1443 return err 1444 } 1445 } 1446 return nil 1447 } 1448 1449 // forEachActiveAddress calls the given function with each active address 1450 // stored in the manager, breaking early on error. 1451 func forEachActiveAddress(ns walletdb.ReadBucket, fn func(rowInterface interface{}) error) error { 1452 bucket := ns.NestedReadBucket(addrBucketName) 1453 c := bucket.ReadCursor() 1454 defer c.Close() 1455 for k, v := c.First(); k != nil; k, v = c.Next() { 1456 // Skip buckets. 1457 if v == nil { 1458 continue 1459 } 1460 1461 // Deserialize the address row first to determine the field 1462 // values. 1463 addrRow, err := fetchAddressByHash(ns, k) 1464 if err != nil { 1465 return errors.E(errors.IO, err) 1466 } 1467 1468 err = fn(addrRow) 1469 if err != nil { 1470 return err 1471 } 1472 } 1473 return nil 1474 } 1475 1476 // deletePrivateKeys removes all private key material from the database. 1477 // 1478 // NOTE: Care should be taken when calling this function. It is primarily 1479 // intended for use in converting to a watching-only copy. Removing the private 1480 // keys from the main database without also marking it watching-only will result 1481 // in an unusable database. It will also make any private keys unrecoverable 1482 // unless there is a backup copy available. 1483 func deletePrivateKeys(ns walletdb.ReadWriteBucket, dbVersion uint32) error { 1484 bucket := ns.NestedReadWriteBucket(mainBucketName) 1485 1486 // Delete the master private key params and the crypto private keys. 1487 if err := bucket.Delete(masterPrivKeyName); err != nil { 1488 return errors.E(errors.IO, err) 1489 } 1490 if err := bucket.Delete(cryptoPrivKeyName); err != nil { 1491 return errors.E(errors.IO, err) 1492 } 1493 if err := bucket.Delete(coinTypeLegacyPrivKeyName); err != nil { 1494 return errors.E(errors.IO, err) 1495 } 1496 if err := bucket.Delete(coinTypeSLIP0044PrivKeyName); err != nil { 1497 return errors.E(errors.IO, err) 1498 } 1499 1500 BIP0044Set := map[string]*dbAccountRow{} 1501 1502 // Fetch all BIP0044 accounts. 1503 bucket = ns.NestedReadWriteBucket(acctBucketName) 1504 c := bucket.ReadCursor() 1505 for k, v := c.First(); k != nil; k, v = c.Next() { 1506 // Skip buckets. 1507 if v == nil { 1508 continue 1509 } 1510 1511 // Deserialize the account row first to determine the type. 1512 row, err := deserializeAccountRow(k, v) 1513 if err != nil { 1514 c.Close() 1515 return err 1516 } 1517 1518 switch row.acctType { 1519 case actBIP0044Legacy: 1520 BIP0044Set[string(k)] = row 1521 } 1522 } 1523 c.Close() 1524 1525 // Delete the account extended private key for all BIP0044 accounts. 1526 for k, row := range BIP0044Set { 1527 arow, err := deserializeBIP0044AccountRow([]byte(k), row, dbVersion) 1528 if err != nil { 1529 return err 1530 } 1531 1532 // Reserialize the account without the private key and 1533 // store it. 1534 row := bip0044AccountInfo(arow.pubKeyEncrypted, nil, 1535 arow.nextExternalIndex, arow.nextInternalIndex, 1536 arow.lastUsedExternalIndex, arow.lastUsedInternalIndex, 1537 arow.lastReturnedExternalIndex, arow.lastReturnedInternalIndex, 1538 arow.name, dbVersion) 1539 err = bucket.Put([]byte(k), serializeAccountRow(&row.dbAccountRow)) 1540 if err != nil { 1541 return errors.E(errors.IO, err) 1542 } 1543 } 1544 1545 importedAddrSet := map[string]*dbAddressRow{} 1546 1547 // Fetch all imported addresses. 1548 bucket = ns.NestedReadWriteBucket(addrBucketName) 1549 c = bucket.ReadCursor() 1550 for k, v := c.First(); k != nil; k, v = c.Next() { 1551 // Skip buckets. 1552 if v == nil { 1553 continue 1554 } 1555 1556 // Deserialize the address row first to determine the field 1557 // values. 1558 row, err := deserializeAddressRow(v) 1559 if err != nil { 1560 c.Close() 1561 return err 1562 } 1563 1564 switch row.addrType { 1565 case adtImport: 1566 importedAddrSet[string(k)] = row 1567 } 1568 } 1569 c.Close() 1570 1571 // Delete the private key for all imported addresses. 1572 for k, row := range importedAddrSet { 1573 irow, err := deserializeImportedAddress(row) 1574 if err != nil { 1575 return err 1576 } 1577 1578 // Reserialize the imported address without the private 1579 // key and store it. 1580 row.rawData = serializeImportedAddress( 1581 irow.encryptedPubKey, nil) 1582 err = bucket.Put([]byte(k), serializeAddressRow(row)) 1583 if err != nil { 1584 return errors.E(errors.IO, err) 1585 } 1586 } 1587 1588 return nil 1589 } 1590 1591 // accountNumberToAddrPoolKey converts an account into a meta-bucket key for 1592 // the storage of the next to use address index as the value. 1593 func accountNumberToAddrPoolKey(isInternal bool, account uint32) []byte { 1594 k := make([]byte, addrPoolMetaKeyLen) 1595 if isInternal { 1596 copy(k, addrPoolKeyPrefixInt) 1597 binary.LittleEndian.PutUint32(k[addrPoolMetaKeyLen-4:], account) 1598 } else { 1599 copy(k, addrPoolKeyPrefixExt) 1600 binary.LittleEndian.PutUint32(k[addrPoolMetaKeyLen-4:], account) 1601 } 1602 1603 return k 1604 } 1605 1606 // putNextToUseAddrPoolIdx stores an address pool address index for a 1607 // given account and branch in the meta bucket of the address manager 1608 // database. 1609 func putNextToUseAddrPoolIdx(ns walletdb.ReadWriteBucket, isInternal bool, account uint32, index uint32) error { 1610 bucket := ns.NestedReadWriteBucket(metaBucketName) 1611 k := accountNumberToAddrPoolKey(isInternal, account) 1612 v := make([]byte, 4) 1613 binary.LittleEndian.PutUint32(v, index) 1614 1615 err := bucket.Put(k, v) 1616 if err != nil { 1617 return errors.E(errors.IO, err) 1618 } 1619 1620 return nil 1621 } 1622 1623 // managerExists returns whether or not the manager has already been created 1624 // in the given database namespace. 1625 func managerExists(ns walletdb.ReadBucket) bool { 1626 mainBucket := ns.NestedReadBucket(mainBucketName) 1627 return mainBucket != nil 1628 } 1629 1630 // createManagerNS creates the initial namespace structure needed for all of the 1631 // manager data. This includes things such as all of the buckets as well as the 1632 // version and creation date. 1633 func createManagerNS(ns walletdb.ReadWriteBucket) error { 1634 mainBucket, err := ns.CreateBucket(mainBucketName) 1635 if err != nil { 1636 return errors.E(errors.IO, err) 1637 } 1638 1639 _, err = ns.CreateBucket(addrBucketName) 1640 if err != nil { 1641 return errors.E(errors.IO, err) 1642 } 1643 1644 _, err = ns.CreateBucket(acctBucketName) 1645 if err != nil { 1646 return errors.E(errors.IO, err) 1647 } 1648 1649 _, err = ns.CreateBucket(addrAcctIdxBucketName) 1650 if err != nil { 1651 return errors.E(errors.IO, err) 1652 } 1653 1654 // usedAddrBucketName bucket was added after manager version 1 release 1655 _, err = ns.CreateBucket(usedAddrBucketName) 1656 if err != nil { 1657 return errors.E(errors.IO, err) 1658 } 1659 1660 _, err = ns.CreateBucket(acctNameIdxBucketName) 1661 if err != nil { 1662 return errors.E(errors.IO, err) 1663 } 1664 1665 _, err = ns.CreateBucket(acctIDIdxBucketName) 1666 if err != nil { 1667 return errors.E(errors.IO, err) 1668 } 1669 1670 _, err = ns.CreateBucket(metaBucketName) 1671 if err != nil { 1672 return errors.E(errors.IO, err) 1673 } 1674 1675 if err := putLastAccount(ns, DefaultAccountNum); err != nil { 1676 return err 1677 } 1678 1679 if err := putManagerVersion(ns, latestMgrVersion); err != nil { 1680 return err 1681 } 1682 1683 createDate := uint64(time.Now().Unix()) 1684 var dateBytes [8]byte 1685 binary.LittleEndian.PutUint64(dateBytes[:], createDate) 1686 err = mainBucket.Put(mgrCreateDateName, dateBytes[:]) 1687 if err != nil { 1688 return errors.E(errors.IO, err) 1689 } 1690 1691 return nil 1692 } 1693 1694 // upgradeToVersion5 upgrades the database from version 4 to version 5. 1695 // Version 5 uses the metadata bucket to store the address pool indexes, 1696 // so lastAddrs can be removed from the db. 1697 func upgradeToVersion5(ns walletdb.ReadWriteBucket) error { 1698 lastDefaultAddsrName := []byte("lastaddrs") 1699 1700 bucket := ns.NestedReadWriteBucket(mainBucketName) 1701 err := bucket.Delete(lastDefaultAddsrName) 1702 if err != nil { 1703 return errors.E(errors.IO, err) 1704 } 1705 1706 return putManagerVersion(ns, 5) 1707 } 1708 1709 // upgradeToVersion6 upgrades the database from version 5 to 6. Version 6 1710 // removes the synchronization buckets that were no longer updated after 1711 // switching the wallet to storing all block headers. 1712 func upgradeToVersion6(ns walletdb.ReadWriteBucket) error { 1713 syncBucketName := []byte("sync") 1714 err := ns.DeleteNestedBucket(syncBucketName) 1715 if err != nil { 1716 return errors.E(errors.IO, err) 1717 } 1718 return putManagerVersion(ns, 6) 1719 } 1720 1721 // upgradeManager upgrades the data in the provided manager namespace to newer 1722 // versions as neeeded. 1723 func upgradeManager(ns walletdb.ReadWriteBucket) error { 1724 version, err := fetchManagerVersion(ns) 1725 if err != nil { 1726 return err 1727 } 1728 1729 // Below is some example code on how to properly perform DB 1730 // upgrades. Use it as a model for future upgrades. 1731 // 1732 // Upgrade one version at a time so it is possible to upgrade across 1733 // an aribtary number of versions without needing to write a bunch of 1734 // additional code to go directly from version X to Y. 1735 // if version < 2 { 1736 // // Upgrade from version 1 to 2. 1737 // if err := upgradeToVersion2(namespace); err != nil { 1738 // return err 1739 // } 1740 // 1741 // // The manager is now at version 2. 1742 // version = 2 1743 // } 1744 // if version < 3 { 1745 // // Upgrade from version 2 to 3. 1746 // if err := upgradeToVersion3(namespace); err != nil { 1747 // return err 1748 // } 1749 // 1750 // // The manager is now at version 3. 1751 // version = 3 1752 // } 1753 1754 if version < 5 { 1755 err := upgradeToVersion5(ns) 1756 if err != nil { 1757 return err 1758 } 1759 1760 // The manager is now at version 5. 1761 version = 5 1762 } 1763 1764 if version < 6 { 1765 err := upgradeToVersion6(ns) 1766 if err != nil { 1767 return err 1768 } 1769 1770 // The manager is now at version 6. 1771 version = 6 1772 } 1773 1774 // Ensure the manager version is equal to the version used by the code. 1775 // This causes failures if the database was not upgraded to the latest 1776 // version or if there is a newer version that this code does not 1777 // understand. 1778 if version != latestMgrVersion { 1779 return errors.E(errors.Invalid, errors.Errorf("incompatible address manager version %d", version)) 1780 } 1781 1782 return nil 1783 }