Skip to content

Commit 3dc27a1

Browse files
committed
doc: Add internal interface conventions to developer notes
1 parent 1dca9dc commit 3dc27a1

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed

doc/developer-notes.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Developer Notes
4343
- [Suggestions and examples](#suggestions-and-examples)
4444
- [Release notes](#release-notes)
4545
- [RPC interface guidelines](#rpc-interface-guidelines)
46+
- [Internal interface guidelines](#internal-interface-guidelines)
4647

4748
<!-- markdown-toc end -->
4849

@@ -1100,3 +1101,124 @@ A few guidelines for introducing and reviewing new RPC interfaces:
11001101
timestamps in the documentation.
11011102

11021103
- *Rationale*: User-facing consistency.
1104+
1105+
Internal interface guidelines
1106+
-----------------------------
1107+
1108+
Internal interfaces between parts of the codebase that are meant to be
1109+
independent (node, wallet, GUI), are defined in
1110+
[`src/interfaces/`](../src/interfaces/). The main interface classes defined
1111+
there are [`interfaces::Chain`](../src/interfaces/chain.h), used by wallet to
1112+
access the node's latest chain state,
1113+
[`interfaces::Node`](../src/interfaces/node.h), used by the GUI to control the
1114+
node, and [`interfaces::Wallet`](../src/interfaces/wallet.h), used by the GUI
1115+
to control an individual wallet. There are also more specialized interface
1116+
types like [`interfaces::Handler`](../src/interfaces/handler.h)
1117+
[`interfaces::ChainClient`](../src/interfaces/chain.h) passed to and from
1118+
various interface methods.
1119+
1120+
Interface classes are written in a particular style so node, wallet, and GUI
1121+
code doesn't need to run in the same process, and so the class declarations
1122+
work more easily with tools and libraries supporting interprocess
1123+
communication:
1124+
1125+
- Interface classes should be abstract and have methods that are [pure
1126+
virtual](https://en.cppreference.com/w/cpp/language/abstract_class). This
1127+
allows multiple implementations to inherit from the same interface class,
1128+
particularly so one implementation can execute functionality in the local
1129+
process, and other implementations can forward calls to remote processes.
1130+
1131+
- Interface method definitions should wrap existing functionality instead of
1132+
implementing new functionality. Any substantial new node or wallet
1133+
functionality should be implemented in [`src/node/`](../src/node/) or
1134+
[`src/wallet/`](../src/wallet/) and just exposed in
1135+
[`src/interfaces/`](../src/interfaces/) instead of being implemented there,
1136+
so it can be more modular and accessible to unit tests.
1137+
1138+
- Interface method parameter and return types should either be serializable or
1139+
be other interface classes. Interface methods shouldn't pass references to
1140+
objects that can't be serialized or accessed from another process.
1141+
1142+
Examples:
1143+
1144+
```c++
1145+
// Good: takes string argument and returns interface class pointer
1146+
virtual unique_ptr<interfaces::Wallet> loadWallet(std::string filename) = 0;
1147+
1148+
// Bad: returns CWallet reference that can't be used from another process
1149+
virtual CWallet& loadWallet(std::string filename) = 0;
1150+
```
1151+
1152+
```c++
1153+
// Good: accepts and returns primitive types
1154+
virtual bool findBlock(const uint256& hash, int& out_height, int64_t& out_time) = 0;
1155+
1156+
// Bad: returns pointer to internal node in a linked list inaccessible to
1157+
// other processes
1158+
virtual const CBlockIndex* findBlock(const uint256& hash) = 0;
1159+
```
1160+
1161+
```c++
1162+
// Good: takes plain callback type and returns interface pointer
1163+
using TipChangedFn = std::function<void(int block_height, int64_t block_time)>;
1164+
virtual std::unique_ptr<interfaces::Handler> handleTipChanged(TipChangedFn fn) = 0;
1165+
1166+
// Bad: returns boost connection specific to local process
1167+
using TipChangedFn = std::function<void(int block_height, int64_t block_time)>;
1168+
virtual boost::signals2::scoped_connection connectTipChanged(TipChangedFn fn) = 0;
1169+
```
1170+
1171+
- For consistency and friendliness to code generation tools, interface method
1172+
input and inout parameters should be ordered first and output parameters
1173+
should come last.
1174+
1175+
Example:
1176+
1177+
```c++
1178+
// Good: error output param is last
1179+
virtual bool broadcastTransaction(const CTransactionRef& tx, CAmount max_fee, std::string& error) = 0;
1180+
1181+
// Bad: error output param is between input params
1182+
virtual bool broadcastTransaction(const CTransactionRef& tx, std::string& error, CAmount max_fee) = 0;
1183+
```
1184+
1185+
- For friendliness to code generation tools, interface methods should not be
1186+
overloaded:
1187+
1188+
Example:
1189+
1190+
```c++
1191+
// Good: method names are unique
1192+
virtual bool disconnectByAddress(const CNetAddr& net_addr) = 0;
1193+
virtual bool disconnectById(NodeId id) = 0;
1194+
1195+
// Bad: methods are overloaded by type
1196+
virtual bool disconnect(const CNetAddr& net_addr) = 0;
1197+
virtual bool disconnect(NodeId id) = 0;
1198+
```
1199+
1200+
- For consistency and friendliness to code generation tools, interface method
1201+
names should be `lowerCamelCase` and standalone function names should be
1202+
`UpperCamelCase`.
1203+
1204+
Examples:
1205+
1206+
```c++
1207+
// Good: lowerCamelCase method name
1208+
virtual void blockConnected(const CBlock& block, int height) = 0;
1209+
1210+
// Bad: uppercase class method
1211+
virtual void BlockConnected(const CBlock& block, int height) = 0;
1212+
```
1213+
1214+
```c++
1215+
// Good: UpperCamelCase standalone function name
1216+
std::unique_ptr<Node> MakeNode(LocalInit& init);
1217+
1218+
// Bad: lowercase standalone function
1219+
std::unique_ptr<Node> makeNode(LocalInit& init);
1220+
```
1221+
1222+
Note: This last convention isn't generally followed outside of
1223+
[`src/interfaces/`](../src/interfaces/), though it did come up for discussion
1224+
before in [#14635](https://github.com/bitcoin/bitcoin/pull/14635).

0 commit comments

Comments
 (0)