| 290 | } |
| 291 | |
| 292 | bool LoadKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr) |
| 293 | { |
| 294 | LOCK(pwallet->cs_wallet); |
| 295 | try { |
| 296 | CPubKey vchPubKey; |
| 297 | ssKey >> vchPubKey; |
| 298 | if (!vchPubKey.IsValid()) |
| 299 | { |
| 300 | strErr = "Error reading wallet database: CPubKey corrupt"; |
| 301 | return false; |
| 302 | } |
| 303 | CKey key; |
| 304 | CPrivKey pkey; |
| 305 | uint256 hash; |
| 306 | |
| 307 | ssValue >> pkey; |
| 308 | |
| 309 | // Old wallets store keys as DBKeys::KEY [pubkey] => [privkey] |
| 310 | // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key |
| 311 | // using EC operations as a checksum. |
| 312 | // Newer wallets store keys as DBKeys::KEY [pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while |
| 313 | // remaining backwards-compatible. |
| 314 | try |
| 315 | { |
| 316 | ssValue >> hash; |
| 317 | } |
| 318 | catch (const std::ios_base::failure&) {} |
| 319 | |
| 320 | bool fSkipCheck = false; |
| 321 | |
| 322 | if (!hash.IsNull()) |
| 323 | { |
| 324 | // hash pubkey/privkey to accelerate wallet load |
| 325 | const auto keypair_hash = Hash(vchPubKey, pkey); |
| 326 | |
| 327 | if (keypair_hash != hash) |
| 328 | { |
| 329 | strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt"; |
| 330 | return false; |
| 331 | } |
| 332 | |
| 333 | fSkipCheck = true; |
| 334 | } |
| 335 | |
| 336 | if (!key.Load(pkey, vchPubKey, fSkipCheck)) |
| 337 | { |
| 338 | strErr = "Error reading wallet database: CPrivKey corrupt"; |
| 339 | return false; |
| 340 | } |
| 341 | if (!pwallet->GetOrCreateLegacyDataSPKM()->LoadKey(key, vchPubKey)) |
| 342 | { |
| 343 | strErr = "Error reading wallet database: LegacyDataSPKM::LoadKey failed"; |
| 344 | return false; |
| 345 | } |
| 346 | } catch (const std::exception& e) { |
| 347 | if (strErr.empty()) { |
| 348 | strErr = e.what(); |
| 349 | } |
no test coverage detected