Scorum
betting_matcher.cpp
Go to the documentation of this file.
2 
9 
10 namespace scorum {
11 namespace chain {
12 
13 static const std::string matching_fix = R"([
14  [
15  "84911b2d-91d9-4375-80c3-8ccbc078e992",
16  [
17  "87e01c87-facd-4c68-93da-4e2dd4e1f546",
18  "26e1f127-5d27-4c40-b551-f36e8e2a1ad2",
19  "be0a2d8c-c525-42a2-a537-a7eab03aa319"
20  ]
21  ],
22  [
23  "c2dd413d-59a5-4bc8-b9f8-4efefb848cc7",
24  [
25  "c4193c3e-3ad9-4aa9-a2d5-df2637b23d32",
26  "2da620fc-40bf-41b3-950b-89d509adf7cf"
27  ]
28  ],
29  [
30  "8256c36f-7399-4c01-967a-888f3730ec02",
31  [
32  "d0934027-e040-4f25-9202-c3e45b00bdd2"
33  ]
34  ],
35  [
36  "b4d3a62a-3ed2-48ee-8880-b23e6af9954b",
37  [
38  "bddff0ce-2e45-4f75-a9a6-dfbca27acd61"
39  ]
40  ],
41  [
42  "f45e1c57-64f4-4d18-a6f4-898df5a06b74",
43  [
44  "d26688cc-4d7b-49fa-801a-b6a3173ab0d3"
45  ]
46  ],
47  [
48  "11d1cd20-5809-481a-b07e-2017ecc5e5f8",
49  [
50  "d26688cc-4d7b-49fa-801a-b6a3173ab0d3"
51  ]
52  ],
53  [
54  "ba75d8ec-f800-414d-a9e1-8d90a6f443b7",
55  [
56  "d458ba6c-61b4-4cca-889d-8f10398bf232",
57  "d26688cc-4d7b-49fa-801a-b6a3173ab0d3"
58  ]
59  ],
60  [
61  "bcda6311-9b6f-43ab-b834-ff04d90f31ea",
62  [
63  "10dc5d25-d690-4429-971f-8a7c1d0eec8f"
64  ]
65  ],
66  [
67  "7fc9e455-dd36-46b9-8534-8b230fa5c8b9",
68  [
69  "10dc5d25-d690-4429-971f-8a7c1d0eec8f"
70  ]
71  ],
72  [
73  "de35cb6b-fa81-4f4a-a0ae-86566162b744",
74  [
75  "ffb58868-1a17-471d-bf2c-e22c56111480",
76  "605312d9-3c72-4552-8134-8e25974cbccd"
77  ]
78  ],
79  [
80  "d522f55f-db34-4be9-920d-4b82b8b7c635",
81  [
82  "10121a46-8178-478b-a80d-e265dc183560",
83  "54cc0f28-0bc1-429b-ac98-3c543b64e3cd"
84  ]
85  ],
86  [
87  "a1a1f581-c614-440f-a599-b6f0cc3f997d",
88  [
89  "cd6ea2db-6a39-449f-9d1d-ab994cdc491d",
90  "3eedea83-ccef-4797-8519-18bbd9c893fd"
91  ]
92  ],
93  [
94  "29fba9fc-edf7-4a3e-ba97-4429196e7e6c",
95  [
96  "c549c186-b3b2-4280-9e4b-4d5d029830ac",
97  "f1990e32-0bfa-46c9-9bb6-ef14c3ce6bf3"
98  ]
99  ],
100  [
101  "dcfe2858-9599-4606-840b-25219d87816d",
102  [
103  "491f5618-14eb-4d61-91e6-090b247e0be0",
104  "e15738c5-036c-4376-881d-6f35ce8fee50"
105  ]
106  ],
107  [
108  "a58fc953-7e7e-4d54-a0c1-a2a21f7d2f96",
109  [
110  "8a938b00-819a-45b9-a3e3-913f5b12b42c",
111  "299396a3-6f29-4cb5-b13f-09ad4bbce295"
112  ]
113  ],
114  [
115  "8765a564-daaf-4971-b265-f43e6188b7aa",
116  [
117  "24494b24-407d-4c40-a742-9d2fadab55a5",
118  "9bbc2474-bbf1-4a3a-93e2-28e484d6899e"
119  ]
120  ],
121  [
122  "72437504-9062-4730-974b-1ebcc66fd4e3",
123  [
124  "b660383c-9fd3-4f03-a1ac-c80ebb6e0826",
125  "d6a616f5-803b-4c4a-8fb4-27873f95a2c2"
126  ]
127  ],
128  [
129  "5aed38ca-8a81-40de-890e-863cf27c0aee",
130  [
131  "c55e1f47-1e6d-44ec-9b37-12df4f6605ea",
132  "2d88eb1c-bf49-482f-a3fa-11d324b24c27"
133  ]
134  ],
135  [
136  "a34d64cd-6a7f-4447-89d3-46dd8b60f012",
137  [
138  "76031c54-0856-4af5-8680-169ef19c4845",
139  "e381cdff-7e4f-4aaf-b2a7-606b5eac2718"
140  ]
141  ],
142  [
143  "c7540a6f-4dd9-4d1c-8693-e009116c55e7",
144  [
145  "0460535a-7284-4dee-802b-1e3e634ee688"
146  ]
147  ],
148  [
149  "ef23721e-1134-4d07-be02-1cd3b6880f83",
150  [
151  "0460535a-7284-4dee-802b-1e3e634ee688"
152  ]
153  ],
154  [
155  "10976313-8081-4023-818f-30d9e6ffedc9",
156  [
157  "0460535a-7284-4dee-802b-1e3e634ee688"
158  ]
159  ],
160  [
161  "fe30cb81-0e8f-4ed5-b260-38c9e44a4725",
162  [
163  "0460535a-7284-4dee-802b-1e3e634ee688"
164  ]
165  ],
166  [
167  "9effbf85-ab41-468a-8c4a-991ea23a8a50",
168  [
169  "0460535a-7284-4dee-802b-1e3e634ee688"
170  ]
171  ],
172  [
173  "3568f452-47d9-456c-b085-c8ba83603016",
174  [
175  "d249b968-9359-42d8-a4aa-13af57bd6bae",
176  "25a10696-58f2-4884-96d0-19ac235c04c8"
177  ]
178  ],
179  [
180  "bb1374e9-d014-4245-b2cd-e1ee0a0ca36b",
181  [
182  "0460535a-7284-4dee-802b-1e3e634ee688"
183  ]
184  ],
185  [
186  "d8ca2fcc-f6d0-4a06-b8d8-257424878b69",
187  [
188  "0460535a-7284-4dee-802b-1e3e634ee688"
189  ]
190  ],
191  [
192  "4de53ab4-eb14-4d5b-a02b-774c8d93c209",
193  [
194  "0460535a-7284-4dee-802b-1e3e634ee688"
195  ]
196  ],
197  [
198  "f59e6dc1-1d41-451e-8239-f9aaee629111",
199  [
200  "5c29e81d-4fd9-4f20-ba3b-03ab01d3c70f"
201  ]
202  ]
203 ])";
204 
205 // clang-format on
206 
207 struct matcher
208 {
210  dba::db_accessor<pending_bet_object>& pending_bet_dba,
211  dba::db_accessor<matched_bet_object>& matched_bet_dba,
213  : _virt_op_emitter(emitter)
214  , _pending_bet_dba(pending_bet_dba)
215  , _matched_bet_dba(matched_bet_dba)
216  , _dprop_dba(dprop_dba)
217  {
218  }
219 
220  ~matcher() = default;
221 
223  {
224  return bet.data.stake * bet.data.odds > bet.data.stake;
225  }
226 
227  bool is_bets_matched(const pending_bet_object& bet1, const pending_bet_object& bet2) const
228  {
229  return bet1.data.odds.inverted() == bet2.data.odds;
230  }
231 
232  const pending_bet_object& get_bet(std::reference_wrapper<const pending_bet_object> ref)
233  {
234  return ref.get();
235  }
236 
238  {
239  return bet;
240  }
241 
242  template <typename T>
243  std::vector<std::reference_wrapper<const pending_bet_object>> match(const pending_bet_object& bet2, T& pending_bets)
244  {
245  std::vector<std::reference_wrapper<const pending_bet_object>> bets_to_cancel;
246 
247  for (const auto& bet_ref : pending_bets)
248  {
249  const pending_bet_object& bet1 = get_bet(bet_ref);
250 
251  if (!is_bets_matched(bet1, bet2))
252  continue;
253 
254  auto matched = calculate_matched_stake(bet1.data.stake, bet2.data.stake, bet1.data.odds, bet2.data.odds);
255 
256  if (matched.bet1_matched.amount > 0 && matched.bet2_matched.amount > 0)
257  {
258  const auto matched_bet_id
259  = create_matched_bet(_matched_bet_dba, bet1, bet2, matched, _dprop_dba.get().time);
260 
261  auto bet1_old_stake = bet1.data.stake;
262  auto bet2_old_stake = bet2.data.stake;
263 
264  _pending_bet_dba.update(bet1, [&](pending_bet_object& o) { o.data.stake -= matched.bet1_matched; });
265  _pending_bet_dba.update(bet2, [&](pending_bet_object& o) { o.data.stake -= matched.bet2_matched; });
266 
267  _dprop_dba.update([&](dynamic_global_property_object& obj) {
268  obj.betting_stats.matched_bets_volume += matched.bet1_matched + matched.bet2_matched;
269  obj.betting_stats.pending_bets_volume -= matched.bet1_matched + matched.bet2_matched;
270  });
271 
273  bet1.game_uuid, bet1.data.better, bet1.data.uuid, bet1_old_stake, bet1.data.stake });
275  bet2.game_uuid, bet2.data.better, bet2.data.uuid, bet2_old_stake, bet2.data.stake });
277  bet1.data.better, bet2.data.better, bet1.get_uuid(), bet2.get_uuid(), matched.bet1_matched,
278  matched.bet2_matched, matched_bet_id));
279  }
280 
281  if (!can_be_matched(bet1))
282  {
283  bets_to_cancel.emplace_back(bet1);
284  }
285 
286  if (!can_be_matched(bet2))
287  {
288  bets_to_cancel.emplace_back(bet2);
289  break;
290  }
291  }
292 
293  return bets_to_cancel;
294  }
295 
296 private:
297  database_virtual_operations_emmiter_i& _virt_op_emitter;
298 
299  dba::db_accessor<pending_bet_object>& _pending_bet_dba;
300  dba::db_accessor<matched_bet_object>& _matched_bet_dba;
302 };
303 
306 
308  dba::db_accessor<pending_bet_object>& pending_bet_dba,
309  dba::db_accessor<matched_bet_object>& matched_bet_dba,
311  : _pending_bet_dba(pending_bet_dba)
312  , _dprop_dba(dprop_dba)
313  , _bets_matching_fix(fc::json::from_string(matching_fix).as<matching_fix_list>())
314  , _impl(std::make_unique<matcher>(virt_op_emitter, pending_bet_dba, matched_bet_dba, dprop_dba))
315 {
316  dlog("${0}", ("0", fc::json::to_string(_bets_matching_fix)));
317 }
318 
319 std::vector<std::reference_wrapper<const pending_bet_object>> betting_matcher::match(const pending_bet_object& bet2)
320 {
321  try
322  {
323  auto key = std::make_tuple(bet2.game_uuid, create_opposite(bet2.get_wincase()));
324 
325  if (_bets_matching_fix.find(bet2.data.uuid) != _bets_matching_fix.end())
326  {
327  dlog("fix matching in block ${0}", ("0", _dprop_dba.get().head_block_number));
328  dlog("fix matching for bet ${0}", ("0", bet2.data.uuid));
329 
330  std::vector<std::reference_wrapper<const pending_bet_object>> bets;
331 
332  for (auto uuid : _bets_matching_fix.at(bet2.data.uuid))
333  {
334  bets.push_back(_pending_bet_dba.get_by<by_uuid>(uuid));
335  dlog("+ ${0}", ("0", uuid));
336  }
337 
338  return _impl->match(bet2, bets);
339  }
340  else
341  {
342  auto bets = _pending_bet_dba.get_range_by<by_game_uuid_wincase_asc>(key);
343  return _impl->match(bet2, bets);
344  }
345  }
346  FC_CAPTURE_LOG_AND_RETHROW((bet2))
347 }
348 
350  const pending_bet_object& bet1,
351  const pending_bet_object& bet2,
352  const matched_stake_type& matched,
353  fc::time_point_sec head_block_time)
354 {
355  FC_ASSERT(bet1.game_uuid == bet2.game_uuid, "bets game id is not equal.");
356  FC_ASSERT(bet1.get_wincase() == create_opposite(bet2.get_wincase()));
357 
358  return matched_bet_dba
359  .create([&](matched_bet_object& obj) {
360  obj.bet1_data = bet1.data;
361  obj.bet2_data = bet2.data;
362  obj.bet1_data.stake = matched.bet1_matched;
363  obj.bet2_data.stake = matched.bet2_matched;
364  obj.market = bet1.market;
365  obj.game_uuid = bet1.game_uuid;
366  obj.created = head_block_time;
367  })
368  .id._id;
369 }
370 
371 } // namespace chain
372 } // namespace scorum
betting_matcher(database_virtual_operations_emmiter_i &, dba::db_accessor< pending_bet_object > &, dba::db_accessor< matched_bet_object > &, dba::db_accessor< dynamic_global_property_object > &)
std::vector< std::reference_wrapper< const pending_bet_object > > match(const pending_bet_object &bet2) override
const object_type & create(modifier_type modifier)
betting_total_stats betting_stats
this section display information about betting totals
wincase_type get_wincase() const
Definition: bet_objects.hpp:66
odds_fraction_type inverted() const
Definition: odds.cpp:29
Definition: game.cpp:4
std::map< scorum::uuid_type, std::vector< scorum::uuid_type > > matching_fix_list
matched_stake_type calculate_matched_stake(const asset &bet1_stake, const asset &bet2_stake, const odds &bet1_odds, const odds &bet2_odds)
int64_t create_matched_bet(dba::db_accessor< matched_bet_object > &matched_bet_dba, const pending_bet_object &bet1, const pending_bet_object &bet2, const matched_stake_type &matched, fc::time_point_sec head_block_time)
wincase_type create_opposite(const wincase_type &wincase)
Definition: market.cpp:61
Definition: asset.cpp:15
account_name_type better
Definition: bet_objects.hpp:29
virtual void push_virtual_operation(const operation &op)=0
std::vector< std::reference_wrapper< const pending_bet_object > > match(const pending_bet_object &bet2, T &pending_bets)
const pending_bet_object & get_bet(std::reference_wrapper< const pending_bet_object > ref)
matcher(database_virtual_operations_emmiter_i &emitter, dba::db_accessor< pending_bet_object > &pending_bet_dba, dba::db_accessor< matched_bet_object > &matched_bet_dba, dba::db_accessor< dynamic_global_property_object > &dprop_dba)
bool can_be_matched(const pending_bet_object &bet)
const pending_bet_object & get_bet(const pending_bet_object &bet)
bool is_bets_matched(const pending_bet_object &bet1, const pending_bet_object &bet2) const