-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit e480371
Showing
25 changed files
with
7,402 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
## Test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
Bitprim's C++ interface is the base layer of the platform, the lowest abstraction level available. It's a fork of the Satoshi/reference implementation with several improvements, the main of them being modularization. Being monolithic, the reference client is harder to change, not only because a change ripples across the whole system, but also because it's not possible to mix and match different module implementations. | ||
|
||
## Package diagram | ||
|
||
--- | ||
|
||
If we were to view the Bitprim projects as UML packages, their dependencies would look like this \(some projects omitted for simplicity\): | ||
|
||
## ![](assets/bitprim_package_diagram.png)Which is the main responsibility/functionality for each package? | ||
|
||
--- | ||
|
||
* **secp256k1**: Implementation of the standard of the same name which deals with ellyptic curves cryptography. | ||
* **bitprim-core**: Basic Bitcoin utilities \(encryption, wallet, math\) to be reused by all projects. | ||
* **bitprim-consensus**: An implementation of Satoshi's algorithm for agreeing on a course of action \(achieving consensus\) between nodes in a network. | ||
* **bitprim-database**: Defines how to store and manipulate Bitcoin transactions. | ||
* **bitprim-network**: P2P communication rules between nodes in the Bitcoin network. | ||
* **bitprim-protocol**: Defines payload structure and lower level communication details. | ||
* **bitprim-blockchain**: Interface for accessing the Bitcoin public ledger, a.k.a. blockchain, in which all transactions are linked between them. | ||
* **bitprim-node**: The highest level of abstraction: a full node in the Bitcoin network; it can query the blockchain in many ways and insert blocks as well. | ||
|
||
## Exploring the public interface for each package | ||
|
||
--- | ||
|
||
All packages follow the same structure: At the top level of their source tree, they have an **include** directory. Inside it, there's a single .hpp file which \#includes all the public headers for the package for convenience. Then, inside the include directory, all the public headers for the library reside. These represent the public interface, i.e. those classes meant to be consumed by other packages or programs built on top of the package. | ||
|
||
For example, for [bitprim-node](https://github.com/bitprim/bitprim-node): | ||
|
||
![](assets/2017-06-28-010231_1920x1080_scrot.png)Taking a look inside [full\_node.hpp](https://github.com/bitprim/bitprim-node/blob/master/include/bitcoin/node/full_node.hpp), we can see in its public methods how an instance of a full node can be consumed: | ||
|
||
![](assets/2017-06-28-010906_1920x1080_scrot.png) | ||
|
||
There's a constructor which receives a configuration object \(see [configuration.hpp](https://github.com/bitprim/bitprim-node/blob/master/include/bitcoin/node/configuration.hpp)\), a destructor, and more interestingly, functions for starting, running, stopping and closing the node. Some have callbacks \(start and run\), which the user will have to implement to handle the associated events asynchronously. Examples of how to do this can be seen in Bitprim projects which use the node package: [bitprim-client](https://github.com/bitprim/bitprim-client) and [bitprim-server](https://github.com/bitprim/bitprim-server). | ||
|
Binary file added
BIN
+91.1 KB
docs/developer_guide/c++/assets/2017-06-28-010231_1920x1080_scrot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+81.6 KB
docs/developer_guide/c++/assets/2017-06-28-010906_1920x1080_scrot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
Bitprim's C interface, the [bitprim-node-cint](https://github.com/bitprim/bitprim-node-cint) project, is built on top of the C++ interface. Asides from allowing a C library or program to consume all the Bitprim functionality, it can act as the base to create bindings for many current popular programming languages, such as Javascript, C\#, Golang, Java and Python. All of these languages can interface easily with C, but not with C++. | ||
|
||
Granted, the Object Oriented paradigm is lost when transitioning to C, but it can be "recovered" when implementing a binding in an object oriented language such as C\#. In such a context, classes can be built in order to give application programmers a friendlier interface for integrating Bitcoin in their projects, bridging the gap created by C/C++'s inherent complexity. | ||
|
||
Therefore, Bitprim's interface is not really meant to be consumed directly, but as the basis for a higher level binding in another language. To make this task easier, most functions will receive a parameter which will wrap the implicit object \(this\), so that OOP can be preserved in the binding if possible. | ||
|
||
## Resource management | ||
|
||
--- | ||
|
||
To avoid memory leaks, all C functions which allocate memory that must be released by the user are clearly documented as such. When implementing a binding on top of the C interface, it is advisable to use the [RAII idiom](https://www.hackcraft.net/raii/) whenever possible to relieve the application programmer from the burden of manual memory management. | ||
|
||
## Basic structure - memory management | ||
|
||
--- | ||
|
||
Since this is C we're dealing with, there is nothing beyond a set of functions and some user defined types, but there is [a structure](https://github.com/bitprim/bitprim-node-cint/tree/master/include/bitprim/nodecint) nevertheless. The main "entry point" for the interface are the functions from [executor\_c.h](https://github.com/bitprim/bitprim-node-cint/blob/master/include/bitprim/nodecint/executor_c.h) and the types defined in [primitives.h](https://github.com/bitprim/bitprim-node-cint/blob/master/include/bitprim/nodecint/primitives.h). To start consuming node functionality, the first step is calling one of these functions: | ||
|
||
```c | ||
executor_t executor_construct(char const* path, FILE* sout, FILE* serr); | ||
|
||
executor_t executor_construct_fd(char const* path, int sout_fd, int serr_fd); | ||
``` | ||
Any function with the **construct** suffix will create an object in dynamic memory, which will have to be released by calling the associated **destruct**: | ||
```c | ||
void executor_destruct(executor_t exec); | ||
``` | ||
|
||
This pattern will be seen with many other types; whenever an object is created by the user with a construct function, it will need to be released with destruct as soon as it is no longer needed. | ||
|
||
Another case is when a function needs to create an object for returning it. For example, if we wanted to fetch the transaction history for a specific Bitcoin address, we could use the fetch\_history function: | ||
|
||
```c | ||
void fetch_history(executor_t exec, payment_address_t address, size_t limit, size_t from_height, | ||
history_fetch_handler_t handler); | ||
``` | ||
There's another concept in play here: a pointer to function acting as a callback. Looking at the definition for history\_fetch\_handler\_t in primitives.h: | ||
```c | ||
typedef void (*history_fetch_handler_t)(int error, history_compact_list_t history); | ||
``` | ||
|
||
The second parameter, history, is created dynamically, and therefore must be released by the user, even if he didn't create it. This has to be done this way because there is no way for the C interface to know when the user is done using history. Therefore, it is up to him/her to call history\__compact\_\_list_\_destruct\(history\)._ | ||
|
||
The remaining header files follow these conventions; transaction.h contains functions for manipulating a transaction object, block.h for blocks, and so on. Keep in mind that objects must be destroyed manually. | ||
|
||
## API documentation | ||
|
||
--- | ||
|
||
[Detailed documentation](api.md) | ||
|
||
|
Oops, something went wrong.