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

to/from json instances for script #84

Merged

Conversation

paweljakubas
Copy link
Collaborator

@paweljakubas paweljakubas commented Oct 14, 2020

https://jira.iohk.io/browse/ADP-474

"e09d36c79dec9bd1b3d9e152247701cd0bb860b5ebfd1de8abb6735a" 
{ "all" : [ "e09d36c79dec9bd1b3d9e152247701cd0bb860b5ebfd1de8abb6735a"
          , "e09d36c79dec9bd1b3d9e152247701cd0bb860b5ebfd1de8abb6735b"
          ]
}
{ "all" : [ "e09d36c79dec9bd1b3d9e152247701cd0bb860b5ebfd1de8abb6735a"
          , {"any": [ "e09d36c79dec9bd1b3d9e152247701cd0bb860b5ebfd1de8abb6735b"
                    ,  "e09d36c79dec9bd1b3d9e152247701cd0bb860b5ebfd1de8abb6735c"
                    ] 
            }
          ]
}
{ "all" : [  "e09d36c79dec9bd1b3d9e152247701cd0bb860b5ebfd1de8abb6735a"
          , {"some": { "from" :[ "e09d36c79dec9bd1b3d9e152247701cd0bb860b5ebfd1de8abb6735b"
                      , "e09d36c79dec9bd1b3d9e152247701cd0bb860b5ebfd1de8abb6735c"
                      , "e09d36c79dec9bd1b3d9e152247701cd0bb860b5ebfd1de8abb6735d"
                      ] 
                        , "at_least" : 2
                     }
            }
          ]
}

@paweljakubas paweljakubas self-assigned this Oct 14, 2020
@paweljakubas paweljakubas force-pushed the paweljakubas/adp-494/to-from-json-instances-for-script branch 2 times, most recently from 4e61593 to 52a73ea Compare October 15, 2020 08:55
Copy link
Contributor

@rvl rvl left a 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?

Comment on lines 249 to 250
let keyHexed = T.decodeUtf8 $ encode EBase16 key
in Object ("key" .= keyHexed)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let keyHexed = T.decodeUtf8 $ encode EBase16 key
in Object ("key" .= keyHexed)
object ["key" .= T.decodeLatin1 (encode EBase16 key)]

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in 3c2bb9a

@@ -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" }
Copy link
Contributor

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?

Copy link
Collaborator Author

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

mOfN <-
(withObject "script" $
\o -> o .:? "at_least" :: Json.Parser (Maybe Value)) obj
case (reqKey, reqAny, reqAll, mOfN) of
Copy link
Contributor

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done 3c2bb9a

where
toHexText = T.decodeUtf8 . encode EBase16
toHexText' (ScriptHash bytes) = toHexText bytes

instance Arbitrary Script where
arbitrary = do
Copy link
Contributor

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?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔

Comment on lines 34 to 35
import Codec.Binary.Encoding
( AbstractEncoding (..), encode, fromBase16 )
Copy link
Contributor

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?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sound idea -> b899a28

@paweljakubas paweljakubas force-pushed the paweljakubas/adp-494/to-from-json-instances-for-script branch from 52a73ea to 3c2bb9a Compare October 20, 2020 20:40
@paweljakubas paweljakubas requested a review from rvl October 20, 2020 21:01
Copy link
Contributor

@rvl rvl left a 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.

Left _ -> Left $ ErrorKeyHashFromTextInvalidString EBase16
Right bytes -> checkPayload bytes
Just EBech32{} -> fromBech32
Just EBase58 -> case fromBase58 (toBytes str) of
Copy link
Contributor

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.

Copy link
Collaborator Author

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

parseKey = withText "Script KeyHash" $
either (fail . showErr) (pure . RequireSignatureOf) . keyHashFromText
parseAnyOf =
withObject "Script AnyOf" $ \o -> RequireAnyOf <$> (o .: "any" :: Json.Parser [Script])
Copy link
Contributor

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?

Copy link
Collaborator Author

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

Comment on lines 274 to 294

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
])
Copy link
Contributor

@rvl rvl Oct 21, 2020

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?

Suggested change
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
]

Copy link
Collaborator Author

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

Copy link
Contributor

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.

Comment on lines 338 to 340
toJSON (RequireMOf m content) =
let inside = Object ("from" .= fmap toJSON content <> "m" .= toJSON m)
in object ["at_least" .= inside]
Copy link
Contributor

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:

Suggested change
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])]

Copy link
Collaborator Author

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this specified anywhere?

Copy link
Collaborator Author

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@rvl rvl force-pushed the paweljakubas/adp-494/to-from-json-instances-for-script branch from bb05bf4 to 02a941b Compare October 22, 2020 04:29
@paweljakubas paweljakubas force-pushed the paweljakubas/adp-494/to-from-json-instances-for-script branch from a0ba4bc to c5d9680 Compare October 22, 2020 08:32
@paweljakubas paweljakubas merged commit 1399751 into master Oct 22, 2020
@paweljakubas paweljakubas deleted the paweljakubas/adp-494/to-from-json-instances-for-script branch October 22, 2020 09:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants