| 1180 | } |
| 1181 | |
| 1182 | static auto InitBlocksdirXorKey(const BlockManager::Options& opts) |
| 1183 | { |
| 1184 | // Bytes are serialized without length indicator, so this is also the exact |
| 1185 | // size of the XOR-key file. |
| 1186 | std::array<std::byte, Obfuscation::KEY_SIZE> obfuscation{}; |
| 1187 | |
| 1188 | // Consider this to be the first run if the blocksdir contains only hidden |
| 1189 | // files (those which start with a .). Checking for a fully-empty dir would |
| 1190 | // be too aggressive as a .lock file may have already been written. |
| 1191 | bool first_run = true; |
| 1192 | for (const auto& entry : fs::directory_iterator(opts.blocks_dir)) { |
| 1193 | const std::string path = fs::PathToString(entry.path().filename()); |
| 1194 | if (!entry.is_regular_file() || !path.starts_with('.')) { |
| 1195 | first_run = false; |
| 1196 | break; |
| 1197 | } |
| 1198 | } |
| 1199 | |
| 1200 | if (opts.use_xor && first_run) { |
| 1201 | // Only use random fresh key when the boolean option is set and on the |
| 1202 | // very first start of the program. |
| 1203 | FastRandomContext{}.fillrand(obfuscation); |
| 1204 | } |
| 1205 | |
| 1206 | const fs::path xor_key_path{opts.blocks_dir / "xor.dat"}; |
| 1207 | if (fs::exists(xor_key_path)) { |
| 1208 | // A pre-existing xor key file has priority. |
| 1209 | AutoFile xor_key_file{fsbridge::fopen(xor_key_path, "rb")}; |
| 1210 | xor_key_file >> obfuscation; |
| 1211 | } else { |
| 1212 | // Create initial or missing xor key file |
| 1213 | AutoFile xor_key_file{fsbridge::fopen(xor_key_path, |
| 1214 | #ifdef __MINGW64__ |
| 1215 | "wb" // Temporary workaround for https://github.com/bitcoin/bitcoin/issues/30210 |
| 1216 | #else |
| 1217 | "wbx" |
| 1218 | #endif |
| 1219 | )}; |
| 1220 | xor_key_file << obfuscation; |
| 1221 | if (xor_key_file.fclose() != 0) { |
| 1222 | throw std::runtime_error{strprintf("Error closing XOR key file %s: %s", |
| 1223 | fs::PathToString(xor_key_path), |
| 1224 | SysErrorString(errno))}; |
| 1225 | } |
| 1226 | } |
| 1227 | // If the user disabled the key, it must be zero. |
| 1228 | if (!opts.use_xor && obfuscation != decltype(obfuscation){}) { |
| 1229 | throw std::runtime_error{ |
| 1230 | strprintf("The blocksdir XOR-key can not be disabled when a random key was already stored! " |
| 1231 | "Stored key: '%s', stored path: '%s'.", |
| 1232 | HexStr(obfuscation), fs::PathToString(xor_key_path)), |
| 1233 | }; |
| 1234 | } |
| 1235 | LogInfo("Using obfuscation key for blocksdir *.dat files (%s): '%s'\n", fs::PathToString(opts.blocks_dir), HexStr(obfuscation)); |
| 1236 | return Obfuscation{obfuscation}; |
| 1237 | } |
| 1238 | |
| 1239 | BlockManager::BlockManager(const util::SignalInterrupt& interrupt, Options opts) |
no test coverage detected