Query utxos on cardano cli#831
Conversation
Add security policy outlining supported versions and reporting process.
📝 WalkthroughWalkthroughAdds a new o7s_unix Changes
Sequence DiagramsequenceDiagram
actor Client
participant Mod as o7s_unix::handle_session
participant Plexer as Plexer
participant Chainsync as ChainsyncTask
participant StateQ as StateQueryTask
participant Session as statequery::Session
participant Domain as Domain
Client->>Mod: open connection
Mod->>Plexer: create plexer
Mod->>Chainsync: spawn ChainsyncTask (CancelToken, plexer)
Mod->>StateQ: spawn StateQueryTask (CancelToken, plexer)
par Concurrent
Chainsync->>Domain: request blocks / sync
Domain-->>Chainsync: block data
StateQ->>Session: initialize session
Session->>Domain: acquire/reacquire point, query tip/UTxO/era
Domain-->>Session: ledger/UTxO/era data
Session->>StateQ: encode CBOR response
StateQ->>Client: send response
end
Chainsync-->>Mod: task result
StateQ-->>Mod: task result
Mod->>Mod: tokio::try_join both tasks
alt join failure
Mod->>Mod: map to ServeError::Internal
else join success
Mod->>Mod: propagate each task's Result
end
Mod->>Plexer: abort
Mod-->>Client: close session
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @src/serve/o7s_unix/statequery.rs:
- Around line 474-484: The match for computing era_index (used when constructing
AnyCbor::from_encode(era_index as u16)) incorrectly groups protocol 8 into the
Conway fallback; update the match on edge.protocol in the era_index binding to
explicitly map Babbage variants to 5 and Conway variants to 6 (e.g. change the
arms to include 7..=8 => 5 for Babbage and 9..=10 => 6 for Conway or extend
ranges as needed) and remove the wildcard catch-all that currently maps
future/unknown versions to Conway so the mapping is explicit.
- Around line 166-174: The code currently hardcodes script_ref: None when
building q16::PostAlonsoTransactionOutput; call output.script_ref() to extract
the Option and convert it to the q16 type (e.g., using .map(|sr| sr.into()) or
the same conversion helper used elsewhere) and set script_ref to that value so
reference scripts are returned; update the block constructing
q16::PostAlonsoTransactionOutput (the code that sets address, amount,
inline_datum) to use output.script_ref().map(...) instead of None.
🧹 Nitpick comments (1)
src/serve/o7s_unix/statequery.rs (1)
274-294: Consider avoiding the clone ofrefs_vec.The
refs_vec.clone()is necessary here becauseget_utxostakes ownership andrefs_vecis reused in the loop. However, you could iterate overutxos.keys()instead if the return order doesn't matter, or restructure to avoid the clone:♻️ Suggested refactor to avoid clone
- let refs_vec: Vec<_> = all_refs.into_iter().collect(); - let utxos = domain - .state() - .get_utxos(refs_vec.clone()) - .map_err(|e| Error::server(format!("failed to get utxos: {}", e)))?; - - debug!(fetched_utxos = utxos.len(), "fetched utxo data"); - - for utxo_ref in refs_vec { - if let Some(era_cbor) = utxos.get(&utxo_ref) { + let refs_vec: Vec<_> = all_refs.into_iter().collect(); + let utxos = domain + .state() + .get_utxos(refs_vec) + .map_err(|e| Error::server(format!("failed to get utxos: {}", e)))?; + + debug!(fetched_utxos = utxos.len(), "fetched utxo data"); + + for (utxo_ref, era_cbor) in utxos {
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/serve/o7s_unix/mod.rssrc/serve/o7s_unix/statequery.rs
🧰 Additional context used
🧬 Code graph analysis (1)
src/serve/o7s_unix/mod.rs (3)
src/serve/o7s_unix/statequery.rs (1)
handle_session(596-623)src/relay/mod.rs (1)
handle_session(19-41)src/serve/o7s_unix/chainsync.rs (1)
handle_session(188-210)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Check Build
🔇 Additional comments (11)
src/serve/o7s_unix/mod.rs (3)
10-10: LGTM!The new statequery module is properly declared alongside the existing chainsync module.
21-26: LGTM!Clean destructuring of
NodeServerto extract the required protocol handlers.
28-48: LGTM!The concurrent task handling pattern is sound. Both sessions run independently with proper error propagation. The approach differs from
src/relay/mod.rswhich usestry_join!directly on futures (no spawning) and ignores results - this implementation is more robust by propagating individual task errors.Note that if one task errors, the other continues running until natural completion since there's no cross-cancellation. This is acceptable for independent protocol sessions.
src/serve/o7s_unix/statequery.rs (8)
1-10: LGTM!Imports are appropriate for the statequery protocol implementation.
50-76: Verify the EraParams CBOR structure.The
safe_from_tipvalue is encoded twice: once within the SafeZone block (lines 58-73) and again at line 75 after the SafeZone. This appears to encode a 4-element array (encoder.array(4)at line 51) with elements: epoch_length, slot_length, SafeZone, and safe_from_tip.Please confirm this matches the expected CBOR schema for era parameters.
186-229: LGTM!Comprehensive recursive conversion of all
PlutusDatavariants.
368-377: Verify theChainPoint::Slot(_)existence check.Line 376 assumes that any
ChainPoint::Slotexists on the chain (=> true). However,tip_cursor()at line 364 can return aChainPoint::Slotwhich might not have a corresponding block. If the slot was never filled (a slot without a block), this could lead to inconsistent behavior downstream.Consider validating slot existence explicitly or clarifying why this assumption is safe.
394-416: LGTM!The
GetSystemStartquery implementation correctly converts the timestamp to the expected protocol format (year, day of year, picoseconds of day).
418-440: LGTM!The block number conversion uses
try_fromwithunwrap_or(u32::MAX)which safely handles overflow. The comment at line 432 documents the intent.
524-531: Consider if returning null for unknown queries is the desired protocol behavior.Currently, unhandled queries and decode failures return
AnyCbor::from_encode(())(null/unit). This is a reasonable fallback, but some clients might expect an error response instead. The warning logs provide good visibility for debugging.
596-623: LGTM!The
handle_sessionimplementation follows the established pattern fromchainsync::handle_session, with proper cancellation support and error handling.
| if output.era() >= pallas::ledger::traverse::Era::Alonzo { | ||
| Ok(q16::TransactionOutput::Current( | ||
| q16::PostAlonsoTransactionOutput { | ||
| address: address.into(), | ||
| amount: value, | ||
| inline_datum, | ||
| script_ref: None, | ||
| }, | ||
| )) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n -C3 'script_ref|reference_script|ScriptRef' --type rustRepository: txpipe/dolos
Length of output: 4242
🏁 Script executed:
# Also, let's look at the full context of the convert_output_to_q16 function
sed -n '112,184p' src/serve/o7s_unix/statequery.rsRepository: txpipe/dolos
Length of output: 2541
🏁 Script executed:
# Check the function signature and input parameters
sed -n '100,115p' src/serve/o7s_unix/statequery.rsRepository: txpipe/dolos
Length of output: 515
🏁 Script executed:
# Search for MultiEraOutput definition and methods
rg -n 'impl.*MultiEraOutput|fn script_ref' --type rust -A 3 | head -50Repository: txpipe/dolos
Length of output: 1568
🏁 Script executed:
# Check the pallas crate for MultiEraOutput and its methods
rg -n 'struct MultiEraOutput|enum MultiEraOutput' --type rust -A 10Repository: txpipe/dolos
Length of output: 38
🏁 Script executed:
# Look at the q16 module to understand PostAlonsoTransactionOutput structure
rg -n 'PostAlonsoTransactionOutput|struct.*TransactionOutput' --type rust -A 5 | head -60Repository: txpipe/dolos
Length of output: 475
🏁 Script executed:
# Check imports and find MultiEraOutput origin
rg -n 'use.*MultiEraOutput|from pallas' src/serve/o7s_unix/statequery.rs | head -20Repository: txpipe/dolos
Length of output: 134
🏁 Script executed:
# Check if script_ref is being used in other parts of the codebase with output
rg -n 'output\.script_ref\(\)' --type rustRepository: txpipe/dolos
Length of output: 38
🏁 Script executed:
# Search for the q16 module definition to understand the structure
find . -name "*.rs" -type f | xargs grep -l "mod q16\|pub mod q16" | head -5Repository: txpipe/dolos
Length of output: 38
🏁 Script executed:
# Find where q16 types are defined
find . -name "*.rs" -type f | xargs grep -l "PostAlonsoTransactionOutput" | head -10Repository: txpipe/dolos
Length of output: 90
🏁 Script executed:
# Check the actual definition of PostAlonsoTransactionOutput
rg -n 'PostAlonsoTransactionOutput' --type rust -B 2 -A 8 | head -80Repository: txpipe/dolos
Length of output: 834
🏁 Script executed:
# Verify MultiEraOutput has script_ref method from pallas documentation/source
rg -n 'script_ref' crates/minibf/src/mapping.rs -B 2 -A 2 | head -60Repository: txpipe/dolos
Length of output: 760
🏁 Script executed:
# Check what type PostAlonsoTransactionOutput expects for script_ref
rg -n 'script_ref:' --type rust -B 5 -A 1 | head -40Repository: txpipe/dolos
Length of output: 1037
🏁 Script executed:
# Look at the full definition in the file where PostAlonsoTransactionOutput is defined
sed -n '1,50p' src/serve/o7s_unix/statequery.rs | grep -n "use\|mod"Repository: txpipe/dolos
Length of output: 546
🏁 Script executed:
# Check imports at the top of statequery.rs to find q16 definition
head -30 src/serve/o7s_unix/statequery.rsRepository: txpipe/dolos
Length of output: 1047
🏁 Script executed:
# Check the exact definition of q16::PostAlonsoTransactionOutput
rg -n 'PostAlonsoTransactionOutput' -A 10 | grep -A 10 "struct\|pub struct" | head -30Repository: txpipe/dolos
Length of output: 38
🏁 Script executed:
# Check if there's documentation or examples of how script_ref should be populated
rg -n 'script_ref.*Some\|Some.*script_ref' --type rust -B 2 -A 2 | head -30Repository: txpipe/dolos
Length of output: 38
🏁 Script executed:
# Let's search for any conversion or handling of script references in the entire statequery.rs file
cat src/serve/o7s_unix/statequery.rs | grep -n -i 'script'Repository: txpipe/dolos
Length of output: 93
🏁 Script executed:
# Check the pallas crate documentation or source to understand MultiEraOutput better
# by looking at how it's used elsewhere in the project
rg -n 'MultiEraOutput.*script' --type rustRepository: txpipe/dolos
Length of output: 38
🏁 Script executed:
# Check if there's any mapping/conversion logic that might handle script_ref elsewhere
rg -n 'fn.*output.*q16|to_q16' --type rust -A 5Repository: txpipe/dolos
Length of output: 969
Extract and convert the script reference from the output.
script_ref is hardcoded to None, which means reference scripts attached to UTxOs will not be returned to clients. The MultiEraOutput provides a script_ref() method (as evidenced by its use in other parts of the codebase like crates/minibf/src/mapping.rs), but it is not being called here. This could cause issues for DApps that rely on reference scripts for transaction building.
Extract the script reference using output.script_ref() and convert it appropriately for the q16::PostAlonsoTransactionOutput structure.
🤖 Prompt for AI Agents
In @src/serve/o7s_unix/statequery.rs around lines 166 - 174, The code currently
hardcodes script_ref: None when building q16::PostAlonsoTransactionOutput; call
output.script_ref() to extract the Option and convert it to the q16 type (e.g.,
using .map(|sr| sr.into()) or the same conversion helper used elsewhere) and set
script_ref to that value so reference scripts are returned; update the block
constructing q16::PostAlonsoTransactionOutput (the code that sets address,
amount, inline_datum) to use output.script_ref().map(...) instead of None.
| let era_index = match edge.protocol { | ||
| 0..=1 => 0, // Byron | ||
| 2 => 1, // Shelley | ||
| 3 => 2, // Allegra | ||
| 4 => 3, // Mary | ||
| 5..=6 => 4, // Alonzo | ||
| 7 => 5, // Babbage | ||
| _ => 6, // Conway | ||
| }; | ||
|
|
||
| AnyCbor::from_encode(era_index as u16) |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Cardano era protocol version mapping Byron Shelley Allegra Mary Alonzo Babbage Conway
💡 Result:
Here’s the protocol-version (major.minor) mapping by Cardano era:
- Byron — 0.0, 1.0. [1][2]
- Shelley — 2.0. [1][2]
- Allegra — 3.0. [1][2]
- Mary — 4.0. [1][2]
- Alonzo — 5.0 (initial) and 6.0 (intra-era update). [2][3]
- Babbage — 7.0 (Babbage/Vasil entry) and 8.0 (subsequent intra-era update). [2][3]
- Conway — 9.0 (Chang) and 10.0+ (Plomin / later governance updates). [2][3]
Sources: Cardano Developer docs / era table and CIP‑59 feature table; ouroboros‑consensus era-transition notes. [1][2][3]
References
[1] Cardano Developer Portal — Cardano ledger eras / governance (era ↔ protocol version table).
[2] CIP‑59 feature table (era, slot/epoch, protocol version entries).
[3] ouroboros‑consensus — era transition / protocol version governance notes.
🏁 Script executed:
# Search for protocol version references in the codebase
rg "protocol.*version|era.*protocol|Byron|Shelley|Allegra|Mary|Alonzo|Babbage|Conway" --type rust -i -A 2 -B 2Repository: txpipe/dolos
Length of output: 50369
Fix incomplete era index mapping for protocol versions 8 and beyond.
The mapping omits protocol version 8 (Babbage intra-era update), causing it to incorrectly map to Conway (6) instead of Babbage (5). Additionally, the catch-all _ => 6 should explicitly handle Conway protocol versions 9+ rather than relying on a wildcard, which would incorrectly classify any future protocol versions.
Update the match expression to:
7..=8 => 5for Babbage9..=10 => 6for Conway (or extend as needed for future Conway protocol versions)
Current code
let era_index = match edge.protocol {
0..=1 => 0, // Byron
2 => 1, // Shelley
3 => 2, // Allegra
4 => 3, // Mary
5..=6 => 4, // Alonzo
7 => 5, // Babbage
_ => 6, // Conway
};🤖 Prompt for AI Agents
In @src/serve/o7s_unix/statequery.rs around lines 474 - 484, The match for
computing era_index (used when constructing AnyCbor::from_encode(era_index as
u16)) incorrectly groups protocol 8 into the Conway fallback; update the match
on edge.protocol in the era_index binding to explicitly map Babbage variants to
5 and Conway variants to 6 (e.g. change the arms to include 7..=8 => 5 for
Babbage and 9..=10 => 6 for Conway or extend ranges as needed) and remove the
wildcard catch-all that currently maps future/unknown versions to Conway so the
mapping is explicit.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/serve/o7s_unix/statequery.rs`:
- Line 66: The multiplication era.slot_length * 1000 can overflow; replace it
with a checked multiply and handle the error before calling encoder.u64. For
example, compute let millis = era.slot_length.checked_mul(1000).ok_or(/*
appropriate overflow error */)? and then call encoder.u64(millis)?; update the
surrounding function (the code that calls encoder.u64) to propagate or map the
overflow error appropriately so overflows don't panic or wrap.
- Around line 433-443: The current snippet silently treats a decode failure as
block number 0; instead, when calling MultiEraBlock::decode on the raw tip from
self.domain.archive().get_tip(), propagate the decode error rather than
returning 0: retrieve the tip, attempt to decode with
MultiEraBlock::decode(&raw) and convert any decode error into the crate Error
(e.g., via map_err or the ? operator) so the surrounding function returns an
error on decode failure; only fall back to 0 when get_tip() returns None, not
when decoding fails.
♻️ Duplicate comments (1)
src/serve/o7s_unix/statequery.rs (1)
179-187:script_refis still hardcoded toNone.This was previously flagged. Reference scripts attached to UTxOs will not be returned to clients, which could cause issues for DApps that rely on reference scripts for transaction building.
🧹 Nitpick comments (1)
src/serve/o7s_unix/statequery.rs (1)
459-463: TheChainPoint::Slotmatch arms at lines 462 and 510 are unreachable defensive code.The
tip_cursor()method (lines 323-347) converts allChainPoint::Slotvariants toChainPoint::Specificbefore returning, so it should never returnSlot. The match arms that handleChainPoint::Slot(_) => OPoint::Originat lines 462 and 510 are therefore unreachable.However, note that
GetEpochNoat line 524 explicitly handlesChainPoint::Slot(s), suggesting developers anticipated this case despite the implementation preventing it. Consider either:
- Removing these unreachable arms (if confident in tip_cursor's guarantee)
- Adding a comment explaining they're defensive
- Ensuring consistency across all query handlers
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/serve/o7s_unix/statequery.rs
🧰 Additional context used
🧬 Code graph analysis (1)
src/serve/o7s_unix/statequery.rs (4)
crates/core/src/lib.rs (1)
era(79-81)src/prelude.rs (1)
server(56-58)crates/cardano/src/eras.rs (1)
edge(96-99)src/serve/o7s_unix/mod.rs (1)
handle_session(16-49)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Check Build
🔇 Additional comments (6)
src/serve/o7s_unix/statequery.rs (6)
1-16: LGTM!Imports and the
EraHistoryResponsestruct are well-organized and appropriate for the state query functionality.
95-123: LGTM!Proper validation and error handling for building the era history response.
199-242: LGTM!Comprehensive Plutus data conversion handling all variants correctly with proper recursive processing.
244-314: LGTM!Good implementation with proper deduplication, fallback to payment credential lookup, and comprehensive debug logging.
487-496: Era index mapping has been corrected.The mapping now properly handles protocol version 8 as Babbage (
7..=8 => 5) and explicitly maps Conway versions (9..=10 => 6). The wildcard fallback for unknown future versions is a reasonable default.
610-637: LGTM!Clean async session handling with proper cancellation support via
tokio::select!and appropriate error propagation.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| // EraParams | ||
| encoder.array(4)?; | ||
| encoder.u64(era.epoch_length)?; | ||
| encoder.u64(era.slot_length * 1000)?; |
There was a problem hiding this comment.
Potential integer overflow on slot_length multiplication.
This line lacks the overflow protection applied elsewhere in this function. If slot_length exceeds u64::MAX / 1000, this will overflow in debug builds (panic) or wrap in release builds.
🔧 Suggested fix
- encoder.u64(era.slot_length * 1000)?;
+ encoder.u64(era.slot_length.saturating_mul(1000))?;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| encoder.u64(era.slot_length * 1000)?; | |
| encoder.u64(era.slot_length.saturating_mul(1000))?; |
🤖 Prompt for AI Agents
In `@src/serve/o7s_unix/statequery.rs` at line 66, The multiplication
era.slot_length * 1000 can overflow; replace it with a checked multiply and
handle the error before calling encoder.u64. For example, compute let millis =
era.slot_length.checked_mul(1000).ok_or(/* appropriate overflow error */)? and
then call encoder.u64(millis)?; update the surrounding function (the code that
calls encoder.u64) to propagate or map the overflow error appropriately so
overflows don't panic or wrap.
…ve error handling in tip block decoding
…d enhance query request handling
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/serve/o7s_unix/statequery.rs`:
- Around line 167-177: The two Option transformations use and_then with closures
that always return Some(...); change them to use map so the closure directly
returns the transformed value: update the inline_datum assignment (which
currently calls output.datum().and_then(|d| match d { DatumOption::Hash(h) =>
Some(q16::DatumOption::Hash(h)), DatumOption::Data(data) =>
Some(q16::DatumOption::Data(pallas::codec::utils::CborWrap(convert_plutus_data(&data.0))))
})) to use output.datum().map(|d| match d { DatumOption::Hash(h) =>
q16::DatumOption::Hash(h), DatumOption::Data(data) =>
q16::DatumOption::Data(pallas::codec::utils::CborWrap(convert_plutus_data(&data.0)))
}); likewise replace the datum_hash assignment (currently using and_then
returning Some(h) / Some(data.original_hash())) with output.datum().map(|d|
match d { DatumOption::Hash(h) => h, DatumOption::Data(data) =>
data.original_hash() }); this preserves types for inline_datum and datum_hash
while eliminating the clippy warning.
♻️ Duplicate comments (1)
src/serve/o7s_unix/statequery.rs (1)
179-186: Return reference scripts for post‑Alonzo outputs.
script_refis hardcoded toNone, so reference scripts on UTxOs are dropped. This is the same gap flagged earlier.Proposed fix
- if output.era() >= pallas::ledger::traverse::Era::Alonzo { + if output.era() >= pallas::ledger::traverse::Era::Alonzo { + let script_ref = output.script_ref().map(|sr| sr.into()); Ok(q16::TransactionOutput::Current( q16::PostAlonsoTransactionOutput { address: address.into(), amount: value, inline_datum, - script_ref: None, + script_ref, }, )) } else {
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/serve/o7s_unix/statequery.rs
🧰 Additional context used
🧬 Code graph analysis (1)
src/serve/o7s_unix/statequery.rs (3)
src/prelude.rs (1)
server(56-58)crates/cardano/src/eras.rs (1)
edge(96-99)src/serve/o7s_unix/mod.rs (1)
handle_session(16-49)
🪛 GitHub Actions: CI
src/serve/o7s_unix/statequery.rs
[error] 167-167: Clippy error: using Option.and_then(|x| Some(y)), which is more succinctly expressed as map(|x| y) (src/serve/o7s_unix/statequery.rs:167)
🪛 GitHub Check: Check Build
src/serve/o7s_unix/statequery.rs
[failure] 431-431:
using map over inspect
[failure] 174-174:
using Option.and_then(|x| Some(y)), which is more succinctly expressed as map(|x| y)
[failure] 167-167:
using Option.and_then(|x| Some(y)), which is more succinctly expressed as map(|x| y)
🔇 Additional comments (1)
src/serve/o7s_unix/statequery.rs (1)
430-434: The proposed fix usinginspectwill not compile—Optionlacks aninspectmethod in std.While Clippy does suggest
inspectfor side-effect-only closures,inspectis only available onIteratorin the standard library. ForOption/Result, there is no built-ininspectmethod. The current code is correct; keep the.map()as-is unless the project adds a helper trait or external crate providinginspectfor these types.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| let inline_datum = output.datum().and_then(|d| match d { | ||
| DatumOption::Hash(h) => Some(q16::DatumOption::Hash(h)), | ||
| DatumOption::Data(data) => Some(q16::DatumOption::Data(pallas::codec::utils::CborWrap( | ||
| convert_plutus_data(&data.0), | ||
| ))), | ||
| }); | ||
|
|
||
| let datum_hash = output.datum().and_then(|d| match d { | ||
| DatumOption::Hash(h) => Some(h), | ||
| DatumOption::Data(data) => Some(data.original_hash()), | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check if the file exists and examine the code around lines 167-177
if [ -f "src/serve/o7s_unix/statequery.rs" ]; then
echo "=== File found, examining lines 160-185 ==="
sed -n '160,185p' "src/serve/o7s_unix/statequery.rs" | cat -n
else
echo "File not found at src/serve/o7s_unix/statequery.rs"
# Try to locate it
find . -name "statequery.rs" -type f
fiRepository: txpipe/dolos
Length of output: 1196
🏁 Script executed:
# Also check the structure to understand the file better
wc -l src/serve/o7s_unix/statequery.rs 2>/dev/null || echo "File not found"Repository: txpipe/dolos
Length of output: 92
🏁 Script executed:
# Check the imports and understand the types involved
head -50 src/serve/o7s_unix/statequery.rs | cat -nRepository: txpipe/dolos
Length of output: 2415
🏁 Script executed:
# Check if there's any type annotation that might affect the fix
sed -n '150,180p' src/serve/o7s_unix/statequery.rs | cat -nRepository: txpipe/dolos
Length of output: 1332
🏁 Script executed:
# Verify the function signature of output.datum() to understand the type
rg -A 5 -B 5 "fn datum" src/serve/o7s_unix/statequery.rs | head -30Repository: txpipe/dolos
Length of output: 38
🏁 Script executed:
# Check if there are any clippy configuration or CI checks related to warnings
find . -name "clippy.toml" -o -name "deny.toml" -o -name ".clippy.toml" | xargs cat 2>/dev/nullRepository: txpipe/dolos
Length of output: 38
🏁 Script executed:
# Look for any CI configuration that might enforce clippy rules
find . -name "*.yml" -o -name "*.yaml" | xargs grep -l "clippy" 2>/dev/null | head -3 | xargs catRepository: txpipe/dolos
Length of output: 1360
🏁 Script executed:
# Check what the output.datum() method returns and understand the type flow
rg -B 10 "let inline_datum = output.datum" src/serve/o7s_unix/statequery.rsRepository: txpipe/dolos
Length of output: 359
🏁 Script executed:
# Look for where inline_datum is used to confirm the type
rg "inline_datum" src/serve/o7s_unix/statequery.rs | head -10Repository: txpipe/dolos
Length of output: 146
🏁 Script executed:
# Check the DatumOption definition and q16::DatumOption to ensure the conversion is correct
rg -A 3 "enum DatumOption\|q16::DatumOption" src/serve/o7s_unix/statequery.rs | head -20Repository: txpipe/dolos
Length of output: 38
🏁 Script executed:
# Find the definition of convert_plutus_data and related types
rg -B 5 "fn convert_plutus_data" src/serve/o7s_unix/statequery.rsRepository: txpipe/dolos
Length of output: 181
🏁 Script executed:
# Check what type output is and what datum() returns
rg -B 20 "let inline_datum = output.datum" src/serve/o7s_unix/statequery.rs | grep -E "fn |output|MultiEraOutput"Repository: txpipe/dolos
Length of output: 179
🏁 Script executed:
# Search for the function signature that contains this code
rg -B 30 "let inline_datum = output.datum" src/serve/o7s_unix/statequery.rs | head -50Repository: txpipe/dolos
Length of output: 1152
🏁 Script executed:
# Get the full function signature
rg -B 50 "let inline_datum = output.datum" src/serve/o7s_unix/statequery.rs | grep -E "^fn |fn convert_output"Repository: txpipe/dolos
Length of output: 148
🏁 Script executed:
# Try to find the function definition more carefully
sed -n '100,180p' src/serve/o7s_unix/statequery.rs | cat -nRepository: txpipe/dolos
Length of output: 3300
🏁 Script executed:
# Confirm the return type of output.datum() by checking the MultiEraOutput trait/impl
rg -A 5 "fn datum" $(find . -name "*.rs" -type f | xargs grep -l "MultiEraOutput" | head -5)Repository: txpipe/dolos
Length of output: 38
🏁 Script executed:
# Check if there are existing clippy issues in CI by looking at workflow runs or issues
rg "and_then.*Some\(" src/serve/o7s_unix/statequery.rsRepository: txpipe/dolos
Length of output: 38
🏁 Script executed:
# Look at the exact clippy lint that would apply here
# The pattern is and_then(|x| Some(...)) which should be map(|x| ...)
# Let's verify the type signature more carefully
sed -n '168,180p' src/serve/o7s_unix/statequery.rs | cat -nRepository: txpipe/dolos
Length of output: 649
🏁 Script executed:
# Check if datum() returns Option
rg "fn datum" -A 3 $(find . -name "*.rs" | head -20)Repository: txpipe/dolos
Length of output: 38
🏁 Script executed:
# Let's verify this is a real clippy issue by searching for the exact pattern in the codebase
rg "and_then\(\|.*Some\(" src/Repository: txpipe/dolos
Length of output: 38
🏁 Script executed:
# Try to understand the exact clippy rule being violated by checking Rust documentation
# For now, let's verify by looking at the pattern more carefully
# and_then with a closure that always returns Some is indeed the lint pattern
# Check if there are other instances of this pattern that have been fixed
rg "\.map\(\|.*match" src/serve/o7s_unix/statequery.rs | head -5Repository: txpipe/dolos
Length of output: 38
🏁 Script executed:
# Let's verify the Rust standard library behavior of and_then vs map
# and_then(|x| Some(y)) is equivalent to map(|x| y)
# This is a well-known pattern that clippy warns about
# Let's check if there's a cargo.toml to understand the Rust version
cat Cargo.toml | head -20Repository: txpipe/dolos
Length of output: 533
🏁 Script executed:
# The key insight: output.datum() returns Option<DatumOption>
# When you use and_then with a closure that always returns Some(...),
# it's the same as using map with a closure that returns the inner value
# This is what clippy warns about
# Let's verify the proposed fix is syntactically correct by checking the exact lines again
sed -n '167,180p' src/serve/o7s_unix/statequery.rsRepository: txpipe/dolos
Length of output: 619
Replace and_then with map for Option conversion.
The code uses and_then(|d| match d { ... => Some(...) }) pattern, where every match arm returns Some(...). This is equivalent to using map with direct value returns, which clippy will flag as a warning. Since the CI enforces clippy with -D warnings, this must be fixed.
Proposed fix
- let inline_datum = output.datum().and_then(|d| match d {
- DatumOption::Hash(h) => Some(q16::DatumOption::Hash(h)),
- DatumOption::Data(data) => Some(q16::DatumOption::Data(pallas::codec::utils::CborWrap(
- convert_plutus_data(&data.0),
- ))),
- });
+ let inline_datum = output.datum().map(|d| match d {
+ DatumOption::Hash(h) => q16::DatumOption::Hash(h),
+ DatumOption::Data(data) => q16::DatumOption::Data(pallas::codec::utils::CborWrap(
+ convert_plutus_data(&data.0),
+ )),
+ });
- let datum_hash = output.datum().and_then(|d| match d {
- DatumOption::Hash(h) => Some(h),
- DatumOption::Data(data) => Some(data.original_hash()),
- });
+ let datum_hash = output.datum().map(|d| match d {
+ DatumOption::Hash(h) => h,
+ DatumOption::Data(data) => data.original_hash(),
+ });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let inline_datum = output.datum().and_then(|d| match d { | |
| DatumOption::Hash(h) => Some(q16::DatumOption::Hash(h)), | |
| DatumOption::Data(data) => Some(q16::DatumOption::Data(pallas::codec::utils::CborWrap( | |
| convert_plutus_data(&data.0), | |
| ))), | |
| }); | |
| let datum_hash = output.datum().and_then(|d| match d { | |
| DatumOption::Hash(h) => Some(h), | |
| DatumOption::Data(data) => Some(data.original_hash()), | |
| }); | |
| let inline_datum = output.datum().map(|d| match d { | |
| DatumOption::Hash(h) => q16::DatumOption::Hash(h), | |
| DatumOption::Data(data) => q16::DatumOption::Data(pallas::codec::utils::CborWrap( | |
| convert_plutus_data(&data.0), | |
| )), | |
| }); | |
| let datum_hash = output.datum().map(|d| match d { | |
| DatumOption::Hash(h) => h, | |
| DatumOption::Data(data) => data.original_hash(), | |
| }); |
🧰 Tools
🪛 GitHub Actions: CI
[error] 167-167: Clippy error: using Option.and_then(|x| Some(y)), which is more succinctly expressed as map(|x| y) (src/serve/o7s_unix/statequery.rs:167)
🪛 GitHub Check: Check Build
[failure] 174-174:
using Option.and_then(|x| Some(y)), which is more succinctly expressed as map(|x| y)
[failure] 167-167:
using Option.and_then(|x| Some(y)), which is more succinctly expressed as map(|x| y)
🤖 Prompt for AI Agents
In `@src/serve/o7s_unix/statequery.rs` around lines 167 - 177, The two Option
transformations use and_then with closures that always return Some(...); change
them to use map so the closure directly returns the transformed value: update
the inline_datum assignment (which currently calls output.datum().and_then(|d|
match d { DatumOption::Hash(h) => Some(q16::DatumOption::Hash(h)),
DatumOption::Data(data) =>
Some(q16::DatumOption::Data(pallas::codec::utils::CborWrap(convert_plutus_data(&data.0))))
})) to use output.datum().map(|d| match d { DatumOption::Hash(h) =>
q16::DatumOption::Hash(h), DatumOption::Data(data) =>
q16::DatumOption::Data(pallas::codec::utils::CborWrap(convert_plutus_data(&data.0)))
}); likewise replace the datum_hash assignment (currently using and_then
returning Some(h) / Some(data.original_hash())) with output.datum().map(|d|
match d { DatumOption::Hash(h) => h, DatumOption::Data(data) =>
data.original_hash() }); this preserves types for inline_datum and datum_hash
while eliminating the clippy warning.
295b558 to
09d0b81
Compare
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.