diff --git a/node/src/components/chainspec_handler/chainspec.rs b/node/src/components/chainspec_handler/chainspec.rs index 54e1827f05..89584fadec 100644 --- a/node/src/components/chainspec_handler/chainspec.rs +++ b/node/src/components/chainspec_handler/chainspec.rs @@ -20,26 +20,49 @@ use serde::{Deserialize, Serialize}; use types::{account::AccountHash, U512}; use super::{config, Error}; -use crate::{components::contract_runtime::shared::wasm_costs::WasmCosts, types::Motes}; +use crate::{ + components::contract_runtime::shared::wasm_costs::WasmCosts, + crypto::{asymmetric_key::PublicKey, hash::hash}, + types::Motes, +}; /// An account that exists at genesis. #[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] pub struct GenesisAccount { account_hash: AccountHash, + public_key: Option, balance: Motes, bonded_amount: Motes, } impl GenesisAccount { - /// Constructs a new `GenesisAccount`. + /// Constructs a new `GenesisAccount` with no public key. pub fn new(account_hash: AccountHash, balance: Motes, bonded_amount: Motes) -> Self { GenesisAccount { + public_key: None, account_hash, balance, bonded_amount, } } + /// Constructs a new `GenesisAccount` with a given public key. + pub fn with_public_key(public_key: PublicKey, balance: Motes, bonded_amount: Motes) -> Self { + // TODO: include the PK variant when hashing + let account_hash = AccountHash::new(hash(public_key).to_bytes()); + GenesisAccount { + public_key: Some(public_key), + account_hash, + balance, + bonded_amount, + } + } + + /// Returns the account's public key. + pub fn public_key(&self) -> Option { + self.public_key + } + /// Returns the account's hash. pub fn account_hash(&self) -> AccountHash { self.account_hash @@ -58,11 +81,13 @@ impl GenesisAccount { impl Distribution for Standard { fn sample(&self, rng: &mut R) -> GenesisAccount { + let public_key = None; let account_hash = AccountHash::new(rng.gen()); let balance = Motes::new(U512(rng.gen())); let bonded_amount = Motes::new(U512(rng.gen())); GenesisAccount { + public_key, account_hash, balance, bonded_amount, @@ -182,8 +207,6 @@ mod tests { use tempfile::NamedTempFile; - use types::account::ACCOUNT_HASH_LENGTH; - use super::*; const TEST_ROOT: &str = "resources/test/valid"; @@ -245,10 +268,6 @@ mod tests { assert_eq!(spec.genesis.accounts.len(), 4); for index in 0..4 { - assert_eq!( - spec.genesis.accounts[index].account_hash.value(), - [index as u8 + 1; ACCOUNT_HASH_LENGTH] - ); assert_eq!( spec.genesis.accounts[index].balance, Motes::new(U512::from(index + 1)) diff --git a/node/src/components/chainspec_handler/config.rs b/node/src/components/chainspec_handler/config.rs index 692fedede1..80469501c1 100644 --- a/node/src/components/chainspec_handler/config.rs +++ b/node/src/components/chainspec_handler/config.rs @@ -11,13 +11,13 @@ use csv::ReaderBuilder; use semver::Version; use serde::{Deserialize, Serialize}; -use types::{ - account::{AccountHash, ACCOUNT_HASH_LENGTH}, - U512, -}; +use types::U512; use super::{chainspec, Error}; -use crate::{components::contract_runtime::shared::wasm_costs::WasmCosts, types::Motes}; +use crate::{ + components::contract_runtime::shared::wasm_costs::WasmCosts, crypto::asymmetric_key::PublicKey, + types::Motes, +}; const DEFAULT_CHAIN_NAME: &str = "casperlabs-devnet"; const DEFAULT_MINT_INSTALLER_PATH: &str = "mint_install.wasm"; @@ -308,7 +308,8 @@ pub(super) fn parse_toml>(chainspec_path: P) -> Result>(file: P) -> Result, Error> { #[derive(Debug, Deserialize)] struct ParsedAccount { - account_hash: String, + public_key: String, + algorithm: String, balance: String, bonded_amount: String, } @@ -319,8 +320,9 @@ fn parse_accounts>(file: P) -> Result>(file: P) -> Result Result<[u8; ACCOUNT_HASH_LENGTH], Error> { - let decoded = if input.len() == 2 * ACCOUNT_HASH_LENGTH { - hex::decode(input)? - } else { - let decoded = base64::decode(input)?; - if decoded.len() != ACCOUNT_HASH_LENGTH { - return Err(Error::InvalidHashLength(decoded.len())); - } - decoded - }; - - let mut array = [0; ACCOUNT_HASH_LENGTH]; - array.copy_from_slice(decoded.as_slice()); - Ok(array) -} - #[cfg(test)] mod tests { use std::path::PathBuf; diff --git a/node/src/components/chainspec_handler/error.rs b/node/src/components/chainspec_handler/error.rs index 795ed6b2a6..2fcf9ce231 100644 --- a/node/src/components/chainspec_handler/error.rs +++ b/node/src/components/chainspec_handler/error.rs @@ -24,14 +24,14 @@ pub enum Error { #[error("decoding from hex error: {0}")] DecodingFromHex(#[from] hex::FromHexError), - /// Error while decoding a genesis account's key hash from base-64 format. - #[error("decoding from base-64 error: {0}")] - DecodingFromBase64(#[from] base64::DecodeError), - /// Error while decoding Motes from a decimal format. #[error("decoding motes from base-10 error: {0}")] DecodingMotes(#[from] FromDecStrErr), + /// Error while decoding a genesis account's key hash from base-64 format. + #[error("crypto module error: {0}")] + Crypto(#[from] crate::crypto::Error), + /// Decoding a genesis account's key hash yielded an invalid length byte array. #[error("expected hash length of {}, got {0}", ACCOUNT_HASH_LENGTH)] InvalidHashLength(usize), diff --git a/node/src/crypto/asymmetric_key.rs b/node/src/crypto/asymmetric_key.rs index 51a862625b..62dbecff84 100644 --- a/node/src/crypto/asymmetric_key.rs +++ b/node/src/crypto/asymmetric_key.rs @@ -14,6 +14,7 @@ use super::Result; const ED25519_TAG: u8 = 0; const ED25519: &str = "Ed25519"; +const ED25519_LOWERCASE: &str = "ed25519"; /// A secret or private asymmetric key. #[derive(Serialize, Deserialize)] @@ -72,6 +73,17 @@ impl PublicKey { Ok(PublicKey::Ed25519(ed25519::PublicKey::from_bytes(&bytes)?)) } + /// Constructs a new key from the algorithm name and a byte slice. + pub fn key_from_algorithm_name_and_bytes, T: AsRef<[u8]>>( + name: N, + bytes: T, + ) -> Result { + match &*name.as_ref().trim().to_lowercase() { + ED25519_LOWERCASE => Self::ed25519_from_bytes(bytes), + _ => panic!("Invalid algorithm name!"), + } + } + /// Constructs a new Ed25519 variant from a byte slice. pub fn ed25519_from_bytes>(bytes: T) -> Result { Ok(PublicKey::Ed25519(ed25519::PublicKey::from_bytes( diff --git a/resources/production/accounts.csv b/resources/production/accounts.csv index b03a980728..4536313439 100644 --- a/resources/production/accounts.csv +++ b/resources/production/accounts.csv @@ -1,5 +1,5 @@ -SLx/2wN11ID70D5390/+3DC585VEVf4E2hWEOgpq8Mc=,100000000000000000,0 -H2bqYyGkipNfZul9T35g7i1/yczGLfvjEPM7SDn8Yus=,1000000000000000,400000000000000 -iedEeDwtcJAqXy73joLh9EECtesIymI0JB2V5Q9hWms=,1000000000000000,300000000000000 -VptB1XTEY5AhLWmGYLUyYmndsKdh0SlCWIl6xxe0lYs=,1000000000000000,200000000000000 -0oZSZmPKN2bIB4FUOhSMY18jiL/hKJgcPkrGnOqI3DU=,1000000000000000,100000000000001 +48bc7fdb0375d480fbd03e77f74ffedc30b9f3954455fe04da15843a0a6af0c7,ed25519,100000000000000000,0 +1f66ea6321a48a935f66e97d4f7e60ee2d7fc9ccc62dfbe310f33b4839fc62eb,ed25519,1000000000000000,400000000000000 +89e744783c2d70902a5f2ef78e82e1f44102b5eb08ca6234241d95e50f615a6b,ed25519,1000000000000000,300000000000000 +569b41d574c46390212d698660b5326269ddb0a761d1294258897ac717b4958b,ed25519,1000000000000000,200000000000000 +d286526663ca3766c80781543a148c635f2388bfe128981c3e4ac69cea88dc35,ed25519,1000000000000000,100000000000001 diff --git a/resources/test/valid/accounts.csv b/resources/test/valid/accounts.csv index 951055b379..2a1544abbf 100644 --- a/resources/test/valid/accounts.csv +++ b/resources/test/valid/accounts.csv @@ -1,4 +1,4 @@ -AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE=,1,10 -AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI=,2,20 -0303030303030303030303030303030303030303030303030303030303030303,3,30 -0404040404040404040404040404040404040404040404040404040404040404,4,40 +48bc7fdb0375d480fbd03e77f74ffedc30b9f3954455fe04da15843a0a6af0c7,ed25519,1,10 +1f66ea6321a48a935f66e97d4f7e60ee2d7fc9ccc62dfbe310f33b4839fc62eb,Ed25519,2,20 +89e744783c2d70902a5f2ef78e82e1f44102b5eb08ca6234241d95e50f615a6b,eD25519,3,30 +569b41d574c46390212d698660b5326269ddb0a761d1294258897ac717b4958b,ED25519,4,40