Skip to content

Commit

Permalink
ledger: generalize the fee field to Value
Browse files Browse the repository at this point in the history
Fixes #1515.

I think this costs us little, and it avoids having to have a central
notion of a native currency.
  • Loading branch information
michaelpj committed Oct 17, 2019
1 parent 0d76e98 commit fdbb7a9
Show file tree
Hide file tree
Showing 20 changed files with 101 additions and 111 deletions.
75 changes: 28 additions & 47 deletions extended-utxo-spec/extended-utxo-specification.tex
Expand Up @@ -137,7 +137,6 @@
\newcommand{\currency}{\ensuremath{\s{CurrencyId}}}
\newcommand{\nativeCur}{\ensuremath{\mathrm{nativeC}}}
\newcommand{\nativeTok}{\ensuremath{\mathrm{nativeT}}}
\newcommand{\injectNative}{\ensuremath{\mathrm{inject}}}

\newcommand{\qtymap}{\ensuremath{\s{Quantities}}}

Expand Down Expand Up @@ -702,16 +701,11 @@ \section{EUTXO-2: multicurrency support and non-fungible tokens}
\label{sec:eutxo-2}
We now extend the EUTXO-1 model further by introducing features which
allow, among other things, the implementation of new currencies and
\textit{non-fungible tokens} (NFTs). We assume that the underlying
blockchain has a unique \textit{native currency} which is the
fundamental currency used for paying fees, for example. The native
currency of the Cardano blockchain is Ada.
\textit{non-fungible tokens} (NFTs).

\paragraph{Custom currencies.} In addition to the native currency, the
EUTXO-2 model allows an unlimited number of other \textit{custom
currencies}, possibly user-defined. Each custom currency has a
unique identifier; the native currency is handled separately and has
no identifier.
\paragraph{Multiple currencies.} The EUTXO-2 model allows an unlimited
number of \textit{currencies}. Each custom currency has a
unique identifier.

\todokwxm{We may wish to implement a DEX to enable exchange of custom
currencies. This is a little problematic in Ethereum because the
Expand Down Expand Up @@ -749,9 +743,7 @@ \subsection{The definition of EUTXO-2}
\begin{array}{rll}
\multicolumn{3}{l}{\textsc{Ledger primitives}}\\
\currency && \mbox{an identifier for a custom currency}\\
\nativeCur && \mbox{a distinguished \currency{} representing the native currency of the ledger}\\
\token && \mbox{a type consisting of identifiers for individual tokens}\\
\nativeTok && \mbox{a distinguished \token{} representing the currency token of the native currency}\\
\\
\multicolumn{3}{l}{\textsc{Defined types}}\\
\qtymap &=& \FinSup{\currency}{\FinSup{\token}{\qty}}\\
Expand All @@ -769,7 +761,7 @@ \subsection{The definition of EUTXO-2}
\eutxotx_2 &=&(\inputs: \FinSet{\s{Input}_2},\\
& &\ \outputs: \List{\s{Output}_2},\\
& &\ \i{validityInterval}: \Interval{\extended{\slotnum}},\\
& &\ \fee: \qty,\\
& &\ \fee: \qtymap,\\
& &\ \forge: \qtymap)\\
\\
\s{Ledger}_2 &=&\!\List{\eutxotx_2}\\
Expand All @@ -783,12 +775,16 @@ \subsubsection{Remarks}
\paragraph{ETUXO-2 on Cardano.}
The Cardano implementation of EUTXO-2 uses the primitives given in
Fig.~\ref{fig:eutxo-2-types-cardano}.

Cardano also defines an \emph{native currency} and \emph{native currency token}.
This allows defining a native currency that behaves as a simple \qty{}. This
is used in Fig~\ref{fig:cardano-fee-validity}.
\begin{ruledfigure}{H}
\begin{displaymath}
\begin{array}{rll}
\currency &=& \H\\
\nativeCur &=& \emptyBs\\
\token &=& \H\\
\nativeCur &=& \emptyBs\\
\nativeTok &=& \emptyBs\\
\end{array}
\end{displaymath}
Expand All @@ -803,16 +799,6 @@ \subsubsection{Remarks}
\qtymap{} is a finitely-supported function \emph{to} another finitely-supported
function. This is well-defined, since finitely-supported functions form a monoid.

\paragraph{Native currency. }
Quantities of the native currency are represented just like any other currency,
using \qtymap{}s with the \nativeCur{} identifier. The one exception is the
\fee{} field, which continues to be a simple \qty{}. This represents a quantity
in the native currency, as fees can only be paid in that.

It may be desirable to choose \nativeCur{} outside the range
of \scriptAddr{}, since this will prevent forging of the native currency
except in the initial transaction (see rule~\ref{rule:forging-2}).

\subsection{The \ptx{} type for EUTXO-2}
\label{sec:pendingtx-2}
The \ptx{} type must be also be updated for the EUTXO-2 model. All
Expand All @@ -835,7 +821,7 @@ \subsection{The \ptx{} type for EUTXO-2}
& &\ \i{thisInput}: \N,\\
& &\ \i{outputInfo}: \List{\s{OutputInfo$_2$}},\\
& &\ \i{validityInterval}: \Interval{\extended{\slotnum}},\\
& &\ \fee: \qty,\\
& &\ \fee: \qtymap,\\
& &\ \forge: \qtymap)\\
\\
\tau_2: \eutxotx_2 \times \N \rightarrow \ptx_2 &=& \mbox{summarises a transaction in the context of an input}\\
Expand All @@ -854,25 +840,6 @@ \subsection{Validity of EUTXO-2 transactions}
Figure~\ref{fig:eutxo-1-validity} must also be updated to take account
of multiple currencies.

We use the definitions of \unspent{} and
\getSpent{} from Figure~\ref{fig:validation-functions-1} unchanged,
but we also require a function to inject a \qty{} of the native currency
into \qtymap{}. We define it in Figure~\ref{fig:validation-functions-2}.
\begin{displaymath}
\end{displaymath}
\begin{ruledfigure}{H}
\begin{displaymath}
\injectNative(q)(c)(t) = \left\{
\begin{array}{ll}
q & \mbox{if $c = \nativeCur$ and $t = \nativeTok$ }\\
0 & \mbox{otherwise}
\end{array}
\right\}
\end{displaymath}
\caption{Auxiliary functions for EUTXO-2 validation}
\label{fig:validation-functions-2}
\end{ruledfigure}

We can now adapt the definition of validity for EUTXO-1
(Figure~\ref{fig:eutxo-1-validity}) to obtain a definition of validity for
EUTXO-2: see Figure~\ref{fig:eutxo-2-validity}.
Expand Down Expand Up @@ -912,7 +879,7 @@ \subsection{Validity of EUTXO-2 transactions}
\label{rule:value-is-preserved-2}
\textbf{Values are preserved}
\begin{displaymath}
t.\forge + \sum_{i \in t.\inputs} \getSpent(i, l) = \injectNative(t.\fee) + \sum_{o \in t.\outputs} o.\val
t.\forge + \sum_{i \in t.\inputs} \getSpent(i, l) = t.\fee + \sum_{o \in t.\outputs} o.\val
\end{displaymath}

\item
Expand Down Expand Up @@ -961,6 +928,20 @@ \subsection{Remarks}
transaction is invalid if it attempts to destroy more of a currency
than is actually available in its inputs.

\paragraph{Validation on Cardano.}
Cardano adds an additional rule in Fig~\ref{fig:cardano-fee-validity}, which
asserts that fees are paid exclusively in the native currency.

\begin{ruledfigure}{H}
\textbf{Fees are paid in the native currency}
\begin{displaymath}
\support(t.\fee) = \{ \nativeCur \} \textrm{ and }
\support(t.\fee(\nativeCur)) = \{ \nativeTok \}
\end{displaymath}
\caption{Validity of a transaction $t$ in the EUTXO-2 model}
\label{fig:cardano-fee-validity}
\end{ruledfigure}

\subsection{The EUTXO-2 model in practice.}
See~\cite{Plutus-book} for examples of contracts which make use of the
features of the EUTXO-2 model. See also
Expand Down Expand Up @@ -1230,8 +1211,8 @@ \section{Comments on the specification}
\label{note:eutxo-2-performance}
The EUTXO-2 model will lose some efficiency in comparison to the EUTXO-1
model, simply because the data structures are more complicated. This
would even apply to transactions which only involve to native
currency, since it would be necessary to check whether the \qtymap{}
would even apply to transactions which only involve the native
currency (if there is one), since it would be necessary to check whether the \qtymap{}
contains anything that needs to be processed. If this is a concern
then one could implement a model with two types of transaction,
essentially just the disjoint union of the EUTXO-1 and EUTXO-2
Expand Down
2 changes: 1 addition & 1 deletion plutus-contract/src/Language/Plutus/Contract/Tx.hs
Expand Up @@ -90,7 +90,7 @@ toLedgerTx utx =
{ L.txInputs = _inputs utx
, L.txOutputs = _outputs utx
, L.txForge = _forge utx
, L.txFee = 0
, L.txFee = mempty
, L.txValidRange = _validityRange utx
, L.txSignatures = Map.empty
}
Expand Down
3 changes: 1 addition & 2 deletions plutus-contract/src/Language/Plutus/Contract/Wallet.hs
Expand Up @@ -21,7 +21,6 @@ import Language.Plutus.Contract.Tx (UnbalancedTx)
import qualified Language.Plutus.Contract.Tx as T
import qualified Language.PlutusTx.Prelude as P
import qualified Ledger as L
import qualified Ledger.Ada as Ada
import qualified Ledger.AddressMap as AM
import Ledger.Tx (Tx, TxOut, TxOutRef)
import qualified Ledger.Tx as Tx
Expand Down Expand Up @@ -52,7 +51,7 @@ balanceWallet utx = do
-- unknown to the wallet.
computeBalance :: WAPI.MonadWallet m => Tx -> m Value
computeBalance tx = (P.-) <$> left <*> pure right where
right = Ada.toValue (L.txFee tx) P.+ foldMap (view Tx.outValue) (tx ^. Tx.outputs)
right = L.txFee tx P.+ foldMap (view Tx.outValue) (tx ^. Tx.outputs)
left = do
inputValues <- traverse lookupValue (Set.toList $ Tx.txInputs tx)
pure $ foldr (P.+) P.zero (L.txForge tx : inputValues)
Expand Down
2 changes: 1 addition & 1 deletion plutus-emulator/test/Spec.hs
Expand Up @@ -188,7 +188,7 @@ validTrace = property $ do
invalidTrace :: Property
invalidTrace = property $ do
(m, txn) <- forAll genChainTxn
let invalidTxn = txn { txFee = 0 }
let invalidTxn = txn { txFee = mempty }
(result, st) = Gen.runTrace m $ simpleTrace invalidTxn
Hedgehog.assert (isLeft result)
Hedgehog.assert ([] == _txPool st)
Expand Down
2 changes: 1 addition & 1 deletion plutus-playground-client/src/Chain/Types.purs
Expand Up @@ -82,7 +82,7 @@ _balances = _Newtype <<< prop (SProxy :: SProxy "balances")
_tx :: Lens' AnnotatedTx Tx
_tx = _Newtype <<< prop (SProxy :: SProxy "tx")

_txFee :: Lens' Tx Ada
_txFee :: Lens' Tx Value
_txFee = _Newtype <<< prop (SProxy :: SProxy "txFee")

_txForge :: Lens' Tx Value
Expand Down
2 changes: 1 addition & 1 deletion plutus-playground-client/src/Chain/View.purs
Expand Up @@ -169,7 +169,7 @@ feeView txFee =
div [ classes [ card, entryClass, feeClass ] ]
[ cardHeader_ [ text "Fee" ]
, cardBody_
[ valueView $ adaToValue txFee
[ valueView txFee
]
]

Expand Down
@@ -1,5 +1,5 @@
==== Slot #0, Tx #0 ====
TxId: d7e9377c3614174e82e53d0cf578c2e8d3b740aefc211478d5959bae5a283810
TxId: 3c92d1c54f212ed5ee8b2db78ac7d41af00991d867dec1dca48576f6836c836c
Fee: -
Forge: Ada: Lovelace: 30000000
b0b0: USDToken: 60
Expand Down Expand Up @@ -51,7 +51,7 @@ Balances Carried Forward:
EURToken: 30

==== Slot #2, Tx #0 ====
TxId: c22e46ca8feff921ccf3bbdfa30182f76d071aa1ca15ea263c859ecb6739d018
TxId: ac9a5e4bb7f45938b561df557806644912528cd994def7d3318a03a7b8c53803
Fee: -
Forge: -
Inputs:
Expand All @@ -62,7 +62,7 @@ Inputs:
b0b0: USDToken: 20
EURToken: 30
Source:
Tx: d7e9377c3614174e82e53d0cf578c2e8d3b740aefc211478d5959bae5a283810
Tx: 3c92d1c54f212ed5ee8b2db78ac7d41af00991d867dec1dca48576f6836c836c
Output #2
PubKey: fc51cd8e6218a1a38da47ed00230f0580816ed13...

Expand All @@ -76,7 +76,7 @@ Outputs:
EURToken: 30

---- Output 1 ----
Destination: Script: 9f182e1118b8186b18db184f0c18e1184218a118...
Destination: Script: 9f18a018be0418f9184f189e18b0186318cf185b...
Value:
Ada: Lovelace: 8000000

Expand All @@ -100,12 +100,12 @@ Balances Carried Forward:
b0b0: USDToken: 20
EURToken: 30

Script: 9f182e1118b8186b18db184f0c18e1184218a118...
Script: 9f18a018be0418f9184f189e18b0186318cf185b...
Value:
Ada: Lovelace: 8000000

==== Slot #3, Tx #0 ====
TxId: c632375cac249e2a14bf7be16aa19de502f9c73a7a5405afa899b97183d89d94
TxId: d7ba7793a1147f6a15ee61372217e601649581e479da326f322f372a71bbe6b6
Fee: -
Forge: -
Inputs:
Expand All @@ -116,7 +116,7 @@ Inputs:
b0b0: USDToken: 20
EURToken: 30
Source:
Tx: d7e9377c3614174e82e53d0cf578c2e8d3b740aefc211478d5959bae5a283810
Tx: 3c92d1c54f212ed5ee8b2db78ac7d41af00991d867dec1dca48576f6836c836c
Output #1
PubKey: 98a5e3a36e67aaba89888bf093de1ad963e77401...

Expand All @@ -130,7 +130,7 @@ Outputs:
EURToken: 30

---- Output 1 ----
Destination: Script: 9f182e1118b8186b18db184f0c18e1184218a118...
Destination: Script: 9f18a018be0418f9184f189e18b0186318cf185b...
Value:
Ada: Lovelace: 8000000

Expand All @@ -154,30 +154,30 @@ Balances Carried Forward:
b0b0: USDToken: 20
EURToken: 30

Script: 9f182e1118b8186b18db184f0c18e1184218a118...
Script: 9f18a018be0418f9184f189e18b0186318cf185b...
Value:
Ada: Lovelace: 16000000

==== Slot #10, Tx #0 ====
TxId: 6cbaa60c9d090a83150ca9df89b68d977578c67734f4cee362944f87b8f78789
TxId: 707e29430d228527cf8a8b3a7575a7830e354b03a6eb83ffea7130da96f9e4eb
Fee: -
Forge: -
Inputs:
---- Input 0 ----
Destination: Script: 9f182e1118b8186b18db184f0c18e1184218a118...
Destination: Script: 9f18a018be0418f9184f189e18b0186318cf185b...
Value:
Ada: Lovelace: 8000000
Source:
Tx: c22e46ca8feff921ccf3bbdfa30182f76d071aa1ca15ea263c859ecb6739d018
Tx: ac9a5e4bb7f45938b561df557806644912528cd994def7d3318a03a7b8c53803
Output #1
Script: f6f6010000c3f6c3f6c3f6c5f6c1f6f664556e69...

---- Input 1 ----
Destination: Script: 9f182e1118b8186b18db184f0c18e1184218a118...
Destination: Script: 9f18a018be0418f9184f189e18b0186318cf185b...
Value:
Ada: Lovelace: 8000000
Source:
Tx: c632375cac249e2a14bf7be16aa19de502f9c73a7a5405afa899b97183d89d94
Tx: d7ba7793a1147f6a15ee61372217e601649581e479da326f322f372a71bbe6b6
Output #1
Script: f6f6010000c3f6c3f6c3f6c5f6c1f6f664556e69...

Expand Down Expand Up @@ -208,6 +208,6 @@ Balances Carried Forward:
b0b0: USDToken: 20
EURToken: 30

Script: 9f182e1118b8186b18db184f0c18e1184218a118...
Script: 9f18a018be0418f9184f189e18b0186318cf185b...
Value:
Ada: Lovelace: 0
@@ -1,5 +1,5 @@
==== Slot #0, Tx #0 ====
TxId: 7a68cea098afed859383feaee49a5ac8d6c17a811e787026d3c65a7973032f79
TxId: 5e4f55d62da6e61324a43232c159377387fa54764f10b40eda5be15a37600ccc
Fee: -
Forge: Ada: Lovelace: 10000000
Inputs:
Expand All @@ -19,7 +19,7 @@ Balances Carried Forward:
Ada: Lovelace: 10000000

==== Slot #1, Tx #0 ====
TxId: 55f28df328e3c09950cfb9d03aa7a23e720b24cf22f267c3f6067b0badedc60e
TxId: aea6fa7761dc136c0e9da1dbc1eaecb5940b285615c8ab7ed105423a5e54ff78
Fee: -
Forge: -
Inputs:
Expand All @@ -28,7 +28,7 @@ Inputs:
Value:
Ada: Lovelace: 10000000
Source:
Tx: 7a68cea098afed859383feaee49a5ac8d6c17a811e787026d3c65a7973032f79
Tx: 5e4f55d62da6e61324a43232c159377387fa54764f10b40eda5be15a37600ccc
Output #0
PubKey: 3d4017c3e843895a92b70aa74d1b7ebc9c982ccf...

Expand All @@ -40,7 +40,7 @@ Outputs:
Ada: Lovelace: 8000000

---- Output 1 ----
Destination: Script: 9f187216188f18a518dc1864185c189218ec187d...
Destination: Script: 9f18be182018de18ef189b181f189318fc188718...
Value:
Ada: Lovelace: 2000000

Expand All @@ -50,6 +50,6 @@ Balances Carried Forward:
Value:
Ada: Lovelace: 8000000

Script: 9f187216188f18a518dc1864185c189218ec187d...
Script: 9f18be182018de18ef189b181f189318fc188718...
Value:
Ada: Lovelace: 2000000
2 changes: 1 addition & 1 deletion plutus-playground-server/usecases/Messages.hs
Expand Up @@ -32,7 +32,7 @@ submitInvalidTxn = do
{ txInputs = Set.empty
, txOutputs = []
, txForge = Ada.adaValueOf 2
, txFee = 0
, txFee = Ada.adaValueOf 0
, txValidRange = defaultSlotRange
, txSignatures = Map.empty
}
Expand Down

0 comments on commit fdbb7a9

Please sign in to comment.