Scorum
fork_database.cpp
Go to the documentation of this file.
2 
4 
5 namespace scorum {
6 namespace chain {
7 
9 {
10 }
12 {
13  _head.reset();
14  _index.clear();
15 }
16 
18 {
19  FC_ASSERT(_head, "cannot pop an empty fork database");
20  auto prev = _head->prev.lock();
21  FC_ASSERT(prev, "popping head block would leave fork DB empty");
22  _head = prev;
23 }
24 
26 {
27  auto item = std::make_shared<fork_item>(std::move(b));
28  _index.insert(item);
29  _head = item;
30 }
31 
36 std::shared_ptr<fork_item> fork_database::push_block(const signed_block& b)
37 {
38  auto item = std::make_shared<fork_item>(b);
39  try
40  {
41  _push_block(item);
42  }
43  catch (const unlinkable_block_exception&)
44  {
45  wlog("Pushing block to fork database that failed to link: ${id}, ${num}", ("id", b.id())("num", b.block_num()));
46  wlog("Head: ${num}, ${id}", ("num", _head->data.block_num())("id", _head->data.id()));
47  throw;
48  _unlinked_index.insert(item);
49  }
50  return _head;
51 }
52 
53 void fork_database::_push_block(const item_ptr& item)
54 {
55  if (_head) // make sure the block is within the range that we are caching
56  {
57  FC_ASSERT(item->num > std::max<int64_t>(0, int64_t(_head->num) - (_max_size)),
58  "attempting to push a block that is too old",
59  ("item->num", item->num)("head", _head->num)("max_size", _max_size));
60  }
61 
62  if (_head && item->previous_id() != block_id_type())
63  {
64  auto& index = _index.get<block_id>();
65  auto itr = index.find(item->previous_id());
66  SCORUM_ASSERT(itr != index.end(), unlinkable_block_exception, "block does not link to known chain");
67  FC_ASSERT(!(*itr)->invalid);
68  item->prev = *itr;
69  }
70 
71  _index.insert(item);
72  if (!_head || item->num > _head->num)
73  _head = item;
74 }
75 
82 void fork_database::_push_next(const item_ptr& new_item)
83 {
84  auto& prev_idx = _unlinked_index.get<by_previous>();
85 
86  auto itr = prev_idx.find(new_item->id);
87  while (itr != prev_idx.end())
88  {
89  auto tmp = *itr;
90  prev_idx.erase(itr);
91  _push_block(tmp);
92 
93  itr = prev_idx.find(new_item->id);
94  }
95 }
96 
98 {
99  _max_size = s;
100  if (!_head)
101  return;
102 
103  {
104  auto& by_num_idx = _index.get<block_num>();
105  auto itr = by_num_idx.begin();
106  while (itr != by_num_idx.end())
107  {
108  if ((*itr)->num < std::max(int64_t(0), int64_t(_head->num) - _max_size))
109  by_num_idx.erase(itr);
110  else
111  break;
112  itr = by_num_idx.begin();
113  }
114  }
115  {
116  auto& by_num_idx = _unlinked_index.get<block_num>();
117  auto itr = by_num_idx.begin();
118  while (itr != by_num_idx.end())
119  {
120  if ((*itr)->num < std::max(int64_t(0), int64_t(_head->num) - _max_size))
121  by_num_idx.erase(itr);
122  else
123  break;
124  itr = by_num_idx.begin();
125  }
126  }
127 }
128 
130 {
131  auto& index = _index.get<block_id>();
132  auto itr = index.find(id);
133  if (itr != index.end())
134  return true;
135  auto& unlinked_index = _unlinked_index.get<block_id>();
136  auto unlinked_itr = unlinked_index.find(id);
137  return unlinked_itr != unlinked_index.end();
138 }
139 
141 {
142  auto& index = _index.get<block_id>();
143  auto itr = index.find(id);
144  if (itr != index.end())
145  return *itr;
146  auto& unlinked_index = _unlinked_index.get<block_id>();
147  auto unlinked_itr = unlinked_index.find(id);
148  if (unlinked_itr != unlinked_index.end())
149  return *unlinked_itr;
150  return item_ptr();
151 }
152 
153 std::vector<item_ptr> fork_database::fetch_block_by_number(uint32_t num) const
154 {
155  try
156  {
157  std::vector<item_ptr> result;
158  auto itr = _index.get<block_num>().find(num);
159  while (itr != _index.get<block_num>().end())
160  {
161  if ((*itr)->num == num)
162  result.push_back(*itr);
163  else
164  break;
165  ++itr;
166  }
167  return result;
168  }
169  FC_LOG_AND_RETHROW()
170 }
171 
172 std::pair<fork_database::branch_type, fork_database::branch_type>
174 {
175  try
176  {
177  // This function gets a branch (i.e. vector<fork_item>) leading
178  // back to the most recent common ancestor.
179  std::pair<branch_type, branch_type> result;
180  auto first_branch_itr = _index.get<block_id>().find(first);
181  FC_ASSERT(first_branch_itr != _index.get<block_id>().end());
182  auto first_branch = *first_branch_itr;
183 
184  auto second_branch_itr = _index.get<block_id>().find(second);
185  FC_ASSERT(second_branch_itr != _index.get<block_id>().end());
186  auto second_branch = *second_branch_itr;
187 
188  while (first_branch->data.block_num() > second_branch->data.block_num())
189  {
190  result.first.push_back(first_branch);
191  first_branch = first_branch->prev.lock();
192  FC_ASSERT(first_branch);
193  }
194  while (second_branch->data.block_num() > first_branch->data.block_num())
195  {
196  result.second.push_back(second_branch);
197  second_branch = second_branch->prev.lock();
198  FC_ASSERT(second_branch);
199  }
200  while (first_branch->data.previous != second_branch->data.previous)
201  {
202  result.first.push_back(first_branch);
203  result.second.push_back(second_branch);
204  first_branch = first_branch->prev.lock();
205  FC_ASSERT(first_branch);
206  second_branch = second_branch->prev.lock();
207  FC_ASSERT(second_branch);
208  }
209  if (first_branch && second_branch)
210  {
211  result.first.push_back(first_branch);
212  result.second.push_back(second_branch);
213  }
214  return result;
215  }
216  FC_CAPTURE_AND_RETHROW((first)(second))
217 }
218 
219 std::shared_ptr<fork_item> fork_database::walk_main_branch_to_num(uint32_t block_num) const
220 {
221  std::shared_ptr<fork_item> next = head();
222  if (block_num > next->num)
223  return std::shared_ptr<fork_item>();
224 
225  while (next.get() != nullptr && next->num > block_num)
226  next = next->prev.lock();
227  return next;
228 }
229 
230 std::shared_ptr<fork_item> fork_database::fetch_block_on_main_branch_by_number(uint32_t block_num) const
231 {
232  std::vector<item_ptr> blocks = fetch_block_by_number(block_num);
233  if (blocks.size() == 1)
234  return blocks[0];
235  if (blocks.size() == 0)
236  return std::shared_ptr<fork_item>();
237  return walk_main_branch_to_num(block_num);
238 }
239 
240 void fork_database::set_head(std::shared_ptr<fork_item> h)
241 {
242  _head = h;
243 }
244 
246 {
247  _index.get<block_id>().erase(id);
248 }
249 
250 } // namespace chain
251 } // namespace scorum
std::vector< item_ptr > fetch_block_by_number(uint32_t n) const
std::shared_ptr< fork_item > push_block(const signed_block &b)
std::shared_ptr< fork_item > fetch_block(const block_id_type &id) const
std::shared_ptr< fork_item > fetch_block_on_main_branch_by_number(uint32_t block_num) const
bool is_known_block(const block_id_type &id) const
std::pair< branch_type, branch_type > fetch_branch_from(block_id_type first, block_id_type second) const
void remove(block_id_type b)
void set_head(std::shared_ptr< fork_item > h)
void start_block(signed_block b)
std::shared_ptr< fork_item > head() const
std::shared_ptr< fork_item > walk_main_branch_to_num(uint32_t block_num) const
#define SCORUM_ASSERT(expr, exc_type, FORMAT,...)
Definition: exceptions.hpp:6
std::shared_ptr< fork_item > item_ptr
fc::ripemd160 block_id_type
Definition: types.hpp:63
Definition: asset.cpp:15
block_id_type id() const
Definition: block.cpp:19