Skip to content

chore: force deterministic args for attestation queries#1215

Merged
MicBun merged 1 commit intomainfrom
forceDeterminism
Oct 14, 2025
Merged

chore: force deterministic args for attestation queries#1215
MicBun merged 1 commit intomainfrom
forceDeterminism

Conversation

@MicBun
Copy link
Member

@MicBun MicBun commented Oct 14, 2025

Add tn_utils.force_last_arg_false precompile to override use_cache parameter in attestation requests, ensuring all validators compute identical results regardless of cache state.

Changes:

  • Add force_last_arg_false() precompile to tn_utils
  • Update request_attestation to force use_cache=false for query actions
  • Add comprehensive tests covering edge cases

Fixes non-deterministic attestation results when users pass use_cache=true for composed stream queries. Query actions (IDs 1-5) now automatically override the last parameter to false before executing via call_dispatch.

resolves: #1208

Summary by CodeRabbit

  • Bug Fixes

    • Ensures deterministic execution for certain attestation actions by disabling caching during dispatch, improving reliability and consistency of results.
    • Preserves original behavior when no arguments are provided and handles malformed inputs more robustly.
  • Tests

    • Added comprehensive tests validating that the last argument is correctly forced to false, including cases with empty inputs, single/multiple arguments, and invalid data, improving error-path coverage and stability.

Add tn_utils.force_last_arg_false precompile to override use_cache
parameter in attestation requests, ensuring all validators compute
identical results regardless of cache state.

Changes:
- Add force_last_arg_false() precompile to tn_utils
- Update request_attestation to force use_cache=false for query actions
- Add comprehensive tests covering edge cases

Fixes non-deterministic attestation results when users pass use_cache=true
for composed stream queries. Query actions (IDs 1-5) now automatically
override the last parameter to false before executing via call_dispatch.

resolves: #1208
@MicBun MicBun requested a review from outerlook October 14, 2025 11:25
@MicBun MicBun self-assigned this Oct 14, 2025
@holdex
Copy link

holdex bot commented Oct 14, 2025

Time Submission Status

Member Status Time Action Last Update
MicBun ✅ Submitted 6h Update time Oct 14, 2025, 11:59 AM
@outerlook ❌ Missing - ⚠️ Submit time -

@coderabbitai
Copy link

coderabbitai bot commented Oct 14, 2025

Walkthrough

Adds a tn_utils precompile method force_last_arg_false with a handler that forces the last encoded action argument to false. Integrates it into the precompile registry. Updates attestation SQL to call this method for actions 1–5 before dispatch. Introduces comprehensive tests for the handler.

Changes

Cohort / File(s) Summary
tn_utils precompile addition
extensions/tn_utils/precompiles.go
Adds force_last_arg_false method and forceLastArgFalseHandler to decode args_bytes, set last arg to false, re-encode, and return modified bytes; registers method in buildPrecompile. Handles empty args and (de)serialization errors.
Handler tests
extensions/tn_utils/serialization_test.go
New tests covering normal, already-false, empty, single-arg, invalid bytes, and non-bytes cases for forceLastArgFalseHandler using EncodeActionArgs/DecodeActionArgs.
Attestation arg enforcement
internal/migrations/024-attestation-actions.sql
Mutates args for attestation actions with IDs 1–5 by calling tn_utils.force_last_arg_false before tn_utils.call_dispatch; removes prior TODO commentary.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant SQL as SQL (attestation)
  participant TN as tn_utils.precompile
  participant Disp as call_dispatch

  Client->>SQL: request_attestation(action_id, args_bytes)
  alt action_id in [1..5]
    SQL->>TN: force_last_arg_false(args_bytes)
    TN->>TN: decode args, set last arg=false, encode
    TN-->>SQL: modified_args_bytes
    SQL->>Disp: call_dispatch(action_id, modified_args_bytes)
  else other actions
    SQL->>Disp: call_dispatch(action_id, args_bytes)
  end
  Disp-->>Client: result/status

  note over TN: New mutation step ensures last arg is false when applicable
Loading
sequenceDiagram
  autonumber
  participant Ext as tn_utils.precompile
  participant Handler as forceLastArgFalseHandler

  Ext->>Handler: handle(args_bytes)
  alt decodable args
    Handler->>Handler: parse list
    alt empty list
      Handler-->>Ext: return original args_bytes
    else non-empty
      Handler->>Handler: set last arg=false
      Handler-->>Ext: return modified_args_bytes
    end
  else decode error
    Handler-->>Ext: error
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I twitch my whiskers, flip a bit, of course—
Last arg now false, a deterministic course.
SQL hops first, precompile in tow,
Bytes get a nudge, then off they go.
Cache dreams fade, consensus holds tight—
A happy hare signs attestations right. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title clearly reflects the primary change of forcing deterministic arguments in attestation queries, matching the code updates that override the use_cache parameter for these actions.
Linked Issues Check ✅ Passed The pull request implements the core requirement of linked issue #1208 by overriding the non-deterministic use_cache argument for attestation actions and ensures consistency across validators through the new precompile and migration update.
Out of Scope Changes Check ✅ Passed All modifications are directly related to forcing deterministic attestation arguments by adding the new precompile, tests, and updating the migration, with no unrelated or extraneous changes outside the scope of the linked issue.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch forceDeterminism

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

🧹 Nitpick comments (1)
extensions/tn_utils/serialization_test.go (1)

465-577: Excellent test coverage with one enhancement opportunity.

The TestForceLastArgFalseHandler test suite provides comprehensive coverage:

Covered scenarios:

  • Normal case: forcing true to false with multiple arguments
  • Idempotency: verifying already-false values remain false
  • Edge cases: empty args and single argument
  • Error handling: invalid bytes and wrong input type

The tests correctly validate the transformation by encoding, processing through the handler, and decoding to verify the last argument is false.

Enhancement opportunity: Add a test case for type safety when the last argument is not boolean:

t.Run("non-boolean last arg returns error on re-encode", func(t *testing.T) {
    // Args with a string as the last parameter instead of boolean
    original := []interface{}{
        "provider",
        "stream",
        int64(100),
        int64(200),
        nil,
        "not_a_boolean", // Last arg is string, not boolean
    }

    argsBytes, err := EncodeActionArgs(original)
    require.NoError(t, err)

    // Attempting to force last arg to false should fail during re-encoding
    // because we're replacing a string with a boolean
    err = forceLastArgFalseHandler(nil, nil, []any{argsBytes}, func([]any) error { return nil })
    // Depending on implementation, this might succeed (if types.EncodeValue accepts bool)
    // or fail (if there's type checking). Document the expected behavior.
    
    // If the implementation allows this, verify the result is a boolean false
    // If not, expect an error
})

This would document and test the behavior when the type assumptions are violated.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3396806 and 10da0a2.

📒 Files selected for processing (3)
  • extensions/tn_utils/precompiles.go (2 hunks)
  • extensions/tn_utils/serialization_test.go (1 hunks)
  • internal/migrations/024-attestation-actions.sql (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-10T13:00:14.189Z
Learnt from: outerlook
PR: trufnetwork/node#1207
File: internal/migrations/024-attestation-actions.sql:58-76
Timestamp: 2025-10-10T13:00:14.189Z
Learning: In the attestation system for internal/migrations/024-attestation-actions.sql, the attestation_hash is computed from (version|algo|data_provider|stream_id|action_id|args) and intentionally excludes created_height. This design ensures the hash is deterministic based only on user input, not network state like block height.

Applied to files:

  • internal/migrations/024-attestation-actions.sql
🧬 Code graph analysis (2)
extensions/tn_utils/serialization_test.go (1)
extensions/tn_utils/serialization.go (2)
  • EncodeActionArgs (45-76)
  • DecodeActionArgs (85-130)
extensions/tn_utils/precompiles.go (1)
extensions/tn_utils/serialization.go (2)
  • DecodeActionArgs (85-130)
  • EncodeActionArgs (45-76)
⏰ 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: acceptance-test
🔇 Additional comments (5)
extensions/tn_utils/precompiles.go (4)

28-28: LGTM! Precompile method correctly registered.

The forceLastArgFalseMethod() is properly added to the Methods list in the precompile bundle, ensuring it's accessible from SQL migrations via the tn_utils namespace.


347-364: LGTM! Method definition follows established patterns.

The forceLastArgFalseMethod is well-structured with:

  • Appropriate access modifiers (VIEW, PUBLIC)
  • Clear parameter and return type definitions
  • Consistent naming that conveys intent

366-394: Verify type safety when the last argument is not boolean.

The handler correctly decodes, modifies, and re-encodes the arguments. However, there's no type checking before forcing the last argument to false (line 385). If the last argument is not boolean-compatible, the subsequent re-encoding might fail or produce unexpected results.

While the current use case (forcing use_cache parameter) guarantees the last argument is boolean, consider adding defensive type checking for robustness:

 // Force last parameter to false (for use_cache)
+// Verify the last argument is boolean before forcing
+if _, ok := args[len(args)-1].(bool); !ok {
+    // Check for boolean pointer as well
+    if ptr, ok := args[len(args)-1].(*bool); !ok || ptr == nil {
+        return fmt.Errorf("last argument must be boolean, got %T", args[len(args)-1])
+    }
+}
 args[len(args)-1] = false

Alternatively, document that this handler is specifically designed for actions where the last parameter is guaranteed to be boolean, and add a test case to verify the error behavior when the last argument has an incompatible type.


380-382: Edge case handling is correct.

Returning the original argsBytes unchanged when there are no arguments is the appropriate behavior. This prevents unnecessary processing and avoids errors from attempting to modify a non-existent last argument.

internal/migrations/024-attestation-actions.sql (1)

40-46: Verify parameter ordering for query actions (1–5)
Ensure use_cache is the final parameter for all actions with IDs 1–5 (get_record, get_index, get_change_over_time, get_last_record, get_first_record); mismatches will break the deterministic enforcement.

@MicBun MicBun merged commit 3a8343e into main Oct 14, 2025
6 of 7 checks passed
@MicBun MicBun deleted the forceDeterminism branch October 14, 2025 12:00
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.

Problem: non-deterministic args in attestation not filtered

2 participants