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 4 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