-
Notifications
You must be signed in to change notification settings - Fork 46
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
to/from json instances for script #84
to/from json instances for script #84
Conversation
4e61593
to
52a73ea
Compare
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.
Looks ok.
Is this schema specified anywhere? Do we need to have a discussion about the schema?
core/lib/Cardano/Script.hs
Outdated
let keyHexed = T.decodeUtf8 $ encode EBase16 key | ||
in Object ("key" .= keyHexed) |
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.
let keyHexed = T.decodeUtf8 $ encode EBase16 key | |
in Object ("key" .= keyHexed) | |
object ["key" .= T.decodeLatin1 (encode EBase16 key)] |
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.
done in 3c2bb9a
core/lib/Cardano/Script.hs
Outdated
@@ -212,3 +220,68 @@ blake2b224 = | |||
-- Size, in bytes, of a hash of public key (without the corresponding chain code) | |||
hashSize :: Int | |||
hashSize = hashDigestSize Blake2b_224 | |||
|
|||
-- Examples of Script jsons: | |||
--{ "key" : "e09d36c79dec9bd1b3d9e152247701cd0bb860b5ebfd1de8abb6735a" } |
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.
Rather than a json object, could this just be a string?
The label "key" is not quite right because it's a hex-encoded hash of a key.
And were we going to use bech32 for key hashes?
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.
good idea, I was also thinking about it (ie. to express verification key hash as string). also in accordance to "line parser" added all, bech32, base16 and base58, support. see 3c2bb9a
core/lib/Cardano/Script.hs
Outdated
mOfN <- | ||
(withObject "script" $ | ||
\o -> o .:? "at_least" :: Json.Parser (Maybe Value)) obj | ||
case (reqKey, reqAny, reqAll, mOfN) of |
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.
Try replacing this with applicative style <|>
. E.g.
parseJSON v = parseKey v <|> parseAnyOf v <|> parseAllOf v <|> parseAtLeast v
where
parseAnyOf = withObject "Script AnyOf" \o -> RequireAnyOf <$> (o .: "any")
-- etc
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.
done 3c2bb9a
core/test/Cardano/ScriptSpec.hs
Outdated
where | ||
toHexText = T.decodeUtf8 . encode EBase16 | ||
toHexText' (ScriptHash bytes) = toHexText bytes | ||
|
||
instance Arbitrary Script where | ||
arbitrary = do |
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 can't remember ... with generators of recursive types, does the generator need to be made smaller for every step down the tree?
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.
🤔
core/lib/Cardano/Script.hs
Outdated
import Codec.Binary.Encoding | ||
( AbstractEncoding (..), encode, fromBase16 ) |
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 forgot to add that I don't really like module names like this.
It confuses me because it looks like the module comes from another package.
Given that it deals with bech32/base56, it is very much a module which should be called Cardano.Addresses.Encoding
.
Also, this module Cardano.Script
. There are multiple kinds of scripts in cardano. How about Cardano.Addresses.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.
sound idea -> b899a28
52a73ea
to
3c2bb9a
Compare
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.
Looks better. I have suggestions for the json schema. It would be good to get the json and bech32 HRPs are correct now so we don't need to fix it later.
core/lib/Cardano/Address/Script.hs
Outdated
Left _ -> Left $ ErrorKeyHashFromTextInvalidString EBase16 | ||
Right bytes -> checkPayload bytes | ||
Just EBech32{} -> fromBech32 | ||
Just EBase58 -> case fromBase58 (toBytes str) of |
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 don't think we should support base58 for key hashes because it will just add confusion. I would even be mildly in favour of only using bech32 and not even supporting hex. The thing I like about bech32 is the HRP - which base16 and base58 don't have. On the other hand, supporting hex is good for interoperability.
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.
now support only to bech32 and base16 (I think some people are very attached to this format - like me;-)) -> 6a1ebd1
core/lib/Cardano/Address/Script.hs
Outdated
parseKey = withText "Script KeyHash" $ | ||
either (fail . showErr) (pure . RequireSignatureOf) . keyHashFromText | ||
parseAnyOf = | ||
withObject "Script AnyOf" $ \o -> RequireAnyOf <$> (o .: "any" :: Json.Parser [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.
Are the type annotations needed to make it build?
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.
indeed - not needed - removed here 6d001e1
|
||
instance Arbitrary Script where | ||
arbitrary = do | ||
reqAllGen <- do | ||
n <- choose (1,10) | ||
pure $ RequireAllOf <$> vector n | ||
reqAnyGen <- do | ||
n <- choose (1,10) | ||
pure $ RequireAnyOf <$> vector n | ||
reqMofNGen <- do | ||
m <- choose (2,5) | ||
n <- choose ((fromInteger $ toInteger m),10) | ||
pure $ RequireMOf m <$> vector n | ||
let reqSig = | ||
(RequireSignatureOf . KeyHash . BS.pack) <$> replicateM 28 arbitrary | ||
oneof | ||
(replicate 15 reqSig ++ | ||
[ reqAllGen | ||
, reqAnyGen | ||
, reqMofNGen | ||
]) |
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 looked it up... We do need to be careful to avoid generators which fail to terminate, or produce very large results. Generating Recursive Data Types 🤔.
Also, can shrink = genericShrink
work here?
instance Arbitrary Script where | |
arbitrary = do | |
reqAllGen <- do | |
n <- choose (1,10) | |
pure $ RequireAllOf <$> vector n | |
reqAnyGen <- do | |
n <- choose (1,10) | |
pure $ RequireAnyOf <$> vector n | |
reqMofNGen <- do | |
m <- choose (2,5) | |
n <- choose ((fromInteger $ toInteger m),10) | |
pure $ RequireMOf m <$> vector n | |
let reqSig = | |
(RequireSignatureOf . KeyHash . BS.pack) <$> replicateM 28 arbitrary | |
oneof | |
(replicate 15 reqSig ++ | |
[ reqAllGen | |
, reqAnyGen | |
, reqMofNGen | |
]) | |
instance Arbitrary Script where | |
arbitrary = sized script' | |
where | |
script' 0 = RequireSignatureOf . KeyHash . BS.pack <$> replicateM 28 arbitrary | |
script' n = | |
let scripts = listOf (arbitrary (script' (n `div` 2))) | |
in oneof | |
[ RequireAllOf <$> scripts | |
, RequireAnyOf <$> scripts | |
, RequireMOf <$> choose (2,5) <*> scripts | |
-- note: perhaps the last one is too invalid | |
] |
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.
instance Arbitrary Script where
arbitrary = sized script'
where
script' 0 = RequireSignatureOf . KeyHash . BS.pack <$> replicateM 28 arbitrary
script' n =
let n' = n `div` 2
scripts = listOf (script' n')
conds = [ RequireAllOf <$> scripts
, RequireAnyOf <$> scripts ]
in if n' >= 5 then
oneof (conds ++ [RequireSomeOf <$> choose (2,5) <*> scripts])
else
oneof conds
seems to stuck when running... on the other hand, for me, it is much less clear to read
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.
OK I fixed it. I think it's important to learn how to generate tests properly and use best practices for quickcheck.
core/lib/Cardano/Address/Script.hs
Outdated
toJSON (RequireMOf m content) = | ||
let inside = Object ("from" .= fmap toJSON content <> "m" .= toJSON m) | ||
in object ["at_least" .= inside] |
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.
Could we rename RequireMOf
to RequireSomeOf
or RequireAtLeast
? That is more descriptive to me.
Then with the JSON, perhaps "at_least"
→ "some"
and "m"
→ "at_least"
.
Also it's probably possible to shorten this:
toJSON (RequireMOf m content) = | |
let inside = Object ("from" .= fmap toJSON content <> "m" .= toJSON m) | |
in object ["at_least" .= inside] | |
toJSON (RequireSomeOf count scripts) = | |
object ["some" .= (object ["at_least" .= count, "from" .= scripts])] |
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.
good idea -> done in 4b26932
(const $ Left $ ErrorKeyHashFromTextInvalidString $ EBech32 ()) | ||
Right (Bech32.decodeLenient txt) | ||
case Bech32.humanReadablePartToText hrp of | ||
"script_vkh" -> do |
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.
Is this specified anywhere?
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.
yes, it it specified here -> cardano-foundation/CIPs#31
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.
Thanks
bb05bf4
to
02a941b
Compare
hlint another hlint fix
a0ba4bc
to
c5d9680
Compare
https://jira.iohk.io/browse/ADP-474