Plutus.V1.Ledger.Bytes

  • 1. 📜 Overview

  • 2. 🔧 LANGUAGE EXTENSIONS AND IMPORTS

  • 3. 🗄️ Data Structures and Type Synonyms

    • 3.1 🏗️ LedgerBytes (newtype)

  • 4. ⚙️ Functions

    • 4.1 🧩 fromHex

    • 4.2 📦 bytes

    • 4.3 🔙 fromBytes

    • 4.4 🔤 encodeByteString

  • 5. 🤝 Typeclass Instances

  • 6. 📚 Glossary


1 📜 Overview

The Plutus.V1.Ledger.Bytes module provides utilities for working with raw byte sequences in Plutus on-chain and off-chain code:

  • Defines a zero‑cost LedgerBytes wrapper around BuiltinByteString.

  • Parses hexadecimal literals into LedgerBytes.

  • Converts between Haskell ByteString and LedgerBytes.

  • Encodes bytes to hex‐text for display.

  • Derives on-chain serialization instances and pretty printing.

This tutorial breaks down the language pragmas/imports, the newtype, core functions, and key instances, concluding with a glossary.


2 🔧 LANGUAGE EXTENSIONS AND IMPORTS

{-# LANGUAGE DataKinds                  #-}
{-# LANGUAGE DeriveAnyClass             #-}
{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE DerivingStrategies         #-}
{-# LANGUAGE DerivingVia                #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE TemplateHaskell            #-}
{-# LANGUAGE TypeApplications           #-}
{-# OPTIONS_GHC -Wno-orphans            #-}

module Plutus.V1.Ledger.Bytes (
    LedgerBytes(..)
  , fromHex
  , bytes
  , fromBytes
  , encodeByteString
  ) where

import Control.DeepSeq (NFData)
import Data.ByteString qualified as BS
import Data.ByteString.Base16 qualified as Base16
import Data.ByteString.Internal (c2w, w2c)
import Data.Either.Extras (unsafeFromEither)
import Data.String (IsString(..))
import Data.Text qualified as Text
import Data.Text.Encoding qualified as TE
import Data.Word (Word8)
import GHC.Generics (Generic)
import PlutusTx qualified as PlutusTx
import PlutusTx.Lift
import PlutusTx.Prelude qualified as P
import Prettyprinter.Extras (Pretty, PrettyShow(..))
  • LANGUAGE pragmas:

    • DataKinds, DeriveAnyClass, DeriveGeneric, DerivingStrategies, DerivingVia, GeneralizedNewtypeDeriving, FlexibleContexts, FlexibleInstances, OverloadedStrings, TemplateHaskell, TypeApplications

    • -Wno-orphans suppresses warnings for orphan instances.

  • OPTIONS_GHC: no additional warnings for orphan instances.

  • Imports:

    • ByteString and Base16 for raw and hex operations

    • Data.Word for Word8 manipulation

    • PlutusTx, PlutusTx.Lift, and PlutusTx.Prelude for on-chain lifting and byte operations

    • Prettyprinter.Extras for deriving Pretty via PrettyShow


3 🗄️ Data Structures and Type Synonyms

3.1 🏗️ LedgerBytes (newtype)

newtype LedgerBytes = LedgerBytes { getLedgerBytes :: P.BuiltinByteString }
    deriving stock   (Eq, Ord, Generic)
    deriving newtype (P.Eq, P.Ord, PlutusTx.ToData, PlutusTx.FromData, PlutusTx.UnsafeFromData)
    deriving anyclass (NFData)
    deriving Pretty via (PrettyShow LedgerBytes)
  • Inputs: wraps a BuiltinByteString (on-chain type)

  • Derivations:

    • Eq, Ord, Generic via stock

    • newtype deriving for on-chain ToData, FromData, equality

    • NFData for deep evaluation

    • Pretty via generic Show for display

  • Example:

    let lb = LedgerBytes (P.toBuiltin someBS)
    print lb  -- uses PrettyShow to render hex

4 ⚙️ Functions

4.1 🧩 fromHex

fromHex :: BS.ByteString -> Either String LedgerBytes
fromHex = fmap (LedgerBytes . P.toBuiltin) . asBSLiteral
  where
    handleChar c = ...  -- map ascii hex to 0–15
    handlePair c c' = ...
    asBytes = ...
    asBSLiteral = withBytes asBytes
  • Inputs: raw ByteString of hex digits

  • Processing:

    1. Split into pairs of hex “nybbles”

    2. Convert each pair to Word8

    3. Pack into ByteString and wrap

  • Output: Either String LedgerBytes

Example:

fromHex "a6b4" == Right (LedgerBytes <builtin 0xa6b4>)
fromHex "zz" == Left "not a hexit: z"

4.2 📦 bytes

bytes :: LedgerBytes -> BS.ByteString
bytes = P.fromBuiltin . getLedgerBytes
  • Inputs: LedgerBytes

  • Processing: unwrap and convert from BuiltinByteString

  • Output: Haskell ByteString

Example:

bytes lb == originalBS

4.3 🔙 fromBytes

fromBytes :: BS.ByteString -> LedgerBytes
fromBytes = LedgerBytes . P.toBuiltin
  • Inputs/Outputs: zero‐cost conversion to on-chain form

Example:

fromBytes someBS == LedgerBytes (P.toBuiltin someBS)

4.4 🔤 encodeByteString

encodeByteString :: BS.ByteString -> Text.Text
encodeByteString = TE.decodeUtf8 . Base16.encode
  • Inputs: raw ByteString

  • Processing: Base16‐encode then decode to UTF8 text

  • Output: hex Text

Example:

encodeByteString "\x0a\x6b" == "0a6b"

5 🤝 Typeclass Instances

instance IsString LedgerBytes where
  fromString = unsafeFromEither . fromHex . fromString
  • Allows string literals (e.g., "a6b4") to be directly interpreted as LedgerBytes.

instance Show LedgerBytes where
  show = Text.unpack . encodeByteString . bytes
  • Renders LedgerBytes as hex string for debugging and logs.

makeLift ''LedgerBytes
  • Generates on-chain Lift instance for embedding LedgerBytes in PlutusTx code.


6 📚 Glossary

  • BuiltinByteString: Plutus on-chain representation of raw bytes.

  • Word8: 8‐bit unsigned integer.

  • Hexit: a single hexadecimal digit (0–9, a–f).

  • Base16: hex encoding scheme for ByteString.

  • unsafeFromEither: helper to throw on a failed Either.

  • PrettyShow: derives Pretty by using Show implementation.

  • makeLift: Template Haskell for on-chain value lifting.

Last updated