Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update CLI to enable Plutus script submission #2798

Merged
merged 2 commits into from
Jun 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions cardano-api/src/Cardano/Api/TxInMode.hs
Original file line number Diff line number Diff line change
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
8 changes: 4 additions & 4 deletions cardano-cli/src/Cardano/CLI/Mary/TxOutParser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@ 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
TxOutAnyEra' addr <$> parseValue

parseAddressAny :: Parser AddressAny
parseAddressAny = do
Expand Down
33 changes: 25 additions & 8 deletions cardano-cli/src/Cardano/CLI/Shelley/Parsers.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1746,14 +1746,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 alonzo: 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
Original file line number Diff line number Diff line change
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
30 changes: 25 additions & 5 deletions cardano-cli/src/Cardano/CLI/Shelley/Run/Transaction.hs
Original file line number Diff line number Diff line change
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 All @@ -47,10 +48,10 @@ import qualified Ouroboros.Network.Protocol.LocalTxSubmission.Client as Net.Tx
import Cardano.CLI.Environment (EnvSocketError, readEnvSocketPath, renderEnvSocketError)
import Cardano.CLI.Run.Friendly (friendlyTxBodyBS)
import Cardano.CLI.Shelley.Key (InputDecodeError, readSigningKeyFileAnyOf)
import Cardano.CLI.Shelley.Script
import Cardano.CLI.Shelley.Parsers
import Cardano.CLI.Shelley.Run.Genesis (ShelleyGenesisCmdError (..), readShelleyGenesis,
renderShelleyGenesisCmdError)
import Cardano.CLI.Shelley.Script
import Cardano.CLI.Types

import qualified System.IO as IO
Expand Down Expand Up @@ -92,6 +93,7 @@ data ShelleyTxCmdError
| ShelleyTxCmdGenesisCmdError !ShelleyGenesisCmdError
| ShelleyTxCmdPolicyIdsMissing [PolicyId]
| ShelleyTxCmdPolicyIdsExcess [PolicyId]
| ShelleyTxCmdDataHashSerializationError Text
deriving Show

data SomeTxBodyError where
Expand Down Expand Up @@ -204,6 +206,8 @@ renderShelleyTxCmdError err =
"A script provided to witness minting does not correspond to the policy \
\id of any asset specified in the \"--mint\" field. The script hash is: "
<> Text.intercalate ", " (map serialiseToRawBytesHexText policyids)
ShelleyTxCmdDataHashSerializationError dHash ->
"Error deserializing datum hash: " <> dHash

renderEra :: AnyCardanoEra -> Text
renderEra (AnyCardanoEra ByronEra) = "Byron"
Expand Down Expand Up @@ -390,10 +394,26 @@ 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 ->
Jimbo4350 marked this conversation as resolved.
Show resolved Hide resolved
left $ ShelleyTxCmdDataHashSerializationError datHashText

toAddressInAnyEra :: AddressAny -> ExceptT ShelleyTxCmdError IO (AddressInEra era)
toAddressInAnyEra addrAny =
Expand Down
21 changes: 19 additions & 2 deletions cardano-cli/src/Cardano/CLI/Types.hs
Original file line number Diff line number Diff line change
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) = TxOutAnyEra addr v

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


data TxOutAnyEra' = TxOutAnyEra'
AddressAny
Value

deriving (Eq, Show)
86 changes: 86 additions & 0 deletions scripts/plutus/example-txin-locking-plutus-script.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/usr/bin/env bash

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

# This script demonstrates how to lock a tx output with a plutus script.
# NB: In this example the Datum must be 42!

# 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 split the utxo
# in order 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

# SUBMIT
cardano-cli transaction submit --tx-file create-datum-output.tx --testnet-magic 42

echo "Pausing for 5 seconds..."
sleep 5

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

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

cardano-cli query utxo --address $utxoaddr --cardano-mode --testnet-magic 42 --out-file utxo.json
txinCollateral=$(jq -r 'keys[]' utxo.json)

echo "Plutus TxIn"
echo $plutusutxotxin

echo "Collateral TxIn"
echo $txinCollateral

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 $txinCollateral \
--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

# SUBMIT alonzo.tx
echo "Manually submit the tx with:"
echo "cardano-cli transaction submit --tx-file alonzo.tx --testnet-magic 42"