Skip to content

Commit 27929e1

Browse files
authored
Remove hash, time and height from ChainClientState. (#4024)
## Motivation The next block height, most recent block hash, and most recent block timestamp are currently read from the wallet and put into `ChainClientState`, which is then updated frequently (but not always: #2652) based on the local node's chain state. So the fields in the `ChainClientState` are meant to first equal the values from the wallet, and then the values from the chain state view. ## Proposal Keep only the values from the wallet in `ChainClient` and never update them. Whenever the _current_ values are needed, read them from the chain state directly. ## Test Plan CI ## Release Plan - Nothing to do / These changes follow the usual release cycle. ## Links - Closes #2652. - _Partly_ addresses #2569. - [reviewer checklist](https://github.com/linera-io/linera-protocol/blob/main/CONTRIBUTING.md#reviewer-checklist)
1 parent 9224282 commit 27929e1

File tree

7 files changed

+212
-201
lines changed

7 files changed

+212
-201
lines changed

linera-client/src/client_context.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ where
100100
self.make_chain_client_internal(
101101
chain_id,
102102
chain.block_hash,
103-
chain.timestamp,
104103
chain.next_block_height,
105104
chain.pending_proposal,
106105
chain.owner,
@@ -272,15 +271,13 @@ impl<Env: Environment, W: Persist<Target = Wallet>> ClientContext<Env, W> {
272271
&self,
273272
chain_id: ChainId,
274273
block_hash: Option<CryptoHash>,
275-
timestamp: Timestamp,
276274
next_block_height: BlockHeight,
277275
pending_proposal: Option<PendingProposal>,
278276
preferred_owner: Option<AccountOwner>,
279277
) -> ChainClient<Env> {
280278
let mut chain_client = self.client.create_chain_client(
281279
chain_id,
282280
block_hash,
283-
timestamp,
284281
next_block_height,
285282
pending_proposal,
286283
preferred_owner,
@@ -316,7 +313,12 @@ impl<Env: Environment, W: Persist<Target = Wallet>> ClientContext<Env, W> {
316313
&mut self,
317314
client: &ChainClient<Env_>,
318315
) -> Result<(), Error> {
319-
self.wallet.as_mut().update_from_state(client);
316+
let info = client.chain_info().await?;
317+
let client_owner = client.preferred_owner();
318+
let pending_proposal = client.pending_proposal().clone();
319+
self.wallet
320+
.as_mut()
321+
.update_from_info(pending_proposal, client_owner, &info);
320322
self.save_wallet().await
321323
}
322324

@@ -777,7 +779,12 @@ where
777779

778780
info!("Updating wallet from chain clients...");
779781
for chain_client in chain_clients.values() {
780-
self.wallet.as_mut().update_from_state(chain_client);
782+
let info = chain_client.chain_info().await?;
783+
let client_owner = chain_client.preferred_owner();
784+
let pending_proposal = chain_client.pending_proposal().clone();
785+
self.wallet
786+
.as_mut()
787+
.update_from_info(pending_proposal, client_owner, &info);
781788
}
782789
self.save_wallet().await?;
783790
}
@@ -903,7 +910,6 @@ where
903910
let mut chain_client = self.make_chain_client_internal(
904911
chain_id,
905912
None,
906-
certificate.block().header.timestamp,
907913
BlockHeight::ZERO,
908914
None,
909915
Some(pub_key.into()),

linera-client/src/unit_tests/chain_listener.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ impl chain_listener::ClientContext for ClientContext {
5757
self.client.create_chain_client(
5858
chain_id,
5959
chain.block_hash,
60-
chain.timestamp,
6160
chain.next_block_height,
6261
chain.pending_proposal.clone(),
6362
chain.owner,
@@ -88,7 +87,11 @@ impl chain_listener::ClientContext for ClientContext {
8887
&mut self,
8988
client: &ChainClient<environment::Test>,
9089
) -> Result<(), Error> {
91-
self.wallet.update_from_state(client);
90+
let info = client.chain_info().await?;
91+
let client_owner = client.preferred_owner();
92+
let pending_proposal = client.pending_proposal().clone();
93+
self.wallet
94+
.update_from_info(pending_proposal, client_owner, &info);
9295
Ok(())
9396
}
9497
}

linera-client/src/wallet.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@ use linera_base::{
99
ensure,
1010
identifiers::{AccountOwner, ChainId},
1111
};
12-
use linera_core::{
13-
client::{ChainClient, PendingProposal},
14-
Environment,
15-
};
12+
use linera_core::{client::PendingProposal, data_types::ChainInfo};
1613
use serde::{Deserialize, Serialize};
1714

1815
use crate::{config::GenesisConfig, error, Error};
@@ -132,16 +129,19 @@ impl Wallet {
132129
Ok(())
133130
}
134131

135-
pub fn update_from_state<Env: Environment>(&mut self, chain_client: &ChainClient<Env>) {
136-
let client_owner = chain_client.preferred_owner();
137-
let state = chain_client.state();
132+
pub fn update_from_info(
133+
&mut self,
134+
pending_proposal: Option<PendingProposal>,
135+
owner: Option<AccountOwner>,
136+
info: &ChainInfo,
137+
) {
138138
self.insert(UserChain {
139-
chain_id: chain_client.chain_id(),
140-
owner: client_owner,
141-
block_hash: state.block_hash(),
142-
next_block_height: state.next_block_height(),
143-
timestamp: state.timestamp(),
144-
pending_proposal: state.pending_proposal().clone(),
139+
chain_id: info.chain_id,
140+
owner,
141+
block_hash: info.block_hash,
142+
next_block_height: info.next_block_height,
143+
timestamp: info.timestamp,
144+
pending_proposal,
145145
});
146146
}
147147

linera-core/src/client/chain_client_state.rs

Lines changed: 22 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,16 @@
44

55
use std::{collections::BTreeSet, sync::Arc};
66

7-
use linera_base::{
8-
crypto::CryptoHash,
9-
data_types::{Blob, BlockHeight, Timestamp},
10-
ensure,
11-
identifiers::AccountOwner,
12-
ownership::ChainOwnership,
13-
};
7+
use linera_base::data_types::Blob;
148
use linera_chain::data_types::ProposedBlock;
159
use tokio::sync::Mutex;
1610

17-
use super::{ChainClientError, PendingProposal};
11+
use super::PendingProposal;
1812
use crate::data_types::ChainInfo;
1913

2014
/// The state of our interaction with a particular chain: how far we have synchronized it and
2115
/// whether we are currently attempting to propose a new block.
2216
pub struct ChainClientState {
23-
/// Latest block hash, if any.
24-
block_hash: Option<CryptoHash>,
25-
/// The earliest possible timestamp for the next block.
26-
timestamp: Timestamp,
27-
/// Sequence number that we plan to use for the next block.
28-
/// We track this value outside local storage mainly for security reasons.
29-
next_block_height: BlockHeight,
3017
/// The block we are currently trying to propose for the next height, if any.
3118
///
3219
/// This is always at the same height as `next_block_height`.
@@ -38,71 +25,44 @@ pub struct ChainClientState {
3825
}
3926

4027
impl ChainClientState {
41-
pub fn new(
42-
block_hash: Option<CryptoHash>,
43-
timestamp: Timestamp,
44-
next_block_height: BlockHeight,
45-
pending_proposal: Option<PendingProposal>,
46-
) -> ChainClientState {
28+
pub fn new(pending_proposal: Option<PendingProposal>) -> ChainClientState {
4729
ChainClientState {
48-
block_hash,
49-
timestamp,
50-
next_block_height,
5130
pending_proposal,
5231
client_mutex: Arc::default(),
5332
}
5433
}
5534

56-
pub fn block_hash(&self) -> Option<CryptoHash> {
57-
self.block_hash
58-
}
59-
60-
pub fn timestamp(&self) -> Timestamp {
61-
self.timestamp
62-
}
63-
64-
pub fn next_block_height(&self) -> BlockHeight {
65-
self.next_block_height
66-
}
67-
6835
pub fn pending_proposal(&self) -> &Option<PendingProposal> {
6936
&self.pending_proposal
7037
}
7138

7239
pub(super) fn set_pending_proposal(&mut self, block: ProposedBlock, blobs: Vec<Blob>) {
73-
if block.height == self.next_block_height {
74-
let blobs = Vec::from_iter(blobs);
75-
assert_eq!(
76-
block.published_blob_ids(),
77-
BTreeSet::from_iter(blobs.iter().map(Blob::id))
78-
);
79-
self.pending_proposal = Some(PendingProposal { block, blobs });
80-
} else {
40+
if self
41+
.pending_proposal
42+
.as_ref()
43+
.is_some_and(|pending| pending.block.height >= block.height)
44+
{
8145
tracing::error!(
82-
"Not setting pending block at height {}, because next_block_height is {}.",
83-
block.height,
84-
self.next_block_height
46+
"Not setting pending block at {}, because we already have a pending proposal.",
47+
block.height
8548
);
49+
return;
8650
}
87-
}
88-
89-
/// Returns whether the given ownership includes anyone whose secret key we don't have.
90-
pub fn has_other_owners(
91-
&self,
92-
ownership: &ChainOwnership,
93-
preferred_owner: &Option<AccountOwner>,
94-
) -> bool {
95-
ownership
96-
.all_owners()
97-
.any(|owner| Some(owner) != preferred_owner.as_ref())
51+
let blobs = Vec::from_iter(blobs);
52+
assert_eq!(
53+
block.published_blob_ids(),
54+
BTreeSet::from_iter(blobs.iter().map(Blob::id))
55+
);
56+
self.pending_proposal = Some(PendingProposal { block, blobs });
9857
}
9958

10059
pub(super) fn update_from_info(&mut self, info: &ChainInfo) {
101-
if info.next_block_height > self.next_block_height {
102-
self.next_block_height = info.next_block_height;
60+
if self
61+
.pending_proposal
62+
.as_ref()
63+
.is_some_and(|pending| pending.block.height < info.next_block_height)
64+
{
10365
self.clear_pending_proposal();
104-
self.block_hash = info.block_hash;
105-
self.timestamp = info.timestamp;
10666
}
10767
}
10868

@@ -113,17 +73,4 @@ impl ChainClientState {
11373
pub(super) fn client_mutex(&self) -> Arc<Mutex<()>> {
11474
self.client_mutex.clone()
11575
}
116-
117-
/// Returns an error if the chain info does not match the block hash and height.
118-
pub(super) fn check_info_is_up_to_date(
119-
&self,
120-
info: &ChainInfo,
121-
) -> Result<(), ChainClientError> {
122-
ensure!(
123-
self.block_hash() == info.block_hash
124-
&& self.next_block_height() == info.next_block_height,
125-
ChainClientError::BlockProposalError("The chain is not synchronized.")
126-
);
127-
Ok(())
128-
}
12976
}

0 commit comments

Comments
 (0)