mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-15 04:11:02 +01:00
doc: Add internal interface conventions to developer notes
This commit is contained in:
parent
1dca9dc4c7
commit
3dc27a1524
1 changed files with 122 additions and 0 deletions
|
@ -43,6 +43,7 @@ Developer Notes
|
||||||
- [Suggestions and examples](#suggestions-and-examples)
|
- [Suggestions and examples](#suggestions-and-examples)
|
||||||
- [Release notes](#release-notes)
|
- [Release notes](#release-notes)
|
||||||
- [RPC interface guidelines](#rpc-interface-guidelines)
|
- [RPC interface guidelines](#rpc-interface-guidelines)
|
||||||
|
- [Internal interface guidelines](#internal-interface-guidelines)
|
||||||
|
|
||||||
<!-- markdown-toc end -->
|
<!-- markdown-toc end -->
|
||||||
|
|
||||||
|
@ -1100,3 +1101,124 @@ A few guidelines for introducing and reviewing new RPC interfaces:
|
||||||
timestamps in the documentation.
|
timestamps in the documentation.
|
||||||
|
|
||||||
- *Rationale*: User-facing consistency.
|
- *Rationale*: User-facing consistency.
|
||||||
|
|
||||||
|
Internal interface guidelines
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Internal interfaces between parts of the codebase that are meant to be
|
||||||
|
independent (node, wallet, GUI), are defined in
|
||||||
|
[`src/interfaces/`](../src/interfaces/). The main interface classes defined
|
||||||
|
there are [`interfaces::Chain`](../src/interfaces/chain.h), used by wallet to
|
||||||
|
access the node's latest chain state,
|
||||||
|
[`interfaces::Node`](../src/interfaces/node.h), used by the GUI to control the
|
||||||
|
node, and [`interfaces::Wallet`](../src/interfaces/wallet.h), used by the GUI
|
||||||
|
to control an individual wallet. There are also more specialized interface
|
||||||
|
types like [`interfaces::Handler`](../src/interfaces/handler.h)
|
||||||
|
[`interfaces::ChainClient`](../src/interfaces/chain.h) passed to and from
|
||||||
|
various interface methods.
|
||||||
|
|
||||||
|
Interface classes are written in a particular style so node, wallet, and GUI
|
||||||
|
code doesn't need to run in the same process, and so the class declarations
|
||||||
|
work more easily with tools and libraries supporting interprocess
|
||||||
|
communication:
|
||||||
|
|
||||||
|
- Interface classes should be abstract and have methods that are [pure
|
||||||
|
virtual](https://en.cppreference.com/w/cpp/language/abstract_class). This
|
||||||
|
allows multiple implementations to inherit from the same interface class,
|
||||||
|
particularly so one implementation can execute functionality in the local
|
||||||
|
process, and other implementations can forward calls to remote processes.
|
||||||
|
|
||||||
|
- Interface method definitions should wrap existing functionality instead of
|
||||||
|
implementing new functionality. Any substantial new node or wallet
|
||||||
|
functionality should be implemented in [`src/node/`](../src/node/) or
|
||||||
|
[`src/wallet/`](../src/wallet/) and just exposed in
|
||||||
|
[`src/interfaces/`](../src/interfaces/) instead of being implemented there,
|
||||||
|
so it can be more modular and accessible to unit tests.
|
||||||
|
|
||||||
|
- Interface method parameter and return types should either be serializable or
|
||||||
|
be other interface classes. Interface methods shouldn't pass references to
|
||||||
|
objects that can't be serialized or accessed from another process.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
// Good: takes string argument and returns interface class pointer
|
||||||
|
virtual unique_ptr<interfaces::Wallet> loadWallet(std::string filename) = 0;
|
||||||
|
|
||||||
|
// Bad: returns CWallet reference that can't be used from another process
|
||||||
|
virtual CWallet& loadWallet(std::string filename) = 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
```c++
|
||||||
|
// Good: accepts and returns primitive types
|
||||||
|
virtual bool findBlock(const uint256& hash, int& out_height, int64_t& out_time) = 0;
|
||||||
|
|
||||||
|
// Bad: returns pointer to internal node in a linked list inaccessible to
|
||||||
|
// other processes
|
||||||
|
virtual const CBlockIndex* findBlock(const uint256& hash) = 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
```c++
|
||||||
|
// Good: takes plain callback type and returns interface pointer
|
||||||
|
using TipChangedFn = std::function<void(int block_height, int64_t block_time)>;
|
||||||
|
virtual std::unique_ptr<interfaces::Handler> handleTipChanged(TipChangedFn fn) = 0;
|
||||||
|
|
||||||
|
// Bad: returns boost connection specific to local process
|
||||||
|
using TipChangedFn = std::function<void(int block_height, int64_t block_time)>;
|
||||||
|
virtual boost::signals2::scoped_connection connectTipChanged(TipChangedFn fn) = 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
- For consistency and friendliness to code generation tools, interface method
|
||||||
|
input and inout parameters should be ordered first and output parameters
|
||||||
|
should come last.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
// Good: error output param is last
|
||||||
|
virtual bool broadcastTransaction(const CTransactionRef& tx, CAmount max_fee, std::string& error) = 0;
|
||||||
|
|
||||||
|
// Bad: error output param is between input params
|
||||||
|
virtual bool broadcastTransaction(const CTransactionRef& tx, std::string& error, CAmount max_fee) = 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
- For friendliness to code generation tools, interface methods should not be
|
||||||
|
overloaded:
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
// Good: method names are unique
|
||||||
|
virtual bool disconnectByAddress(const CNetAddr& net_addr) = 0;
|
||||||
|
virtual bool disconnectById(NodeId id) = 0;
|
||||||
|
|
||||||
|
// Bad: methods are overloaded by type
|
||||||
|
virtual bool disconnect(const CNetAddr& net_addr) = 0;
|
||||||
|
virtual bool disconnect(NodeId id) = 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
- For consistency and friendliness to code generation tools, interface method
|
||||||
|
names should be `lowerCamelCase` and standalone function names should be
|
||||||
|
`UpperCamelCase`.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
// Good: lowerCamelCase method name
|
||||||
|
virtual void blockConnected(const CBlock& block, int height) = 0;
|
||||||
|
|
||||||
|
// Bad: uppercase class method
|
||||||
|
virtual void BlockConnected(const CBlock& block, int height) = 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
```c++
|
||||||
|
// Good: UpperCamelCase standalone function name
|
||||||
|
std::unique_ptr<Node> MakeNode(LocalInit& init);
|
||||||
|
|
||||||
|
// Bad: lowercase standalone function
|
||||||
|
std::unique_ptr<Node> makeNode(LocalInit& init);
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: This last convention isn't generally followed outside of
|
||||||
|
[`src/interfaces/`](../src/interfaces/), though it did come up for discussion
|
||||||
|
before in [#14635](https://github.com/bitcoin/bitcoin/pull/14635).
|
||||||
|
|
Loading…
Add table
Reference in a new issue