Skip to content

Commit e939852

Browse files
authored
Faucet: some deduplication and added sanity check. (#4640)
## Motivation #4631 made the faucet use SQLite for the chains map, but it introduced some duplicated logic. Also, the rule that "start > end disables rate limiting" is strange. If no rate limiting is desired, one can just set start and end to 0, so all tokens are unlocked at all times. ## Proposal Deduplicate getting chain descriptions from a block; extract some utility functions; add a sanity check that created chains' owners are as expected; fix a few typos. Remove the rate limiting special case. ## Test Plan CI ## Release Plan - _Maybe_ backport to `testnet_conway` to keep the diff small. ## Links - Original PR: #4631 - [reviewer checklist](https://github.com/linera-io/linera-protocol/blob/main/CONTRIBUTING.md#reviewer-checklist)
1 parent 25d4466 commit e939852

File tree

6 files changed

+132
-158
lines changed

6 files changed

+132
-158
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

linera-chain/src/block.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -502,15 +502,15 @@ impl Block {
502502
&& blob_id.hash == self.header.chain_id.0))
503503
}
504504

505-
/// Returns all the published blob IDs in this block's operations.
505+
/// Returns all the published blob IDs in this block's transactions.
506506
pub fn published_blob_ids(&self) -> BTreeSet<BlobId> {
507507
self.body
508508
.operations()
509509
.flat_map(Operation::published_blob_ids)
510510
.collect()
511511
}
512512

513-
/// Returns all the blob IDs created by the block's operations.
513+
/// Returns all the blob IDs created by the block's transactions.
514514
pub fn created_blob_ids(&self) -> BTreeSet<BlobId> {
515515
self.body
516516
.blobs
@@ -520,7 +520,7 @@ impl Block {
520520
.collect()
521521
}
522522

523-
/// Returns all the blobs created by the block's operations.
523+
/// Returns all the blobs created by the block's transactions.
524524
pub fn created_blobs(&self) -> BTreeMap<BlobId, Blob> {
525525
self.body
526526
.blobs

linera-faucet/server/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ async-trait.workspace = true
5656
derive_more.workspace = true
5757
linera-views.workspace = true
5858
tempfile.workspace = true
59+
test-log.workspace = true
5960
[dev-dependencies.linera-core]
6061
features = ["test"]
6162
workspace = true

linera-faucet/server/src/database.rs

Lines changed: 8 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,17 @@ use std::{collections::BTreeMap, path::PathBuf};
77

88
use anyhow::Context as _;
99
use linera_base::{
10-
bcs,
1110
crypto::CryptoHash,
12-
data_types::{BlockHeight, ChainDescription},
11+
data_types::BlockHeight,
1312
identifiers::{AccountOwner, ChainId},
1413
};
15-
use linera_chain::{data_types::Transaction, types::ConfirmedBlockCertificate};
1614
use linera_core::client::ChainClient;
17-
use linera_execution::{system::SystemOperation, Operation};
1815
use linera_storage::Storage;
1916
use sqlx::{
2017
sqlite::{SqliteConnectOptions, SqlitePool, SqlitePoolOptions},
2118
Row,
2219
};
23-
use tracing::{debug, info};
20+
use tracing::info;
2421

2522
/// SQLite database for persistent storage of chain assignments.
2623
pub struct FaucetDatabase {
@@ -131,11 +128,11 @@ impl FaucetDatabase {
131128
let current_height = certificate.block().header.height;
132129

133130
// Check if this block's chains are already in our database
134-
let chains_in_block = self.extract_opened_chains(&certificate).await?;
131+
let chains_in_block = super::extract_opened_single_owner_chains(&certificate)?;
135132

136133
if !chains_in_block.is_empty() {
137134
let mut all_chains_exist = true;
138-
for (owner, _chain_id) in &chains_in_block {
135+
for (owner, _description) in &chains_in_block {
139136
if self.get_chain_id(owner).await?.is_none() {
140137
all_chains_exist = false;
141138
break;
@@ -180,7 +177,10 @@ impl FaucetDatabase {
180177
.await?
181178
.ok_or_else(|| anyhow::anyhow!("Certificate not found for hash {}", hash))?;
182179

183-
let chains_to_store = self.extract_opened_chains(&certificate).await?;
180+
let chains_to_store = super::extract_opened_single_owner_chains(&certificate)?
181+
.into_iter()
182+
.map(|(owner, description)| (owner, description.id()))
183+
.collect::<Vec<_>>();
184184

185185
if !chains_to_store.is_empty() {
186186
info!(
@@ -194,50 +194,6 @@ impl FaucetDatabase {
194194
Ok(())
195195
}
196196

197-
/// Extracts OpenChain operations from a certificate and returns (owner, chain_id) pairs.
198-
async fn extract_opened_chains(
199-
&self,
200-
certificate: &ConfirmedBlockCertificate,
201-
) -> anyhow::Result<Vec<(AccountOwner, ChainId)>> {
202-
let mut chains = Vec::new();
203-
let block = certificate.block();
204-
205-
// Parse chain descriptions from the block's blobs
206-
let blobs = block.body.blobs.iter().flatten();
207-
let chain_descriptions = blobs
208-
.map(|blob| bcs::from_bytes::<ChainDescription>(blob.bytes()))
209-
.collect::<Result<Vec<ChainDescription>, _>>()?;
210-
211-
let mut chain_desc_iter = chain_descriptions.into_iter();
212-
213-
// Examine each transaction in the block
214-
for transaction in &block.body.transactions {
215-
if let Transaction::ExecuteOperation(Operation::System(system_op)) = transaction {
216-
if let SystemOperation::OpenChain(config) = system_op.as_ref() {
217-
// Extract the owner from the OpenChain operation
218-
// We expect single-owner chains from the faucet
219-
let mut owners = config.ownership.all_owners();
220-
if let Some(owner) = owners.next() {
221-
// Verify it's a single-owner chain (faucet only creates these)
222-
if owners.next().is_none() {
223-
// Get the corresponding chain description from the blobs
224-
if let Some(description) = chain_desc_iter.next() {
225-
chains.push((*owner, description.id()));
226-
debug!(
227-
"Found OpenChain operation for owner {} creating chain {}",
228-
owner,
229-
description.id()
230-
);
231-
}
232-
}
233-
}
234-
}
235-
}
236-
}
237-
238-
Ok(chains)
239-
}
240-
241197
/// Gets the chain ID for an owner if it exists.
242198
pub async fn get_chain_id(&self, owner: &AccountOwner) -> anyhow::Result<Option<ChainId>> {
243199
let owner_str = owner.to_string();

0 commit comments

Comments
 (0)