1 #include <bitcoin/bitcoin.hpp>
2 using namespace libbitcoin;
4 #include "/home/genjix/python-bitcoin/src/primitive.h"
6 namespace ph = std::placeholders;
8 int cmp(const bc::message::output_point& a,
9 const bc::message::output_point& b)
11 if (a.index < b.index)
13 else if (a.index > b.index)
18 else if (a.hash > b.hash)
23 struct outpoint_less_cmp
25 bool operator()(const bc::message::output_point& a,
26 const bc::message::output_point& b)
28 return cmp(a, b) == -1;
32 struct address_less_cmp
34 bool operator()(const payment_address& a, const payment_address& b)
36 if (a.hash() < b.hash())
38 else if (a.hash() > b.hash())
40 if (a.version() < b.version())
47 : public std::enable_shared_from_this<memory_buffer>
57 typedef std::vector<check_item> check_result;
59 typedef std::function<
60 void (const std::error_code&)> receive_handler;
61 typedef std::function<
62 void (const std::error_code&, const check_result&)> check_handler;
64 memory_buffer(async_service_ptr service, blockchain_ptr chain,
65 transaction_pool_ptr txpool)
66 : strand_(service->get_service()), chain_(chain), txpool_(txpool)
70 void set_handles(python::object handle_tx_stored,
71 python::object handle_tx_confirmed)
73 auto this_ptr = shared_from_this();
75 [&, this_ptr, handle_tx_stored, handle_tx_confirmed]()
77 handle_tx_stored_ = handle_tx_stored;
78 handle_tx_confirmed_ = handle_tx_confirmed;
82 void receive(const message::transaction& tx,
83 python::object handle_receive)
86 strand_.wrap(std::bind(&memory_buffer::confirmed,
87 shared_from_this(), ph::_1, tx)),
88 strand_.wrap(std::bind(&memory_buffer::stored,
89 shared_from_this(), ph::_1, tx, handle_receive)));
92 void check(const message::output_point_list& output_points,
93 const payment_address& address, check_handler handle_check)
95 auto this_ptr = shared_from_this();
97 [&, this_ptr, output_points, address, handle_check]()
100 for (auto& outpoint: output_points)
102 auto it = lookup_input_.find(outpoint);
103 if (it != lookup_input_.end())
106 item.tx_hash = it->second.hash;
107 item.index = it->second.index;
108 item.is_input = true;
109 item.timestamp = timestamps_[item.tx_hash];
110 result.push_back(item);
113 auto range = lookup_address_.equal_range(address);
114 for (auto it = range.first; it != range.second; ++it)
117 item.tx_hash = it->second.hash;
118 item.index = it->second.index;
119 item.is_input = false;
120 item.timestamp = timestamps_[item.tx_hash];
121 result.push_back(item);
123 handle_check(std::error_code(), result);
128 void stored(const std::error_code& ec, const message::transaction& tx,
129 python::object handle_receive)
133 pyfunction<const std::error_code&> f(handle_receive);
137 const hash_digest& tx_hash = hash_transaction(tx);
138 for (uint32_t input_index = 0;
139 input_index < tx.inputs.size(); ++input_index)
141 const auto& prevout = tx.inputs[input_index].previous_output;
142 lookup_input_[prevout] =
143 message::input_point{tx_hash, input_index};
145 for (uint32_t output_index = 0;
146 output_index < tx.outputs.size(); ++output_index)
148 payment_address address;
149 if (extract(address, tx.outputs[output_index].output_script))
151 lookup_address_.insert(
152 std::make_pair(address,
153 message::output_point{tx_hash, output_index}));
156 timestamps_[tx_hash] = time(nullptr);
157 pyfunction<const std::error_code&> f(handle_receive);
158 f(std::error_code());
160 if (!handle_tx_stored_.is_none())
162 pyfunction<const message::transaction&> g(handle_tx_stored_);
167 void confirmed(const std::error_code& ec, const message::transaction& tx)
169 const hash_digest& tx_hash = hash_transaction(tx);
172 std::cerr << "Problem confirming transaction "
173 << pretty_hex(tx_hash) << " : " << ec.message() << std::endl;
176 std::cout << "Confirmed " << pretty_hex(tx_hash) << std::endl;
177 for (uint32_t input_index = 0;
178 input_index < tx.inputs.size(); ++input_index)
180 const auto& prevout = tx.inputs[input_index].previous_output;
181 auto it = lookup_input_.find(prevout);
182 BITCOIN_ASSERT(it != lookup_input_.end());
183 BITCOIN_ASSERT((it->second ==
184 message::input_point{tx_hash, input_index}));
185 lookup_input_.erase(it);
187 for (uint32_t output_index = 0;
188 output_index < tx.outputs.size(); ++output_index)
190 message::output_point outpoint{tx_hash, output_index};
191 payment_address address;
192 if (extract(address, tx.outputs[output_index].output_script))
194 auto range = lookup_address_.equal_range(address);
195 auto it = range.first;
196 for (; it != range.second; ++it)
198 if (it->second == outpoint)
200 lookup_address_.erase(it);
204 BITCOIN_ASSERT(it != range.second);
207 auto time_it = timestamps_.find(tx_hash);
208 BITCOIN_ASSERT(time_it != timestamps_.end());
209 timestamps_.erase(time_it);
211 if (!handle_tx_stored_.is_none())
213 pyfunction<const message::transaction&> f(handle_tx_confirmed_);
218 io_service::strand strand_;
219 blockchain_ptr chain_;
220 transaction_pool_ptr txpool_;
222 std::map<message::output_point,
223 message::input_point, outpoint_less_cmp> lookup_input_;
224 std::multimap<payment_address,
225 message::output_point, address_less_cmp> lookup_address_;
226 std::map<hash_digest, uint64_t> timestamps_;
228 python::object handle_tx_stored_, handle_tx_confirmed_;
231 typedef std::shared_ptr<memory_buffer> memory_buffer_ptr;