at-block

Using the at-block function to evaluate expressions at a specific block in Clarity smart contracts.

Function Signature

(at-block id-block-hash expr)
  • Input:
    • id-block-hash: A 32-byte buffer representing a block hash
    • expr: An expression to be evaluated
  • Output: The result of evaluating expr

Why it matters

The at-block function is crucial for:

  1. Accessing historical contract state at a specific block.
  2. Implementing time-dependent logic based on blockchain state.
  3. Verifying past conditions or values in the contract.
  4. Creating mechanisms that depend on specific blockchain checkpoints.

When to use it

Use the at-block function when you need to:

  • Evaluate contract state or expressions as they were at a specific past block.
  • Implement logic that depends on historical blockchain data.
  • Verify past conditions without relying on stored state.
  • Create time-locked or checkpoint-based features in your contract.

Best Practices

  • Only use at-block when historical data is necessary, as it can be computationally expensive.
  • Ensure the block hash used is from the id-header-hash property, not header-hash.
  • Use read-only expressions within at-block to maintain determinism.
  • Be aware of the potential for chain reorganizations when using recent block hashes.

Practical Example: Historical Price Check

Let's implement a simple function that checks if a price was above a certain threshold at a specific block:

(define-map AssetPrices uint uint)

(define-public (set-price (price uint))
  (ok (map-set AssetPrices block-height price))
)

(define-read-only (was-price-above-at-block (threshold uint) (blockHash (buff 32)))
  (at-block blockHash
    (let
      (
        (pastPrice (default-to u0 (map-get? AssetPrices block-height)))
      )
      (> pastPrice threshold)
    )
  )
)

;; Usage
(set-price u100)
;; ... several blocks later
(was-price-above-at-block u50 0x123456...) ;; Returns true if the price was above 50 at the specified block

This example demonstrates:

  1. Using at-block to evaluate a condition based on historical data.
  2. Combining at-block with map lookups to access past state.
  3. Implementing a read-only function that depends on blockchain history.

Common Pitfalls

  1. Using header-hash instead of id-header-hash, which can lead to inconsistencies across forks.
  2. Attempting to modify state within an at-block expression, which is not allowed.
  3. Overusing at-block, which can lead to performance issues due to the cost of historical lookups.
  • get-block-info?: Used to retrieve information about specific blocks.
  • block-height: Often used in conjunction with at-block for time-based logic.
  • id-header-hash: Provides the correct hash to use with at-block.

Conclusion

The at-block function is a powerful tool for implementing history-dependent logic in Clarity smart contracts. By allowing contracts to evaluate expressions as they would have at a specific past block, it enables sophisticated time-based mechanisms and historical verifications. However, it should be used judiciously due to its potential performance impact and the complexities of working with blockchain history.