Skip to content

Commit

Permalink
Update CLI in order to allow tx outs with datum hashes and other fixe…
Browse files Browse the repository at this point in the history
…s to

enable Plutus script submission
  • Loading branch information
Jimbo4350 committed Jun 8, 2021
1 parent 1038002 commit a77cc9a
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 28 deletions.
4 changes: 2 additions & 2 deletions cabal.project
Expand Up @@ -11,8 +11,8 @@ packages:
cardano-submit-api
nix/workbench/cardano-topology

package cardano-api
ghc-options: -Werror
--package cardano-api
-- ghc-options: -Werror

package cardano-cli
ghc-options: -Werror
Expand Down
5 changes: 3 additions & 2 deletions cardano-api/src/Cardano/Api/ProtocolParameters.hs
Expand Up @@ -301,8 +301,8 @@ instance FromJSON ProtocolParameters where
<*> o .:? "utxoCostPerWord"
<*> o .:? "costModel" .!= Map.empty
<*> o .:? "executionUnitPrices"
<*> o .:? "maxTxExecUnits"
<*> o .:? "maxBlockExecUnits"
<*> o .:? "maxTxExecutionUnits"
<*> o .:? "maxBlockExecutionUnits"
<*> o .:? "maxValueSize"
<*> o .:? "collateralPercentage"
<*> o .:? "maxCollateralInputs"
Expand Down Expand Up @@ -333,6 +333,7 @@ instance ToJSON ProtocolParameters where
, "txFeeFixed" .= protocolParamTxFeeFixed
, "txFeePerByte" .= protocolParamTxFeePerByte
-- Alonzo era:
, "utxoCostPerWord" .= protocolParamUTxOCostPerWord
, "costModels" .= protocolParamCostModels
, "executionUnitPrices" .= protocolParamPrices
, "maxTxExecutionUnits" .= protocolParamMaxTxExUnits
Expand Down
6 changes: 6 additions & 0 deletions cardano-api/src/Cardano/Api/ScriptData.hs
Expand Up @@ -27,6 +27,7 @@ module Cardano.Api.ScriptData (
-- * Data family instances
AsType(..),
Hash(..),
hashScriptData,
) where

import Prelude
Expand Down Expand Up @@ -60,6 +61,7 @@ import qualified Cardano.Crypto.Hash.Class as Crypto
import qualified Cardano.Ledger.SafeHash as Ledger
import Ouroboros.Consensus.Shelley.Eras (StandardCrypto)
import qualified Cardano.Ledger.Alonzo.Data as Alonzo
import qualified Cardano.Ledger.Alonzo as Alonzo
import qualified Plutus.V1.Ledger.Api as Plutus

import Cardano.Api.Eras
Expand Down Expand Up @@ -113,6 +115,10 @@ instance ToJSON (Hash ScriptData) where
instance Aeson.ToJSONKey (Hash ScriptData) where
toJSONKey = Aeson.toJSONKeyText serialiseToRawBytesHexText

hashScriptData :: ScriptData -> Hash ScriptData
hashScriptData sd =
let aData = toAlonzoData sd :: Alonzo.Data (Alonzo.AlonzoEra StandardCrypto)
in ScriptDataHash $ Alonzo.hashData aData

-- ----------------------------------------------------------------------------
-- Conversion functions
Expand Down
5 changes: 2 additions & 3 deletions cardano-api/src/Cardano/Api/TxInMode.hs
Expand Up @@ -102,11 +102,10 @@ toConsensusGenTx (TxInMode (ShelleyTx _ tx) MaryEraInCardanoMode) =
where
tx' = Consensus.mkShelleyTx tx

toConsensusGenTx (TxInMode (ShelleyTx _ _tx) AlonzoEraInCardanoMode) =
toConsensusGenTx (TxInMode (ShelleyTx _ tx) AlonzoEraInCardanoMode) =
Consensus.HardForkGenTx (Consensus.OneEraGenTx (S (S (S (S (Z tx'))))))
where
tx' = error "toConsensusGenTx: Alonzo not implemented yet"
-- Consensus needs to expose a function that can make create Alonzo txs
tx' = Consensus.mkShelleyTx tx



Expand Down
9 changes: 5 additions & 4 deletions cardano-cli/src/Cardano/CLI/Mary/TxOutParser.hs
Expand Up @@ -7,25 +7,26 @@ import Prelude
import Data.Char (isAsciiLower, isAsciiUpper, isDigit)
import Data.Text (Text)
import qualified Data.Text as Text
import Control.Applicative

import Control.Applicative (some)
import Text.Parsec (option, satisfy, (<?>))
import Text.Parsec.Char (char, spaces)
import Text.Parsec.String (Parser)

import Cardano.Api (AddressAny (..), AsType (..), deserialiseAddress)
import Cardano.CLI.Mary.ValueParser (parseValue)
import Cardano.CLI.Types (TxOutAnyEra (..))
import Cardano.CLI.Types (TxOutAnyEra' (..))


parseTxOutAnyEra :: Parser TxOutAnyEra
parseTxOutAnyEra :: Parser TxOutAnyEra'
parseTxOutAnyEra = do
addr <- parseAddressAny
spaces
-- Accept the old style of separating the address and value in a
-- transaction output:
option () (char '+' >> spaces)
TxOutAnyEra addr <$> parseValue
val <- parseValue
return $ TxOutAnyEra' addr val

parseAddressAny :: Parser AddressAny
parseAddressAny = do
Expand Down
33 changes: 25 additions & 8 deletions cardano-cli/src/Cardano/CLI/Shelley/Parsers.hs
Expand Up @@ -1730,14 +1730,31 @@ parseTxIx = toEnum <$> Atto.decimal

pTxOut :: Parser TxOutAnyEra
pTxOut =
Opt.option (readerFromParsecParser parseTxOutAnyEra)
( Opt.long "tx-out"
<> Opt.metavar "TX-OUT"
-- TODO: Update the help text to describe the new syntax as well.
<> Opt.help "The transaction output as Address+Lovelace where Address is \
\the Bech32-encoded address followed by the amount in \
\Lovelace."
)
toTxOutanyEra
<$> Opt.option (readerFromParsecParser parseTxOutAnyEra)
( Opt.long "tx-out"
<> Opt.metavar "TX-OUT"
-- TODO: Update the help text to describe the new syntax as well.
<> Opt.help "The transaction output as Address+Lovelace where Address is \
\the Bech32-encoded address followed by the amount in \
\Lovelace."
)
<*> optional pDatumHash


pDatumHash :: Parser Text
pDatumHash =
Opt.option (readerFromAttoParser parseHex)
( Opt.long "datum-hash"
<> Opt.metavar "HASH"
<> Opt.help "Required datum hash for tx inputs intended \
\to be utilizied by a Plutus script."
)

parseHex :: Atto.Parser Text
parseHex =
Text.decodeUtf8 <$> Atto.takeWhile1 Char.isHexDigit


pMultiAsset :: Parser Value
pMultiAsset =
Expand Down
6 changes: 3 additions & 3 deletions cardano-cli/src/Cardano/CLI/Shelley/Run/Query.hs
Expand Up @@ -199,7 +199,7 @@ runQueryTip (AnyConsensusModeParams cModeParams) network mOutFile = do
case mOutFile of
Just (OutputFile fpath) -> liftIO $ LBS.writeFile fpath output
Nothing -> liftIO $ LBS.putStrLn output

where
tuple3Fst :: (a, b, c) -> a
tuple3Fst (a, _, _) = a
Expand Down Expand Up @@ -623,12 +623,12 @@ printUtxo shelleyBasedEra' txInOutTuple =
, " " <> printableValue value
]
ShelleyBasedEraAlonzo ->
let (TxIn (TxId txhash) (TxIx index), TxOut _ value _) = txInOutTuple
let (TxIn (TxId txhash) (TxIx index), TxOut _ value mDatum) = txInOutTuple
in Text.putStrLn $
mconcat
[ Text.decodeLatin1 (hashToBytesAsHex txhash)
, textShowN 6 index
, " " <> printableValue value
, " " <> printableValue value <> " + " <> Text.pack (show mDatum)
]
where
textShowN :: Show a => Int -> a -> Text
Expand Down
28 changes: 24 additions & 4 deletions cardano-cli/src/Cardano/CLI/Shelley/Run/Transaction.hs
Expand Up @@ -21,6 +21,7 @@ import qualified Data.ByteString.Lazy.Char8 as LBS
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import Data.Type.Equality (TestEquality (..))

import Control.Monad.Trans.Except.Extra (firstExceptT, handleIOExceptT, hoistEither,
Expand Down Expand Up @@ -390,10 +391,29 @@ validateTxOuts era = mapM toTxOutInAnyEra
where
toTxOutInAnyEra :: TxOutAnyEra
-> ExceptT ShelleyTxCmdError IO (TxOut era)
toTxOutInAnyEra (TxOutAnyEra addr val) = TxOut <$> toAddressInAnyEra addr
<*> toTxOutValueInAnyEra val
<*> pure TxOutDatumHashNone
-- TODO alonzo ^^ allow tx out data
toTxOutInAnyEra (TxOutAnyEra addr val mDatumHash) =
case scriptDataSupportedInEra era of
Nothing ->
TxOut <$> toAddressInAnyEra addr
<*> toTxOutValueInAnyEra val
<*> pure TxOutDatumHashNone
Just supported ->
case mDatumHash of
Nothing ->
TxOut <$> toAddressInAnyEra addr
<*> toTxOutValueInAnyEra val
<*> pure TxOutDatumHashNone
Just datHashText ->
case deserialiseFromRawBytesHex (AsHash AsScriptData) (Text.encodeUtf8 datHashText) of
Just sDataHash ->
TxOut <$> toAddressInAnyEra addr
<*> toTxOutValueInAnyEra val
<*> pure (TxOutDatumHash supported sDataHash)
Nothing ->
TxOut <$> toAddressInAnyEra addr
<*> toTxOutValueInAnyEra val
<*> pure TxOutDatumHashNone


toAddressInAnyEra :: AddressAny -> ExceptT ShelleyTxCmdError IO (AddressInEra era)
toAddressInAnyEra addrAny =
Expand Down
21 changes: 19 additions & 2 deletions cardano-cli/src/Cardano/CLI/Types.hs
Expand Up @@ -19,10 +19,12 @@ module Cardano.CLI.Types
, ScriptDatumOrFile (..)
, TransferDirection(..)
, TxOutAnyEra (..)
, TxOutAnyEra' (..)
, UpdateProposalFile (..)
, VerificationKeyFile (..)
, Stakes (..)
, Params (..)
, toTxOutanyEra
) where

import Cardano.Prelude
Expand Down Expand Up @@ -193,6 +195,21 @@ data TransferDirection = TransferToReserves | TransferToTreasury
-- values passed on the command line. It can be converted into the
-- era-dependent 'TxOutValue' type.
--
data TxOutAnyEra = TxOutAnyEra AddressAny Value
-- TODO alonzo: ^^ add support for tx out data


toTxOutanyEra :: TxOutAnyEra' -> Maybe Text -> TxOutAnyEra
toTxOutanyEra (TxOutAnyEra' addr v) mHash = TxOutAnyEra addr v mHash

data TxOutAnyEra = TxOutAnyEra
AddressAny
Value
-- Datum hash
(Maybe Text)
deriving (Eq, Show)


data TxOutAnyEra' = TxOutAnyEra'
AddressAny
Value

deriving (Eq, Show)
80 changes: 80 additions & 0 deletions scripts/plutus/example-txin-locking-plutus-script.sh
@@ -0,0 +1,80 @@
#!/usr/bin/env bash

set -e
# Unoffiical bash strict mode.
# See: http://redsymbol.net/articles/unofficial-bash-strict-mode/
set -u
set -o pipefail

# cardano-cli address build --payment-script-file scripts/plutus/always-succeeds-txin.plutus --testnet-magic 42
# Always succeeding PLUTUS SCRIPT ADDRESS - addr_test1wzpu87f5k52qvua9wn6gncg0m6hle4w86w5c4m9ryk6dxmsrw7evr

#UTXOADDR=$(cardano-cli address build --testnet-magic 42 --payment-verification-key-file example/shelley/utxo-keys/utxo1.vkey)

#TXIN=$(cardano-cli transaction txid --tx-body-file tx3.txbody)#

#cardano-cli query protocol-parameters --testnet-magic 42 --out-file example/pparams.json

# This script demonstrates how to lock a txin with a plutus script. NB: In this example any datum will succeed

# Step 1: Create a tx ouput with a datum hash at the script address. In order for a tx ouput to be locked
# by a plutus script, it must have a datahash.
# We also need collateral tx inputs so we splut the utxo as well to accomodate this.

plutusscriptaddr=$(cardano-cli address build --payment-script-file scripts/plutus/always-succeeds-txin.plutus --testnet-magic 42)

utxovkey=example/shelley/utxo-keys/utxo1.vkey
utxoskey=example/shelley/utxo-keys/utxo1.skey

utxoaddr=$(cardano-cli address build --testnet-magic 42 --payment-verification-key-file $utxovkey)

utxo=$(cardano-cli query utxo --address $utxoaddr --cardano-mode --testnet-magic 42 --out-file utxo.json)

txin=$(jq -r 'keys[]' utxo.json)

cardano-cli transaction build-raw \
--alonzo-era \
--fee 0 \
--tx-in $txin \
--tx-out $plutusscriptaddr+500000000 --datum-hash 9e1199a988ba72ffd6e9c269cadb3b53b5f360ff99f112d9b2ee30c4d74ad88b \
--tx-out $utxoaddr+500000000 \
--out-file create-datum-output.body

cardano-cli transaction sign \
--tx-body-file create-datum-output.body \
--testnet-magic 42 \
--signing-key-file $utxoskey\
--out-file create-datum-output.tx

# Step 2
# After "locking" our tx output at the script address, we can now can attempt to spend
# the "locked" tx output below.

plutusutxo=$(cardano-cli query utxo --address $plutusscriptaddr --testnet-magic 42 --out-file plutusutxo.json)
plutusutxotxin=$(jq -r 'keys[]' plutusutxo.json)

cardano-cli query protocol-parameters --testnet-magic 42 --out-file example/pparams.json

cardano-cli transaction build-raw \
--alonzo-era \
--fee 0 \
--tx-in $plutusutxotxin \
--tx-in-collateral $txin \
--tx-out $utxoaddr+500000000 \
--txin-script-file ./scripts/plutus/always-succeeds-txin.plutus \
--datum-value 42 \
--protocol-params-file example/pparams.json\
--redeemer-value 42 \
--execution-units "(0,0)" \
--out-file test-alonzo.body

cardano-cli transaction sign \
--tx-body-file test-alonzo.body \
--testnet-magic 42 \
--signing-key-file example/shelley/utxo-keys/utxo1.skey \
--out-file alonzo.tx
#
# cardano-cli transaction submit --tx-file alonzo.tx --testnet-magic 42
#
#
#> cabal exec cardano-cli -- query utxo --address addr_test1vrnzmw3tcq6llyh79tu7ym86p2gfhj47ap0wqcwkweqpnaq0r6yg4 --cardano-mode --testnet-magic 42

0 comments on commit a77cc9a

Please sign in to comment.