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

Add servant post transaction endpoint #111

Merged
merged 8 commits into from
Apr 9, 2019

Conversation

akegalj
Copy link
Contributor

@akegalj akegalj commented Mar 22, 2019

Issue Number

#93

Overview

  • I have added post transaction endpoint to servant api
  • I have added json golden files to cover new api
  • I have adjusted servant api with swagger spec

Comments

Real diff of this PR is ~250L , rest is mostly golden files produced by our test spec so don't be intemidated. Golden files might be too big: #111 (comment) ?

@akegalj akegalj self-assigned this Mar 22, 2019
src/Cardano/Wallet/Api.hs Outdated Show resolved Hide resolved
@@ -221,6 +223,15 @@ newtype Address = Address

instance NFData Address

data AddressError
= AddressDecodeError T.Text
Copy link
Member

Choose a reason for hiding this comment

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

What about a record with meaningful field to give better meaning to the underlying Text (also, the qualified import isn't necessary here).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed - this type was moved to different module (by other author) https://github.com/input-output-hk/cardano-wallet/blob/5c7d690e5d994c931e5b437c5bdbaf222f6dc675/src/Cardano/Wallet/Api/Types.hs#L205 .

It is not a record but it also doesn't seem to be used as a sum type in future. Rather it looks like a self containing wrapper type where constructor/type name tells the storry (at least for now). So I think we can forget about this until we run into more complicated use case

@KtorZ KtorZ force-pushed the master branch 2 times, most recently from 049fddd to a8d7c7d Compare March 23, 2019 12:45
@akegalj akegalj force-pushed the akegalj/93/create_transaction_servant branch from c1f20d6 to 40bbd60 Compare March 29, 2019 07:11
@@ -147,15 +149,10 @@ data WalletPutPassphraseData = WalletPutPassphraseData
} deriving (Eq, Generic, Show)

data CreateTransactionData = CreateTransactionData
{ _targets :: ![TargetOutput]
{ _targets :: ![TxOut]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@KtorZ what do you think about reusing tx output here and a bit bellow how aeson instances are handled

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have abandoned this idea as it didn't quite suite my needs - I had to wrap fields of TxOut with ApiT and it was easier to opt for a separate type.

ps - If number of such types increases, we could use template haskell to generate such types, types - but number of types is low so there is no need for such heavy machinery at this point (and I am not sure what is our opinion about template haskell in general).

For example if we had something like:

deriveApiTFor TxOut

something like this would create type

data TxOut = TxOut
  { address :: ApiT Address
  ,  coin :: ApiT Coin
  }

As personally I run only to one such use case so far I didn't want to introduce anything like the solution above - but if there were many such examples we might consider it

@akegalj akegalj force-pushed the akegalj/93/create_transaction_servant branch 2 times, most recently from cd5868e to 426d374 Compare April 8, 2019 16:44
maxLength: 64
minLength: 64
maxLength: 128
minLength: 128
Copy link
Contributor Author

Choose a reason for hiding this comment

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

According to the comment https://github.com/input-output-hk/cardano-wallet/blob/5c7d690e5d994c931e5b437c5bdbaf222f6dc675/src/Cardano/Wallet/Binary.hs#L569 , Hash "Tx" is a 64 byte string, which translates to 128 long hex encoded string (because byte is encoded as 2 char string).

Copy link
Member

Choose a reason for hiding this comment

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

Hmmm no. The hex-encoded version is 64-byte, the hash itself is 32 bytes. The spec was right here (cf current transaction ids..)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ups - ok. Will fix

, depth :: !(Quantity "block" Natural)
, direction :: !(ApiT Direction)
, inputs :: !(NonEmpty ApiCoinSelection)
, outputs :: !(NonEmpty ApiCoinSelection)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

inputs and outputs could be sepparate datatypes here such as TxInputs and TxOutputs but I decided to merge datatype into one named ApiCoinSelection. I am not sure is this a good idea or not. They do represent the same idea but I opt for the simplicity here and dropped the extra type safety that we were getting from having two types at this level

Alternitavely we would create two types ApiTxInputs and ApiTxOutputs which would look similar to TxIn and TxOut from Primitive module (except they will have wrappers for ApiT). Simiarly we would use ApiTxOut in PostTransactionData.targets.

Also ApiCoinSelection might be unfortunate name pick as it conflicts with coin selection algorithm that we implemented https://github.com/input-output-hk/cardano-wallet/tree/5c7d690e5d994c931e5b437c5bdbaf222f6dc675/src/Cardano/Wallet/CoinSelection although the context is the same

Copy link
Member

Choose a reason for hiding this comment

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

Agreed that keeping types identical here makes sense (from the API perspective, they are the same thing). About the name clash / confusion, I would go for ApiCoins or ApiResolvedInputs to makes it slightly less ambiguous though, it's all more-or-less the same thing.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Something other than ApiCoinSelection 👍

If possible, a short doc-comment about what it is would be awesome too. E.g if you were to go with ApiResolvedInputs, it might be worth knowing that it's used for outputs, and not just inputs of ApiTransaction

ApiCoins sounds reasonable to me. Or with some tweak like ApiOwnedCoins to indicate that they contain addresses, which I presume are the previous and current owner.

Copy link
Contributor Author

@akegalj akegalj Apr 9, 2019

Choose a reason for hiding this comment

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

doc-comment

@Anviking I guess you meant to document this in code because this object name doesn't appear in our swagger produced UI

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah - yeah

@@ -159,6 +177,33 @@ data WalletPutPassphraseData = WalletPutPassphraseData
, newPassphrase :: !(ApiT (Passphrase "encryption"))
} deriving (Eq, Generic, Show)

data PostTransactionData = PostTransactionData
{ targets :: !(NonEmpty ApiCoinSelection)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

},
{
"passphrase": "7ehYx\\==l5𡄩\"RlwoO6R|k`1~;tVP)&𩺄2?!!?ujj{w]meZ]Ti5{TAu(M;%}_E휊Wao<Ji4AC<~w-&+gHH[fBVj⅝jp↯$e𧶥콁P:\".YOmVAQ7t]PpxEoc5;;/ypb<}e R@@F'H=2Y$ZUH[g𦲧XRH (L&!fCRTV/&wPaqWn54D!5gVⷝ-oshW_l)S/XN贂0<YWjjNM\\fu9",
"targets": [
Copy link
Contributor Author

Choose a reason for hiding this comment

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

arbitrary generates rather big example here - is this ok or should we aim for a smaller golden file (with only one item in lists/arrays which would probably be ok to validate)?

Copy link
Member

@KtorZ KtorZ Apr 9, 2019

Choose a reason for hiding this comment

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

Na it's okay. We aren't "quickchecking" that but actually, we do want to cover the maximum surface with the golden tests. Bigger is better here.

"quantity": 37,
"unit": "lovelace"
},
"inputs": [
Copy link
Contributor Author

Choose a reason for hiding this comment

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

"samples": [
{
"passphrase": "AR1Q_'7!S?n}Owo`OrO8^OJKiS\"0COj=(vkE}duI떚pw&$h?[+ l9*bW>⫪Y192RaqVPg>X!y\\Xsd<&^fqL/ji>xwl]dd+7!]\\*_H鏨oP'\\$(^li6vZ=}Zg\\Yz胶}r+M/I1S",
"targets": [
Copy link
Contributor Author

Choose a reason for hiding this comment

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

arbitrary = Quantity . fromIntegral <$> (arbitrary @Word8)

instance Arbitrary (Hash "Tx") where
arbitrary = Hash . B8.pack <$> replicateM 64 arbitrary
Copy link
Contributor Author

Choose a reason for hiding this comment

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

huge entropy here - do we want to give less entropy then 64 bytes for constructing Hash "Tx" in order to trigger collisions?

Copy link
Member

Choose a reason for hiding this comment

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

I don't see any particular reason to want collision at this level? Any reason I am missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

no particular reason. It would be good to have such collision somewhere in tests. If not now top level then probably later somwhere closer to the core/primitives

Copy link
Contributor Author

@akegalj akegalj left a comment

Choose a reason for hiding this comment

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

Diff of this PR is ~250L , rest is mostly golden files produced by our test spec so don't be intemidated

@akegalj akegalj requested review from Anviking and KtorZ April 8, 2019 18:09
@akegalj akegalj marked this pull request as ready for review April 8, 2019 18:11
@akegalj akegalj changed the title Akegalj/93/create transaction servant Add servant post transaction endpoint Apr 8, 2019
Copy link
Member

@KtorZ KtorZ left a comment

Choose a reason for hiding this comment

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

LGTM.

Let's keep the text decoder aligned and consistent with the others and fix the tx id length in the spec and get it merged A.S.A.P.

maxLength: 64
minLength: 64
maxLength: 128
minLength: 128
Copy link
Member

Choose a reason for hiding this comment

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

Hmmm no. The hex-encoded version is 64-byte, the hash itself is 32 bytes. The spec was right here (cf current transaction ids..)

, depth :: !(Quantity "block" Natural)
, direction :: !(ApiT Direction)
, inputs :: !(NonEmpty ApiCoinSelection)
, outputs :: !(NonEmpty ApiCoinSelection)
Copy link
Member

Choose a reason for hiding this comment

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

Agreed that keeping types identical here makes sense (from the API perspective, they are the same thing). About the name clash / confusion, I would go for ApiCoins or ApiResolvedInputs to makes it slightly less ambiguous though, it's all more-or-less the same thing.

-- | Converts tx hash to a Base16-encoded string.
encodeApiTxHash :: ApiT (Hash "Tx") -> Text
encodeApiTxHash =
T.decodeUtf8 . convertToBase Base16 . getHash . getApiT
Copy link
Member

Choose a reason for hiding this comment

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

Let's define ToText and FromText instances for those in Primitive.Types 👍

test/data/Cardano/Wallet/Api/ApiT TxStatus.json Outdated Show resolved Hide resolved
},
{
"passphrase": "7ehYx\\==l5𡄩\"RlwoO6R|k`1~;tVP)&𩺄2?!!?ujj{w]meZ]Ti5{TAu(M;%}_E휊Wao<Ji4AC<~w-&+gHH[fBVj⅝jp↯$e𧶥콁P:\".YOmVAQ7t]PpxEoc5;;/ypb<}e R@@F'H=2Y$ZUH[g𦲧XRH (L&!fCRTV/&wPaqWn54D!5gVⷝ-oshW_l)S/XN贂0<YWjjNM\\fu9",
"targets": [
Copy link
Member

@KtorZ KtorZ Apr 9, 2019

Choose a reason for hiding this comment

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

Na it's okay. We aren't "quickchecking" that but actually, we do want to cover the maximum surface with the golden tests. Bigger is better here.

arbitrary = Quantity . fromIntegral <$> (arbitrary @Word8)

instance Arbitrary (Hash "Tx") where
arbitrary = Hash . B8.pack <$> replicateM 64 arbitrary
Copy link
Member

Choose a reason for hiding this comment

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

I don't see any particular reason to want collision at this level? Any reason I am missing?

test/unit/Cardano/Wallet/Api/TypesSpec.hs Show resolved Hide resolved
Copy link
Collaborator

@Anviking Anviking left a comment

Choose a reason for hiding this comment

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

lgtm!

Think calling ApiCoinSelection something else makes sense

, depth :: !(Quantity "block" Natural)
, direction :: !(ApiT Direction)
, inputs :: !(NonEmpty ApiCoinSelection)
, outputs :: !(NonEmpty ApiCoinSelection)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Something other than ApiCoinSelection 👍

If possible, a short doc-comment about what it is would be awesome too. E.g if you were to go with ApiResolvedInputs, it might be worth knowing that it's used for outputs, and not just inputs of ApiTransaction

ApiCoins sounds reasonable to me. Or with some tweak like ApiOwnedCoins to indicate that they contain addresses, which I presume are the previous and current owner.

test/data/Cardano/Wallet/Api/ApiT TxStatus.json Outdated Show resolved Hide resolved
@akegalj akegalj force-pushed the akegalj/93/create_transaction_servant branch 3 times, most recently from ca612bf to 6b2d8b3 Compare April 9, 2019 15:16
"time": "1864-06-04T01:25:12.205046097466Z",
"block": {
"epoch_number": 11863932,
"slot_number": 6928
Copy link
Member

Choose a reason for hiding this comment

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

I love how we are in 1864 but with epoch 11863932 🤷‍♂️

"bd1b1817695b42134ff5cc7a023972ca5c3d5c500b235c1a5d0a324f7d3c49284d6a1e51289e5031501f394a283720373c490d414f424d45178c4a27412e763d",
"2c47c30f62146920cc32468168daa03f1b127c6f7140044915de1a25541819047f4444224b5408690b480f056141794b38554c736474133e0083461e12787200",
"160830005e014910157d434c322f60101e5d785400550e094e7a3e668115782060225c234b7b7f5f3c2b4d345c554568416b4d732a2b4461155c3c4a8d05433b"
]
Copy link
Member

Choose a reason for hiding this comment

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

Those looks surprisingly long. They are 128-char long 🤔 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hm - that looks strange because its generated with arbitrary 32 bytes/chars so that should give 64 chars string: https://github.com/input-output-hk/cardano-wallet/blob/dfa7167225ff44477c25333e1613f86e46286f15/test/unit/Cardano/Wallet/Api/TypesSpec.hs#L455 .

> hash <- generate (arbitrary :: Gen (Hash "Tx"))
> hash
Hash {getHash = "\NAKtc@\249X\DELd\DC3(5W\NUL\\]J('\DC2,_@?s\SO<\vq\RS,M\164"}
> encode $ ApiT hash
"\"15746340f9587f6413283557005c5d4a2827122c5f403f730e3c0b711e2c4da4\""
> length "15746340f9587f6413283557005c5d4a2827122c5f403f730e3c0b711e2c4da4"
64

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Aha, I see you have fixed it. Sorry forgot to push regenerated golden tests

@KtorZ KtorZ force-pushed the akegalj/93/create_transaction_servant branch from 6b2d8b3 to dfa7167 Compare April 9, 2019 17:26
@KtorZ KtorZ merged commit 1cedad6 into master Apr 9, 2019
@KtorZ KtorZ deleted the akegalj/93/create_transaction_servant branch April 9, 2019 18:18
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.

None yet

3 participants