Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the genesis hash to the database #2928

Merged
merged 5 commits into from
Oct 27, 2022
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 2 additions & 2 deletions bin/light-base/src/json_rpc_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ impl ServicePrototype {
Default::default(),
),
}),
genesis_block: config.genesis_block_hash,
genesis_block_hash: config.genesis_block_hash,
next_subscription_id: atomic::AtomicU64::new(0),
subscriptions: Mutex::new(Subscriptions {
misc: HashMap::with_capacity_and_hasher(
Expand Down Expand Up @@ -466,7 +466,7 @@ struct Background<TPlat: Platform> {
/// Hash of the genesis block.
/// Keeping the genesis block is important, as the genesis block hash is included in
/// transaction signatures, and must therefore be queried by upper-level UIs.
genesis_block: [u8; 32],
genesis_block_hash: [u8; 32],

/// Identifier to use for the next subscription.
///
Expand Down
1 change: 1 addition & 0 deletions bin/light-base/src/json_rpc_service/chain_head.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1441,6 +1441,7 @@ impl<TPlat: Platform> Background<TPlat> {
let response = super::super::encode_database(
&self.network_service.0,
&self.sync_service,
&self.genesis_block_hash,
self.sync_service.block_number_bytes(),
usize::try_from(max_size_bytes.unwrap_or(u64::max_value()))
.unwrap_or(usize::max_value()),
Expand Down
4 changes: 2 additions & 2 deletions bin/light-base/src/json_rpc_service/getters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl<TPlat: Platform> Background<TPlat> {
.respond(
state_machine_request_id,
methods::Response::chainHead_unstable_genesisHash(methods::HashHexString(
self.genesis_block,
self.genesis_block_hash,
))
.to_json_response(request_id),
)
Expand Down Expand Up @@ -93,7 +93,7 @@ impl<TPlat: Platform> Background<TPlat> {
.respond(
state_machine_request_id,
methods::Response::chainSpec_unstable_genesisHash(methods::HashHexString(
self.genesis_block,
self.genesis_block_hash,
))
.to_json_response(request_id),
)
Expand Down
2 changes: 1 addition & 1 deletion bin/light-base/src/json_rpc_service/state_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ impl<TPlat: Platform> Background<TPlat> {
let response = {
match height {
Some(0) => methods::Response::chain_getBlockHash(methods::HashHexString(
self.genesis_block,
self.genesis_block_hash,
))
.to_json_response(request_id),
None => {
Expand Down
43 changes: 38 additions & 5 deletions bin/light-base/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,16 @@ impl<TPlat: platform::Platform, TChain> Client<TPlat, TChain> {
),
) {
// Use the database if it contains a more recent block than the chain spec checkpoint.
(Ok(Ok(genesis_ci)), checkpoint, Ok((database, checkpoint_nodes)))
if checkpoint
(
Ok(Ok(genesis_ci)),
checkpoint,
Ok((genesis_hash, database, checkpoint_nodes)),
) if genesis_hash
== genesis_ci
.as_ref()
.finalized_block_header
.hash(chain_spec.block_number_bytes().into())
&& checkpoint
.as_ref()
.and_then(|r| r.as_ref().ok())
.map_or(true, |cp| {
Expand All @@ -386,7 +394,7 @@ impl<TPlat: platform::Platform, TChain> Client<TPlat, TChain> {
(
Err(chain_spec::FromGenesisStorageError::UnknownStorageItems),
checkpoint,
Ok((database, checkpoint_nodes)),
Ok((database_genesis_hash, database, checkpoint_nodes)),
) if checkpoint
.as_ref()
.and_then(|r| r.as_ref().ok())
Expand All @@ -403,7 +411,20 @@ impl<TPlat: platform::Platform, TChain> Client<TPlat, TChain> {
digest: header::DigestRef::empty().into(),
};

(database, genesis_header, checkpoint_nodes)
if database_genesis_hash
== genesis_header.hash(chain_spec.block_number_bytes().into())
{
(database, genesis_header, checkpoint_nodes)
} else if let Some(Ok(checkpoint)) = checkpoint {
// Database is incorrect.
(checkpoint, genesis_header, checkpoint_nodes)
} else {
// TODO: we can in theory support chain specs that have neither a checkpoint nor the genesis storage, but it's complicated
return Err(
"Either a checkpoint or the genesis storage must be provided"
.to_string(),
);
}
}

(Err(chain_spec::FromGenesisStorageError::UnknownStorageItems), None, _) => {
Expand Down Expand Up @@ -1115,11 +1136,13 @@ async fn start_services<TPlat: platform::Platform>(
async fn encode_database<TPlat: platform::Platform>(
network_service: &network_service::NetworkService<TPlat>,
sync_service: &sync_service::SyncService<TPlat>,
genesis_block_hash: &[u8; 32],
block_number_bytes: usize,
max_size: usize,
) -> String {
// Craft the structure containing all the data that we would like to include.
let mut database_draft = SerdeDatabase {
genesis_hash: hex::encode(genesis_block_hash),
chain: match sync_service.serialize_chain_information().await {
Some(ci) => {
let encoded = finalized_serialize::encode_chain(&ci, block_number_bytes);
Expand Down Expand Up @@ -1188,13 +1211,20 @@ fn decode_database(
block_number_bytes: usize,
) -> Result<
(
[u8; 32],
chain::chain_information::ValidChainInformation,
Vec<(PeerId, Vec<multiaddr::Multiaddr>)>,
),
(),
> {
let decoded: SerdeDatabase = serde_json::from_str(encoded).map_err(|_| ())?;

let genesis_hash = if decoded.genesis_hash.len() == 64 {
<[u8; 32]>::try_from(hex::decode(&decoded.genesis_hash).map_err(|_| ())?).unwrap()
} else {
return Err(());
};

let (chain, _) = finalized_serialize::decode_chain(
&serde_json::to_string(&decoded.chain).unwrap(),
block_number_bytes,
Expand All @@ -1216,11 +1246,14 @@ fn decode_database(
})
.collect::<Vec<_>>();

Ok((chain, nodes))
Ok((genesis_hash, chain, nodes))
}

#[derive(serde::Serialize, serde::Deserialize)]
struct SerdeDatabase {
/// Hexadecimal-encoded hash of the genesis block header. Has no `0x` prefix.
#[serde(rename = "genesisHash")]
genesis_hash: String,
chain: Box<serde_json::value::RawValue>,
nodes: hashbrown::HashMap<String, Vec<String>, fnv::FnvBuildHasher>,
}
1 change: 1 addition & 0 deletions bin/wasm-node/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- The `payment_queryInfo` JSON-RPC function now works with runtimes that have defined the type of `Balance` to be less than 16 bytes. ([#2914](https://github.com/paritytech/smoldot/pull/2914))
- The parameter of `chainHead_unstable_finalizedDatabase` has been renamed from `max_size_bytes` to `maxSizeBytes`. ([#2923](https://github.com/paritytech/smoldot/pull/2923))
- The database now contains the hash of the genesis block header. This hash is verified when the database is loaded, and the database is ignored if there is a mismatch. This prevents accidents where the wrong database is provided, which would lead to the chain not working and would be hard to debug. ([#2928](https://github.com/paritytech/smoldot/pull/2928))

## 0.7.3 - 2022-10-19

Expand Down