| License | Apache-2.0 |
|---|---|
| Safe Haskell | None |
| Language | GHC2021 |
Singular.Registry.Deployment
Description
A runner boots its own registry and publishes its own reference scripts on every run. On a private devnet that is free and right. On a public network it means every run pays to publish the same scripts again and creates a registry nothing else will ever look at — a demonstration of the code rather than of a deployment.
This module is the other half: a deployment manifest recording one registry booted once and one set of reference-script outputs published once, and the means to attach a later run to them. It is the facade the caller imports; the definitions live in the three focused owners behind it — Singular.Registry.Deployment.Manifest for the manifest, its JSON and the paths around it, Singular.Registry.Deployment.Mirror for the proof mirror persisted beside it, and Singular.Registry.Deployment.Attach for the node decisions. See the deployment ownership guide for who owns what and which way the dependencies run.
Three operations:
- record — the
deploycommand writes the manifest after booting and publishing (writeDeployment). - check —
verifyDeploymentasks a node whether it still agrees: every reference output is live and carries the hash the manifest pins, the registry's state output carries the recorded token, and the release in hand compiles to the hashes the manifest was made with. - attach —
attachrebuilds the cage configuration from the manifest and resolves the reference outputs and the state output, so a run uses them instead of creating its own.
What the manifest cannot carry. Writing to a registry — folding a
claim in — means proving the key against the registry's current trie,
and that proof needs the whole trie, not the root the chain reports.
Nothing on chain hands it over in one query, so a deployment carries it
as a file beside the manifest (mirrorPathFor), written by each run
and read by the next.
That file is the deployment's one non-chain dependency: a second machine needs a copy of it to fold, though not to read — proving a name is alive needs the registry entry and the NFT, and no trie at all. Rebuilding the trie from the chain instead, by following the registry token from the bootstrap transaction and replaying each fold's request datums, is the next milestone's work.
That file is a hazard, so it is checked rather than hoped away — by the
caller that attaches, not by attach itself: after attaching, the
retained journey callers compare the loaded mirror's root with the
chain's root, so a mirror that drifted (a run that died mid-fold, a copy
belonging to another deployment) fails by name instead of building
proofs against a trie the chain does not have.
Synopsis
- data Deployment = Deployment {
- depRelease :: Text
- depLeanRevision :: Text
- depNetworkMagic :: Word32
- depSeedOutRef :: Text
- depCageToken :: Text
- depStatePolicy :: Text
- depRequestHash :: Text
- depApplicationHash :: Text
- depRepresentativePolicy :: Text
- depProcessTime :: Integer
- depRetractTime :: Integer
- depTip :: Integer
- depReferenceScripts :: [ReferenceScript]
- depBootstrapTxs :: [Text]
- data ReferenceScript = ReferenceScript {
- refRole :: Text
- refHash :: Text
- refOutRef :: Text
- refAddress :: Text
- refAddressBytes :: Text
- readDeployment :: FilePath -> IO Deployment
- writeDeployment :: FilePath -> Deployment -> IO ()
- deploymentPathFromArgs :: [String] -> Maybe FilePath
- deploymentPathFromEnvironment :: IO (Maybe FilePath)
- data CageParts = CageParts {
- partsStateBytes :: ShortByteString
- partsRequestBytes :: ShortByteString
- partsApplicationPolicy :: ShortByteString
- partsActivePolicy :: ShortByteString
- partsAbsentPolicy :: ShortByteString
- partsTerminalPolicy :: ShortByteString
- partsConsumerScript :: ShortByteString
- cageConfigFor :: Deployment -> CageParts -> Either String CageConfig
- verifyDeployment :: Session NoWitness IO -> Deployment -> CageParts -> IO [String]
- data Attached = Attached {
- attCfg :: CageConfig
- attToken :: TokenId
- attRefUtxos :: [(TxIn, TxOut ConwayEra)]
- attStateUtxo :: (TxIn, TxOut ConwayEra)
- attach :: Session NoWitness IO -> Deployment -> CageParts -> IO Attached
- mirrorPathFor :: FilePath -> FilePath
- loadMirror :: FilePath -> IO (Map TokenId MPFInMemoryDB)
- saveMirror :: FilePath -> Map TokenId MPFInMemoryDB -> IO ()
- replaceDurably :: FilePath -> ByteString -> IO ()
- renderOutRef :: TxIn -> Text
- parseOutRef :: Text -> Either String TxIn
- renderAddrBytes :: Addr -> Text
The manifest
data Deployment Source #
A registry that exists, recorded well enough to find it again and to refuse to use the wrong one.
Constructors
| Deployment | |
Fields
| |
Instances
| FromJSON Deployment Source # | |||||
Defined in Singular.Registry.Deployment.Manifest Methods parseJSON :: Value -> Parser Deployment parseJSONList :: Value -> Parser [Deployment] omittedField :: Maybe Deployment | |||||
| ToJSON Deployment Source # | |||||
Defined in Singular.Registry.Deployment.Manifest Methods toJSON :: Deployment -> Value toEncoding :: Deployment -> Encoding toJSONList :: [Deployment] -> Value toEncodingList :: [Deployment] -> Encoding omitField :: Deployment -> Bool | |||||
| Generic Deployment Source # | |||||
Defined in Singular.Registry.Deployment.Manifest Associated Types
| |||||
| Show Deployment Source # | |||||
Defined in Singular.Registry.Deployment.Manifest Methods showsPrec :: Int -> Deployment -> ShowS Source # show :: Deployment -> String Source # showList :: [Deployment] -> ShowS Source # | |||||
| Eq Deployment Source # | |||||
Defined in Singular.Registry.Deployment.Manifest Methods (==) :: Deployment -> Deployment -> Bool Source # (/=) :: Deployment -> Deployment -> Bool Source # | |||||
| type Rep Deployment Source # | |||||
Defined in Singular.Registry.Deployment.Manifest type Rep Deployment = D1 ('MetaData "Deployment" "Singular.Registry.Deployment.Manifest" "singular-registry-0.1.0.0-Ixhbs5JE28qkUXbRQkkWU" 'False) (C1 ('MetaCons "Deployment" 'PrefixI 'True) (((S1 ('MetaSel ('Just "depRelease") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text) :*: (S1 ('MetaSel ('Just "depLeanRevision") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "depNetworkMagic") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Word32))) :*: ((S1 ('MetaSel ('Just "depSeedOutRef") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "depCageToken") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text)) :*: (S1 ('MetaSel ('Just "depStatePolicy") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "depRequestHash") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text)))) :*: ((S1 ('MetaSel ('Just "depApplicationHash") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text) :*: (S1 ('MetaSel ('Just "depRepresentativePolicy") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "depProcessTime") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Integer))) :*: ((S1 ('MetaSel ('Just "depRetractTime") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Integer) :*: S1 ('MetaSel ('Just "depTip") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Integer)) :*: (S1 ('MetaSel ('Just "depReferenceScripts") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 [ReferenceScript]) :*: S1 ('MetaSel ('Just "depBootstrapTxs") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 [Text])))))) | |||||
data ReferenceScript Source #
One reference-script output: what it carries, where it is, and the hash a node must agree it holds.
Constructors
| ReferenceScript | |
Fields
| |
Instances
| FromJSON ReferenceScript Source # | |||||
Defined in Singular.Registry.Deployment.Manifest Methods parseJSON :: Value -> Parser ReferenceScript parseJSONList :: Value -> Parser [ReferenceScript] omittedField :: Maybe ReferenceScript | |||||
| ToJSON ReferenceScript Source # | |||||
Defined in Singular.Registry.Deployment.Manifest Methods toJSON :: ReferenceScript -> Value toEncoding :: ReferenceScript -> Encoding toJSONList :: [ReferenceScript] -> Value toEncodingList :: [ReferenceScript] -> Encoding omitField :: ReferenceScript -> Bool | |||||
| Generic ReferenceScript Source # | |||||
Defined in Singular.Registry.Deployment.Manifest Associated Types
Methods from :: ReferenceScript -> Rep ReferenceScript x Source # to :: Rep ReferenceScript x -> ReferenceScript Source # | |||||
| Show ReferenceScript Source # | |||||
Defined in Singular.Registry.Deployment.Manifest Methods showsPrec :: Int -> ReferenceScript -> ShowS Source # show :: ReferenceScript -> String Source # showList :: [ReferenceScript] -> ShowS Source # | |||||
| Eq ReferenceScript Source # | |||||
Defined in Singular.Registry.Deployment.Manifest Methods (==) :: ReferenceScript -> ReferenceScript -> Bool Source # (/=) :: ReferenceScript -> ReferenceScript -> Bool Source # | |||||
| type Rep ReferenceScript Source # | |||||
Defined in Singular.Registry.Deployment.Manifest type Rep ReferenceScript = D1 ('MetaData "ReferenceScript" "Singular.Registry.Deployment.Manifest" "singular-registry-0.1.0.0-Ixhbs5JE28qkUXbRQkkWU" 'False) (C1 ('MetaCons "ReferenceScript" 'PrefixI 'True) ((S1 ('MetaSel ('Just "refRole") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "refHash") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text)) :*: (S1 ('MetaSel ('Just "refOutRef") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text) :*: (S1 ('MetaSel ('Just "refAddress") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "refAddressBytes") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text))))) | |||||
readDeployment :: FilePath -> IO Deployment Source #
Read a manifest, naming the file when it will not parse.
writeDeployment :: FilePath -> Deployment -> IO () Source #
Write a manifest, formatted for a person to read in review.
Choosing one
deploymentPathFromArgs :: [String] -> Maybe FilePath Source #
The manifest a command line names, if any. --deployment PATH and
--deployment=PATH are both accepted; absent, the caller keeps its
existing behaviour of booting its own registry.
deploymentPathFromEnvironment :: IO (Maybe FilePath) Source #
deploymentPathFromArgs for this process, falling back to
SINGULAR_DEPLOYMENT.
The release halves the manifest pins only by hash
The compiled bytes a release ships. The manifest records their hashes; the bytes themselves come from the blueprints in hand, so a manifest can never be used to smuggle in a different validator.
Constructors
| CageParts | |
Fields
| |
cageConfigFor :: Deployment -> CageParts -> Either String CageConfig Source #
The cage configuration a manifest describes: this release's compiled scripts, with the seed and the economics the deployment was booted with.
Refuses when the release in hand compiles the state validator to a different hash than the deployment was made with — the manifest then belongs to another release and attaching to it would spend against a registry whose validator this code does not implement.
Checking one against a node
verifyDeployment :: Session NoWitness IO -> Deployment -> CageParts -> IO [String] Source #
Ask a node whether it still agrees with a manifest, and return what it answered, one line per claim.
Every claim is about the chain or about the compiled release, never about the file restating itself: the seed determines the recorded token, this release compiles to the recorded state hash, every recorded reference output is live at its recorded address carrying the hash the manifest pins, and the registry's state output carries the recorded token under the recorded policy. The first claim that fails is raised by name.
Attaching a run to one
What a run gets instead of booting and publishing.
Constructors
| Attached | |
Fields
| |
attach :: Session NoWitness IO -> Deployment -> CageParts -> IO Attached Source #
Attach a run to a recorded deployment: the release, token and
reference/state resolution verifyDeployment performs, plus the
resolved outputs a runner needs in hand. The live state's active policy
and windows are not checked here; verification is the operation that
reads them.
The proof mirror beside the manifest
mirrorPathFor :: FilePath -> FilePath Source #
Where the proof mirror for a manifest lives: the manifest's own
path with a .mirror.json extension, so the two travel together and
neither is guessed from a separate flag.
loadMirror :: FilePath -> IO (Map TokenId MPFInMemoryDB) Source #
Read the mirror beside a manifest. A missing file is the empty mirror, which is what a registry booted a moment ago actually has — the caller that attaches compares the loaded root with the chain's, so an empty mirror against a registry that has grown is refused by that comparison rather than assumed.
saveMirror :: FilePath -> Map TokenId MPFInMemoryDB -> IO () Source #
Write the mirror beside a manifest, replacing what was there whole
or not at all (replaceDurably).
replaceDurably :: FilePath -> ByteString -> IO () Source #
Replace a file whole, durably: the bytes go to a sibling
PATH.partial, synchronised to disk, which is then renamed over PATH,
and the directory is synchronised. A process killed at any point leaves
PATH holding either its previous bytes or the new ones, never a
prefix; a killed replacement may leave the .partial sibling, which the
next replacement overwrites.
Output references
renderOutRef :: TxIn -> Text Source #
txid#index, the spelling every Cardano tool prints.
parseOutRef :: Text -> Either String TxIn Source #
Parse txid#index back, naming what was wrong with it.
renderAddrBytes :: Addr -> Text Source #
An address as the manifest records it: exact bytes, in hex.