rippled
TransactionAcquire.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 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/ConsensusTransSetSF.h>
21 #include <ripple/app/ledger/InboundLedgers.h>
22 #include <ripple/app/ledger/InboundTransactions.h>
23 #include <ripple/app/ledger/impl/TransactionAcquire.h>
24 #include <ripple/app/main/Application.h>
25 #include <ripple/app/misc/NetworkOPs.h>
26 #include <ripple/overlay/Overlay.h>
27 
28 #include <memory>
29 
30 namespace ripple {
31 
32 using namespace std::chrono_literals;
33 
34 // Timeout interval in milliseconds
35 auto constexpr TX_ACQUIRE_TIMEOUT = 250ms;
36 
37 enum {
40 };
41 
43  Application& app,
44  uint256 const& hash,
45  clock_type& clock)
46  : PeerSet(
47  app,
48  hash,
50  clock,
51  app.journal("TransactionAcquire"))
52  , mHaveRoot(false)
53  , j_(app.journal("TransactionAcquire"))
54 {
55  mMap =
56  std::make_shared<SHAMap>(SHAMapType::TRANSACTION, hash, app_.family());
57  mMap->setUnbacked();
58 }
59 
60 void
62 {
64  jtTXN_DATA, "TransactionAcquire", [ptr = shared_from_this()](Job&) {
65  ptr->invokeOnTimer();
66  });
67 }
68 
69 void
71 {
72  // We hold a PeerSet lock and so cannot do real work here
73 
74  if (mFailed)
75  {
76  JLOG(j_.warn()) << "Failed to acquire TX set " << mHash;
77  }
78  else
79  {
80  JLOG(j_.debug()) << "Acquired TX set " << mHash;
81  mMap->setImmutable();
82 
83  uint256 const& hash(mHash);
84  std::shared_ptr<SHAMap> const& map(mMap);
85  auto const pap = &app_;
86  // Note that, when we're in the process of shutting down, addJob()
87  // may reject the request. If that happens then giveSet() will
88  // not be called. That's fine. According to David the giveSet() call
89  // just updates the consensus and related structures when we acquire
90  // a transaction set. No need to update them if we're shutting down.
92  jtTXN_DATA, "completeAcquire", [pap, hash, map](Job&) {
93  pap->getInboundTransactions().giveSet(hash, map, true);
94  });
95  }
96 }
97 
98 void
100 {
101  bool aggressive = false;
102 
103  if (getTimeouts() >= NORM_TIMEOUTS)
104  {
105  aggressive = true;
106 
107  if (getTimeouts() > MAX_TIMEOUTS)
108  {
109  mFailed = true;
110  done();
111  return;
112  }
113  }
114 
115  if (aggressive)
116  trigger(nullptr);
117 
118  addPeers(1);
119 }
120 
123 {
124  return std::dynamic_pointer_cast<PeerSet>(shared_from_this());
125 }
126 
127 void
129 {
130  if (mComplete)
131  {
132  JLOG(j_.info()) << "trigger after complete";
133  return;
134  }
135  if (mFailed)
136  {
137  JLOG(j_.info()) << "trigger after fail";
138  return;
139  }
140 
141  if (!mHaveRoot)
142  {
143  JLOG(j_.trace()) << "TransactionAcquire::trigger "
144  << (peer ? "havePeer" : "noPeer") << " no root";
145  protocol::TMGetLedger tmGL;
146  tmGL.set_ledgerhash(mHash.begin(), mHash.size());
147  tmGL.set_itype(protocol::liTS_CANDIDATE);
148  tmGL.set_querydepth(3); // We probably need the whole thing
149 
150  if (getTimeouts() != 0)
151  tmGL.set_querytype(protocol::qtINDIRECT);
152 
153  *(tmGL.add_nodeids()) = SHAMapNodeID().getRawString();
154  sendRequest(tmGL, peer);
155  }
156  else if (!mMap->isValid())
157  {
158  mFailed = true;
159  done();
160  }
161  else
162  {
164  auto nodes = mMap->getMissingNodes(256, &sf);
165 
166  if (nodes.empty())
167  {
168  if (mMap->isValid())
169  mComplete = true;
170  else
171  mFailed = true;
172 
173  done();
174  return;
175  }
176 
177  protocol::TMGetLedger tmGL;
178  tmGL.set_ledgerhash(mHash.begin(), mHash.size());
179  tmGL.set_itype(protocol::liTS_CANDIDATE);
180 
181  if (getTimeouts() != 0)
182  tmGL.set_querytype(protocol::qtINDIRECT);
183 
184  for (auto const& node : nodes)
185  {
186  *tmGL.add_nodeids() = node.first.getRawString();
187  }
188  sendRequest(tmGL, peer);
189  }
190 }
191 
194  const std::list<SHAMapNodeID>& nodeIDs,
195  const std::list<Blob>& data,
196  std::shared_ptr<Peer> const& peer)
197 {
198  ScopedLockType sl(mLock);
199 
200  if (mComplete)
201  {
202  JLOG(j_.trace()) << "TX set complete";
203  return SHAMapAddNode();
204  }
205 
206  if (mFailed)
207  {
208  JLOG(j_.trace()) << "TX set failed";
209  return SHAMapAddNode();
210  }
211 
212  try
213  {
214  if (nodeIDs.empty())
215  return SHAMapAddNode::invalid();
216 
217  std::list<SHAMapNodeID>::const_iterator nodeIDit = nodeIDs.begin();
218  std::list<Blob>::const_iterator nodeDatait = data.begin();
220 
221  while (nodeIDit != nodeIDs.end())
222  {
223  if (nodeIDit->isRoot())
224  {
225  if (mHaveRoot)
226  JLOG(j_.debug()) << "Got root TXS node, already have it";
227  else if (!mMap->addRootNode(
228  SHAMapHash{getHash()},
229  makeSlice(*nodeDatait),
230  snfWIRE,
231  nullptr)
232  .isGood())
233  {
234  JLOG(j_.warn()) << "TX acquire got bad root node";
235  }
236  else
237  mHaveRoot = true;
238  }
239  else if (!mMap->addKnownNode(*nodeIDit, makeSlice(*nodeDatait), &sf)
240  .isGood())
241  {
242  JLOG(j_.warn()) << "TX acquire got bad non-root node";
243  return SHAMapAddNode::invalid();
244  }
245 
246  ++nodeIDit;
247  ++nodeDatait;
248  }
249 
250  trigger(peer);
251  progress();
252  return SHAMapAddNode::useful();
253  }
254  catch (std::exception const&)
255  {
256  JLOG(j_.error()) << "Peer sends us junky transaction node data";
257  return SHAMapAddNode::invalid();
258  }
259 }
260 
261 void
263 {
264  app_.overlay().selectPeers(*this, numPeers, ScoreHasTxSet(getHash()));
265 }
266 
267 void
269 {
270  ScopedLockType sl(mLock);
271 
272  addPeers(numPeers);
273 
274  setTimer();
275 }
276 
277 void
279 {
280  ScopedLockType sl(mLock);
281 
282  if (mTimeouts > NORM_TIMEOUTS)
284 }
285 
286 } // namespace ripple
ripple::TransactionAcquire::mHaveRoot
bool mHaveRoot
Definition: TransactionAcquire.h:72
ripple::Application
Definition: Application.h:94
ripple::SHAMapAddNode
Definition: SHAMapAddNode.h:28
ripple::TX_ACQUIRE_TIMEOUT
constexpr auto TX_ACQUIRE_TIMEOUT
Definition: TransactionAcquire.cpp:35
ripple::Application::getTempNodeCache
virtual NodeCache & getTempNodeCache()=0
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:194
std::shared_ptr
STL class.
std::exception
STL class.
std::list
STL class.
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::SHAMapType::TRANSACTION
@ TRANSACTION
ripple::TransactionAcquire::trigger
void trigger(std::shared_ptr< Peer > const &)
Definition: TransactionAcquire.cpp:128
ripple::PeerSet::mHash
uint256 mHash
Definition: PeerSet.h:187
ripple::ScoreHasTxSet
Definition: Overlay.h:275
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::PeerSet::mComplete
bool mComplete
Definition: PeerSet.h:190
ripple::JobQueue::addJob
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition: JobQueue.h:166
ripple::SHAMapNodeID
Definition: SHAMapNodeID.h:33
ripple::TransactionAcquire::pmDowncast
std::weak_ptr< PeerSet > pmDowncast() override
Definition: TransactionAcquire.cpp:122
ripple::SHAMapHash
Definition: SHAMapTreeNode.h:43
ripple::base_uint::size
constexpr static std::size_t size()
Definition: base_uint.h:462
ripple::ConsensusTransSetSF
Definition: ConsensusTransSetSF.h:34
ripple::TransactionAcquire::addPeers
void addPeers(int num)
Definition: TransactionAcquire.cpp:262
ripple::SHAMapAddNode::useful
static SHAMapAddNode useful()
Definition: SHAMapAddNode.h:144
ripple::jtTXN_DATA
@ jtTXN_DATA
Definition: Job.h:55
ripple::TransactionAcquire::mMap
std::shared_ptr< SHAMap > mMap
Definition: TransactionAcquire.h:71
ripple::base_uint< 256 >
ripple::TransactionAcquire::TransactionAcquire
TransactionAcquire(Application &app, uint256 const &hash, clock_type &clock)
Definition: TransactionAcquire.cpp:42
std::enable_shared_from_this< TransactionAcquire >::shared_from_this
T shared_from_this(T... args)
ripple::Application::family
virtual Family & family()=0
ripple::SHAMapAddNode::invalid
static SHAMapAddNode invalid()
Definition: SHAMapAddNode.h:150
ripple::TransactionAcquire::j_
beast::Journal j_
Definition: TransactionAcquire.h:73
ripple::TransactionAcquire::onTimer
void onTimer(bool progress, ScopedLockType &peerSetLock) override
Definition: TransactionAcquire.cpp:99
std::unique_lock
STL class.
ripple::MAX_TIMEOUTS
@ MAX_TIMEOUTS
Definition: TransactionAcquire.cpp:39
ripple::SHAMapNodeID::getRawString
std::string getRawString() const
Definition: SHAMapNodeID.cpp:92
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
beast::Journal::error
Stream error() const
Definition: Journal.h:333
beast::Journal::info
Stream info() const
Definition: Journal.h:321
ripple::Job
Definition: Job.h:82
ripple::Overlay::selectPeers
virtual std::size_t selectPeers(PeerSet &set, std::size_t limit, std::function< bool(std::shared_ptr< Peer > const &)> score)=0
Select from active peers.
ripple::TransactionAcquire::init
void init(int startPeers)
Definition: TransactionAcquire.cpp:268
beast::abstract_clock< std::chrono::steady_clock >
memory
ripple::PeerSet::sendRequest
void sendRequest(const protocol::TMGetLedger &message)
Definition: PeerSet.cpp:132
std::weak_ptr
STL class.
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::TransactionAcquire::takeNodes
SHAMapAddNode takeNodes(const std::list< SHAMapNodeID > &IDs, const std::list< Blob > &data, std::shared_ptr< Peer > const &)
Definition: TransactionAcquire.cpp:193
ripple::PeerSet::getTimeouts
int getTimeouts() const
Returns the number of times we timed out.
Definition: PeerSet.h:76
ripple::base_uint::begin
iterator begin()
Definition: base_uint.h:114
ripple::PeerSet::app_
Application & app_
Definition: PeerSet.h:181
std::list::begin
T begin(T... args)
ripple::PeerSet
Supports data retrieval by managing a set of peers.
Definition: PeerSet.h:48
ripple::PeerSet::mFailed
bool mFailed
Definition: PeerSet.h:191
ripple::snfWIRE
@ snfWIRE
Definition: SHAMapTreeNode.h:37
ripple::TransactionAcquire::stillNeed
void stillNeed()
Definition: TransactionAcquire.cpp:278
ripple::Application::overlay
virtual Overlay & overlay()=0
std::list::empty
T empty(T... args)
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::list::end
T end(T... args)
ripple::PeerSet::getHash
uint256 const & getHash() const
Returns the hash of the data we want.
Definition: PeerSet.h:55
ripple::PeerSet::mTimeouts
int mTimeouts
Definition: PeerSet.h:189
ripple::TransactionAcquire::execute
void execute() override
Definition: TransactionAcquire.cpp:61
ripple::PeerSet::setTimer
void setTimer()
Definition: PeerSet.cpp:74
ripple::PeerSet::progress
void progress()
Called to indicate that forward progress has been made.
Definition: PeerSet.h:86
ripple::PeerSet::mLock
std::recursive_mutex mLock
Definition: PeerSet.h:185
ripple::NORM_TIMEOUTS
@ NORM_TIMEOUTS
Definition: TransactionAcquire.cpp:38
ripple::TransactionAcquire::done
void done()
Definition: TransactionAcquire.cpp:70