{"id":24144956,"url":"https://github.com/plebhash/stratum-message-generator","last_synced_at":"2025-12-31T14:21:07.135Z","repository":{"id":241430479,"uuid":"806803026","full_name":"plebhash/stratum-message-generator","owner":"plebhash","description":"Stratum Message Generator: execute interoperability tests between SRI and other SV2 complaint software","archived":false,"fork":false,"pushed_at":"2024-10-27T22:24:25.000Z","size":117543,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"message-generator-split","last_synced_at":"2025-03-01T15:14:24.492Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/plebhash.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-28T00:01:57.000Z","updated_at":"2024-09-02T22:06:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"f8f1a97d-a93e-4796-b0a5-50c3256deead","html_url":"https://github.com/plebhash/stratum-message-generator","commit_stats":null,"previous_names":["stratum-mining/stratum-message-generator"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/plebhash/stratum-message-generator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plebhash%2Fstratum-message-generator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plebhash%2Fstratum-message-generator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plebhash%2Fstratum-message-generator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plebhash%2Fstratum-message-generator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/plebhash","download_url":"https://codeload.github.com/plebhash/stratum-message-generator/tar.gz/refs/heads/message-generator-split","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plebhash%2Fstratum-message-generator/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265849011,"owners_count":23838195,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-12T06:13:33.247Z","updated_at":"2025-12-31T14:21:07.105Z","avatar_url":"https://github.com/plebhash.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Message Generator\n\n\nLittle utility to execute interoperability tests between SRI and other Sv2 complaint software.   \n\n## Try it\n1. Stop any `bitcoind` regtest processes running (the `message-generator` starts it for you).\n2. In `test.json` specify `bitcoind`, `bitcoin-cli`, and `datadir` paths:\n```\n...\n    \"setup_commands\": [\n        {\n            \"command\": \"PATH TO bitcoind\",\n            \"args\": [\"--regtest\", \"--datadir=PATH TO bitcoin datadir\"],\n\n...\n\n        {\n            \"command\": \"PATH TO bitcoin-cli\",\n            \"args\": [\n                        \"--regtest\",\n                        \"--datadir=PATH TO bitcoin datadir\",\n...\n```\n3. `% cargo run test.json`\n4. If the test is in the `/test/message-geneator` directory, you have to lauch it from the MG\n   directory using relative path. For example, \n```\ncargo run ../../test/message-generator/test/pool-sri-test-1-standard.json\n```\n\n## Test execution\n\nThe message generator executes a test with the following steps: \n1. Setup Commands: Executes shell commands or bash scripts to be run on start up, e.g. a `bitcoind` a node.\n2. Role Connection: Setups up one or two TCP connections, both plain and noise are supported, e.g. a connection to an Upstream role.\n3. Execution Commands: Executes shell commands or bash scripts to be run after a connection has been opened between two roles, e.g. a mocked Pool to a test Proxy.\n4. Actions: Executes the actions using the previously opened connection. If a SV2 test is executing, each action\n   sends zero or more `Sv2Frames` and checks if the received frame satisfies the conditions (defined\n   in the action). If a SV1 test is executing, each action sends one or more JSON-RPC Requests and checks if the received Response satisfies the conditions. More than one condition can be defined if more than one message is expected to be\n   received.\n5. Cleanup Commands: Executes shell commands or bash scripts to be run on test completion, e.g. remove a `bitcoind` `datadir`.\n\n## True tests, mocks and modules\nThe true tests are located in `test/message-generator/test`. Some files have the structure of a \ntest but in fact they are not. \nFor example, the file in \n`test/message-generator/mock` are mocks of application, namely they are tests whose purpose is \nto pretend to be an SV2 role. Currently only the TemplateProvider and the JobDeclarator are the \nonly roles mocked. These mocks are usually used in the true tests. For example, in the test\n`test/message-generator/test/pool-sri-test-standard-1.json`\nthe pool has a mocked environment, i.e. the JD and TP mocks.\nThe files in `test/message-generator/messages` also are not true tests, but the are intended to be\nmodules. For example, the `common_messages.json` is the module that contains the frame builders of\nthe common messages for the true tests and the mocks.\n\nTrue tests are made to be run and produce positive outcome. \nMocks and common messages are meant to work as a part of a true test and they are not supposed to\nbe run as standalone.\n\n\n## Test format\n\nTests are written in json and must follow the below format:\n\n### version\n\n`version` is a string that indicates if the test is a SV1 test or a SV2 test. It can be either `\"1\"` or `\"2\"`.\n\n### doc\n\n`doc` is an array of strings that explain what the test do. This field is optional.\n\n```json\n{\n    \"doc\": [\n        \"This test do:\",\n            \"1) launch bitcoind in regtest and wait for TP initialization\",\n            \"2) create a bunch of block using bictoin-cli\",\n            \"...\"\n    ]\n}\n```\n\n### common_messages\n\n`common_messages` is an array of messages (defined below) belonging to the common (sub)protocol, \nwhere the common subprotocol is composed by: `SetupConnection` and `SetupConnectionSuccees` and `SetupConnectionError`.\nThis field is optional.\n\n### mining_messages\n\n`mining_messages` is an array of messages (defined below) belonging to the mining (sub)protocol. This field is optional.\n\n### job_declaration_messages\n\n`job_declaration_messages` is an array of messages (defined below) that belongs to the job declaration (sub)protocol. This field is optional.\n\n### template_distribution_messages\n\n`template_distribution_messages` is an array of messages (defined below) that belongs to the template distribution (sub)protocol. This field is optional.\n\n### sv1_messages\n\n`sv1_messages` is an array of messages that belongs to the SV1 protocol. If `version` is `\"2\"` this field should be empty.\n\n**Definition of messages mentioned above**\n\nA message is an object with two field `message` and `id`.\nThe `message` field contains the actual message. The `id` field contains a unique id\nused to refer to the message in other part of the test.\nFor SV2 messages, the `message` field is an object composed by:\n1. type: message type name as defined in the Sv2 spec is a string eg `SetupConnection`\n2. all the other field of that specific message as defined in the Sv2 spec with the only exception\n   of the field `protocol` that is a string and not a number eg instead of `0` we have\n   `MiningProtocol`\n\n\n```json\n{\n    \"common_messages\": [\n        {\n            \"message\": {\n                \"type\": \"SetupConnection\",\n                \"protocol\": \"MiningProtocol\",\n                \"min_version\": 2,\n                \"max_version\": 2,\n                \"flags\": 0,\n                \"endpoint_host\": \"\",\n                \"endpoint_port\": 0,\n                \"vendor\": \"\",\n                \"hardware_version\": \"\",\n                \"firmware\": \"\",\n                \"device_id\": \"\"\n            },\n            \"id\": \"setup_connection\"\n        }\n    ]\n}\n```\n\nFor SV1 messages, the `message` field is a JSON-RPC StandardRequest, composed by the fields `id`, `method` and `params`.\n\n\n```json\n{\n    \"sv1_messages\": [\n        {\n            \"message\": {\n                \"id\": 1,\n                \"method\": \"mining.subscribe\",\n                \"params\": [\"cpuminer\"]\n            },\n            \"id\": \"mining.subscribe\"\n        },\n        {\n            \"message\": {\n                \"id\": 2,\n                \"method\": \"mining.authorize\",\n                \"params\": [\"username\", \"password\"]\n            },\n            \"id\": \"mining.authorize\"\n        }\n    ]\n}\n```\n\n\n### frame_builders\n\nObjects in `frame_builders` are used by the message generator to construct Sv2 frames in order to send the message\nto the tested software. Objects in `frame_builders` can be either **automatic** (where the sv2 frame header is\nconstructed by the SRI libs and is supposed to be correct) or **manual** (if we want to test a software\nagainst an incorrect frame).\n\n`frame_builders` is an array of objects. Every object in `frame_builders` must contain `message_id`, that is a \nstring with the id of the previously defined message. In the example below, the message id refers to\nthe item `setup_connection` of `common_messages`. Every object in `frames` must have the\nfield `type`, a string that can be either `automatic` or `manual` with meaning of the paragraph\nabove.\n\nIf `type` == `manual` the object must contain 3 additional fields:\n1. `message_type`: a string the must start with `0x` followed by an hex encoded integer not bigger\n   than `0xff`\n2. `extension_type`: a string composed by 16 elements, each element must be either `0` or `1`, the\n   elements can be separated by `_` that is not counted as element so we can have as many\n   separator as we want eg: `0000_0000_0000_0000`\n   Separator are there only to human readability and are removed when the test is parsed.\n3. `channel_msg`: a `bool`\n\n```json\n{\n    \"frame_builders\": [\n        {\n            \"type\": \"automatic\",\n            \"message_id\": \"setup_connection\"\n        },\n        {\n            \"type\": \"manual\",\n            \"message_id\": \"close_channel\",\n            \"message_type\": \"0x18\",\n            \"extension_type\": \"0000_0000_0000_0000\",\n            \"channel_msg\": true\n        }\n    ]\n}\n```\nIf the frame relative to common messages is defined is a different file (for example, some \ncommon_messages frames are defined in `/test/message-geneator/messages/common_messages.json`), to \nuse it you have to use the syntax `\u003caddress::id\u003e`. For example, in the test \n`/test/message/generator/test`, the following message \n```\n   {\n       \"type\": \"automatic\",\n       \"message_id\": \"test/message-generator/messages/common_messages.json::setup_connection_success_template_distribution\"\n   }\n```\ncalls the id `setup_connection_success_template_distribution` that appears in the file \n`test/message-generator/messages/common_messages.json`. In the main file, the id of this\nmessage will be the abbreviated with `setup_connection_success_template_distribution`. \n \n\n\n### actions\n\n`actions` is an array of objects. If the test version is \"2\", each object is composed by:\n1. `role`: can be either `client` or `server`. This because the message generator can act at the\n   same time as a client and as a server for example when we are mocking a proxy.\n2. `messages_ids`: an array of strings, that are ids of messages previously defined.\n3. `results`: is an array of objects, used by the message generator to test if certain property of\n   the received frames are true or not.  Accepts values:\n    - \"type\": String - match option - match_message_type, match_message_field, match_message_len, or match_extension_type\n    - \"value\": Array - varries depending on \"type\"\n\n```json\n{\n    \"actions\": [\n        {\n            \"message_ids\": [\"open_standard_mining_channel\"],\n            \"role\": \"client\",\n            \"results\": [\n                {\n                    \"type\": \"match_message_field\",\n                    \"value\": [\n                        \"MiningProtocol\",\n                        \"OpenStandardMiningChannelSuccess\",\n                        [\n                            \"request_id\",\n                            {\"U32\": 89}\n                        ]\n                    ]\n                }\n            ] \n        }\n    ]\n}\n```\n\nIf the test version is \"1\", each object is composed by:\n1. `messages_ids`: an array of strings, that are ids of sv1_messages previously defined.\n2. `results`: is an array of objects, used by the message generator to test if certain property of\n   the received Responses are true or not.  Accepts values:\n    - \"type\": String - match option - match_message_id, match_message_field\n    - \"value\": Array - varries depending on \"type\"\n\n### setup commands\n\nAn array of commands (defined below) that are executed before that the message generator open one\nore more connection with the tested software.\n\n### excution commands\n\nAn array of commands (defined below) that are executed after that the message generator open one\nore more connection with the tested software.\n\n### cleanup_commands commands\n\nAn array of commands (defined below) that are executed after that all the actions have been executed.\nTODO this commands should be executed not only if all the action pass but also if something fail\n\n**Definition of commands mentioned above**\n\nA command is an object with the following fields:\n1. `command`: the bash command that we want to execute\n2. `args`: the command's args\n3. `condition`: can be either `WithConditions` or `None` in the first case the command executor\n   will wait for some condition before return in the latter it just launch the command and return\n\n`WithConditions` is an object composed by the following fields:\n1. `conditions`: an array of object that must be true or false on order for the executor to\n   return\n2. `timer_secs`: number of seconds after then the command is considered stuck and the test fail\n3. `warn_no_panic`: `bool` if true the test do not fail with panic if timer secs terminate but it\n   just exit (passing) and emit a warning\n\nThe objects contained in conditions are structured in the following way:\n1. `output_string`: a string that we need to check in the StdOut or StdErr\n2. `output_location`: say if the string is expected in StdOut or StdErr\n3. `condition`: a `bool` if true and we have `output_string` in `output_location` the executor return\n   and keep going, if false the executor fail.\n\nIn the below example we launch `bitcoind` we wait for `\"sv2 thread start\"` in StdOut and we fail if\nanything is written in StdErr\n```json\n{\n    \"setup_commands\": [\n        {\n            \"command\": \"./test/bitcoind\",\n            \"args\": [\"--regtest\", \"--datadir=./test/bitcoin_data/\"],\n            \"conditions\": {\n                \"WithConditions\": {\n                    \"conditions\": [\n                        {\n                            \"output_string\": \"sv2 thread start\",\n                            \"output_location\": \"StdOut\",\n                            \"condition\": true\n                        },\n                        {\n                            \"output_string\": \"\",\n                            \"output_location\": \"StdErr\",\n                            \"condition\": false\n                        }\n                    ],\n                    \"timer_secs\": 10,\n                    \"warn_no_panic\": false\n                }\n            }\n        }\n    ]\n}\n```\n\n### role\n\n`role` is a string and can be on of the three: client server proxy\n1. If we have client we expect to have a `downstream` field\n2. If we have server we expect to have an `upstream` field\n3. If we have proxy we expect to have both\n\n### downstream\n\n`downstream` is an object the contain the info need to open a connection as a downstream is composed by:\n1. `ip`: a string with the upstream ip address\n2. `port`: a string with the port address\n3. `pub_key`: optional if present we open a noise connection if no we open a plain connection, is a\n   string with the server public key\n\n### upstream\n\n`upstream` is an object the contain the info need to start listening:\n1. `ip`: a string with the ip where we will accept connection\n2. `port`: a string with the port address\n3. `pub_key`: optional if present accept noise connection if no plain connection\n3. `secret_key`: optional if present accept noise connection if no plain connection\n\n## Using Message Generator to produce test coverage with llvm-cov\n\nInformation on installation and use of llvm-cov found here: https://crates.io/crates/cargo-llvm-cov/0.1.13\nMore information on underlying dependancies here: https://doc.rust-lang.org/rustc/instrument-coverage.html\n\n### Including code coverage in command\n\nExample of llvm-cov code coverage run with pool setup_command\nllvm-cov requires a minimum of rustc 1.60.0 and LLVM 13.0.0\n\n```json\n        {\n            \"command\": \"cargo\",\n            \"args\": [\n                        \"llvm-cov\",\n                        \"--no-report\",\n                        \"run\",\n                        \"-p\",\n                        \"pool\",\n                        \"--\",\n                        \"-c\",\n                        \"./roles/v2/pool/pool-config.toml\"\n            ],\n            \"conditions\": {...} \n        },\n```\n\n`\"--no-report\"` caches the results in the background until the end of the test.  It also allows you collect coverage data from other processes in parallel by adding `\"llv-cov --no-report\"`, and all report data is reflected in the final report. \n\nTo generate the report, execute the `llvm-cov report` command in the cleanup_commands.  This example adds an output file path(from project root), the output file name and type, and paths to ignore in the report.\n\n```json\n    \"cleanup_commands\": [\n        {\n            \"command\": \"cargo\",\n            \"args\": [\n                        \"llvm-cov\",\n                        \"--ignore-filename-regex\",\n                        \"utils/|experimental/|protocols/\",\n                        \"--output-path\",\n                        \"target/tmp/pool_translator_cov.txt\",\n                        \"report\"\n            ],\n            \"conditions\": \"None\"\n        }\n    ]\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplebhash%2Fstratum-message-generator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplebhash%2Fstratum-message-generator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplebhash%2Fstratum-message-generator/lists"}