-
Notifications
You must be signed in to change notification settings - Fork 213
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
Support reference scripts #4070
Support reference scripts #4070
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some early comments!
I propose to revise our generators of arbitrary TxOut
values so that we're not always generating values of Nothing
for the script
field. I suspect that if we do this, that several property tests will fail. (See comments.)
@@ -57,6 +63,9 @@ import GHC.Generics | |||
import qualified Cardano.Wallet.Primitive.Types.Coin as Coin | |||
import qualified Cardano.Wallet.Primitive.Types.TokenBundle as TokenBundle | |||
import qualified Cardano.Wallet.Primitive.Types.TokenMap as TokenMap | |||
import qualified Data.Text as T | |||
import qualified Text.ParserCombinators.ReadP as Parse | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -84,7 +95,7 @@ data TxOut = TxOut | |||
instance Ord TxOut where | |||
compare = comparing projection | |||
where | |||
projection (TxOut address bundle) = (address, Lexicographic bundle) | |||
projection (TxOut address bundle _) = (address, Lexicographic bundle) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this Ord
instance is not lawful w.r.t. the antisymmetry law:
(x <= y && y <= x) ==> (x == y)
Here's a counterexample:
>>> s1 == s2
False
>>> TxOut a b s1 <= TxOut a b s2
True
>>> TxOut a b s1 >= TxOut a b s2
True
>>> TxOut a b s1 == TxOut a b s2
False 💥
To fix this, we need to take all parts of a TxOut
into account:
projection (TxOut address bundle _) = (address, Lexicographic bundle) | |
projection (TxOut address bundle script) = | |
( address | |
, Lexicographic bundle | |
, script | |
) |
scriptToText :: Script KeyHash -> T.Text | ||
scriptToText (RequireSignatureOf keyhash) = | ||
keyHashToText keyhash | ||
scriptToText (RequireAllOf contents) = | ||
"all [" <> T.intercalate "," (map scriptToText contents) <> "]" | ||
scriptToText (RequireAnyOf contents) = | ||
"any [" <> T.intercalate "," (map scriptToText contents) <> "]" | ||
scriptToText (RequireSomeOf m contents) = | ||
"at_least "<> T.pack (show m) <> | ||
" [" <> T.intercalate "," (map scriptToText contents) <> "]" | ||
scriptToText (ActiveFromSlot s) = | ||
"active_from " <> T.pack (show s) | ||
scriptToText (ActiveUntilSlot s) = | ||
"active_until " <> T.pack (show s) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scriptToText :: Script KeyHash -> T.Text | |
scriptToText (RequireSignatureOf keyhash) = | |
keyHashToText keyhash | |
scriptToText (RequireAllOf contents) = | |
"all [" <> T.intercalate "," (map scriptToText contents) <> "]" | |
scriptToText (RequireAnyOf contents) = | |
"any [" <> T.intercalate "," (map scriptToText contents) <> "]" | |
scriptToText (RequireSomeOf m contents) = | |
"at_least "<> T.pack (show m) <> | |
" [" <> T.intercalate "," (map scriptToText contents) <> "]" | |
scriptToText (ActiveFromSlot s) = | |
"active_from " <> T.pack (show s) | |
scriptToText (ActiveUntilSlot s) = | |
"active_until " <> T.pack (show s) | |
scriptToText :: Script KeyHash -> T.Text | |
scriptToText (RequireSignatureOf keyhash) = | |
keyHashToText keyhash | |
scriptToText (RequireAllOf contents) = | |
"all [" <> T.intercalate "," (map scriptToText contents) <> "]" | |
scriptToText (RequireAnyOf contents) = | |
"any [" <> T.intercalate "," (map scriptToText contents) <> "]" | |
scriptToText (RequireSomeOf m contents) = | |
"at_least "<> T.pack (show m) <> | |
" [" <> T.intercalate "," (map scriptToText contents) <> "]" | |
scriptToText (ActiveFromSlot s) = | |
"active_from " <> T.pack (show s) | |
scriptToText (ActiveUntilSlot s) = | |
"active_until " <> T.pack (show s) |
|
||
toInternalUTxO' :: (TokenBundle -> b) -> (TxIn, TxOut) -> (WalletUTxO, b) | ||
toInternalUTxO' f (i, TxOut a b) = (WalletUTxO i a, f b) | ||
toInternalUTxO' f (i, TxOut a b _) = (WalletUTxO i a, f b) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect this will break the following round-trip property:
cardano-wallet/lib/balance-tx/test/spec/Cardano/Tx/Balance/Internal/CoinSelectionSpec.hs
Lines 87 to 89 in 7181feb
prop_toInternalUTxO_toExternalUTxO :: TxIn -> TxOut -> Property | |
prop_toInternalUTxO_toExternalUTxO i o = | |
(toExternalUTxO . toInternalUTxO) (i, o) === (i, o) |
However, our current property tests will not discover this breakage, as this PR adjusts the generators for TxOut
so that they always generate Nothing
for the script
field.
We should definitely adjust the generator for TxOut
used by Cardano.Tx.Balance.Internal.CoinSelectionSpec
so that it generates a wider range of values for the script
field: i.e., not just Nothing
.
To fix this round-trip property, I'm guessing we will probably need to add a script
field to the WalletUTxO
type (above).
@@ -123,7 +123,7 @@ genSelection = Selection | |||
genAssetsToBurn = genTokenMap | |||
genExtraCoinSource = genCoin | |||
genExtraCoinSink = genCoin | |||
genTxOutCoin = TxOut <$> genAddress <*> (TokenBundle.fromCoin <$> genCoin) | |||
genTxOutCoin = TxOut <$> genAddress <*> (TokenBundle.fromCoin <$> genCoin) <*> pure Nothing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should generate a wider range of values here, and not just Nothing
. In particular, always specifying Nothing
hides the fact that this property no longer holds:
cardano-wallet/lib/balance-tx/test/spec/Cardano/Tx/Balance/Internal/CoinSelectionSpec.hs
Lines 87 to 89 in 7181feb
prop_toInternalUTxO_toExternalUTxO :: TxIn -> TxOut -> Property | |
prop_toInternalUTxO_toExternalUTxO i o = | |
(toExternalUTxO . toInternalUTxO) (i, o) === (i, o) |
instance {-# OVERLAPPING #-} Show (Maybe (Script KeyHash)) where | ||
show scriptM = case scriptM of | ||
Nothing -> "not present" | ||
Just script -> T.unpack . scriptToText $ script |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Is it actually necessary to define an overlapping instance here? 🤔
Could we instead define a Show
instance for Script KeyHash
(in the module that defines Script
), and then just rely upon the default Show
instance for Maybe
?
@@ -54,11 +54,16 @@ genTxOut :: Gen TxOut | |||
genTxOut = TxOut | |||
<$> genAddress | |||
<*> genTokenBundleSmallRange `suchThat` tokenBundleHasNonZeroCoin | |||
<*> pure Nothing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should generate a wider range of values here than just Nothing
.
Are there already generators for the Script
type, and if so, can we import one of them and use it here?
|
||
shrinkTxOut :: TxOut -> [TxOut] | ||
shrinkTxOut (TxOut a b) = uncurry TxOut <$> shrinkInterleaved | ||
shrinkTxOut (TxOut a b c) = | ||
map enrichPair $ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
map enrichPair $ | |
enrichPair <$> |
Scripts.RequireSignature $ | ||
Ledger.KeyHash $ Crypto.UnsafeHash $ toShort h |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Scripts.RequireSignature $ | |
Ledger.KeyHash $ Crypto.UnsafeHash $ toShort h | |
Scripts.RequireSignature $ | |
Ledger.KeyHash $ Crypto.UnsafeHash $ toShort h |
reference_policy_script_template: | ||
<<: *ScriptTemplateValue | ||
description: | | ||
Optional policy script template that could be used as script reference |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional policy script template that could be used as script reference | |
Optional policy script template that could be used as a script reference |
@@ -67,6 +76,8 @@ data TxOut = TxOut | |||
:: !Address | |||
, tokens | |||
:: !TokenBundle | |||
, script | |||
:: !(Maybe (Script KeyHash)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we can use the StrictMaybe
type here instead?
Actually, I asked Pawel to not change the |
closing in favor of #4086 |
Comments
Issue Number