#include using namespace libbitcoin; #include "/home/genjix/python-bitcoin/src/primitive.h" namespace ph = std::placeholders; int cmp(const bc::message::output_point& a, const bc::message::output_point& b) { if (a.index < b.index) return -1; else if (a.index > b.index) return 1; // a.index == b.index if (a.hash < b.hash) return -1; else if (a.hash > b.hash) return 1; return 0; } struct outpoint_less_cmp { bool operator()(const bc::message::output_point& a, const bc::message::output_point& b) { return cmp(a, b) == -1; } }; struct address_less_cmp { bool operator()(const payment_address& a, const payment_address& b) { if (a.hash() < b.hash()) return true; else if (a.hash() > b.hash()) return false; if (a.version() < b.version()) return true; return false; } }; class memory_buffer : public std::enable_shared_from_this { public: struct check_item { hash_digest tx_hash; size_t index; bool is_input; uint64_t timestamp; // Convenient storage message::output_point previous_output; }; typedef std::vector check_result; typedef std::shared_ptr check_result_ptr; typedef std::function< void (const std::error_code&)> receive_handler; typedef std::function< void (const std::error_code&, check_result_ptr)> check_handler; memory_buffer(async_service_ptr service, blockchain_ptr chain, transaction_pool_ptr txpool) : strand_(service->get_service()), chain_(chain), txpool_(txpool) { } void set_handles(python::object handle_tx_stored, python::object handle_tx_confirmed) { auto this_ptr = shared_from_this(); strand_.post( [&, this_ptr, handle_tx_stored, handle_tx_confirmed]() { handle_tx_stored_ = handle_tx_stored; handle_tx_confirmed_ = handle_tx_confirmed; }); } void receive(const message::transaction& tx, python::object handle_receive) { txpool_->store(tx, strand_.wrap(std::bind(&memory_buffer::confirmed, shared_from_this(), ph::_1, tx)), strand_.wrap(std::bind(&memory_buffer::stored, shared_from_this(), ph::_1, tx, handle_receive))); } void check(const message::output_point_list& output_points, const std::string& address, check_handler handle_check) { } private: void stored(const std::error_code& ec, const message::transaction& tx, python::object handle_receive) { if (ec) { pyfunction f(handle_receive); f(ec); return; } const hash_digest& tx_hash = hash_transaction(tx); for (uint32_t input_index = 0; input_index < tx.inputs.size(); ++input_index) { const auto& prevout = tx.inputs[input_index].previous_output; lookup_input_[prevout] = message::input_point{tx_hash, input_index}; } for (uint32_t output_index = 0; output_index < tx.outputs.size(); ++output_index) { payment_address address; if (extract(address, tx.outputs[output_index].output_script)) { lookup_address_.insert( std::make_pair(address, message::output_point{tx_hash, output_index})); } } timestamps_[tx_hash] = time(nullptr); pyfunction f(handle_receive); f(std::error_code()); // tx stored if (!handle_tx_stored_.is_none()) { pyfunction g(handle_tx_stored_); g(tx); } } void confirmed(const std::error_code& ec, const message::transaction& tx) { const hash_digest& tx_hash = hash_transaction(tx); if (ec) { std::cerr << "Problem confirming transaction " << pretty_hex(tx_hash) << " : " << ec.message() << std::endl; return; } std::cout << "Confirmed " << pretty_hex(tx_hash) << std::endl; for (uint32_t input_index = 0; input_index < tx.inputs.size(); ++input_index) { const auto& prevout = tx.inputs[input_index].previous_output; auto it = lookup_input_.find(prevout); BITCOIN_ASSERT(it != lookup_input_.end()); BITCOIN_ASSERT((it->second == message::input_point{tx_hash, input_index})); lookup_input_.erase(it); } for (uint32_t output_index = 0; output_index < tx.outputs.size(); ++output_index) { message::output_point outpoint{tx_hash, output_index}; payment_address address; if (extract(address, tx.outputs[output_index].output_script)) { auto range = lookup_address_.equal_range(address); auto it = range.first; for (; it != range.second; ++it) { if (it->second == outpoint) { lookup_address_.erase(it); break; } } BITCOIN_ASSERT(it != range.second); } } auto time_it = timestamps_.find(tx_hash); BITCOIN_ASSERT(time_it != timestamps_.end()); timestamps_.erase(time_it); // tx_confirmed if (!handle_tx_stored_.is_none()) { pyfunction f(handle_tx_confirmed_); f(tx); } } io_service::strand strand_; blockchain_ptr chain_; transaction_pool_ptr txpool_; std::map lookup_input_; std::multimap lookup_address_; std::map timestamps_; python::object handle_tx_stored_, handle_tx_confirmed_; }; typedef std::shared_ptr memory_buffer_ptr;