Skip to content

chore: Include scripts on indexes#899

Merged
scarmuega merged 8 commits intomainfrom
chore/include-scripts-on-index
Mar 5, 2026
Merged

chore: Include scripts on indexes#899
scarmuega merged 8 commits intomainfrom
chore/include-scripts-on-index

Conversation

@gonzalezzfelipe
Copy link
Contributor

@gonzalezzfelipe gonzalezzfelipe commented Feb 13, 2026

Summary by CodeRabbit

  • New Features

    • Search and retrieve scripts by hash (returns script bytes and language: Native, PlutusV1/V2/V3).
    • New API endpoints for scripts (raw / JSON / CBOR) and datum (JSON / CBOR) by hash.
  • Indexing

    • Script hashes are now captured during indexing for improved discoverability.
  • Data/Serialization

    • Plutus map data now serializes as an array of key/value objects.
  • Documentation

    • API docs updated to include the new script and datum endpoints.

@coderabbitai
Copy link

coderabbitai bot commented Feb 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds end-to-end script support: emits SCRIPT tags in index deltas, extracts script hashes from outputs and witnesses during batch processing, provides a query to find scripts by hash (language + bytes) and exposes new HTTP endpoints returning script/datum JSON and CBOR.

Changes

Cohort / File(s) Summary
Index Delta
crates/cardano/src/indexes/delta.rs
Adds pub fn add_script_hash(&mut self, hash: Vec<u8>) to append SCRIPT tags to block tag accumulation.
Query API & Types
crates/cardano/src/indexes/query.rs, crates/cardano/src/indexes/mod.rs
Adds ScriptLanguage enum and ScriptData struct; extends AsyncCardanoQueryExt with script_by_hash(&Hash<28>) -> Result<Option<ScriptData>, DomainError> and implements archive-iteration search over SCRIPT-tagged blocks; re-exports ScriptData and ScriptLanguage.
Batch Processing
crates/cardano/src/roll/batch.rs
Imports ScriptRef and traversal traits; extracts script bytes/hashes from outputs' script_ref and witnesses (Native, PlutusV1/V2/V3) and calls add_script_hash to collect SCRIPT tags.
HTTP routes / API surface
crates/minibf/src/routes/scripts.rs, crates/minibf/src/lib.rs, docs/content/apis/minibf.mdx
Adds route handlers and routes for /scripts/{script_hash}, /scripts/{script_hash}/json, /scripts/{script_hash}/cbor, /scripts/datum/{datum_hash}, /scripts/datum/{datum_hash}/cbor; updates docs.
Serialization mapping
crates/minibf/src/mapping.rs
Changes Plutus Map serialization: emits an array of { "k": ..., "v": ... } entries under a map field instead of a string-keyed JSON object.

Sequence Diagram

sequenceDiagram
    participant BP as BlockProcessor
    participant DB as DeltaBuilder
    participant AR as ArchiveIndex
    participant QF as QueryFacade
    participant HTTP as HTTPHandler

    BP->>BP: process block & transactions
    alt outputs or witnesses contain scripts / script_ref
        BP->>BP: extract script bytes & determine language
        BP->>DB: add_script_hash(hash)
        DB->>AR: append SCRIPT tag to block
    end

    HTTP->>QF: script_by_hash(hash) request
    QF->>AR: iterate blocks by tag=SCRIPT up to tip
    AR-->>QF: SCRIPT-tagged blocks
    QF->>QF: inspect native/plutus scripts & script_refs
    alt match found
        QF-->>HTTP: return ScriptData(language, script bytes)
    else
        QF-->>HTTP: return None
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • scarmuega

Poem

🐰 I hop through blocks and sniff each little hash,

I tuck scripts in tags like carrots in my stash,
I chase Plutus bytes and native code so bright,
I fetch them back in JSON, CBOR — what a sight!
Hoppy indexing, hoppity-hop — delight! 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 43.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is vague and generic, using the term 'Include scripts on indexes' which doesn't clearly convey the specific functionality being added (script indexing by hash with multiple API endpoints and Plutus script language support). Consider a more specific title like 'Add script indexing by hash with API endpoints for script retrieval' to clearly communicate the main change to reviewers.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/include-scripts-on-index

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/cardano/src/roll/batch.rs (1)

427-440: Remove unnecessary inner block scope.

The {} wrapping the witness-script loops adds a level of indentation without any scoping benefit — no variables are declared that need to be dropped or shadowed.

♻️ Proposed refactor
-                // Witness scripts
-                {
-                    for script in tx.native_scripts() {
-                        builder.add_script_hash(script.original_hash().to_vec());
-                    }
-                    for script in tx.plutus_v1_scripts() {
-                        builder.add_script_hash(script.compute_hash().to_vec());
-                    }
-                    for script in tx.plutus_v2_scripts() {
-                        builder.add_script_hash(script.compute_hash().to_vec());
-                    }
-                    for script in tx.plutus_v3_scripts() {
-                        builder.add_script_hash(script.compute_hash().to_vec());
-                    }
-                }
+                // Witness scripts
+                for script in tx.native_scripts() {
+                    builder.add_script_hash(script.original_hash().to_vec());
+                }
+                for script in tx.plutus_v1_scripts() {
+                    builder.add_script_hash(script.compute_hash().to_vec());
+                }
+                for script in tx.plutus_v2_scripts() {
+                    builder.add_script_hash(script.compute_hash().to_vec());
+                }
+                for script in tx.plutus_v3_scripts() {
+                    builder.add_script_hash(script.compute_hash().to_vec());
+                }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cardano/src/roll/batch.rs` around lines 427 - 440, Remove the
unnecessary inner block that wraps the witness-script loops: delete the
surrounding `{ ... }` so the four for-loops (iterating tx.native_scripts(),
tx.plutus_v1_scripts(), tx.plutus_v2_scripts(), tx.plutus_v3_scripts() and
calling builder.add_script_hash(...)) live directly in the parent scope without
the extra braces; no other logic changes are required.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/cardano/src/roll/batch.rs`:
- Around line 408-440: The code currently may append duplicate script hashes
because both output.script_ref() handling and witness script loops call
add_script_hash unconditionally; remove the extra surrounding block scope and
deduplicate by collecting script hashes into a HashSet first (use the
script.original_hash()/compute_hash() values from output.script_ref(),
tx.native_scripts(), tx.plutus_v1_scripts(), tx.plutus_v2_scripts(),
tx.plutus_v3_scripts()), then iterate the set and call
builder.add_script_hash(...) once per unique hash; ensure you reference the
existing functions/methods (output.script_ref(),
ScriptRef::{NativeScript,PlutusV1Script,PlutusV2Script,PlutusV3Script},
tx.native_scripts(), tx.plutus_v1_scripts(), tx.plutus_v2_scripts(),
tx.plutus_v3_scripts(), and builder.add_script_hash) when implementing the
change.

---

Nitpick comments:
In `@crates/cardano/src/roll/batch.rs`:
- Around line 427-440: Remove the unnecessary inner block that wraps the
witness-script loops: delete the surrounding `{ ... }` so the four for-loops
(iterating tx.native_scripts(), tx.plutus_v1_scripts(), tx.plutus_v2_scripts(),
tx.plutus_v3_scripts() and calling builder.add_script_hash(...)) live directly
in the parent scope without the extra braces; no other logic changes are
required.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 144e072 and 6b263f8.

📒 Files selected for processing (1)
  • crates/cardano/src/roll/batch.rs

Comment on lines +408 to 440
if let Some(script_ref) = output.script_ref() {
match script_ref {
ScriptRef::NativeScript(script) => {
builder.add_script_hash(script.original_hash().to_vec());
}
ScriptRef::PlutusV1Script(script) => {
builder.add_script_hash(script.compute_hash().to_vec());
}
ScriptRef::PlutusV2Script(script) => {
builder.add_script_hash(script.compute_hash().to_vec());
}
ScriptRef::PlutusV3Script(script) => {
builder.add_script_hash(script.compute_hash().to_vec());
}
}
}
}

// Witness scripts
{
for script in tx.native_scripts() {
builder.add_script_hash(script.original_hash().to_vec());
}
for script in tx.plutus_v1_scripts() {
builder.add_script_hash(script.compute_hash().to_vec());
}
for script in tx.plutus_v2_scripts() {
builder.add_script_hash(script.compute_hash().to_vec());
}
for script in tx.plutus_v3_scripts() {
builder.add_script_hash(script.compute_hash().to_vec());
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, find where add_script_hash is defined
fd -t f "delta.rs" | head -5

Repository: txpipe/dolos

Length of output: 91


🏁 Script executed:

# Search for add_script_hash method definition
rg "fn add_script_hash" --type rs -A 10

Repository: txpipe/dolos

Length of output: 82


🏁 Script executed:

# Look for the builder implementation and SCRIPT tag handling
rg "add_script_hash|SCRIPT" crates/cardano/src/roll/ --type rs -B 2 -A 2

Repository: txpipe/dolos

Length of output: 82


🏁 Script executed:

# Check if there's any deduplication logic in the codebase
rg "deduplicate|dedup|HashSet|BTreeSet" crates/cardano/src/roll/ --type rs | head -20

Repository: txpipe/dolos

Length of output: 82


🏁 Script executed:

# Examine the full context of the batch.rs file around those lines
sed -n '1,30p' crates/cardano/src/roll/batch.rs

Repository: txpipe/dolos

Length of output: 1109


🏁 Script executed:

# Check the actual implementation of add_script_hash and surrounding code
sed -n '400,450p' crates/cardano/src/roll/batch.rs

Repository: txpipe/dolos

Length of output: 2327


🏁 Script executed:

# Search for add_script_hash implementation in delta.rs
rg "fn add_script_hash" crates/cardano/src/indexes/delta.rs -A 10

Repository: txpipe/dolos

Length of output: 490


🏁 Script executed:

# Look for the builder type and how SCRIPT tags are handled
rg "add_script_hash|SCRIPT" crates/cardano/src/indexes/delta.rs -B 2 -A 5 | head -50

Repository: txpipe/dolos

Length of output: 448


🏁 Script executed:

# Check the data structure used to store script hashes (sets, vectors, etc.)
rg "struct.*Builder|field.*script" crates/cardano/src/indexes/delta.rs -A 15 | head -100

Repository: txpipe/dolos

Length of output: 446


🏁 Script executed:

# Look for deduplication or set usage in the entire indexes module
rg "HashSet|BTreeSet|dedup" crates/cardano/src/indexes/ --type rs

Repository: txpipe/dolos

Length of output: 82


🏁 Script executed:

# Check if add_script_hash is called elsewhere and how duplicates might be handled
rg "add_script_hash" crates/ --type rs

Repository: txpipe/dolos

Length of output: 82


🏁 Script executed:

# Search for IndexDelta structure definition
rg "struct IndexDelta" crates/ -A 15

Repository: txpipe/dolos

Length of output: 955


🏁 Script executed:

# Look for where IndexDelta is used and if tags are processed/deduplicated
rg "IndexDelta" crates/cardano/src/ -B 2 -A 3 | head -50

Repository: txpipe/dolos

Length of output: 2762


🏁 Script executed:

# Check if there's any post-processing of tags before storage
rg "\.tags" crates/ --type rust | head -30

Repository: txpipe/dolos

Length of output: 2480


🏁 Script executed:

# Look for script handling tests or documentation
rg "script_ref|add_script_hash" crates/ --type rust -B 3 -A 3 | head -80

Repository: txpipe/dolos

Length of output: 5297


🏁 Script executed:

# Search for any existing duplicate handling patterns in the codebase
rg "Vec.*clone|to_vec" crates/cardano/src/roll/batch.rs -B 2 -A 2 | head -50

Repository: txpipe/dolos

Length of output: 2192


🏁 Script executed:

# Check if there's any test coverage or comments about duplicate script handling
rg "script.*duplicate|duplicate.*script" crates/ -i

Repository: txpipe/dolos

Length of output: 38


🏁 Script executed:

# Look for any deduplication in the tag processing at storage layer
rg "apply.*tags|history.*tags|utxos.*tags" crates/ --type rust -B 3 -A 5 | head -80

Repository: txpipe/dolos

Length of output: 3025


🏁 Script executed:

# Examine how tags are applied/stored in the index
cat crates/fjall/src/index/utxos.rs | head -100

Repository: txpipe/dolos

Length of output: 3181


🏁 Script executed:

# Check the archive block structure more thoroughly
rg "struct.*Block|struct.*ArchiveIndexDelta" crates/ -A 10 | head -80

Repository: txpipe/dolos

Length of output: 4636


Remove duplicate script-hash indexing and unnecessary block scope.

The output script_ref loop (lines 408–424) and witness scripts loop (lines 428–439) both unconditionally call add_script_hash within the same transaction. A transaction that produces a reference script and uses that same script in its witnesses will push the same hash twice to the block's tag list. Since add_script_hash simply appends to a vector without deduplication, this creates duplicate SCRIPT tags.

Additionally, the {} wrapper around the witness scripts block (lines 427–440) is unnecessary and only adds indentation.

Consider deduplicating script hashes before indexing, or skip witness scripts that were already added via script_ref. The block scope can be removed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cardano/src/roll/batch.rs` around lines 408 - 440, The code currently
may append duplicate script hashes because both output.script_ref() handling and
witness script loops call add_script_hash unconditionally; remove the extra
surrounding block scope and deduplicate by collecting script hashes into a
HashSet first (use the script.original_hash()/compute_hash() values from
output.script_ref(), tx.native_scripts(), tx.plutus_v1_scripts(),
tx.plutus_v2_scripts(), tx.plutus_v3_scripts()), then iterate the set and call
builder.add_script_hash(...) once per unique hash; ensure you reference the
existing functions/methods (output.script_ref(),
ScriptRef::{NativeScript,PlutusV1Script,PlutusV2Script,PlutusV3Script},
tx.native_scripts(), tx.plutus_v1_scripts(), tx.plutus_v2_scripts(),
tx.plutus_v3_scripts(), and builder.add_script_hash) when implementing the
change.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/minibf/src/routes/scripts.rs (1)

26-46: Optional: deduplicate hash parsing helpers.

parse_script_hash and parse_datum_hash are structurally identical except for size. A small generic helper would reduce repetition and keep error behavior centralized.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/minibf/src/routes/scripts.rs` around lines 26 - 46, The two functions
parse_script_hash and parse_datum_hash are identical except for the hash size;
replace them with a single generic helper like parse_hash<const N: usize>(s:
&str) -> Result<Hash<N>, StatusCode> that validates length (2*N bytes => hex
length 2*N), decodes hex with hex::decode and maps errors to
StatusCode::NOT_FOUND, then constructs Hash::<N>::from(decoded.as_slice());
update parse_script_hash and parse_datum_hash to call this generic helper (or
remove them and call parse_hash::<28> and parse_hash::<32> where used) so all
parsing and error mapping is centralized.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/minibf/src/routes/scripts.rs`:
- Around line 151-159: The handler currently treats the Option returned by
domain.query().plutus_data(&parse_datum_hash(&datum_hash)?) as if it were always
Some, which can yield a 200 for missing data; update the logic in the function
that returns Json(ScriptDatumCbor) so that if datum is None you return an
Err(StatusCode::NOT_FOUND) (similar to by_datum_hash), otherwise serialize the
datum with minicbor::to_vec and hex::encode as before; reference the
domain.query().plutus_data call, parse_datum_hash(&datum_hash), ScriptDatumCbor
construction, and use StatusCode::NOT_FOUND for the missing case while keeping
existing map_err usages for internal errors.

---

Nitpick comments:
In `@crates/minibf/src/routes/scripts.rs`:
- Around line 26-46: The two functions parse_script_hash and parse_datum_hash
are identical except for the hash size; replace them with a single generic
helper like parse_hash<const N: usize>(s: &str) -> Result<Hash<N>, StatusCode>
that validates length (2*N bytes => hex length 2*N), decodes hex with
hex::decode and maps errors to StatusCode::NOT_FOUND, then constructs
Hash::<N>::from(decoded.as_slice()); update parse_script_hash and
parse_datum_hash to call this generic helper (or remove them and call
parse_hash::<28> and parse_hash::<32> where used) so all parsing and error
mapping is centralized.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 45730ade-b307-4198-a12a-e3fb65ec671f

📥 Commits

Reviewing files that changed from the base of the PR and between 6b263f8 and b6cdb34.

📒 Files selected for processing (4)
  • crates/minibf/src/lib.rs
  • crates/minibf/src/mapping.rs
  • crates/minibf/src/routes/scripts.rs
  • docs/content/apis/minibf.mdx

builder.add_script_hash(script.original_hash().to_vec());
}
ScriptRef::PlutusV1Script(script) => {
builder.add_script_hash(script.compute_hash().to_vec());
Copy link
Member

Choose a reason for hiding this comment

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

why not original_hash()?

}))
}

fn native_script_json(script: &NativeScript) -> Result<serde_json::Value, StatusCode> {
Copy link
Member

Choose a reason for hiding this comment

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

IIRC, there's a trait called ToCanonicalJson that provides this serialization out-of-the-box.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/minibf/src/routes/scripts.rs (1)

94-95: Remove commented-out code.

Line 94 contains dead code that should be removed to maintain code cleanliness.

♻️ Proposed fix
         let native: NativeScript =
             minicbor::decode(&script.script).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
-            // Some(native_script_json(&native)?)
             Some(native.to_json())
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/minibf/src/routes/scripts.rs` around lines 94 - 95, Remove the dead
commented-out code "// Some(native_script_json(&native)?)" in
crates/minibf/src/routes/scripts.rs to keep the codebase clean; specifically
delete that commented line near the Some(native.to_json()) return so only
Some(native.to_json()) remains (references: native_script_json and
native.to_json) and ensure no other commented legacy call remains in the
surrounding function.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/minibf/src/routes/scripts.rs`:
- Around line 94-95: Remove the dead commented-out code "//
Some(native_script_json(&native)?)" in crates/minibf/src/routes/scripts.rs to
keep the codebase clean; specifically delete that commented line near the
Some(native.to_json()) return so only Some(native.to_json()) remains
(references: native_script_json and native.to_json) and ensure no other
commented legacy call remains in the surrounding function.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a6054b2f-2a11-4cf3-893a-748dde6fa2b9

📥 Commits

Reviewing files that changed from the base of the PR and between b6cdb34 and 8a40d89.

📒 Files selected for processing (4)
  • crates/minibf/src/lib.rs
  • crates/minibf/src/mapping.rs
  • crates/minibf/src/routes/scripts.rs
  • docs/content/apis/minibf.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/minibf/src/lib.rs

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/minibf/src/routes/scripts.rs (1)

94-95: Remove commented-out code.

Line 94 contains dead code that should be removed to keep the codebase clean.

🧹 Proposed cleanup
         let native: NativeScript =
             minicbor::decode(&script.script).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
-            // Some(native_script_json(&native)?)
             Some(native.to_json())
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/minibf/src/routes/scripts.rs` around lines 94 - 95, Remove the dead
commented-out invocation native_script_json(&native)? from
crates/minibf/src/routes/scripts.rs and leave only the active return
Some(native.to_json()); — delete the commented line referencing
native_script_json to clean up the codebase and avoid stale code, ensuring the
surrounding function (the match arm returning Some(...)) and the
native.to_json() call remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/minibf/src/routes/scripts.rs`:
- Around line 94-95: Remove the dead commented-out invocation
native_script_json(&native)? from crates/minibf/src/routes/scripts.rs and leave
only the active return Some(native.to_json()); — delete the commented line
referencing native_script_json to clean up the codebase and avoid stale code,
ensuring the surrounding function (the match arm returning Some(...)) and the
native.to_json() call remain unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: da7e8615-b468-40f0-9805-013f7df1383a

📥 Commits

Reviewing files that changed from the base of the PR and between 8a40d89 and a0b4c15.

📒 Files selected for processing (1)
  • crates/minibf/src/routes/scripts.rs

@scarmuega scarmuega merged commit 0edc11e into main Mar 5, 2026
12 checks passed
@scarmuega scarmuega deleted the chore/include-scripts-on-index branch March 5, 2026 10:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants