Today we enter a new era with all core components done. But this is not the end. This is the beginning!
Everything is still far from finished:
https://bitcoinconsultancy.com/wiki/index.php?title=LibbitcoinServices:
- blockchain
-- bdb_blockchain (berkeley db)
-- postgresql_blockchain
- network
- transaction memory pool
Other:
- scripting system
- full validation of blocks and unconfirmed transactions
- all the usual utilities like base58, encryption, hashing
Todo (minor things):
- wallet
- node discovery
Headers:
include/bitcoin/error.hpp
include/bitcoin/address.hpp
include/bitcoin/network/channel.hpp
include/bitcoin/network/discovery.hpp
include/bitcoin/network/handshake.hpp
include/bitcoin/network/shared_const_buffer.hpp
include/bitcoin/network/network.hpp
include/bitcoin/block.hpp
include/bitcoin/data_helpers.hpp
include/bitcoin/exporter.hpp
include/bitcoin/validate.hpp
include/bitcoin/constants.hpp
include/bitcoin/transaction_pool.hpp
include/bitcoin/types.hpp
include/bitcoin/messages.hpp
include/bitcoin/blockchain/postgresql_blockchain.hpp
include/bitcoin/blockchain/organizer.hpp
include/bitcoin/blockchain/bdb_blockchain.hpp
include/bitcoin/blockchain/blockchain.hpp
include/bitcoin/utility/threads.hpp
include/bitcoin/utility/elliptic_curve_key.hpp
include/bitcoin/utility/assert.hpp
include/bitcoin/utility/ripemd.hpp
include/bitcoin/utility/logger.hpp
include/bitcoin/utility/sha256.hpp
include/bitcoin/utility/base58.hpp
include/bitcoin/utility/big_number.hpp
include/bitcoin/utility/serializer.hpp
include/bitcoin/utility/clock.hpp
include/bitcoin/script.hpp
include/bitcoin/transaction.hpp
The benchmark I use for how the API is progressing is the classical poller application which has become much more intuitive and simple yet flexible and powerful since the early days:
#include
using namespace libbitcoin;
using std::placeholders::_1;
using std::placeholders::_2;
class pollapp
: public threaded_service,
public std::enable_shared_from_this
{
public:
pollapp();
void start(std::string hostname, unsigned int port);
private:
void handle_connect(const std::error_code& ec, channel_ptr node);
void initial_ask_blocks(const std::error_code& ec,
const message::block_locator& loc);
void recv_inv(const std::error_code& ec,
const message::inventory& packet);
void recv_blk(const std::error_code& ec,
const message::block& blk);
void handle_store(const std::error_code& ec, block_info info,
const hash_digest& block_hash);
void ask_blocks(const std::error_code& ec,
const message::block_locator& loc, const hash_digest& hash_stop);
network_ptr network_;
handshake_ptr handshake_;
blockchain_ptr chain_;
channel_ptr node_;
};
typedef std::shared_ptr pollapp_ptr;
pollapp::pollapp()
{
network_ = std::make_shared();
handshake_ = std::make_shared();
chain_ = std::make_shared("database/");
}
void pollapp::start(std::string hostname, unsigned int port)
{
handshake_->connect(network_, "localhost", 8333,
std::bind(&pollapp::handle_connect, shared_from_this(), _1, _2));
}
void pollapp::handle_connect(const std::error_code& ec, channel_ptr node)
{
if (ec)
{
log_fatal() << ec.message();
return;
}
node_ = node;
chain_->fetch_block_locator(
std::bind(&pollapp::initial_ask_blocks, shared_from_this(), _1, _2));
}
void handle_send_packet(const std::error_code& ec)
{
if (ec)
log_error() << ec.message();
}
void pollapp::initial_ask_blocks(const std::error_code& ec,
const message::block_locator& loc)
{
if (ec)
{
log_fatal() << ec.message();
return;
}
node_->subscribe_inventory(
std::bind(&pollapp::recv_inv, shared_from_this(), _1, _2));
node_->subscribe_block(
std::bind(&pollapp::recv_blk, shared_from_this(), _1, _2));
ask_blocks(ec, loc, null_hash);
}
void pollapp::recv_inv(const std::error_code& ec,
const message::inventory& packet)
{
if (ec)
{
log_fatal() << ec.message();
return;
}
message::get_data getdata;
for (const message::inventory_vector& ivv: packet.inventories)
{
if (ivv.type != message::inventory_type::block)
continue;
getdata.inventories.push_back(ivv);
}
node_->send(getdata, handle_send_packet);
// Re-subscribe
node_->subscribe_inventory(
std::bind(&pollapp::recv_inv, shared_from_this(), _1, _2));
}
void pollapp::recv_blk(const std::error_code& ec,
const message::block& blk)
{
if (ec)
{
log_fatal() << ec.message();
return;
}
chain_->store(blk,
std::bind(&pollapp::handle_store, shared_from_this(),
_1, _2, hash_block_header(blk)));
// Re-subscribe
node_->subscribe_block(
std::bind(&pollapp::recv_blk, shared_from_this(), _1, _2));
}
void pollapp::handle_store(const std::error_code& ec, block_info info,
const hash_digest& block_hash)
{
if (ec)
{
log_fatal() << ec.message();
return;
}
switch (info.status)
{
case block_status::orphan:
chain_->fetch_block_locator(
std::bind(&pollapp::ask_blocks, shared_from_this(),
_1, _2, block_hash));
break;
case block_status::rejected:
log_error() << "Rejected block " << pretty_hex(block_hash);
break;
case block_status::confirmed:
log_debug() << "block #" << info.depth;
break;
}
}
void pollapp::ask_blocks(const std::error_code& ec,
const message::block_locator& loc, const hash_digest& hash_stop)
{
if (ec)
{
log_fatal() << ec.message();
return;
}
message::get_blocks packet;
packet.locator_start_hashes = loc;
packet.hash_stop = hash_stop;
node_->send(packet, std::bind(&handle_send_packet, _1));
}
int main(int argc, const char** argv)
{
bdb_blockchain::setup("database/");
pollapp_ptr app = std::make_shared();
app->start("localhost", 8333);
// Wait for CTRL-D
while (true)
{
char n;
std::cin >> n;
if (std::cin.eof())
break;
}
return 0;
}