Skip to content
This repository has been archived by the owner on Feb 3, 2023. It is now read-only.

0.0.6 merge: Compare hashes before installing DNA #1093

Merged
merged 6 commits into from
Mar 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- get_as_type - Similar but for a single entry
- link_entries_bidir - Same as link_entries but creates link in both directions
- commit_and_link - Save a line and commit and link in a single function
- The `admin/dna/install_from_file` RPC method now takes an optional `expected_hash`, which performs an integrity check of the DNA file before installing it in the conductor [PR#1093](https://github.com/holochain/holochain-rust/pull/1093).

### Fixed
- Validation of link entries gets retried now if base or target of the link were not yet accessible on the validating node. This fixes a bug where links have been invalid due to network timing issues [PR#1054](https://github.com/holochain/holochain-rust/pull/1054).
Expand Down
58 changes: 56 additions & 2 deletions conductor_api/src/conductor/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use crate::{
},
error::HolochainInstanceError,
};
use holochain_core_types::{cas::content::AddressableContent, error::HolochainError};
use holochain_core_types::{
cas::content::AddressableContent, error::HolochainError, hash::HashString,
};
use json_patch;
use std::{fs, path::PathBuf, sync::Arc};

Expand All @@ -16,6 +18,7 @@ pub trait ConductorAdmin {
path: PathBuf,
id: String,
copy: bool,
expected_hash: Option<HashString>,
properties: Option<&serde_json::Value>,
) -> Result<(), HolochainError>;
fn uninstall_dna(&mut self, id: &String) -> Result<(), HolochainError>;
Expand Down Expand Up @@ -65,6 +68,7 @@ impl ConductorAdmin for Conductor {
path: PathBuf,
id: String,
copy: bool,
expected_hash: Option<HashString>,
properties: Option<&serde_json::Value>,
) -> Result<(), HolochainError> {
let path_string = path
Expand All @@ -79,6 +83,12 @@ impl ConductorAdmin for Conductor {
))
})?;

if let Some(hash) = expected_hash {
if dna.address() != hash {
return Err(HolochainError::DnaHashMismatch(dna.address(), hash));
}
}

if let Some(props) = properties {
if !copy {
return Err(HolochainError::ConfigError(
Expand Down Expand Up @@ -673,6 +683,7 @@ pattern = '.*'"#
new_dna_path.clone(),
String::from("new-dna"),
false,
None,
None
),
Ok(()),
Expand Down Expand Up @@ -741,6 +752,7 @@ id = 'new-dna'"#,
new_dna_path.clone(),
String::from("new-dna"),
true,
None,
None
),
Ok(()),
Expand Down Expand Up @@ -779,6 +791,40 @@ id = 'new-dna'"#,
assert!(output_dna_file.is_file())
}

#[test]
fn test_install_dna_with_expected_hash() {
let test_name = "test_install_dna_with_expected_hash";
let mut conductor = create_test_conductor(test_name, 3000);
let mut new_dna_path = PathBuf::new();
new_dna_path.push("new-dna.dna.json");
let dna = Arc::get_mut(&mut conductor.dna_loader).unwrap()(&new_dna_path).unwrap();

assert_eq!(
conductor.install_dna_from_file(
new_dna_path.clone(),
String::from("new-dna"),
false,
Some(dna.address()),
None
),
Ok(()),
);

assert_eq!(
conductor.install_dna_from_file(
new_dna_path.clone(),
String::from("new-dna"),
false,
Some("wrong-address".into()),
None
),
Err(HolochainError::DnaHashMismatch(
dna.address(),
"wrong-address".into()
)),
);
}

#[test]
fn test_install_dna_from_file_with_properties() {
let test_name = "test_install_dna_from_file_with_properties";
Expand All @@ -793,6 +839,7 @@ id = 'new-dna'"#,
new_dna_path.clone(),
String::from("new-dna-with-props"),
false,
None,
Some(&new_props)
),
Err(HolochainError::ConfigError(
Expand All @@ -805,6 +852,7 @@ id = 'new-dna'"#,
new_dna_path.clone(),
String::from("new-dna-with-props"),
true,
None,
Some(&new_props)
),
Ok(()),
Expand Down Expand Up @@ -854,7 +902,13 @@ id = 'new-dna'"#,
let mut new_dna_path = PathBuf::new();
new_dna_path.push("new-dna.dna.json");
conductor
.install_dna_from_file(new_dna_path.clone(), String::from("new-dna"), false, None)
.install_dna_from_file(
new_dna_path.clone(),
String::from("new-dna"),
false,
None,
None,
)
.expect("Could not install DNA");

let add_result = conductor.add_instance(
Expand Down
14 changes: 14 additions & 0 deletions conductor_api/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ impl ConductorApiBuilder {
/// Params:
/// * `id`: [string] internal handle/name of the newly created DNA config
/// * `path`: [string] local file path to DNA file
/// * `expected_hash`: [string] (optional) the hash of this DNA. If this does not match the actual hash, installation will fail.
///
/// * `admin/dna/uninstall`
/// Uninstalls a DNA from the conductor config. Recursively also removes (and stops)
Expand Down Expand Up @@ -392,11 +393,24 @@ impl ConductorApiBuilder {
let id = Self::get_as_string("id", &params_map)?;
let path = Self::get_as_string("path", &params_map)?;
let copy = Self::get_as_bool("copy", &params_map).unwrap_or(false);
let expected_hash = match params_map.get("expected_hash") {
Some(value) => Some(
value
.as_str()
.ok_or(jsonrpc_core::Error::invalid_params(format!(
"`{}` is not a valid json string",
&value
)))?
.into(),
),
None => None,
};
let properties = params_map.get("properties");
conductor_call!(|c| c.install_dna_from_file(
PathBuf::from(path),
id.to_string(),
copy,
expected_hash,
properties
))?;
Ok(json!({"success": true}))
Expand Down
7 changes: 7 additions & 0 deletions core_types/src/error/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{
json::*,
};
use futures::channel::oneshot::Canceled as FutureCanceled;
use hash::HashString;
use serde_json::Error as SerdeError;
use std::{
error::Error,
Expand Down Expand Up @@ -96,6 +97,7 @@ pub enum HolochainError {
ConfigError(String),
Timeout,
InitializationFailed(String),
DnaHashMismatch(HashString, HashString),
}

pub type HcResult<T> = Result<T, HolochainError>;
Expand Down Expand Up @@ -127,6 +129,11 @@ impl fmt::Display for HolochainError {
ConfigError(err_msg) => write!(f, "{}", err_msg),
Timeout => write!(f, "timeout"),
InitializationFailed(err_msg) => write!(f, "{}", err_msg),
DnaHashMismatch(hash1, hash2) => write!(
f,
"DNA hash does not match expected hash!\n{} != {}",
hash1, hash2
),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions core_types/src/error/ribosome_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ impl From<HolochainError> for RibosomeErrorCode {
HolochainError::ConfigError(_) => RibosomeErrorCode::Unspecified,
HolochainError::Timeout => RibosomeErrorCode::Unspecified,
HolochainError::InitializationFailed(_) => RibosomeErrorCode::Unspecified,
HolochainError::DnaHashMismatch(_, _) => RibosomeErrorCode::Unspecified,
}
}
}
Expand Down