Skip to content

chore: compatibilize evm attestation integration#1218

Merged
MicBun merged 8 commits intomainfrom
chore/enhance-att
Oct 17, 2025
Merged

chore: compatibilize evm attestation integration#1218
MicBun merged 8 commits intomainfrom
chore/enhance-att

Conversation

@outerlook
Copy link
Contributor

@outerlook outerlook commented Oct 16, 2025

Description

  • Replaced the buildCanonical function with BuildCanonicalPayload, ensuring consistent use of big-endian length prefixes for variable sections.
  • Updated tests to reflect changes in the canonical payload structure, including adjustments to dataProvider and streamID.
  • Enhanced validation for canonical payloads to ensure compliance with expected formats, particularly for algorithm and length checks.
  • Introduced new helper functions for length-prefixing data, improving code clarity and maintainability.

Related Problem

How Has This Been Tested?

Summary by CodeRabbit

  • New Features

    • Precompile to convert canonical attestations into ABI-encoded data points.
    • Exported canonical payload builder and EVM-compatible payload validation.
    • Big-endian length-prefix encoding for canonical fields.
  • Tests

    • Comprehensive attestation E2E tests, golden fixture, docker-compose setup and runner; updated integration and harness tests.
  • Documentation

    • Attestation E2E README and updated length-prefix docs.
  • Bug Fixes / Changes

    • Request attestation inputs normalized/validated; payload hashing uses length-prefixed fields; algorithm selector updated.

- Replaced the buildCanonical function with BuildCanonicalPayload, ensuring consistent use of big-endian length prefixes for variable sections.
- Updated tests to reflect changes in the canonical payload structure, including adjustments to dataProvider and streamID.
- Enhanced validation for canonical payloads to ensure compliance with expected formats, particularly for algorithm and length checks.
- Introduced new helper functions for length-prefixing data, improving code clarity and maintainability.

These changes enhance the reliability and consistency of the attestation processing workflow, ensuring accurate handling of canonical payloads.
@outerlook outerlook self-assigned this Oct 16, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 16, 2025

Walkthrough

Adds exported BuildCanonicalPayload and CanonicalPayload.ValidateForEVM; switches canonical length-prefixes to big-endian across payload building, hashing, precompiles, docs, and migrations; adds canonical→DataPoints ABI encoder and precompile; updates processor validation and hashing; introduces attestation E2E tests, fixtures, and tooling.

Changes

Cohort / File(s) Summary
Core Canonical Payload Logic
extensions/tn_attestation/canonical.go
Adds exported BuildCanonicalPayload(...) []byte, adds (*CanonicalPayload) ValidateForEVM() error, replaces little-endian length prefixes with big-endian, and introduces lengthPrefixBigEndian helper.
Attestation Tests & Integration
extensions/tn_attestation/canonical_test.go, extensions/tn_attestation/integration_test.go, extensions/tn_attestation/processor_test.go, extensions/tn_attestation/harness_integration_test.go
Tests updated to call BuildCanonicalPayload; fixtures changed to deterministic byte patterns; algorithm value changed to 0; tests/harness updated to use big-endian length-prefixed canonical payloads and new validation semantics.
Processor & Validation
extensions/tn_attestation/processor.go
Calls payload.ValidateForEVM() in prepareSigningWork; computeAttestationHash now includes big-endian length-prefixed DataProvider, StreamID, and Args in hash material.
TN Utils — Precompile & Datapoints
extensions/tn_utils/precompiles.go, extensions/tn_utils/datapoints.go
Adds precompile canonical_to_datapoints_abi and handler; adds EncodeDataPointsABI(canonical []byte) ([]byte, error) to parse canonical rows and ABI-pack uint256[] timestamps + int256[] values; aligns length-prefix semantics to big-endian.
TN Utils — Serialization & Docs
extensions/tn_utils/serialization_test.go, extensions/tn_utils/README.md
Tests and docs updated to expect 4-byte big-endian length prefixes (replacing little-endian).
Database Migration / Actions
internal/migrations/024-attestation-actions.sql
Changes request_attestation params: $data_provider,$stream_id from BYTEATEXT; normalizes/validates inputs, derives byte arrays, uses bytea_length_prefix(...) (big-endian) and canonical_to_datapoints_abi($query_result); sets algorithm to 0.
End-to-End Test infra
tests/extensions/tn_attestation/attestation_e2e_test.go, tests/extensions/tn_attestation/docker-compose.yml, tests/extensions/tn_attestation/test_tn_attestation.sh, tests/extensions/tn_attestation/README.md
Adds an attestation E2E test, docker-compose for services, a bash test runner, and README documenting the workflow and test steps.
Stream Tests & Helpers
tests/streams/attestation/attestation_request_test.go, tests/streams/attestation/test_helpers.go
Replaces local canonical builders with attestation.BuildCanonicalPayload(...); updates fixtures (TestStreamID, TestDataProviderHex, TestDataProviderBytes); removes legacy helper functions and local length-prefix utilities.
Testdata & Fixtures
extensions/tn_attestation/testdata/attestation_golden.json
Adds golden attestation fixture (canonical, signature, payload, metadata).

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client as Request / Tests
    participant Builder as BuildCanonicalPayload
    participant Parser as CanonicalPayload (parse)
    participant Validator as ValidateForEVM
    participant Hasher as computeAttestationHash
    participant Signer as Signing Worker

    Client->>Builder: (version, algo, height, provider, stream, action, args, result)
    Builder-->>Client: canonical bytes (big-endian length-prefixed)
    Client->>Parser: parse(canonical)
    Parser->>Validator: ValidateForEVM()
    Validator-->>Parser: ok / error
    Parser->>Hasher: fields (with length-prefixes)
    Hasher-->>Signer: attestation hash
    Signer-->>Client: signature
    Note over Builder,Validator: New: big-endian prefixes & EVM validation
Loading
sequenceDiagram
    autonumber
    participant SQL as request_attestation
    participant Normalize as Migration logic
    participant Precompile as canonical_to_datapoints_abi
    participant Encoder as bytea_length_prefix (big-endian)
    participant DB as Store attestation row

    SQL->>Normalize: accept TEXT inputs ($data_provider, $stream_id)
    Normalize->>Normalize: validate/normalize (hex, length)
    Normalize->>Precompile: canonical_to_datapoints_abi($query_result)
    Precompile-->>Normalize: result_payload (ABI)
    Normalize->>Encoder: bytea_length_prefix(data_provider_bytes), bytea_length_prefix(stream_bytes)
    Encoder-->>DB: store canonical payload + attestation_hash
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • MicBun
  • williamrusdyputra

Poem

🐰 I hopped through bytes and flipped their end,

Big-endian beats little now — a tidy bend.
I packed the points and checked each key,
I signed the hop and set them free.
Carrots, code, and proofs — attest with glee.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 title "chore: compatibilize evm attestation integration" is concise and clearly refers to the primary objective of the changeset: improving EVM compatibility for attestation encoding. The changes comprehensively address EVM attestation compatibility through unified big-endian encoding, public API exports (BuildCanonicalPayload, ValidateForEVM), ABI-encoded data points, and updated migrations. While the title is somewhat broad and doesn't specify the mechanisms used (big-endian encoding, length-prefixes), it effectively communicates the main goal from the developer's perspective.
Linked Issues Check ✅ Passed The changeset fully addresses all objectives from linked issue #1217. The endianness unification objective is met through consistent big-endian length prefixes across canonical.go, precompiles.go, and the migration file. The ABI-encoded data points standardization is achieved via the new EncodeDataPointsABI function and canonical_to_datapoints_abi precompile. The interface improvement objectives are satisfied by exporting BuildCanonicalPayload as a public function, introducing ValidateForEVM for strict EVM constraints, and updating the migration to properly handle data_provider and stream_id as TEXT with validation. These changes collectively make the node-to-EVM contract interface easier to implement and maintain.
Out of Scope Changes Check ✅ Passed All changes in the pull request are directly in scope and aligned with the linked issue objectives. Core changes include the public BuildCanonicalPayload function, big-endian encoding standardization, ValidateForEVM validation method, and the new EncodeDataPointsABI function with canonical_to_datapoints_abi precompile—all addressing EVM compatibility. Test file updates, migrations, and the new e2e test infrastructure are necessary supporting changes to validate and implement the core functionality. No extraneous changes or refactorings unrelated to the stated objectives are present.
✨ 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 chore/enhance-att

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.

- Updated the harness integration test to use byte arrays for dataProvider and streamID, ensuring consistency with EVM-compatible field sizes.
- Added validation checks in the SQL migration to enforce specific byte lengths for dataProvider and streamID, improving data integrity.
- Refactored end-to-end tests to implement a realistic stream-based workflow, enhancing the testing of the attestation process.

These changes improve the reliability and maintainability of the attestation system, ensuring accurate processing and validation of attestations.
…nality

- Replaced DROP and CREATE statements with CREATE OR REPLACE for the request_attestation and sign_attestation actions, enhancing the migration process.
- Updated end-to-end tests to utilize clienttypes.WithSyncBroadcast for improved transaction handling and error management.
- Enhanced error logging in the registerDataProvider function to provide clearer context on action availability.

These changes improve the maintainability and reliability of the attestation actions and their associated tests, ensuring a more robust integration within the system.
- Changed data types for $data_provider and $stream_id in the request_attestation action from BYTEA to TEXT, improving input handling.
- Added validation checks to ensure $data_provider is 0x-prefixed and has a length of 42 characters, and that $stream_id has a length of 32 characters, enhancing data integrity.
- Updated end-to-end tests to reflect changes in data handling, ensuring consistency with the new input types and validation logic.

These changes improve the robustness and reliability of the attestation process, ensuring accurate data validation and handling.
@outerlook outerlook marked this pull request as ready for review October 16, 2025 18:25
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 (2)
tests/extensions/tn_attestation/README.md (1)

40-54: Add language identifier to fenced code block.

The test flow diagram would benefit from a language identifier for better syntax highlighting and parsing.

Apply this diff to add the identifier:

-```
+```text
 request_attestation (SQL)
     ↓
 queue_for_signing (precompile adds to queue)

Based on static analysis hints.

extensions/tn_utils/precompiles.go (1)

80-88: Update comment to reflect big-endian prefixing

The docstring still says “little endian,” but lengthPrefixBytes (and the rest of the stack) now emit big-endian headers. Please refresh the wording so future readers don’t get tripped up.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b92a38 and 4f84501.

📒 Files selected for processing (17)
  • extensions/tn_attestation/canonical.go (4 hunks)
  • extensions/tn_attestation/canonical_test.go (3 hunks)
  • extensions/tn_attestation/harness_integration_test.go (3 hunks)
  • extensions/tn_attestation/integration_test.go (1 hunks)
  • extensions/tn_attestation/processor.go (2 hunks)
  • extensions/tn_attestation/processor_test.go (4 hunks)
  • extensions/tn_utils/README.md (1 hunks)
  • extensions/tn_utils/datapoints.go (1 hunks)
  • extensions/tn_utils/precompiles.go (5 hunks)
  • extensions/tn_utils/serialization_test.go (2 hunks)
  • internal/migrations/024-attestation-actions.sql (4 hunks)
  • tests/extensions/tn_attestation/README.md (1 hunks)
  • tests/extensions/tn_attestation/attestation_e2e_test.go (1 hunks)
  • tests/extensions/tn_attestation/docker-compose.yml (1 hunks)
  • tests/extensions/tn_attestation/test_tn_attestation.sh (1 hunks)
  • tests/streams/attestation/attestation_request_test.go (3 hunks)
  • tests/streams/attestation/test_helpers.go (4 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 (8)
extensions/tn_utils/precompiles.go (1)
extensions/tn_utils/datapoints.go (1)
  • EncodeDataPointsABI (32-64)
extensions/tn_attestation/processor_test.go (1)
extensions/tn_attestation/canonical.go (1)
  • BuildCanonicalPayload (38-58)
extensions/tn_utils/datapoints.go (1)
extensions/tn_utils/serialization.go (1)
  • DecodeQueryResultCanonical (188-239)
tests/extensions/tn_attestation/test_tn_attestation.sh (1)
tests/extensions/tn_attestation/attestation_e2e_test.go (1)
  • TestAttestationE2E (28-49)
extensions/tn_attestation/canonical_test.go (1)
extensions/tn_attestation/canonical.go (1)
  • BuildCanonicalPayload (38-58)
tests/extensions/tn_attestation/attestation_e2e_test.go (1)
extensions/tn_utils/serialization.go (1)
  • EncodeActionArgs (45-76)
extensions/tn_attestation/integration_test.go (1)
extensions/tn_attestation/canonical.go (1)
  • BuildCanonicalPayload (38-58)
tests/streams/attestation/attestation_request_test.go (3)
extensions/tn_utils/serialization.go (1)
  • EncodeQueryResultCanonical (145-184)
extensions/tn_utils/datapoints.go (1)
  • EncodeDataPointsABI (32-64)
extensions/tn_attestation/canonical.go (1)
  • BuildCanonicalPayload (38-58)
🪛 LanguageTool
tests/extensions/tn_attestation/README.md

[grammar] ~9-~9: There might be a mistake here.
Context: ...tion-like environment. Complete flow: 1. Submit request_attestation → stores in...

(QB_NEW_EN)


[grammar] ~11-~11: There might be a mistake here.
Context: ...recompile → adds hash to in-memory queue 3. End-of-block hook → dequeues and process...

(QB_NEW_EN)


[grammar] ~12-~12: There might be a mistake here.
Context: ...ock hook → dequeues and processes hashes 4. Query database → finds unsigned attestat...

(QB_NEW_EN)


[grammar] ~13-~13: There might be a mistake here.
Context: ...y database → finds unsigned attestations 5. Sign → validator generates signature 6. ...

(QB_NEW_EN)


[grammar] ~14-~14: There might be a mistake here.
Context: ... 5. Sign → validator generates signature 6. Broadcast → submits sign_attestation t...

(QB_NEW_EN)


[grammar] ~15-~15: There might be a mistake here.
Context: ...→ submits sign_attestation transaction 7. Retrieve → get_signed_attestation retu...

(QB_NEW_EN)


[grammar] ~58-~58: There might be a mistake here.
Context: ...Request confirmed and stored in database - ✅ Signature generated within 90 seconds ...

(QB_NEW_EN)


[grammar] ~59-~59: There might be a mistake here.
Context: ... 90 seconds (proves end-of-block worked) - ✅ Signed payload retrieved successfully ...

(QB_NEW_EN)


[grammar] ~60-~60: There might be a mistake here.
Context: ... ✅ Signed payload retrieved successfully - ✅ Payload structure valid: `canonical ||...

(QB_NEW_EN)


[grammar] ~65-~65: There might be a mistake here.
Context: ...ngle validator (no multi-node consensus) - Fixed validator key (deterministic for t...

(QB_NEW_EN)


[grammar] ~66-~66: There might be a mistake here.
Context: ...alidator key (deterministic for testing) - No network failure simulation - Assumes ...

(QB_NEW_EN)


[grammar] ~67-~67: There might be a mistake here.
Context: ...testing) - No network failure simulation - Assumes node is always leader ## Valida...

(QB_NEW_EN)


[grammar] ~76-~76: There might be a mistake here.
Context: ...istribute validator keys out of band and rotate them via node configuration, not ...

(QB_NEW_EN)

🪛 markdownlint-cli2 (0.18.1)
tests/extensions/tn_attestation/README.md

42-42: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ 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: lint
  • GitHub Check: acceptance-test
🔇 Additional comments (24)
tests/streams/attestation/test_helpers.go (4)

8-9: LGTM!

The added imports support the new mustHexToBytes helper function for hex string conversion.


27-28: LGTM!

The test data constants have been updated to use deterministic hex patterns that align with EVM address formats, improving compatibility with the attestation encoding changes.


35-46: LGTM!

The mustHexToBytes helper correctly normalizes hex strings and panics on error, which is appropriate for package initialization. The TestDataProviderBytes variable provides convenient pre-decoded test data.


158-159: LGTM!

Test helper methods correctly use the new hex-formatted test constants, maintaining consistency across the test suite.

Also applies to: 215-216

extensions/tn_utils/README.md (1)

16-16: Documentation correctly updated.

The endianness change from little-endian to big-endian is clearly documented, aligning with the broader attestation encoding improvements.

extensions/tn_utils/serialization_test.go (2)

359-364: LGTM!

Test expectations correctly updated to reflect big-endian 4-byte length prefixes. The encoding is accurate: length 2 → [0, 0, 0, 2], length 3 → [0, 0, 0, 3].


401-403: LGTM!

Multi-element prefix test expectations correctly updated for big-endian encoding: [0, 0, 0, 1] for length 1 and [0, 0, 0, 2] for length 2.

extensions/tn_attestation/processor.go (2)

142-144: LGTM!

The addition of ValidateForEVM() provides essential validation to ensure canonical payloads meet EVM compatibility requirements before signing. Good defensive programming.


218-219: LGTM!

The hash computation correctly incorporates big-endian length prefixes for variable-length fields (DataProvider, StreamID, Args), aligning with the new canonical payload structure. Note that this changes the hash calculation, so existing attestations will have different hashes under the new encoding.

Also applies to: 224-224

extensions/tn_attestation/harness_integration_test.go (3)

6-6: LGTM!

The bytes import is required for the new test data generation using bytes.Repeat.


97-98: LGTM!

Test data generation using bytes.Repeat provides deterministic byte patterns that better represent the actual data types (20-byte addresses, 32-byte IDs) used in production.


151-151: Algorithm value 0 is correct
All existing builders, parsers, and tests (processor_test.go, canonical_test.go, attestation_request_test.go) use algorithm = 0 and BuildCanonicalPayload writes the passed byte unconditionally, so the change is intentional and aligned with the canonical format.

tests/extensions/tn_attestation/docker-compose.yml (3)

4-16: LGTM! Test-only security posture noted.

The postgres configuration is appropriate for a test environment. The POSTGRES_HOST_AUTH_METHOD=trust setting allows passwordless connections, which is acceptable for isolated test containers but should never be used in production.


18-49: LGTM! Test configuration is comprehensive.

The kwild service configuration properly depends on postgres health, uses appropriate test credentials, and includes comprehensive health checks. The private key is clearly a test key (sequential pattern) suitable only for test environments.


51-53: LGTM!

The dedicated bridge network provides proper service isolation and internal name resolution for the test environment.

extensions/tn_utils/datapoints.go (5)

11-28: LGTM!

Package initialization correctly sets up ABI argument types for uint256[] and int256[]. The scale value of 18 matches standard Ethereum decimal precision. Panic on initialization failure is appropriate.


30-64: LGTM!

The main ABI encoding function properly decodes canonical results, validates row structure (requiring at least 2 columns), and encodes to the expected ABI format with clear error messages.


66-84: LGTM!

Timestamp extraction correctly handles both pointer and value types, validates non-NULL and non-negative constraints, and safely converts to *big.Int.


86-98: LGTM!

Data point value extraction correctly handles both pointer and value decimal types, validates non-NULL, and delegates to the scale conversion helper.


100-110: LGTM!

Decimal to scaled integer conversion correctly validates the expected scale (18), extracts the big integer value, and properly applies the sign. This ensures precision alignment with EVM decimal standards.

extensions/tn_attestation/integration_test.go (1)

45-56: Canonical payload builder aligns with the new big-endian scheme

Switching the fixture to BuildCanonicalPayload with deterministic provider/stream IDs matches the production path and keeps the integration test in lockstep with the contract-facing format. Looks solid.

extensions/tn_attestation/canonical_test.go (1)

11-40: Happy path coverage stays comprehensive

The test updates exercise BuildCanonicalPayload and verify the digest against the raw bytes, so we still cover all fields under the new encoding. All good here.

extensions/tn_attestation/processor_test.go (1)

239-250: Hash material now mirrors canonical payload exactly

Updating the hash fixture to use the same big-endian length-prefix helper removes the previous divergence between tests and production. Nice catch.

extensions/tn_utils/precompiles.go (1)

138-153: New ABI precompile integrates smoothly

Adding canonical_to_datapoints_abi with the existing helpers cleanly exposes the ABI encoder to SQL. Registration and handler wiring look spot on.

@holdex
Copy link

holdex bot commented Oct 16, 2025

Time Submission Status

Member Status Time Action Last Update
outerlook ✅ Submitted 9h Update time Oct 17, 2025, 9:17 PM
@MicBun ❌ Missing - ⚠️ Submit time -

…n workflow

- Updated the harness integration test to replace byte arrays with string representations for dataProvider and streamID, improving readability and consistency with expected formats.
- Refactored the requestStreamAttestation function to return encoded action arguments, facilitating better validation in end-to-end tests.
- Enhanced the testCompleteStreamAttestationWorkflow function to include detailed validation of canonical payload fields, ensuring accurate verification of attestation results.
- Introduced new helper functions for decoding payload strings and handling argument types, improving code clarity and maintainability.

These changes enhance the reliability and clarity of the attestation testing framework, ensuring robust validation of the attestation process.
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

♻️ Duplicate comments (1)
tests/extensions/tn_attestation/attestation_e2e_test.go (1)

422-424: Remove ASCII fallback to avoid masking bad payloads.

If the payload string isn’t valid hex/base64 we immediately return the raw ASCII bytes, so we’re back to slicing textual data—the bug from the earlier review. Let this surface as an error instead so the test fails when the payload isn’t real binary.

-	// As a last resort, treat the original string as raw bytes.
-	return []byte(raw), nil
+	return nil, fmt.Errorf("unrecognized payload encoding: %q", raw)
🧹 Nitpick comments (1)
extensions/tn_attestation/harness_integration_test.go (1)

353-397: Consider the implications of requester-based lookup.

The function changed from querying by attestation_hash (which is unique) to querying by requester with ORDER BY created_height DESC, request_tx_id DESC LIMIT 1. While this works in the current test context where each requester has only one attestation, it's less precise and could be fragile if the test is extended to create multiple attestations for the same requester.

Consider these options:

  1. Keep current approach if the test will always use unique requesters or only query the latest attestation.
  2. Revert to hash-based lookup for more precise row identification:
-func fetchAttestationRowHarness(t *testing.T, ctx context.Context, platform *kwilTesting.Platform, requester []byte) harnessAttestationRow {
+func fetchAttestationRowHarness(t *testing.T, ctx context.Context, platform *kwilTesting.Platform, attestationHash []byte) harnessAttestationRow {
	// ...
	err := platform.Engine.Execute(engineCtx, platform.DB, `
-WHERE requester = $requester
-ORDER BY created_height DESC, request_tx_id DESC
-LIMIT 1;
-`, map[string]any{"requester": requester}, func(row *common.Row) error {
+WHERE attestation_hash = $attestation_hash;
+`, map[string]any{"attestation_hash": attestationHash}, func(row *common.Row) error {

Or document the assumption that each requester has only one attestation in this test.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f84501 and f60a56f.

📒 Files selected for processing (2)
  • extensions/tn_attestation/harness_integration_test.go (7 hunks)
  • tests/extensions/tn_attestation/attestation_e2e_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
tests/extensions/tn_attestation/attestation_e2e_test.go (2)
extensions/tn_attestation/canonical.go (1)
  • ParseCanonicalPayload (63-105)
extensions/tn_utils/serialization.go (2)
  • DecodeActionArgs (85-130)
  • EncodeActionArgs (45-76)
extensions/tn_attestation/harness_integration_test.go (2)
extensions/tn_utils/serialization.go (2)
  • EncodeActionArgs (45-76)
  • EncodeQueryResultCanonical (145-184)
extensions/tn_attestation/canonical.go (2)
  • BuildCanonicalPayload (38-58)
  • ParseCanonicalPayload (63-105)
⏰ 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: acceptance-test
  • GitHub Check: lint
🔇 Additional comments (4)
extensions/tn_attestation/harness_integration_test.go (4)

96-98: LGTM - dataProvider and streamID standardization.

The change from fixed byte slices to generated Ethereum address and stream ID aligns with the PR's standardization objectives. Using util.GenerateStreamId and string representations improves consistency with the production code path.


202-204: LGTM - Algorithm and field validations updated for standardization.

The algorithm field validation changed from 1 to 0 to correctly represent secp256k1 (as documented in line 128). The DataProvider and StreamID assertions are updated to match the new canonical payload structure using Ethereum addresses and string-based stream IDs. These changes align with the PR's standardization objectives.


216-217: LGTM - Improved error handling for key generation.

Adding proper error checking for kcrypto.GenerateSecp256k1Key improves test robustness. Previously, a key generation failure could have gone unnoticed, leading to confusing test failures downstream.


106-179: SQL migration request_attestation is adequately tested elsewhere.

Verification confirms that request_attestation is thoroughly tested in:

  • tests/streams/attestation/attestation_request_test.go — direct unit test of the SQL action
  • tests/streams/attestation/test_helpers.go — helper functions used across test suites
  • tests/extensions/tn_attestation/attestation_e2e_test.go — end-to-end client execution

The manual payload construction in this harness test appropriately isolates testing of BuildCanonicalPayload, while the SQL migration path is exercised separately and comprehensively elsewhere.

@MicBun MicBun marked this pull request as draft October 17, 2025 06:38
@outerlook outerlook marked this pull request as ready for review October 17, 2025 15:53
@outerlook
Copy link
Contributor Author

I'll keep it as a non-draft to receive checks from coderabbit

- Updated the harness integration test to manually construct the attestation using the BuildCanonicalPayload function, ensuring accurate verification of attestation bytes.
- Refactored the request_attestation test to replace byte arrays with hex string representations for dataProvider, improving consistency and readability.
- Enhanced validation in the runAttestationHappyPath function to ensure correct data types for return values, improving test reliability.
- Modified the SetupTestAction function to return a more detailed result structure, enhancing clarity in the test setup.

These changes improve the robustness and maintainability of the attestation testing framework, ensuring accurate validation of the attestation process.
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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f60a56f and a7e083b.

📒 Files selected for processing (3)
  • extensions/tn_attestation/harness_integration_test.go (7 hunks)
  • tests/streams/attestation/attestation_request_test.go (4 hunks)
  • tests/streams/attestation/test_helpers.go (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
extensions/tn_attestation/harness_integration_test.go (2)
extensions/tn_utils/serialization.go (2)
  • EncodeActionArgs (45-76)
  • EncodeQueryResultCanonical (145-184)
extensions/tn_attestation/canonical.go (2)
  • BuildCanonicalPayload (38-58)
  • ParseCanonicalPayload (63-105)
tests/streams/attestation/attestation_request_test.go (4)
tests/streams/attestation/test_helpers.go (2)
  • TestDataProviderHex (28-28)
  • TestStreamID (27-27)
extensions/tn_utils/serialization.go (1)
  • EncodeQueryResultCanonical (145-184)
extensions/tn_utils/datapoints.go (1)
  • EncodeDataPointsABI (32-64)
extensions/tn_attestation/canonical.go (1)
  • BuildCanonicalPayload (38-58)
🔇 Additional comments (13)
extensions/tn_attestation/harness_integration_test.go (3)

94-96: Comment update addresses prior feedback.

The updated comment accurately describes that the test manually constructs the attestation using BuildCanonicalPayload, rather than claiming to request through the live migration. This resolves the previously flagged discrepancy.


203-206: Canonical payload assertions updated correctly.

The algorithm value of 0 corresponds to secp256k1 (as noted in the comment at line 129), and the DataProvider/StreamID assertions now correctly validate the new canonical payload structure with big-endian encoding.


354-399: Function now fetches by requester (latest attestation).

The signature changed from hash-based lookup to requester-based lookup with ORDER BY created_height DESC, request_tx_id DESC LIMIT 1. This returns the most recent attestation for the requester rather than a specific attestation by hash. For this test harness where only one attestation per requester exists, this is acceptable. The addition of the found flag to verify a row was returned is a good defensive check.

If future tests create multiple attestations per requester and need to retrieve a specific one, consider adding an optional hash parameter or creating a separate hash-based fetch helper.

tests/streams/attestation/test_helpers.go (5)

8-9: LGTM! Imports support hex decoding.

The new imports are used appropriately by the mustHexToBytes helper function.


39-46: LGTM! Hex decoding helper is correct.

The implementation correctly handles the 0x prefix and uses panic for test initialization failures, which is appropriate for fail-fast test setup.


158-159: LGTM! Standardized test constants eliminate magic strings.

Using TestDataProviderHex and TestStreamID constants improves test maintainability and ensures consistency across all attestation tests.

Also applies to: 215-216


243-244: Verify NUMERIC(36,18) precision is intentional.

The NUMERIC(36,18) return type provides 36 total digits with 18 decimal places. While 18 decimals align with Ethereum's wei precision (supporting EVM compatibility per PR objectives), 36 total digits allows values up to ~10^18, which may be excessive. Ensure this precision matches your domain requirements and is documented if it's a deliberate design choice.


27-28: Review comment remains valid but requires developer judgment.

The address collision is confirmed: TestDataProviderHex and the owner in NewTestAddresses() both use "0x0000000000000000000000000000000000000b11". The collision appears intentional (not a typo), while other test addresses (Requester1, Requester2) are distinct.

The concern about potential confusion is architectural rather than a bug: in real attestation systems, owner and data provider are typically different entities. Using identical addresses simplifies tests but may not adequately exercise scenarios where these roles are distinct. No test logic differentiates based on address equality, and no validations require them to be different—the code handles identical addresses without issue.

Developer verification needed: Consider whether using separate addresses (e.g., reusing an existing requester address) better represents production scenarios where owner and data provider are distinct entities.

tests/streams/attestation/attestation_request_test.go (5)

7-7: LGTM! New imports support standardized canonical payload construction.

The imports enable the refactored code to use BuildCanonicalPayload and proper decimal/address handling.

Also applies to: 13-13, 15-15, 19-19


46-47: LGTM! Using standardized test constants.

Referencing TestDataProviderHex and TestStreamID from test helpers ensures consistency across the test suite.


64-70: LGTM! Enhanced type safety and defensive copying.

The explicit length check, type assertions, and defensive copy of the hash bytes improve test robustness and provide clearer error messages.


81-93: Verify hardcoded values match action definition.

The canonical result construction uses:

  • Line 81: Decimal formatting with fixed 18 zeros (assumes integer values)
  • Line 85: Hardcoded timestamp of 1

These should match the test action's return values. From test_helpers.go line 244, the action returns 1 as event_time, which aligns correctly. The decimal format works for integer attestedValue but would fail for fractional values.

Consider adding a comment explaining the decimal format assumption if this pattern is reused elsewhere:

// Construct decimal with 18 decimal places (assumes integer input)
valueDecimal := types.MustParseDecimal(fmt.Sprintf("%d.%018d", attestedValue, 0))

95-105: Excellent refactoring to use standardized BuildCanonicalPayload!

This change replaces the local buildExpectedCanonicalPayload helper with the centralized attestation.BuildCanonicalPayload, which:

  • Uses big-endian length prefixes (per PR objectives)
  • Improves EVM compatibility
  • Reduces code duplication
  • Ensures consistency across the codebase

The parameters are correctly mapped to the standardized function signature.

- Introduced a new test, TestGoldenPayloadFixtureMatches, to validate the canonical payload, signature, and payload hex against a predefined golden fixture.
- Added a new JSON file, attestation_golden.json, containing expected values for canonical payload, signature, and payload hex, along with associated arguments and results.
- Enhanced the test to read the fixture data, encode action arguments, and verify the computed values against the expected results, improving the robustness of attestation tests.

These changes enhance the accuracy and reliability of attestation validation by ensuring consistency with expected outputs.
- Updated the harness integration test to use a new variable, persistedHash, for comparing the stored attestation hash, ensuring accurate validation.
- Enhanced the error message for the hash comparison to provide clearer context in case of failure.

These changes improve the reliability of the attestation tests by ensuring that the correct values are being compared.
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 (7)
extensions/tn_attestation/harness_integration_test.go (7)

104-106: Drop redundant temp var.

Inline requestTxID assignment to avoid an unused/extra variable.

-				expectedTxID := engineCtx.TxContext.TxID
-				requestTxID := expectedTxID
+				requestTxID := engineCtx.TxContext.TxID

123-136: Disambiguate variable names: “rows canonical” vs “payload canonical”.

Rename locals so it’s obvious which bytes represent the row-encoding vs the full canonical payload, reducing mental overhead when reading later assertions and SQL params.

-				resultCanonical, err := tn_utils.EncodeQueryResultCanonical(dispatchRows)
+				rowsCanonical, err := tn_utils.EncodeQueryResultCanonical(dispatchRows)
 				require.NoError(t, err, "encode canonical query result")

 				providerAddr := util.Unsafe_NewEthereumAddressFromString(dataProvider)
-				canonicalBytes := BuildCanonicalPayload(
+				canonicalPayload := BuildCanonicalPayload(
 					1, // version
 					0, // algorithm (secp256k1)
 					uint64(engineCtx.TxContext.BlockContext.Height),
 					providerAddr.Bytes(),
 					[]byte(streamID),
 					uint16(testActionID),
 					argsBytes,
-					resultCanonical,
+					rowsCanonical,
 				)
-					"result_canonical": canonicalBytes,
+					"result_canonical": canonicalPayload,

Also applies to: 173-178


126-136: Replace magic numbers with named constants for version/algorithm.

Use local constants to avoid drift and self-document intent.

Add near the other test constants:

const (
	canonicalVersion   uint8 = 1
	algorithmSecp256k1 uint8 = 0
)

Then apply:

-				canonicalPayload := BuildCanonicalPayload(
-					1, // version
-					0, // algorithm (secp256k1)
+				canonicalPayload := BuildCanonicalPayload(
+					canonicalVersion,
+					algorithmSecp256k1,

138-143: Assert pre-store digest equivalence.

Sanity-check that the computed attestationHash equals the payload’s SigningDigest before persistence.

 				payloadStruct, err := ParseCanonicalPayload(canonicalBytes)
 				require.NoError(t, err, "parse canonical payload for hashing")

 				hashArray := computeAttestationHash(payloadStruct)
 				attestationHash := append([]byte(nil), hashArray[:]...)
+				require.Equal(t, attestationHash, payloadStruct.SigningDigest(), "hash must match signing digest (pre-store)")

185-192: Unnecessary reassign of attestationHash.

After asserting equality, reassigning attestationHash to persistedHash adds no value.

-				require.Equal(t, attestationHash, persistedHash, "returned attestation hash should match stored hash")
-				attestationHash = persistedHash
+				require.Equal(t, attestationHash, persistedHash, "returned attestation hash should match stored hash")

201-206: Strengthen canonical verification: validate + block height.

Add explicit ValidateForEVM and assert the block height to lock the wire format tighter.

 				payload, err := ParseCanonicalPayload(stored.resultCanonical)
 				require.NoError(t, err, "canonical payload should be parseable")
+				require.NoError(t, payload.ValidateForEVM(), "canonical payload must be EVM-valid")
 				require.Equal(t, uint8(1), payload.Version)
 				require.Equal(t, uint8(0), payload.Algorithm)
+				require.Equal(t, uint64(engineCtx.TxContext.BlockContext.Height), payload.BlockHeight)
 				require.Equal(t, providerAddr.Bytes(), payload.DataProvider)
 				require.Equal(t, []byte(streamID), payload.StreamID)

355-377: Clarify helper intent with a doc comment (latest-by-requester).

Add a brief comment so future readers don’t assume this fetches by hash.

+// fetchAttestationRowHarness returns the latest attestation row for a requester,
+// ordered by (created_height DESC, request_tx_id DESC). Intended for single-row
+// workflows in this harness; not a general “fetch by hash” lookup.
 func fetchAttestationRowHarness(t *testing.T, ctx context.Context, platform *kwilTesting.Platform, requester []byte) harnessAttestationRow {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 611ea1a and 42d0033.

📒 Files selected for processing (1)
  • extensions/tn_attestation/harness_integration_test.go (7 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
extensions/tn_attestation/harness_integration_test.go (2)
extensions/tn_utils/serialization.go (2)
  • EncodeActionArgs (45-76)
  • EncodeQueryResultCanonical (145-184)
extensions/tn_attestation/canonical.go (2)
  • BuildCanonicalPayload (38-58)
  • ParseCanonicalPayload (63-105)
⏰ 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 (1)
extensions/tn_attestation/harness_integration_test.go (1)

94-97: Comment fix LGTM.

Updated note now accurately describes the manual canonical construction path used by the test.

@outerlook outerlook requested a review from MicBun October 17, 2025 21:04
Copy link
Member

@MicBun MicBun left a comment

Choose a reason for hiding this comment

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

lgtm

@MicBun MicBun merged commit 766d7e0 into main Oct 17, 2025
6 of 7 checks passed
@MicBun MicBun deleted the chore/enhance-att branch October 17, 2025 21:17
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: Attestation encoding needs better compatibilization

2 participants