Skip to content

Commit 02c1e07

Browse files
committed
docs: auto-generate graphml docs from schema
1 parent 1d1e567 commit 02c1e07

File tree

6 files changed

+150
-2121
lines changed

6 files changed

+150
-2121
lines changed

docs/graph.md

+49-97
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ Warnet creates a Bitcoin network using a network topology from a [graphml](https
55
Before any scenarios or RPC commands can be executed, a Warnet network must be started from a graph.
66
See [warcli.md](warcli.md) for more details on these commands.
77

8-
To start a network called `"warnet"` from the [default graph file](../src/graphs/default.graphml)
9-
which consists of 12 Bitcoin Core v26.0 nodes connected in a ring:
8+
To start a network called `"warnet"` from the [default graph file](../src/graphs/default.graphml):
109
```
1110
warcli network start
1211
```
@@ -16,110 +15,63 @@ To start a network with custom configurations:
1615
warcli network start <path/to/file.graphml> --network="network_name"
1716
```
1817

19-
## GraphML file specification
20-
21-
```graphml
22-
<?xml version="1.0" encoding="UTF-8"?><graphml xmlns="http://graphml.graphdrawing.org/xmlns">
23-
<key attr.name="label" attr.type="string" for="node" id="label"/>
24-
<key attr.name="x" attr.type="float" for="node" id="x"/>
25-
<key attr.name="y" attr.type="float" for="node" id="y"/>
26-
<key attr.name="version" attr.type="string" for="node" id="version"/>
27-
<key attr.name="bitcoin_config" attr.type="string" for="node" id="bitcoin_config"/>
28-
<key attr.name="tc_netem" attr.type="string" for="node" id="tc_netem"/>
29-
<graph edgedefault="directed">
30-
31-
<!-- <nodes> -->
32-
<!-- <edges> -->
33-
34-
</graph>
35-
</graphml>
36-
37-
```
38-
### Node attributes
39-
40-
* `id` should be a unique integer identifier
41-
* `label` [optional] specifies the node's label
42-
* `x` specifies the node's x position when rendered in a GUI
43-
* `y` specifies the node's y position when rendered in a GUI
44-
* `version` specifies the node's Bitcoin Core release version, or GitHub branch
45-
* `bitcoin_config` is a comma-separated list of values the node should apply to it's bitcoin.conf, using bitcoin.conf syntax
46-
* `tc_netem` is a `tc-netem` command as a string beginning with "tc qdisc add dev eth0 root netem"
47-
48-
`version` should be either a version number from the pre-compiled binary list on https://bitcoincore.org/bin/ **or** a branch to be compiled from GitHub using `<user>/<repo>#<branch>` syntax.
49-
50-
Nodes can be added to the graph as follows:
51-
52-
53-
#### Release binaries
54-
55-
```graphml
56-
<node id="0">
57-
<data key="x">5.5</data>
58-
<data key="y">2.5</data>
59-
<data key="version">26.0</data>
60-
<data key="bitcoin_config">uacomment=warnet0_v24,debugexclude=libevent</data>
61-
<data key="tc_netem"></data>
62-
</node>
63-
```
64-
#### Pre-built custom image
65-
66-
For a pre-built custom image, remove the `version` tag, and add the image repository to an `image` tag.
67-
These should be built using the `warcli image build` command to ensure they have the needed patches.
68-
69-
```graphml
70-
<node id="0">
71-
<data key="x">5.5</data>
72-
<data key="y">2.5</data>
73-
<data key="image">bitcoindevproject/bitcoin:26.0</data>
74-
<data key="bitcoin_config">uacomment=warnet0_v24,debugexclude=libevent</data>
75-
<data key="tc_netem"></data>
76-
</node>
77-
```
78-
79-
#### On-demand built branch
80-
81-
For an on-demand built branch with traffic shaping rules applied using `tc_netem`:
82-
83-
```graphml
84-
<node id="0">
85-
<data key="x">2.5</data>
86-
<data key="y">5.0</data>
87-
<data key="version">vasild/bitcoin#relay_tx_to_priv_nets</data>
88-
<data key="bitcoin_config">uacomment=warnet1_custom,debug=1</data>
89-
<data key="tc_netem">tc qdisc add dev eth0 root netem delay 100ms</data>
90-
</node>
91-
```
92-
93-
`x`, `y`, `version`, `bitcoin_config` and `tc_netem` data fields are optional for all nodes.
94-
95-
### Edges
96-
97-
Edges can be added between the nodes as follows:
98-
99-
```graphml
100-
<edge id="0" source="0" target="1">
101-
</edge>
102-
```
103-
104-
## Creating graphs
18+
## Creating graphs automatically
10519

10620
Graphs can be created via the graph menu:
10721

10822
```bash
10923
# show graph commands
11024
warcli graph --help
11125

112-
# Create an erdos renyi graph of 12 nodes using edge connection probability of 0.3 and default bitcoin version (v26.0)
113-
warcli graph create n=12 p=0.3 --outfile=erdos-renyi_n12_v26.0.graphml
26+
# Create a cycle graph of 12 nodes using default Bitcoin Core version (v26.0)
27+
warcli graph create 12 --outfile=./12_x_v26.0.graphml
11428

115-
# Create an erdos renyi graph of 15 nodes using default edge connection probability of p=0.2 and using random bitcoin versions
116-
warcli graph create n=15 --outfile=erdos-renyi_n15_random.graphml --random
29+
# Start network with default name "warnet"
30+
warcli network start ./12_x_v26.0.graphml
11731
```
11832

119-
## Examples
33+
## Warnet graph nodes and edges
34+
35+
Nodes in a Warnet graph MUST have either a `"version"` key or an `"image"` key.
36+
These dictate what version of Bitcoin Core to deploy in a fiven tank.
37+
38+
Edges without additional properties are interpreted as Bitcoin p2p connections.
39+
If an edge has additional key-value properties, it will be interpreted as a
40+
lightning network channel (see [lightning.md](lightning.md)).
41+
42+
## GraphML file specification
12043

121-
1. [example.graphml](../src/graphs/default.graphml) -- This is the default graph.
122-
2. [random_internet_as_graph_n100_pos.graphml](../src/graphs/random_internet_as_graph_n100_pos.graphml)
44+
### GraphML file format and headers
45+
```xml
46+
<?xml version="1.0" encoding="UTF-8"?><graphml xmlns="http://graphml.graphdrawing.org/xmlns">
47+
<key id="version" attr.name="version" attr.type="string" for="node">
48+
<key id="image" attr.name="image" attr.type="string" for="node">
49+
<key id="bitcoin_config" attr.name="bitcoin_config" attr.type="string" for="node">
50+
<key id="tc_netem" attr.name="tc_netem" attr.type="string" for="node">
51+
<key id="exporter" attr.name="exporter" attr.type="boolean" for="node">
52+
<key id="collect_logs" attr.name="collect_logs" attr.type="boolean" for="node">
53+
<key id="build_args" attr.name="build_args" attr.type="string" for="node">
54+
<key id="ln" attr.name="ln" attr.type="string" for="node">
55+
<key id="ln-image" attr.name="ln-image" attr.type="string" for="node">
56+
<key id="ln-cb-image" attr.name="ln-cb-image" attr.type="string" for="node">
57+
<key id="channel" attr.name="channel" attr.type="number" for="edge">
58+
<graph edgedefault="directed">
59+
<!-- <nodes> -->
60+
<!-- <edges> -->
61+
</graph>
62+
</graphml>
63+
```
12364

124-
![random_internet_as_graph_n100](../docs/random_internet_as_graph_n100.png)
125-
*random_internet_as_graph_n100*
65+
| key | for | type | default | explanation |
66+
|----------------|-------|---------|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
67+
| version | node | string | | Bitcoin Core version with an available Warnet tank image on Dockerhub. May also be a GitHub repository with format user/repository:branch to build from source code |
68+
| image | node | string | | Bitcoin Core Warnet tank image on Dockerhub with the format repository/image:tag |
69+
| bitcoin_config | node | string | | A string of Bitcoin Core options in command-line format, e.g. '-debug=net -blocksonly' |
70+
| tc_netem | node | string | | A tc-netem command as a string beginning with 'tc qdisc add dev eth0 root netem' |
71+
| exporter | node | boolean | False | Whether to attach a Prometheus data exporter to the tank |
72+
| collect_logs | node | boolean | False | Whether to collect Bitcoin Core debug logs with Promtail |
73+
| build_args | node | string | | A string of configure options used when building Bitcoin Core from source code, e.g. '--without-gui --disable-tests' |
74+
| ln | node | string | | Attach a lightning network node of this implementation (currently only supports 'lnd') |
75+
| ln-image | node | string | | Specify a lightning network node image from Dockerhub with the format repository/image:tag |
76+
| ln-cb-image | node | string | | Specify a lnd Circuit Breaker image from Dockerhub with the format repository/image:tag |
77+
| channel | edge | number | | Indicate that this edge is a lightning channel with this specified capacity |

scripts/apidocs.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from click import Context
99
from tabulate import tabulate
1010

11+
file_path = Path(os.path.dirname(os.path.abspath(__file__))) / ".." / "docs" / "warcli.md"
12+
1113
doc = ""
1214

1315

@@ -46,8 +48,6 @@ def print_cmd(cmd, super=""):
4648
for subcmd in cmd["commands"].values():
4749
print_cmd(subcmd, " " + cmd["name"])
4850

49-
file_path = Path(os.path.dirname(os.path.abspath(__file__))) / ".." / "docs" / "warcli.md"
50-
5151
with open(file_path) as file:
5252
text = file.read()
5353

scripts/graphdocs.py

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env python3
2+
3+
import os
4+
import re
5+
from pathlib import Path
6+
7+
from tabulate import tabulate
8+
from warnet.utils import load_schema
9+
10+
graph_schema = load_schema()
11+
12+
file_path = Path(os.path.dirname(os.path.abspath(__file__))) / ".." / "docs" / "graph.md"
13+
14+
doc = ""
15+
16+
doc += "### GraphML file format and headers\n"
17+
doc += "```xml\n"
18+
doc += '<?xml version="1.0" encoding="UTF-8"?><graphml xmlns="http://graphml.graphdrawing.org/xmlns">\n'
19+
for name, details in graph_schema["node"]["properties"].items():
20+
vname = f'"{name}"'
21+
vtype = f'"{details["type"]}"'
22+
doc += f' <key {"id=" + vname:20} {"attr.name=" + vname:28} {"attr.type=" + vtype:20} for="node">\n'
23+
for name, details in graph_schema["edge"]["properties"].items():
24+
vname = f'"{name}"'
25+
vtype = f'"{details["type"]}"'
26+
doc += f' <key {"id=" + vname:20} {"attr.name=" + vname:28} {"attr.type=" + vtype:20} for="edge">\n'
27+
doc += ' <graph edgedefault="directed">\n <!-- <nodes> -->\n <!-- <edges> -->\n </graph>\n</graphml>\n'
28+
doc += "```\n\n"
29+
30+
headers = ["key", "for", "type", "default", "explanation"]
31+
data = [
32+
[
33+
name,
34+
"node",
35+
p["type"],
36+
p["default"] if "default" in p else "",
37+
p["comment"]
38+
]
39+
for name, p in graph_schema["node"]["properties"].items()
40+
]
41+
data += [
42+
[
43+
name,
44+
"edge",
45+
p["type"],
46+
p["default"] if "default" in p else "",
47+
p["comment"]
48+
]
49+
for name, p in graph_schema["edge"]["properties"].items()
50+
]
51+
doc += tabulate(data, headers=headers, tablefmt="github")
52+
53+
54+
with open(file_path) as file:
55+
text = file.read()
56+
57+
pattern = r"(## GraphML file specification\n)(.*\n)*?\Z"
58+
updated_text = re.sub(pattern, rf"\1\n{doc}\n", text)
59+
60+
with open(file_path, "w") as file:
61+
file.write(updated_text)

0 commit comments

Comments
 (0)