Skip to content

Automate flow-go test#98

Open
tim-barry wants to merge 6 commits into
mainfrom
tim/localnet-integration-test
Open

Automate flow-go test#98
tim-barry wants to merge 6 commits into
mainfrom
tim/localnet-integration-test

Conversation

@tim-barry

@tim-barry tim-barry commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Adds an automated version of the test described in script/README.md. Also includes some minor cleanups, but no changes to the Rosetta server itself.

The test should be run against a localnet running the new flow-go version, to confirm that the existing Rosetta server is compatible with the flow-go upgrade. If the test fails, most likely Rosetta will need to be updated with a new compatibility version (adding a new spork version with appropriate changes to be able to successfully verify new and old blocks).

Summary by CodeRabbit

  • New Features

    • Added an end-to-end localnet compatibility test covering account creation, transfers, indexing, and balance updates.
    • Added a command to run the localnet test suite.
  • Bug Fixes

    • Improved command failure handling when creating derived accounts.
    • Corrected block hash verification for emulator networks.
  • Documentation

    • Updated account creation instructions and documented localnet test prerequisites.
  • Tests

    • Added validation for hash and event processing on the latest spork configuration.

tim-barry and others added 6 commits May 21, 2026 10:26
Encodes the script/README.md localnet validation procedure as a Go
integration test behind the `localnet` build tag, runnable via
`make localnet-test`. It bootstraps and funds an originator, starts the
server against a running localnet, waits for the indexer to reach tip, then
creates a derived account and transfers funds through the construction API —
asserting via the REST API that the server indexes the network and observes
the transfer. Funding renders basic-transfer.cdc through script.Compile (the
template is invalid Cadence as-is, so `make fund-accounts` never worked), and
the indexer fails fast on block-ID mismatches so a stale spork version or a
flow-go incompatibility surfaces immediately.

Verified against a flow-go-master localnet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Opens the possibility of running Rosetta against the flow emulator.
Localnet should be preferred over benchnet anyway.
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a localnet compatibility test and Makefile entry point, centralizes Badger key prefixes, removes emulator chain-ID remapping, and adds mainnet28 spork version 8 hash verification coverage.

Changes

Localnet compatibility test

Layer / File(s) Summary
Localnet test setup and bootstrap
localnettest/*, localnet.json
Adds localnet prerequisites, configuration loading, state reset, account discovery, originator funding, and package documentation.
Rosetta synchronization and transfer validation
localnettest/localnet_test.go
Builds and runs the server, waits for indexer synchronization, performs account and transfer requests, polls balances, and manages process failures and retries.
Localnet workflow integration
Makefile, script/README.md
Adds make localnet-test, makes derived-account creation fail fast, and updates the documented account-creation command.

Index key prefix centralization

Layer / File(s) Summary
Shared prefixes and lookups
indexdb/indexdb.go
Defines shared Badger key prefixes and uses them for account, proxy, balance, and hash/height lookups and iteration.
Index and reset key construction
indexdb/indexdb.go
Applies the shared prefixes to index writes, genesis initialization, reset scans, and related key deletion.

Protocol version 8 hash verification

Layer / File(s) Summary
Chain ID and mainnet28 verification
state/convert.go, state/convert_test.go
Removes emulator-specific chain-ID remapping and adds mainnet28 spork version 8 checks for block, execution-result, and events hashes.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • onflow/rosetta#86: Updates related block-hash verification and protocol version 8 hashing behavior.
  • onflow/rosetta#90: Changes versioned execution-result and chunk handling used by the new spork version 8 tests.

Suggested reviewers: peterargue, ulyanaandrukhiv, jordanschalm

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and related to the main change: adding an automated flow-go test.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tim/localnet-integration-test

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
indexdb/indexdb.go (1)

312-318: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the centralized prefix variables instead of hardcoded byte literals.

Several pre-allocated key construction sites still hardcode single-character byte literals accompanied by a comment, which defeats the purpose of centralizing prefixes in package variables. Reference the 0th index of the centralized prefix variables directly to enforce a single source of truth.

  • indexdb/indexdb.go#L312-L318: Replace key[0] = 'a' with key[0] = accountPrefix[0].
  • indexdb/indexdb.go#L427-L432: Replace key[0] = 'p' with key[0] = isProxyPrefix[0].
  • indexdb/indexdb.go#L444-L450: Replace key[0] = 'a' with key[0] = accountPrefix[0].
  • indexdb/indexdb.go#L701-L715: Replace blockKey[0] = 'b' with blockKey[0] = blockPrefix[0], and hash2HeightKey[0] = 'c' with hash2HeightKey[0] = hash2HeightPrefix[0].
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@indexdb/indexdb.go` around lines 312 - 318, Replace hardcoded key-prefix byte
literals with the centralized prefix variables’ first bytes in Store.HasBalance
and the affected key-construction sites: use accountPrefix[0], isProxyPrefix[0],
accountPrefix[0], blockPrefix[0], and hash2HeightPrefix[0] respectively. Apply
these changes in indexdb/indexdb.go at lines 312-318, 427-432, 444-450, and
701-715, preserving the existing key layouts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@indexdb/indexdb.go`:
- Around line 28-35: Define byte constants for each prefix alongside the
existing prefix slices, then initialize accountPrefix, blockPrefix,
hash2HeightPrefix, height2HashPrefix, and isProxyPrefix from those constants.
Update hardcoded prefix assignments such as key[0] in the relevant code to use
the corresponding constant, while retaining the slices for iterator usage and
avoiding direct append operations on shared global slices.
- Around line 341-345: Eliminate concurrent append operations on shared prefix
slices in indexdb/indexdb.go at lines 341-345, 368-372, 456-462, and 781-789. In
the affected indexdb methods, allocate each key buffer with its exact required
length, copy the prefix and payload into it, and preserve the existing key
contents and ordering; update all listed blockPrefix, hash2HeightPrefix, and
height2HashPrefix constructions, with no direct changes needed beyond these
replacements.

---

Nitpick comments:
In `@indexdb/indexdb.go`:
- Around line 312-318: Replace hardcoded key-prefix byte literals with the
centralized prefix variables’ first bytes in Store.HasBalance and the affected
key-construction sites: use accountPrefix[0], isProxyPrefix[0],
accountPrefix[0], blockPrefix[0], and hash2HeightPrefix[0] respectively. Apply
these changes in indexdb/indexdb.go at lines 312-318, 427-432, 444-450, and
701-715, preserving the existing key layouts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 89881450-9f1d-4cd8-b1fb-b55520350f31

📥 Commits

Reviewing files that changed from the base of the PR and between 6ff2deb and ddac19b.

📒 Files selected for processing (8)
  • Makefile
  • indexdb/indexdb.go
  • localnet.json
  • localnettest/doc.go
  • localnettest/localnet_test.go
  • script/README.md
  • state/convert.go
  • state/convert_test.go
💤 Files with no reviewable changes (1)
  • state/convert.go

Comment thread indexdb/indexdb.go
Comment on lines +28 to +35
var (
accountPrefix = []byte("a")
blockPrefix = []byte("b")
hash2HeightPrefix = []byte("c")
height2HashPrefix = []byte("d")
isProxyPrefix = []byte("p")
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Consider defining byte constants to fix inconsistencies and avoid potential slice-append races.

While centralizing the prefix definitions is a great refactor, defining them solely as global slices creates an unsafe pattern later in the file where append(prefix, ...) is called on them. If the capacity of a global slice happens to be larger than its length, concurrent append calls will write to the same backing array, causing a data race.

Additionally, because accountPrefix is a slice, other areas of the code (like line 315) are still forced to hardcode key[0] = 'a', defeating the purpose of centralizing the prefixes.

Consider defining the exact bytes as constants, and deriving the slices from them for iterators:

const (
	accountPrefixByte     = 'a'
	blockPrefixByte       = 'b'
	hash2HeightPrefixByte = 'c'
	height2HashPrefixByte = 'd'
	isProxyPrefixByte     = 'p'
)

var (
	accountPrefix     = []byte{accountPrefixByte}
	blockPrefix       = []byte{blockPrefixByte}
	hash2HeightPrefix = []byte{hash2HeightPrefixByte}
	height2HashPrefix = []byte{height2HashPrefixByte}
	isProxyPrefix     = []byte{isProxyPrefixByte}
)

This allows the rest of the file to use key[0] = accountPrefixByte safely and cleanly, while avoiding the unsafe append on global slices.


🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Consider defining byte constants to fix inconsistencies and avoid potential slice-append races.

While centralizing the prefix definitions is a great refactor, defining them solely as global slices creates an unsafe pattern later in the file where append(prefix, ...) is called on them. If the capacity of a global slice happens to be larger than its length, concurrent append calls will write to the same backing array, causing a data race.

Additionally, because accountPrefix is a slice, other areas of the code (like line 315) are still forced to hardcode key[0] = 'a', defeating the purpose of centralizing the prefixes.

Consider defining the exact bytes as constants, and deriving the slices from them for iterators:

const (
	accountPrefixByte     = 'a'
	blockPrefixByte       = 'b'
	hash2HeightPrefixByte = 'c'
	height2HashPrefixByte = 'd'
	isProxyPrefixByte     = 'p'
)

var (
	accountPrefix     = []byte{accountPrefixByte}
	blockPrefix       = []byte{blockPrefixByte}
	hash2HeightPrefix = []byte{hash2HeightPrefixByte}
	height2HashPrefix = []byte{height2HashPrefixByte}
	isProxyPrefix     = []byte{isProxyPrefixByte}
)

This allows the rest of the file to use key[0] = accountPrefixByte safely and cleanly, while avoiding the unsafe append on global slices.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@indexdb/indexdb.go` around lines 28 - 35, Define byte constants for each
prefix alongside the existing prefix slices, then initialize accountPrefix,
blockPrefix, hash2HeightPrefix, height2HashPrefix, and isProxyPrefix from those
constants. Update hardcoded prefix assignments such as key[0] in the relevant
code to use the corresponding constant, while retaining the slices for iterator
usage and avoiding direct append operations on shared global slices.

Comment thread indexdb/indexdb.go
Comment on lines 341 to 345
var hash []byte
heightEnc := make([]byte, 8)
binary.BigEndian.PutUint64(heightEnc, height)
key := append([]byte("d"), heightEnc...)
key := append(height2HashPrefix, heightEnc...)
err := s.db.View(func(txn *badger.Txn) error {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Data race hazard: append on global slices.

Using append on a global slice variable is unsafe in concurrent code. If the global slice has any spare capacity (cap > len), concurrent append calls will write over each other in the same backing array, leading to a data race and index corruption. Pre-allocate the target slice and use copy to guarantee thread safety.

  • indexdb/indexdb.go#L341-L345: Replace append(height2HashPrefix, heightEnc...) with a safely pre-allocated slice key := make([]byte, 1+8); key[0] = height2HashPrefix[0]; copy(key[1:], heightEnc).
  • indexdb/indexdb.go#L368-L372: Replace append(hash2HeightPrefix, hash...) with safe pre-allocation and copy().
  • indexdb/indexdb.go#L456-L462: Replace append on blockPrefix, hash2HeightPrefix, and height2HashPrefix with safe pre-allocation and copy().
  • indexdb/indexdb.go#L781-L789: Replace append on blockPrefix, hash2HeightPrefix, and height2HashPrefix with safe pre-allocation and copy().
📍 Affects 1 file
  • indexdb/indexdb.go#L341-L345 (this comment)
  • indexdb/indexdb.go#L368-L372
  • indexdb/indexdb.go#L456-L462
  • indexdb/indexdb.go#L781-L789
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@indexdb/indexdb.go` around lines 341 - 345, Eliminate concurrent append
operations on shared prefix slices in indexdb/indexdb.go at lines 341-345,
368-372, 456-462, and 781-789. In the affected indexdb methods, allocate each
key buffer with its exact required length, copy the prefix and payload into it,
and preserve the existing key contents and ordering; update all listed
blockPrefix, hash2HeightPrefix, and height2HashPrefix constructions, with no
direct changes needed beyond these replacements.

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.

1 participant