Skip to content

Commit c407202

Browse files
committed
add README
1 parent 03d6983 commit c407202

1 file changed

Lines changed: 293 additions & 0 deletions

File tree

README.md

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
# RGB Multisig Bridge
2+
3+
RGB multisig bridge to enable collaboration between a group of cosigners.
4+
5+
Cosigners are the members of the multisig setup, they propose new operations
6+
and review, then accept or refuse, the ones proposed by other cosigners.
7+
8+
Optionally, third parties can be given watch-only access.
9+
10+
Each cosigner runs an [rgb-lib] wallet with the same multisig setup, used for
11+
all operations except signing, and a singlesig (software or hardware) wallet
12+
only used for signing.
13+
Watch-only parties only run the multisig wallet and they're only allowed access
14+
to a subset of the exposed APIs.
15+
16+
## Overview
17+
18+
The bridge allows a group of cosigners to exchange the information needed to
19+
cooperate a multisig setup.
20+
21+
On initial setup, authentication and the cosigners are configured.
22+
Authentication is handled via biscuit tokens, see [Authentication] for
23+
details. Configuration includes the xPubs for all cosigners, the thresholds for
24+
operation approval and rgb-lib versioning, see [Configuration] for details.
25+
26+
Once the bridge is operational, cosigners can use it to propose a new
27+
operation, which is then retrieved by the others, who will review it and
28+
respond to either approve or deny it.
29+
30+
There can only be 1 pending operation at a time. Once enough cosigners have
31+
responded to either reach the threshold (operation approved) or make it
32+
impossible to reach (operation discarded), the operation moves to its final
33+
state and cosigners can process (approved) or skip (discarded) the operation.
34+
35+
Cosigners get the operations from the bridge by their (progressive) ID and are
36+
responsible for keeping track of the last operation they have processed. When a
37+
new operation is retrieved from the bridge, it can either be pending (to be
38+
reviewed and responded to), approved (to be processed) or discarded (to be
39+
skipped).
40+
41+
Operations must be processed in order. Cosigners are responsible to make sure
42+
they have processed all operations before they propose or process a new one.
43+
The bridge keeps track of the last processed operation for each cosigner in
44+
order to help prevent accidental out-of-order processing.
45+
46+
It is advised not to run more than one copy of each cosigner, although the
47+
bridge design should allow such mode of operation.
48+
49+
## Requirements
50+
51+
The [biscuit-cli] tool is needed to setup and manage authentication.
52+
53+
Local installation requires [cargo].
54+
55+
Each cosigner must run a compatible version of rgb-lib, specifically:
56+
- the configured rgb-lib version must be in the bridge's supported version range
57+
- all cosigners must use the rgb-lib version specified in the configuration file
58+
59+
See [Configuration] for details on how the version boundaries are set.
60+
61+
The service has currently only been tested on Linux but it may run on other
62+
operating systems as well.
63+
64+
## Install
65+
66+
Clone the project:
67+
```sh
68+
git clone https://github.com/RGB-Tools/rgb-multisig-bridge
69+
```
70+
71+
### Local
72+
73+
To install the bridge locally, from the project root, run:
74+
```sh
75+
cargo install --locked --path .
76+
```
77+
78+
This will produce the `rgb-multisig-bridge` binary.
79+
80+
### Docker
81+
82+
To build the docker image, run:
83+
```sh
84+
docker build -t rgb-multisig-bridge .
85+
```
86+
87+
## Setup
88+
89+
Before the bridge can be run, authentication (root keys and tokens) needs to be
90+
setup and the service needs to be configured.
91+
92+
### Authentication
93+
94+
Authentication is handled via [Biscuit tokens].
95+
96+
To setup the authentication, a root key pair needs to be generated. The private
97+
key is used to generate new signed tokens manually. The public key is
98+
configured in the bridge and is used to verify the tokens provided by users in
99+
request headers.
100+
101+
Authentication is mandatory and cannot be disabled.
102+
103+
#### Root key pair
104+
105+
Key and token generation are handled via the biscuit CLI, which can be
106+
installed via cargo:
107+
```sh
108+
cargo install biscuit-cli
109+
```
110+
or a pre-built binary can be downloaded from the [biscuit-cli releases page].
111+
112+
To generate the private key, run:
113+
```sh
114+
biscuit keypair --only-private-key > private-key-file
115+
```
116+
117+
To generate the corresponding public key, run:
118+
```sh
119+
biscuit keypair --from-file private-key-file --only-public-key
120+
```
121+
See [Configuration] for how to configure this in the bridge.
122+
123+
Notes:
124+
- the root private key must be kept secret and it is advised to store it safely
125+
in a password manager
126+
- if the root private key is compromised or lost it needs to be abandoned and
127+
a new one needs to be generated, along with its public counterpart
128+
- changing root key pair means updating the configured root public key, which
129+
will make all previous tokens become invalid so new ones will need to be
130+
generated and distributed
131+
132+
#### Tokens
133+
134+
Tokens must have a role, either `cosigner` or `watch-only`. Cosigner tokens
135+
must embed their xPub, watch-only tokens must not embed an xPub. Cosigner
136+
tokens grant access to all APIs, watch-only tokens only grant access to a
137+
subset of the APIs.
138+
139+
To generate a cosigner token, run:
140+
```sh
141+
echo 'role("cosigner"); xpub("<cosigner_xpub>");' \
142+
| biscuit generate --private-key-file private-key-file -
143+
```
144+
Repeat this for all cosigners, each identified by its xPub.
145+
146+
To generate a watch-only token, run:
147+
```sh
148+
echo 'role("watch-only");' \
149+
| biscuit generate --private-key-file private-key-file -
150+
```
151+
152+
Tokens can also carry an **expiry** date. A `check` clause can be added to
153+
enforce it. Here's an example for a watch-only token:
154+
```sh
155+
echo 'role("watch-only"); check if time($t), $t <= 2026-12-25T00:00:00Z;' \
156+
| biscuit generate --private-key-file private-key-file -
157+
```
158+
159+
Tokens can be revoked, but this features is not implemented at the moment.
160+
161+
### Configuration
162+
163+
The service needs a data directory and a TOML configuration file.
164+
165+
The storage data directory (e.g. `data`) is passed as a CLI parameter when
166+
starting the service. The configuration file is named `config.toml` and is
167+
located inside the data directory (e.g. `data/config.toml`).
168+
169+
The configuration file requires the following parameters to be set:
170+
- `cosigner_xpubs`: list of the cosigner xPubs
171+
- `threshold_colored`: the threshold for colored operations
172+
- `threshold_vanilla`: the threshold for vanilla operations
173+
- `root_public_key`: the 32-byte hex-encoded authentication root public key
174+
(without the `ed25519/` prefix)
175+
- `rgb_lib_version`: the `<major.minor>` rgb-lib version that all cosigners
176+
must use
177+
178+
Notes:
179+
- after the service has started, the `cosigner_xpubs` and `threshold_*`
180+
parameters cannot be changed
181+
- `rgb_lib_version` must fall in the `MIN_RGB_LIB_VERSION`-`MAX_RGB_LIB_VERSION`
182+
range, defined in `src/startup.rs`
183+
184+
An example configuration file:
185+
```toml
186+
cosigner_xpubs = [
187+
"tpubD6NzVbkrYhZ4XJ6aDsDYTCUkn1QqC6ie7eappEWB823FLSsRo1VBoEmtQVPJEJYdBt1UArW74BJg54FbW217Xoae6SDgj71JQZTfYCSJUyy",
188+
"tpubD6NzVbkrYhZ4XoJ4SGokACCMyKUYycuuu4tNDAW9qQrksXPNU9C9jeqQJQsdd18Dgt5v2hcc1w4qjNqYQg4nJ15YQNBHsWUuv2cEmneU7Mn",
189+
"tpubD6NzVbkrYhZ4WYbMkJwEwwTsQfjND3xNcXF6MoG7Ge8DbP8yWAkeg7DKPcuYfuHZYxCGWg9bFsAKLvJjb66LRM1wAkeszXKNAZdPpwnfHtd",
190+
"tpubD6NzVbkrYhZ4Yj7WVQNN28FDdpGyyscw1vi73xuxNoKqQ6uStVh3Pp11sh6y1PT7ohULyP6suzZkDBUuLvx7qd3YK4eU36rxAL9wdKRnVJk",
191+
]
192+
threshold_colored = 3
193+
threshold_vanilla = 2
194+
root_public_key = "df200ea3dab3eae6e518e55e6853dc39c50979d77a7d3d36c964c534c66bfad2"
195+
rgb_lib_version = "0.3"
196+
```
197+
198+
## Run
199+
200+
Once the installation and initial setup are complete, the bridge daemon can be
201+
started.
202+
203+
### Local
204+
205+
To start the bridge daemon locally, run:
206+
```sh
207+
rgb-multisig-bridge <data_dir>
208+
```
209+
210+
The data directory needs to exist and contain the configuration file.
211+
212+
### Docker
213+
214+
To start the bridge container, run:
215+
```sh
216+
docker run -it \
217+
-p 3001:3001 \
218+
-v <host_dir_or_volume>:/srv/data \
219+
rgb-multisig-bridge
220+
```
221+
222+
Notes:
223+
- if using a host directory, it doesn't need to already exist
224+
- it is advised not to use the same host data directory for both local and
225+
docker running, as the docker container runs as root and may change file
226+
permissions
227+
228+
## Stop
229+
230+
To stop the daemon press `Ctrl+C` on the console where it is running or, if
231+
running in docker, stop the container.
232+
233+
## Use
234+
235+
Once the daemon is running, it can be operated via HTTP JSON APIs.
236+
237+
The node currently exposes the following APIs:
238+
- `/bumpaddressindices` (POST)
239+
- `/getcurrentaddressindices` (GET)
240+
- `/getfile` (POST)
241+
- `/getlastprocessedopidx` (GET)
242+
- `/getoperationbyidx` (POST)
243+
- `/info` (GET)
244+
- `/markoperationprocessed` (POST)
245+
- `/postoperation` (POST)
246+
- `/respondtooperation` (POST)
247+
248+
See the [OpenAPI specification] for details.
249+
250+
All requests must include the Biscuit token in the `Authorization` header.
251+
252+
### Swagger
253+
254+
A Swagger UI for the `master` branch is generated from the specification and
255+
made available at https://rgb-tools.github.io/rgb-multisig-bridge.
256+
257+
A local copy can be exposed. To do so, from the project root, run:
258+
```sh
259+
docker run -it \
260+
-p 8246:8080 \
261+
-e SWAGGER_JSON=/var/specs/openapi.yaml \
262+
-v $PWD/openapi.yaml:/var/specs/openapi.yaml \
263+
swaggerapi/swagger-ui
264+
```
265+
It can then be accessed by pointing a browser at `http://localhost:8246`.
266+
267+
If a daemon is running on the local host on the default port (3001), the APIs
268+
can be called directly from the Swagger UI.
269+
270+
Authentication is achieved by adding the token via the Authorize button (lock
271+
icon) at the top right, pasting the token and clicking `Authorize`.
272+
273+
### Curl
274+
275+
APIs can be called via curl.
276+
277+
An example `getoperationbyidx` call:
278+
```sh
279+
curl -X POST -H "Content-type: application/json" \
280+
-H "Authorization: Bearer <token>" \
281+
-d '{"operation_idx": "1"}' \
282+
http://localhost:3001/getoperationbyidx
283+
```
284+
285+
286+
[Authentication]: #authentication
287+
[Biscuit tokens]: https://www.biscuitsec.org/
288+
[Configuration]: #configuration
289+
[OpenAPI specification]: /openapi.yaml
290+
[biscuit-cli releases page]: https://github.com/eclipse-biscuit/biscuit-cli/releases
291+
[biscuit-cli]: https://github.com/eclipse-biscuit/biscuit-cli
292+
[cargo]: https://github.com/rust-lang/cargo
293+
[rgb-lib]: https://github.com/RGB-Tools/rgb-lib

0 commit comments

Comments
 (0)