Skip to content

Conversation

@wolf31o2
Copy link
Member

@wolf31o2 wolf31o2 commented Dec 7, 2025

Closes #399
Closes #500

Summary by CodeRabbit

  • New Features

    • Added transaction script evaluation capability with cost model calculations for Plutus scripts.
  • Chores

    • Updated core dependencies (adder, gouroboros) and integrated Plutigo library for enhanced script processing support.

✏️ Tip: You can customize this high-level summary in your review settings.

@wolf31o2 wolf31o2 requested a review from a team as a code owner December 7, 2025 17:08
@coderabbitai
Copy link

coderabbitai bot commented Dec 7, 2025

Warning

Rate limit exceeded

@wolf31o2 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 29 minutes and 0 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 3207ff0 and 75e427c.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (7)
  • go.mod (3 hunks)
  • internal/utxorpc/submit.go (2 hunks)
  • openapi/test/api_chainsync_test.go (1 hunks)
  • openapi/test/api_default_test.go (1 hunks)
  • openapi/test/api_localstatequery_test.go (1 hunks)
  • openapi/test/api_localtxmonitor_test.go (1 hunks)
  • openapi/test/api_localtxsubmission_test.go (1 hunks)

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

This PR introduces script evaluation capabilities to the UTXORPC service layer. It updates dependencies to enable Plutus script handling, with plutigo added as a direct dependency (v0.0.16). The implementation adds a new EvalTx RPC handler that parses transactions, fetches protocol parameters and cost models, extracts Plutus scripts and witnesses, evaluates scripts with provided data arguments, and populates execution unit budgets in redeemer structures. Supporting utility functions handle script evaluation across different Plutus versions and data conversion between plutigo and Cardano data structures.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–25 minutes

  • evaluateScript function: Review script execution logic, cost model application, and budget calculation across different Plutus script versions
  • convertPlutusData function: Verify correct mapping of plutigo data structures to Cardano PlutusData types
  • EvalTx RPC handler: Examine transaction parsing, script extraction and grouping logic, protocol parameter integration, context and datum handling
  • go.mod dependency changes: Verify plutigo version (now direct) and new indirect dependencies are compatible with the implementation

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(utxorpc): implement submit.EvalTx' clearly and specifically describes the main change: implementing the submit.EvalTx functionality in the utxorpc package.
Linked Issues check ✅ Passed The PR implements submit.EvalTx with script evaluation, PlutusData conversion, and EvalTx RPC handler as required for issue #399.
Out of Scope Changes check ✅ Passed Changes are focused on implementing submit.EvalTx with dependency updates (go.mod) and script evaluation logic, all aligned with the stated objective.

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: 10

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f995e56 and 3207ff0.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (2)
  • go.mod (3 hunks)
  • internal/utxorpc/submit.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
internal/utxorpc/submit.go (1)
internal/node/node.go (1)
  • GetConnection (31-75)
🪛 GitHub Actions: golangci-lint
internal/utxorpc/submit.go

[error] 256-256: golangci-lint: Consider pre-allocating txEvalRedeemers (prealloc)

🪛 GitHub Actions: nilaway
internal/utxorpc/submit.go

[error] 229-229: nilaway: Potential nil panic detected. Observed nil flow from source to dereference point at internal/utxorpc/submit.go:229.

🪛 GitHub Check: lint
internal/utxorpc/submit.go

[failure] 91-91:
evaluateScript - costModel is unused (unparam)


[failure] 256-256:
Consider pre-allocating txEvalRedeemers (prealloc)

🪛 GitHub Check: nilaway
internal/utxorpc/submit.go

[failure] 257-257:
�[31merror: �[0mPotential nil panic detected. Observed nil flow from source to dereference point:


[failure] 229-229:
�[31merror: �[0mPotential nil panic detected. Observed nil flow from source to dereference point:

⏰ 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). (2)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Analyze (go)

Comment on lines +11 to +13
github.com/blinklabs-io/adder v0.35.0
github.com/blinklabs-io/gouroboros v0.142.0
github.com/blinklabs-io/plutigo v0.0.16
Copy link

@coderabbitai coderabbitai bot Dec 7, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

blinklabs-io plutigo latest release version

💡 Result:

The latest release is v0.0.15 (released Nov 27, 2025). [1][2]

Sources:
[1] blinklabs-io/plutigo — Releases (GitHub).
[2] CardanoUpdates — blinklabs-io/adder (dependency bump referencing plutigo).


🌐 Web query:

blinklabs-io/adder go module latest release

💡 Result:

The latest release (tag) of the Go module github.com/blinklabs-io/adder is v0.33.0 — tagged Oct 26, 2025. [1][2]

Sources:

  • GitHub tags for blinklabs-io/adder (v0.33.0, Oct 26, 2025). [1]
  • pkg.go.dev module page for github.com/blinklabs-io/adder. [2]

🌐 Web query:

blinklabs-io/gouroboros go module latest release

💡 Result:

The latest release is tag v0.143.0 — published Dec 5, 2025. [1][2]

Sources:
[1] GitHub tags for blinklabs-io/gouroboros (v0.143.0, Dec 5, 2025).
[2] blinklabs-io/gouroboros repository README.


Address version discrepancies before merging.

The dependency versions in go.mod appear misaligned with latest public releases: plutigo v0.0.16 and adder v0.35.0 are ahead of the documented latest versions (plutigo v0.0.15 released Nov 27, 2025; adder v0.33.0 released Oct 26, 2025), while gouroboros v0.142.0 is behind the latest v0.143.0 (Dec 5, 2025). Clarify whether these versions are pre-release builds or development versions before deploying to production. Since plutigo remains in 0.0.x, verify its API stability for the new scripting features in this change.

🤖 Prompt for AI Agents
In go.mod around lines 11 to 13, the dependency versions are inconsistent with
public releases (plutigo v0.0.16 and adder v0.35.0 appear ahead of published
tags while gouroboros is behind v0.143.0); update go.mod to use the intended,
documented versions (or explicit pre-release pseudo-versions) and document the
decision: either pin to the latest published stable tags (e.g., adder v0.33.0
and plutigo v0.0.15) or, if you intentionally need unreleased/dev builds,
replace the entries with the exact commit pseudo-versions and add a note in the
repo (CHANGELOG or dependency file comment) indicating they are pre-release/dev.
After updating, run go get ./... and go mod tidy, run the unit/integration tests
to verify API compatibility (especially for plutigo's 0.0.x changes), and vendor
the modules or add a short note in the PR description documenting the stability
decision before merging.

Copy link
Member Author

Choose a reason for hiding this comment

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

Your information on the latest versions is incorrect. Ignoring this one.

Copy link

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the latest releases for the three dependencies using GitHub CLI

echo "=== Checking blinklabs-io/plutigo ==="
gh release list --repo blinklabs-io/plutigo --limit 5

echo ""
echo "=== Checking blinklabs-io/adder ==="
gh release list --repo blinklabs-io/adder --limit 5

echo ""
echo "=== Checking blinklabs-io/gouroboros ==="
gh release list --repo blinklabs-io/gouroboros --limit 5

echo ""
echo "=== Checking latest tags as well ==="
echo "plutigo tags:"
gh api repos/blinklabs-io/plutigo/tags --jq '.[0:5] | .[] | "\(.name) - \(.commit.sha[0:7])"'

echo ""
echo "adder tags:"
gh api repos/blinklabs-io/adder/tags --jq '.[0:5] | .[] | "\(.name) - \(.commit.sha[0:7])"'

echo ""
echo "gouroboros tags:"
gh api repos/blinklabs-io/gouroboros/tags --jq '.[0:5] | .[] | "\(.name) - \(.commit.sha[0:7])"'

Length of output: 1072


@wolf31o2, you're absolutely right, and I apologize for the incorrect information.

I've verified the actual latest releases:

  • plutigo v0.0.16 (Dec 3, 2025) - Latest ✓
  • adder v0.35.0 (Dec 5, 2025) - Latest ✓
  • gouroboros v0.142.0 (Dec 1, 2025) - One version behind v0.143.0 (Dec 5, 2025)

The versions in your go.mod are correct and up-to-date. The gouroboros dependency is only one minor version behind, which is reasonable. Thank you for the correction!

Comment on lines 90 to 118
// evaluateScript evaluates a Plutus script with the given arguments and cost model
func evaluateScript(scriptBytes []byte, args []data.PlutusData, costModel map[uint][]int64) (uint64, uint64, error) {
// Decode the script
program, err := syn.Decode[syn.DeBruijn](scriptBytes)
if err != nil {
return 0, 0, fmt.Errorf("decode script: %w", err)
}

// Apply arguments to the script
term := program.Term
for _, arg := range args {
term = &syn.Apply[syn.DeBruijn]{
Function: term,
Argument: &syn.Constant{
Con: &syn.Data{Inner: arg},
},
}
}

// Create machine with version-based cost model
machine := cek.NewMachineWithVersionCosts[syn.DeBruijn](program.Version, 200)

_, err = machine.Run(term)
if err != nil {
return 0, 0, fmt.Errorf("execute script: %w", err)
}

return uint64(machine.ExBudget.Cpu), uint64(machine.ExBudget.Mem), nil
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Unused costModel parameter and hardcoded budget value.

The costModel parameter is passed but never used (flagged by static analysis). Additionally, the hardcoded value 200 in NewMachineWithVersionCosts is unclear.

Either integrate the cost model into the machine creation or remove the parameter if it's not needed. Please clarify what the 200 value represents.

-func evaluateScript(scriptBytes []byte, args []data.PlutusData, costModel map[uint][]int64) (uint64, uint64, error) {
+func evaluateScript(scriptBytes []byte, args []data.PlutusData, version uint, costModel []int64) (uint64, uint64, error) {
 	// Decode the script
 	program, err := syn.Decode[syn.DeBruijn](scriptBytes)
 	if err != nil {
 		return 0, 0, fmt.Errorf("decode script: %w", err)
 	}

 	// Apply arguments to the script
 	term := program.Term
 	for _, arg := range args {
 		term = &syn.Apply[syn.DeBruijn]{
 			Function: term,
 			Argument: &syn.Constant{
 				Con: &syn.Data{Inner: arg},
 			},
 		}
 	}

-	// Create machine with version-based cost model
-	machine := cek.NewMachineWithVersionCosts[syn.DeBruijn](program.Version, 200)
+	// Create machine with version-based cost model
+	// TODO: Integrate costModel parameter properly
+	machine := cek.NewMachineWithVersionCosts[syn.DeBruijn](version, 200)

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 GitHub Check: lint

[failure] 91-91:
evaluateScript - costModel is unused (unparam)

🤖 Prompt for AI Agents
In internal/utxorpc/submit.go around lines 90 to 118, the function
evaluateScript accepts a costModel parameter that is never used and passes a
hardcoded literal 200 into NewMachineWithVersionCosts; update the function so
the provided costModel is applied when constructing the CEK machine (or remove
the unused parameter if callers never supply meaningful models). Concretely: if
callers supply costModel, convert it into the cost structure expected by
cek.NewMachineWithVersionCosts (or the appropriate machine constructor) and pass
that instead of 200; if costModel is not required, remove the parameter from the
signature and update all call sites. Also replace the magic literal 200 with a
named constant (e.g., DefaultCostLimit) or derive the value from the cost model
so the meaning is explicit.

Comment on lines +151 to +178
case *data.Integer:
return &cardano.PlutusData{
PlutusData: &cardano.PlutusData_BigInt{
BigInt: &cardano.BigInt{
BigInt: &cardano.BigInt_Int{
Int: v.Inner.Int64(),
},
},
},
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential integer overflow when converting large integers.

v.Inner.Int64() truncates values that exceed the int64 range. Plutus integers can be arbitrarily large. The cardano.BigInt type supports BigUInt for larger values.

 	case *data.Integer:
+		// Check if the integer fits in int64
+		if v.Inner.IsInt64() {
+			return &cardano.PlutusData{
+				PlutusData: &cardano.PlutusData_BigInt{
+					BigInt: &cardano.BigInt{
+						BigInt: &cardano.BigInt_Int{
+							Int: v.Inner.Int64(),
+						},
+					},
+				},
+			}
+		}
+		// Use BigUInt for larger integers
 		return &cardano.PlutusData{
 			PlutusData: &cardano.PlutusData_BigInt{
 				BigInt: &cardano.BigInt{
-					BigInt: &cardano.BigInt_Int{
-						Int: v.Inner.Int64(),
+					BigInt: &cardano.BigInt_BigUInt{
+						BigUInt: v.Inner.Bytes(),
 					},
 				},
 			},
 		}
📝 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.

Suggested change
case *data.Integer:
return &cardano.PlutusData{
PlutusData: &cardano.PlutusData_BigInt{
BigInt: &cardano.BigInt{
BigInt: &cardano.BigInt_Int{
Int: v.Inner.Int64(),
},
},
},
}
case *data.Integer:
// Check if the integer fits in int64
if v.Inner.IsInt64() {
return &cardano.PlutusData{
PlutusData: &cardano.PlutusData_BigInt{
BigInt: &cardano.BigInt{
BigInt: &cardano.BigInt_Int{
Int: v.Inner.Int64(),
},
},
},
}
}
// Use BigUInt for larger integers
return &cardano.PlutusData{
PlutusData: &cardano.PlutusData_BigInt{
BigInt: &cardano.BigInt{
BigInt: &cardano.BigInt_BigUInt{
BigUInt: v.Inner.Bytes(),
},
},
},
}

Comment on lines +179 to +200
default:
// Should not happen
return nil
}
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

Silent nil return for unknown data types may cause downstream issues.

Returning nil silently for unexpected types could lead to nil pointer dereferences when the returned value is used (e.g., in map pairs or array items). Consider logging a warning or returning an error.

 	default:
-		// Should not happen
+		// Log unexpected type for debugging
+		log.Printf("WARNING: unexpected PlutusData type: %T", pd)
 		return nil
 	}
📝 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.

Suggested change
default:
// Should not happen
return nil
}
default:
// Log unexpected type for debugging
log.Printf("WARNING: unexpected PlutusData type: %T", pd)
return nil
}
🤖 Prompt for AI Agents
In internal/utxorpc/submit.go around lines 179 to 182, the switch default
currently returns nil silently for unknown data types which can cause nil
pointer dereferences downstream; change this to surface the problem by returning
an error (or at minimum logging a warning) that includes the unexpected type
information and context (e.g., the value and its reflect.Type or a descriptive
message) so callers can handle the failure instead of getting a nil; update the
function signature if necessary to propagate the error or ensure the caller
checks and handles the logged condition.

Comment on lines +220 to +243
// Get protocol parameters for cost models
oConn.LocalStateQuery().Client.Start()
protoParams, err := oConn.LocalStateQuery().Client.GetCurrentProtocolParams()
if err != nil {
return connect.NewResponse(resp), err
}
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

Missing error handling for LocalStateQuery().Client.Start().

The Start() call may fail and should have its return value checked, similar to how other client operations are handled.

 	// Get protocol parameters for cost models
-	oConn.LocalStateQuery().Client.Start()
+	if err := oConn.LocalStateQuery().Client.Start(); err != nil {
+		return connect.NewResponse(resp), fmt.Errorf("start local state query: %w", err)
+	}
 	protoParams, err := oConn.LocalStateQuery().Client.GetCurrentProtocolParams()
📝 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.

Suggested change
// Get protocol parameters for cost models
oConn.LocalStateQuery().Client.Start()
protoParams, err := oConn.LocalStateQuery().Client.GetCurrentProtocolParams()
if err != nil {
return connect.NewResponse(resp), err
}
// Get protocol parameters for cost models
if err := oConn.LocalStateQuery().Client.Start(); err != nil {
return connect.NewResponse(resp), fmt.Errorf("start local state query: %w", err)
}
protoParams, err := oConn.LocalStateQuery().Client.GetCurrentProtocolParams()
if err != nil {
return connect.NewResponse(resp), err
}
🤖 Prompt for AI Agents
In internal/utxorpc/submit.go around lines 220 to 225, the call
oConn.LocalStateQuery().Client.Start() is not checking its returned error;
update the code to capture the error from Start(), check if it's non-nil, and
return the same response/error pattern used elsewhere (e.g., return
connect.NewResponse(resp), err) so startup failures are propagated and handled
consistently.

Comment on lines +231 to +267
// Get cost models from protocol parameters
var costModels map[uint][]int64
if conwayParams, ok := protoParams.(*ledger.ConwayProtocolParameters); ok {
costModels = conwayParams.CostModels
}
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

Only ConwayProtocolParameters are handled; other eras will have nil cost models.

If the node returns protocol parameters from a different era, costModels will remain nil, causing script evaluation to fail silently (empty cost model passed to evaluateScript).

 	// Get cost models from protocol parameters
 	var costModels map[uint][]int64
 	if conwayParams, ok := protoParams.(*ledger.ConwayProtocolParameters); ok {
 		costModels = conwayParams.CostModels
+	} else {
+		log.Printf("WARNING: unsupported protocol parameters type %T, script evaluation may fail", protoParams)
 	}
🤖 Prompt for AI Agents
internal/utxorpc/submit.go around lines 231-235: the current code only extracts
CostModels when protoParams is *ledger.ConwayProtocolParameters, leaving
costModels nil for other eras which leads to silent script-evaluation failures.
Update the logic to handle other protocol-parameter types (e.g., Alonzo/Babbage
if present in your ledger package) by type-asserting those types and extracting
their CostModels, or if the ledger types share a common accessor use that; if no
cost models are available, return an explicit error instead of passing nil to
evaluateScript so callers can handle the unsupported era. Ensure you update
control flow and error messages accordingly.

Comment on lines +268 to +317
// Try to evaluate if we have a script for this redeemer
if int(key.Index) < len(allScripts) {
scriptBytes := allScripts[key.Index]
version := scriptVersions[key.Index]
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Incorrect script lookup logic - redeemer index does not map to script array index.

The redeemer's key.Index represents the index of the input/output being redeemed (e.g., the input index for spending), not an index into the allScripts array. This will cause incorrect script-redeemer pairing and likely evaluation failures.

Scripts should be looked up by their hash, matching against the script hash referenced by the UTxO or policy being redeemed.

-		// Try to evaluate if we have a script for this redeemer
-		if int(key.Index) < len(allScripts) {
-			scriptBytes := allScripts[key.Index]
-			version := scriptVersions[key.Index]
+		// TODO: Look up the correct script by hash based on redeemer purpose and index
+		// For spending: get the script hash from the input's UTxO
+		// For minting: get the script hash from the policy ID
+		// For now, skip evaluation until proper script matching is implemented
+		_ = allScripts // Avoid unused variable warning
+		_ = scriptVersions

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
internal/utxorpc/submit.go around lines 268 to 271: the code incorrectly treats
redeemer key.Index as an index into allScripts; replace this with a lookup by
script hash: obtain the script hash referenced by the UTxO or policy being
redeemed (from the tx input/output or datum/policy context), iterate or use a
map to find the matching entry in allScripts by comparing hashes, retrieve the
corresponding scriptBytes and version from that matched entry, and handle the
case where no matching script is found by returning a clear error or skipping
evaluation.

Comment on lines +276 to +336
// For now, only handle spending scripts with datum, redeemer, context
if key.Tag == 0 { // RedeemerTagSpend
// Get datum - for simplicity, assume it's the redeemer data for now
datum := value.Data.Data
redeemerData := value.Data.Data
// TODO: build proper script context
contextData := data.NewConstr(0) // dummy context

args = []data.PlutusData{datum, redeemerData, contextData}
} else {
// For other purposes, just redeemer and context
redeemerData := value.Data.Data
contextData := data.NewConstr(0) // dummy context
args = []data.PlutusData{redeemerData, contextData}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Placeholder datum and context will produce incorrect evaluation results.

Using the redeemer data as the datum (line 279) and a dummy empty constructor as the script context (lines 282, 288) will cause scripts to fail or produce incorrect execution unit estimates. This fundamentally undermines the purpose of EvalTx.

Consider either:

  1. Fetching actual datums from UTxOs via the node connection
  2. Building a proper ScriptContext structure
  3. Documenting this as a known limitation and returning an appropriate error
🤖 Prompt for AI Agents
In internal/utxorpc/submit.go around lines 276 to 290, the code wrongly uses
redeemer data as the datum and a dummy empty constructor as ScriptContext which
will produce incorrect EvalTx results; replace the placeholders by either (a)
fetching the actual datum for the UTxO from the node (via the node client) and
using that real datum and building a proper ScriptContext structure populated
with the tx, inputs, outputs and relevant signatures, or (b) if
fetching/building is not possible here, fail fast: detect missing datum/context
and return a clear error documenting that EvalTx cannot run without on-chain
datum and full ScriptContext; do not continue to call EvalTx with dummy values.
Ensure the chosen fix populates args with the correct data.PlutusData order
expected by the validator (datum, redeemer, context) or returns an explicit
error.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 3 files

Prompt for AI agents (all 2 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="internal/utxorpc/submit.go">

<violation number="1" location="internal/utxorpc/submit.go:156">
P1: Calling `Int64()` on a big integer can silently truncate values that exceed int64 range. Check if the value fits in int64 first, and use `BigInt_BigUInt` or `BigInt_BigNInt` for larger values.</violation>

<violation number="2" location="internal/utxorpc/submit.go:269">
P1: The redeemer index does not correspond to the script index in `allScripts`. The redeemer index refers to the input/policy index being validated, not the script position in the witness set. Scripts should be matched by their hash, not by array position.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

}

// Try to evaluate if we have a script for this redeemer
if int(key.Index) < len(allScripts) {
Copy link

@cubic-dev-ai cubic-dev-ai bot Dec 7, 2025

Choose a reason for hiding this comment

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

P1: The redeemer index does not correspond to the script index in allScripts. The redeemer index refers to the input/policy index being validated, not the script position in the witness set. Scripts should be matched by their hash, not by array position.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At internal/utxorpc/submit.go, line 269:

<comment>The redeemer index does not correspond to the script index in `allScripts`. The redeemer index refers to the input/policy index being validated, not the script position in the witness set. Scripts should be matched by their hash, not by array position.</comment>

<file context>
@@ -83,6 +87,238 @@ func (s *submitServiceServer) SubmitTx(
+		}
+
+		// Try to evaluate if we have a script for this redeemer
+		if int(key.Index) &lt; len(allScripts) {
+			scriptBytes := allScripts[key.Index]
+			version := scriptVersions[key.Index]
</file context>
Fix with Cubic

PlutusData: &cardano.PlutusData_BigInt{
BigInt: &cardano.BigInt{
BigInt: &cardano.BigInt_Int{
Int: v.Inner.Int64(),
Copy link

@cubic-dev-ai cubic-dev-ai bot Dec 7, 2025

Choose a reason for hiding this comment

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

P1: Calling Int64() on a big integer can silently truncate values that exceed int64 range. Check if the value fits in int64 first, and use BigInt_BigUInt or BigInt_BigNInt for larger values.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At internal/utxorpc/submit.go, line 156:

<comment>Calling `Int64()` on a big integer can silently truncate values that exceed int64 range. Check if the value fits in int64 first, and use `BigInt_BigUInt` or `BigInt_BigNInt` for larger values.</comment>

<file context>
@@ -83,6 +87,238 @@ func (s *submitServiceServer) SubmitTx(
+			PlutusData: &amp;cardano.PlutusData_BigInt{
+				BigInt: &amp;cardano.BigInt{
+					BigInt: &amp;cardano.BigInt_Int{
+						Int: v.Inner.Int64(),
+					},
+				},
</file context>
Fix with Cubic

@wolf31o2 wolf31o2 force-pushed the feat/utxorpc-evaltx branch from 3207ff0 to 75e427c Compare December 7, 2025 17:35
@wolf31o2
Copy link
Member Author

wolf31o2 commented Dec 7, 2025

@cubic-dev-ai review this PR

@cubic-dev-ai
Copy link

cubic-dev-ai bot commented Dec 7, 2025

@cubic-dev-ai review this PR

@wolf31o2 I've started the AI code review. It'll take a few minutes to complete.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 8 files

Prompt for AI agents (all 3 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="internal/utxorpc/submit.go">

<violation number="1" location="internal/utxorpc/submit.go:174">
P1: Potential integer overflow: `v.Inner.Int64()` will silently truncate big integers that exceed int64 range. Consider using `BigInt_BigUInt` or `BigInt_BigNInt` for arbitrary precision, or at minimum check if the value fits with `v.Inner.IsInt64()` before conversion.</violation>

<violation number="2" location="internal/utxorpc/submit.go:315">
P1: Incorrect script lookup: Redeemer indices are per-purpose and don&#39;t directly map to the concatenated `allScripts` array. Scripts should be looked up by their hash matching the script reference in the transaction input/policy, not by redeemer index.</violation>

<violation number="3" location="internal/utxorpc/submit.go:325">
P1: Incorrect datum source: For spending scripts, `datum` is incorrectly set to `value.Data.Data` (the redeemer). The datum should be retrieved from the UTxO being spent at the index specified by `key.Index`, not from the redeemer itself.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

PlutusData: &cardano.PlutusData_BigInt{
BigInt: &cardano.BigInt{
BigInt: &cardano.BigInt_Int{
Int: v.Inner.Int64(),
Copy link

@cubic-dev-ai cubic-dev-ai bot Dec 7, 2025

Choose a reason for hiding this comment

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

P1: Potential integer overflow: v.Inner.Int64() will silently truncate big integers that exceed int64 range. Consider using BigInt_BigUInt or BigInt_BigNInt for arbitrary precision, or at minimum check if the value fits with v.Inner.IsInt64() before conversion.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At internal/utxorpc/submit.go, line 174:

<comment>Potential integer overflow: `v.Inner.Int64()` will silently truncate big integers that exceed int64 range. Consider using `BigInt_BigUInt` or `BigInt_BigNInt` for arbitrary precision, or at minimum check if the value fits with `v.Inner.IsInt64()` before conversion.</comment>

<file context>
@@ -83,6 +87,291 @@ func (s *submitServiceServer) SubmitTx(
+			PlutusData: &amp;cardano.PlutusData_BigInt{
+				BigInt: &amp;cardano.BigInt{
+					BigInt: &amp;cardano.BigInt_Int{
+						Int: v.Inner.Int64(),
+					},
+				},
</file context>
Fix with Cubic

// For now, only handle spending scripts with datum, redeemer, context
if key.Tag == 0 { // RedeemerTagSpend
// Get datum - for simplicity, assume it's the redeemer data for now
datum := value.Data.Data
Copy link

@cubic-dev-ai cubic-dev-ai bot Dec 7, 2025

Choose a reason for hiding this comment

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

P1: Incorrect datum source: For spending scripts, datum is incorrectly set to value.Data.Data (the redeemer). The datum should be retrieved from the UTxO being spent at the index specified by key.Index, not from the redeemer itself.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At internal/utxorpc/submit.go, line 325:

<comment>Incorrect datum source: For spending scripts, `datum` is incorrectly set to `value.Data.Data` (the redeemer). The datum should be retrieved from the UTxO being spent at the index specified by `key.Index`, not from the redeemer itself.</comment>

<file context>
@@ -83,6 +87,291 @@ func (s *submitServiceServer) SubmitTx(
+			// For now, only handle spending scripts with datum, redeemer, context
+			if key.Tag == 0 { // RedeemerTagSpend
+				// Get datum - for simplicity, assume it&#39;s the redeemer data for now
+				datum := value.Data.Data
+				redeemerData := value.Data.Data
+				// TODO: build proper script context
</file context>
Fix with Cubic

}

// Try to evaluate if we have a script for this redeemer
if int(key.Index) < len(allScripts) {
Copy link

@cubic-dev-ai cubic-dev-ai bot Dec 7, 2025

Choose a reason for hiding this comment

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

P1: Incorrect script lookup: Redeemer indices are per-purpose and don't directly map to the concatenated allScripts array. Scripts should be looked up by their hash matching the script reference in the transaction input/policy, not by redeemer index.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At internal/utxorpc/submit.go, line 315:

<comment>Incorrect script lookup: Redeemer indices are per-purpose and don&#39;t directly map to the concatenated `allScripts` array. Scripts should be looked up by their hash matching the script reference in the transaction input/policy, not by redeemer index.</comment>

<file context>
@@ -83,6 +87,291 @@ func (s *submitServiceServer) SubmitTx(
+		}
+
+		// Try to evaluate if we have a script for this redeemer
+		if int(key.Index) &lt; len(allScripts) {
+			scriptBytes := allScripts[key.Index]
+			version := scriptVersions[key.Index]
</file context>
Fix with Cubic

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.

[UTXORPC] Implement submit.EvalTx

2 participants