rippled
UnitaryShard.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2021 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/rdb/UnitaryShard.h>
21 #include <ripple/basics/StringUtilities.h>
22 #include <boost/format.hpp>
23 #include <boost/range/adaptor/transformed.hpp>
24 
25 namespace ripple {
26 
27 DatabasePair
29  Config const& config,
30  DatabaseCon::Setup const& setup)
31 {
32  auto tx{std::make_unique<DatabaseCon>(
34  tx->getSession() << boost::str(
35  boost::format("PRAGMA cache_size=-%d;") %
36  kilobytes(config.getValueFor(SizedItem::txnDBCache, std::nullopt)));
37 
38  auto lgr{std::make_unique<DatabaseCon>(
40  lgr->getSession() << boost::str(
41  boost::format("PRAGMA cache_size=-%d;") %
42  kilobytes(config.getValueFor(SizedItem::lgrDBCache, std::nullopt)));
43 
44  return {std::move(lgr), std::move(tx)};
45 }
46 
47 DatabasePair
49  Config const& config,
50  DatabaseCon::Setup const& setup,
51  DatabaseCon::CheckpointerSetup const& checkpointerSetup)
52 {
53  // transaction database
54  auto tx{std::make_unique<DatabaseCon>(
55  setup, TxDBName, TxDBPragma, TxDBInit, checkpointerSetup)};
56  tx->getSession() << boost::str(
57  boost::format("PRAGMA cache_size=-%d;") %
59 
60  // ledger database
61  auto lgr{std::make_unique<DatabaseCon>(
62  setup, LgrDBName, LgrDBPragma, LgrDBInit, checkpointerSetup)};
63  lgr->getSession() << boost::str(
64  boost::format("PRAGMA cache_size=-%d;") %
66 
67  return {std::move(lgr), std::move(tx)};
68 }
69 
70 bool
72  soci::session& txsession,
73  soci::session& lgrsession,
74  std::shared_ptr<Ledger const> const& ledger,
75  std::uint32_t index,
76  std::atomic<bool>& stop,
78 {
79  auto const ledgerSeq{ledger->info().seq};
80 
81  // Update the transactions database
82  {
83  auto& session{txsession};
84  soci::transaction tr(session);
85 
86  session << "DELETE FROM Transactions "
87  "WHERE LedgerSeq = :seq;",
88  soci::use(ledgerSeq);
89  session << "DELETE FROM AccountTransactions "
90  "WHERE LedgerSeq = :seq;",
91  soci::use(ledgerSeq);
92 
93  if (ledger->info().txHash.isNonZero())
94  {
95  auto const sSeq{std::to_string(ledgerSeq)};
96  if (!ledger->txMap().isValid())
97  {
98  JLOG(j.error())
99  << "shard " << index << " has an invalid transaction map"
100  << " on sequence " << sSeq;
101  return false;
102  }
103 
104  for (auto const& item : ledger->txs)
105  {
106  if (stop)
107  return false;
108 
109  auto const txID{item.first->getTransactionID()};
110  auto const sTxID{to_string(txID)};
111  auto const txMeta{std::make_shared<TxMeta>(
112  txID, ledger->seq(), *item.second)};
113 
114  session << "DELETE FROM AccountTransactions "
115  "WHERE TransID = :txID;",
116  soci::use(sTxID);
117 
118  auto const& accounts = txMeta->getAffectedAccounts();
119  if (!accounts.empty())
120  {
121  auto const sTxnSeq{std::to_string(txMeta->getIndex())};
122  auto const s{boost::str(
123  boost::format("('%s','%s',%s,%s)") % sTxID % "%s" %
124  sSeq % sTxnSeq)};
125  std::string sql;
126  sql.reserve((accounts.size() + 1) * 128);
127  sql =
128  "INSERT INTO AccountTransactions "
129  "(TransID, Account, LedgerSeq, TxnSeq) VALUES ";
130  sql += boost::algorithm::join(
131  accounts |
132  boost::adaptors::transformed(
133  [&](AccountID const& accountID) {
134  return boost::str(
135  boost::format(s) %
136  ripple::toBase58(accountID));
137  }),
138  ",");
139  sql += ';';
140  session << sql;
141 
142  JLOG(j.trace())
143  << "shard " << index << " account transaction: " << sql;
144  }
145  else if (!isPseudoTx(*item.first))
146  {
147  // It's okay for pseudo transactions to not affect any
148  // accounts. But otherwise...
149  JLOG(j.warn())
150  << "shard " << index << " transaction in ledger "
151  << sSeq << " affects no accounts";
152  }
153 
154  Serializer s;
155  item.second->add(s);
156  session
158  item.first->getMetaSQL(
159  ledgerSeq, sqlBlobLiteral(s.modData())) +
160  ';');
161  }
162  }
163 
164  tr.commit();
165  }
166 
167  auto const sHash{to_string(ledger->info().hash)};
168 
169  // Update the ledger database
170  {
171  auto& session{lgrsession};
172  soci::transaction tr(session);
173 
174  auto const sParentHash{to_string(ledger->info().parentHash)};
175  auto const sDrops{to_string(ledger->info().drops)};
176  auto const sAccountHash{to_string(ledger->info().accountHash)};
177  auto const sTxHash{to_string(ledger->info().txHash)};
178 
179  session << "DELETE FROM Ledgers "
180  "WHERE LedgerSeq = :seq;",
181  soci::use(ledgerSeq);
182  session << "INSERT OR REPLACE INTO Ledgers ("
183  "LedgerHash, LedgerSeq, PrevHash, TotalCoins, ClosingTime,"
184  "PrevClosingTime, CloseTimeRes, CloseFlags, AccountSetHash,"
185  "TransSetHash)"
186  "VALUES ("
187  ":ledgerHash, :ledgerSeq, :prevHash, :totalCoins,"
188  ":closingTime, :prevClosingTime, :closeTimeRes,"
189  ":closeFlags, :accountSetHash, :transSetHash);",
190  soci::use(sHash), soci::use(ledgerSeq), soci::use(sParentHash),
191  soci::use(sDrops),
192  soci::use(ledger->info().closeTime.time_since_epoch().count()),
193  soci::use(
194  ledger->info().parentCloseTime.time_since_epoch().count()),
195  soci::use(ledger->info().closeTimeResolution.count()),
196  soci::use(ledger->info().closeFlags), soci::use(sAccountHash),
197  soci::use(sTxHash);
198 
199  tr.commit();
200  }
201 
202  return true;
203 }
204 
207  DatabaseCon::Setup const& setup,
208  DatabaseCon::CheckpointerSetup const& checkpointerSetup)
209 {
210  return std::make_unique<DatabaseCon>(
211  setup,
215  checkpointerSetup);
216 }
217 
218 void
219 insertAcquireDBIndex(soci::session& session, std::uint32_t index)
220 {
221  session << "INSERT INTO Shard (ShardIndex) "
222  "VALUES (:shardIndex);",
223  soci::use(index);
224 }
225 
227 selectAcquireDBLedgerSeqs(soci::session& session, std::uint32_t index)
228 {
229  // resIndex and must be boost::optional (not std) because that's
230  // what SOCI expects in its interface.
231  boost::optional<std::uint32_t> resIndex;
232  soci::blob sociBlob(session);
233  soci::indicator blobPresent;
234 
235  session << "SELECT ShardIndex, StoredLedgerSeqs "
236  "FROM Shard "
237  "WHERE ShardIndex = :index;",
238  soci::into(resIndex), soci::into(sociBlob, blobPresent),
239  soci::use(index);
240 
241  if (!resIndex || index != resIndex)
242  return {false, {}};
243 
244  if (blobPresent != soci::i_ok)
245  return {true, {}};
246 
247  std::string s;
248  convert(sociBlob, s);
249 
250  return {true, s};
251 }
252 
254 selectAcquireDBLedgerSeqsHash(soci::session& session, std::uint32_t index)
255 {
256  // resIndex and sHash0 must be boost::optional (not std) because that's
257  // what SOCI expects in its interface.
258  boost::optional<std::uint32_t> resIndex;
259  boost::optional<std::string> sHash0;
260  soci::blob sociBlob(session);
261  soci::indicator blobPresent;
262 
263  session << "SELECT ShardIndex, LastLedgerHash, StoredLedgerSeqs "
264  "FROM Shard "
265  "WHERE ShardIndex = :index;",
266  soci::into(resIndex), soci::into(sHash0),
267  soci::into(sociBlob, blobPresent), soci::use(index);
268 
270  (sHash0 ? *sHash0 : std::optional<std::string>());
271 
272  if (!resIndex || index != resIndex)
273  return {false, {{}, {}}};
274 
275  if (blobPresent != soci::i_ok)
276  return {true, {{}, sHash}};
277 
278  std::string s;
279  convert(sociBlob, s);
280 
281  return {true, {s, sHash}};
282 }
283 
284 void
286  soci::session& session,
287  std::shared_ptr<Ledger const> const& ledger,
288  std::uint32_t index,
289  std::uint32_t lastSeq,
290  std::optional<std::string> const& seqs)
291 {
292  soci::blob sociBlob(session);
293  auto const sHash{to_string(ledger->info().hash)};
294 
295  if (seqs)
296  convert(*seqs, sociBlob);
297 
298  if (ledger->info().seq == lastSeq)
299  {
300  // Store shard's last ledger hash
301  session << "UPDATE Shard "
302  "SET LastLedgerHash = :lastLedgerHash,"
303  "StoredLedgerSeqs = :storedLedgerSeqs "
304  "WHERE ShardIndex = :shardIndex;",
305  soci::use(sHash), soci::use(sociBlob), soci::use(index);
306  }
307  else
308  {
309  session << "UPDATE Shard "
310  "SET StoredLedgerSeqs = :storedLedgerSeqs "
311  "WHERE ShardIndex = :shardIndex;",
312  soci::use(sociBlob), soci::use(index);
313  }
314 }
315 
316 } // namespace ripple
ripple::AcquireShardDBPragma
constexpr std::array< char const *, 1 > AcquireShardDBPragma
Definition: DBInit.h:198
ripple::AcquireShardDBName
constexpr auto AcquireShardDBName
Definition: DBInit.h:196
ripple::SHAMap::isValid
bool isValid() const
Definition: SHAMap.h:617
ripple::makeAcquireDB
std::unique_ptr< DatabaseCon > makeAcquireDB(DatabaseCon::Setup const &setup, DatabaseCon::CheckpointerSetup const &checkpointerSetup)
makeAcquireDB Opens the shard acquire database and returns its descriptor.
Definition: UnitaryShard.cpp:206
std::string
STL class.
std::shared_ptr
STL class.
ripple::LedgerInfo::parentHash
uint256 parentHash
Definition: ReadView.h:104
ripple::TxDBPragma
constexpr std::array< char const *, 4 > TxDBPragma
Definition: DBInit.h:78
ripple::base_uint::isNonZero
bool isNonZero() const
Definition: base_uint.h:536
ripple::DatabaseCon::Setup
Definition: DatabaseCon.h:84
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::Serializer::modData
Blob & modData()
Definition: Serializer.h:178
std::pair
std::string::reserve
T reserve(T... args)
ripple::LedgerInfo::hash
uint256 hash
Definition: ReadView.h:101
ripple::convert
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
Definition: SociDB.cpp:154
ripple::selectAcquireDBLedgerSeqsHash
std::pair< bool, AcquireShardSeqsHash > selectAcquireDBLedgerSeqsHash(soci::session &session, std::uint32_t index)
selectAcquireDBLedgerSeqsHash Returns the set of acquired ledger sequences and the last ledger hash f...
Definition: UnitaryShard.cpp:254
ripple::insertAcquireDBIndex
void insertAcquireDBIndex(soci::session &session, std::uint32_t index)
insertAcquireDBIndex Adds a new shard index to the shard acquire database.
Definition: UnitaryShard.cpp:219
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
ripple::DatabaseCon::CheckpointerSetup
Definition: DatabaseCon.h:107
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::kilobytes
constexpr auto kilobytes(T value) noexcept
Definition: ByteUtilities.h:27
ripple::AcquireShardDBInit
constexpr std::array< char const *, 1 > AcquireShardDBInit
Definition: DBInit.h:201
ripple::STTx::getMetaSQLInsertReplaceHeader
static std::string const & getMetaSQLInsertReplaceHeader()
Definition: STTx.cpp:251
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:93
ripple::LedgerInfo::txHash
uint256 txHash
Definition: ReadView.h:102
ripple::LgrDBInit
constexpr std::array< char const *, 5 > LgrDBInit
Definition: DBInit.h:48
ripple::LedgerInfo::closeTime
NetClock::time_point closeTime
Definition: ReadView.h:124
ripple::TxDBName
constexpr auto TxDBName
Definition: DBInit.h:73
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:81
ripple::updateAcquireDB
void updateAcquireDB(soci::session &session, std::shared_ptr< Ledger const > const &ledger, std::uint32_t index, std::uint32_t lastSeq, std::optional< std::string > const &seqs)
updateAcquireDB Updates information in the acquire DB.
Definition: UnitaryShard.cpp:285
ripple::Ledger::info
LedgerInfo const & info() const override
Returns information about the ledger.
Definition: Ledger.h:148
std::chrono::time_point::time_since_epoch
T time_since_epoch(T... args)
ripple::isPseudoTx
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
Definition: STTx.cpp:559
ripple::Config::getValueFor
int getValueFor(SizedItem item, std::optional< std::size_t > node=std::nullopt) const
Retrieve the default value for the item at the specified node size.
Definition: Config.cpp:991
ripple::LgrDBPragma
constexpr std::array< char const *, 1 > LgrDBPragma
Definition: DBInit.h:45
ripple::Config
Definition: Config.h:69
ripple::LedgerInfo::closeFlags
int closeFlags
Definition: ReadView.h:115
std::to_string
T to_string(T... args)
beast::Journal::error
Stream error() const
Definition: Journal.h:333
ripple::SizedItem::lgrDBCache
@ lgrDBCache
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::uint32_t
std::atomic< bool >
ripple::SizedItem::txnDBCache
@ txnDBCache
ripple::FinalShardDBPragma
constexpr std::array< char const *, 2 > FinalShardDBPragma
Definition: DBInit.h:212
ripple::LedgerInfo::drops
XRPAmount drops
Definition: ReadView.h:106
ripple::Serializer
Definition: Serializer.h:39
ripple::Ledger::txMap
SHAMap const & txMap() const
Definition: Ledger.h:319
ripple::updateLedgerDBs
bool updateLedgerDBs(soci::session &txsession, soci::session &lgrsession, std::shared_ptr< Ledger const > const &ledger, std::uint32_t index, std::atomic< bool > &stop, beast::Journal j)
updateLedgerDBs Saves the given ledger to shard databases.
Definition: UnitaryShard.cpp:71
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::ReadView::seq
LedgerIndex seq() const
Returns the sequence number of the base ledger.
Definition: ReadView.h:203
ripple::LedgerInfo::closeTimeResolution
NetClock::duration closeTimeResolution
Definition: ReadView.h:118
std::chrono::duration::count
T count(T... args)
ripple::makeShardIncompleteLedgerDBs
DatabasePair makeShardIncompleteLedgerDBs(Config const &config, DatabaseCon::Setup const &setup, DatabaseCon::CheckpointerSetup const &checkpointerSetup)
makeShardIncompleteLedgerDBs Opens shard databases for partially downloaded or unverified shards and ...
Definition: UnitaryShard.cpp:48
std::optional< std::string >
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::selectAcquireDBLedgerSeqs
std::pair< bool, std::optional< std::string > > selectAcquireDBLedgerSeqs(soci::session &session, std::uint32_t index)
selectAcquireDBLedgerSeqs Returns the set of acquired ledgers for the given shard.
Definition: UnitaryShard.cpp:227
ripple::TxDBInit
constexpr std::array< char const *, 8 > TxDBInit
Definition: DBInit.h:94
std::unique_ptr
STL class.
ripple::sqlBlobLiteral
std::string sqlBlobLiteral(Blob const &blob)
Format arbitrary binary data as an SQLite "blob literal".
Definition: StringUtilities.cpp:33
ripple::LedgerInfo::accountHash
uint256 accountHash
Definition: ReadView.h:103
ripple::ReadView::txs
txs_type txs
Definition: ReadView.h:333
ripple::makeShardCompleteLedgerDBs
DatabasePair makeShardCompleteLedgerDBs(Config const &config, DatabaseCon::Setup const &setup)
makeShardCompleteLedgerDBs Opens shard databases for verified shards and returns their descriptors.
Definition: UnitaryShard.cpp:28
ripple::LedgerInfo::parentCloseTime
NetClock::time_point parentCloseTime
Definition: ReadView.h:94
ripple::LgrDBName
constexpr auto LgrDBName
Definition: DBInit.h:43