CTL environment (ContractEnv
type) consists of:
- various settings
- network protocol parameters (fetched once on initialization)
- active Ogmios
WebSocket
(optional) - CIP-30 wallet connection (optional)
- internal state used by synchronization primitives
Initialization is a costly operation, and having multiple distinct runtimes may lead to problems with state synchronization and excessive WebSocket
use, so it is recommended to use only one runtime at any point in time.
If only one Contract
is ever executed, just using runContract
is perfectly fine. Otherwise, there are two better approaches:
Bracket pattern in functional programming world is commonly used to safely manage resources. In our case, withContractEnv
should be used to initialize and finalize a ContractEnv
. runContractEnv
should be used to run a Contract
within the environment:
withContractEnv :: forall (a :: Type). ContractParams -> (ContractEnv -> Aff a) -> Aff a
runContractInEnv :: forall (a :: Type). ContractEnv -> Contract a -> Aff a
myContract1 :: Contract Uni
myContract2 :: Contract Uni
myRunner :: ContractParams -> Aff Unit
myRunner params = withContractEnv params \env -> do
runContractInEnv env myContract1
runContractInEnv env myContract2
Using bracket functions is safe, but is not always convenient, because withContractEnv
callback must hold the Aff
context until all Contract
s exit.
Another approach is using mkContractEnv
coupled with runContractInEnv
and stopContractEnv
.
Here's an example:
mkContractEnv :: ContractParams -> Aff ContractEnv
stopContractEnv :: ContractEnv -> Aff Unit
myContract1 :: Contract Uni
myContract2 :: Contract Uni
myRunner :: ContractParams -> Aff Unit
myRunner params = do
env <- mkContractEnv
void $ try do
runContractInEnv env myContract1
runContractInEnv env myContract2
stopContractEnv env
This approach is less safe in general, and it's fairly easy to hit the max WebSocket connections limit (which is 200 for Firefox) due to a forgotten stopContractEnv
call (e.g. due to an exception), not to mention that any websocket that is not closed will force the server to also keep the connection.
This approach, however, is better suited for use when creating custom JavaScript SDKs.