Skip to content

Commit 0cd0451

Browse files
authored
Merge pull request #617 from input-output-hk/jpraynaud/585-deprecate-unverified-signer-registration
Deprecate uncertified signer registration
2 parents 9050f3f + c57c993 commit 0cd0451

File tree

8 files changed

+82
-60
lines changed

8 files changed

+82
-60
lines changed

docs/root/manual/getting-started/run-signer-node.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ For more information about the **Mithril Protocol**, please refer to the [About
3535
## What you'll need
3636

3737
* Operating a **Cardano Node** as a **Stake Pool**:
38-
* **Stable**: The Cardano `Pool Id` in a `BECH32` format such as `pool1frevxe70aqw2ce58c0muyesnahl88nfjjsp25h85jwakzgd2g2l`
39-
* **Experimental**:
38+
* **Stable**:
4039
* The Cardano `Operational Certificate` file of the pool
4140
* The Cardano `KES Secret Key` file of the pool
41+
* **Deprecated**: The Cardano `Pool Id` in a `BECH32` format such as `pool1frevxe70aqw2ce58c0muyesnahl88nfjjsp25h85jwakzgd2g2l`
4242

4343
* Access to the file system of a `relay` **Cardano Node** running on the `testnet`:
4444
* Read rights on the `Database` folder (`--database-path` setting of the **Cardano Node**)
@@ -62,21 +62,21 @@ Your feedback is very important, so feel free to contact us on the #moria channe
6262

6363
:::
6464

65-
### Stable mode: Declare your Pool Id
66-
67-
In this stable mode, the Cardano `Pool Id` that you specify is not strictly verified. It is associated to Cardano stakes based on your declaration. This mode is soon to be deprecated and replaced by the certification mode below.
68-
69-
This is the default mode presented in the setup of this document, it is displayed with a specific **Stable** mention.
70-
71-
### Experimental mode: Certify your Pool Id
65+
### Stable mode: Certify your Pool Id
7266

7367
In this mode, you declare your Cardano `Operational Certificate` file and `KES Secret Key` file which allows to:
7468

7569
* Compute automatically the `PoolId`
7670
* Verify that you are the owner of the `PoolId`, and thus of the associated stakes used by Mithril protocol
7771
* Verify that you are the owner of the Mithril `Signer Secret Key`, and thus allowed to contribute to the multi-signatures and certificate production of the Mithril network
7872

79-
This mode is displayed with a specific **Experimental** mention in this document.
73+
This mode is displayed with a specific **Stable** mention in this document.
74+
75+
### Deprecated mode: Declare your Pool Id
76+
77+
In this mode, the Cardano `Pool Id` that you specify is not strictly verified. It is associated to Cardano stakes based on your declaration. This mode is deprecated and replaced by the certification mode above.
78+
79+
This mode is presented in the setup of this document with a specific **Deprecated** mention.
8080

8181
## Building your own executable
8282

@@ -165,16 +165,16 @@ sudo mv mithril-signer /opt/mithril
165165
Replace this value with the correct user. We assume that the user used to run the **Cardano Node** is `cardano`. The **Mithril Signer** must imperatively run with the same user.
166166

167167
* **Stable mode**: in the `/opt/mithril/mithril-signer/service.env` env file:
168-
* `PARTY_ID=YOUR_POOL_ID_BECH32`: replace `YOUR_POOL_ID_BECH32` with your BECH32 `Pool Id`
168+
* `KES_SECRET_KEY_PATH=/cardano/keys/kes.skey`: replace `/cardano/keys/kes.skey` with the path to your Cardano `KES Secret Key` file
169+
* `OPERATIONAL_CERTIFICATE_PATH=/cardano/cert/opcert.cert`: replace `/cardano/cert/opcert.cert` with the path to your Cardano `Operational Certificate` file
169170
* `DB_DIRECTORY=/cardano/db`: replace `/cardano/db` with the path to the database folder of the **Cardano Node** (the one in `--database-path`)
170171
* `CARDANO_NODE_SOCKET_PATH=/cardano/ipc/node.socket`: replace with the path to the IPC file (`CARDANO_NODE_SOCKET_PATH` env var)
171172
* `CARDANO_CLI_PATH=/app/bin/cardano-cli`: replace with the path to the `cardano-cli` executable
172173
* `DATA_STORES_DIRECTORY=/opt/mithril/stores`: replace with the path to a folder where the **Mithril Signer** will store its data (`/opt/mithril/stores` e.g.)
173174
* `STORE_RETENTION_LIMIT`: if set, this will limit the number of records in some internal stores (5 is a good fit).
174175

175-
* :boom: **Experimental mode**: in the `/opt/mithril/mithril-signer/service.env` env file:
176-
* `KES_SECRET_KEY_PATH=/cardano/keys/kes.skey`: replace `/cardano/keys/kes.skey` with the path to your Cardano `KES Secret Key` file
177-
* `OPERATIONAL_CERTIFICATE_PATH=/cardano/cert/pool.cert`: replace `/cardano/cert/pool.cert` with the path to your Cardano `Operational Certificate` file
176+
* **Deprecated mode**: in the `/opt/mithril/mithril-signer/service.env` env file:
177+
* `PARTY_ID=YOUR_POOL_ID_BECH32`: replace `YOUR_POOL_ID_BECH32` with your BECH32 `Pool Id`
178178
* `DB_DIRECTORY=/cardano/db`: replace `/cardano/db` with the path to the database folder of the **Cardano Node** (the one in `--database-path`)
179179
* `CARDANO_NODE_SOCKET_PATH=/cardano/ipc/node.socket`: replace with the path to the IPC file (`CARDANO_NODE_SOCKET_PATH` env var)
180180
* `CARDANO_CLI_PATH=/app/bin/cardano-cli`: replace with the path to the `cardano-cli` executable
@@ -189,7 +189,8 @@ First create an env file that will be used by the service:
189189

190190
```bash
191191
sudo bash -c 'cat > /opt/mithril/mithril-signer.env << EOF
192-
PARTY_ID=**YOUR_POOL_ID_BECH32**
192+
KES_SECRET_KEY_PATH=**YOUR_KES_SECRET_KEY_PATH**
193+
OPERATIONAL_CERTIFICATE_PATH=**YOUR_OPERATIONAL_CERTIFICATE_PATH**
193194
NETWORK=**YOUR_CARDANO_NETWORK**
194195
AGGREGATOR_ENDPOINT=**YOUR_AGGREGATOR_ENDPOINT**
195196
RUN_INTERVAL=60000
@@ -201,12 +202,11 @@ STORE_RETENTION_LIMIT=5
201202
EOF'
202203
```
203204

204-
* :boom: **Experimental mode**:
205+
* **Deprecated mode**:
205206

206207
```bash
207208
sudo bash -c 'cat > /opt/mithril/mithril-signer.env << EOF
208-
KES_SECRET_KEY_PATH=**YOUR_KES_SECRET_KEY_PATH**
209-
OPERATIONAL_CERTIFICATE_PATH=**YOUR_OPERATIONAL_CERTIFICATE_PATH**
209+
PARTY_ID=**YOUR_POOL_ID_BECH32**
210210
NETWORK=**YOUR_CARDANO_NETWORK**
211211
AGGREGATOR_ENDPOINT=**YOUR_AGGREGATOR_ENDPOINT**
212212
RUN_INTERVAL=60000

mithril-common/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ mithril-stm = { path = "../mithril-stm", default-features = false, features = ["
5454
slog-scope = "4.4.0"
5555

5656
[features]
57+
default = ["allow_skip_signer_certification"]
5758
portable = ["mithril-stm/portable"]
5859
test_only = []
5960
allow_skip_signer_certification = []
61+

mithril-common/src/crypto_helper/cardano/key_certification.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ pub enum ProtocolRegistrationErrorWrapper {
4343
#[error("party id does not exist in the stake distribution")]
4444
PartyIdNonExisting,
4545

46+
/// Error raised when the operational certificate is missing
47+
#[error("missing operational certificate")]
48+
OpCertMissing,
49+
4650
/// Error raised when an operational certificate is invalid
4751
#[error("invalid operational certificate")]
4852
OpCertInvalid,
@@ -245,7 +249,10 @@ impl KeyRegWrapper {
245249
opcert.start_kes_period,
246250
))?
247251
} else {
248-
println!("WARNING: Signer certification is skipped! {:?}", party_id);
252+
if cfg!(not(feature = "allow_skip_signer_certification")) {
253+
Err(ProtocolRegistrationErrorWrapper::OpCertMissing)?
254+
}
255+
println!("WARNING: Uncertified signer regsitration by providing a Pool Id is deprecated and will be removed soon! (Pool Id: {:?})", party_id);
249256
party_id.ok_or(ProtocolRegistrationErrorWrapper::PartyIdMissing)?
250257
};
251258

mithril-common/src/crypto_helper/tests_setup.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ use std::{cmp::min, fs, sync::Arc};
1515

1616
use std::{collections::HashMap, path::PathBuf};
1717

18-
fn setup_temp_directory_for_signer(
18+
/// Create or retrieve a temporary directory for storing cryptographic material for a signer, use this for tests only.
19+
pub fn setup_temp_directory_for_signer(
1920
party_id: &ProtocolPartyId,
2021
auto_create: bool,
2122
) -> Option<PathBuf> {
@@ -62,8 +63,11 @@ pub fn setup_signers(
6263
let stake_distribution = (0..total)
6364
.into_iter()
6465
.map(|party_idx| {
65-
let party_id = if party_idx % 2 == 0 {
66-
// 50% of signers with key certification
66+
let party_id = if party_idx % 2 == 0
67+
|| cfg!(not(feature = "allow_skip_signer_certification"))
68+
{
69+
// 50% of signers with key certification if allow unverified signer registration
70+
// Or 100% of signers otherwise
6771
let keypair = ColdKeyGenerator::create_deterministic_keypair([party_idx as u8; 32]);
6872
let (kes_secret_key, kes_verification_key) = Sum6Kes::keygen(&mut kes_keys_seed);
6973
let operational_certificate = OpCert::new(kes_verification_key, 0, 0, keypair);
@@ -77,14 +81,15 @@ pub fn setup_signers(
7781
.to_file(temp_dir.join("kes.sk"))
7882
.expect("KES secret key file export should not fail");
7983
}
80-
if !temp_dir.join("pool.cert").exists() {
84+
if !temp_dir.join("opcert.cert").exists() {
8185
operational_certificate
82-
.to_file(temp_dir.join("pool.cert"))
86+
.to_file(temp_dir.join("opcert.cert"))
8387
.expect("operational certificate file export should not fail");
8488
}
8589
party_id
8690
} else {
87-
// 50% of signers without key certification (legacy)
91+
// 50% of signers without key certification (legacy) if allow unverified signer registration
92+
// Or 0% of signers otherwise
8893
// TODO: Should be removed once the signer certification is fully deployed
8994
format!("{:<032}", party_idx)
9095
};
@@ -132,7 +137,7 @@ pub fn setup_signers_from_stake_distribution(
132137
.for_each(|(party_id, _stake, protocol_initializer)| {
133138
let temp_dir = setup_temp_directory_for_signer(party_id, false);
134139
let operational_certificate = temp_dir.as_ref().map(|dir| {
135-
OpCert::from_file(dir.join("pool.cert"))
140+
OpCert::from_file(dir.join("opcert.cert"))
136141
.expect("operational certificate decoding should not fail")
137142
});
138143
let verification_key = protocol_initializer.verification_key();
@@ -154,7 +159,7 @@ pub fn setup_signers_from_stake_distribution(
154159
.map(|(party_id, stake, protocol_initializer)| {
155160
let temp_dir = setup_temp_directory_for_signer(&party_id, false);
156161
let operational_certificate: Option<OpCert> = temp_dir.as_ref().map(|dir| {
157-
OpCert::from_file(dir.join("pool.cert"))
162+
OpCert::from_file(dir.join("opcert.cert"))
158163
.expect("operational certificate decoding should not fail")
159164
});
160165
let kes_period = 0;

mithril-signer/tests/state_machine.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
mod test_extensions;
22

3-
use mithril_common::entities::Epoch;
3+
use mithril_common::{
4+
crypto_helper::tests_setup,
5+
entities::{Epoch, SignerWithStake},
6+
};
47

58
use test_extensions::StateMachineTester;
69

710
#[rustfmt::skip]
811
#[tokio::test]
912
async fn test_create_single_signature() {
10-
let mut tester = StateMachineTester::init().await;
13+
14+
let protocol_parameters = tests_setup::setup_protocol_parameters();
15+
let signers = tests_setup::setup_signers(10, &protocol_parameters);
16+
let signers_with_stake = signers.iter().map(|(signer_with_stake, _, _)| signer_with_stake.to_owned()).collect::<Vec<SignerWithStake>>();
17+
let mut tester = StateMachineTester::init(&signers_with_stake).await.expect("state machine tester init should not fail");
1118

1219
tester
1320
.comment("state machine starts and remains in Unregistered state until a epoch settings is got")
@@ -25,7 +32,7 @@ async fn test_create_single_signature() {
2532
.comment("getting an epoch settings changes the state → Registered")
2633
.aggregator_send_epoch_settings().await
2734
.cycle_registered().await.unwrap()
28-
.register_signers(2).await.unwrap()
35+
.register_signers(&signers_with_stake[..2]).await.unwrap()
2936
.check_protocol_initializer(Epoch(3)).await.unwrap()
3037
.check_stake_store(Epoch(3)).await.unwrap()
3138

mithril-signer/tests/test_extensions/state_machine_tester.rs

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,30 @@ pub struct StateMachineTester {
4545
}
4646

4747
impl StateMachineTester {
48-
pub async fn init() -> Self {
48+
pub async fn init(signers_with_stake: &[SignerWithStake]) -> Result<Self> {
49+
let selected_signer_with_stake = signers_with_stake.first().ok_or_else(|| {
50+
TestError::AssertFailed("there should be at least one signer with stakes".to_string())
51+
})?;
52+
let selected_signer_party_id = selected_signer_with_stake.party_id.clone();
53+
let selected_signer_temp_dir =
54+
tests_setup::setup_temp_directory_for_signer(&selected_signer_party_id, false);
4955
let config = Config {
5056
aggregator_endpoint: "http://0.0.0.0:8000".to_string(),
5157
cardano_cli_path: PathBuf::new(),
5258
cardano_node_socket_path: PathBuf::new(),
5359
db_directory: PathBuf::new(),
5460
network: "devnet".to_string(),
5561
network_magic: Some(42),
56-
party_id: Some("99999999999999999999999999999999".to_string()),
62+
party_id: Some(selected_signer_party_id),
5763
run_interval: 5000,
5864
data_stores_directory: PathBuf::new(),
5965
store_retention_limit: None,
60-
kes_secret_key_path: None,
61-
operational_certificate_path: None,
66+
kes_secret_key_path: selected_signer_temp_dir
67+
.as_ref()
68+
.map(|dir| dir.join("kes.sk")),
69+
operational_certificate_path: selected_signer_temp_dir
70+
.as_ref()
71+
.map(|dir| dir.join("opcert.cert")),
6272
};
6373

6474
let decorator = slog_term::PlainDecorator::new(slog_term::TestStdoutWriter);
@@ -103,22 +113,9 @@ impl StateMachineTester {
103113
stake_store: stake_store.clone(),
104114
};
105115
// set up stake distribution
106-
let protocol_parameters = tests_setup::setup_protocol_parameters();
107-
let mut signers: Vec<SignerWithStake> =
108-
tests_setup::setup_signers(10, &protocol_parameters)
109-
.into_iter()
110-
.map(|(signer_with_stake, _, _)| signer_with_stake)
111-
.collect();
112-
signers.push(SignerWithStake {
113-
party_id: "99999999999999999999999999999999".to_string(),
114-
stake: 999,
115-
verification_key: "".to_string(),
116-
verification_key_signature: None,
117-
operational_certificate: None,
118-
kes_period: None,
119-
});
120-
121-
chain_observer.set_signers(signers).await;
116+
chain_observer
117+
.set_signers(signers_with_stake.to_owned())
118+
.await;
122119

123120
let runner = Box::new(SignerRunner::new(config, services));
124121

@@ -128,7 +125,7 @@ impl StateMachineTester {
128125
Duration::from_secs(5),
129126
);
130127

131-
StateMachineTester {
128+
Ok(StateMachineTester {
132129
state_machine,
133130
immutable_observer,
134131
chain_observer,
@@ -137,7 +134,7 @@ impl StateMachineTester {
137134
stake_store,
138135
comment_no: 0,
139136
_logs_guard: logs_guard,
140-
}
137+
})
141138
}
142139

143140
fn assert(&mut self, condition: bool, description: String) -> Result<&mut Self> {
@@ -279,11 +276,11 @@ impl StateMachineTester {
279276
}
280277

281278
/// register the signer in the certificate handler
282-
pub async fn register_signers(&mut self, count: u64) -> Result<&mut Self> {
283-
let protocol_parameters = tests_setup::setup_protocol_parameters();
284-
for (signer_with_stake, _signer, _protocol_initializer) in
285-
tests_setup::setup_signers(count, &protocol_parameters)
286-
{
279+
pub async fn register_signers(
280+
&mut self,
281+
signers_with_stake: &[SignerWithStake],
282+
) -> Result<&mut Self> {
283+
for signer_with_stake in signers_with_stake {
287284
self.certificate_handler
288285
.register_signer(&signer_with_stake.to_owned().into())
289286
.await

mithril-test-lab/mithril-end-to-end/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,6 @@ tokio = { version = "1.17.0", features = ["full"] }
2727
tokio-util = { version = "0.7.1", features = ["codec"] }
2828

2929
[features]
30+
default = ["allow_skip_signer_certification"]
3031
portable = ["mithril-common/portable"]
32+
allow_skip_signer_certification = []

mithril-test-lab/mithril-end-to-end/src/mithril/infrastructure.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ impl MithrilInfrastructure {
3939

4040
let mut signers: Vec<Signer> = vec![];
4141
for (index, pool_node) in devnet_topology.pool_nodes.iter().enumerate() {
42-
// 50% of signers with key certification
43-
// TODO: Should be removed 100% once the signer certification is fully deployed
44-
let enable_certification = index % 2 == 0;
42+
// 50% of signers with key certification if allow unverified signer registration
43+
// Or 100% of signers otherwise
44+
// TODO: Should be removed once the signer certification is fully deployed
45+
let enable_certification =
46+
index % 2 == 0 || cfg!(not(feature = "allow_skip_signer_certification"));
4547
let mut signer = Signer::new(
4648
aggregator.endpoint(),
4749
pool_node,

0 commit comments

Comments
 (0)