Ethereum  PoC-8
The C++ Implementation of Ethereum
SnapshotImporter.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include "SnapshotImporter.h"
19 #include "Client.h"
20 #include "SnapshotStorage.h"
21 
22 #include <libdevcore/FileSystem.h>
23 #include <libdevcore/RLP.h>
24 #include <libdevcore/TrieHash.h>
25 #include <libethashseal/Ethash.h>
26 
27 #include <snappy.h>
28 
29 namespace dev
30 {
31 namespace eth
32 {
33 
34 void SnapshotImporter::import(SnapshotStorageFace const& _snapshotStorage, h256 const& /*_genesisHash*/)
35 {
36  bytes const manifestBytes = _snapshotStorage.readManifest();
37  RLP manifest(manifestBytes);
38 
39  // For Snapshot format see https://github.com/paritytech/parity/wiki/Warp-Sync-Snapshot-Format
40  u256 const version = manifest[0].toInt<u256>(RLP::VeryStrict);
41  if (version != 2)
42  BOOST_THROW_EXCEPTION(UnsupportedSnapshotManifestVersion());
43  if (manifest.itemCount() != 6)
44  BOOST_THROW_EXCEPTION(InvalidSnapshotManifest());
45 
46  u256 const blockNumber = manifest[4].toInt<u256>(RLP::VeryStrict);
47  h256 const blockHash = manifest[5].toHash<h256>(RLP::VeryStrict);
48  LOG(m_logger) << "Importing snapshot for block " << blockNumber << " block hash " << blockHash;
49 
50  h256s const stateChunkHashes = manifest[1].toVector<h256>(RLP::VeryStrict);
51  h256 const stateRoot = manifest[3].toHash<h256>(RLP::VeryStrict);
52  importStateChunks(_snapshotStorage, stateChunkHashes, stateRoot);
53 
54  h256s const blockChunkHashes = manifest[2].toVector<h256>(RLP::VeryStrict);
55  importBlockChunks(_snapshotStorage, blockChunkHashes);
56 }
57 
58 void SnapshotImporter::importStateChunks(SnapshotStorageFace const& _snapshotStorage, h256s const& _stateChunkHashes, h256 const& _stateRoot)
59 {
60  size_t const stateChunkCount = _stateChunkHashes.size();
61 
62  size_t chunksImported = 0;
63  size_t accountsImported = 0;
64 
65  for (auto const& stateChunkHash: _stateChunkHashes)
66  {
67  std::string const chunkUncompressed = _snapshotStorage.readChunk(stateChunkHash);
68 
69  RLP const accounts(chunkUncompressed);
70  size_t const accountCount = accounts.itemCount();
71  for (size_t accountIndex = 0; accountIndex < accountCount; ++accountIndex)
72  {
73  RLP const addressAndAccount = accounts[accountIndex];
74  if (addressAndAccount.itemCount() != 2)
75  BOOST_THROW_EXCEPTION(InvalidStateChunkData());
76 
77  h256 const addressHash = addressAndAccount[0].toHash<h256>(RLP::VeryStrict);
78  if (!addressHash)
79  BOOST_THROW_EXCEPTION(InvalidStateChunkData());
80 
81  // splitted parts of account can be only first in chunk
82  if (accountIndex > 0 && m_stateImporter.isAccountImported(addressHash))
83  BOOST_THROW_EXCEPTION(AccountAlreadyImported());
84 
85  RLP const account = addressAndAccount[1];
86  if (account.itemCount() != 5)
87  BOOST_THROW_EXCEPTION(InvalidStateChunkData());
88 
89  u256 const nonce = account[0].toInt<u256>(RLP::VeryStrict);
90  u256 const balance = account[1].toInt<u256>(RLP::VeryStrict);
91 
92  RLP const storage = account[4];
93  std::map<h256, bytes> storageMap;
94  for (auto hashAndValue: storage)
95  {
96  if (hashAndValue.itemCount() != 2)
97  BOOST_THROW_EXCEPTION(InvalidStateChunkData());
98 
99  h256 const keyHash = hashAndValue[0].toHash<h256>(RLP::VeryStrict);
100  if (!keyHash || storageMap.find(keyHash) != storageMap.end())
101  BOOST_THROW_EXCEPTION(InvalidStateChunkData());
102 
103  bytes value = hashAndValue[1].toBytes(RLP::VeryStrict);
104  if (value.empty())
105  BOOST_THROW_EXCEPTION(InvalidStateChunkData());
106 
107  storageMap.emplace(keyHash, std::move(value));
108  }
109 
110  byte const codeFlag = account[2].toInt<byte>(RLP::VeryStrict);
111  h256 codeHash;
112  switch (codeFlag)
113  {
114  case 0:
115  codeHash = EmptySHA3;
116  break;
117  case 1:
118  codeHash = m_stateImporter.importCode(account[3].toBytesConstRef(RLP::VeryStrict));
119  break;
120  case 2:
121  codeHash = account[3].toHash<h256>(RLP::VeryStrict);
122  if (!codeHash || m_stateImporter.lookupCode(codeHash).empty())
123  BOOST_THROW_EXCEPTION(InvalidStateChunkData());
124  break;
125  default:
126  BOOST_THROW_EXCEPTION(InvalidStateChunkData());
127  }
128 
129  m_stateImporter.importAccount(addressHash, nonce, balance, storageMap, codeHash);
130  }
131  accountsImported += accountCount;
132 
133  m_stateImporter.commitStateDatabase();
134 
135  ++chunksImported;
136  LOG(m_logger) << "Imported chunk " << chunksImported << " (" << accounts.itemCount()
137  << " account records) Total account records imported: " << accountsImported;
138  LOG(m_logger) << stateChunkCount - chunksImported << " chunks left to import";
139  }
140 
141  // check root
142  LOG(m_logger) << "Chunks imported: " << chunksImported;
143  LOG(m_logger) << "Account records imported: " << accountsImported;
144  LOG(m_logger) << "Reconstructed state root: " << m_stateImporter.stateRoot();
145  LOG(m_logger) << "Manifest state root: " << _stateRoot;
146  if (m_stateImporter.stateRoot() != _stateRoot)
147  BOOST_THROW_EXCEPTION(StateTrieReconstructionFailed());
148 }
149 
150 void SnapshotImporter::importBlockChunks(SnapshotStorageFace const& _snapshotStorage, h256s const& _blockChunkHashes)
151 {
152  size_t const blockChunkCount = _blockChunkHashes.size();
153  size_t blockChunksImported = 0;
154  // chunks are in decreasing order of first block number, so we go backwards to start from the oldest block
155  for (auto chunk = _blockChunkHashes.rbegin(); chunk != _blockChunkHashes.rend(); ++chunk)
156  {
157  std::string const chunkUncompressed = _snapshotStorage.readChunk(*chunk);
158 
159  RLP blockChunk(chunkUncompressed);
160  if (blockChunk.itemCount() < 3)
161  BOOST_THROW_EXCEPTION(InvalidBlockChunkData());
162 
163  int64_t const firstBlockNumber = blockChunk[0].toPositiveInt64(RLP::VeryStrict);
164  h256 const firstBlockHash = blockChunk[1].toHash<h256>(RLP::VeryStrict);
165  u256 const firstBlockDifficulty = blockChunk[2].toInt<u256>(RLP::VeryStrict);
166  if (!firstBlockNumber || !firstBlockHash || !firstBlockDifficulty)
167  BOOST_THROW_EXCEPTION(InvalidBlockChunkData());
168 
169  LOG(m_logger) << "chunk first block " << firstBlockNumber << " first block hash "
170  << firstBlockHash << " difficulty " << firstBlockDifficulty;
171 
172  size_t const itemCount = blockChunk.itemCount();
173  h256 parentHash = firstBlockHash;
174  int64_t number = firstBlockNumber + 1;
175  u256 totalDifficulty = firstBlockDifficulty;
176  for (size_t i = 3; i < itemCount; ++i, ++number)
177  {
178  RLP blockAndReceipts = blockChunk[i];
179  if (blockAndReceipts.itemCount() != 2)
180  BOOST_THROW_EXCEPTION(InvalidBlockChunkData());
181 
182  RLP abridgedBlock = blockAndReceipts[0];
183 
184  BlockHeader header;
185  header.setParentHash(parentHash);
186  header.setAuthor(abridgedBlock[0].toHash<Address>(RLP::VeryStrict));
187 
188  h256 const blockStateRoot = abridgedBlock[1].toHash<h256>(RLP::VeryStrict);
189  RLP transactions = abridgedBlock[8];
190  h256 const txRoot = trieRootOver(transactions.itemCount(), [&](unsigned i) { return rlp(i); }, [&](unsigned i) { return transactions[i].data().toBytes(); });
191  RLP uncles = abridgedBlock[9];
192  RLP receipts = blockAndReceipts[1];
193  std::vector<bytesConstRef> receiptsVector;
194  for (auto receipt: receipts)
195  receiptsVector.push_back(receipt.data());
196  h256 const receiptsRoot = orderedTrieRoot(receiptsVector);
197  h256 const unclesHash = sha3(uncles.data());
198  header.setRoots(txRoot, receiptsRoot, unclesHash, blockStateRoot);
199 
200  header.setLogBloom(abridgedBlock[2].toHash<LogBloom>(RLP::VeryStrict));
201  u256 const difficulty = abridgedBlock[3].toInt<u256>(RLP::VeryStrict);
202  header.setDifficulty(difficulty);
203  header.setNumber(number);
204  header.setGasLimit(abridgedBlock[4].toInt<u256>(RLP::VeryStrict));
205  header.setGasUsed(abridgedBlock[5].toInt<u256>(RLP::VeryStrict));
206  header.setTimestamp(abridgedBlock[6].toPositiveInt64(RLP::VeryStrict));
207  header.setExtraData(abridgedBlock[7].toBytes(RLP::VeryStrict));
208 
209  Ethash::setMixHash(header, abridgedBlock[10].toHash<h256>(RLP::VeryStrict));
210  Ethash::setNonce(header, abridgedBlock[11].toHash<Nonce>(RLP::VeryStrict));
211 
212  totalDifficulty += difficulty;
213  m_blockChainImporter.importBlock(header, transactions, uncles, receipts, totalDifficulty);
214 
215  parentHash = header.hash();
216  }
217 
218  LOG(m_logger) << "Imported chunk " << *chunk << " (" << itemCount - 3 << " blocks)";
219  LOG(m_logger) << blockChunkCount - (++blockChunksImported) << " chunks left to import";
220 
221  if (chunk == _blockChunkHashes.rbegin())
222  {
223  LOG(m_logger) << "Setting chain start block: " << firstBlockNumber + 1;
224  m_blockChainImporter.setChainStartBlockNumber(firstBlockNumber + 1);
225  }
226  }
227 }
228 
229 } // namespace eth
230 } // namespace dev
SnapshotImporter.h
dev::RLP::VeryStrict
@ VeryStrict
Definition: RLP.h:58
dev::eth::StateImporterFace::importAccount
virtual void importAccount(h256 const &_addressHash, u256 const &_nonce, u256 const &_balance, std::map< h256, bytes > const &_storage, h256 const &_codeHash)=0
SnapshotStorage.h
dev::eth::StateImporterFace::lookupCode
virtual std::string lookupCode(h256 const &_hash) const =0
dev::sha3
bool sha3(bytesConstRef _input, bytesRef o_output) noexcept
Definition: SHA3.cpp:28
dev::trieRootOver
h256 trieRootOver(unsigned _itemCount, T const &_getKey, U const &_getValue)
Definition: TrieHash.h:36
dev::EmptySHA3
h256 const EmptySHA3
Definition: SHA3.cpp:25
dev::h256
FixedHash< 32 > h256
Definition: FixedHash.h:356
dev::orderedTrieRoot
h256 orderedTrieRoot(std::vector< bytes > const &_data)
Definition: TrieHash.cpp:112
dev::eth::BlockChainImporterFace::importBlock
virtual void importBlock(BlockHeader const &_header, RLP _transactions, RLP _uncles, RLP _receipts, u256 const &_totalDifficulty)=0
dev::eth::SnapshotStorageFace
Definition: SnapshotStorage.h:42
dev::FixedHash< 32 >
LOG
#define LOG
Definition: Log.h:63
dev::eth::SnapshotStorageFace::readChunk
virtual std::string readChunk(h256 const &_chunkHash) const =0
dev::RLP::toVector
std::vector< T > toVector(int _flags=LaissezFaire) const
Definition: RLP.h:186
dev::eth::StateImporterFace::commitStateDatabase
virtual void commitStateDatabase()=0
dev::eth::StateImporterFace::importCode
virtual h256 importCode(bytesConstRef _code)=0
dev::h256s
std::vector< h256 > h256s
Definition: FixedHash.h:361
Client.h
dev::bytes
std::vector< byte > bytes
Definition: Common.h:72
dev::eth::StateImporterFace::isAccountImported
virtual bool isAccountImported(h256 const &_addressHash) const =0
TrieHash.h
FileSystem.h
dev::RLP::itemCount
size_t itemCount() const
Definition: RLP.h:101
dev::u256
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void > > u256
Definition: Common.h:121
dev::eth::SnapshotStorageFace::readManifest
virtual bytes readManifest() const =0
dev::RLP::toInt
_T toInt(int _flags=Strict) const
Converts to int of type given; if isData(), decodes as big-endian bytestream.
Definition: RLP.h:257
dev::RLP::toHash
_N toHash(int _flags=Strict) const
Definition: RLP.h:288
dev::eth::SnapshotImporter::import
void import(SnapshotStorageFace const &_snapshotStorage, h256 const &_genesisHash)
Definition: SnapshotImporter.cpp:34
dev::eth::BlockChainImporterFace::setChainStartBlockNumber
virtual void setChainStartBlockNumber(u256 const &_number)=0
dev
Definition: Address.cpp:21
dev::eth::StateImporterFace::stateRoot
virtual h256 stateRoot() const =0
dev::RLP
Definition: RLP.h:48
RLP.h