Skip to content
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
20 changes: 19 additions & 1 deletion linera-client/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use linera_execution::{
use linera_rpc::config::{
ExporterServiceConfig, ValidatorInternalNetworkConfig, ValidatorPublicNetworkConfig,
};
use linera_storage::Storage;
use linera_storage::{NetworkDescription, Storage};
use serde::{Deserialize, Serialize};

#[derive(Debug, thiserror::Error)]
Expand All @@ -35,6 +35,8 @@ pub enum Error {
Chain(#[from] linera_chain::ChainError),
#[error("persistence error: {0}")]
Persistence(Box<dyn std::error::Error + Send + Sync>),
#[error("storage is already initialized: {0:?}")]
StorageIsAlreadyInitialized(NetworkDescription),
}

use crate::{
Expand Down Expand Up @@ -284,6 +286,13 @@ impl GenesisConfig {
where
S: Storage + Clone + Send + Sync + 'static,
{
if let Some(description) = storage
.read_network_description()
.await
.map_err(linera_chain::ChainError::from)?
{
return Err(Error::StorageIsAlreadyInitialized(description));
}
let committee = self.create_committee();
let committees: BTreeMap<_, _> = [(
Epoch::ZERO,
Expand All @@ -308,6 +317,15 @@ impl GenesisConfig {
let description = ChainDescription::new(origin, config, self.timestamp);
storage.create_chain(description).await?;
}
let network_description = NetworkDescription {
name: self.network_name.clone(),
genesis_config_hash: CryptoHash::new(self),
genesis_timestamp: self.timestamp,
};
storage
.write_network_description(&network_description)
.await
.map_err(linera_chain::ChainError::from)?;
Ok(())
}

Expand Down
5 changes: 3 additions & 2 deletions linera-core/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use linera_chain::{
ChainError,
};
use linera_execution::{committee::Committee, ExecutionError};
use linera_storage::NetworkDescription;
use linera_version::VersionInfo;
use linera_views::views::ViewError;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -92,8 +93,8 @@ pub trait ValidatorNode {
/// Gets the version info for this validator node.
async fn get_version_info(&self) -> Result<VersionInfo, NodeError>;

/// Gets the network's genesis config hash.
async fn get_genesis_config_hash(&self) -> Result<CryptoHash, NodeError>;
/// Gets the network's description.
async fn get_network_description(&self) -> Result<NetworkDescription, NodeError>;

/// Subscribes to receiving notifications for a collection of chains.
async fn subscribe(&self, chains: Vec<ChainId>) -> Result<Self::NotificationStream, NodeError>;
Expand Down
10 changes: 7 additions & 3 deletions linera-core/src/unit_tests/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use linera_chain::{
},
};
use linera_execution::{committee::Committee, ResourceControlPolicy, WasmRuntime};
use linera_storage::{DbStorage, Storage, TestClock};
use linera_storage::{DbStorage, NetworkDescription, Storage, TestClock};
#[cfg(all(not(target_arch = "wasm32"), feature = "storage-service"))]
use linera_storage_service::client::ServiceStoreClient;
use linera_version::VersionInfo;
Expand Down Expand Up @@ -173,8 +173,12 @@ where
Ok(Default::default())
}

async fn get_genesis_config_hash(&self) -> Result<CryptoHash, NodeError> {
Ok(CryptoHash::test_hash("genesis config"))
async fn get_network_description(&self) -> Result<NetworkDescription, NodeError> {
Ok(NetworkDescription {
name: "test network".to_string(),
genesis_config_hash: CryptoHash::test_hash("genesis config"),
genesis_timestamp: Timestamp::default(),
})
}

async fn upload_blob(&self, content: BlobContent) -> Result<BlobId, NodeError> {
Expand Down
10 changes: 8 additions & 2 deletions linera-rpc/proto/rpc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ service ValidatorNode {
// Request the node's version info.
rpc GetVersionInfo(google.protobuf.Empty) returns (VersionInfo);

// Request the genesis configuration hash of the network this node is part of.
rpc GetGenesisConfigHash(google.protobuf.Empty) returns (CryptoHash);
// Request the network description seen by this node.
rpc GetNetworkDescription(google.protobuf.Empty) returns (NetworkDescription);

// Download a blob.
rpc DownloadBlob(BlobId) returns (BlobContent);
Expand Down Expand Up @@ -120,6 +120,12 @@ message VersionInfo {
string wit_hash = 6;
}

message NetworkDescription {
string name = 1;
CryptoHash genesis_config_hash = 2;
uint64 genesis_timestamp = 3;
}

// A request for client to subscribe to notifications for a given `ChainId`
message SubscriptionRequest {
repeated ChainId chain_ids = 1;
Expand Down
8 changes: 5 additions & 3 deletions linera-rpc/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,14 @@ impl ValidatorNode for Client {
})
}

async fn get_genesis_config_hash(&self) -> Result<CryptoHash, NodeError> {
async fn get_network_description(
&self,
) -> Result<linera_storage::NetworkDescription, NodeError> {
Ok(match self {
Client::Grpc(grpc_client) => grpc_client.get_genesis_config_hash().await?,
Client::Grpc(grpc_client) => grpc_client.get_network_description().await?,

#[cfg(with_simple_network)]
Client::Simple(simple_client) => simple_client.get_genesis_config_hash().await?,
Client::Simple(simple_client) => simple_client.get_network_description().await?,
})
}

Expand Down
5 changes: 3 additions & 2 deletions linera-rpc/src/grpc/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use linera_core::{
node::{CrossChainMessageDelivery, NodeError, NotificationStream, ValidatorNode},
worker::Notification,
};
use linera_storage::NetworkDescription;
use linera_version::VersionInfo;
use tonic::{Code, IntoRequest, Request, Status};
use tracing::{debug, error, info, instrument, warn};
Expand Down Expand Up @@ -346,9 +347,9 @@ impl ValidatorNode for GrpcClient {
}

#[instrument(target = "grpc_client", skip_all, err, fields(address = self.address))]
async fn get_genesis_config_hash(&self) -> Result<CryptoHash, NodeError> {
async fn get_network_description(&self) -> Result<NetworkDescription, NodeError> {
let req = ();
Ok(client_delegate!(self, get_genesis_config_hash, req)?.try_into()?)
Ok(client_delegate!(self, get_network_description, req)?.try_into()?)
}

#[instrument(target = "grpc_client", skip(self), err, fields(address = self.address))]
Expand Down
34 changes: 34 additions & 0 deletions linera-rpc/src/grpc/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,40 @@ impl From<api::VersionInfo> for linera_version::VersionInfo {
}
}

impl From<linera_storage::NetworkDescription> for api::NetworkDescription {
fn from(
linera_storage::NetworkDescription {
name,
genesis_config_hash,
genesis_timestamp,
}: linera_storage::NetworkDescription,
) -> Self {
Self {
name,
genesis_config_hash: Some(genesis_config_hash.into()),
genesis_timestamp: genesis_timestamp.micros(),
}
}
}

impl TryFrom<api::NetworkDescription> for linera_storage::NetworkDescription {
type Error = GrpcProtoConversionError;

fn try_from(
api::NetworkDescription {
name,
genesis_config_hash,
genesis_timestamp,
}: api::NetworkDescription,
) -> Result<Self, Self::Error> {
Ok(Self {
name,
genesis_config_hash: try_proto_convert(genesis_config_hash)?,
genesis_timestamp: genesis_timestamp.into(),
})
}
}

impl TryFrom<Notification> for api::Notification {
type Error = GrpcProtoConversionError;

Expand Down
24 changes: 17 additions & 7 deletions linera-rpc/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use linera_core::{
data_types::{ChainInfoQuery, ChainInfoResponse, CrossChainRequest},
node::NodeError,
};
use linera_storage::NetworkDescription;
use linera_version::VersionInfo;
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -42,14 +43,14 @@ pub enum RpcMessage {
BlobLastUsedBy(Box<BlobId>),
MissingBlobIds(Vec<BlobId>),
VersionInfoQuery,
GenesisConfigHashQuery,
NetworkDescriptionQuery,

// Outbound
Vote(Box<LiteVote>),
ChainInfoResponse(Box<ChainInfoResponse>),
Error(Box<NodeError>),
VersionInfoResponse(Box<VersionInfo>),
GenesisConfigHashResponse(Box<CryptoHash>),
NetworkDescriptionResponse(Box<NetworkDescription>),
UploadBlobResponse(Box<BlobId>),
DownloadBlobResponse(Box<BlobContent>),
DownloadPendingBlobResponse(Box<BlobContent>),
Expand Down Expand Up @@ -84,8 +85,8 @@ impl RpcMessage {
| ChainInfoResponse(_)
| VersionInfoQuery
| VersionInfoResponse(_)
| GenesisConfigHashQuery
| GenesisConfigHashResponse(_)
| NetworkDescriptionQuery
| NetworkDescriptionResponse(_)
| UploadBlob(_)
| UploadBlobResponse(_)
| DownloadBlob(_)
Expand Down Expand Up @@ -113,7 +114,7 @@ impl RpcMessage {

match self {
VersionInfoQuery
| GenesisConfigHashQuery
| NetworkDescriptionQuery
| UploadBlob(_)
| DownloadBlob(_)
| DownloadConfirmedBlock(_)
Expand All @@ -131,7 +132,7 @@ impl RpcMessage {
| Error(_)
| ChainInfoResponse(_)
| VersionInfoResponse(_)
| GenesisConfigHashResponse(_)
| NetworkDescriptionResponse(_)
| UploadBlobResponse(_)
| DownloadPendingBlob(_)
| DownloadPendingBlobResponse(_)
Expand Down Expand Up @@ -206,13 +207,22 @@ impl TryFrom<RpcMessage> for CryptoHash {
fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
match message {
RpcMessage::BlobLastUsedByResponse(hash) => Ok(*hash),
RpcMessage::GenesisConfigHashResponse(hash) => Ok(*hash),
RpcMessage::Error(error) => Err(*error),
_ => Err(NodeError::UnexpectedMessage),
}
}
}

impl TryFrom<RpcMessage> for NetworkDescription {
type Error = NodeError;
fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
match message {
RpcMessage::NetworkDescriptionResponse(description) => Ok(*description),
_ => Err(NodeError::UnexpectedMessage),
}
}
}

impl TryFrom<RpcMessage> for Vec<BlobId> {
type Error = NodeError;
fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
Expand Down
5 changes: 3 additions & 2 deletions linera-rpc/src/simple/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use linera_core::{
data_types::{ChainInfoQuery, ChainInfoResponse},
node::{CrossChainMessageDelivery, NodeError, NotificationStream, ValidatorNode},
};
use linera_storage::NetworkDescription;
use linera_version::VersionInfo;

use super::{codec, transport::TransportProtocol};
Expand Down Expand Up @@ -156,8 +157,8 @@ impl ValidatorNode for SimpleClient {
self.query(RpcMessage::VersionInfoQuery).await
}

async fn get_genesis_config_hash(&self) -> Result<CryptoHash, NodeError> {
self.query(RpcMessage::GenesisConfigHashQuery).await
async fn get_network_description(&self) -> Result<NetworkDescription, NodeError> {
self.query(RpcMessage::NetworkDescriptionQuery).await
}

async fn upload_blob(&self, content: BlobContent) -> Result<BlobId, NodeError> {
Expand Down
4 changes: 2 additions & 2 deletions linera-rpc/src/simple/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,8 @@ where
| RpcMessage::Error(_)
| RpcMessage::ChainInfoResponse(_)
| RpcMessage::VersionInfoResponse(_)
| RpcMessage::GenesisConfigHashQuery
| RpcMessage::GenesisConfigHashResponse(_)
| RpcMessage::NetworkDescriptionQuery
| RpcMessage::NetworkDescriptionResponse(_)
| RpcMessage::DownloadBlob(_)
| RpcMessage::DownloadBlobResponse(_)
| RpcMessage::DownloadPendingBlobResponse(_)
Expand Down
13 changes: 10 additions & 3 deletions linera-rpc/tests/snapshots/format__format.yaml.snap
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,13 @@ ModuleId:
TYPENAME: CryptoHash
- vm_runtime:
TYPENAME: VmRuntime
NetworkDescription:
STRUCT:
- name: STR
- genesis_config_hash:
TYPENAME: CryptoHash
- genesis_timestamp:
TYPENAME: Timestamp
NodeError:
ENUM:
0:
Expand Down Expand Up @@ -984,7 +991,7 @@ RpcMessage:
14:
VersionInfoQuery: UNIT
15:
GenesisConfigHashQuery: UNIT
NetworkDescriptionQuery: UNIT
16:
Vote:
NEWTYPE:
Expand All @@ -1002,9 +1009,9 @@ RpcMessage:
NEWTYPE:
TYPENAME: VersionInfo
20:
GenesisConfigHashResponse:
NetworkDescriptionResponse:
NEWTYPE:
TYPENAME: CryptoHash
TYPENAME: NetworkDescription
21:
UploadBlobResponse:
NEWTYPE:
Expand Down
39 changes: 23 additions & 16 deletions linera-service/src/linera/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,12 +456,15 @@ impl Runnable for Job {
}

let genesis_config_hash = context.wallet().genesis_config().hash();
match node.get_genesis_config_hash().await {
Ok(hash) if hash == genesis_config_hash => {}
Ok(hash) => error!(
"Validator's genesis config hash {} does not match our own: {}.",
hash, genesis_config_hash
),
match node.get_network_description().await {
Ok(description) => {
if description.genesis_config_hash != genesis_config_hash {
error!(
"Validator's genesis config hash {} does not match our own: {}.",
description.genesis_config_hash, genesis_config_hash
);
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it might be useful to also print both network names. (Also below.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmm I'm going to send another PR for this.

Err(error) => {
error!(
"Failed to get genesis config hash for validator {address}:\n{error}"
Expand Down Expand Up @@ -631,16 +634,20 @@ impl Runnable for Job {
),
}
let genesis_config_hash = context.wallet().genesis_config().hash();
match node.get_genesis_config_hash().await {
Ok(hash) if hash == genesis_config_hash => {}
Ok(hash) => bail!(
"Validator's genesis config hash {} does not match our own: {}.",
hash,
genesis_config_hash
),
Err(error) => bail!(
"Failed to get genesis config hash for validator {public_key:?} at {address}:\n{error}"
),
match node.get_network_description().await {
Ok(description) => {
if description.genesis_config_hash != genesis_config_hash {
error!(
"Validator's genesis config hash {} does not match our own: {}.",
description.genesis_config_hash, genesis_config_hash
);
}
}
Err(error) => {
error!(
"Failed to get genesis config hash for validator {address}:\n{error}"
)
}
}
}
let chain_client = context
Expand Down
Loading