Coverage Summary for Class: BootstrapFileHandler (co.rsk.db.importer.provider)
Class |
Class, %
|
Method, %
|
Line, %
|
BootstrapFileHandler |
0%
(0/1)
|
0%
(0/9)
|
0%
(0/41)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2019 RSK Labs Ltd.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package co.rsk.db.importer.provider;
20
21 import co.rsk.db.importer.BootstrapImportException;
22 import co.rsk.db.importer.BootstrapURLProvider;
23 import co.rsk.db.importer.provider.index.data.BootstrapDataEntry;
24 import org.bouncycastle.util.encoders.Hex;
25 import org.ethereum.crypto.HashUtil;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 import java.io.*;
30 import java.net.URL;
31 import java.nio.file.Files;
32 import java.nio.file.Path;
33 import java.nio.file.StandardCopyOption;
34 import java.security.SecureRandom;
35 import java.util.*;
36
37 public class BootstrapFileHandler {
38
39 private static final Logger logger = LoggerFactory.getLogger(BootstrapFileHandler.class);
40 private static final String BOOTSTRAP_DATA_NAME = "bootstrap-data.zip";
41 private static final String EXTRACTED_PATH = "bootstrap-data.bin";
42
43 private final BootstrapURLProvider bootstrapUrlProvider;
44 private final Unzipper unzipper;
45 private Path tempPath;
46
47 public BootstrapFileHandler(
48 BootstrapURLProvider bootstrapUrlProvider,
49 Unzipper unzipper) {
50 this.bootstrapUrlProvider = bootstrapUrlProvider;
51 this.unzipper = unzipper;
52 }
53
54 // for testing purposes these 3 methods are splitted into 3 public items
55 public void setTempDirectory() {
56 this.tempPath = getTempDirectory();
57 }
58
59 public byte[] getBootstrapData() {
60 Path bootstrapPath = tempPath.resolve(EXTRACTED_PATH);
61 try {
62 return Files.readAllBytes(bootstrapPath);
63 } catch (IOException e) {
64 throw new BootstrapImportException(String.format(
65 "Failed reading data after decompression %s", bootstrapPath), e);
66
67 }
68 }
69
70 public void retrieveAndUnpack(Map<String, BootstrapDataEntry> selectedEntries) {
71 Path zipPath = tempPath.resolve(BOOTSTRAP_DATA_NAME);
72
73 List<String> publicKeys = new ArrayList<>(selectedEntries.keySet());
74 String publicKey = publicKeys.get(new SecureRandom().nextInt(publicKeys.size()));
75 String expectedHash = selectedEntries.get(publicKey).getHash();
76
77 String dbSuffix = selectedEntries.get(publicKey).getDb();
78 URL dbURL = bootstrapUrlProvider.getFullURL(dbSuffix);
79
80 downloadFile(zipPath, dbURL);
81 checkFileHash(zipPath, expectedHash);
82 unzipFile(zipPath, tempPath);
83 }
84
85 private void checkFileHash(Path databasePath, String expectedHash) {
86 try {
87 byte[] fileContent = Files.readAllBytes(databasePath);
88 byte[] hash = HashUtil.sha256(fileContent);
89 if (!Arrays.equals(hash, Hex.decode(expectedHash))) {
90 throw new BootstrapImportException(String.format(
91 "File: %s does not match with expected hash: %s", databasePath, expectedHash));
92 }
93 logger.info("Bootstrap data hash checked");
94 } catch (IOException e) {
95 throw new BootstrapImportException(
96 "Error trying to read bootstrap data contents. Please start again the import process", e);
97 }
98 }
99
100 private void unzipFile(Path sourcePath, Path destinationPath) {
101 try (InputStream inputStream = Files.newInputStream(sourcePath)){
102 unzipper.unzip(inputStream, destinationPath);
103 logger.info("Bootstrap data extracted");
104 } catch (IOException e) {
105 throw new BootstrapImportException(
106 "The file is corrupted or incomplete. Please start again the import process", e);
107 }
108 }
109
110 private Path getTempDirectory() {
111 try {
112 return Files.createTempDirectory("import");
113 } catch (IOException e) {
114 throw new BootstrapImportException(
115 "Failed to create a temporary directory. Please start again the import process", e);
116 }
117 }
118
119 private void downloadFile(Path downloadPath, URL url) {
120 try (InputStream is = url.openStream()) {
121 Files.copy(is, downloadPath, StandardCopyOption.REPLACE_EXISTING);
122 logger.info("Bootstrap data downloaded");
123 } catch (IOException e) {
124 throw new BootstrapImportException(String.format(
125 "Error downloading bootstrap data from %s. Please start again the import process", url
126 ), e);
127 }
128 }
129 }