Leios ThreadNet (#1883)
In order to have quicker iteration speeds during Leios prototype
development we want to enable running "simulated networks".
cardano-node has this ability because of the `io-classes` abstraction
used, which is ultimately reified in the ThreadNet tests.
This PR implements the `run-threadnet` CLI that runs a simulated
cardano-node network as specified by the user.
DONE:
- [x] Wire in Leios specifics into ThreadNet machinery such that we can
observe Leios state and events after each run
- [x] Collect traces
- [x] Store traces in the configure locations
- [x] Augment traces with SlotNo and CoreNodeId information
- [x] Collect relevant state
- [x] Leios in memory store
- [x] Implement `run-threadnet` CLI
- [x] Design and implement the configuration format
- [x] Tranlsate it into the ThreadNet configuration
- [x] Implement a simple & configurable tx generator
- [x] Configured the Nix build to only work with GHC96
- it's slow and painful to maintain green builds across all compiler
versions and platforms, reducing it to essentials.
- [x] Refactored `ThreadNet.Network` bits for clarity (during debugging)
### Example: Run the threadnet for 30 slots and generated a 1000
transactions per slot
$ cat run-threadnet-example-config/example-threadnet-config.json
```json
{
"tncCoreNodes" : [
{
"cncCardanoConfig" : "run-threadnet-example-config/config.json",
"cncKesSigningKey" : "run-threadnet-example-config/pools-keys/pool1/kes.skey",
"cncOCert" : "run-threadnet-example-config/pools-keys/pool1/opcert.cert",
"cncVrfSigningKey" : "run-threadnet-example-config/pools-keys/pool1/vrf.skey",
"cncLog": "node0.log"
},
{
"cncCardanoConfig" : "run-threadnet-example-config/config.json",
"cncKesSigningKey" : "run-threadnet-example-config/pools-keys/pool2/kes.skey",
"cncOCert" : "run-threadnet-example-config/pools-keys/pool2/opcert.cert",
"cncVrfSigningKey" : "run-threadnet-example-config/pools-keys/pool2/vrf.skey",
"cncLog": "node1.log"
},
{
"cncCardanoConfig" : "run-threadnet-example-config/config.json",
"cncKesSigningKey" : "run-threadnet-example-config/pools-keys/pool3/kes.skey",
"cncOCert" : "run-threadnet-example-config/pools-keys/pool3/opcert.cert",
"cncVrfSigningKey" : "run-threadnet-example-config/pools-keys/pool3/vrf.skey",
"cncLog": "node2.log"
}
],
"tncTopology" : [
[ 0, 1],
[ 0, 2],
[ 1, 2]
],
"tncTxGenerators" : [
{
"tgcSubmitToNodes" : [
0
],
"tgcTxGeneratorKind" : {
"tacPaymentSigningKey" : "run-threadnet-example-config/stake-delegators/delegator2/payment.skey"
}
}
]
}
```
and run with
```shell
$ cabal run ouroboros-consensus-cardano:run-threadnet
Usage: run-threadnet COMMAND
Run ThreadNet, ie. run nodes in a simulated IO environment
Available options:
-h,--help Show this help text
Available commands:
run Run the simulation
dump-example-config Dump an example configuration file
(example-threadnet.config)
$ cabal run ouroboros-consensus-cardano:run-threadnet -- run --threadnet-config run-threadnet-example-config/example-threadnet-config.json --slots 30 --txs-per-slot 1000
...
("current slot",SlotNo 29)
("current slot",SlotNo 29)
("current slot",SlotNo 29)
*** Tips
Just (SlotNo 29,fromList [(CoreId (CoreNodeId 0),At (BlockNo 1)),(CoreId (CoreNodeId 1),At (BlockNo 1)),(CoreId (CoreNodeId 2),At (BlockNo 1))])
*** Leios
("eb-slotno",fromList [(CoreId (CoreNodeId 0),fromList []),(CoreId (CoreNodeId 1),fromList []),(CoreId (CoreNodeId 2),fromList [("\179@Af:\160\130\204\205\ACKFU\251t\EMk\EOT\172*\152s\145\187I\192\191\235=4\244\149\233",SlotNo 10),("\240\ESC \155\DC2\a\247\167\248x\NUL\ETB\254\194\bv\170\GS\139.\201\249\182h\186\184;\SOH\141\188\255J",SlotNo 7)])])
("eb-points",fromList [(CoreId (CoreNodeId 0),fromList []),(CoreId (CoreNodeId 1),fromList []),(CoreId (CoreNodeId 2),fromList [(7,("\240\ESC \155\DC2\a\247\167\248x\NUL\ETB\254\194\bv\170\GS\139.\201\249\182h\186\184;SOH\141\188\255J",13827)),(10, "\179@Af:160\130\204\205\ACKFU\251t\EMk\EOT\172*\152s\145\187I\192\191\235=4\244\149\233",13827))])])
("eb-txs",fromList [(CoreId (CoreNodeId 0),0),(CoreId (CoreNodeId 1),0),(CoreId (CoreNodeId 2),768)])
*** Outputting log files
$ grep -i leios node*.log
node0.log:FromLeios (MkTraceLeiosKernel "leiosFetchLogic: wait for leios ready")
node1.log:FromLeios (MkTraceLeiosKernel "leiosFetchLogic: wait for leios ready")
node2.log:FromLeios (MkTraceLeiosKernel "leiosFetchLogic: wait for leios ready")
node2.log:FromLeios (TraceLeiosBlockForged {slot = SlotNo 7, eb = MkLeiosEb {leiosEbTxs = [("\236\216\134\a\233'\158\DC3\175\211\210\228v^<\t\212f|\219\DC4\160\&5I\n\205\199?\140gJ\220",229),("\177\SUB\137V\156R@\
node2.log:FromLeios (TraceLeiosBlockStored {slot = SlotNo 7, eb = MkLeiosEb {leiosEbTxs = [("\236\216\134\a\233'\158\DC3\175\211\210\228v^<\t\212f|\219\DC4\160\&5I\n\205\199?\140gJ\220",229),("\177\SUB\137V\156R@\
node2.log:FromLeios (TraceLeiosBlockForged {slot = SlotNo 10, eb = MkLeiosEb {leiosEbTxs = [("\138\138H\226\SUB\147\149\&4\169\143\179\240\173\214Ue\229\210x^\227q\198\DC3f=b\170\DEL\237v|",229),("\224\DC4\132\170
node2.log:FromLeios (TraceLeiosBlockStored {slot = SlotNo 10, eb = MkLeiosEb {leiosEbTxs = [("\138\138H\226\SUB\147\149\&4\169\143\179\240\173\214Ue\229\210x^\227q\198\DC3f=b\170\DEL\237v|",229),("\224\DC4\132\170
```