diff --git a/.gitignore b/.gitignore index 6afab6c3..9884bef8 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,9 @@ coverage # production build +# documentation generation +docs/config.md + # misc .DS_Store npm-debug.log diff --git a/docs/docTemplate.js b/docs/docTemplate.js new file mode 100644 index 00000000..9a358a8e --- /dev/null +++ b/docs/docTemplate.js @@ -0,0 +1,49 @@ + +const BufferList = require('bl'); + +module.exports = { + preExampleConfig: new BufferList(` +--- +title: Configuring Parity Ethereum +--- + +Parity can be configured using either the [CLI options](#cli-options) or a [config file](#config-file). Should the CLI flags and the config file disagree about a setting, the CLI takes precedence. + +You can list all CLI options by running \`$parity --help\`. The vast majority of CLI options map to a setting in the TOML file, for example \`--mode-timeout 500\` can be set by creating a config file: + +\`\`\`toml +[parity] +mode_timeout = 500 +\`\`\` + +## Config File + +Parity can be configured using a [TOML](https://github.com/toml-lang/toml) file. The file can be generated using the [Parity Config Generator](https://paritytech.github.io/parity-config-generator/). To start parity with a config file, the file needs to be located in: + + * Windows: \`%UserProfile%\\AppData\\Roaming\\Parity\\Ethereum\\config.toml\` + * Linux: \`~/.local/share/io.parity.ethereum/config.toml\` + * macOS: \`$HOME/Library/Application Support/io.parity.ethereum/config.toml\` + +To use a custom path run \`$ parity --config path/to/config.toml\`. + +## Default config.toml + +The following is a representation of a configuration file with all default values (*note: the \`[stratum]\` section is not present by default, and including it in your config currently enables stratum*). + +\`\`\`toml`), + postExampleConfig: new BufferList('\n```\n'), + preConfigDoc: new BufferList(` +## Presets + +Parity can also be launched with a [preset configuration file](https://github.com/paritytech/parity-ethereum/tree/master/parity/cli/presets) using the \`--config\` flag with one of the following values: + * \`dev\`: uses [dev chain specifications](Private-development-chain) with [Instant-seal](Pluggable-Consensus#instant-seal) consensus engine. The gas price is set to 0. + * \`dev-insecure\`: uses the same configuration as \`dev\`, plus sets the flag \`no_consensus\`, allows all RPC APIs and accepts all RPC interfaces and hosts, as well as all IPFS hosts. + * \`insecure\`: uses the Mainnet default configuration, plus sets the flag \`no_consensus\`, allows all RPC APIs and accepts all RPC interfaces and hosts, as well as all IPFS hosts. + * \`mining\`: uses the Mainnet default configuration, plus increases the number of peers to min 50 and max 100, it disables the Dapps and IPC interface. It forces the sealing of blocks with a minimum of 4 seconds interval, forces the reseal for any new transaction (external or local), reduces the transaction queue size to 2048 while increasing the cache size to 256 MB and setting the \`trace\` logging level for the \`miner\` and \`own_tx\` modules. + * \`non-standard-ports\`: sets the client to listen to the port 30305 and 8645 for RPC connections. + +## Configuration options + +`), + postConfigDoc: new BufferList(``) +}; diff --git a/package.json b/package.json index 5fc0f65a..a2485289 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,9 @@ "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject", "lint": "semistandard --verbose | snazzy", - "generate-data": "node scripts/generate-config-data.js" + "lint-fix": "semistandard --fix --verbose | snazzy", + "generate-data": "node scripts/generate-config-data.js", + "generate-docs": "node scripts/generate-config-docs.js" }, "semistandard": { "parser": "babel-eslint" diff --git a/scripts/generate-config-data.js b/scripts/generate-config-data.js index 61b76aa2..9505f429 100644 --- a/scripts/generate-config-data.js +++ b/scripts/generate-config-data.js @@ -12,6 +12,9 @@ const CONFIG_IS = { }; function fetchSource () { + if (process.env.AUTOGENSCRIPT) { + return fs.readFile(path.resolve(__dirname, '../../parity/cli/mod.rs'), 'UTF-8'); + } return new Promise((resolve, reject) => { https.get('https://raw.githubusercontent.com/paritytech/parity/master/parity/cli/mod.rs', res => { if (res.statusCode !== 200) { @@ -26,7 +29,8 @@ function fetchSource () { resolve(data.toString()); })); }); - }); + } + ); } function getCliOptions (source) { @@ -236,9 +240,7 @@ function augment (data, extra) { return dataAugmentedOrdered; } -(async function () { - const source = await fetchSource(); - +function generateAugmentedData (source) { // Parse CLI options const cliOptions = getCliOptions(source); @@ -264,28 +266,40 @@ function augment (data, extra) { // Augment with data.extra.json const extra = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../src/data.extra.json'), 'UTF-8')); - const dataAugmented = augment(data, extra); + return augment(data, extra); +} +if (!module.parent) { + (async function () { // Make sure that config items with unrecognized default values // were set a default value in data.extra.json - Object.keys(dataAugmented).forEach(section => { - const undefinedDefaults = Object.keys(dataAugmented[section]) + const dataAugmented = generateAugmentedData(await fetchSource()); + + Object.keys(dataAugmented).forEach(section => { + const undefinedDefaults = Object.keys(dataAugmented[section]) .filter(prop => { const item = dataAugmented[section][prop]; return typeof item === 'object' && typeof item.default === 'undefined'; }) .map(prop => `${section}.${prop}`); - if (undefinedDefaults.length) { - throw new Error(`Couldn't parse the default CLI value for the following config items: ${undefinedDefaults.join(', ')}. Please set a default value for them in data.extra.json.`); - } - }); + if (undefinedDefaults.length) { + throw new Error(`Couldn't parse the default CLI value for the following config items: ${undefinedDefaults.join(', ')}. Please set a default value for them in data.extra.json.`); + } + }); // Write to file - fs.writeFileSync(path.resolve(__dirname, '../src/data.compiled.json'), JSON.stringify(dataAugmented, null, 2)); -})().catch(e => { - console.error(e); - process.exit(1); -}); + fs.writeFileSync(path.resolve(__dirname, '../src/data.compiled.json'), JSON.stringify(dataAugmented, null, 2)); + })().catch(e => { + console.error(e); + process.exit(1); + }); +} else { + module.exports = { + fetchSource: fetchSource, + getCliOptions: getCliOptions, + getData: generateAugmentedData + }; +} diff --git a/scripts/generate-config-docs.js b/scripts/generate-config-docs.js new file mode 100644 index 00000000..c3ca1038 --- /dev/null +++ b/scripts/generate-config-docs.js @@ -0,0 +1,109 @@ +const fs = require('fs'); +const path = require('path'); +const BufferList = require('bl'); +const docTemplate = require('../docs/docTemplate.js'); +const data = require('./generate-config-data.js'); + +const outputDir = '../docs/'; +const outputFile = 'config.md'; + +function dirtySerialize (valueItem) { + if (typeof valueItem !== 'undefined') { + const rawDefaultValue = valueItem; + var defaultValue; + if (typeof rawDefaultValue === 'object') { + if (rawDefaultValue === null) { + defaultValue = 'null'; + } else { + defaultValue = JSON.stringify(rawDefaultValue); + } + } else { + if (rawDefaultValue === '') { + defaultValue = '""'; + } else { + defaultValue = rawDefaultValue; + } + } + return defaultValue; + } +} + +function compiledToml (compiledData) { + var compiledBuffer = new BufferList(); + for (const key in compiledData) { + if (key[0] !== '_') { + const sectionValues = compiledData[key]; + compiledBuffer.append('[' + key + ']\n'); + for (const value in sectionValues) { + if (value.indexOf('section') < 0 && value.indexOf('description') < 0) { + const valueItem = sectionValues[value]['default']; + compiledBuffer.append(value + ' = ' + dirtySerialize(valueItem) + '\n'); + } + } + compiledBuffer.append('\n'); + } + } + return compiledBuffer; +} + +// Command line options, configs, and descriptions. +function compiledMd (cliOptions) { + const compiledBuffer = new BufferList(); + const builtTree = {}; + for (const option in cliOptions) { + const configSection = cliOptions[option]['configSection']; + const configProp = cliOptions[option]['configProp']; + const helpText = cliOptions[option]['help']; + const variableName = cliOptions[option]['variableName']; + const defaultValue = dirtySerialize(cliOptions[option]['defaultValue']); + var cliName = variableName.replace(/_/g, '-').slice(4); + if (cliName[0] === '-') { + cliName = cliName.slice(1); + } + cliName = '--' + cliName; + const toAppend = BufferList('\n'); + toAppend.append('## ' + cliName.slice(2) + '\n'); + toAppend.append(helpText + '\n'); // description + toAppend.append('#### Command line option \n `' + cliName + '`\n'); // cli flag + if (typeof configSection !== 'undefined') { + toAppend.append('#### Config file option \n```toml\n' + '[' + configSection + ']' + '\n' + configProp + ' = ' + defaultValue + '\n```\n'); // config item + } + toAppend.append('#### Default Value \n`' + defaultValue + '`\n'); + if (typeof builtTree[configSection] !== 'undefined') { + builtTree[configSection].append(toAppend); + } else { + builtTree[configSection] = toAppend; + } + } + for (var section in builtTree) { + var sectionText = section; + if (section === 'undefined') { + sectionText = 'CLI Only'; + } + compiledBuffer.append('# ' + sectionText + '\n'); + compiledBuffer.append(builtTree[section]); + compiledBuffer.append('\n'); + } + + return compiledBuffer; +} + +async function buildPage () { + var compiledBuffer = new BufferList(); + const source = await data.fetchSource(); + compiledBuffer.append(docTemplate.preExampleConfig); + compiledBuffer.append(compiledToml(data.getData(source))); + compiledBuffer.append(docTemplate.postExampleConfig); + compiledBuffer.append(docTemplate.preConfigDoc); + compiledBuffer.append(compiledMd(data.getCliOptions(source))); + compiledBuffer.append(docTemplate.postConfigDoc); + return compiledBuffer; +} + +(async function () { + fs.writeFileSync(path.resolve(__dirname, outputDir + outputFile), (await buildPage()).toString()); +})().catch(e => { + console.error(e); + process.exit(1); +}); + diff --git a/src/data.compiled.json b/src/data.compiled.json index d7ea387a..608c1249 100644 --- a/src/data.compiled.json +++ b/src/data.compiled.json @@ -490,7 +490,7 @@ "processing_threads": { "name": "Processing threads", "type": "number", - "description": "Turn on additional processing threads in all HTTP JSON-RPC servers. Setting this to non-zero value allows parallel execution of cpu-heavy queries.", + "description": "Turn on additional processing threads for JSON-RPC servers (all transports). Setting this to a non-zero value allows parallel execution of cpu-heavy queries.", "default": 4 }, "max_payload": { @@ -499,6 +499,30 @@ "description": "Specify maximum size for HTTP JSON-RPC requests in megabytes.", "default": null }, + "keep_alive": { + "name": "Keep alive", + "type": "bool", + "description": "Disable HTTP/1.1 keep alive header. Disabling keep alive will prevent re-using the same TCP connection to fire multiple requests, recommended when using one request per connection.", + "default": false + }, + "experimental_rpcs": { + "name": "Experimental rpcs", + "type": "bool", + "description": "Enable experimental RPCs. Enable to have access to methods from unfinalised EIPs in all namespaces", + "default": false + }, + "poll_lifetime": { + "name": "Poll lifetime", + "type": "number", + "description": "Set the RPC filter lifetime to S seconds. The filter has to be polled at least every S seconds , otherwise it is removed.", + "default": 60 + }, + "allow_missing_blocks": { + "name": "Allow missing blocks", + "type": "bool", + "description": "RPC calls will return 'null' instead of an error if ancient block sync is still in progress and the block information requested could not be found", + "default": false + }, "description": "Expose JSON-RPC APIs over HTTP." }, "websockets": { @@ -994,12 +1018,6 @@ "description": "Set PCT percentile gas price value from last 100 blocks as default gas price when sending transactions.", "default": 50 }, - "poll_lifetime": { - "name": "Poll lifetime", - "type": "number", - "description": "Set the lifetime of the internal index filter to S seconds.", - "default": 60 - }, "tx_queue_per_sender": { "name": "Tx queue per sender", "type": "number", @@ -1030,6 +1048,12 @@ "description": "Pending block will be created with maximal possible gas limit and will execute all transactions in the queue. Note that such block is invalid and should never be attempted to be mined.", "default": false }, + "max_round_blocks_to_import": { + "name": "Max round blocks to import", + "type": "number", + "description": "Maximal number of blocks to import for each import round.", + "default": 12 + }, "description": "Options for mining nodes." }, "stratum": { @@ -1213,6 +1237,12 @@ "default": false }, "section": "Snapshots", + "processing_threads": { + "name": "Processing threads", + "type": "number", + "description": "Enables multiple threads for snapshots creation.", + "default": null + }, "description": "Snapshoting (warp sync) settings." }, "misc": { @@ -1311,5 +1341,38 @@ "default": 10 }, "description": "Whisper network" + }, + "light": { + "section": "Light", + "on_demand_response_time_window": { + "name": "On demand response time window", + "type": "number", + "description": "Specify the maximum time to wait for a successful response", + "default": null + }, + "on_demand_request_backoff_start": { + "name": "On demand request backoff start", + "type": "number", + "description": "Specify light client initial backoff time for a request", + "default": null + }, + "on_demand_request_backoff_max": { + "name": "On demand request backoff max", + "type": "number", + "description": "Specify light client maximum backoff time for a request", + "default": null + }, + "on_demand_request_backoff_rounds_max": { + "name": "On demand request backoff rounds max", + "type": "number", + "description": "Specify light client maximum number of backoff iterations for a request", + "default": null + }, + "on_demand_request_consecutive_failures": { + "name": "On demand request consecutive failures", + "type": "number", + "description": "Specify light client the number of failures for a request until it gets exponentially backed off", + "default": null + } } } \ No newline at end of file