Skip to content

Commit 58ef107

Browse files
committed
Add ApiTransactionTimeout newtype, Fix after review
1 parent bade14c commit 58ef107

File tree

11 files changed

+99
-62
lines changed

11 files changed

+99
-62
lines changed

docs/docs/dev/architecture/hydra-components.svg

Lines changed: 1 addition & 1 deletion
Loading

docs/docs/tutorial/index.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,19 +639,23 @@ Submit the transaction through the already open WebSocket connection. Generate t
639639
cat tx-signed.json | jq -c '{tag: "NewTx", transaction: .}'
640640
```
641641

642+
<details>
643+
<summary>Alternative: use the HTTP API endpoint</summary>
644+
642645
Alternatively, you can submit the transaction using the HTTP API endpoint:
643646

644647
```shell
645648
curl -X POST 127.0.0.1:4001/transaction \
646649
--data @tx-signed.json \
647-
--header "Content-Type: application/json"
648650
```
649651

650652
The HTTP endpoint provides a synchronous response with different status codes:
651653
- **200 OK**: Transaction was included in a confirmed snapshot (includes `snapshotNumber`)
652654
- **202 Accepted**: Transaction was accepted but not yet confirmed
653655
- **400 Bad Request**: Transaction was rejected due to validation errors (includes `validationError`)
654656

657+
</details>
658+
655659
The transaction will be validated by both `hydra-node`s and either result in a
656660
`TxInvalid` message with a reason, or a `TxValid` message and a
657661
`SnapshotConfirmed` with the new UTXO available in the head shortly after.

hydra-node/golden/ReasonablySized SubmitHydraTxResponse.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
{
22
"samples": [
33
{
4-
"tag": "SubmitHydraTxSubmitted"
4+
"tag": "SubmitTxSubmitted"
55
},
66
{
7-
"tag": "SubmitHydraTxInvalid",
7+
"tag": "SubmitTxInvalid",
88
"validationError": ""
99
},
1010
{
11-
"tag": "SubmitHydraTxInvalid",
11+
"tag": "SubmitTxInvalid",
1212
"validationError": "\u0001)e"
1313
},
1414
{
15-
"tag": "SubmitHydraTxInvalid",
15+
"tag": "SubmitTxInvalid",
1616
"validationError": "=\u000e􂨤p"
1717
},
1818
{
19-
"tag": "SubmitHydraTxSubmitted"
19+
"tag": "SubmitTxSubmitted"
2020
}
2121
],
2222
"seed": -1369626537

hydra-node/golden/RunOptions.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"tag": "IPv4"
1111
},
1212
"apiPort": 18036,
13-
"apiTransactionTimeout": -0.833333333334,
13+
"apiTransactionTimeout": 0,
1414
"chainConfig": {
1515
"cardanoSigningKey": "a/c/b/c.sk",
1616
"cardanoVerificationKeys": [
@@ -145,7 +145,7 @@
145145
"tag": "IPv4"
146146
},
147147
"apiPort": 20019,
148-
"apiTransactionTimeout": 26.4375,
148+
"apiTransactionTimeout": 26,
149149
"chainConfig": {
150150
"cardanoSigningKey": "c/b/a/b/c/b.sk",
151151
"cardanoVerificationKeys": [
@@ -226,7 +226,7 @@
226226
"tag": "IPv4"
227227
},
228228
"apiPort": 9965,
229-
"apiTransactionTimeout": 17.714285714285,
229+
"apiTransactionTimeout": 17,
230230
"chainConfig": {
231231
"initialUTxOFile": "b/c/b/a/a/c.json",
232232
"ledgerGenesisFile": "b/c/a.json",
@@ -267,7 +267,7 @@
267267
"tag": "IPv4"
268268
},
269269
"apiPort": 8054,
270-
"apiTransactionTimeout": -23.4,
270+
"apiTransactionTimeout": 23,
271271
"chainConfig": {
272272
"cardanoSigningKey": "a/c/a.sk",
273273
"cardanoVerificationKeys": [

hydra-node/hydra-node.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ library
9090
Hydra.Network.Message
9191
Hydra.NetworkVersions
9292
Hydra.Node
93+
Hydra.Node.ApiTransactionTimeout
9394
Hydra.Node.DepositPeriod
9495
Hydra.Node.EmbedTH
9596
Hydra.Node.Environment

hydra-node/json-schemas/api.yaml

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ channels:
367367
$ref: "api.yaml#/components/schemas/Transaction"
368368
bindings:
369369
http:
370-
type: response
370+
type: request
371371
method: POST
372372
bindingVersion: '0.1.0'
373373
subscribe:
@@ -390,7 +390,7 @@ channels:
390390
$ref: "api.yaml#/components/schemas/PostTxError"
391391
bindings:
392392
http:
393-
type: request
393+
type: response
394394
method: POST
395395
bindingVersion: '0.1.0'
396396

@@ -401,7 +401,7 @@ channels:
401401
operationId: submitHydraTxRequest
402402
message:
403403
summary: |
404-
Hydra transaction to be submitted to the head.
404+
A transaction to be submitted to the head.
405405
Accepts transactions encoded as Base16 CBOR string, TextEnvelope type or JSON.
406406
payload:
407407
$ref: "api.yaml#/components/schemas/Transaction"
@@ -414,7 +414,7 @@ channels:
414414
operationId: submitHydraTxResponse
415415
message:
416416
oneOf:
417-
- name: SubmitHydraTxConfirmed
417+
- name: SubmitTxConfirmed
418418
summary: 200 OK
419419
description: Transaction was included in a confirmed snapshot.
420420
payload:
@@ -423,11 +423,11 @@ channels:
423423
properties:
424424
tag:
425425
type: string
426-
enum: ["SubmitHydraTxConfirmed"]
426+
enum: ["SubmitTxConfirmed"]
427427
snapshotNumber:
428428
type: integer
429429
minimum: 0
430-
- name: SubmitHydraTxInvalid
430+
- name: SubmitTxInvalid
431431
summary: 400 Bad Request
432432
description: Transaction was rejected due to validation errors.
433433
payload:
@@ -436,10 +436,10 @@ channels:
436436
properties:
437437
tag:
438438
type: string
439-
enum: ["SubmitHydraTxInvalid"]
439+
enum: ["SubmitTxInvalid"]
440440
validationError:
441441
type: string
442-
- name: SubmitHydraTxSubmitted
442+
- name: SubmitTxSubmitted
443443
summary: 202 Accepted
444444
description: Transaction was accepted but not yet confirmed.
445445
payload:
@@ -448,7 +448,7 @@ channels:
448448
properties:
449449
tag:
450450
type: string
451-
enum: ["SubmitHydraTxSubmitted"]
451+
enum: ["SubmitTxSubmitted"]
452452
bindings:
453453
http:
454454
type: response
@@ -3326,7 +3326,7 @@ components:
33263326

33273327
SubmitHydraTxResponse:
33283328
oneOf:
3329-
- title: SubmitHydraTxConfirmed
3329+
- title: SubmitTxConfirmed
33303330
type: object
33313331
additionalProperties: false
33323332
required:
@@ -3335,11 +3335,11 @@ components:
33353335
properties:
33363336
tag:
33373337
type: string
3338-
enum: ["SubmitHydraTxConfirmed"]
3338+
enum: ["SubmitTxConfirmed"]
33393339
snapshotNumber:
33403340
type: integer
33413341
minimum: 0
3342-
- title: SubmitHydraTxInvalid
3342+
- title: SubmitTxInvalid
33433343
type: object
33443344
additionalProperties: false
33453345
required:
@@ -3348,18 +3348,18 @@ components:
33483348
properties:
33493349
tag:
33503350
type: string
3351-
enum: ["SubmitHydraTxInvalid"]
3351+
enum: ["SubmitTxInvalid"]
33523352
validationError:
33533353
type: string
3354-
- title: SubmitHydraTxSubmitted
3354+
- title: SubmitTxSubmitted
33553355
type: object
33563356
additionalProperties: false
33573357
required:
33583358
- tag
33593359
properties:
33603360
tag:
33613361
type: string
3362-
enum: ["SubmitHydraTxSubmitted"]
3362+
enum: ["SubmitTxSubmitted"]
33633363

33643364
DepositStatus:
33653365
oneOf:

hydra-node/src/Hydra/API/APIServerLog.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ data APIServerLog
1616
{ method :: Method
1717
, path :: PathInfo
1818
}
19-
| APITransactionSubmitted {txid :: String}
19+
| APITransactionSubmitted {submittedTxId :: String}
2020
deriving stock (Eq, Show, Generic)
2121
deriving anyclass (ToJSON)
2222

hydra-node/src/Hydra/API/HTTPServer.hs

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import Hydra.Chain.Direct.State ()
2121
import Hydra.HeadLogic.State (HeadState (..))
2222
import Hydra.Ledger (ValidationError (..))
2323
import Hydra.Logging (Tracer, traceWith)
24+
import Hydra.Node.ApiTransactionTimeout (ApiTransactionTimeout (..))
2425
import Hydra.Node.DepositPeriod (toNominalDiffTime)
2526
import Hydra.Node.Environment (Environment (..))
2627
import Hydra.Tx (CommitBlueprintTx (..), ConfirmedSnapshot, IsTx (..), Snapshot (..), UTxOType)
@@ -124,45 +125,45 @@ instance (Arbitrary tx, Arbitrary (UTxOType tx), IsTx tx) => Arbitrary (SideLoad
124125
shrink = \case
125126
SideLoadSnapshotRequest snapshot -> SideLoadSnapshotRequest <$> shrink snapshot
126127

127-
-- | Request to submit a Hydra transaction to the head
128+
-- | Request to submit a transaction to the head
128129
newtype SubmitHydraTxRequest tx = SubmitHydraTxRequest
129130
{ submitHydraTx :: tx
130131
}
131132
deriving newtype (Eq, Show, Arbitrary)
132133
deriving newtype (ToJSON, FromJSON)
133134

134-
-- | Response for Hydra transaction submission
135+
-- | Response for transaction submission
135136
data SubmitHydraTxResponse
136137
= -- | Transaction was included in a confirmed snapshot
137-
SubmitHydraTxConfirmed Integer
138+
SubmitTxConfirmed Integer
138139
| -- | Transaction was rejected due to validation errors
139-
SubmitHydraTxInvalidResponse Text
140+
SubmitTxInvalidResponse Text
140141
| -- | Transaction was accepted but not yet confirmed
141-
SubmitHydraTxSubmitted
142+
SubmitTxSubmitted
142143
deriving stock (Eq, Show, Generic)
143144

144145
instance ToJSON SubmitHydraTxResponse where
145146
toJSON = \case
146-
SubmitHydraTxConfirmed snapshotNumber ->
147+
SubmitTxConfirmed snapshotNumber ->
147148
object
148-
[ "tag" .= Aeson.String "SubmitHydraTxConfirmed"
149+
[ "tag" .= Aeson.String "SubmitTxConfirmed"
149150
, "snapshotNumber" .= snapshotNumber
150151
]
151-
SubmitHydraTxInvalidResponse validationError ->
152+
SubmitTxInvalidResponse validationError ->
152153
object
153-
[ "tag" .= Aeson.String "SubmitHydraTxInvalid"
154+
[ "tag" .= Aeson.String "SubmitTxInvalid"
154155
, "validationError" .= validationError
155156
]
156-
SubmitHydraTxSubmitted -> object ["tag" .= Aeson.String "SubmitHydraTxSubmitted"]
157+
SubmitTxSubmitted -> object ["tag" .= Aeson.String "SubmitTxSubmitted"]
157158

158159
instance FromJSON SubmitHydraTxResponse where
159-
parseJSON = withObject "SubmitHydraTxResponse" $ \o -> do
160+
parseJSON = withObject "SubmitTxResponse" $ \o -> do
160161
tag <- o .: "tag"
161162
case tag :: Text of
162-
"SubmitHydraTxConfirmed" -> SubmitHydraTxConfirmed <$> o .: "snapshotNumber"
163-
"SubmitHydraTxInvalid" -> SubmitHydraTxInvalidResponse <$> o .: "validationError"
164-
"SubmitHydraTxSubmitted" -> pure SubmitHydraTxSubmitted
165-
_ -> fail "Expected tag to be SubmitHydraTxConfirmed, SubmitHydraTxInvalid, or SubmitHydraTxSubmitted"
163+
"SubmitTxConfirmed" -> SubmitTxConfirmed <$> o .: "snapshotNumber"
164+
"SubmitTxInvalid" -> SubmitTxInvalidResponse <$> o .: "validationError"
165+
"SubmitTxSubmitted" -> pure SubmitTxSubmitted
166+
_ -> fail "Expected tag to be SubmitTxConfirmed, SubmitTxInvalid, or SubmitTxSubmitted"
166167

167168
instance Arbitrary SubmitHydraTxResponse where
168169
arbitrary = genericArbitrary
@@ -187,7 +188,7 @@ httpApp ::
187188
-- | Callback to yield a 'ClientInput' to the main event loop.
188189
(ClientInput tx -> IO ()) ->
189190
-- | Timeout for transaction submission
190-
NominalDiffTime ->
191+
ApiTransactionTimeout ->
191192
-- | Channel to listen for events
192193
TChan (Either (TimedServerOutput tx) (ClientMessage tx)) ->
193194
Application
@@ -377,7 +378,7 @@ handleSubmitHydraTx ::
377378
forall tx.
378379
IsChainState tx =>
379380
(ClientInput tx -> IO ()) ->
380-
NominalDiffTime ->
381+
ApiTransactionTimeout ->
381382
TChan (Either (TimedServerOutput tx) (ClientMessage tx)) ->
382383
LBS.ByteString ->
383384
IO Response
@@ -390,15 +391,18 @@ handleSubmitHydraTx putClientInput apiTransactionTimeout responseChannel body =
390391
putClientInput (NewTx submitHydraTx)
391392

392393
let txid = txId submitHydraTx
393-
result <- timeout (realToFrac apiTransactionTimeout) (waitForTransactionResult txid)
394+
result <-
395+
timeout
396+
(realToFrac (apiTransactionTimeoutNominalDiffTime apiTransactionTimeout))
397+
(waitForTransactionResult txid)
394398

395399
case result of
396-
Just (SubmitHydraTxConfirmed snapshotNumber) ->
397-
pure $ responseLBS status200 jsonContent (Aeson.encode $ SubmitHydraTxConfirmed snapshotNumber)
398-
Just (SubmitHydraTxInvalidResponse validationError) ->
399-
pure $ responseLBS status400 jsonContent (Aeson.encode $ SubmitHydraTxInvalidResponse validationError)
400-
Just SubmitHydraTxSubmitted ->
401-
pure $ responseLBS status202 jsonContent (Aeson.encode SubmitHydraTxSubmitted)
400+
Just (SubmitTxConfirmed snapshotNumber) ->
401+
pure $ responseLBS status200 jsonContent (Aeson.encode $ SubmitTxConfirmed snapshotNumber)
402+
Just (SubmitTxInvalidResponse validationError) ->
403+
pure $ responseLBS status400 jsonContent (Aeson.encode $ SubmitTxInvalidResponse validationError)
404+
Just SubmitTxSubmitted ->
405+
pure $ responseLBS status202 jsonContent (Aeson.encode SubmitTxSubmitted)
402406
Nothing ->
403407
-- Timeout occurred - return 202 Accepted with timeout info
404408
pure $
@@ -407,30 +411,29 @@ handleSubmitHydraTx putClientInput apiTransactionTimeout responseChannel body =
407411
jsonContent
408412
( Aeson.encode $
409413
object
410-
[ "tag" .= Aeson.String "SubmitHydraTxSubmitted"
414+
[ "tag" .= Aeson.String "SubmitTxSubmitted"
411415
, "timeout" .= Aeson.String ("Transaction submission timed out after " <> pack (show apiTransactionTimeout) <> " seconds")
412416
]
413417
)
414418
where
415419
-- Wait for transaction result by listening to events
416420
waitForTransactionResult :: TxIdType tx -> IO SubmitHydraTxResponse
417-
waitForTransactionResult txid = do
418-
go
421+
waitForTransactionResult txid = go
419422
where
420423
go = do
421424
event <- atomically $ readTChan responseChannel
422425
case event of
423426
Left (TimedServerOutput{output}) -> case output of
424427
TxValid{transactionId}
425428
| transactionId == txid ->
426-
pure SubmitHydraTxSubmitted
429+
pure SubmitTxSubmitted
427430
TxInvalid{transaction, validationError = ValidationError reason}
428431
| txId transaction == txid ->
429-
pure $ SubmitHydraTxInvalidResponse reason
432+
pure $ SubmitTxInvalidResponse reason
430433
SnapshotConfirmed{snapshot} ->
431434
-- Check if the transaction is in the confirmed snapshot
432435
if txid `elem` map txId (confirmed snapshot)
433-
then pure $ SubmitHydraTxConfirmed (fromIntegral $ number snapshot)
436+
then pure $ SubmitTxConfirmed (fromIntegral $ number snapshot)
434437
else go
435438
_ -> go
436439
Right _ -> go

hydra-node/src/Hydra/API/Server.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import Hydra.HeadLogic.State (
4141
import Hydra.HeadLogic.StateEvent (StateEvent (..))
4242
import Hydra.Logging (Tracer, traceWith)
4343
import Hydra.Network (IP, PortNumber)
44+
import Hydra.Node.ApiTransactionTimeout (ApiTransactionTimeout)
4445
import Hydra.Node.Environment (Environment)
4546
import Hydra.Tx (HeadId, IsTx (..), Party, txId)
4647
import Network.HTTP.Types (status500)
@@ -72,7 +73,7 @@ data APIServerConfig = APIServerConfig
7273
, port :: PortNumber
7374
, tlsCertPath :: Maybe FilePath
7475
, tlsKeyPath :: Maybe FilePath
75-
, apiTransactionTimeout :: NominalDiffTime
76+
, apiTransactionTimeout :: ApiTransactionTimeout
7677
}
7778

7879
withAPIServer ::

0 commit comments

Comments
 (0)