From 45bbb5bef011e51695c69e1de0f47cc66f93498a Mon Sep 17 00:00:00 2001 From: Jordan Millar Date: Fri, 30 Apr 2021 10:37:58 +0100 Subject: [PATCH] Update mkfiles.sh to allow immediate hard forking to Alonzo --- .../src/Cardano/CLI/Shelley/Run/Genesis.hs | 50 +++++++++----- .../src/Cardano/Node/Protocol/Alonzo.hs | 65 ++++++++++++++----- .../src/Cardano/Node/Protocol/Cardano.hs | 7 +- .../cardano/shelley_qa-shelley-genesis.json | 2 +- .../burn.sh | 0 .../mint.sh | 0 .../mkfiles.sh | 46 +++++++++---- .../update-1.sh | 0 .../update-2.sh | 0 .../update-3.sh | 0 .../update-4.sh | 0 11 files changed, 120 insertions(+), 50 deletions(-) rename scripts/{byron-to-mary => byron-to-alonzo}/burn.sh (100%) rename scripts/{byron-to-mary => byron-to-alonzo}/mint.sh (100%) rename scripts/{byron-to-mary => byron-to-alonzo}/mkfiles.sh (90%) rename scripts/{byron-to-mary => byron-to-alonzo}/update-1.sh (100%) rename scripts/{byron-to-mary => byron-to-alonzo}/update-2.sh (100%) rename scripts/{byron-to-mary => byron-to-alonzo}/update-3.sh (100%) rename scripts/{byron-to-mary => byron-to-alonzo}/update-4.sh (100%) diff --git a/cardano-cli/src/Cardano/CLI/Shelley/Run/Genesis.hs b/cardano-cli/src/Cardano/CLI/Shelley/Run/Genesis.hs index b4539bce408..a7fff589a7f 100644 --- a/cardano-cli/src/Cardano/CLI/Shelley/Run/Genesis.hs +++ b/cardano-cli/src/Cardano/CLI/Shelley/Run/Genesis.hs @@ -66,13 +66,15 @@ import qualified Cardano.Ledger.Alonzo.Language as Alonzo import qualified Cardano.Ledger.Alonzo.Scripts as Alonzo import qualified Cardano.Ledger.Alonzo.Translation as Alonzo import Cardano.Ledger.Coin (Coin (..)) -import qualified Plutus.V1.Ledger.Api as Plutus -import qualified PlutusCore.Evaluation.Machine.ExBudgeting as Plutus import qualified Shelley.Spec.Ledger.API as Ledger import qualified Shelley.Spec.Ledger.BaseTypes as Ledger import qualified Shelley.Spec.Ledger.Keys as Ledger import qualified Shelley.Spec.Ledger.PParams as Shelley +-- TODO: Remove me, cli should not depend directly on plutus repo. +import qualified PlutusCore.Evaluation.Machine.ExBudgeting as Plutus +import qualified PlutusCore.Evaluation.Machine.ExBudgetingDefaults as Plutus + import Cardano.Ledger.Era () import Cardano.CLI.Helpers (textShow) @@ -963,26 +965,38 @@ readAlonzoGenesis fpath = do createAlonzoGenesis :: AlonzoGenWrapper -> ExceptT ShelleyGenesisCmdError IO Alonzo.AlonzoGenesis -createAlonzoGenesis (AlonzoGenWrapper costModelFp' alonzoGenesis) = do - costModel <- readAndDecode - case Plutus.extractModelParams costModel of - -- TODO: We should not be using functions directly from the plutus repo - -- These should be exposed via the ledger - Just m -> if Plutus.validateCostModelParams m - then left $ ShelleyGenesisCmdCostModelsError costModelFp' - else return $ alonzoGenesis { Alonzo.costmdls = Map.singleton Alonzo.PlutusV1 $ Alonzo.CostModel m } - - Nothing -> panic "" +createAlonzoGenesis (AlonzoGenWrapper costModelFp' alonzoGenesis) = + case costModelFp' of + Just fp -> do + costModel <- readAndDecode fp + case Plutus.extractModelParams costModel of + -- TODO: We should not be using functions directly from the plutus repo + -- These should be exposed via the ledger + Just m -> -- if Plutus.validateCostModelParams m + -- then left $ ShelleyGenesisCmdCostModelsError costModelFp' + -- else + --TODO: Plutus repo needs to expose a cost model validation function + return $ alonzoGenesis { Alonzo.costmdls = Map.singleton Alonzo.PlutusV1 $ Alonzo.CostModel m } + + Nothing -> panic "createAlonzoGenesis: not implemented yet" + Nothing -> + case Plutus.extractModelParams Plutus.defaultCostModel of + Just m -> + if Alonzo.validateCostModelParams m + then return $ alonzoGenesis { Alonzo.costmdls = Map.singleton Alonzo.PlutusV1 $ Alonzo.CostModel m } + else panic "createAlonzoGenesis: Plutus.defaultCostModel is invalid" + + Nothing -> panic "createAlonzoGenesis: Could not extract cost model params from Plutus.defaultCostModel" where - readAndDecode :: ExceptT ShelleyGenesisCmdError IO Plutus.CostModel - readAndDecode = do - lbs <- handleIOExceptT (ShelleyGenesisCmdGenesisFileError . FileIOError costModelFp') $ LBS.readFile costModelFp' - firstExceptT (ShelleyGenesisCmdAesonDecodeError costModelFp' . Text.pack) + readAndDecode :: FilePath -> ExceptT ShelleyGenesisCmdError IO Plutus.CostModel + readAndDecode fp = do + lbs <- handleIOExceptT (ShelleyGenesisCmdGenesisFileError . FileIOError fp) $ LBS.readFile fp + firstExceptT (ShelleyGenesisCmdAesonDecodeError fp . Text.pack) . hoistEither $ Aeson.eitherDecode' lbs data AlonzoGenWrapper = - AlonzoGenWrapper { costModelFp :: FilePath + AlonzoGenWrapper { costModelFp :: Maybe FilePath , genesis :: Alonzo.AlonzoGenesis } @@ -990,7 +1004,7 @@ instance FromJSON AlonzoGenWrapper where parseJSON = withObject "Alonzo Genesis Wrapper" $ \o -> do -- NB: This has an empty map for the cost model alonzoGenensis <- parseJSON (Aeson.Object o) :: Aeson.Parser Alonzo.AlonzoGenesis - cModelFp <- o .: "alonzoCostModel" + cModelFp <- o .:? "costModel" return $ AlonzoGenWrapper { costModelFp = cModelFp , genesis = alonzoGenensis diff --git a/cardano-node/src/Cardano/Node/Protocol/Alonzo.hs b/cardano-node/src/Cardano/Node/Protocol/Alonzo.hs index 578a8065157..b1b78bb3a11 100644 --- a/cardano-node/src/Cardano/Node/Protocol/Alonzo.hs +++ b/cardano-node/src/Cardano/Node/Protocol/Alonzo.hs @@ -4,6 +4,7 @@ module Cardano.Node.Protocol.Alonzo ( AlonzoProtocolInstantiationError(..) + , renderAlonzoProtocolInstantiationError -- * Reusable parts , readAlonzoGenesis ) where @@ -13,7 +14,7 @@ import Cardano.Prelude import Cardano.Api import Control.Monad.Trans.Except.Extra (firstExceptT, handleIOExceptT, hoistEither, left) -import Data.Aeson (FromJSON (..), withObject, (.:)) +import Data.Aeson (FromJSON (..), withObject, (.:?)) import qualified Data.Aeson as Aeson import qualified Data.Aeson.Types as Aeson import qualified Data.ByteString.Lazy as LBS @@ -24,8 +25,10 @@ import System.IO.Error (isDoesNotExistError) import qualified Cardano.Ledger.Alonzo.Language as Alonzo import qualified Cardano.Ledger.Alonzo.Scripts as Alonzo import qualified Cardano.Ledger.Alonzo.Translation as Alonzo -import qualified Plutus.V1.Ledger.Api as Plutus + +-- TODO: Remove me, cli should not depend directly on plutus repo. import qualified PlutusCore.Evaluation.Machine.ExBudgeting as Plutus +import qualified PlutusCore.Evaluation.Machine.ExBudgetingDefaults as Plutus import Cardano.Node.Orphans () @@ -66,24 +69,37 @@ readAlonzoGenesis fpath = do createAlonzoGenesis :: AlonzoGenWrapper -> ExceptT AlonzoProtocolInstantiationError IO Alonzo.AlonzoGenesis -createAlonzoGenesis (AlonzoGenWrapper costModelFp' alonzoGenesis) = do - costModel <- readAndDecode - case Plutus.extractModelParams costModel of - Just m -> if Plutus.validateCostModelParams m - then left $ InvalidCostModelError costModelFp' - else return $ alonzoGenesis { Alonzo.costmdls = Map.singleton Alonzo.PlutusV1 $ Alonzo.CostModel m } - - Nothing -> left CostModelExtractionError -- TODO: costModel +createAlonzoGenesis (AlonzoGenWrapper costModelFp' alonzoGenesis) = + case costModelFp' of + Just fp -> do + costModel <- readAndDecode fp + case Plutus.extractModelParams costModel of + -- TODO: We should not be using functions directly from the plutus repo + -- These should be exposed via the ledger + Just m -> -- if Plutus.validateCostModelParams m + -- then left $ ShelleyGenesisCmdCostModelsError costModelFp' + -- else + --TODO: Plutus repo needs to expose a cost model validation function + return $ alonzoGenesis { Alonzo.costmdls = Map.singleton Alonzo.PlutusV1 $ Alonzo.CostModel m } + + Nothing -> panic "createAlonzoGenesis: not implemented yet" + Nothing -> + case Plutus.extractModelParams Plutus.defaultCostModel of + Just m -> + if Alonzo.validateCostModelParams m + then return $ alonzoGenesis { Alonzo.costmdls = Map.singleton Alonzo.PlutusV1 $ Alonzo.CostModel m } + else panic "createAlonzoGenesis: Plutus.defaultCostModel is invalid" + Nothing -> panic "createAlonzoGenesis: Could not extract cost model params from Plutus.defaultCostModel" where - readAndDecode :: ExceptT AlonzoProtocolInstantiationError IO Plutus.CostModel - readAndDecode = do - lbs <- handleIOExceptT (AlonzoCostModelFileError . FileIOError costModelFp') $ LBS.readFile costModelFp' - firstExceptT (AlonzoCostModelDecodeError costModelFp' . Text.pack) + readAndDecode :: FilePath -> ExceptT AlonzoProtocolInstantiationError IO Plutus.CostModel + readAndDecode fp = do + lbs <- handleIOExceptT (AlonzoCostModelFileError . FileIOError fp) $ LBS.readFile fp + firstExceptT (AlonzoCostModelDecodeError fp . Text.pack) . hoistEither $ Aeson.eitherDecode' lbs data AlonzoGenWrapper = - AlonzoGenWrapper { costModelFp :: FilePath + AlonzoGenWrapper { costModelFp :: Maybe FilePath , genesis :: Alonzo.AlonzoGenesis } @@ -91,7 +107,7 @@ instance FromJSON AlonzoGenWrapper where parseJSON = withObject "Alonzo Genesis Wrapper" $ \o -> do -- NB: This has an empty map for the cost model alonzoGenensis <- parseJSON (Aeson.Object o) :: Aeson.Parser Alonzo.AlonzoGenesis - cModelFp <- o .: "alonzoCostModel" + cModelFp <- o .:? "costModel" return $ AlonzoGenWrapper { costModelFp = cModelFp , genesis = alonzoGenensis @@ -99,7 +115,7 @@ instance FromJSON AlonzoGenWrapper where data AlonzoProtocolInstantiationError = InvalidCostModelError !FilePath - | CostModelExtractionError + | CostModelExtractionError !FilePath | AlonzoCostModelFileError !(FileError ()) | AlonzoCostModelDecodeError !FilePath !Text | AlonzoGenesisFileError !(FileError ()) @@ -107,4 +123,19 @@ data AlonzoProtocolInstantiationError | GenesisFileNotFound !FilePath deriving Show +renderAlonzoProtocolInstantiationError :: AlonzoProtocolInstantiationError -> Text +renderAlonzoProtocolInstantiationError (InvalidCostModelError fp) = + "Invalid cost model: " <> Text.pack (show fp) +renderAlonzoProtocolInstantiationError (CostModelExtractionError fp) = + "Error extracting the cost model at: " <> Text.pack (show fp) +renderAlonzoProtocolInstantiationError (AlonzoCostModelFileError err) = + Text.pack $ displayError err +renderAlonzoProtocolInstantiationError (AlonzoCostModelDecodeError fp err) = + "Error decoding cost model at: " <> Text.pack (show fp) <> " Error: " <> err +renderAlonzoProtocolInstantiationError (AlonzoGenesisFileError err) = + Text.pack $ displayError err +renderAlonzoProtocolInstantiationError (AlonzoGenesisDecodeError fp err) = + "Error decoding genesis at: " <> Text.pack fp <> " Error: " <> err +renderAlonzoProtocolInstantiationError (GenesisFileNotFound fp) = + "Genesis file not found at: " <> Text.pack fp diff --git a/cardano-node/src/Cardano/Node/Protocol/Cardano.hs b/cardano-node/src/Cardano/Node/Protocol/Cardano.hs index baa5ddf0206..0e8a60eebc6 100644 --- a/cardano-node/src/Cardano/Node/Protocol/Cardano.hs +++ b/cardano-node/src/Cardano/Node/Protocol/Cardano.hs @@ -36,7 +36,8 @@ import Cardano.Node.Types import Cardano.Tracing.OrphanInstances.Byron () import Cardano.Tracing.OrphanInstances.Shelley () -import Cardano.Node.Protocol.Alonzo (AlonzoProtocolInstantiationError, readAlonzoGenesis) +import Cardano.Node.Protocol.Alonzo (AlonzoProtocolInstantiationError, readAlonzoGenesis, + renderAlonzoProtocolInstantiationError) import qualified Cardano.Node.Protocol.Byron as Byron import qualified Cardano.Node.Protocol.Shelley as Shelley @@ -268,5 +269,5 @@ renderCardanoProtocolInstantiationError Shelley.renderShelleyProtocolInstantiationError err renderCardanoProtocolInstantiationError - (CardanoProtocolInstantiationErrorAlonzo _) = - error "TODO: renderCardanoProtocolInstantiationError CardanoProtocolInstantiationErrorAlonzo" + (CardanoProtocolInstantiationErrorAlonzo err) = + renderAlonzoProtocolInstantiationError err diff --git a/configuration/cardano/shelley_qa-shelley-genesis.json b/configuration/cardano/shelley_qa-shelley-genesis.json index fcf7db31fef..2dd3bcb5bf3 100644 --- a/configuration/cardano/shelley_qa-shelley-genesis.json +++ b/configuration/cardano/shelley_qa-shelley-genesis.json @@ -54,7 +54,7 @@ "executionPrices": 42, "maxTxExUnits": 42, "maxBlockExUnits": 42, - "maxMultiAssetSize": 42, + "maxValueSize": 42, "costModel": "configuration/cardano/alonzo/shelley_qa_cost-model.json" } \ No newline at end of file diff --git a/scripts/byron-to-mary/burn.sh b/scripts/byron-to-alonzo/burn.sh similarity index 100% rename from scripts/byron-to-mary/burn.sh rename to scripts/byron-to-alonzo/burn.sh diff --git a/scripts/byron-to-mary/mint.sh b/scripts/byron-to-alonzo/mint.sh similarity index 100% rename from scripts/byron-to-mary/mint.sh rename to scripts/byron-to-alonzo/mint.sh diff --git a/scripts/byron-to-mary/mkfiles.sh b/scripts/byron-to-alonzo/mkfiles.sh similarity index 90% rename from scripts/byron-to-mary/mkfiles.sh rename to scripts/byron-to-alonzo/mkfiles.sh index a9c11f4c028..8d92215d2f6 100755 --- a/scripts/byron-to-mary/mkfiles.sh +++ b/scripts/byron-to-alonzo/mkfiles.sh @@ -1,7 +1,11 @@ #!/usr/bin/env bash set -e -#set -x +# Unoffiical bash strict mode. +# See: http://redsymbol.net/articles/unofficial-bash-strict-mode/ +set -u +set -o pipefail + # This script sets up a cluster that starts out in Byron, and can transition to Mary. # @@ -97,7 +101,7 @@ pushd ${ROOT} # create the node directories for NODE in ${ALL_NODES}; do - mkdir ${NODE} ${NODE}/byron ${NODE}/shelley + mkdir "${NODE}" "${NODE}/byron" "${NODE}/shelley" done @@ -186,7 +190,7 @@ EOF cardano-cli byron genesis genesis \ --protocol-magic ${NETWORK_MAGIC} \ - --start-time ${START_TIME} \ + --start-time "${START_TIME}" \ --k ${SECURITY_PARAM} \ --n-poor-addresses 0 \ --n-delegate-addresses ${NUM_BFT_NODES} \ @@ -202,8 +206,8 @@ mv byron.genesis.spec.json byron/genesis.spec.json # Symlink the BFT operator keys from the genesis delegates, for uniformity for N in ${BFT_NODES_N}; do - ln -s ../../byron/delegate-keys.00$((${N} - 1)).key node-bft${N}/byron/delegate.key - ln -s ../../byron/delegation-cert.00$((${N} - 1)).json node-bft${N}/byron/delegate.cert + ln -s ../../byron/delegate-keys.00$((${N} - 1)).key "node-bft${N}/byron/delegate.key" + ln -s ../../byron/delegation-cert.00$((${N} - 1)).json "node-bft${N}/byron/delegate.cert" done @@ -227,7 +231,7 @@ for N in ${BFT_NODES_N}; do --testnet-magic 42 \ --tx tx$((${N} - 1)).tx \ --wallet-key byron/delegate-keys.00$((${N} - 1)).key \ - --rich-addr-from $(head -n 1 byron/genesis-address-00$((${N} - 1))) \ + --rich-addr-from "$(head -n 1 byron/genesis-address-00$((${N} - 1)))" \ --txout "(\"$(head -n 1 byron/address-00$((${N} - 1)))\", $FUNDS_PER_BYRON_ADDRESS)" done @@ -502,21 +506,21 @@ echo echo "In order to do the protocol updates, proceed as follows:" echo echo " 0. wait for the nodes to start producing blocks" -echo " 1. invoke ./scripts/byron-to-mary/update-1.sh" +echo " 1. invoke ./scripts/byron-to-alonzo/update-1.sh" echo " wait for the next epoch for the update to take effect" echo -echo " 2. invoke ./scripts/byron-to-mary/update-2.sh" +echo " 2. invoke ./scripts/byron-to-alonzo/update-2.sh" echo " 3. restart the nodes" echo " wait for the next epoch for the update to take effect" echo -echo " 4. invoke ./scripts/byron-to-mary/update-3.sh " +echo " 4. invoke ./scripts/byron-to-alonzo/update-3.sh " echo " Here, the current epoch (2 if you're quick)." echo " If you provide the wrong epoch, you will see an error" echo " that will tell you the current epoch, and can run" echo " the script again." echo " 5. restart the nodes" echo " wait for the next epoch for the update to take effect" -echo " 6. invoke ./scripts/byron-to-mary/update-4.sh " +echo " 6. invoke ./scripts/byron-to-alonzo/update-4.sh " echo " 7. restart the nodes" echo echo "You can observe the status of the updates by grepping the logs, via" @@ -545,7 +549,27 @@ popd # For an automatic transition at epoch 0, specifying mary, allegra or shelley # will start the node in the appropriate era. echo "" -if [ "$1" = "mary" ]; then +if [ "$1" = "alonzo" ]; then + echo "TestShelleyHardForkAtEpoch: 0" >> ${ROOT}/configuration.yaml + echo "TestAllegraHardForkAtEpoch: 0" >> ${ROOT}/configuration.yaml + echo "TestMaryHardForkAtEpoch: 0" >> ${ROOT}/configuration.yaml + echo "TestAlonzoHardForkAtEpoch: 0" >> ${ROOT}/configuration.yaml + echo "TestEnableDevelopmentHardForkEras: True" >> ${ROOT}/configuration.yaml + echo "TestEnableDevelopmentNetworkProtocols: True" >> ${ROOT}/configuration.yaml + + sed -i ${ROOT}/configuration.yaml \ + -e 's/LastKnownBlockVersion-Major: 1/LastKnownBlockVersion-Major: 5/' + + # Update shelley genesis with required Alonzo fields. + alonzogenesisparams='.+ {adaPerUTxOWord: 0, executionPrices: {prMem: 1, prSteps: 1}, maxTxExUnits: {exUnitsMem: 1, exUnitsSteps: 1}, maxBlockExUnits: {exUnitsMem: 1, exUnitsSteps: 1}, maxValueSize: 1000, costModel: "example/shelley/alonzo/costmodel.json", collateralPercentage: 100, maxCollateralInputs: 1}' + alonzogenesis=$(jq "${alonzogenesisparams}" < ${ROOT}/shelley/genesis.json) + echo "${alonzogenesis}" > ${ROOT}/shelley/genesis.json + # Copy the cost model + mkdir ${ROOT}/shelley/alonzo + cp configuration/cardano/alonzo/shelley_qa_cost-model.json ${ROOT}/shelley/alonzo/costmodel.json + echo "Nodes will start in Alonzo era from epoch 0" + +elif [ "$1" = "mary" ]; then echo "TestShelleyHardForkAtEpoch: 0" >> ${ROOT}/configuration.yaml echo "TestAllegraHardForkAtEpoch: 0" >> ${ROOT}/configuration.yaml echo "TestMaryHardForkAtEpoch: 0" >> ${ROOT}/configuration.yaml diff --git a/scripts/byron-to-mary/update-1.sh b/scripts/byron-to-alonzo/update-1.sh similarity index 100% rename from scripts/byron-to-mary/update-1.sh rename to scripts/byron-to-alonzo/update-1.sh diff --git a/scripts/byron-to-mary/update-2.sh b/scripts/byron-to-alonzo/update-2.sh similarity index 100% rename from scripts/byron-to-mary/update-2.sh rename to scripts/byron-to-alonzo/update-2.sh diff --git a/scripts/byron-to-mary/update-3.sh b/scripts/byron-to-alonzo/update-3.sh similarity index 100% rename from scripts/byron-to-mary/update-3.sh rename to scripts/byron-to-alonzo/update-3.sh diff --git a/scripts/byron-to-mary/update-4.sh b/scripts/byron-to-alonzo/update-4.sh similarity index 100% rename from scripts/byron-to-mary/update-4.sh rename to scripts/byron-to-alonzo/update-4.sh