rippled
LedgerHistory_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2018 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/ledger/LedgerHistory.h>
21 #include <ripple/app/ledger/LedgerMaster.h>
22 #include <ripple/app/tx/apply.h>
23 #include <ripple/beast/insight/NullCollector.h>
24 #include <ripple/beast/unit_test.h>
25 #include <ripple/ledger/OpenView.h>
26 #include <chrono>
27 #include <memory>
28 #include <sstream>
29 #include <test/jtx.h>
30 #include <test/jtx/CheckMessageLogs.h>
31 
32 namespace ripple {
33 namespace test {
34 
35 class LedgerHistory_test : public beast::unit_test::suite
36 {
37 public:
48  jtx::Env& env,
49  LedgerHistory& lh,
50  NetClock::duration closeOffset,
52  {
53  if (!prev)
54  {
55  assert(!stx);
56  return std::make_shared<Ledger>(
58  env.app().config(),
60  env.app().getNodeFamily());
61  }
62  auto res = std::make_shared<Ledger>(
63  *prev, prev->info().closeTime + closeOffset);
64 
65  if (stx)
66  {
67  OpenView accum(&*res);
69  env.app(), accum, *stx, false, tapNONE, env.journal);
70  accum.apply(*res);
71  }
72  res->updateSkipList();
73 
74  {
75  res->stateMap().flushDirty(hotACCOUNT_NODE);
76  res->txMap().flushDirty(hotTRANSACTION_NODE);
77  }
78  res->unshare();
79 
80  // Accept ledger
81  res->setAccepted(
82  res->info().closeTime,
83  res->info().closeTimeResolution,
84  true /* close time correct*/);
85  lh.insert(res, false);
86  return res;
87  }
88 
89  void
91  {
92  testcase("LedgerHistory mismatch");
93  using namespace jtx;
94  using namespace std::chrono;
95 
96  // No mismatch
97  {
98  bool found = false;
99  Env env{
100  *this,
101  envconfig(),
102  std::make_unique<CheckMessageLogs>("MISMATCH ", &found)};
104  auto const genesis = makeLedger({}, env, lh, 0s);
105  uint256 const dummyTxHash{1};
106  lh.builtLedger(genesis, dummyTxHash, {});
107  lh.validatedLedger(genesis, dummyTxHash);
108 
109  BEAST_EXPECT(!found);
110  }
111 
112  // Close time mismatch
113  {
114  bool found = false;
115  Env env{
116  *this,
117  envconfig(),
118  std::make_unique<CheckMessageLogs>(
119  "MISMATCH on close time", &found)};
121  auto const genesis = makeLedger({}, env, lh, 0s);
122  auto const ledgerA = makeLedger(genesis, env, lh, 4s);
123  auto const ledgerB = makeLedger(genesis, env, lh, 40s);
124 
125  uint256 const dummyTxHash{1};
126  lh.builtLedger(ledgerA, dummyTxHash, {});
127  lh.validatedLedger(ledgerB, dummyTxHash);
128 
129  BEAST_EXPECT(found);
130  }
131 
132  // Prior ledger mismatch
133  {
134  bool found = false;
135  Env env{
136  *this,
137  envconfig(),
138  std::make_unique<CheckMessageLogs>(
139  "MISMATCH on prior ledger", &found)};
141  auto const genesis = makeLedger({}, env, lh, 0s);
142  auto const ledgerA = makeLedger(genesis, env, lh, 4s);
143  auto const ledgerB = makeLedger(genesis, env, lh, 40s);
144  auto const ledgerAC = makeLedger(ledgerA, env, lh, 4s);
145  auto const ledgerBD = makeLedger(ledgerB, env, lh, 4s);
146 
147  uint256 const dummyTxHash{1};
148  lh.builtLedger(ledgerAC, dummyTxHash, {});
149  lh.validatedLedger(ledgerBD, dummyTxHash);
150 
151  BEAST_EXPECT(found);
152  }
153 
154  // Simulate a bug in which consensus may agree on transactions, but
155  // somehow generate different ledgers
156  for (bool const txBug : {true, false})
157  {
158  std::string const msg = txBug
159  ? "MISMATCH with same consensus transaction set"
160  : "MISMATCH on consensus transaction set";
161  bool found = false;
162  Env env{
163  *this,
164  envconfig(),
165  std::make_unique<CheckMessageLogs>(msg, &found)};
167 
168  Account alice{"A1"};
169  Account bob{"A2"};
170  env.fund(XRP(1000), alice, bob);
171  env.close();
172 
173  auto const ledgerBase =
175 
176  JTx txAlice = env.jt(noop(alice));
177  auto const ledgerA =
178  makeLedger(ledgerBase, env, lh, 4s, txAlice.stx);
179 
180  JTx txBob = env.jt(noop(bob));
181  auto const ledgerB = makeLedger(ledgerBase, env, lh, 4s, txBob.stx);
182 
183  lh.builtLedger(ledgerA, txAlice.stx->getTransactionID(), {});
184  // Simulate the bug by claiming ledgerB had the same consensus hash
185  // as ledgerA, but somehow generated different ledgers
186  lh.validatedLedger(
187  ledgerB,
188  txBug ? txAlice.stx->getTransactionID()
189  : txBob.stx->getTransactionID());
190 
191  BEAST_EXPECT(found);
192  }
193  }
194 
195  void
196  run() override
197  {
199  }
200 };
201 
203 
204 } // namespace test
205 } // namespace ripple
ripple::test::jtx::noop
Json::Value noop(Account const &account)
The null transaction.
Definition: noop.h:31
sstream
ripple::Application::getNodeFamily
virtual Family & getNodeFamily()=0
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
std::string
STL class.
std::shared_ptr< Ledger >
ripple::OpenView
Writable ledger view that accumulates state and tx changes.
Definition: OpenView.h:55
ripple::hotACCOUNT_NODE
@ hotACCOUNT_NODE
Definition: NodeObject.h:35
std::vector
STL class.
ripple::applyTransaction
ApplyResult applyTransaction(Application &app, OpenView &view, STTx const &tx, bool retryAssured, ApplyFlags flags, beast::Journal journal)
Transaction application helper.
Definition: apply.cpp:125
ripple::test::LedgerHistory_test::run
void run() override
Definition: LedgerHistory_test.cpp:196
ripple::test::LedgerHistory_test::makeLedger
static std::shared_ptr< Ledger > makeLedger(std::shared_ptr< Ledger const > const &prev, jtx::Env &env, LedgerHistory &lh, NetClock::duration closeOffset, std::shared_ptr< STTx const > stx={})
Generate a new ledger by hand, applying a specific close time offset and optionally inserting a trans...
Definition: LedgerHistory_test.cpp:46
ripple::test::jtx::JTx::stx
std::shared_ptr< STTx const > stx
Definition: JTx.h:50
ripple::test::jtx::Env::jt
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition: Env.h:439
std::chrono::duration
ripple::test::jtx::Env::journal
const beast::Journal journal
Definition: Env.h:144
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:241
ripple::test::jtx::envconfig
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:49
ripple::hotTRANSACTION_NODE
@ hotTRANSACTION_NODE
Definition: NodeObject.h:36
ripple::LedgerHistory
Retains historical ledgers.
Definition: LedgerHistory.h:36
ripple::tapNONE
@ tapNONE
Definition: ApplyView.h:30
ripple::LedgerHistory::insert
bool insert(std::shared_ptr< Ledger const > const &ledger, bool validated)
Track a ledger.
Definition: LedgerHistory.cpp:54
ripple::test::LedgerHistory_test
Definition: LedgerHistory_test.cpp:35
ripple::LedgerHistory::builtLedger
void builtLedger(std::shared_ptr< Ledger const > const &, uint256 const &consensusHash, Json::Value)
Report that we have locally built a particular ledger.
Definition: LedgerHistory.cpp:426
ripple::base_uint< 256 >
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
chrono
ripple::Application::config
virtual Config & config()=0
ripple::test::jtx::JTx
Execution context for applying a JSON transaction.
Definition: JTx.h:42
ripple::LedgerHistory::validatedLedger
void validatedLedger(std::shared_ptr< Ledger const > const &, std::optional< uint256 > const &consensusHash)
Report that we have validated a particular ledger.
Definition: LedgerHistory.cpp:467
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
memory
ripple::LedgerMaster::getClosedLedger
std::shared_ptr< Ledger const > getClosedLedger()
Definition: LedgerMaster.h:98
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:228
ripple::create_genesis
const create_genesis_t create_genesis
Definition: Ledger.cpp:62
ripple::test::LedgerHistory_test::testHandleMismatch
void testHandleMismatch()
Definition: LedgerHistory_test.cpp:90
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
beast::insight::NullCollector::New
static std::shared_ptr< Collector > New()
Definition: NullCollector.cpp:152
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)
std::chrono