> ## Documentation Index
> Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Hardfork.range

> Get hardforks between two versions (inclusive)

<Card title="Try it Live" icon="play" href="https://playground.tevm.sh?example=primitives/hardfork.ts">
  Run Hardfork examples in the interactive playground
</Card>

<Tabs />

## Range Direction

### Forward Range (start \< end)

Returns hardforks in chronological order:

```typescript theme={null}
import { Hardfork, BERLIN, CANCUN } from 'tevm'

const forks = Hardfork.range(BERLIN, CANCUN)
// [BERLIN, LONDON, ARROW_GLACIER, GRAY_GLACIER, MERGE, SHANGHAI, CANCUN]
```

### Reverse Range (start > end)

Returns hardforks in reverse chronological order:

```typescript theme={null}
import { Hardfork, CANCUN, BERLIN } from 'tevm'

const forks = Hardfork.range(CANCUN, BERLIN)
// [CANCUN, SHANGHAI, MERGE, GRAY_GLACIER, ARROW_GLACIER, LONDON, BERLIN]
```

### Single Hardfork (start === end)

Returns array with single element:

```typescript theme={null}
import { Hardfork, LONDON } from 'tevm'

const forks = Hardfork.range(LONDON, LONDON)
// [LONDON]
```

## Usage Patterns

### Upgrade Path

Get hardforks to upgrade through:

```typescript theme={null}
import { Hardfork, BERLIN, CANCUN } from 'tevm'

function getUpgradePath(from: BrandedHardfork, to: BrandedHardfork) {
  const path = Hardfork.range(from, to)
  return path.slice(1)  // Exclude current version
}

const upgrades = getUpgradePath(BERLIN, CANCUN)
// [LONDON, ARROW_GLACIER, GRAY_GLACIER, MERGE, SHANGHAI, CANCUN]

console.log(`Need to upgrade through ${upgrades.length} hardforks`)
```

### Feature Changes

List features introduced in range:

```typescript theme={null}
import { Hardfork, LONDON, CANCUN } from 'tevm'

function listFeatureChanges(start: BrandedHardfork, end: BrandedHardfork) {
  const forks = Hardfork.range(start, end)

  return forks.map(fork => {
    const name = Hardfork.toString(fork)
    const features = []

    if (fork.hasEIP1559() && !start.hasEIP1559()) {
      features.push("EIP-1559 base fee")
    }
    if (fork.hasEIP3855() && !start.hasEIP3855()) {
      features.push("PUSH0 opcode")
    }
    if (fork.hasEIP4844() && !start.hasEIP4844()) {
      features.push("Blob transactions")
    }
    if (fork.isPostMerge() && !start.isPostMerge()) {
      features.push("Proof of Stake")
    }

    return { name, features }
  })
}

const changes = listFeatureChanges(LONDON, CANCUN)
// [
//   { name: "london", features: [] },
//   { name: "arrowglacier", features: [] },
//   { name: "grayglacier", features: [] },
//   { name: "merge", features: ["Proof of Stake"] },
//   { name: "shanghai", features: ["PUSH0 opcode"] },
//   { name: "cancun", features: ["Blob transactions"] }
// ]
```

### Migration Planning

Plan network upgrade:

```typescript theme={null}
import { Hardfork, BERLIN, PRAGUE } from 'tevm'

function planMigration(current: BrandedHardfork, target: BrandedHardfork) {
  if (current.isAtLeast(target)) {
    return { needed: false, message: "Already at target version" }
  }

  const path = Hardfork.range(current, target).slice(1)

  return {
    needed: true,
    steps: path.length,
    hardforks: path.map(Hardfork.toString),
    features: path.map(fork => ({
      name: Hardfork.toString(fork),
      eip1559: fork.hasEIP1559(),
      push0: fork.hasEIP3855(),
      blobs: fork.hasEIP4844(),
      transient: fork.hasEIP1153(),
      pos: fork.isPostMerge()
    }))
  }
}

const plan = planMigration(BERLIN, PRAGUE)
console.log(`Upgrade requires ${plan.steps} steps`)
```

### Version Range Validation

Check if fork is in supported range:

```typescript theme={null}
import { Hardfork, BERLIN, SHANGHAI } from 'tevm'

function isSupportedVersion(fork: BrandedHardfork): boolean {
  const MIN_VERSION = BERLIN
  const MAX_VERSION = SHANGHAI

  const supportedRange = Hardfork.range(MIN_VERSION, MAX_VERSION)
  return supportedRange.includes(fork)
}

isSupportedVersion(LONDON)   // true
isSupportedVersion(CANCUN)   // false
```

### Breaking Changes Detection

Find breaking changes in range:

```typescript theme={null}
import { Hardfork } from 'tevm'

function findBreakingChanges(start: BrandedHardfork, end: BrandedHardfork) {
  const forks = Hardfork.range(start, end)
  const breakingChanges = []

  for (const fork of forks) {
    if (fork.isPostMerge() && !start.isPostMerge()) {
      breakingChanges.push({
        fork: Hardfork.toString(fork),
        change: "DIFFICULTY opcode now returns PREVRANDAO"
      })
    }
  }

  return breakingChanges
}
```

## Network Configuration

Generate network upgrade timeline:

```typescript theme={null}
import { Hardfork, LONDON, OSAKA } from 'tevm'

function generateUpgradeTimeline(from: BrandedHardfork, to: BrandedHardfork) {
  const forks = Hardfork.range(from, to)

  return {
    current: Hardfork.toString(from),
    target: Hardfork.toString(to),
    steps: forks.map((fork, index) => ({
      step: index + 1,
      name: Hardfork.toString(fork),
      isPoS: fork.isPostMerge()
    }))
  }
}
```

## Edge Cases

### Empty Range

When start > end but reverse=false not supported, returns empty or throws:

```typescript theme={null}
import { Hardfork, BERLIN, LONDON } from 'tevm'

// Forward range works
const forward = Hardfork.range(BERLIN, LONDON)  // [BERLIN, LONDON]

// Reverse range also works
const reverse = Hardfork.range(LONDON, BERLIN)  // [LONDON, BERLIN]
```

### Invalid Hardforks

If hardforks don't exist in order, an `InvalidFormatError` is thrown:

```typescript theme={null}
import { Hardfork, LONDON } from 'tevm'
import { InvalidFormatError } from 'tevm/errors'

const invalidFork = "notahardfork" as any

try {
  const range = Hardfork.range(invalidFork, LONDON)
} catch (e) {
  if (e instanceof InvalidFormatError) {
    console.error(e.name)    // "InvalidFormatError"
    console.error(e.code)    // "HARDFORK_INVALID_RANGE"
    console.error(e.value)   // The invalid hardfork value
  }
}
```

## Error Handling

The `range` function throws `InvalidFormatError` when given invalid hardfork values:

| Error Type           | Code                     | When Thrown                                      |
| -------------------- | ------------------------ | ------------------------------------------------ |
| `InvalidFormatError` | `HARDFORK_INVALID_RANGE` | Start or end hardfork is not a valid hardfork ID |

```typescript theme={null}
import { Hardfork, BERLIN } from 'tevm'
import { InvalidFormatError } from 'tevm/errors'

function safeRange(start: string, end: string) {
  try {
    return Hardfork.range(start as any, end as any)
  } catch (e) {
    if (e instanceof InvalidFormatError) {
      console.error(`Invalid hardfork: ${e.value}`)
      return null
    }
    throw e
  }
}
```

## Performance

**Time Complexity:** O(n) where n = range size

**Typical Time:** \~100ns + (50ns × range size)

**Example Ranges:**

* BERLIN → LONDON: 2 hardforks (\~150ns)
* BERLIN → CANCUN: 7 hardforks (\~450ns)
* FRONTIER → OSAKA: 19 hardforks (\~1050ns)

## See Also

* [allIds](/primitives/hardfork/all-ids) - Get all hardforks
* [isAtLeast](/primitives/hardfork/is-at-least) - Check if in range
* [compare](/primitives/hardfork/compare) - Determine range direction
