-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathAwaitTxConfirmedIssue.hs
149 lines (134 loc) · 3.89 KB
/
AwaitTxConfirmedIssue.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Issues.AwaitTxConfirmedIssue where
-- Issue brought up by @dino in discord.
-- - `awaitTxConfirmed` loops forever if validation fails
-- - I.e. contract is blocked for further requests
-- - Same as what happened in lecture 02
--
-- Solution:
-- - Add a timeout to the `awaitTxConfirmed`
-- - Note: Transaction confirmation handling will change in future, so probably not worth to contribute
--
import Control.Monad ( Monad((>>), return, (>>=)), void )
import Data.Text ( Text )
import Data.Void (Void)
import Ledger
( ScriptContext,
scriptCurrencySymbol,
mkMonetaryPolicyScript,
txId,
Slot,
CurrencySymbol )
import Ledger.Constraints as Constraints
( monetaryPolicy,
mustForgeValue,
)
import qualified Ledger.Typed.Scripts as Scripts
import Ledger.Value as Value (singleton)
import Playground.TH (mkKnownCurrencies, mkSchemaDefinitions)
import Playground.Types (KnownCurrency (..))
import Plutus.Contract as Contract
( AsContractError,
BlockchainActions,
Contract,
Endpoint,
HasBlockchainActions,
awaitTxConfirmed,
currentSlot,
endpoint,
logError,
logInfo,
submitTxConstraintsWith,
throwError,
timeout,
type (.\/),
)
import Plutus.Trace.Emulator as Emulator
( activateContractWallet,
callEndpoint,
runEmulatorTraceIO,
waitNSlots,
)
import qualified PlutusTx
import PlutusTx.Prelude
( AdditiveSemigroup ((+)),
Bool (False),
IO,
Integer,
Show (show),
String,
maybe,
traceIfFalse,
($),
)
import Text.Printf (printf)
import Wallet.Emulator.Wallet (Wallet (Wallet))
{-# INLINEABLE mkPolicy #-}
mkPolicy :: ScriptContext -> Bool
mkPolicy _ =
traceIfFalse "Validation error" False
policy :: Scripts.MonetaryPolicy
policy = mkMonetaryPolicyScript
$$(PlutusTx.compile [||Scripts.wrapMonetaryPolicy mkPolicy||])
curSymbol :: CurrencySymbol
curSymbol = scriptCurrencySymbol policy
type SignedSchema =
BlockchainActions
.\/ Endpoint "mint" Integer
mint :: Integer -> Contract w SignedSchema Text ()
mint amt = do
let val = Value.singleton curSymbol "ABC" amt
lookups = Constraints.monetaryPolicy policy
tx = Constraints.mustForgeValue val
ledgerTx <- submitTxConstraintsWith @Void lookups tx
withTimeoutLogging 2 $ do
Contract.logInfo @String $ printf "Awaiting confirmation"
awaitTxConfirmed $ txId ledgerTx
Contract.logInfo @String $ printf "forged %s" (show val)
withTimeout ::
(HasBlockchainActions s, AsContractError e) =>
Slot ->
Contract w s e a ->
Contract w s e a ->
Contract w s e a
withTimeout t c onError = do
curSlot <- Contract.currentSlot
result <- timeout (curSlot + t) c
maybe onError return result
withTimeoutLogging ::
HasBlockchainActions s =>
Slot ->
Contract w s Text () ->
Contract w s Text ()
withTimeoutLogging t c = withTimeout t c $ Contract.logError @String $ printf "Timeout for awaiting confirmation"
withTimeoutThrowError ::
HasBlockchainActions s =>
Slot ->
Contract w s Text () ->
Contract w s Text ()
withTimeoutThrowError t c = withTimeout t c $ Contract.throwError "Timeout for awaiting confirmation"
endpoints :: Contract () SignedSchema Text ()
endpoints = mint' >> endpoints
where
mint' = endpoint @"mint" >>= mint
mkSchemaDefinitions ''SignedSchema
mkKnownCurrencies []
test :: IO ()
test = runEmulatorTraceIO $ do
h <- activateContractWallet (Wallet 1) endpoints
callEndpoint @"mint" h 333
void $ Emulator.waitNSlots 3
callEndpoint @"mint" h 444
void $ Emulator.waitNSlots 3
callEndpoint @"mint" h 555
void $ Emulator.waitNSlots 3